Monitor Claude Code Usage and Cost with the Monitoring Service
Overview
Claude Code is a command-line coding agent from Anthropic. It can export OpenTelemetry data about its own activity, including how many tokens each model consumed, what each session cost, how long developers spent working with it, and how many lines of code it changed.
Since OpenTelemetry Protocol (OTLP) ingestion became available in August 2026, the IONOS CLOUD Monitoring Service accepts this data directly. OpenTelemetry Collector and translation layers are not required. Connect Claude Code's exporter to your pipeline to start receiving metrics.
Claude Code emits each OpenTelemetry signal separately, so each one can be sent to a different IONOS CLOUD observability service:
Signal
Service
What it gives you
Metrics
Monitoring Service
Token usage, cost per model, sessions, and active time.
Traces
Tracing Service
A span for each interaction, showing every model request and tool call within it.
Metrics aggregate usage over time, while traces record individual interactions, so the two answer different questions. Steps 1 to 7 cover metrics, including a dashboard you can import. Steps 8 to 10 cover traces and are optional.
Target audience
Platform and DevOps engineers, and engineering leads who need visibility over AI coding assistant usage and cost, and who want that data stored on European infrastructure they control.
What you will learn
You will learn how to:
Configure Claude Code's OpenTelemetry exporter for the IONOS CLOUD Monitoring Service.
Confirm that metrics arrived, and diagnose it when they have not.
Import a Grafana dashboard for token usage and cost.
Control label cardinality, which drives what you are billed for.
Handle the personal data that Claude Code attaches to every metric.
Before you begin
Ensure you have:
An active IONOS CLOUD account. Contract owners and administrators already have the necessary access. Any other user needs the Access and manage Monitoring privilege. For more information, see Set User Privileges.
A monitoring pipeline, together with its HTTP endpoint and API key. For more information, see Monitoring Service User Guide.
Access to the Grafana endpoint of the respective pipeline. Monitoring privileges govern pipeline access only and do not grant Grafana access.
Claude Code 2.x installed on macOS or Linux. For more information, see Claude Code Documentation.
Cost considerations
This tutorial uses an existing IONOS CLOUD Monitoring Service subscription. The Monitoring Service bills ingested samples and stored data, so sending Claude Code metrics adds to your usage.
Claude Code emits eight metrics. At the default 60-second export interval, a single active developer generates tens of thousands of samples daily, meaning telemetry costs scale linearly with your team size.
Two settings affect the volume more than the number of developers does:
Label cardinality: Each distinct session identifier creates a new time series. Step 6 shows how to switch the label off.
Export interval: Halving
OTEL_METRIC_EXPORT_INTERVALdoubles the number of samples.
For pricing information, see Monitoring Service Billing and IONOS CLOUD Prices.
Architecture
Claude Code on your machine exports two OpenTelemetry signals directly, without an intermediate collector. Metrics travel over OTLP to the IONOS CLOUD Monitoring pipeline and into the Monitoring Service, which stores them in Grafana Mimir. Traces travel over OTLP to the IONOS CLOUD Tracing pipeline and into the Tracing Service, which stores them in Grafana Tempo. Both paths converge on Grafana, which queries the Monitoring Service with PromQL and the Tracing Service with TraceQL.

