tel

package module
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Jul 31, 2026 License: Apache-2.0 Imports: 36 Imported by: 0

README

tel

OTLP metrics and traces for Go. The record path is allocation-sensitive; export is batched OTLP/gRPC—keep those worlds separate.

Module: github.com/gopherust-io/tel · JetStream: nats

OpenSSF Scorecard

go get github.com/gopherust-io/tel@latest

Example

package main

import (
	"context"
	"log"

	"github.com/gopherust-io/tel"
)

func main() {
	// Local/tests: tel.DefaultDebugConfig() (OTLP + monitor off).
	cfg := tel.DefaultConfig()
	cfg.Service = "orders-api"
	cfg.TelConfig.Address = "127.0.0.1:4317"

	t := tel.NewWithConfig(cfg)
	tel.SetGlobal(t)

	ctx := context.Background()
	if err := t.Start(ctx); err != nil {
		log.Fatal(err)
	}
	defer t.Shutdown(ctx)

	ctx = tel.WrapContext(ctx, t)

	processed, err := t.Registry().Counter("orders.processed")
	if err != nil {
		log.Fatal(err)
	}
	processed.AddWith(ctx, 1, "orders.created")
}

Record

Create instruments once. Use subject-keyed *With helpers—they hit AttrCache. Subjects must be a bounded set or you will blow cardinality.

r := tel.FromCtx(ctx).Registry()

count, err := r.Counter("orders.processed")
if err != nil {
	return err
}
latency, err := r.Histogram("orders.latency_seconds")
if err != nil {
	return err
}

count.AddWith(ctx, 1, "orders.created")

timer := tel.NewTimer(latency)
timer.Start()
// work
timer.StopWith(ctx, "orders.created")

Propagate

headers := tel.InjectContext(ctx, nil)
ctx = tel.ExtractContext(ctx, inboundHeaders)

Prefer MessagingSystem / MessagingSubject (and friends) over hand-rolled attribute maps.

Logging

Process-global zerolog via tel.InitLogger / tel.ConfigureLogger and tel.Info() / tel.Ctx(ctx). Every line includes caller as funcName:line (e.g. main.main:42). Err(err) adds a stack field (func/file/line frames) for the call path to the log site.

Knobs

Concern Knob
Collector TelConfig.Address / TEL_COLLECTOR_GRPC_ADDR
Export on/off TelConfig.Enable / TEL_ENABLE
Quiet local DefaultDebugConfig()
Compression On by default; gzip BestSpeed on export only (TEL_ENABLE_COMPRESSION)
Monitor MonitorConfigGET /healthz, GET /stats

Compression sets the process-wide gRPC gzip level. Default export is insecure—fine for a local collector; use TelConfig.Raw PEM for TLS/mTLS.

Lifecycle

Call Start before recording. Instruments obtained before Start are invalidated when Start runs—re-fetch via Registry() afterward. Shutdown is restart-safe (StartShutdownStartShutdown).

Do not

  1. Put network I/O, locks, or attribute allocation on the record path.
  2. Pass unbounded strings (user IDs, raw URLs) as *With subjects.
  3. Skip Start on a production DefaultConfig() and assume metrics still export.
  4. Keep using Counter/Histogram handles created before Start.

Development

make test
make demo

CONTRIBUTING.md

License

Apache License 2.0 — see LICENSE.

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func ConfigureLogger

func ConfigureLogger(cfg Config)

ConfigureLogger applies Config.LogLevel / LogEncode to the process logger. Call once at process startup before concurrent logging (not from NewWithConfig).

func Ctx

func Ctx(ctx context.Context) *zerolog.Logger

Ctx returns the logger from ctx, falling back to DefaultContextLogger.

func Debug

func Debug() *zerolog.Event

func EndSpan

func EndSpan(span trace.Span, err error)

EndSpan ends a span and records an error when present.

func Error

func Error() *zerolog.Event

func ExtractContext

func ExtractContext(ctx context.Context, headers map[string][]string) context.Context

ExtractContext reads trace context from a string header map.

func Info

func Info() *zerolog.Event

func InitLogger

func InitLogger(opts LoggerOptions)

InitLogger configures structured logging. Safe to call at startup (and again to reconfigure).

func InjectContext

func InjectContext(ctx context.Context, headers map[string][]string) map[string][]string

InjectContext writes trace context into a string header map.

Example

ExampleInjectContext demonstrates W3C trace context propagation via headers.

headers := InjectContext(context.Background(), map[string][]string{})
_ = ExtractContext(context.Background(), headers)

func Logger

func Logger() zerolog.Logger

Logger returns the process-global logger.

func MessagingOperationProcess

func MessagingOperationProcess() attribute.KeyValue

func MessagingOperationPublish

func MessagingOperationPublish() attribute.KeyValue

func MessagingSubject

func MessagingSubject(subject string) attribute.KeyValue

