otel

package module
v0.6.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 19, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Overview

Package otel provides OpenTelemetry integration for distributed tracing, metrics, and logging correlation in Tjo applications.

Usage:

provider, err := otel.New(otel.Config{
    ServiceName: "my-app",
    Endpoint:    "localhost:4317",
})
if err != nil {
    log.Fatal(err)
}
defer provider.Shutdown(context.Background())

// Use middleware
router.Use(provider.Middleware())

Package otel provides OpenTelemetry integration for Tjo applications.

Overview

This package enables distributed tracing, metrics collection, and log correlation using the OpenTelemetry standard. It integrates seamlessly with Tjo's existing logging and metrics infrastructure.

Quick Start

// Create provider
provider, err := otel.New(otel.Config{
    ServiceName: "my-app",
    Endpoint:    "localhost:4317",
    Insecure:    true, // For local development
})
if err != nil {
    log.Fatal(err)
}
defer provider.Shutdown(context.Background())

// Add middleware to your router
router.Use(provider.Middleware())

Tracing HTTP Requests

The middleware automatically creates spans for all HTTP requests:

router.Use(provider.Middleware())
// All requests now have:
// - Automatic span creation
// - Request attributes (method, URL, status, etc.)
// - Context propagation
// - X-Trace-ID response header

Custom Spans

Create custom spans for operations within your handlers:

func (h *Handler) ProcessOrder(w http.ResponseWriter, r *http.Request) {
    ctx, span := otel.Start(r.Context(), "process_order")
    defer span.End()

    // Add attributes
    otel.SetAttributes(ctx,
        otel.String("order.id", orderID),
        otel.Int("order.items", len(items)),
    )

    // Add events
    otel.AddEvent(ctx, "validation_complete")

    // Record errors
    if err != nil {
        otel.RecordError(ctx, err)
    }
}

Database Tracing

Wrap your database connection for automatic query tracing:

tracedDB := otel.WrapDB(db, "postgres", "myapp")
rows, err := tracedDB.Query(ctx, "SELECT * FROM users WHERE id = ?", userID)

Log Correlation

Add trace context to your logs:

logger := otel.LoggerWithTrace(ctx, g.Logging.Logger)
logger.Info("Processing request", nil)
// Logs include trace_id and span_id fields

Or add trace fields manually:

g.Logging.Logger.Info("Processing", otel.TraceFields(ctx))

Exporters

The package supports three exporters:

  • OTLP (recommended): Works with any OpenTelemetry Collector, Jaeger, etc.
  • Zipkin: Direct export to Zipkin
  • None: Disables export (useful for testing)

Example with OTLP:

provider, _ := otel.New(otel.Config{
    ServiceName: "my-app",
    Exporter:    otel.ExporterOTLP,
    Endpoint:    "localhost:4317",
})

Sampling

Control trace sampling to reduce overhead:

// Sample all traces (default, good for development)
Sampler: otel.SamplerAlways

// Sample 10% of traces (good for high-traffic production)
Sampler: otel.SamplerRatio
SampleRatio: 0.1

// Respect parent span's sampling decision
Sampler: otel.SamplerParentBased

Environment Configuration

Set these environment variables for configuration:

OTEL_ENABLED=true
OTEL_SERVICE_NAME=my-app
OTEL_SERVICE_VERSION=1.0.0
OTEL_EXPORTER=otlp
OTEL_ENDPOINT=localhost:4317
OTEL_INSECURE=true
OTEL_SAMPLER=ratio
OTEL_SAMPLE_RATIO=0.1

Local Development with Jaeger

Run Jaeger locally with Docker:

docker run -d --name jaeger \
  -p 16686:16686 \
  -p 4317:4317 \
  jaegertracing/all-in-one:latest

Then view traces at http://localhost:16686

Index

Constants

This section is empty.

Variables

View Source
var (
	String  = attribute.String
	Int     = attribute.Int
	Int64   = attribute.Int64
	Float64 = attribute.Float64
	Bool    = attribute.Bool
)

Attr is a convenience function to create attributes.

Functions

func AddCallerInfo

func AddCallerInfo(ctx context.Context)

AddCallerInfo adds source location as span attributes.

func AddEvent

func AddEvent(ctx context.Context, name string, attrs ...attribute.KeyValue)

AddEvent adds an event to the current span.

func CallerInfo

func CallerInfo(skip int) (file string, line int, function string)

CallerInfo returns file and line information for the caller. Useful for adding source location to spans.

func DBAttributes

func DBAttributes(system, name, statement string) []attribute.KeyValue

DBAttributes returns common database span attributes.

func ErrorEvent