Each OpenTelemetry signal is exported independently, with its own endpoint, protocol, and authentication setting. That is what allows one Claude Code installation to send each signal to a different IONOS CLOUD service.
Procedure
Collect the pipeline endpoint
In the Data Center Designer (DCD), open your monitoring pipeline and note the HTTP endpoint. The OTLP metrics path is appended to it:
Important: The metrics path is /otlp/v1/metrics, not /v1/metrics. Because it differs from the OpenTelemetry default, you must set the metrics-specific endpoint variable in step 3. The generic OTEL_EXPORTER_OTLP_ENDPOINT variable appends /v1/metrics and does not reach the Monitoring Service.
Store the API key
1. Copy the pipeline API key and export it, so that it never appears in a settings file or in your shell history:
On Linux, use xclip -o in place of pbpaste.
2. Confirm the value arrived without printing it:
Warning: Handle the pipeline key like a password. The Monitoring Service returns it only once, when the pipeline is created. Store it in a password manager, and do not paste it into files, chats, tickets, or version control. If it is exposed, rotate the pipeline key to generate a new one.
Configure Claude Code to export metrics
Set these variables in the terminal that you will start Claude Code from:
Two of these settings are often overlooked, and misconfiguring either one will prevent any data from arriving:
Setting
Why it is required
OTEL_EXPORTER_OTLP_METRICS_PROTOCOL=http/protobuf
OpenTelemetry defaults to gRPC Remote Procedure Call (gRPC). The Monitoring Service endpoint is an HTTPS path, so gRPC fails without reporting an error.
OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=cumulative
Claude Code sends delta values by default. Grafana Mimir expects cumulative counters.
Confirm the metrics arrived
Open the Grafana endpoint of your pipeline, go to Explore, select the Mimir data source, switch to Code mode, select Instant, and run:
The following metric names appear:
Metric names are rewritten on ingestion, so that dots become underscores. Query claude_code_token_usage rather than claude_code.token.usage.
Four further metrics (claude_code_lines_of_code_count, claude_code_commit_count, claude_code_pull_request_count, and claude_code_code_edit_tool_decision) appear only once a session edits files, commits, or asks you to approve a tool. Their absence before that point is expected.
Review the labels
To review the labels received, set Format to Table and query the metric name on its own:
Warning: While you are signed in, Claude Code attaches user.email, organization.id, and other account identifiers to every metric series. Because these become labels in Grafana Mimir, your metric storage will contain Personally Identifiable Information (PII). Currently, no environment variable can remove the user.email label.
Check your organization's policies before using this beyond a single machine. Deleting individual series from a metrics store is operationally difficult, so decide before you ingest rather than afterwards. If you need the data without the identifier, route it through an OpenTelemetry Collector and drop or hash the attribute there. For more information, see [Next steps.
Import the dashboard
In Grafana, go to Dashboards > New > Import, paste the following definition, and select your Mimir data source when prompted.
Once a few sessions have been reported, the imported Grafana dashboard displays Claude Code usage and costs over the last seven days. Four stat panels across the top show total cost, session count, active time, and reused input token share. Below these sit time-series charts detailing cost per model, a model breakdown bar gauge, and a cost-per-session stat.

The Reused input token share panel is the most actionable. Reused input tokens bill at a fraction of fresh ones, so a low share on a long-running project points to a prompt that changes more often than necessary.
The Code activity row is collapsed by default because its metrics populate only after Claude Code edits files, makes a commit, or requests your approval. You can expand it once you have completed a few tasks.
The stat panels use max_over_time rather than increase. Because each session reports its own counter series, a counter that reaches its final value and stops updating will evaluate to an increase of zero. This causes the panel to appear empty even when data exists.
Create a tracing pipeline
1. Create a tracing pipeline with the protocol set to otlp-http, which matches the http/protobuf setting used in the next step. Do not select a gRPC pipeline. A gRPC endpoint consists of a host and a port without a path, so it cannot accept the endpoint format shown below. For more information, see Tracing Service User Guide.
2. Note the HTTP endpoint of the pipeline, then store its API key:
Warning: As with the monitoring pipeline, the Tracing Service returns the ingestion key only once. Store it in your password manager. If it is exposed, rotate the pipeline key to generate a new one.
View an interaction as a trace
1. In Grafana, select the Tempo data source and run the following in the TraceQL tab:
2. The Search tab produces the same result without any syntax. Set Service Name to claude-code.
3. Open a trace. It has the following shape:
A real interaction repeats the pattern as many times as the task requires. The following trace shows a single prompt that took 11.08 seconds and generated 12 spans, alternating between model requests and tool calls. A 9.9-second parent interaction span contains five model request spans, the longest running for 5.45 seconds, and two tool spans. Each tool span includes separate child spans for approval wait time and execution.

