fix(llmobs): sanitize dots in metric keys#18986
Draft
Yun-Kim wants to merge 1 commit into
Draft
Conversation
LLMObs ingestion interprets a dot in a metric key as a nested-path separator. Because the backend metrics field decodes as a flat map of numeric values (map[string]float64), a dotted key such as "anomaly.query_count" is expanded into a nested map, fails to decode, and drops the entire span batch. Replace dots with underscores in metric keys at annotation time (the central funnel for all metric sources, covering both export modes), and log a warning when a key is rewritten. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codeowners resolved as |
Circular import analysis
|
Contributor
🎉 All green!🧪 All tests passed 🔗 Commit SHA: 6c729f6 | Docs | Datadog PR Page | Give us feedback! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
LLM Observability ingestion interprets a dot in a metric key as a nested-path separator. Because the backend
metricsfield decodes as a flat map of numeric values (map[string]float64), a dotted metric key such asanomaly.query_countgets expanded into a nested map ({"anomaly": {"query_count": 8}}), fails CBOR decode inllm-obs-events-processorwithcannot unmarshal map into Go struct field ...SpansIngestPayload.custom of type float64, and drops the entire span batch — so nothing gets indexed.This was hit by a staging customer (
ml_app:reveng_anomaly_tooling_api) whose workflow span set custom metrics with dotted keys viaLLMObs.annotate(metrics=...).The SDK already handles this exact downstream behavior for tags (
_llmobs.py,k.replace(".", "_")inAPM_AGENTLESSmode) but not for metrics. This PR extends the same treatment to metric keys.Fix
_sanitize_metric_key()inddtrace/llmobs/_utils.pythat replaces.→_in string metric keys (non-string keys untouched; value validation already happens inannotate)._annotate_llmobs_span_data— the central funnel for all metric sources — so it covers bothLLMObs.annotate(metrics=...)and integration-set metrics, in both export modes.Chose annotation-time (mode-agnostic) over serialization-time because the backend
metricsfield can never represent nested metrics — flattening dots is always correct, and metrics are vulnerable regardless of export path.Testing
test_annotate_metrics_dotted_keys_sanitizedverifies dotted keys are flattened to underscores.tests/llmobs/test_llmobs_service.py -k annotate_metrics: 4 passed, 0 failed.Risks
Low. Metric keys containing dots were already being silently dropped (whole batch), so any prior behavior for such keys was data loss. A key collision is theoretically possible if a user submitted both
a.banda_bas separate metrics; the second wins. This is an accepted edge case since dotted keys were previously unusable entirely.Additional Notes
Scope is metrics-only.
metadatawith dotted keys still nests silently on the backend (map[string]interface{}— decodes without error but loses flat-key semantics). Happy to extend the same treatment to metadata in a follow-up if desired.Claude session:
4aa13fb9-084b-4459-bfda-cc9ee284fc15Resume:
claude --resume 4aa13fb9-084b-4459-bfda-cc9ee284fc15🤖 Generated with Claude Code