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
Develop With Ai
Structure Business Logic With Di
Upgrade Putnami
Principles
Tooling & Workspace
Workspace
Cli
Jobs & Caching
Extensions
Templates
Error Handling
Frameworks
Typescript
ExtensionOverviewWebReact RoutingForms And ActionsStatic FilesApiErrors And ResponsesConfigurationLoggingHttp And MiddlewareDependency InjectionPlugins And LifecycleSessionsAuthPersistenceEventsStorageCachingWebsocketsTestingHealth ChecksTelemetryProto GrpcSmart ClientSchema
Go
ExtensionOverviewHttpDependency InjectionPlugins And LifecycleConfigurationSecurityPersistenceErrorsEventsStorageCachingLoggingTelemetryGrpcService ClientsValidationOpenapiTesting
Python
Extension
Platform
Ci
  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