Operation
Tracing

OpenTelemetry tracing

AIOpen as plain markdown for AI

eRPC instruments every layer of the request pipeline (HTTP server → network → upstream → cache → failsafe → client) with OpenTelemetry spans. Export over OTLP (gRPC or HTTP) to Jaeger, Tempo, Honeycomb, Datadog, or any OTel-compatible backend.

You can configure:

  • Where to send — OTLP endpoint, gRPC or HTTP transport, optional TLS, optional auth headers
  • How much to sendsampleRate (probabilistic), forceTraceMatchers (always-trace specific network/method combos), detailed (include high-cardinality attributes)
  • How to labelserviceName and arbitrary resourceAttributes (env-var expanded)

Minimum useful config

A working setup with 10% sampling, gRPC export to a local Jaeger.

tracing
erpc.yaml
server: # ...projects: # ...
tracing:  enabled: true  endpoint: localhost:4317           # OTLP gRPC endpoint  protocol: grpc                     # "grpc" or "http"  sampleRate: 0.1                    # 10% probabilistic sampling  serviceName: erpc-prod             # OTel service.name resource attribute  detailed: false                    # set true to include high-cardinality attrs

Force-tracing specific methods

When you need deterministic traces for a specific (network, method) pair regardless of the global sampleRate, use forceTraceMatchers. Useful for debugging a customer-impacting issue without raising the global sample rate.

tracingforceTraceMatchers[]
erpc.yaml
tracing:  enabled: true  endpoint: localhost:4317  protocol: grpc  sampleRate: 0.01                # 1% global sample  forceTraceMatchers:    - network: "evm:1"             # always trace mainnet      method: "eth_getLogs"        # ...for getLogs specifically    - network: "evm:*"      method: "debug_*|trace_*"    # always trace expensive trace/debug methods on any chain

Custom resource attributes

Attach instance-level metadata that flows into every span. Useful for filtering by region, machine, or pod in your tracing backend.

tracing:
  enabled: true
  endpoint: localhost:4317
  resourceAttributes:
    fly.region: ${FLY_REGION}
    fly.machine_id: ${FLY_MACHINE_ID}
    # Or for Kubernetes:
    # k8s.pod_name: ${HOSTNAME}
    # k8s.node_name: ${NODE_NAME}

Values support ${VAR} env-var expansion. Attributes with empty values (after expansion) are automatically omitted.

Using with Jaeger

The repo's docker-compose.yml (opens in a new tab) includes a Jaeger service for development.

docker-compose up jaeger
tracing:
  enabled: true
  endpoint: localhost:4317
  protocol: grpc
  sampleRate: 1.0        # sample everything during development
  detailed: true

Then open the Jaeger UI at http://localhost:16686 (opens in a new tab).

Copy for your AI assistant — full tracing referenceExpand for every option, default, and edge case — or copy this entire section into your AI assistant.

TracingConfig — every field

