Model id, token usage and cost, prompt version, user and session id, and finish reason answer the five operational questions every LLM dashboard cares about. Secrets never.
Imagine running a restaurant and labeling every receipt with the dish name, how much it cost the kitchen, which recipe version was used, which table ordered it, and whether the customer finished it. Five small labels and you can answer every question your manager has at the end of the night: which dishes are popular, which are unprofitable, which recipe revisions worked, which table needs follow-up, and which dishes get left half-eaten. Now imagine someone also writing the chef's home address on every receipt. The first five labels run the restaurant; that sixth one is a lawsuit waiting to happen. The trick is knowing which labels to stamp and which to never stamp.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
An LLM span is a tiny budget for indexed attributes. The temptation is to log everything that might be useful later. The discipline is to log exactly what answers the operational questions that come up every day, and to keep everything else either off the span entirely or in events that are not indexed.
This deep dive walks through why the five canonical attributes earned their floor status, how each maps to the OpenTelemetry GenAI semantic conventions, and the cardinality and compliance disciplines that keep the attribute surface healthy as the system scales.
The five operational questions and their attributes
Every production team running LLMs answers the same five questions on a weekly basis. The attribute load on the span is shaped around those questions.
What ran
The model id. gen_ai.request.model in OTel terms. Use the canonical provider name (gpt-4o, claude-3-5-sonnet-20241022, gemini-2.0-flash-001) so price-table joins and model-mix dashboards both work. A provider may also return its own model id on the response (sometimes different when a fallback fires); that goes in gen_ai.response.model as a separate attribute.
How much it cost
Input tokens, output tokens, total tokens, and computed USD cost. OTel keys are gen_ai.usage.input_tokens and gen_ai.usage.output_tokens. Cost is computed at ingest by joining the model id against a price table. Some backends (Langfuse, Phoenix) ship a maintained price table; some require you to supply your own. Either way, cost is a derived attribute, not a primary one; if model and usage are wrong, cost is wrong.
Which prompt was responsible
A template id and version label. prompt.template_name=summary_v3 and prompt.version=2025.10.14. When a quality drop appears at 14:00 and the new prompt version shipped at 13:55, the filter is one line and the rollback is one config change. Without this attribute the post-mortem starts with a text-grep over prompts.
Whose request was it
User id and session id. user.id=opaque_token_abc123 and session.id=conv_xyz. The session groups multi-turn chat; the user id supports per-customer dashboards. Both should be stable opaque tokens, not emails or names, both for cardinality and for compliance.
Did it complete or truncate
Finish reason. gen_ai.response.finish_reasons carries values like stop, length, content_filter, tool_call. A spike in length is a sign that max_tokens is set too low; a spike in content_filter is a sign of guardrail-policy drift. Both are first-class alerting signals.
Situations where this technique stops working.
2–4 min · Everything important, quickly.
Real products, models, and research that use this idea.
- OpenTelemetry's GenAI semantic conventions document standardizes exactly these attribute names; production deployments at companies using OTel-native tracing emit them as `gen_ai.request.model` and friends.
- Langfuse's default generation shape ships with model, usage, and cost as first-class fields; user_id and session_id are top-level trace attributes; prompt template name and version attach via the prompt API.
What an interviewer would ask next. Try answering before peeking at the approach.
QIf you must log a prompt for debugging but PII is a concern, what is the production-safe pattern?
Emit the prompt as a span event with role attributes (gen_ai.user.message), apply a regex or model based redactor at the SDK layer before the event is emitted, and gate retention of the events behind a separate access-controlled storage tier; the indexed attributes stay PII-free while the audit trail still exists.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Stuffing the full prompt and completion into a single span attribute. Index size explodes and per-message redaction becomes impossible.
60 second bullets to scan on the way to the call.
The five attributes that answer the five everyday operational questions
Why secrets must never be logged on spans (compliance plus cardinality)
Primary sources. Browse if you want the original framing.
Same topic, related formats. Practice these next.