Skip to main content
Sherlock has no Go distribution and needs none. The upstream OpenTelemetry Go SDK sends what Sherlock expects once four things are set: delta metrics, exemplars on every request, a trace_flags attribute on each exemplar, and Sherlock’s histogram boundaries. One file, sherlock.go, takes care of them. This page adds it to a net/http service. The file comes in two variants that send the same data. In the first, every Sherlock setting is written in the file, so a reader sees all of them in one place. In the second, the standard OTEL_* environment variables carry the settings, which suits a team that already configures OpenTelemetry that way, and the file is shorter. Step 2 has both. Configuration covers production settings such as health checks, custom histograms, sampling, and logs. Differences from Node.js lists what the Go setup does differently from the Sherlock SDK for Node.js.

What you’ll learn

  • Which modules to add, at which versions
  • The two places the Sherlock settings can live, and what stays in code either way
  • What sherlock.go sets, and why each setting is there
  • Where the first traces and metrics show up

Prerequisites

  • Go 1.22 or later, for ServeMux method-and-path patterns. Tested with Go 1.25.
  • A Sherlock organization and its bearer token from Settings → Collector. Get started shows where.
  • A service on net/http. For other routers, see Routers and nested muxes.

Steps

1

Add the modules

These are the versions this page was tested with. Recent contrib releases changed behavior that this page relies on: otelhttp.WithRouteTag was removed and the OTEL_SEMCONV_STABILITY_OPT_IN switch is gone. Keep the pins until you have tested an upgrade.
2

Add sherlock.go and set the environment

Pick one variant. Save the file next to your main.go and export the variables it expects. Nothing in either file is specific to your routes.
sherlock.go
What it sets, and why:The file reads four variables:
Settings → Collector shows the Endpoint and the Bearer Token for your organization; copy both, since the endpoint differs by organization. env selects the source the data lands in, so use the value you chose in Get started. A value that matches no source is not shown.
3

Wrap your server

Call Setup before the server starts, wrap the mux with otelhttp.NewHandler, and on shutdown stop the server first, then flush telemetry. This main.go is complete and works with either variant.
main.go
Register handlers with method-and-path patterns, such as GET /work. The span name and the http.route metric attribute come from the pattern. A handler registered as a bare path gives a span named GET with no route, and a mux mounted behind http.StripPrefix reports its mount pattern for every inner route. See Routers and nested muxes.
4

Run

Send a few requests so there is something to look at:
5

Open Sherlock

  • Traces. Open Traces, switch to the Spans view, and pick checkout-api. Spans leave in batches of a few seconds. Each request from this main.go is one span named by its pattern, GET /work, with http.response.status_code on it. The Traces view lists only traces with more than one span, so it stays empty until a request makes a nested call.
  • Metrics. Open Metrics and choose http.server.request.duration. It appears after the first export, 60 seconds by default. Group by http.route to see the two routes apart. Each bucket carries an exemplar; click one to open the request’s trace.
  • Runtime. With the settings-in-the-file variant, go.goroutine.count and go.memory.used are on the same page.
Stop the app with Ctrl-C. The shutdown waits for the server to close, then flushes the last spans and metrics; both arrive.

What arrives

Outbound calls through an otelhttp.NewTransport client add http.client.request.duration with the same boundaries. Logs are not sent by this setup. Logs with trace ids adds them over OTLP with the same bearer token, or stamps stdout lines for a collector.

Troubleshooting

Export errors go to stderr through the SDK’s error handler, prefixed with traces export: or failed to upload metrics:. A 401 means the token is wrong or missing. Check that the endpoint and token variables are set in the shell that runs the service, that both match Settings → Collector, and that the endpoint has no trailing path.
The env value in OTEL_RESOURCE_ATTRIBUTES did not match a source. Compare it with the source’s match value under Settings → Collector.
A request matched no pattern, or a health checker hit the service. Requests that match no pattern get no http.route. Health checks need a filter; there is no default ignore list. See Skip health checks.
The periodic reader exports every 60 seconds by default. Set OTEL_METRIC_EXPORT_INTERVAL=30000 for 30 seconds. The catalog refreshes every 60 seconds on top of that.

Configuration

Health checks, custom histograms, sampling, kill switches, logs, shutdown.

Differences from Node.js

What to expect if you know the Sherlock SDK for Node.js.

Traces

Find a request, read the waterfall, jump to its logs.

Exemplars

From a spike on a chart to the request behind it.