FieldTypeDefaultNotes
enabledboolfalseMaster switch. When false, no spans are exported (instrumentation still runs as no-ops).
endpointstringOTLP exporter target. For gRPC: host:port (e.g. localhost:4317). For HTTP: full URL (e.g. http://localhost:4318/v1/traces).
protocol"grpc"|"http"grpcOTLP transport. grpc uses standard OTLP/gRPC; http uses OTLP/HTTP+protobuf.
sampleRatefloat 0..10Probabilistic head sampling — fraction of root spans recorded. 0 = no traces; 1.0 = every request.
detailedboolfalseWhen true, includes high-cardinality attributes on spans: request JSON-RPC IDs, request params, actual cache keys, internal mutex/lock spans. Significantly increases trace volume; use sparingly.
serviceNamestringhostname-derivedOverrides the OTel service.name resource attribute that tracing backends use as the service grouping.
headersmap[string]stringnoneExtra headers attached to OTLP exporter requests. Use for authenticated collectors: e.g. Authorization: Bearer ... for Honeycomb / DataDog / Tempo Cloud.
tlsTLSConfignoneTLS for OTLP/gRPC connections. See "TLS sub-fields" below.
resourceAttributesmap[string]stringnoneExtra OTel resource attributes attached to every span. Values support ${VAR} env-var expansion; empty values are dropped.
forceTraceMatchers[]ForceTraceMatcher[]noneForce-trace rules that bypass sampleRate. See "ForceTraceMatcher" below.

Key spans you'll see:

  • HTTP server request handling
  • Network-level (chain) forwarding — the Network.Forward span carries the full per-request execution trace (execution.attempts, upstreams.tried, upstreams.outcomes, upstreams.reasons, upstreams.durations_ms). See failsafe → Per-attempt observability.
  • Upstream-level request forwarding
  • Cache operations (get/set)
  • Failsafe executor operations (hedges, retries, timeouts, breaker probes)
  • HTTP client requests to upstreams
  • Rate limiters

TLS sub-fields (when protocol: grpc with TLS)

The tls block uses the shared TLSConfig struct. See TLS configuration for the full field reference (enabled, certFile, keyFile, caFile, insecureSkipVerify).

Example for a gRPC OTLP collector with mutual-TLS:

tracing:
  endpoint: collector.example.com:4317
  protocol: grpc
  tls:
    enabled: true
    certFile: /path/to/client.crt        # optional client cert
    keyFile: /path/to/client.key         # optional client key
    caFile: /path/to/ca.crt              # CA chain for verifying the collector
    insecureSkipVerify: false            # set true for development; never in prod

ForceTraceMatcher

forceTraceMatchers:
  - network: <matcher-pattern>
    method: <matcher-pattern>
FieldNotes
networkMatcher pattern (matcher syntax: *, |, !). e.g. evm:1, evm:1|evm:10, evm:*. When omitted, matches any network.
methodSame matcher syntax. e.g. eth_getLogs, eth_*, debug_*|trace_*. When omitted, matches any method.

A request is force-traced if any matcher's network AND method both match. Force-traced requests bypass sampleRate entirely (treated as sampled-in regardless of the random draw).

Common uses:

  • Always trace expensive methods: { method: "debug_*|trace_*" }
  • Always trace one chain that's the focus of debugging: { network: "evm:42161" }
  • Trace one method on one chain during a customer escalation: { network: "evm:1", method: "eth_call" }

Headers — concrete examples

For authenticated OTLP collectors:

# Honeycomb
tracing:
  endpoint: api.honeycomb.io:443
  protocol: grpc
  headers:
    x-honeycomb-team: ${HONEYCOMB_API_KEY}
 
# Grafana Cloud Tempo (basic auth via Authorization header)
tracing:
  endpoint: tempo-eu-west-0.grafana.net:443
  protocol: grpc
  headers:
    Authorization: Basic \${GRAFANA_CLOUD_BASIC_AUTH}
 
# Self-hosted with mTLS, no headers needed (use tls.* instead)

Authorization headers should use env-var interpolation; never commit credentials to YAML/TS.

Traced components

Every span eRPC emits is a child of an HTTP server root span. The instrumented layers:

LayerWhat spans cover
HTTP serverParsing, auth check, project + network selection, response serialization
Network forwardingSelection-policy eval, upstream pick, retry/hedge/consensus orchestration
Upstream forwardingRate-limit check, payload assembly, response normalization
CacheGet/set per policy, compression/decompression, multi-connector fanout
FailsafeEach attempt within a retry/hedge; circuit-breaker decisions; consensus participants
HTTP clientOutbound request, response read
Rate limitersToken acquisition, queue wait

detailed: true adds finer-grained internal spans (mutexes, internal selection-policy bookkeeping) and high-cardinality attributes.

Common pitfalls

  • sampleRate: 0.1 and 100% of force-traced requestsforceTraceMatchers operates on top of sampling; force-traced requests are not subject to the rate. So your collector ingests sampleRate * total + forceTraced. Make sure that's affordable.
  • detailed: true in production — request params and cache keys can be huge (think eth_getLogs filters), and they hit your ingest cost. Reserve for debugging.
  • headers interpolation${VAR} is only resolved at config load time. Rotating tokens requires a config reload.
  • tls.insecureSkipVerify: true — accepts any cert. Never set in production; use a proper CA chain or mTLS.
  • protocol: http without https:// in endpoint — exports go to plaintext HTTP. Most managed providers require HTTPS; set the endpoint to the https://.../v1/traces form.
  • OTLP/HTTP endpoint formatprotocol: http expects a FULL URL including the /v1/traces path segment; protocol: grpc expects just host:port without scheme.

Append .llms.txt to this URL (or use the AI link above) to fetch the entire expanded reference as plain markdown for an AI assistant.