or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

attributes.mdbridges.mdcontext-propagation.mdexporters-other.mdexporters-otlp.mdindex.mdlogging.mdmetrics.mdsdk-log.mdsdk-metric.mdsdk-resource.mdsdk-trace.mdsemantic-conventions.mdtracing.md
tile.json

index.mddocs/

OpenTelemetry Go

OpenTelemetry Go is the official Go implementation of OpenTelemetry, providing a comprehensive set of APIs and SDKs for distributed tracing, metrics collection, and logging. It enables developers to instrument their Go applications to collect, process, and export telemetry data to observability platforms.

Package Information

Package Name: go.opentelemetry.io/otel

Package Type: Library

Latest Version: v1.38.0

Installation:

# Core API
go get go.opentelemetry.io/otel@v1.38.0

# Trace API
go get go.opentelemetry.io/otel/trace@v1.38.0

# Metric API
go get go.opentelemetry.io/otel/metric@v1.38.0

# Log API
go get go.opentelemetry.io/otel/log@v1.38.0

# SDK
go get go.opentelemetry.io/otel/sdk@v1.38.0

# OTLP Exporters
go get go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp@v1.38.0
go get go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp@v1.38.0
go get go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp@v1.38.0

Overview

OpenTelemetry Go consists of multiple modules organized into three main categories:

  1. API Packages: Define interfaces for instrumentation (tracing, metrics, logs)
  2. SDK Packages: Provide concrete implementations of the API interfaces
  3. Exporter Packages: Send telemetry data to various backends (OTLP, Prometheus, Zipkin, etc.)

Project Status

SignalStatus
TracesStable
MetricsStable
LogsBeta

Supported Go Versions

OpenTelemetry Go supports the current and previous two major Go releases (Go 1.23, 1.24, 1.25 as of v1.38.0).

Core Imports

import (
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/trace"
	"go.opentelemetry.io/otel/metric"
	"go.opentelemetry.io/otel/log"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/codes"

	// For internal logging configuration
	"github.com/go-logr/logr"
)

Basic Usage

Complete Example: Tracing, Metrics, and Logs

package main

import (
	"context"
	"log"
	"time"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
	"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
	"go.opentelemetry.io/otel/sdk/metric"
	"go.opentelemetry.io/otel/sdk/resource"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
)

func main() {
	ctx := context.Background()

	// Create resource with service information
	res, err := resource.New(ctx,
		resource.WithAttributes(
			semconv.ServiceName("my-service"),
			semconv.ServiceVersion("1.0.0"),
		),
	)
	if err != nil {
		log.Fatal(err)
	}

	// Setup trace exporter and provider
	traceExporter, err := otlptracehttp.New(ctx)
	if err != nil {
		log.Fatal(err)
	}

	tracerProvider := sdktrace.NewTracerProvider(
		sdktrace.WithBatcher(traceExporter),
		sdktrace.WithResource(res),
	)
	otel.SetTracerProvider(tracerProvider)
	defer tracerProvider.Shutdown(ctx)

	// Setup metric exporter and provider
	metricExporter, err := otlpmetrichttp.New(ctx)
	if err != nil {
		log.Fatal(err)
	}

	meterProvider := metric.NewMeterProvider(
		metric.WithReader(metric.NewPeriodicReader(metricExporter)),
		metric.WithResource(res),
	)
	otel.SetMeterProvider(meterProvider)
	defer meterProvider.Shutdown(ctx)

	// Instrument your application
	tracer := otel.Tracer("my-service")
	meter := otel.Meter("my-service")

	// Create a counter metric
	counter, err := meter.Int64Counter(
		"api.requests",
		metric.WithDescription("Number of API requests"),
		metric.WithUnit("{call}"),
	)
	if err != nil {
		log.Fatal(err)
	}

	// Create a span and record metrics
	ctx, span := tracer.Start(ctx, "operation")
	defer span.End()

	// Add attributes to span
	span.SetAttributes(
		attribute.String("user.id", "12345"),
		attribute.String("operation", "process"),
	)

	// Record metric
	counter.Add(ctx, 1, metric.WithAttributes(
		attribute.String("method", "GET"),
		attribute.String("endpoint", "/api/users"),
	))

	// Simulate work
	time.Sleep(100 * time.Millisecond)
}

Global API Functions

The otel package provides global accessors for setting and retrieving telemetry providers:

