Skip to content

[claude_code] Improve ECS field mappings: adopt gen_ai.* fields and fix event.category assignments #19967

Description

@jamiehynds

Summary

To improve cross-integration correlation and take advantage of Elastic's ECS GenAI fieldset, we can map several of the claude_code integration's custom fields onto their ECS equivalents. The current pipeline is in good shape — it already sets event.kind, event.action, event.outcome, event.duration, the categorization set, and populates related.user. The items below are incremental refinements, mostly enabled by the recent addition of gen_ai.* fields to ECS.

Context: Claude Code exports telemetry over OTLP but uses its own attribute naming rather than the OTel GenAI semantic conventions on the metrics/logs this integration ingests, so the ECS alignment has to be done in the ingest pipeline.

1. Map custom fields to ECS gen_ai.* (not currently set)

Currently mapped as Better ECS field Notes
claude_code.events.model gen_ai.request.model (+ gen_ai.response.model)
claude_code.events.input_tokens gen_ai.usage.input_tokens long → integer
claude_code.events.output_tokens gen_ai.usage.output_tokens long → integer
claude_code.events.cache_read_tokens gen_ai.usage.cache_read.input_tokens
claude_code.events.cache_creation_tokens gen_ai.usage.cache_creation.input_tokens
claude_code.events.request_id gen_ai.response.id
claude_code.events.tool_name / mcp_tool_name gen_ai.tool.name
claude_code.events.tool_use_id gen_ai.tool.call.id
claude_code.events.tool_input_flattened / tool_parameters_flattened gen_ai.tool.call.arguments flattened → flattened
claude_code.events.query_source gen_ai.operation.name loose mapping
(constant) gen_ai.provider.name = "anthropic" add as constant_keyword

2. Map custom fields to ECS core (not currently set)

Currently mapped as Better ECS field Notes
claude_code.events.error error.message Currently copied to event.reason only; error.message is the canonical home. Keep event.reason if desired.
claude_code.events.error_code error.code
claude_code.events.error_type error.type
claude_code.events.organization.id organization.id
claude_code.events.user.email user.email Already appended to related.user; the core user.email field is not set.
claude_code.events.user.id user.id Already appended to related.user; the core user.id field is not set.
claude_code.events.user.account_id / account_uuid user.domain / user.id

3. ECS categorization refinements

3a. Additional signals for the categorization set

event.action, event.outcome (from success), event.kind, and event.duration are already handled in the pipeline. Remaining opportunities:

Signal ECS field Mapping Status
source event.provider user, system not set
decision / decision_type event.outcome acceptsuccess, rejectfailure ⚠️ verify — outcome is currently driven off success, so tool_decision rejects may not register as failure

3b. Fix event.category per event type

Event Current Proposed Rationale
api_request web / info api / info Outbound API call to Anthropic; api is the purpose-built ECS value.
api_error web / error api / error Failed API call.
api_retries_exhausted web / error api / error Failed API call.
api_refusal web / denied api / denied Model refusal on an API response, not a web-server log.
tool_decision process / info iam (or configuration) / allowed|denied Authorization/permission decision, not a process event.
user_prompt process / start (leave category empty) No fitting closed-vocab value; rely on event.kind + event.action.
skill_activated process / info (leave category empty) Same as user_prompt.
hook_registered process / info configuration (marginal) Registration is a config action; execution is the process.
hook_execution_start process / info process / start Refine type.
hook_execution_complete process / info process / end Refine type.
plugin_loaded package / info library (marginal) package implies install/remove; runtime load is closer to library.
plugin_installed package / info package — leave as-is Install genuinely fits package.
tool_result process / info process default, ideally derived from tool_name Spans process (Bash), file (Read/Write), web (WebFetch).
auth authentication / info ✅ no change Correct.
permission_mode_changed configuration / change ✅ no change Correct.
mcp_server_connection network / connection ✅ no change Correct.

Note: event.category is a closed vocabulary. Where nothing fits (e.g. user_prompt, skill_activated), leave it empty and rely on event.kind + event.action rather than the current process.

4. Explicitly kept custom (no ECS equivalent)

cost_usd, cost_usd_micros (ECS GenAI has no cost field), session.id, prompt.id (no gen_ai.conversation.id), effort, speed, prompt_length, prompt_text, and all feature-specific fields (hook_*, mcp_*/server_*, plugin.*, skill.*, marketplace.*, *_path_count, permission-mode fields, terminal.type, tool_*_size_bytes, raw tool_input/tool_parameters).

Acceptance criteria

  • GenAI fields mapped to gen_ai.* (Section 1), originals retained
  • error.message / error.code / error.type, organization.id, and core user.email/user.id populated (Section 2)
  • event.category corrected per event type (3b) — api_*api, tool_decisioniam, empty where nothing fits
  • event.provider populated from source; permission-decision outcome handling verified (3a)
  • Docs/fields.yml and ingest pipeline updated; sample events re-tested

References

Metadata

Metadata

Assignees

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions