Skip to content
Last9
Book demo

net/http

Instrument Go standard library net/http applications with the Last9 Go Agent for automatic HTTP tracing and metrics

Use the Last9 Go Agent to instrument applications using Go’s standard net/http package — no framework required. The agent wraps the official OpenTelemetry otelhttp package with automatic setup and minimal code changes.

Prerequisites

  • Go 1.22 or higher
  • Last9 account with OTLP credentials

Installation

  1. Install the Last9 Go Agent

    go get github.com/last9/go-agent
  2. Set Environment Variables

    export OTEL_SERVICE_NAME="your-service"
    export OTEL_EXPORTER_OTLP_ENDPOINT="$last9_otlp_endpoint"
    export OTEL_EXPORTER_OTLP_HEADERS="Authorization=$last9_otlp_auth_header"
    export OTEL_TRACES_SAMPLER="always_on"
    export OTEL_RESOURCE_ATTRIBUTES="deployment.environment=production"
  3. Instrument your application

    The simplest approach — replace http.NewServeMux() with nethttpagent.NewServeMux():

    package main
    import (
    "log"
    "net/http"
    "github.com/last9/go-agent"
    nethttpagent "github.com/last9/go-agent/instrumentation/nethttp"
    )
    func main() {
    if err := agent.Start(); err != nil {
    log.Fatalf("failed to start agent: %v", err)
    }
    defer agent.Shutdown()
    // Drop-in replacement for http.NewServeMux()
    mux := nethttpagent.NewServeMux()
    mux.HandleFunc("/", indexHandler)
    mux.HandleFunc("/users", usersHandler)
    log.Fatal(http.ListenAndServe(":8080", mux))
    }

TLS Support

// Drop-in replacement for http.ListenAndServeTLS
log.Fatal(nethttpagent.ListenAndServeTLS(":8443", "cert.pem", "key.pem", mux))

Wrap an Existing http.Server

srv := &http.Server{
Addr: ":8080",
Handler: mux,
}
// Instruments the server's handler in place
nethttpagent.Server(srv)
log.Fatal(srv.ListenAndServe())

Context Propagation Helpers

For manual W3C traceparent propagation between services:

// Extract incoming trace context from a request
func incomingHandler(w http.ResponseWriter, r *http.Request) {
ctx := nethttpagent.ExtractContext(r.Context(), r)
// ctx now carries the upstream trace
}
// Inject outgoing trace context into a request
func outgoingHandler(w http.ResponseWriter, r *http.Request) {
outReq, _ := http.NewRequestWithContext(r.Context(), "GET", "https://service-b/api", nil)
nethttpagent.InjectContext(r.Context(), outReq)
// outReq now carries traceparent header
}

Database Instrumentation

import "github.com/last9/go-agent/integrations/database"
db, err := database.Open(database.Config{
DriverName: "postgres",
DSN: "postgres://user:pass@localhost/mydb",
DatabaseName: "mydb",
})
if err != nil {
log.Fatal(err)
}
defer db.Close()
func usersHandler(w http.ResponseWriter, r *http.Request) {
rows, err := db.QueryContext(r.Context(), "SELECT id, name FROM users")
// ...
}

The agent automatically extracts server.address, server.port, db.user, and db.name from the DSN and attaches them to every span.

Redis Instrumentation

import redisagent "github.com/last9/go-agent/integrations/redis"
// Drop-in replacement for redis.NewClient()
rdb := redisagent.NewClient(&redis.Options{
Addr: "localhost:6379",
})
func cacheHandler(w http.ResponseWriter, r *http.Request) {
val, err := rdb.Get(r.Context(), "key").Result()
// ...
}

HTTP Client Instrumentation

For outgoing requests with automatic traceparent propagation:

import httpagent "github.com/last9/go-agent/integrations/http"
client := httpagent.NewClient(&http.Client{
Timeout: 10 * time.Second,
})
func proxyHandler(w http.ResponseWriter, r *http.Request) {
req, _ := http.NewRequestWithContext(r.Context(), "GET", "https://upstream.example.com/api", nil)
resp, err := client.Do(req)
// ...
}

What Gets Traced Automatically

SignalWhat’s captured
TracesEvery HTTP request: method, route pattern, status code, latency
TracesDatabase queries: SQL statement, db system, server address/port
TracesRedis commands: command name, key
TracesOutbound HTTP: method, URL, status code
MetricsRuntime: memory, GC pause, goroutine count
MetricsHTTP: request duration, request/response sizes, active connections
MetricsDatabase: connection pool usage, idle, wait time

View Traces and Metrics

After running your application, navigate to Trace Explorer and Metrics Explorer in Last9 to view your telemetry data.


Troubleshooting

Please get in touch with us on Discord or Email if you have any questions.