// Tracer Provider
func SetTracerProvider(tp trace.TracerProvider)
func GetTracerProvider() trace.TracerProvider
func Tracer(name string, opts ...trace.TracerOption) trace.Tracer

// Meter Provider
func SetMeterProvider(mp metric.MeterProvider)
func GetMeterProvider() metric.MeterProvider
func Meter(name string, opts ...metric.MeterOption) metric.Meter

// Text Map Propagator
func SetTextMapPropagator(propagator propagation.TextMapPropagator)
func GetTextMapPropagator() propagation.TextMapPropagator

// Error Handler
func SetErrorHandler(h ErrorHandler)
func GetErrorHandler() ErrorHandler
func Handle(err error)

// Version
func Version() string

// Internal Logging
func SetLogger(logger logr.Logger)

Capabilities

OpenTelemetry Go provides comprehensive instrumentation capabilities across three signals:

1. Distributed Tracing

Create and manage distributed traces to track requests across services.

Key Features:

  • Span creation and management
  • Context propagation
  • Span attributes, events, and links
  • Multiple sampling strategies
  • Baggage support

Quick Example:

import (
	"context"
	"go.opentelemetry.io/otel"
)

func performWork(ctx context.Context) {
	tracer := otel.Tracer("my-service")
	ctx, span := tracer.Start(ctx, "work-operation")
	defer span.End()

	// Add event to span
	span.AddEvent("processing started")

	// Your work here

	span.AddEvent("processing completed")
}

See Tracing Documentation for complete API reference.

2. Metrics Collection

Collect and aggregate metrics for monitoring application performance.

Key Features:

  • Synchronous instruments (Counter, UpDownCounter, Histogram, Gauge)
  • Asynchronous instruments (ObservableCounter, ObservableUpDownCounter, ObservableGauge)
  • Aggregation and temporality configuration
  • Views for metric customization
  • Multiple exporters (OTLP, Prometheus, stdout)

Quick Example:

import (
	"context"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/metric"
)

func recordMetrics(ctx context.Context) error {
	meter := otel.Meter("my-service")

	// Create counter
	counter, err := meter.Int64Counter(
		"requests.count",
		metric.WithDescription("Total number of requests"),
		metric.WithUnit("{request}"),
	)
	if err != nil {
		return err
	}

	// Record measurement
	counter.Add(ctx, 1, metric.WithAttributes(
		attribute.String("method", "POST"),
	))

	return nil
}

See Metrics Documentation for complete API reference.

3. Logging (Beta)

Emit structured logs integrated with trace and metric context.

Key Features:

  • Structured log records
  • Integration with trace context
  • Log processors and exporters
  • Bridge support for standard logging libraries
  • Filtering and transformation

Quick Example:

import (
	"context"
	"go.opentelemetry.io/otel/log"
	"go.opentelemetry.io/otel/log/global"
)

func emitLog(ctx context.Context) {
	logger := global.GetLoggerProvider().Logger("my-service")

	// Emit log record
	logger.Emit(ctx, log.Record{
		Timestamp:         time.Now(),
		ObservedTimestamp: time.Now(),
		Body:              log.StringValue("User action performed"),
		Severity:          log.SeverityInfo,
		SeverityText:      "INFO",
		Attributes: []log.KeyValue{
			log.String("user.id", "12345"),
			log.String("action", "login"),
		},
	})
}

See Logging Documentation for complete API reference.

4. Context Propagation

Propagate context across service boundaries using W3C standards.

Key Features:

  • W3C Trace Context propagation
  • W3C Baggage propagation
  • Custom propagator support
  • HTTP and gRPC carrier implementations

Quick Example:

import (
	"net/http"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/propagation"
)

func setupPropagation() {
	// Configure composite propagator
	otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
		propagation.TraceContext{},
		propagation.Baggage{},
	))
}

func injectContext(req *http.Request, ctx context.Context) {
	otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(req.Header))
}

func extractContext(req *http.Request) context.Context {
	return otel.GetTextMapPropagator().Extract(req.Context(),
		propagation.HeaderCarrier(req.Header))
}

See Context Propagation Documentation for complete API reference.

5. Attributes

Define and manage key-value attributes for telemetry data enrichment.

Key Features:

  • Type-safe attribute creation
  • Attribute sets and filtering
  • Encoding and serialization
  • Semantic conventions support

See Attributes Documentation for complete API reference.

