Integration · Go

Go monitoring and Golang APM

Wrap your handlers with OpenTelemetry Go and Obseria shows traces, goroutines, heap, GC and scheduler latency for every Go service, correlated with CPU profiles, logs and Kubernetes.
Obseria apps and capabilities: observability, APM, infrastructure and integrations
Obseria home dashboard with service health, open problems, SLO compliance and ingestion
Obseria trace explorer with span list and span attributes
Overview

Why monitor Go with Obseria

Standard, stable instrumentation

Traces and metrics in the OpenTelemetry Go SDK are stable, and contrib packages cover net/http, gRPC, database/sql drivers and popular frameworks.

Goroutines and GC in context

Goroutine counts, heap size and the GC goal sit next to the traces they slow down, so leaks and allocation pressure are easy to spot.

Down to the function

Continuous profiling with under 1% overhead shows which functions burn CPU or allocate memory in production.

Coverage

Go libraries and runtimes Obseria monitors

  • net/http servers and clients. otelhttp wraps handlers and transports, creating server and client spans with route, status code and latency.
  • gRPC. otelgrpc stats handlers trace unary and streaming calls and propagate context across services.
  • Gin, Echo and other web frameworks. Contrib middleware for common routers adds spans with route templates instead of raw paths.
  • database/sql, Redis and Kafka clients. Instrumented drivers and clients turn queries, cache calls and messages into spans with timing.
  • Go runtime. The contrib runtime package reports goroutines, memory, GC goal, GOMAXPROCS and scheduler latency per OpenTelemetry semantic conventions.
  • Containers and Kubernetes. The Obseria Agent enriches every Go service with pod, node and container metadata.
At a glance

The Go signals that matter

Obseria collects these values automatically and shows them in ready-made dashboards and alerts.

Response speed

Shows how quickly your Go services answer requests, so slow pages and APIs are noticed before customers complain.

  • http.server.request.duration

Parallel work

Tells you whether the many small tasks inside the application finish normally or get stuck and wait too long.

  • go.goroutine.count
  • go.schedule.duration
  • go.processor.limit

Memory usage

Shows how much memory the application uses compared with its limit, so restarts caused by full memory are avoided.

  • go.memory.used
  • go.memory.limit
  • go.memory.gc.goal

Memory churn

Reveals how much short-lived data the application creates, which drives extra cleanup work and wasted computing power.

  • go.memory.allocated
  • go.memory.allocations
Show all 9 metrics in detail
MetricUnitWhat it tells you
http.server.request.durationsLatency histogram of inbound HTTP requests per route and status code, recorded by otelhttp.
go.goroutine.count{goroutine}Live goroutines; a count that only goes up points to a goroutine leak.
go.schedule.durationsTime goroutines wait to be scheduled; high values mean CPU starvation or GOMAXPROCS limits.
go.memory.usedByMemory used by the Go runtime, the basis for leak and capacity analysis.
go.memory.limitBySoft memory limit from GOMEMLIMIT, reported when a limit is set.
go.memory.allocatedByBytes allocated on the heap; a steep rate drives GC work.
go.memory.allocations{allocation}Number of heap allocations, to find allocation-heavy code paths.
go.memory.gc.goalByHeap size target for the next GC cycle, set by GOGC and GOMEMLIMIT.
go.processor.limit{thread}GOMAXPROCS, the number of OS threads that can run Go code at once.
Setup

Set up Go monitoring in minutes

  1. Step 1

    Add the SDK and exporters

    go get the OpenTelemetry Go SDK, the OTLP HTTP exporters for traces and metrics and the contrib runtime package.

  2. Step 2

    Initialize providers

    Create tracer and meter providers at startup, call runtime.Start and wrap your mux with otelhttp.NewHandler.

  3. Step 3

    Point it to Obseria

    Set OTEL_SERVICE_NAME, the Obseria OTLP endpoint and your token as environment variables; traces and runtime metrics arrive within minutes.

Example configuration · GO
// Modules: go.opentelemetry.io/otel/sdk, .../otel/sdk/metric, .../otlptracehttp,
// .../otlpmetrichttp, go.opentelemetry.io/contrib/instrumentation/runtime and .../otelhttp
// OTEL_SERVICE_NAME, OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_EXPORTER_OTLP_HEADERS
// (Authorization=Bearer%20${OBSERIA_TOKEN}) are read from the environment.
func main() {
    ctx := context.Background()
    traceExp, err := otlptracehttp.New(ctx)
    if err != nil {
        log.Fatal(err)
    }
    tp := sdktrace.NewTracerProvider(sdktrace.WithBatcher(traceExp))
    defer tp.Shutdown(ctx)
    otel.SetTracerProvider(tp)
    otel.SetTextMapPropagator(propagation.TraceContext{})

    metricExp, err := otlpmetrichttp.New(ctx)
    if err != nil {
        log.Fatal(err)
    }
    reader := sdkmetric.NewPeriodicReader(metricExp, sdkmetric.WithProducer(runtime.NewProducer()))
    mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader))
    defer mp.Shutdown(ctx)
    otel.SetMeterProvider(mp)
    runtime.Start() // go.goroutine.count, go.memory.used, go.memory.gc.goal ...

    mux := http.NewServeMux()
    mux.HandleFunc("/orders", handleOrders)
    log.Fatal(http.ListenAndServe(":8080", otelhttp.NewHandler(mux, "orders-api")))
}