MessagingSubject returns a messaging destination attribute for NATS spans.

func MessagingSystem

func MessagingSystem() attribute.KeyValue

func SetExitFunc

func SetExitFunc(fn func(int))

SetExitFunc overrides the function called after Fatal logs (for tests).

func SetGlobal

func SetGlobal(t *Telemetry)

func SetLogger

func SetLogger(l zerolog.Logger)

SetLogger replaces the process-global logger and DefaultContextLogger.

func Warn

func Warn() *zerolog.Event

func WrapContext

func WrapContext(ctx context.Context, l *Telemetry) context.Context

Types

type AttrCache

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

AttrCache interns attribute sets and metric options for hot-path label reuse. Entries are sharded by subject hash; each shard is a lock-free CoW map.

func (*AttrCache) Len

func (c *AttrCache) Len() int

func (*AttrCache) SetDetector

func (c *AttrCache) SetDetector(d *cardinalityDetector)

SetDetector wires optional cardinality observation into the hot path.

func (*AttrCache) Subject

func (c *AttrCache) Subject(subject string) attribute.Set

func (*AttrCache) SubjectOpts

func (c *AttrCache) SubjectOpts(subject string) []metric.AddOption

func (*AttrCache) SubjectRecordOpts

func (c *AttrCache) SubjectRecordOpts(subject string) []metric.RecordOption

type Config

type Config struct {
	MonitorConfig
	TelConfig

	Service     string `env:"TEL_SERVICE_NAME"`
	Namespace   string `env:"NAMESPACE"          envDefault:"default"`
	Environment string `env:"DEPLOY_ENVIRONMENT" envDefault:"dev"`
	Version     string `env:"VERSION"            envDefault:"dev"`
	LogLevel    string `env:"LOG_LEVEL"          envDefault:"info"`
	LogEncode   string `env:"LOG_ENCODE"         envDefault:"json"`
	Debug       bool   `env:"DEBUG"              envDefault:"false"`
}

Config holds process-wide telemetry settings. Embedded configs stay first (embeddedstructfieldcheck); fieldalignment is excluded for this file in .golangci.yml and make align.

goalign:ignore

func DefaultConfig

func DefaultConfig() Config

func DefaultDebugConfig

func DefaultDebugConfig() Config

type FastCounter

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

func (*FastCounter) Add

func (c *FastCounter) Add(ctx context.Context, n int64)

func (*FastCounter) AddWith

func (c *FastCounter) AddWith(ctx context.Context, n int64, subject string)

func (*FastCounter) WithAttrs

func (c *FastCounter) WithAttrs(attrs attribute.Set) *FastCounter

type FastGauge

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

func (*FastGauge) Record

func (g *FastGauge) Record(ctx context.Context, value int64)

func (*FastGauge) RecordWith

func (g *FastGauge) RecordWith(ctx context.Context, value int64, subject string)

func (*FastGauge) WithAttrs

func (g *FastGauge) WithAttrs(attrs attribute.Set) *FastGauge

type FastHistogram

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

func (*FastHistogram) Record

func (h *FastHistogram) Record(ctx context.Context, value float64)

func (*FastHistogram) RecordWith

func (h *FastHistogram) RecordWith(ctx context.Context, value float64, subject string)

func (*FastHistogram) WithAttrs

func (h *FastHistogram) WithAttrs(attrs attribute.Set) *FastHistogram

type FatalEvent

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

FatalEvent mirrors zerolog's chainable API but exits via SetExitFunc instead of os.Exit directly.

func Fatal

func Fatal() *FatalEvent

Fatal logs at fatal level and invokes the configured exit function (default os.Exit).

func (*FatalEvent) Err

func (f *FatalEvent) Err(err error) *FatalEvent

func (*FatalEvent) Msg

func (f *FatalEvent) Msg(msg string)

func (*FatalEvent) Msgf

func (f *FatalEvent) Msgf(format string, v ...any)

func (*FatalEvent) Str

func (f *FatalEvent) Str(key, val string) *FatalEvent

type HistogramOpt

type HistogramOpt struct {
	Name       string
	Boundaries []float64
}

type LoggerOptions

type LoggerOptions struct {
	Level string
	JSON  bool
}

LoggerOptions configures the process-global zerolog logger.

goalign:ignore

type MonitorConfig

type MonitorConfig struct {
	MonitorAddr string `env:"MONITOR_ADDR"   envDefault:"0.0.0.0:8011"`
	Enable      bool   `env:"MONITOR_ENABLE" envDefault:"true"`
}

MonitorConfig holds health/stats monitor settings.

goalign:ignore

type Registry

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

func (*Registry) AttrCache

func (r *Registry) AttrCache() *AttrCache

func (*Registry) Counter

func (r *Registry) Counter(name string, opts ...metric.Int64CounterOption) (*FastCounter, error)

