What You Get
The stack ingests logs into OpenSearch and exposes them through OpenSearch Dashboards for ad-hoc querying and dashboarding. Prometheus backs metrics with its own UI. You can see per-agent and per-project activity for:- Cost and token usage — API call costs, input/output tokens, rate limiting
- Coding activity — file edits, tool invocations, command executions
- Tool usage — which tools the agent calls, how often, and how long they take
- Session detail — full event timeline for individual agent sessions
- Egress traffic — Envoy access logs and CoreDNS query logs from the firewall stack (when enabled)
Architecture
The monitoring stack runs as four long-lived Docker Compose services on theclawker-net network, plus one short-lived bootstrap container that runs at bring-up (and on monitor reload) to preconfigure the cluster:
CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1 flag (baked into the image alongside CLAUDE_CODE_ENABLE_TELEMETRY=1). The OTEL Collector’s spanmetrics connector also produces RED (rate/error/duration) metrics from incoming spans and feeds them into the same Prometheus pipeline.
Services
All containers are pre-configured with labels (
dev.clawker.purpose=monitoring) and attached to the clawker-net network. The OpenSearch security plugin is disabled by default for local development — Dashboards is reachable at http://localhost:5601 with no login required. Set OPENSEARCH_JAVA_OPTS via the opensearch_heap_mb setting if you need more heap.
Service Hostnames
The monitoring services have fixed, stable hostnames onclawker-net. Agent containers resolve otel-collector and prometheus through the firewall’s DNS, since agents push telemetry through the collector and never query OpenSearch directly. opensearch-node and opensearch-dashboards are deliberately left out of that forwarded set — other containers on clawker-net that do need them reach them via Docker’s embedded resolver.
How Agents Connect
Infrastructure telemetry (egress, DNS, CLI, control plane) is emitted host-side for every harness. Agent-session OTEL endpoints are baked into images whose harness bundle declares them — the claude bundle ships a full OTLP env block. At container creation, Clawker checks whether the monitoring stack is running and conditionally enables telemetry:OTEL_EXPORTER_OTLP_ENDPOINT— single base URL pointing at the collector’s OTLP/HTTP listener (baked into image). The Claude Code SDK appends/v1/metrics,/v1/logs,/v1/tracesper signalOTEL_METRICS_EXPORTER/OTEL_LOGS_EXPORTER/OTEL_TRACES_EXPORTER— baked tootlp, overridden tononeat container creation when theotel-collectorcontainer is not detected as running onclawker-netCLAUDE_CODE_ENABLE_TELEMETRY— always1(baked into the image; not conditionally toggled — the exporter overrides above are what turn telemetry off)CLAUDE_CODE_ENHANCED_TELEMETRY_BETA— set to1(gates Claude Code’s span export; both this andCLAUDE_CODE_ENABLE_TELEMETRYmust be1for traces to flow)OTEL_RESOURCE_ATTRIBUTES— tags withproject=andagent=for filtering
agent.env in your .clawker.yaml even when the stack is down, but Claude Code won’t retry failed collector connections.
Start the monitoring stack before starting your agents to ensure telemetry is captured.
Egress Traffic Visibility
When the firewall is enabled, Envoy and CoreDNS access logs flow into OpenSearch alongside agent telemetry, plus a per-decision-point eBPF event stream that closes the bypass-mode forensic gap.- Envoy access logs (
clawker-envoy) —server.address(host the client asked for),network.peer.address/network.peer.port(post-resolution upstream),network.transport/network.protocol.name/network.protocol.version,tls.established/tls.protocol.version/tls.cipher,action(clawker firewall verdict:allowed/denied),response_code/response_code_details(distinguishes Envoydirect_responsefrom upstreamvia_upstream), duration breakdown (req_duration_ms/resp_duration_ms/resp_tx_duration_ms/duration_ms), and byte counters. Queryaction:deniedfor clawker firewall blocks;response_code:>=400 AND action:allowedfor upstream errors. - CoreDNS query logs (
clawker-coredns) — querieddomain,qtype(A/AAAA),rcode(NOERROR / NXDOMAIN), resolutionduration.rcode:NXDOMAINis ambiguous: it covers both DNS-layer firewall blocks (non-allowlisted host) and legitimate misses inside allowed zones (typo, missing record). CoreDNS makes no per-query allow/deny decision — correlatedomainagainst the allowlist, or use the eBPF egress stream below (explicitaction:denied) for the authoritative block signal. - eBPF egress events (
clawker-ebpf-egress) — one record per firewall decision, including bypass-mode traffic that skips Envoy and CoreDNS entirely, so bypass windows still leave a complete audit trail. See Egress Observability for the full record shape and per-attribute reference.
Monitoring Extensions
What the stack observes beyond the core firewall and control-plane telemetry is contributed by monitoring extensions your project selects. An extension ships the OpenSearch indices, ingest pipelines, and dashboards for one telemetry stream; clawker’s built-inclaude-code extension is what lands Claude Code
session telemetry (cost, tokens, tool calls) and its two dashboards.
Select the extensions a project contributes under monitor.extensions in
clawker.yaml:
claude-code extension; set an explicit
empty list (extensions: []) to opt out of all monitoring. clawker monitor up is bring-up only: it seeds
the current project’s selection when it starts the stack, and exits untouched
when the stack is already running — there is no host-side registry, and the
collector routes from the union of every extension ever seeded. To apply an
extension change to a running stack, run clawker monitor reload (seeds the
selection, re-renders the config, and recreates the collector). See
Monitoring Extensions for selection semantics and
Authoring monitoring extensions for writing your own.
Setup
1. Initialize Configuration
~/.local/share/clawker/monitor/):
compose.yaml— Docker Compose definition for all services (four long-lived + one-shot bootstrap)otel-config.yaml— OpenTelemetry Collector pipeline configurationprometheus.yaml— Prometheus scrape targets
--force to regenerate files if they already exist.
2. Start the Stack
3. Run Agents
Start agents as usual — telemetry flows automatically:4. Explore in OpenSearch Dashboards
Open OpenSearch Dashboards athttp://localhost:5601. From the splash / welcome screen, under the Analytics panel on the far right, click Clawker to enter the auto-created workspace.
Inside the workspace, the left navbar has an Explore section — click Logs or Metrics to browse. The preconfigured index patterns (claude-code, clawker-cli, clawkercp, clawker-envoy, clawker-coredns, clawker-ebpf-egress) and the clawker_prometheus direct-query datasource are already wired, so logs and Prometheus metrics are both reachable from inside OSD. Raw Prometheus is also still available at http://localhost:9090 if you prefer it.
Dashboards. Which dashboards are preinstalled depends on the monitoring
extensions your project selects. Clawker Networking is core firewall
telemetry and is always present; the two Claude Code dashboards come from the
built-in claude-code extension (when selected):
- Claude Code Cost & Usage — KPI strip over Claude Code sessions, cost, input/output/cache tokens. Sourced from Prometheus counters. (From the
claude-codeextension.) - Claude Code Activity — Claude Code security activity audit: prompts, tooling, code editing, permissions, hooks, MCP, plugins — totals, distributions, and full event tables. (From the
claude-codeextension.) - Clawker Networking — per-source firewall telemetry: three event-stream panels (Envoy access logs, CoreDNS query log, eBPF egress decisions) plus three verdict pies (Envoy
action, CoreDNSrcode, eBPFaction). Verdict pies use each source’s own field — values not normalized so each component’s truth stays visible (e.g. CoreDNS denies show asNXDOMAIN, not collapsed intodenied). Red slices = denials. Sourced from OS log indices; no Prometheus counters for network telemetry today.
Bootstrap
The stack is preconfigured at bring-up (and again on everymonitor reload). A one-shot clawker-opensearch-bootstrap compose service runs after OpenSearch reports healthy, applies:
- Component templates with shared mappings (
@timestampas date,service.name/ingest_source/project/agentas keyword) - Index templates with per-source field mappings for each log index plus the SS4O
tracesmapping (so dynamic mapping never locks the wrong type at first ingest) - ISM retention policy (7-day rollover-to-delete, auto-attached via
ism_template.index_patterns) - Empty index pre-creation for the log indices so OSD Discover and dashboards don’t error on initial load before the first record arrives
clawker_prometheusdirect-query datasource registered via the OpenSearch SQL plugin so OSD can read Prometheus metrics without a federated proxy- OSD
Clawkerworkspace withfeatures: ["use-case-all"]so the explore-flavormetrics/logs/tracesnav groups all mount - Saved objects imported INTO the Clawker workspace — the core index patterns and the
Clawker Networkingdashboard, plus the index patterns, ingest pipelines, and dashboards contributed by every monitoring extension seeded into the stack (theclaude-codeextension adds theClaude Code Cost & UsageandClaude Code Activitydashboards). Build additional dashboards off the index patterns + Prometheus datasource, or ship them as a monitoring extension.
otel-collector gates on bootstrap completing successfully — it never starts until the cluster is preconfigured. Prometheus starts in parallel; bootstrap depends on Prometheus being up so the clawker_prometheus datasource registration can validate the configured URI. Bootstrap failure surfaces in docker logs clawker-opensearch-bootstrap and leaves the stack half-up by design (so wrong-mapped indices can’t be silently created). The throwaway-stack model means picking up template/policy edits requires monitor down --volumes && monitor up; templates only apply at index creation.
Telemetry Controls
Fine-tune what telemetry is collected viasettings.yaml:
Port Configuration
Override default ports insettings.yaml if they conflict with other services:
Checking Status
Teardown
--volumes, monitoring data persists across restarts (named volume clawker-opensearch for indices, clawker-prometheus for TSDB) — as do the monitoring extensions seeded into the stack, so subsequent monitor up runs from any project keep them. --volumes clears both the telemetry data and the seeded extensions, resetting the stack. The clawker-net network is preserved for other Clawker services (firewall, agents).