otx

package module
v0.0.0-...-de6cbd0 Latest Latest
Warning

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

Go to latest
Published: Aug 17, 2026 License: MIT Imports: 23 Imported by: 0

README

go-otx

github.com/7e3b/go-otx is a lightweight Go wrapper around OpenTelemetry that provides a unified API for:

  • Distributed tracing
  • Structured logging
  • Metrics
  • Trace-context propagation
  • Trace/log correlation
  • Optional source-code metadata
  • JSON console logging

The package is designed around a single application-wide telemetry client configured once during startup and reused throughout the application.

Installation

go get github.com/7e3b/go-otx

Quick Start

package main

import (
    "context"
    "log"

    "github.com/7e3b/go-otx"
)

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

    err := otx.Config{
        Name:        "my-service",
        Namespace:   "my-company",
        Environment: "production",
        Version:     "1.0.0",
        Endpoint:    "localhost:4318",
        Insecure:    true,

        Tracer: otx.TracerConfig{
            SamplingRatio: 1.0,
        },

        Logger: otx.LoggerConfig{
            Severity: otx.SeverityInfo,
            Console:  true,
        },

        Meter: otx.MeterConfig{
            Enabled: true,
        },
    }.Connect(ctx)
    if err != nil {
        log.Fatal(err)
    }
    defer otx.Shutdown(context.Background())

    span := otx.Start(ctx)
    defer span.End()

    span.Info("request started", map[string]any{
        "user_id": 123,
    })
}

Configuration

Config controls service identity and which telemetry providers are enabled.


Field Description


Name Service name used as service.name.

Namespace Service namespace used as service.namespace.

Environment Deployment environment, such as development or production.

Version Service version used as service.version.

InstanceID Identifier for the running service instance.

Endpoint OTLP HTTP endpoint used by the exporters.

Insecure Disables TLS for the OTLP HTTP exporters.

WithoutMetadata Disables automatic file/function/line metadata.

Tracer Distributed tracing configuration.

Meter Metrics configuration.

Logger Structured logging configuration.

Tracing

Tracing is enabled when Tracer.SamplingRatio is greater than zero.

Tracer: otx.TracerConfig{
    SamplingRatio: 1.0,
},

Common sampling ratios:

  • 1.0 --- sample all traces
  • 0.1 --- sample approximately 10% of traces
  • 0 --- disable tracing

The tracer uses parent-based sampling with a trace-ID ratio sampler.

Logging

Logging is enabled when Logger.Severity is not empty.

Supported severities:

trace
debug
info
warn
error
fatal

Example:

Logger: otx.LoggerConfig{
    Severity: otx.SeverityInfo,
    Console:  true,
},

The configured severity is the minimum severity exported.

For example, with SeverityError, Error and Fatal records are exported, while Info, Debug, Trace, and Warn records are filtered.

Console: true additionally writes structured JSON logs to standard output using Go's log/slog.

Metrics

Metrics are enabled with:

Meter: otx.MeterConfig{
    Enabled: true,
},

The metrics provider uses an OTLP HTTP exporter and a periodic reader.

Spans

Start a span with:

span := otx.Start(ctx)
defer span.End()

The returned span provides both tracing and structured logging APIs.

Span Configuration
span := otx.Start(ctx, otx.SpanConfig{
    Name: "process-order",
    Kind: otx.KindServer,
    Attributes: map[string]any{
        "order_id": 123,
    },
})
defer span.End()

SpanConfig supports:

  • Name --- explicit span name.
  • Kind --- OpenTelemetry span kind.
  • Attributes --- attributes attached to the span.

Supported span kinds:

otx.KindInternal
otx.KindServer
otx.KindClient
otx.KindProducer
otx.KindConsumer

If Name is empty and metadata collection is enabled, the calling function is used as the span name.

Span Logging

A span can emit structured logs:

span.Trace("trace message")
span.Debug("debug message")
span.Info("user authenticated")
span.Warn("slow downstream service")
span.Error(err)
span.Fatal(err)

Additional attributes can be supplied as maps:

span.Info("order processed", map[string]any{
    "order_id": 123,
    "amount":   500,
})

The same event is correlated with the span's trace context when OpenTelemetry logging is enabled.

Errors

Error and Fatal require a non-nil error.

if err != nil {
    span.Error(err, map[string]any{
        "operation": "create_order",
    })
}

When an error is recorded:

  • The log record contains the error.
  • The span records the error.
  • The span status is set to Error.

Fatal records fatal telemetry but does not terminate the process.

Source Metadata

