49
loading...
This website collects cookies to deliver better user experience
OpenTelemetry is a set of APIs, SDKs, tooling and integrations that are designed for the creation and management of telemetry data such as traces, metrics, and logs. The project provides a vendor-agnostic implementation that can be configured to send telemetry data to the backend(s) of your choice.
OpenTelemetry
was the indirect result of observability, where the need to monitor multiple services written in different technologies made harder to collect and aggregate observability data.OpenTelemetry
does not provide concrete observability backends but rather a standard way to configure, emit, collect, process and export telemetry data; there are commercially-supported options for those backends, like NewRelic and Lightstep, as well as some Open Source projects that can be used with it, for this post I'm covering specifically:OpenTelemetry
status regarding the support in Go:The code used for this post is available on Github.
promExporter, _ := prometheus.NewExportPipeline(prometheus.Config{}) // XXX: error omitted for brevity
global.SetMeterProvider(promExporter.MeterProvider())
http.Handler
, so we can define it as another endpoint part of our HTTP Server, which then Prometheus will be using for polling metric values:r := mux.NewRouter()
r.Handle("/metrics", promExporter)
scrape_configs:
- job_name: to-do-api
scrape_interval: 5s
static_configs:
- targets: ['host.docker.internal:9234']
http://localhost:9090/
should display a user interface like the following after typing a metric and selecting it:jaegerEndpoint, _ := conf.Get("JAEGER_ENDPOINT")
jaegerExporter, _ := jaeger.NewRawExporter(
jaeger.WithCollectorEndpoint(jaegerEndpoint),
jaeger.WithSDKOptions(sdktrace.WithSampler(sdktrace.AlwaysSample())),
jaeger.WithProcessFromEnv(),
) // XXX: error omitted for brevity
tp := sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithSyncer(jaegerExporter),
)
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
postgresql
package each method of each type defines instructions like the following:ctx, span := trace.SpanFromContext(ctx).Tracer().Start(ctx, "<name>")
// If needed: N calls to "span.SetAttributes(...)"
defer span.End()
postgres.Task.Create
, we have:ctx, span := trace.SpanFromContext(ctx).Tracer().Start(ctx, "Task.Create")
span.SetAttributes(attribute.String("db.system", "postgresql"))
defer span.End()
OpenTelemetry
specification defines a few conventions regarding attribute names and supported values, so the attribute db.system
we used above is part of the Database conventions; in some cases the go.opentelemetry.io/otel/semconv
package defines constants we can use, but this is not always the case so keep an eye out.service.Task.Create
method does the following:ctx, span := trace.SpanFromContext(ctx).Tracer().Start(ctx, "Task.Create")
defer span.End()
http://localhost:16686/search
should display a user interface like the following:OpenTelemetry
and spans is that if there are interactions that include other OpenTelemetry-enabled calls, we could join them to see the full interaction between all of them.OpenTelemetry
does not support logs in Go yet, logging certain messages should be considered when Building Microservices; the approach I like to recommend is to define a logger instance and then when needed pass it around as an argument when initializating concrete types, the package we are going to be using is uber-go/zap
.logger, _ := zap.NewProduction()
defer logger.Sync()
middleware := func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
logger.Info(r.Method,
zap.Time("time", time.Now()),
zap.String("url", r.URL.String()),
)
h.ServeHTTP(w, r)
})
}
srv := &http.Server{
Handler: middleware(r),
// ... other fields ...
}
OpenTelemetry
, for Go specifically, is a work in progress, it's definitely a good idea but it is hard to keep your own code up to date with the minor releases, because those happen to break API from time to time. For long running projects I'd recommend to wait until a major version is released, otherwise finding a non-OpenTelemetry option may make more sense.