func ErrorEvent(err error) (string, []attribute.KeyValue)

ErrorEvent creates a standard error event.

func HTTPClientAttributes

func HTTPClientAttributes(method, url string, statusCode int) []attribute.KeyValue

HTTPClientAttributes returns common HTTP client span attributes.

func LoggerWithTrace

func LoggerWithTrace(ctx context.Context, logger *logging.Logger) *logging.Logger

LoggerWithTrace returns a logger with trace context fields added. This enables log correlation with traces.

Usage:

logger := otel.LoggerWithTrace(ctx, g.Logging.Logger)
logger.Info("Processing request", nil)
// Logs will include trace_id and span_id fields

func MergeFields

func MergeFields(ctx context.Context, additional map[string]interface{}) map[string]interface{}

MergeFields merges trace fields with additional fields.

func MessagingAttributes

func MessagingAttributes(system, destination, operation string) []attribute.KeyValue

MessagingAttributes returns common messaging span attributes.

func MetricsMiddleware

func MetricsMiddleware(metrics *logging.ApplicationMetrics) func(http.Handler) http.Handler

MetricsMiddleware returns a middleware that records HTTP metrics. It integrates with Tjo's existing metrics system.

func Middleware

func Middleware(serviceName string) func(http.Handler) http.Handler

MiddlewareFunc is a convenience type for middleware without a provider. Use this when you want to use the global tracer.

func RecordDuration

func RecordDuration(histogram *logging.Histogram, start time.Time)

RecordDuration is a helper to record operation duration.

func RecordError

func RecordError(ctx context.Context, err error, opts ...trace.EventOption)

RecordError records an error on the current span. The error is recorded as an event and the span status is set to Error.

func SetAttributes

func SetAttributes(ctx context.Context, attrs ...attribute.KeyValue)

SetAttributes sets attributes on the current span.

func SetStatus

func SetStatus(ctx context.Context, code codes.Code, description string)

SetStatus sets the status of the current span.

func SpanFromContext

func SpanFromContext(ctx context.Context) trace.Span

SpanFromContext returns the current span from the context. Returns a no-op span if no span is present.

func SpanIDFromContext

func SpanIDFromContext(ctx context.Context) string

SpanIDFromContext extracts the span ID from the context. Returns an empty string if no span is active.

func Start

func Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span)

Start creates a new span with the given name. It returns the updated context and the span. Remember to call span.End() when the operation is complete.

Usage:

ctx, span := otel.Start(ctx, "operation_name")
defer span.End()

func StartWithTracer

func StartWithTracer(ctx context.Context, tracer trace.Tracer, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span)

StartWithTracer creates a new span using the specified tracer.

func TraceFields

func TraceFields(ctx context.Context) map[string]interface{}

TraceFields returns log fields with trace context. Use this when you want to add trace context to a log call.

Usage:

logger.Info("Processing", otel.TraceFields(ctx))

func TraceIDFromContext

func TraceIDFromContext(ctx context.Context) string

TraceIDFromContext extracts the trace ID from the context. Returns an empty string if no trace is active.

func WithSpan

func WithSpan(ctx context.Context, name string, fn func(context.Context) error, opts ...trace.SpanStartOption) error

WithSpan executes a function within a new span. The span is automatically ended when the function returns. If the function returns an error, it is recorded on the span.

Usage:

err := otel.WithSpan(ctx, "process_data", func(ctx context.Context) error {
    // Your code here
    return nil
})

func WithSpanResult

func WithSpanResult[T any](ctx context.Context, name string, fn func(context.Context) (T, error), opts ...trace.SpanStartOption) (T, error)

WithSpanResult executes a function within a new span and returns both result and error. Useful when you need to return a value from the traced operation.

Types

type Config

type Config struct {
	// ServiceName identifies this service in traces. Required.
	ServiceName string

	// ServiceVersion is the version of this service (optional).
	ServiceVersion string

	// Environment identifies the deployment environment (e.g., "production", "staging").
	Environment string

	// Endpoint is the collector endpoint (e.g., "localhost:4317" for OTLP).
	// Required unless Exporter is ExporterNone.
	Endpoint string

	// Exporter selects the telemetry exporter. Defaults to OTLP.
	Exporter ExporterType

	// Insecure disables TLS for the exporter connection.
	// Set to true for local development.
	Insecure bool

	// Sampler selects the sampling strategy. Defaults to SamplerAlways.
	Sampler SamplerType

	// SampleRatio is the sampling ratio when Sampler is SamplerRatio.
	// Value between 0.0 and 1.0. Defaults to 1.0.
	SampleRatio float64

	// EnableMetrics enables OpenTelemetry metrics collection.
	// Metrics are exported alongside traces.
	EnableMetrics bool

	// EnableTracing enables distributed tracing. Defaults to true.
	EnableTracing bool

	// Headers are additional headers to send with exports (e.g., authentication).
	Headers map[string]string

	// ResourceAttributes are additional attributes to add to all spans.
	ResourceAttributes map[string]string

	// PropagateB3 enables B3 propagation format (used by Zipkin).
	// By default, W3C TraceContext is used.
	PropagateB3 bool
}

