For the complete documentation index, see llms.txt. This page is also available as Markdown.

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_INTERVAL doubles 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.

Architecture of Claude Code exporting metrics and traces

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

1

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:

2

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:

3

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.

4

Start Claude Code and generate activity

1. Start Claude Code from the same terminal:

Claude Code reads environment variables only at startup, so ensure the exports above are set before starting it.

2. Send a few prompts to generate some reportable activity.

Note: To avoid re-exporting the non-secret variables in every terminal, move them into an env block in ~/.claude/settings.json. Values must be strings, and Claude Code must be restarted after you edit the file. Do not store OTEL_EXPORTER_OTLP_METRICS_HEADERS in this file, as it contains your API key and is saved in plain text. In team environments, use the otelHeadersHelper hook to fetch the credential at runtime instead.

5

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.

6

Review the labels

To review the labels received, set Format to Table and query the metric name on its own:

Note: Session and account identifiers are included by default, creating a new time series for every session and user. While manageable on a single machine, this metric volume grows uncontrollably across a team, driving up costs since the Monitoring Service bills per ingested sample. To reduce it, set the following environment variables and restart Claude Code:

To check the current series count, run count(count by (session_id) (claude_code_token_usage)).

7

Import the dashboard

In Grafana, go to Dashboards > New > Import, paste the following definition, and select your Mimir data source when prompted.

Dashboard definition

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 Claude Code usage and cost dashboard in Grafana

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.

8

Create a tracing pipeline

Note: Steps 8 to 10 are optional. The metrics above aggregate usage over time. Traces record each interaction on its own, including the model requests inside it and the tool calls that those requests triggered. Use them to see what one particular interaction did, rather than what a week of them cost.

Prerequisite: These steps use a second service, so they need the Access and manage Tracing privilege. It is granted separately from the monitoring one.

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:

9

Configure Claude Code to export traces

1. Tracing is a beta feature of Claude Code and requires an extra variable. Configure as follows:

2. Restart Claude Code. Ask it to read a file so that the trace contains both a tool call and model requests.

Note: Availability of the Claude Code tracing beta depends on your Claude plan. This beta applies to Claude Code only. The IONOS CLOUD Tracing Service is generally available. To check the Claude Code feature without involving the pipeline, run the following and look for printed spans:

10

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.

A Claude Code trace in Grafana Tempo

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.

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.

  1. 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 env block 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 env block, so a stale export in one terminal sends that session somewhere else.

  2. 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.

  3. Check the protocol. If OTEL_EXPORTER_OTLP_METRICS_PROTOCOL is unset, OpenTelemetry uses gRPC, which cannot reach an HTTPS path endpoint. Set it to http/protobuf.

  4. Check the endpoint path. It must end in /otlp/v1/metrics.

  5. 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, and claude_code_code_edit_tool_decision become 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_ID and OTEL_METRICS_INCLUDE_ACCOUNT_UUID once more than a few developers are reporting.

Last updated

Was this helpful?