The waterfall reveals details that metrics cannot capture. Here, model requests dominate elapsed time, tool execution is brief, and the tiny blocked_on_user spans of 6 and 2.21 milliseconds prove that the interaction did not wait for human approval.
Each claude_code.llm_request span records one call, with model, input_tokens, output_tokens, duration_ms, ttft_ms, stop_reason, and the counts of tokens reused from earlier requests. Each claude_code.tool.blocked_on_user span records how long Claude Code waited for a tool call approval, which no metric reports.
Resource attributes reach the spans, so the team value set in OTEL_RESOURCE_ATTRIBUTES is available as a span attribute and can be used to filter traces.
Warning: Spans carry the same identifying attributes as metrics, including user.email, organization.id, and the account identifiers. Prompt text is redacted by default and appears as <REDACTED>, with only its length recorded. Read the guidance in step 6 before you send traces from more than one machine.
Result
Claude Code activity from your machine is stored in your IONOS CLOUD monitoring pipeline, and the imported dashboard reports total cost, session count, active time, the share of input tokens that were reused, cost broken down by model, and token usage broken down by type. If you completed the optional steps, you can also open an individual interaction as a trace. The trace shows every model request and tool call within it.
Troubleshooting
No metrics appear in Grafana
The arrival of data is the only reliable confirmation that the configuration works, so start there. Run the following over the last hour, open a session, send a prompt, and wait for one export interval:
If the count rises, the configuration is correct. If it does not, work through the following checks in order, because each one isolates a different stage.
Confirm that the configuration reached Claude Code. Asking Claude Code from inside a session does not work, because
OTEL_*variables are deliberately removed from child processes. A session cannot read its own exporter settings and reports them as empty even when they are set.How to check depends on where you put the configuration.
If you exported the variables in a shell, inspect the environment the process started with:
Variables set after Claude Code started do not apply to it, so restart it if the list is incomplete.
If you used the
envblock in~/.claude/settings.json, this command returns nothing, which is expected. Those values are read by Claude Code and never enter the process environment. Confirm the file instead, and restart Claude Code after any edit:Do not mix the two. A shell export takes precedence over the
envblock, so a stale export in one terminal sends that session somewhere else.Confirm that Claude Code produces metrics at all. Run the following in a separate terminal. Metric records printed to the terminal mean that the problem lies in transport rather than collection.
Check the protocol. If
OTEL_EXPORTER_OTLP_METRICS_PROTOCOLis unset, OpenTelemetry uses gRPC, which cannot reach an HTTPS path endpoint. Set it tohttp/protobuf.Check the endpoint path. It must end in
/otlp/v1/metrics.Check the region. If you have pipelines in more than one region, confirm that you are querying the Grafana instance belonging to the same pipeline you are sending to.
Metrics appear but the values look incorrect
Confirm that OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE is set to cumulative. With delta values, rate() and increase() produce meaningless results.
A query returns vector cannot contain metrics with the same labelset
Functions such as count_over_time drop the metric name, which makes the _sum and _count series of a histogram indistinguishable. Aggregate one metric at a time instead of using a wildcard selector.
Decommission resources
To stop the export, unset the variables and restart Claude Code:
Remove any env block that you added to ~/.claude/settings.json.
Metrics that have already been ingested remain until the retention period of the pipeline expires. To stop all charges, delete the pipeline in the DCD.
Next steps
Route through an OpenTelemetry Collector for team rollouts. This gives developers a single endpoint, centralises credential management, and lets you remove identifying attributes before anything is stored:
Hashing rather than deleting preserves per-developer grouping for cost attribution without storing the address itself.
Add the activity metrics. Once sessions start editing files and committing,
claude_code_lines_of_code_count,claude_code_commit_count, andclaude_code_code_edit_tool_decisionbecome available. Add panels for accepted and rejected edit suggestions.Alert on cost. Create a Grafana alert on
sum(increase(claude_code_cost_usage[24h]))to catch unexpected spend.Reduce cardinality before scaling up. Revisit
OTEL_METRICS_INCLUDE_SESSION_IDandOTEL_METRICS_INCLUDE_ACCOUNT_UUIDonce more than a few developers are reporting.
Last updated
Was this helpful?