Unless WithoutMetadata is enabled, telemetry generated through spans includes:

  • file
  • function
  • line

Disable it with:

WithoutMetadata: true,

Disabling metadata reduces runtime inspection overhead and telemetry volume.

Context

Use Span.Ctx() when subsequent operations need the span's context:

span := otx.Start(ctx)
defer span.End()

ctx = span.Ctx()

The returned context contains the active OpenTelemetry span when tracing is enabled.

Trace Context Propagation

Inject and Extract provide propagation for HTTP requests, queues, NATS messages, jobs, and other transports.

Producer
carrier := map[string]string{}

otx.Inject(span.Ctx(), carrier)

// Send carrier with the message.
Consumer
ctx := otx.Extract(context.Background(), carrier)

span := otx.Start(ctx)
defer span.End()

The extracted context allows the consumer span to continue the distributed trace.

The package configures W3C Trace Context and W3C Baggage propagation.

Linking Asynchronous Work

For asynchronous work such as queues, the consumer operation can be represented as a linked span rather than a child span.

Producer:

carrier := map[string]string{}
otx.Inject(span.Ctx(), carrier)

Consumer:

ctx := otx.Extract(context.Background(), carrier)

span := otx.Link(ctx, otx.SpanConfig{
    Name: "process-message",
    Kind: otx.KindConsumer,
})
defer span.End()

Link creates a new root span and adds the extracted span context as a span link.

This is useful when the producer and consumer do not have a meaningful synchronous parent-child relationship.

Context Without the Original Deadline

WithoutTimeout preserves the OpenTelemetry trace context while removing the original context's deadline and cancellation.

ctx := otx.WithoutTimeout(requestCtx)

go process(ctx)

This is useful when work must continue after the original request has completed.

WithNewTimeout provides the same behavior while applying a new timeout:

ctx, cancel := otx.WithNewTimeout(requestCtx, 30*time.Second)
defer cancel()

The resulting context keeps the trace context but does not inherit the original deadline or cancellation.

Graceful Shutdown

Call Shutdown during application shutdown:

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

if err := otx.Shutdown(ctx); err != nil {
    log.Printf("telemetry shutdown failed: %v", err)
}

Shutdown flushes pending telemetry and shuts down the enabled tracing, logging, and metrics providers.

Package-Level API

The package exposes the following primary operations:


Function Purpose


Connect Initializes the global telemetry client.

Start Starts a normal span.

Link Starts a new root span linked to another span context.

Shutdown Flushes and shuts down telemetry providers.

Inject Injects trace context into a carrier.

Extract Extracts trace context from a carrier.

WithNewTimeout Creates a new timeout context while preserving trace context.

WithoutTimeout Removes deadline/cancellation while preserving trace context.

Exported Types

Span

Represents a unit of work within a distributed trace and provides structured logging methods.

Methods:

  • End()
  • Trace(...)
  • Info(...)
  • Debug(...)
  • Warn(...)
  • Error(...)
  • Fatal(...)
  • Ctx()
SpanConfig

Configures a span's name, kind, and attributes.

Config

Configures the telemetry client and service resource information.

TracerConfig

Configures trace sampling.

MeterConfig

Enables or disables metrics.

LoggerConfig

Configures minimum logging severity and console output.

OpenTelemetry Resource Attributes

The configured service identity is exported as OpenTelemetry resource attributes:

  • service.name
  • service.namespace
  • service.version
  • service.instance.id
  • deployment.environment.name
  • host.name

Architecture

The package maintains one global client:

                    ┌─────────────────┐
                    │    otx.Config   │
                    └────────┬────────┘
                             │ Connect
                             ▼
                    ┌─────────────────┐
                    │     client      │
                    ├─────────────────┤
                    │ tracer          │
                    │ logger          │
                    │ meter           │
                    │ metadata        │
                    └───────┬─────────┘
                            │
          ┌─────────────────┼─────────────────┐
          ▼                 ▼                 ▼
       Tracing           Logging           Metrics
          │                 │                 │
          └─────────────────┼─────────────────┘
                            ▼
                     OTLP HTTP Collector

The global client is protected by a read/write mutex and is intended to be initialized once during application startup.

Requirements

  • Go with a version compatible with the OpenTelemetry dependencies used by this module.
  • An OTLP HTTP-compatible collector or backend.

The package can be used with observability backends such as SigNoz, provided they accept OTLP over HTTP.

License

See LICENSE.

Documentation

Index

Constants

