otelkit-go provides a small reusable OpenTelemetry bootstrap layer for Coordimap Go microservices. It keeps to standard OpenTelemetry Go packages, supports standard environment-variable configuration, and adds thin helpers for HTTP, gRPC, NATS, Redis, and database/sql instrumentation.
go get github.com/coordimap/otelkit-gootelkit: env-based config, provider bootstrap, shutdown, tracer and meter accessorshttpotel: inbound HTTP middleware and outbound HTTP client helpersgrpcotel: gRPC client and server interceptorsnatsotel: NATS header propagation helpersredisotel: thingo-redis/v9tracing and metrics helperssqlotel: thindatabase/sqlwrappers backed bygithub.com/XSAM/otelsql
OTEL_SERVICE_NAMEOTEL_RESOURCE_ATTRIBUTESOTEL_EXPORTER_OTLP_ENDPOINTOTEL_EXPORTER_OTLP_PROTOCOLOTEL_EXPORTER_OTLP_HEADERSOTEL_TRACES_EXPORTEROTEL_METRICS_EXPORTEROTEL_LOGS_EXPORTEROTELKIT_SQLOTEL_SPAN_PRESETOTEL_PROPAGATORSOTEL_TRACES_SAMPLEROTEL_TRACES_SAMPLER_ARG
Supported exporter values:
otlpnone
Supported OTLP protocols:
grpchttp/protobuf
Supported SQL span presets:
reducednone
Supported propagators:
tracecontextbaggageb3b3multijaegerxraynone
Supported samplers:
always_onalways_offtraceidratioparentbased_always_onparentbased_always_offparentbased_traceidratio
ctx := context.Background()
tel, err := otelkit.New(ctx)
if err != nil {
return err
}
defer tel.Shutdown(context.Background())
tracer := tel.Tracer("coordimap.api")
meter := tel.Meter("coordimap.api")
_ = tracer
_ = meterotelkit.New loads config from standard OpenTelemetry env vars, initializes trace/metric/log providers, installs them as globals by default, and returns explicit ForceFlush and Shutdown hooks for main().
OTEL_RESOURCE_ATTRIBUTES is parsed into resource attributes and merged with detected process, host, OS, and telemetry SDK metadata.
- detected resource attributes are loaded first
- env resource attributes override detected values
OTEL_SERVICE_NAMEoverrides anyservice.namepresent inOTEL_RESOURCE_ATTRIBUTES- extra resource options passed through
otelkit.WithResourceOptions(...)are merged last
Example:
export OTEL_SERVICE_NAME=coordimap-api
export OTEL_RESOURCE_ATTRIBUTES=service.name=legacy-name,deployment.environment=staging,team=platformThe effective service.name becomes coordimap-api.
Runnable examples live under examples/:
examples/http-serviceexamples/grpc-serviceexamples/http-clientexamples/nats-propagationexamples/redis-client
Example OTLP HTTP collector configuration:
export OTEL_SERVICE_NAME=coordimap-api
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
go run ./examples/http-servicemux := http.NewServeMux()
mux.Handle("/hello", httpotel.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte("hello"))
}), "hello"))server := grpc.NewServer(
grpc.UnaryInterceptor(grpcotel.UnaryServerInterceptor()),
)client := httpotel.NewClient(nil)
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, upstreamURL, nil)
resp, err := client.Do(req)msg := &nats.Msg{Subject: "coordimap.events", Header: nats.Header{}}
msg.Header = natsotel.Inject(ctx, msg.Header)
consumerCtx := natsotel.Extract(context.Background(), msg.Header)client := redis.NewClient(&redis.Options{Addr: "localhost:6379"})
if err := redisotel.InstrumentTracingReducedNoise(client); err != nil {
return err
}
if err := client.Set(ctx, "coordimap", "otelkit", 0).Err(); err != nil {
return err
}redisotel.InstrumentTracingReducedNoise(...) disables raw command statements, caller metadata, and dial spans, and filters low-value commands like PING and CLIENT.
db, err := sqlotel.Open(
"postgres",
dsn,
sqlotel.WithDBSystem("postgresql"),
sqlotel.WithDBName("asset_repository"),
sqlotel.WithServerAddress("postgres:5432"),
sqlotel.WithReducedSpanNoise(),
)
if err != nil {
return err
}
defer db.Close()sqlotel.Open(...), sqlotel.OpenDB(...), and sqlotel.Register(...) apply sqlotel.WithReducedSpanNoise() by default. You can still tune SQL span volume further with sqlotel.WithSpanOptions(...) or sqlotel.WithSpanFilter(...).
To override the default globally, set:
export OTELKIT_SQLOTEL_SPAN_PRESET=noneUse reduced to keep the default behavior explicit, or none to disable the built-in noise reduction. Explicit options passed to sqlotel.Open(...), sqlotel.OpenDB(...), or sqlotel.Register(...) can still override the defaults.
The package does not hard-code Coordimap resource fields, exporters, or interceptors. Any Coordimap-specific behavior stays optional and injectable:
tel, err := otelkit.New(
ctx,
otelkit.WithResourceOptions(resource.WithAttributes(
attribute.String("coordimap.cluster", clusterName),
attribute.String("coordimap.region", region),
)),
)You can also skip global installation with otelkit.WithoutGlobals() and wire providers explicitly.
- Remove service-local tracer provider bootstrap code and OTLP exporter setup.
- Add
otelkit.New(ctx)during process startup. - Replace direct
otelhttporotelgrpcimports withhttpotelandgrpcotelhelpers where convenient. - Replace
sql.Open(...)withsqlotel.Open(...)for instrumenteddatabase/sqlconnections. - Use
tel.Tracer("service-name")andtel.Meter("service-name")instead of building providers manually. - Defer
tel.Shutdown(context.Background())inmain(). - Move collector configuration to env vars.
Minimal startup snippet:
func main() {
ctx := context.Background()
tel, err := otelkit.New(ctx)
if err != nil {
log.Fatalf("init telemetry: %v", err)
}
defer func() {
_ = tel.Shutdown(context.Background())
}()
tracer := tel.Tracer("coordimap.api")
_ = tracer
}- Set
OTEL_SERVICE_NAMEin each service deployment. - Set collector env vars once per service or shared workload template.
- Replace existing HTTP transport wrapping with
httpotel.NewClient(nil)orhttpotel.NewTransport(...). - Replace gRPC interceptor wiring with
grpcotel.UnaryServerInterceptor()andgrpcotel.UnaryClientInterceptor(). - Inject or extract NATS headers with
natsotel.Injectandnatsotel.Extractaround publish and consume code. - Instrument Redis clients with
redisotel.InstrumentTracing(...)anywhere services usego-redis/v9. - Swap
sql.Open(...)calls tosqlotel.Open(...)anywhere services usedatabase/sqldirectly.
- Only standard OTLP exporters are enabled; per-signal protocol overrides are not yet added.
- Sampler support is intentionally limited to the common standard samplers.
- The package initializes log exporters but leaves application log bridge choice to each service.
- A future version could add richer metric reader tuning, per-signal OTLP env overrides, and optional semantic-convention presets for Coordimap services.