Out of the box

Dashboards, alerts and SLOs that are ready the moment data arrives.

  • Go runtime: goroutines, heap, GC goal, scheduler
  • Service health with RED metrics per route
  • Alert on steadily rising goroutine count
  • Alert on memory approaching GOMEMLIMIT
  • Slowest gRPC methods and downstream calls
Guide

Go monitoring: what matters

Why Go monitoring matters

Go is the language of cloud infrastructure and high-throughput backends: API gateways, payment services, Kubernetes operators and CLIs. Go services are usually lean and fast, which is exactly why problems are easy to miss until they hurt. A goroutine leak grows quietly for days, a container memory limit that does not match GOMEMLIMIT causes sudden restarts, and a CPU limit that is lower than GOMAXPROCS leads to throttling and tail latency. Go monitoring brings these runtime details together with request traces so you can tell code, runtime and infrastructure apart.

Unlike Java or Python, Go compiles to a static binary, so the main path for Golang APM is the OpenTelemetry Go SDK plus contrib instrumentation libraries: otelhttp for net/http, otelgrpc for gRPC and wrappers for database drivers and frameworks. Traces and metrics in the Go SDK are stable. For teams that cannot touch code, OpenTelemetry also works on zero-code options for Go, including the eBPF-based opentelemetry-go-instrumentation project and compile-time instrumentation; check their current maturity before relying on them in production.

Signals that matter for Go performance monitoring

  • Request latency and errors: http.server.request.duration per route plus error spans give rate, errors and duration for each service.
  • Goroutines: go.goroutine.count should rise and fall with traffic. A count that only rises is the classic sign of a leak, usually a blocked channel or a missing context cancellation.
  • Scheduler latency: go.schedule.duration shows how long runnable goroutines wait for a thread. High values with moderate CPU often mean CPU throttling in the container.
  • Memory and GC: go.memory.used, go.memory.gc.goal and go.memory.limit show how close the heap is to its target and limit; go.memory.allocated and go.memory.allocations show the pressure behind GC work.
  • Parallelism: go.processor.limit reveals the effective GOMAXPROCS, which should match the CPU you actually get.

Common Go performance problems and how to detect them

Goroutine leaks

Goroutines that wait forever on a channel, a lock or a request without timeout accumulate. Memory follows the goroutine count upward. A trend alert on goroutines per instance catches the leak long before an out-of-memory kill.

GC pressure

Short-lived allocations in hot paths, such as JSON encoding or string building, force frequent GC cycles. Allocation profiles from continuous profiling show which functions to optimize, and the heap goal metric shows the effect.

CPU throttling in containers

If GOMAXPROCS is higher than the container CPU limit, the runtime schedules more work than the quota allows. You see rising scheduler latency and p99 spikes while average CPU looks fine.

Slow downstream calls

Missing timeouts and exhausted connection pools let one slow dependency block many goroutines. Client spans for HTTP, gRPC and SQL make the waiting time visible in every trace.

Retries that amplify load

Aggressive retries in Go clients can turn a short slowdown of one dependency into an overload. Traces with repeated client spans for the same operation, together with a jump in outbound request rate, reveal retry storms quickly.

Best practices for Golang monitoring

  1. Pass context.Context through every call so spans connect and cancellations propagate.
  2. Set service.name, service.version and deployment.environment.name via environment variables to compare releases.
  3. Align GOMEMLIMIT and GOMAXPROCS with container limits, and monitor both runtime and cgroup metrics.
  4. Use route templates as span names to keep cardinality low.
  5. Combine traces with continuous profiling to move from a slow span to the responsible function.

How Obseria helps with Golang APM

Obseria accepts OpenTelemetry Go traces and metrics over OTLP, so you keep the standard SDK and no proprietary agent is needed. The Obseria Agent adds host, container and Kubernetes context, and TopoGraph maps each Go service to its callers, databases and queues. Continuous profiling with under 1% overhead links hot functions to slow traces. When latency rises, Obseria Intelligence correlates goroutine growth, GC pressure, throttling or a deployment and presents the root cause with its chain of evidence. Dashboards, alerts and SLOs are included.

Go monitoring FAQ

The common approach is the OpenTelemetry Go SDK with contrib libraries such as otelhttp and otelgrpc, which needs a few lines at startup. OpenTelemetry also develops eBPF-based and compile-time zero-code options for Go; evaluate their current status for your workloads.

Everything the contrib runtime package emits, including go.goroutine.count, go.memory.used, go.memory.gc.goal, go.processor.limit and, with its producer, go.schedule.duration.

The OpenTelemetry Go SDK is designed for production use. Overhead depends on span volume, so sample routine traffic and keep span names low in cardinality. Continuous profiling in Obseria runs at under 1% overhead.

Yes. Obseria ingests Prometheus metrics via scraping or remote write and supports PromQL, so existing client_golang metrics and dashboards keep working next to OpenTelemetry data.

Yes. Deploy the Obseria Agent as a DaemonSet via Helm and set the OTEL_* variables in your pod spec. Traces are enriched with pod, namespace and node metadata.

Start monitoring Go today

Connect Go in minutes with OpenTelemetry or the Obseria Agent. Free for 14 days.