Config holds OpenTelemetry configuration.

func (*Config) String

func (c *Config) String() string

String returns a human-readable representation of the config.

func (*Config) Validate

func (c *Config) Validate() error

Validate checks that the configuration is valid.

type ExporterType

type ExporterType string

ExporterType defines the telemetry exporter to use.

const (
	// ExporterOTLP exports to an OTLP-compatible collector (recommended).
	ExporterOTLP ExporterType = "otlp"
	// ExporterJaeger exports directly to Jaeger.
	ExporterJaeger ExporterType = "jaeger"
	// ExporterZipkin exports directly to Zipkin.
	ExporterZipkin ExporterType = "zipkin"
	// ExporterNone disables exporting (useful for testing).
	ExporterNone ExporterType = "none"
)

type HTTPRequestMetrics

type HTTPRequestMetrics struct {
	// contains filtered or unexported fields
}

HTTPRequestMetrics records metrics for an HTTP request. Use this when you need manual control over metric recording.

func StartRequest

func StartRequest(metrics *logging.ApplicationMetrics, method, path string) *HTTPRequestMetrics

StartRequest begins tracking metrics for an HTTP request.

func (*HTTPRequestMetrics) End

func (m *HTTPRequestMetrics) End(statusCode int)

End completes the metric recording for the request.

type LogContext

type LogContext struct {
	// contains filtered or unexported fields
}

LogContext provides logging methods that automatically include trace context.

func NewLogContext

func NewLogContext(ctx context.Context, logger *logging.Logger) *LogContext

NewLogContext creates a new LogContext.

func (*LogContext) Debug

func (l *LogContext) Debug(message string, fields ...map[string]interface{})

Debug logs a debug message with trace context.

func (*LogContext) Error

func (l *LogContext) Error(message string, fields ...map[string]interface{})

Error logs an error message with trace context.

func (*LogContext) Info

func (l *LogContext) Info(message string, fields ...map[string]interface{})

Info logs an info message with trace context.

func (*LogContext) Trace

func (l *LogContext) Trace(message string, fields ...map[string]interface{})

Trace logs a trace message with trace context.

func (*LogContext) Warn

func (l *LogContext) Warn(message string, fields ...map[string]interface{})

Warn logs a warning message with trace context.

func (*LogContext) WithField

func (l *LogContext) WithField(key string, value interface{}) *LogContext

WithField adds a field and returns a new LogContext.

func (*LogContext) WithFields

func (l *LogContext) WithFields(fields map[string]interface{}) *LogContext

WithFields adds fields and returns a new LogContext.

type MetricsRecorder

type MetricsRecorder struct {
	// contains filtered or unexported fields
}

MetricsRecorder provides a simple interface for recording custom metrics.

func NewMetricsRecorder

func NewMetricsRecorder(registry *logging.MetricRegistry) *MetricsRecorder

NewMetricsRecorder creates a new metrics recorder.

func (*MetricsRecorder) Add

func (r *MetricsRecorder) Add(name string, delta int64)

Add adds to a counter by name.

func (*MetricsRecorder) Counter

func (r *MetricsRecorder) Counter(name string) *logging.Counter

Counter gets or creates a counter by name.

func (*MetricsRecorder) Gauge

func (r *MetricsRecorder) Gauge(name string) *logging.Gauge

Gauge gets or creates a gauge by name.

func (*MetricsRecorder) Histogram

func (r *MetricsRecorder) Histogram(name string) *logging.Histogram

Histogram gets or creates a histogram by name.

func (*MetricsRecorder) Inc

func (r *MetricsRecorder) Inc(name string)

Inc increments a counter by name.

func (*MetricsRecorder) Observe

func (r *MetricsRecorder) Observe(name string, value float64)

Observe records a histogram observation by name.

func (*MetricsRecorder) Set

func (r *MetricsRecorder) Set(name string, value int64)

Set sets a gauge by name.

func (*MetricsRecorder) TimeSince

func (r *MetricsRecorder) TimeSince(name string, start time.Time)

TimeSince records the duration since start as a histogram observation.

type Module

