Go Native OpenTelemetry Integration
Install via Claude Code
Use Claude Code? Our skill will instrument this project for you. Add the marketplace, install the skill, and install our CLI:
claude plugin marketplace add monoscope-tech/skills
claude plugin install monoscope-skills@monoscope-skills
curl monoscope.tech/install.sh | sh
monoscope auth login
Then run inside Claude Code:
/monoscope-skills:instrument OpenTelemetry via Monoscope into this project
The skill drives the CLI to wire up the SDK and verify it. Prefer a human? Email us — happy to jump on a call or connect over Slack.
Installation
Install the Monoscope native Go SDK using the following command go get command:
go get github.com/monoscope-tech/monoscope-go/native
Configuration
Before configuration open telemetery and setting up the Monoscope middleware, you need to configure a few environment variables. These variables provide essential information for setting up openTelemetry and Monoscope.
OTEL_EXPORTER_OTLP_ENDPOINT="http://otelcol.monoscope.tech:4317"
OTEL_RESOURCE_ATTRIBUTES="x-api-key=YOUR_API_KEY"
OTEL_SERVICE_NAME="monoscope-otel-go-demo"
OTEL_SERVICE_VERSION="0.0.1"
OTEL_EXPORTER_OTLP_PROTOCOL="grpc"
Usage
After setting up the environment variables, you can configure the OpenTelemetry SDK and Monoscope middleware like so:
package main
import (
"log"
monoscope "github.com/monoscope-tech/monoscope-go/native"
_ "github.com/joho/godotenv/autoload" // autoload .env file for otel configuration
)
func main() {
// configure openTelemetry
shutdown, err := monoscope.ConfigureOpenTelemetry()
if err != nil {
log.Printf("error configuring openTelemetry: %v", err)
}
defer shutdown()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, World!"))
})
// configure monoscope middleware
nativeMiddleware := monoscope.Middleware(monoscope.Config{
RedactHeaders: []string{"Authorization", "X-Api-Key"},
RedactRequestBody: []string{"password", "credit_card"},
RedactResponseBody: []string{"password", "credit_card"},
})
// Wrap handler with middleware for monitoring requests and reporting errors
http.Handle("/", nativeMiddleware(handler))
if err := http.ListenAndServe(":8000", nil); err != nil {
log.Fatal(err)
}
}
All Environment Variables
Set the following environment variables in your application to enable the SDK:
| Variable Name | Description | Required | Example |
|---|---|---|---|
OTEL_RESOURCE_ATTRIBUTES |
Monoscope project key (x-api-key=<YOUR_API_KEY>) |
Yes | x-api-key=my-api-key |
OTEL_SERVICE_NAME |
The name of the service being monitored | No | example-chi-server |
OTEL_SERVICE_VERSION |
The version of your application or service | No | 0.0.1 |
OTEL_EXPORTER_OTLP_ENDPOINT |
The grpc endpoint for the OpenTelemetry collector. | No | otelcol.monoscope.tech:4317 |
OTEL_TRACES_ENABLED |
Enable or disable tracing | No | true |
OTEL_METRICS_ENABLED |
Enable or disable metrics | No | true |
OTEL_LOG_LEVEL |
The log level for the SDK (Set to debug to enable debug logs) | No | info |
OTEL_EXPORTER_OTLP_METRICS_PERIOD |
The period at which metrics are exported. | No | 30s |
OTEL_PROPAGATORS |
The propagators to use for tracing. | No | tracecontext,baggage |
All Middleware Configuration Fields
The middleware configuration specifies how the Monoscope SDK should handle requests and responses. Below are the available fields:
| Field Name | Type | Description | Default Value | Example |
|---|---|---|---|---|
Debug |
bool |
Enable detailed logs during development | false |
true |
ServiceName |
string |
Name of the service being monitored | - | "example-chi-server" |
ServiceVersion |
string |
Version of the service | - | "0.0.1" |
Tags |
[]string |
Additional tags for contextual information | [] |
[]string{"env:dev", "team:backend"} |
CaptureRequestBody |
bool |
Enable capturing of request body | false |
true |
CaptureResponseBody |
bool |
Enable capturing of response body | false |
true |
RedactHeaders |
[]string |
List of headers to redact | [] |
[]string{"Authorization", "X-Api-Key"} |
RedactRequestBody |
[]string |
JSONPath list of request body fields to redact | [] |
[]string{"$.password", "$.credit_card"} |
RedactResponseBody |
[]string |
JSONPath list of response body fields to redact | [] |
[]string{"$.password", "$.credit_card"} |
Non-HTTP Entry Points (Background Jobs, Workers, CLIs)
The net/http handler wrapper only covers HTTP requests. Cron jobs (robfig/cron), task queues (hibiken/asynq, gocraft/work), Kafka/NATS consumers, and standalone CLI commands are invisible until you wrap each handler in a span yourself. Always cover these alongside your HTTP routes — without it, half your production work has no observability.
Use the standard OpenTelemetry Go SDK; the same TracerProvider you configured for HTTP also instruments downstream calls (database, outbound HTTP) once a parent span is active.
import (
"context"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"go.opentelemetry.io/otel/trace"
"github.com/hibiken/asynq"
)
var tracer = otel.Tracer("my-service-worker")
func ProcessEmail(ctx context.Context, t *asynq.Task) error {
ctx, span := tracer.Start(ctx, "email.send",
trace.WithSpanKind(trace.SpanKindConsumer),
trace.WithAttributes(
semconv.MessagingSystem("asynq"),
attribute.String("messaging.operation", "process"),
attribute.String("messaging.destination.name", t.Type()),
attribute.String("code.function", "ProcessEmail"),
))
defer span.End()
if err := sendEmail(ctx, t.Payload()); err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
}
return nil
}
The same wrapper goes around robfig/cron job functions, Kafka/NATS subscribers, and any goroutine-based worker. For one-shot CLI binaries, call tp.Shutdown(ctx) on your TracerProvider before os.Exit so the BatchSpanProcessor flushes; otherwise spans are dropped silently.
Tips
- Remember to keep your Monoscope project key (`x-api-key`) secure and not expose it in public repositories or logs.