OpenTelemetry Echo by Labstack [otelecho]

Vladimir Mihailenco
February 20, 2026
5 min read

OpenTelemetry Echo instrumentation allows developers to monitor and diagnose issues with their Echo applications, providing valuable insights into application behavior in production.

Quick Setup

StepActionCode/Command
1. InstallInstall otelecho packagego get go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho
2. ImportImport otelechoimport "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho"
3. InstrumentAdd middleware to Echoe.Use(otelecho.Middleware("my-service"))
4. VerifyCheck your backend for tracesTraces collected automatically

Minimal working example:

go
import (
    "github.com/labstack/echo/v4"
    "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho"
)

func main() {
    e := echo.New()
    e.Use(otelecho.Middleware("my-service"))

    e.GET("/", func(c echo.Context) error {
        return c.JSON(200, map[string]string{"message": "Hello World"})
    })
    e.Start(":8080")
}

This single middleware call automatically captures all incoming HTTP requests, traces request flow, and exports telemetry data to your configured backend.

What is Echo?

Echo is a high performance, extensible, minimalist web framework for Go. It features a highly optimized HTTP router with zero dynamic memory allocations, making it one of the fastest Go web frameworks available.

Echo's key features include:

  • Optimized router with zero dynamic memory allocation
  • Middleware support with built-in middleware
  • Data binding for JSON, XML, and form payloads
  • HTTP/2 support
  • Automatic TLS via Let's Encrypt

Echo's simplicity and performance make it a popular choice for building web applications and RESTful APIs in Go.

What is OpenTelemetry?

OpenTelemetry is an open-source observability framework that aims to standardize and simplify the collection, processing, and export of telemetry data from applications and systems.

OpenTelemetry supports multiple programming languages and platforms, making it suitable for a wide range of applications and environments.

OpenTelemetry enables developers to instrument their code and collect telemetry data, which can then be exported to various OpenTelemetry backends or observability platforms for analysis and visualization. The OpenTelemetry architecture provides a modular, vendor-neutral approach to observability.

Configuration can be managed through OpenTelemetry environment variables, providing a standardized way to configure exporters, resource attributes, and sampling behavior across environments.

Echo instrumentation

OpenTelemetry Echo instrumentation (otelecho) provides automatic tracing and metrics collection for your Echo applications. It captures HTTP request details, timing information, and error states without requiring manual instrumentation.

Note: Metrics support (WithMeterProvider, WithMetricAttributeFn, WithEchoMetricAttributeFn) requires otelecho v0.63.0 or later.

To install otelecho instrumentation:

shell
go get go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho

Usage

You can instrument Echo router by installing OpenTelemetry middleware:

go
import (
    "github.com/labstack/echo/v4"
    "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho"
)

func main() {
    e := echo.New()
    e.Use(otelecho.Middleware("my-service"))

    e.GET("/users/:id", getUser)
    e.Start(":8080")
}

Once instrumented, otelecho automatically creates spans for each incoming HTTP request, capturing method, route, status code, and timing information.

Middleware options

The otelecho middleware supports several configuration options:

OptionDescription
WithTracerProviderUse a custom TracerProvider instead of the global one
WithMeterProviderUse a custom MeterProvider instead of the global one
WithPropagatorsSpecify propagators for extracting trace context
WithSkipperSkip tracing (return true to skip, false to trace)
WithMetricAttributeFnExtract custom attributes from http.Request for metrics
WithEchoMetricAttributeFnExtract custom attributes from echo.Context for metrics

Skipping health checks

Use the WithSkipper option to exclude certain endpoints from tracing:

go
import (
    "github.com/labstack/echo/v4"
    "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho"
)

e := echo.New()
e.Use(otelecho.Middleware("my-service",
    otelecho.WithSkipper(func(c echo.Context) bool {
        // Return true to skip, false to trace
        return c.Path() == "/health" || c.Path() == "/ready"
    }),
))

Custom tracer and meter providers

For more control over telemetry collection, you can specify custom providers:

go
import (
    "github.com/labstack/echo/v4"
    "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho"
    "go.opentelemetry.io/otel"
)

e := echo.New()
e.Use(otelecho.Middleware("my-service",
    otelecho.WithTracerProvider(otel.GetTracerProvider()),
    otelecho.WithMeterProvider(otel.GetMeterProvider()),
))

