AI Observability
The AI Observability module logs calls to AI providers to the Drupal Logger (currently) and OpenTelemetry endpoints (in the future), including detailed information like request duration, token usage, optionally input prompts text and output, etc.
This makes it possible to track the usage of tokens per user, per provider, build aggregated reports and usage charts, calculate cost usage and expenses, limit per-week token usage per user, and many more.
This module only produces logs, that can be stored anywhere - in the local Drupal database, Syslog, file, cloud log collectors.
For quick start and local development it's recommended to use the "Extended Logger" module in conjunction with its submodule, "Extended Logger DB", to store logs generated by this module into the Drupal Database as well as providing a page to review these logs.
For production, it's recommended to use production-ready log scrappers.
OpenTelemetry attribute schema
When OpenTelemetry export is enabled, the module emits spans and metrics using the
OpenTelemetry GenAI semantic conventions
(gen_ai.*). These attributes are dual-emitted alongside the module's original
ad-hoc attributes, so existing dashboards keep working while consumers can migrate to
the standard schema. The gen_ai.* attributes are Experimental in the OpenTelemetry
specification.
Span attributes (AI provider request)
Standard GenAI attributes (emitted unconditionally when span export is on):
| Attribute | Source | Notes |
|---|---|---|
gen_ai.provider.name |
provider plugin id | Mapped to a well-known value (openai, anthropic, gcp.vertex_ai, …); unknown providers fall back to the raw plugin id. |
gen_ai.operation.name |
operation type | Only the well-known values chat, text_completion, embeddings are emitted; non-standard operations (e.g. image generation) are omitted. |
gen_ai.request.model |
requested model id | |
gen_ai.usage.input_tokens |
token usage | Scalar; explicit 0 is preserved. |
gen_ai.usage.output_tokens |
token usage | Scalar; explicit 0 is preserved. |
gen_ai.response.model |
raw provider response model |
Best-effort; emitted when present. |
gen_ai.response.finish_reasons |
raw provider response | Array of finish reasons (OpenAI finish_reason per choice / Anthropic stop_reason). For streamed responses the finish reason is taken from the stream iterator (requires the streaming-span finalization fix, #3586473). |
A sample exported span dump:
{
"name": "AI provider request",
"attributes": {
"gen_ai.provider.name": "openai",
"gen_ai.operation.name": "chat",
"gen_ai.request.model": "gpt-4o-mini",
"gen_ai.usage.input_tokens": 11,
"gen_ai.usage.output_tokens": 27,
"gen_ai.response.model": "gpt-4o-mini-2024-07-18",
"gen_ai.response.finish_reasons": ["stop"],
"provider": "openai",
"operation_type": "chat",
"model": "gpt-4o-mini",
"token_usage": {"input": 11, "output": 27, "total": 38}
}
}
Metrics
| Instrument | Type | Dimensions | Notes |
|---|---|---|---|
gen_ai.client.token.usage |
histogram | gen_ai.token.type (input/output), gen_ai.provider.name, gen_ai.request.model |
Records input and output token counts. |
Legacy attributes (deprecated)
The original ad-hoc attributes and counters remain for backwards compatibility but are
deprecated, with removal targeted for 2.0.x. Migrate consumers to the gen_ai.*
schema above.
- Span attributes:
provider,operation_type,model,token_usage(an array;NULLand0values are filtered out). - Metric counters:
ai_token_usage_<key>(one counter per token-usage key).