type Module struct {
	Provider *Provider
	// contains filtered or unexported fields
}

Module implements the tjo.Module interface for OpenTelemetry functionality. Use this to opt-in to distributed tracing in your application.

Example:

app := tjo.Tjo{}
app.New(rootPath, otel.NewModule(
    otel.WithServiceName("my-app"),
    otel.WithOTLPExporter("localhost:4317"),
))

// Later, use the provider:
if otelModule := app.Modules.Get("otel"); otelModule != nil {
    provider := otelModule.(*otel.Module).Provider
    ctx, span := provider.Tracer().Start(ctx, "my-operation")
    defer span.End()
}

func NewModule

func NewModule(opts ...ModuleOption) *Module

NewModule creates a new OpenTelemetry module with default configuration from environment.

func (*Module) Initialize

func (m *Module) Initialize(g interface{}) error

Initialize creates the OpenTelemetry provider. This is called automatically during app.New().

func (*Module) IsEnabled

func (m *Module) IsEnabled() bool

IsEnabled returns true if tracing is enabled and configured

func (*Module) Name

func (m *Module) Name() string

Name returns the module identifier

func (*Module) Shutdown

func (m *Module) Shutdown(ctx context.Context) error

Shutdown gracefully stops the OpenTelemetry provider, flushing pending spans.

type ModuleOption

type ModuleOption func(*Module)

ModuleOption is a function that configures the OTel module

func WithAlwaysSample

func WithAlwaysSample() ModuleOption

WithAlwaysSample configures the always-sample strategy

func WithConfig

func WithConfig(cfg Config) ModuleOption

WithConfig sets the full configuration

func WithEnvironment

func WithEnvironment(env string) ModuleOption

WithEnvironment sets the deployment environment

func WithOTLPExporter

func WithOTLPExporter(endpoint string, insecure bool) ModuleOption

WithOTLPExporter configures OTLP export to the given endpoint

func WithRatioSample

func WithRatioSample(ratio float64) ModuleOption

WithRatioSample configures ratio-based sampling

func WithServiceName

func WithServiceName(name string) ModuleOption

WithServiceName sets the service name for traces

func WithServiceVersion

func WithServiceVersion(version string) ModuleOption

WithServiceVersion sets the service version for traces

func WithZipkinExporter

func WithZipkinExporter(endpoint string) ModuleOption

WithZipkinExporter configures Zipkin export to the given endpoint

type Provider

type Provider struct {
	// contains filtered or unexported fields
}

Provider manages OpenTelemetry tracing and metrics.

func New

func New(cfg Config) (*Provider, error)

New creates a new OpenTelemetry provider with the given configuration.

func (*Provider) Config

func (p *Provider) Config() Config

Config returns the provider configuration.

func (*Provider) ForceFlush

func (p *Provider) ForceFlush(ctx context.Context) error

ForceFlush immediately exports all pending spans.

func (*Provider) IsEnabled

func (p *Provider) IsEnabled() bool

IsEnabled returns true if tracing is enabled and the provider is active.

func (*Provider) Middleware

func (p *Provider) Middleware() func(http.Handler) http.Handler

Middleware returns an HTTP middleware that traces requests. It extracts trace context from incoming requests and creates spans.

func (*Provider) Propagator

func (p *Provider) Propagator() propagation.TextMapPropagator

Propagator returns the text map propagator for context injection/extraction.

func (*Provider) Shutdown

func (p *Provider) Shutdown(ctx context.Context) error

Shutdown gracefully shuts down the provider, flushing any pending spans. It should be called when the application exits.

func (*Provider) Tracer

func (p *Provider) Tracer() trace.Tracer

Tracer returns the tracer for creating spans.

func (*Provider) TracerProvider

func (p *Provider) TracerProvider() *sdktrace.TracerProvider

TracerProvider returns the underlying tracer provider.

type SamplerType

type SamplerType string

SamplerType defines the sampling strategy.

const (
	// SamplerAlways samples all traces.
	SamplerAlways SamplerType = "always"
	// SamplerNever samples no traces.
	SamplerNever SamplerType = "never"
	// SamplerRatio samples a percentage of traces.
	SamplerRatio SamplerType = "ratio"
	// SamplerParentBased respects the parent span's sampling decision.
	SamplerParentBased SamplerType = "parent"
)

type SpanMetrics

type SpanMetrics struct {
	// contains filtered or unexported fields
}

SpanMetrics bridges OpenTelemetry spans with Tjo metrics. It automatically records span duration as a histogram observation.

func NewSpanMetrics

func NewSpanMetrics(ctx context.Context, histogram *logging.Histogram, counter *logging.Counter) *SpanMetrics