6. SDK Implementation

The SDK provides concrete implementations of the API interfaces.

Key Features:

  • Trace provider with sampling and batching
  • Metric provider with aggregation
  • Log provider with processing
  • Resource detection
  • Exporters for multiple backends

See:

7. Exporters

Export telemetry data to observability backends.

Available Exporters:

  • OTLP: gRPC and HTTP exporters for traces, metrics, and logs
  • Prometheus: Pull-based metric exporter
  • Zipkin: Distributed tracing backend
  • Stdout: Console output for development/debugging

See:

8. Bridges

Integrate with existing observability systems.

Available Bridges:

  • OpenCensus: Migrate from OpenCensus to OpenTelemetry
  • OpenTracing: Use OpenTelemetry with OpenTracing APIs

See Bridges Documentation for complete API reference.

9. Semantic Conventions

Standard attribute names and values for common operations.

Available Conventions:

  • HTTP attributes
  • Database attributes
  • RPC attributes
  • FaaS attributes
  • Messaging attributes
  • Resource attributes
  • And many more...

See Semantic Conventions Documentation for complete API reference.

Error Handling

OpenTelemetry Go uses a global error handler to report irremediable errors:

import "go.opentelemetry.io/otel"

// Set custom error handler
otel.SetErrorHandler(otel.ErrorHandlerFunc(func(err error) {
	log.Printf("OpenTelemetry error: %v", err)
}))

// Get current error handler
handler := otel.GetErrorHandler()

// Handle an error
otel.Handle(err)

ErrorHandler Interface

type ErrorHandler interface {
	Handle(error)
}

ErrorHandlerFunc

type ErrorHandlerFunc func(error)

func (f ErrorHandlerFunc) Handle(err error) {
	f(err)
}

Internal Logging Configuration

OpenTelemetry uses internal logging to report non-critical issues and debug information. By default, it uses a no-op logger. You can configure a custom logger using logr-compatible implementations:

import (
	"go.opentelemetry.io/otel"
	"github.com/go-logr/logr"
	"github.com/go-logr/zapr"
	"go.uber.org/zap"
)

func main() {
	// Configure zap logger
	zapLogger, _ := zap.NewDevelopment()
	otel.SetLogger(zapr.NewLogger(zapLogger))

	// Now OpenTelemetry internal logs will use your logger
}

Note: This is separate from the application-level logging signal (go.opentelemetry.io/otel/log). SetLogger configures how OpenTelemetry itself logs its internal operations, while the log API is for instrumenting your application's logs.

Architecture

OpenTelemetry Go follows a layered architecture:

Application Code
       |
       v
  API Layer (Interfaces)
       |
       v
  SDK Layer (Implementation)
       |
       v
  Exporters (Backends)

API Layer: Defines interfaces for instrumentation (trace.TracerProvider, metric.MeterProvider, log.LoggerProvider)

SDK Layer: Provides default implementations with batching, sampling, and processing

Exporters: Send data to observability backends

Best Practices

1. Use Global Providers

Set up global providers once during application initialization:

func main() {
	ctx := context.Background()

	// Setup providers
	tp := setupTracerProvider(ctx)
	defer tp.Shutdown(ctx)
	otel.SetTracerProvider(tp)

	mp := setupMeterProvider(ctx)
	defer mp.Shutdown(ctx)
	otel.SetMeterProvider(mp)

	// Run application
	run()
}

2. Name Your Instrumentations

Use descriptive names for tracers and meters:

// Good: Package-specific name
tracer := otel.Tracer("github.com/myorg/myapp/database")

// Bad: Generic name
tracer := otel.Tracer("tracer")

3. Use Context Everywhere

Pass context through your call chain to maintain trace correlation:

func handler(ctx context.Context) {
	ctx, span := tracer.Start(ctx, "handler")
	defer span.End()

	// Pass context to downstream calls
	processRequest(ctx)
}

func processRequest(ctx context.Context) {
	ctx, span := tracer.Start(ctx, "processRequest")
	defer span.End()

	// Work happens here
}

4. Defer Span End

Always defer span.End() immediately after starting a span:

ctx, span := tracer.Start(ctx, "operation")
defer span.End()

// Your code here

5. Add Meaningful Attributes

Use semantic conventions when available:

import semconv "go.opentelemetry.io/otel/semconv/v1.37.0"

