OpenTelemetry Plugin
The otel
plugin is a Goa plugin that instruments
HTTP endpoints with OpenTelemetry configuring it with the endpoint route pattern. This
plugin is used in conjunction with the Clue project to
instrument services with OpenTelemetry.
Usage
Simply import the plugin in the service design package. Use the blank identifier _
as explicit
package name:
package design
import . "goa.design/goa/v3/dsl"
import _ "goa.design/plugins/v3/otel" # Enables the otel plugin
var _ = API("...
and generate as usual:
goa gen PACKAGE
where PACKAGE
is the Go import path of the design package.
Effects of the Plugin
Importing the otel
package changes the behavior of the gen
command of the
goa
tool. The gen
command output is modified so that the generated HTTP
handlers are wrapped with a call to the otelhttp.WithRouteTag
.
That is the code generated in gen/http/<service>/server/server.go
that
mounts an endpoint handler onto the HTTP mux changes from:
mux.Handle("<VERB>", "<PATH>", f)
to:
mux.Handle("<VERB>", otelhttp.WithRouteTag("<PATH>", f).ServeHTTP))
OpenTelemetry Configuration
For the code generated by the plugin to work the OpenTelemetry SDK must be
initialized. This can be done by importing the clue
package and calling
clue.ConfigureOpenTelemetry
in the main
function of the service:
package main
import (
"context"
"net/http"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel/exporters/stdout/stdoutmetric"
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
"goa.design/clue/clue"
"goa.design/clue/log"
)
func main() {
// Create OpenTelemetry metric and span exporters
// Use stdout exporters for demo.
metricExporter, err := stdoutmetric.New()
if err != nil {
panic(err)
}
spanExporter, err := stdouttrace.New()
if err != nil {
panic(err)
}
// Configure OpenTelemetry.
ctx := log.Context(context.Background())
cfg, err := clue.NewConfig(ctx, "service", "1.0.0", metricExporter, spanExporter)
if err != nil {
panic(err)
}
clue.ConfigureOpenTelemetry(ctx, cfg)
// Create HTTP handler and start server.
var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, World!"))
})
handler = otelhttp.NewHandler(handler, "service") // Instrument handler.
http.ListenAndServe(":8080", handler)
}