Manually instrument a Go application using OpenTelemetry and Applicare

Install the following packages:

go get "go.opentelemetry.io/otel" \
  "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" \
  "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" \
  "go.opentelemetry.io/otel/exporters/stdout/stdoutlog" \
  "go.opentelemetry.io/otel/sdk/log" \
  "go.opentelemetry.io/otel/log/global" \
  "go.opentelemetry.io/otel/propagation" \
  "go.opentelemetry.io/otel/sdk/metric" \
  "go.opentelemetry.io/otel/sdk/resource" \
  "go.opentelemetry.io/otel/sdk/trace" \
  "go.opentelemetry.io/otel/semconv/v1.24.0" \
  "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"\
  "go.opentelemetry.io/contrib/bridges/otelslog"

This installs the OpenTelemetry SDK components and net/http instrumentation.

Add the following packages to your Go application:

import (
	"context"
	"fmt"
	"net"
	"os"
	"os/signal"
        "time"
	"net/http"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"go.opentelemetry.io/otel"

	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/sdk/resource"

         semconv "go.opentelemetry.io/otel/semconv/v1.25.0"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
	"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)

You need to wrap the HTTP handlers with instrumented code.

var serviceName = semconv.ServiceNameKey.String(<APPLICARE_AGENT_NAME>)

func initConn() (*grpc.ClientConn, error) {
    conn, err := grpc.NewClient("localhost:4317",
        grpc.WithTransportCredentials(insecure.NewCredentials()),
    )
    if err != nil {
        return nil, fmt.Errorf("failed to create gRPC connection to collector: %w", err)
    }
    return conn, err
}

func initTracerProvider(ctx context.Context, res *resource.Resource, conn *grpc.ClientConn) (func(context.Context) error, error) {
 traceExporter, err := otlptracegrpc.New(ctx, otlptracegrpc.WithGRPCConn(conn))
    if err != nil {
        return nil, fmt.Errorf("failed to create trace exporter: %w", err)
    }
    bsp := sdktrace.NewBatchSpanProcessor(traceExporter)
    tracerProvider := sdktrace.NewTracerProvider(
        sdktrace.WithSampler(sdktrace.AlwaysSample()),
        sdktrace.WithResource(res),
        sdktrace.WithSpanProcessor(bsp),
    )
    otel.SetTracerProvider(tracerProvider)
    otel.SetTextMapPropagator(propagation.TraceContext{})
    return tracerProvider.Shutdown, nil
}

func main() {
    if err := run(); err != nil {
        log.Fatalln(err)
    }
}

func run() (err error) {
    ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
    defer stop()

    conn, err := initConn()

    if err != nil {
        log.Fatal(err)
    }

    res, err := resource.New(ctx,
        resource.WithAttributes(
            serviceName,
        ),
    )

    if err != nil {
        log.Fatal(err)
    }

    shutdownTracerProvider, err := initTracerProvider(ctx, res, conn)

    if err != nil {
        log.Fatal(err)
    }

    defer func() {
        if err := shutdownTracerProvider(ctx); err != nil {
            log.Fatalf("failed to shutdown TracerProvider: %s", err)
        }
    }()

 // Start HTTP server.
    srv := &http.Server{
        Addr:         ":8080",
        BaseContext:  func(_ net.Listener) context.Context { return ctx },
        ReadTimeout:  time.Second,
        WriteTimeout: 10 * time.Second,
        Handler:      newHTTPHandler(),
    }

    srvErr := make(chan error, 1)
        go func() {
        srvErr <- srv.ListenAndServe()
    }()

    select {
        case err = <-srvErr:
        return
        case <-ctx.Done():
        stop()
    }

    err = srv.Shutdown(context.Background())
    return
}

   func newHTTPHandler() http.Handler {
       mux := http.NewServeMux()
       handleFunc := func(pattern string, handlerFunc func(http.ResponseWriter, *http.Request)) {
        handler := otelhttp.WithRouteTag(pattern, http.HandlerFunc(handlerFunc))
        mux.Handle(pattern, handler)
    }

   // your handler function here ..........
   // ...........

    handler := otelhttp.NewHandler(mux, "/")
    return handler
}

Was this article helpful?

Votes, comments and follows are kept by Zendesk, so they need a Help Center account. These buttons open this article there.

Opens Zendesk · needs internet and sign-in

Still stuck? Contact support