View Source
const (
	// SeverityTrace represents trace-level logging.
	SeverityTrace = "trace"

	// SeverityDebug represents debug-level logging.
	SeverityDebug = "debug"

	// SeverityInfo represents informational logging.
	SeverityInfo = "info"

	// SeverityWarn represents warning-level logging.
	SeverityWarn = "warn"

	// SeverityError represents error-level logging.
	SeverityError = "error"

	// SeverityFatal represents fatal-level logging.
	//
	// Fatal severity records a critical error but does not terminate the
	// application.
	SeverityFatal = "fatal"
)
View Source
const (
	// KindInternal identifies an internal operation within an application.
	KindInternal = "internal"

	// KindServer identifies a span representing a request received by a service.
	KindServer = "server"

	// KindClient identifies a span representing an outbound request to another service.
	KindClient = "client"

	// KindProducer identifies a span representing message production.
	KindProducer = "producer"

	// KindConsumer identifies a span representing message consumption.
	KindConsumer = "consumer"
)

Variables

View Source
var ErrInvalidSeverity = errors.New("invalid severity")

ErrInvalidSeverity indicates that LoggerConfig.Severity contains an unsupported severity value.

Functions

func Extract

func Extract(ctx context.Context, carrier map[string]string) context.Context

Extract extracts an OpenTelemetry trace context from carrier and returns a new context containing the extracted context.

The returned context can be used to create spans associated with the trace represented by the propagated data.

Config.Connect must be called successfully before using Extract.

Extract returns context.Background() when tracing is disabled.

func Inject

func Inject(ctx context.Context, carrier map[string]string)

Inject injects the OpenTelemetry trace context from ctx into carrier.

The resulting key-value pairs can be transported with an outbound message, such as a queue message or HTTP request, and later extracted by the receiving service using Extract.

Config.Connect must be called successfully before using Inject.

Inject does nothing when tracing is disabled.

func Shutdown

func Shutdown(ctx context.Context) error

Shutdown flushes pending telemetry and shuts down all enabled OpenTelemetry providers on the globally configured client.

Config.Connect must be called successfully before using Shutdown.

Shutdown should be called during graceful application shutdown.

func WithNewTimeout

func WithNewTimeout(ctx context.Context, expiry time.Duration) (context.Context, context.CancelFunc)

WithNewTimeout creates a new context with the specified timeout while preserving the OpenTelemetry trace context from the supplied context.

Config.Connect must be called successfully before using WithNewTimeout.

The returned context does not inherit the deadline or cancellation of the supplied context, but retains its OpenTelemetry trace context.

The returned CancelFunc must be called when the context is no longer needed.

func WithoutTimeout

func WithoutTimeout(ctx context.Context) context.Context

WithoutTimeout creates a new context without inheriting the deadline or cancellation of the supplied context while preserving its OpenTelemetry trace context.

Config.Connect must be called successfully before using WithoutTimeout.

This is useful when work must continue independently of the lifetime of the original request context while remaining part of the same trace.

Types

type Config

type Config struct {
	// Name identifies the service emitting telemetry.
	//
	// This value is used as the OpenTelemetry service.name resource attribute.
	Name string `json:"name"`

	// Namespace identifies the logical namespace of the service.
	Namespace string `json:"namespace"`

	// Environment identifies the deployment environment, such as
	// "development", "staging", or "production".
	Environment string `json:"environment"`

	// Version identifies the version of the running service.
	Version string `json:"version"`

	// InstanceID identifies the specific running instance of the service.
	//
	// In a containerized environment this can be set to a pod, task, or
	// other instance identifier.
	InstanceID string `json:"instance_id"`

	// Endpoint specifies the OTLP HTTP endpoint used to export telemetry.
	//
	// The configured endpoint is used by the enabled tracing, logging,
	// and metrics exporters.
	Endpoint string `json:"endpoint"`

	// Insecure disables TLS when communicating with the OTLP endpoint.
	//
	// This is generally useful for local development or environments where
	// the collector endpoint does not require TLS.
	Insecure bool `json:"insecure"`

	// WithoutMetadata disables automatic source-code metadata.
	//
	// When metadata is enabled, telemetry includes the source file,
	// function, and line number associated with the operation.
	//
	// Disabling metadata can reduce runtime overhead and telemetry volume.
	WithoutMetadata bool `json:"without_metadata"`

	// Tracer configures distributed tracing.
	Tracer TracerConfig `json:"tracer"`

	// Meter configures metrics collection.
	Meter MeterConfig `json:"meter"`

	// Logger configures structured logging.
	Logger LoggerConfig `json:"logger"`
}