Adding custom attributes

Extract custom attributes from requests to enhance your metrics:

go
import (
    "net/http"

    "github.com/labstack/echo/v4"
    "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho"
    "go.opentelemetry.io/otel/attribute"
)

e := echo.New()
e.Use(otelecho.Middleware("my-service",
    otelecho.WithMetricAttributeFn(func(r *http.Request) []attribute.KeyValue {
        return []attribute.KeyValue{
            attribute.String("http.client_ip", r.RemoteAddr),
            attribute.String("http.user_agent", r.UserAgent()),
        }
    }),
))

HTTP metrics

Starting from v0.63.0, the otelecho middleware automatically collects the following HTTP server metrics:

MetricDescription
http.server.request.durationDuration of HTTP server requests
http.server.request.body.sizeSize of HTTP server request bodies
http.server.response.body.sizeSize of HTTP server response bodies

These metrics follow the OpenTelemetry semantic conventions for HTTP and include attributes like method, route, and status code.

Creating Custom Spans

Add custom spans to trace specific operations within your handlers:

go
import (
    "net/http"

    "github.com/labstack/echo/v4"
    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/attribute"
)

var tracer = otel.Tracer("my-service")

func getUser(c echo.Context) error {
    ctx := c.Request().Context()

    // Create a custom span for the database query
    ctx, span := tracer.Start(ctx, "fetch_user")
    defer span.End()

    userID := c.Param("id")
    span.SetAttributes(attribute.String("user.id", userID))

    user, err := fetchUserFromDB(ctx, userID)
    if err != nil {
        span.SetAttributes(attribute.Bool("user.found", false))
        return c.JSON(http.StatusNotFound, map[string]string{"error": "User not found"})
    }

    span.SetAttributes(attribute.Bool("user.found", true))
    return c.JSON(http.StatusOK, user)
}

Recording Errors

Record errors on spans to mark them as failed and capture error details:

go
import (
    "net/http"

    "github.com/labstack/echo/v4"
    "go.opentelemetry.io/otel/codes"
    "go.opentelemetry.io/otel/trace"
)

func processOrder(c echo.Context) error {
    span := trace.SpanFromContext(c.Request().Context())

    var order Order
    if err := c.Bind(&order); err != nil {
        span.RecordError(err)
        span.SetStatus(codes.Error, "invalid request body")
        return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
    }

    if err := validateOrder(order); err != nil {
        span.RecordError(err)
        span.SetStatus(codes.Error, err.Error())
        return c.JSON(http.StatusUnprocessableEntity, map[string]string{"error": err.Error()})
    }

    return c.JSON(http.StatusOK, map[string]string{"status": "ok"})
}

FAQ

What versions of Echo are supported? The otelecho middleware supports Echo v4. If you're still on Echo v3, upgrade to v4 first—the migration is straightforward and well-documented.

How do I pass context to downstream services? The otelecho middleware automatically injects trace context into the request context. Use c.Request().Context() to retrieve it, then pass it to your database clients, HTTP clients, or gRPC calls to propagate tracing across services.

Why are my health check endpoints cluttering traces? Use WithSkipper to exclude /health and /ready endpoints. This reduces noise and lowers telemetry costs without losing visibility into real traffic.

Can I use otelecho with Echo's built-in middleware? Yes. Place otelecho.Middleware early in the middleware chain (before logging, auth, etc.) so that all downstream middleware and handlers are captured in the trace.

How do I add metrics alongside traces? Starting from otelecho v0.63.0, the middleware automatically collects HTTP server metrics (http.server.request.duration, http.server.request.body.size, http.server.response.body.size). Configure a MeterProvider to export them.

What is Uptrace?

Uptrace is an OpenTelemetry APM that supports distributed tracing, metrics, and logs. You can use it to monitor applications and troubleshoot issues.

Uptrace Overview

Uptrace comes with an intuitive query builder, rich dashboards, alerting rules with notifications, and integrations for most languages and frameworks.

Uptrace can process billions of spans and metrics on a single server and allows you to monitor your applications at 10x lower cost.

In just a few minutes, you can try Uptrace by visiting the cloud demo (no login required) or running it locally with Docker. The source code is available on GitHub.

What's next?

With OpenTelemetry Echo instrumentation in place, you can monitor request latency, track error rates, and trace requests across your distributed systems.

Next steps to enhance your observability: