You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Two independent outputs from the same instrumentation events, no overlap:
1. Logs to stderr. Text formatter (default) for dev; JSON Lines
(ESET_MCP_LOG_FORMAT=json) for prod log shippers. Every layer emits a
typed 'event' record with low-cardinality fields - tool_call,
token_refresh, http_request_complete, http_request_retry,
server_starting, onprem_default.
2. Prometheus metrics at /metrics (opt-in via ESET_MCP_METRICS_ENABLED=true).
Mounted on the same uvicorn server but bypasses the basic-auth
middleware - scrapers can't speak Basic, and /metrics carries no
secrets. Protect at the network layer.
Counters: esetmcp_tool_calls_total{tool,deployment,status}
esetmcp_token_refresh_total{deployment,reason}
esetmcp_http_retries_total{deployment,status}
esetmcp_responses_capped_total{tool}
Histograms: esetmcp_tool_duration_seconds{tool,deployment}
esetmcp_response_bytes{tool,deployment}
Gauge: esetmcp_client_pool_size
prometheus_client is an OPTIONAL dependency (pip install eset-mcp[metrics]).
When missing, all metric helpers are no-ops and /metrics returns a 503
with a hint.
Defensive secrets gate (the whole point):
The log_event() helper applies a hard-coded deny-list before any field
reaches a formatter. Anything whose key contains 'password', 'secret',
'token', 'authorization', 'cookie', 'api_key', 'bearer', 'credentials',
or 'cf-access-client-*' is dropped entirely - no '****' redaction, no
'value present but hidden' marker. Even if a future caller accidentally
passes Authorization=..., it never appears in any log artefact under any
circumstance.
Path templates from the OpenAPI spec are logged ('/v1/devices/{deviceUuid}')
but the SUBSTITUTED path (with the actual UUID) is never logged - that
would leak tenant data through request-id correlation.
Username (api@firma.tld) is logged - useful for per-tenant debugging,
not a secret. NEVER appears as a metric label (would explode cardinality).
Test coverage: tests/test_observability.py adds 36 unit tests:
- Sensitive-key matcher against 15 representative keys
- _scrub() removes sensitive keys, keeps safe ones
- log_event() drops sensitive fields end-to-end (asserts no leakage in
the serialised line text, not just the parsed record)
- JSON formatter produces parseable lines with ISO-Z timestamps
- Text formatter appends scrubbed extras
- configure_logging() is idempotent (no handler stacking)
- All metric helpers callable; /metrics returns Prometheus content-type
and contains the expected metric names/labels
- /metrics ignores lifespan scope without crashing
Snyk Code: 0 issues in eset_mcp/observability/. Ruff: clean. Tests:
136/136 unit + 11 RO smoke against real ESET passed.
0 commit comments