Config configures the OpenTelemetry client.

A Config controls service identity, OTLP export settings, and the individual tracing, logging, and metrics providers.

Create the Client once during application startup and reuse it throughout the application.

func (Config) Connect

func (config Config) Connect(ctx context.Context) error

Connect initializes and configures the package-level OpenTelemetry client.

Connect must be called successfully before using the package-level functions Start, Shutdown, WithNewTimeout, or WithoutTimeout.

Only the telemetry providers enabled by the configuration are initialized.

Connect is intended to be called during application startup.

Call Shutdown during graceful application shutdown to flush pending telemetry and shut down the configured providers.

type LoggerConfig

type LoggerConfig struct {
	// Severity specifies the minimum severity exported by the logger.
	//
	// Supported values are:
	//
	//	trace
	//	debug
	//	info
	//	warn
	//	error
	//	fatal
	//
	// An empty value disables logging.
	Severity string `json:"severity"`

	// Console determines whether log records are also written as structured
	// JSON to the process's standard output.
	Console bool `json:"console"`
}

LoggerConfig configures structured logging.

type MeterConfig

type MeterConfig struct {
	// Enabled determines whether metrics collection is enabled.
	Enabled bool `json:"enabled"`
}

MeterConfig configures metrics collection.

type Span

type Span interface {
	// End completes the span.
	//
	// End should normally be called using:
	//
	//	span := client.Start(ctx)
	//	defer span.End()
	End()

	// Trace records a trace-level diagnostic event.
	Trace(string, ...map[string]any)

	// Info records an informational event.
	Info(string, ...map[string]any)

	// Debug records a debug-level diagnostic event.
	Debug(string, ...map[string]any)

	// Warn records a warning event.
	Warn(string, ...map[string]any)

	// Error records an error event and marks the associated span as failed.
	//
	// A nil error is ignored.
	Error(error, ...map[string]any)

	// Fatal records a fatal error event and marks the associated span as failed.
	//
	// A nil error is ignored. This method records telemetry but does not
	// terminate the application.
	Fatal(error, ...map[string]any)

	// Ctx returns the context associated with the span.
	//
	// The returned context contains the span's trace context and should be
	// used for operations performed within the span when propagation is
	// required.
	Ctx() context.Context
}

Span represents a unit of work within a distributed trace.

A Span also provides structured logging methods. Logs emitted through a Span are associated with the Span's trace context, allowing logs and traces to be correlated in an observability backend.

A Span should normally be ended exactly once using defer immediately after it is created.

func Link(ctx context.Context, config ...SpanConfig) Span

Link starts a new span that is linked to the trace represented by ctx rather than making the new span a child of it.

This is useful when work is triggered asynchronously, such as through a queue, where the new operation belongs to the same trace but should not appear as a direct child of the span that produced the work.

Span configuration can be supplied through SpanConfig.

Config.Connect must be called successfully before using Link.

At most one SpanConfig should be supplied. If multiple configurations are supplied, only the first configuration is used.

The returned Span should normally be ended using defer:

span := otx.Link(ctx)
defer span.End()

func Start

func Start(ctx context.Context, config ...SpanConfig) Span

Start starts a new span using the globally configured OpenTelemetry client.

Config.Connect must be called successfully before using Start.

The returned Span should normally be ended using defer:

span := otx.Start(ctx)
defer span.End()

Span configuration can be supplied through SpanConfig. At most one SpanConfig should be supplied. If multiple configurations are supplied, only the first configuration is used.

type SpanConfig

type SpanConfig struct {
	// Name specifies the span name.
	//
	// When empty, the client derives the name from the calling function if the client was configured with metadata.
	Name string

	// Kind specifies the OpenTelemetry span kind.
	//
	// Supported values are KindInternal, KindServer, KindClient,
	// KindProducer, and KindConsumer.
	//
	// An empty value leaves the span kind unspecified.
	Kind string

	// Attributes specifies attributes to attach to the span.
	//
	// Attribute values are converted to strings before being attached.
	Attributes map[string]any
}

SpanConfig configures a span created by Client.Start.

type TracerConfig

type TracerConfig struct {
	// SamplingRatio specifies the proportion of traces to sample.
	//
	// For example:
	//
	//	1.0  - sample all traces
	//	0.1  - sample approximately 10% of traces
	//
	// A value greater than zero enables tracing.
	SamplingRatio float64 `json:"sampling_ratio"`
}

TracerConfig configures distributed tracing.

Jump to

Keyboard shortcuts

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