Putnami
DocsGitHub

Licensed under FSL-1.1-MIT

Getting Started
Concepts
How To
Build A Web App
Build An Api Service
Share Code Between Projects
Configure Your App
Add Persistence
Add Authentication
Add Background Jobs
Principles
Tooling & Workspace
Workspace Overview
Cli
Jobs & Commands
SDK
Error Handling
Extensions
Typescript
Go
Python
Docker
Ci
Frameworks
Typescript
OverviewWebReact RoutingForms And ActionsStatic FilesApiErrors And ResponsesConfigurationLoggingHttp And MiddlewareDependency InjectionPlugins And LifecycleSessionsAuthPersistenceEventsStorageCachingWebsocketsTestingHealth ChecksTelemetryProto GrpcSmart Client
Go
OverviewHttpDependency InjectionPlugins And LifecycleConfigurationSecurityPersistenceErrorsEventsStorageCachingLoggingTelemetryGrpcService ClientsValidationOpenapiTesting
Platform
  1. DocsSeparator
  2. FrameworksSeparator
  3. GoSeparator
  4. Telemetry

Telemetry

go.putnami.dev/telemetry provides OpenTelemetry integration for distributed tracing and metrics collection.

Plugin setup

import (
    "go.putnami.dev/app"
    "go.putnami.dev/telemetry"
)

a := app.New("my-service")
a.Module.Use(telemetry.NewPlugin(telemetry.Config{
    ServiceName:    "my-service",
    ServiceVersion: "1.0.0",
    TraceSampleRate: 0.1, // Sample 10% of traces
}))

The plugin:

  • Initializes the OpenTelemetry SDK
  • Registers trace.TracerProvider and metric.MeterProvider in DI
  • Shuts down exporters gracefully on application stop

Configuration

Field Type Default Description
ServiceName string — Service name for telemetry data
ServiceVersion string — Service version
TraceSampleRate float64 1.0 Trace sampling rate (0.0–1.0)
TraceExporter exporter — Custom trace exporter
MetricReader reader — Custom metric reader

Tracing

Creating spans

import "go.putnami.dev/telemetry"

func processOrder(ctx context.Context, orderID string) error {
    ctx, span := telemetry.StartSpan(ctx, "processOrder", "order")
    defer span.End()

    telemetry.SpanAttrs(span, "orderId", orderID)

    if err := chargePayment(ctx, orderID); err != nil {
        telemetry.SetSpanError(span, err)
        return err
    }

    telemetry.SetSpanOK(span)
    return nil
}

Getting a tracer

tracer := telemetry.Tracer("my-service")

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

Span helpers

Function Description
StartSpan(ctx, name, op) Create a child span
SetSpanError(span, err) Record an error on the span
SetSpanOK(span) Mark the span as successful
SetSpanErrorStructured(span, err) Record a structured error (bridges go.putnami.dev/errors)
SpanAttrs(span, key, value, ...) Set span attributes
TraceIDFromContext(ctx) Extract trace ID (32-char hex)

Trace ID extraction

traceID := telemetry.TraceIDFromContext(ctx)
// "4bf92f3577b34da6a3ce929d0e0e4736"

Metrics

Creating instruments

import "go.putnami.dev/telemetry"

meter := telemetry.Meter("my-service")

// Counter
counter, _ := telemetry.Counter(meter, "requests_total")
counter.Add(ctx, 1)

// Histogram
histogram, _ := telemetry.Histogram(meter, "request_duration_ms")
histogram.Record(ctx, 42.5)

// Gauge
gauge, _ := telemetry.Gauge(meter, "active_connections")
gauge.Record(ctx, 15.0)

// Up/down counter
upDown, _ := telemetry.UpDownCounter(meter, "queue_size")
upDown.Add(ctx, 1)  // item added
upDown.Add(ctx, -1) // item removed

Metric helpers

Function Returns Description
Counter(meter, name) metric.Int64Counter Monotonically increasing counter
Histogram(meter, name, opts...) metric.Float64Histogram Distribution of values
Gauge(meter, name, opts...) metric.Float64Gauge Point-in-time value
UpDownCounter(meter, name) metric.Int64UpDownCounter Counter that can increase or decrease

HTTP middleware

Auto-trace HTTP requests with the telemetry middleware:

import (
    fhttp "go.putnami.dev/http"
    "go.putnami.dev/telemetry"
)

server := fhttp.NewServerPlugin(fhttp.ServerConfig{Port: 3000})
server.Use(telemetry.HTTPMiddleware("my-service"))

The middleware automatically:

  • Creates a span per request
  • Records http.method, http.path, http.status_code attributes
  • Emits http.server.request_count and http.server.duration metrics
  • Propagates trace context to downstream services

Error bridge

When the telemetry plugin is active, structured errors from go.putnami.dev/errors automatically emit an errors_total counter with labels:

Label Source
error.code Error code
error.category Error category
error.source Package where the error originated
// This error automatically increments errors_total{code="db.query", category="infra"}
err := errors.Wrap(dbErr, "db.query").WithCategory(errors.CategoryInfra)

Patterns

Service-level tracing

type OrderService struct {
    tracer trace.Tracer
    repo   *OrderRepository
}

func NewOrderService(repo *OrderRepository) *OrderService {
    return &OrderService{
        tracer: telemetry.Tracer("OrderService"),
        repo:   repo,
    }
}

func (s *OrderService) Create(ctx context.Context, input CreateOrderInput) (*Order, error) {
    ctx, span := s.tracer.Start(ctx, "CreateOrder")
    defer span.End()

    order, err := s.repo.Create(ctx, input)
    if err != nil {
        telemetry.SetSpanError(span, err)
        return nil, err
    }

    span.SetAttributes(attribute.String("orderId", order.ID))
    return order, nil
}

Custom metrics

type PaymentService struct {
    meter          metric.Meter
    paymentCounter metric.Int64Counter
    amountHist     metric.Float64Histogram
}

func NewPaymentService() *PaymentService {
    meter := telemetry.Meter("payments")
    counter, _ := telemetry.Counter(meter, "payments_total")
    hist, _ := telemetry.Histogram(meter, "payment_amount")
    return &PaymentService{meter: meter, paymentCounter: counter, amountHist: hist}
}

func (s *PaymentService) Process(ctx context.Context, amount float64) error {
    s.paymentCounter.Add(ctx, 1)
    s.amountHist.Record(ctx, amount)
    return nil
}

Related guides

  • HTTP & Middleware — HTTP tracing
  • Errors — error metrics
  • Logging — trace-correlated logs

On this page

  • Telemetry
  • Plugin setup
  • Configuration
  • Tracing
  • Creating spans
  • Getting a tracer
  • Span helpers
  • Trace ID extraction
  • Metrics
  • Creating instruments
  • Metric helpers
  • HTTP middleware
  • Error bridge
  • Patterns
  • Service-level tracing
  • Custom metrics
  • Related guides