span.SetAttributes(
	semconv.HTTPMethod("GET"),
	semconv.HTTPStatusCode(200),
	semconv.HTTPRoute("/api/users/:id"),
)

6. Handle Errors Properly

Record errors in spans when they occur:

import (
	"go.opentelemetry.io/otel/codes"
	"go.opentelemetry.io/otel/trace"
)

func operation(ctx context.Context) error {
	ctx, span := tracer.Start(ctx, "operation")
	defer span.End()

	result, err := doWork()
	if err != nil {
		span.RecordError(err)
		span.SetStatus(codes.Error, err.Error())
		return err
	}

	return nil
}

7. Resource Configuration

Define resources to identify your service:

import (
	"go.opentelemetry.io/otel/sdk/resource"
	semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
)

res, err := resource.New(ctx,
	resource.WithAttributes(
		semconv.ServiceName("my-service"),
		semconv.ServiceVersion("1.0.0"),
		semconv.ServiceInstanceID("instance-1"),
	),
	resource.WithProcess(),
	resource.WithHost(),
	resource.WithOS(),
)

Common Patterns

HTTP Server Instrumentation

import (
	"net/http"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/codes"
	semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
)

func instrumentedHandler(w http.ResponseWriter, r *http.Request) {
	tracer := otel.Tracer("http-server")

	// Extract context from incoming request
	ctx := otel.GetTextMapPropagator().Extract(
		r.Context(),
		propagation.HeaderCarrier(r.Header),
	)

	// Start span
	ctx, span := tracer.Start(ctx, r.URL.Path)
	defer span.End()

	// Add HTTP attributes
	span.SetAttributes(
		semconv.HTTPMethod(r.Method),
		semconv.HTTPRoute(r.URL.Path),
		semconv.HTTPScheme(r.URL.Scheme),
	)

	// Handle request
	statusCode := http.StatusOK
	// ... your handler logic ...

	// Record response
	span.SetAttributes(semconv.HTTPStatusCode(statusCode))
	if statusCode >= 400 {
		span.SetStatus(codes.Error, "HTTP error")
	}

	w.WriteHeader(statusCode)
}

HTTP Client Instrumentation

func makeRequest(ctx context.Context, url string) error {
	tracer := otel.Tracer("http-client")

	ctx, span := tracer.Start(ctx, "HTTP GET")
	defer span.End()

	req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
	if err != nil {
		span.RecordError(err)
		return err
	}

	// Inject context into request
	otel.GetTextMapPropagator().Inject(ctx,
		propagation.HeaderCarrier(req.Header))

	// Add attributes
	span.SetAttributes(
		semconv.HTTPMethod(req.Method),
		semconv.HTTPURL(url),
	)

	// Make request
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		span.RecordError(err)
		span.SetStatus(codes.Error, err.Error())
		return err
	}
	defer resp.Body.Close()

	span.SetAttributes(semconv.HTTPStatusCode(resp.StatusCode))
	return nil
}

Database Operation Tracing

func queryDatabase(ctx context.Context, query string) error {
	tracer := otel.Tracer("database")

	ctx, span := tracer.Start(ctx, "db.query")
	defer span.End()

	span.SetAttributes(
		semconv.DBSystem("postgresql"),
		semconv.DBStatement(query),
		semconv.DBName("users"),
	)

	// Execute query
	result, err := db.QueryContext(ctx, query)
	if err != nil {
		span.RecordError(err)
		span.SetStatus(codes.Error, err.Error())
		return err
	}
	defer result.Close()

	return nil
}

Documentation Structure

This documentation is organized into the following sections:

  • Tracing: Complete trace API including Tracer, Span, SpanContext, and more
  • Metrics: Complete metric API including instruments, observers, and aggregation
  • Logging: Log API for structured logging with OpenTelemetry integration
  • Context Propagation: Baggage, propagation, and context management
  • Attributes: Attribute handling, types, and encoding
  • SDK Trace: SDK implementation for distributed tracing
  • SDK Metric: SDK implementation for metrics collection
  • SDK Log: SDK implementation for logging
  • SDK Resource: Resource detection and configuration
  • OTLP Exporters: OTLP protocol exporters for all signals
  • Other Exporters: Prometheus, Zipkin, stdout exporters
  • Bridges: OpenCensus and OpenTracing integration
  • Semantic Conventions: Standard attributes and naming conventions

Additional Resources

Support