Skip to main content
Guides

OpenTelemetry

Gatekeeper emits traces, metrics, and logs via OpenTelemetry. Configuration uses standard OTEL_* environment variables — no YAML knobs required.

Prerequisites

  • A working gatekeeper configuration
  • An OpenTelemetry collector or compatible backend (Jaeger, Grafana, Honeycomb, etc.)

Configuration

Set OTEL environment variables before starting gatekeeper:

export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
export OTEL_SERVICE_NAME="gatekeeper"
gatekeeper --config gatekeeper.yaml

For authenticated endpoints:

export OTEL_EXPORTER_OTLP_ENDPOINT="https://your-collector:4318"
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer <token>"

Gatekeeper creates OTLP HTTP exporters for traces, metrics, and logs and registers them as global providers.

To disable the OTel SDK entirely, set OTEL_SDK_DISABLED=true (case-insensitive; any other value, or leaving it unset, keeps the SDK enabled):

export OTEL_SDK_DISABLED=true

With the SDK disabled, gatekeeper skips exporter setup and provider registration — no traces, metrics, or logs are emitted, and no connection to a collector is attempted.

Traces

Every proxy request creates a span. Span names reflect the request type:

Request TypeSpan Name
CONNECTproxy.request
MCP relayproxy.mcp
HTTP relayproxy.relay
Plain HTTPproxy.http

Each span includes attributes:

  • http.request.method — request method
  • server.address — target host
  • proxy.request.type — one of connect, mcp, relay, http
  • http.response.status_code — response status (not set for hijacked CONNECT connections)

A request.complete event is added to each span with detailed context: request_id, duration_ms, credential_injected, injected_headers, grants, denied, and deny_reason.

Metrics

Four instruments are registered under the gatekeeper meter:

MetricTypeDescriptionAttributes
proxy.request.durationHistogram (s)Request duration in secondshttp.request.method, server.address, proxy.request.type, http.response.status_code
proxy.request.countCounterTotal proxy requestsSame as above
proxy.credential.injectionsCounterCredential injection countserver.address, proxy.credential.header
proxy.policy.denialsCounterPolicy denial countproxy.policy.scope, proxy.policy.rule

Logs

Gatekeeper bridges slog output to OTel via otelslog. Structured log records are sent to both the configured slog handler (text/JSON to stderr) and the OTel log exporter. Log records carry trace context for correlation.

Local collector example

Run a local OpenTelemetry Collector with Jaeger:

docker run -d --name jaeger \
  -p 4318:4318 \
  -p 16686:16686 \
  jaegertracing/all-in-one:latest

Start gatekeeper pointing to the local collector:

export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
export OTEL_SERVICE_NAME="gatekeeper"
gatekeeper --config gatekeeper.yaml

Make a request through the proxy, then open http://localhost:16686 to view traces.

Verification

After sending requests through the proxy, confirm traces and metrics are arriving at the collector. In Jaeger, search for service gatekeeper and look for proxy.request spans with credential_injected=true events.

Troubleshooting

Export failures (for example, no collector listening at the configured OTEL_EXPORTER_OTLP_ENDPOINT) log at DEBUG level rather than INFO, so they don’t drown canonical request log lines when the log level is info. If traces or metrics aren’t arriving and nothing appears in gatekeeper’s logs, set log.level: debug (or run with a debug-level slog handler) to surface the underlying export errors.

Note: Without a registered OTel error handler, export errors fall through to the standard library log package, which gatekeeper’s logging setup rewires through the configured slog handler at INFO level. Gatekeeper registers its own handler so these errors log at DEBUG instead.

Next steps

  • Go Library — embed gatekeeper in a Go application with custom instrumentation