Debug logging
The plugin prints only essential startup messages (backend connected / failed, hook count) to stdout. Everything else goes to a debug log file that's off by default.
Enabling
export HERMES_OTEL_DEBUG=true
Then restart Hermes. The log file is:
~/.hermes/plugins/hermes_otel/debug.log
It's append-only — old entries stick around until you delete the file. No rotation; if you use debug mode for long periods, rm debug.log occasionally or pipe through logrotate.
What gets logged
With debug enabled, every hook logs:
[2026-04-19 14:12:33.104] pre_tool_call tool=bash session_id=abc123 parent=api.claude-sonnet-4-6 args={"command": "ls -la"}
[2026-04-19 14:12:33.812] post_tool_call tool=bash duration_ms=708 outcome=completed result_len=1284
Span lifecycle events:
[2026-04-19 14:12:33.104] span.start name=tool.bash span_id=0x3a7b parent_span_id=0xff12 trace_id=0x0001...
[2026-04-19 14:12:33.812] span.end name=tool.bash duration_ms=708 attr_count=18
OTLP export attempts:
[2026-04-19 14:12:34.001] export backend=phoenix batch=12 spans duration=42ms status=200
[2026-04-19 14:12:34.245] export backend=langfuse batch=12 spans duration=1284ms status=200
Queue warnings:
[2026-04-19 14:12:40.123] ▲ phoenix queue full — dropped 5 spans (queue_size=2048)
And the OTLP request bodies, redacted for secrets:
[2026-04-19 14:12:34.001] POST http://localhost:6006/v1/traces body={"resourceSpans": [...]} headers={"Authorization": "Bearer ***REDACTED***"}
Secret masking
The debug logger passes any header value matching a known secret-carrying name (Authorization, api_key, x-honeycomb-team, signoz-ingestion-key, etc.) through a masker. Only the first 4 and last 4 characters of the value are logged; the middle is replaced with ***.
If a secret is logged unredacted, that's a bug — open an issue.
Typical workflows
"Spans aren't showing up in the backend"
export HERMES_OTEL_DEBUG=true
# Run one Hermes turn
tail -f ~/.hermes/plugins/hermes_otel/debug.log
Look for:
export backend=... status=...— is the export succeeding?▲ queue full— the queue is overwhelmedspan.endcount ≈ what you expect from the turn's tool calls- No
span.start/span.endat all? Checkpre_*hook lines — the hooks might not be firing
"Wrong parent/child nesting"
Look for span.start lines; verify parent_span_id matches the expected parent's span_id from a previous span.start. Misnesting usually means the SpanTracker parent stack is confused — often because of an error path that skipped a post_* hook.
"Token counts are zero"
Find the post_api_request log line; check the usage= field. If it's missing or {}, the provider didn't return usage data (some streaming responses don't). Not a plugin bug.
Performance impact
The debug log writes synchronously via Python's logging module with a FileHandler. Write latency is a few hundred microseconds per call — cheap, but not free. On very high-throughput deployments, debug logging can add 1-5% overhead. Turn it off when you're done debugging.
Disabling
unset HERMES_OTEL_DEBUG
# or
export HERMES_OTEL_DEBUG=false
Restart Hermes. The file isn't deleted on disable; rm ~/.hermes/plugins/hermes_otel/debug.log to clean up.