func (*Registry) Gauge

func (r *Registry) Gauge(name string, opts ...metric.Int64GaugeOption) (*FastGauge, error)

func (*Registry) Histogram

func (r *Registry) Histogram(name string, opts ...metric.Float64HistogramOption) (*FastHistogram, error)

type TelConfig

type TelConfig struct {
	Address    string `env:"TEL_COLLECTOR_GRPC_ADDR"       envDefault:"127.0.0.1:4317"`
	ServerName string `env:"TEL_COLLECTOR_TLS_SERVER_NAME"`
	Raw        struct {
		CA   []byte `env:"OTEL_COLLECTOR_TLS_CA_CERT"`
		Cert []byte `env:"OTEL_COLLECTOR_TLS_CLIENT_CERT"`
		Key  []byte `env:"OTEL_COLLECTOR_TLS_CLIENT_KEY"`
	}

	BucketView []HistogramOpt

	Metrics struct {
		CardinalityDetector struct {
			MaxCardinality     int           `env:"METRICS_CARDINALITY_DETECTOR_MAX_CARDINALITY"     envDefault:"100"`
			MaxInstruments     int           `env:"METRICS_CARDINALITY_DETECTOR_MAX_INSTRUMENTS"     envDefault:"500"`
			DiagnosticInterval time.Duration `env:"METRICS_CARDINALITY_DETECTOR_DIAGNOSTIC_INTERVAL" envDefault:"10m"`
			Enable             bool          `env:"METRICS_CARDINALITY_DETECTOR_ENABLE"              envDefault:"true"`
		}
		EnableRetry bool `env:"METRICS_ENABLE_RETRY" envDefault:"false"`
	}
	MetricsPeriodicIntervalSec int `env:"TEL_METRIC_PERIODIC_INTERVAL_SEC" envDefault:"15"`
	// ExportIntervalSec overrides MetricsPeriodicIntervalSec when > 0 (OTLP push cadence).
	ExportIntervalSec int  `env:"TEL_EXPORT_INTERVAL_SEC" envDefault:"0"`
	WithInsecure      bool `env:"TEL_EXPORTER_WITH_INSECURE"       envDefault:"true"`
	Enable            bool `env:"TEL_ENABLE"                       envDefault:"true"`
	WithCompression   bool `env:"TEL_ENABLE_COMPRESSION"           envDefault:"true"`
	Traces            struct {
		Enable bool `env:"TEL_TRACES_ENABLE" envDefault:"true"`
	}
}

TelConfig holds OTLP export and related collector settings.

goalign:ignore

type Telemetry

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

Telemetry is the process-wide metrics/traces runtime. Telemetry is the process-wide metrics/traces runtime.

goalign:ignore

func FromCtx

func FromCtx(ctx context.Context) *Telemetry

func Global

func Global() *Telemetry

func New

func New() *Telemetry

func NewWithConfig

func NewWithConfig(cfg Config) *Telemetry

func NewWithTracerProvider

func NewWithTracerProvider(cfg Config, provider trace.TracerProvider) *Telemetry

NewWithTracerProvider wires a custom tracer provider (useful in tests and custom setups).

func (*Telemetry) Config

func (t *Telemetry) Config() Config

func (*Telemetry) Meter

func (t *Telemetry) Meter(ins string, opts ...metric.MeterOption) metric.Meter

func (*Telemetry) Registry

func (t *Telemetry) Registry() *Registry

func (*Telemetry) Shutdown

func (t *Telemetry) Shutdown(ctx context.Context) error

Shutdown flushes exporters and releases resources. Safe to call after Start, and again after a subsequent Start (restart-safe; not sync.Once).

func (*Telemetry) Start

func (t *Telemetry) Start(ctx context.Context) error

func (*Telemetry) StartSpan

func (t *Telemetry) StartSpan(
	ctx context.Context,
	spanName string,
	opts ...trace.SpanStartOption,
) (context.Context, trace.Span)

StartSpan starts a span on the telemetry tracer provider. The caller is responsible for ending the returned span.

func (*Telemetry) Tracer

func (t *Telemetry) Tracer(name string) trace.Tracer

Tracer returns a named tracer from the configured provider.

type Timer

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

func NewTimer

func NewTimer(hist *FastHistogram) Timer

func (*Timer) Start

func (t *Timer) Start()

func (*Timer) Stop

func (t *Timer) Stop(ctx context.Context)

func (*Timer) StopWith

func (t *Timer) StopWith(ctx context.Context, subject string)

Directories

Path Synopsis
examples
basic command
Basic example: tel lifecycle and low-allocation metrics.
Basic example: tel lifecycle and low-allocation metrics.
internal
bytesconv
Package bytesconv provides zero-allocation string↔[]byte conversions.
Package bytesconv provides zero-allocation string↔[]byte conversions.

Jump to

Keyboard shortcuts

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