NewSpanMetrics creates a span metrics tracker.

func (*SpanMetrics) End

func (s *SpanMetrics) End()

End records the duration metric.

func (*SpanMetrics) EndWithError

func (s *SpanMetrics) EndWithError(err error, errorCounter *logging.Counter)

EndWithError records the duration and optionally increments an error counter.

func (*SpanMetrics) WithAttributes

func (s *SpanMetrics) WithAttributes(attrs ...attribute.KeyValue) *SpanMetrics

WithAttributes adds attributes to track.

type SpanOptions

type SpanOptions struct {
	// contains filtered or unexported fields
}

SpanOptions provides a fluent interface for building span options.

func NewSpanOptions

func NewSpanOptions() *SpanOptions

NewSpanOptions creates a new SpanOptions builder.

func (*SpanOptions) Build

func (s *SpanOptions) Build() []trace.SpanStartOption

Build returns the accumulated span options.

func (*SpanOptions) WithAttribute

func (s *SpanOptions) WithAttribute(key, value string) *SpanOptions

WithAttribute adds a string attribute.

func (*SpanOptions) WithAttributes

func (s *SpanOptions) WithAttributes(attrs ...attribute.KeyValue) *SpanOptions

WithAttributes adds multiple attributes.

func (*SpanOptions) WithKind

func (s *SpanOptions) WithKind(kind trace.SpanKind) *SpanOptions

WithKind sets the span kind.

type TraceInfo

type TraceInfo struct {
	TraceID string
	SpanID  string
	Sampled bool
}

TraceInfo returns both trace ID and span ID from context.

func GetTraceInfo

func GetTraceInfo(ctx context.Context) TraceInfo

GetTraceInfo extracts trace information from context.

type TracedDB

type TracedDB struct {
	// contains filtered or unexported fields
}

TracedDB wraps a sql.DB to add tracing to all database operations.

func WrapDB

func WrapDB(db *sql.DB, dbType, dbName string) *TracedDB

WrapDB wraps a sql.DB with tracing capabilities.

func WrapDBWithTracer

func WrapDBWithTracer(db *sql.DB, tracer trace.Tracer, dbType, dbName string) *TracedDB

WrapDBWithTracer wraps a sql.DB with a specific tracer.

func (*TracedDB) Begin

func (t *TracedDB) Begin(ctx context.Context) (*TracedTx, error)

Begin starts a transaction and traces it.

func (*TracedDB) Close

func (t *TracedDB) Close() error

Close closes the database connection.

func (*TracedDB) DB

func (t *TracedDB) DB() *sql.DB

DB returns the underlying sql.DB.

func (*TracedDB) Exec

func (t *TracedDB) Exec(ctx context.Context, query string, args ...interface{}) (sql.Result, error)

Exec executes a statement and traces it.

func (*TracedDB) Ping

func (t *TracedDB) Ping(ctx context.Context) error

Ping verifies the database connection.

func (*TracedDB) Prepare

func (t *TracedDB) Prepare(ctx context.Context, query string) (*TracedStmt, error)

Prepare creates a prepared statement and traces it.

func (*TracedDB) Query

func (t *TracedDB) Query(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)

Query executes a query and traces it.

func (*TracedDB) QueryRow

func (t *TracedDB) QueryRow(ctx context.Context, query string, args ...interface{}) *sql.Row

QueryRow executes a query that returns a single row and traces it.

type TracedStmt

type TracedStmt struct {
	// contains filtered or unexported fields
}

TracedStmt is a traced prepared statement.

func (*TracedStmt) Close

func (s *TracedStmt) Close() error

Close closes the prepared statement.

func (*TracedStmt) Exec

func (s *TracedStmt) Exec(ctx context.Context, args ...interface{}) (sql.Result, error)

Exec executes the prepared statement with tracing.

func (*TracedStmt) Query

func (s *TracedStmt) Query(ctx context.Context, args ...interface{}) (*sql.Rows, error)

Query executes the prepared statement with tracing.

type TracedTx

type TracedTx struct {
	// contains filtered or unexported fields
}

TracedTx is a traced transaction.

func (*TracedTx) Commit

func (t *TracedTx) Commit() error

Commit commits the transaction.

func (*TracedTx) Exec

func (t *TracedTx) Exec(ctx context.Context, query string, args ...interface{}) (sql.Result, error)

Exec executes a statement within the transaction.

func (*TracedTx) Query

func (t *TracedTx) Query(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)

Query executes a query within the transaction.

func (*TracedTx) Rollback

func (t *TracedTx) Rollback() error

Rollback rolls back the transaction.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL