Skip to content

Instrumentations for Go

Instrumentations are plugins for popular frameworks and libraries. They use OpenTelemetry API to record important operations such as HTTP requests, DB queries, logs, errors, and more.

HTTP

net/http

To instrument a handler func:

import (
    "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)

// Your app handler.
var handler http.Handler
handler = http.HandlerFunc(userProfileEndpoint)

// Wrap it with OpenTelemetry plugin.
handler = otelhttp.WithRouteTag("/profiles/:username", handler)
handler = otelhttp.NewHandler(handler, "server-name")

// Register handler.
http.Handle("/profiles/", handler)

func userProfileEndpoint(w http.ResponseWriter, req *http.Request) { ... }

gRPC

Installation:

go get go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc

Client setup outline:

import (
    "google.golang.org/grpc"
    "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
)

tracer := otel.Tracer("github.com/my/repo")

otelInterceptor := grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor(tracer))
conn, err := grpc.Dial("grpc-server:9999", grpc.WithInsecure(), otelInterceptor)

Server setup outline:

import (
    "google.golang.org/grpc"
    "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
)

tracer := otel.Tracer("github.com/my/repo")

otelInterceptor := grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor(tracer))
server := grpc.NewServer(otelInterceptor)

Gin

Installation:

go get go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin

To propagate active span through the app, use context.Context from the http.Request (not gin.Context). To measure HTML template rendering, use otelgin.HTML helper.

import "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"

func main() {
    router := gin.Default()
    router.Use(otelgin.Middleware("service-name"))
    router.GET("/profiles/:username", userProfileEndpoint)
}

func userProfileEndpoint(c *gin.Context) {
    ctx := c.Request.Context()
    // Use request context to propagate active span.
    doSomething(ctx)

    // Use otelgin to instrument HTML generation.
    otelgin.HTML(c, http.StatusOK, "template-name", gin.H{
        "foo": "bar",
    })
}

Echo

Installation:

go get go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho

Setup outline:

import "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho"

func main() {
    r := echo.New()
    r.Use(otelecho.Middleware("service-name"))
}

Beego

Installation:

go get go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego

Setup outline:

import "go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego"

func main() {
    // To enable tracing on template rendering, disable autorender and
    // call otelbeego.Render manually.
    beego.BConfig.WebConfig.AutoRender = false

    mware := otelbeego.NewOTelBeegoMiddleWare("service-name")
    beego.RunWithMiddleWares(":7777", mware)
}

gorilla/mux

Installation:

go get go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux

Setup outline:

import "go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux"

func main() {
    r := mux.NewRouter()
    r.Use(otelmux.Middleware("service-name"))
}

go-restful

Installation:

go get go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful

Setup outline:

import "go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful"

func main() {
    filter := otelrestful.OTelFilter("service-name")
    restful.DefaultContainer.Filter(filter)
}

macaron.v1

Installation:

go get go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron

Setup outline:

import "go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron"

func main() {
    m := macaron.Classic()
    m.Use(otelmacaron.Middleware("service-name"))
    m.Run()
}

Database

go-pg

Installation:

go get github.com/go-pg/pgext

Setup outline:

db := pg.Connect(&pg.Options{
    Addr:     "postgresql-server:5432",
    User:     "postgres",
    Database: "example",
})

db.AddQueryHook(pgext.OpenTelemetryHook{})

mongo-driver

Installation:

go get go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo

Setup outline:

import (
    "go.mongodb.org/mongo-driver/mongo/options"
    "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo"
)

opt := options.Client()
opt.Monitor = otelmongo.NewMonitor("service-name")

go-redis

Installation:

go get github.com/go-redis/redisext

Setup outline:

import "github.com/go-redis/redisext"

rdb := redis.NewClient(&redis.Options{
    Addr: "redis-server:6379",
})
rdb.AddHook(redisext.OpenTelemetryHook{})

gomemcache

Installation:

go get go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache

Setup outline:

import "go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache"

// Wrap memcache client.
mc := otelmemcache.NewClientWithTracing(
    memcache.New("localhost:11211"),
)

func do(ctx context.Context, mc *otelmemcache.Client) {
    // Set context.
    mc = mc.WithContext(ctx)
}

gocql

Installation:

go get go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql

Setup outline:

import (
    "github.com/gocql/gocql"
    "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql"
)

cluster := gocql.NewCluster("localhost")

session, err := otelgocql.NewSessionWithTracing(ctx, cluster)
if err != nil {
    panic(err)
}

Logging

Logrus

Installation:

go get github.com/uptrace/uptrace-go/extra/otellogrus

Logrus instrumentation attaches your logs to the active span as events. You must use logrus.WithContext to propagate the active span.

import (
    "github.com/sirupsen/logrus"
    "github.com/uptrace/uptrace-go/extra/otellogrus"
)

func main() {
    logrus.AddHook(otellogrus.NewLoggingHook())

    // You must use WithContext to propagate the active span.
    logrus.WithContext(ctx).
        WithError(err).
        WithField("foo", "bar").
        Error("something failed")
}