elastic / elastic/integrations

[claude_code] ECS GenAI Field Support for detections

Open
#20,741 1 comment 0 reactions 0 assignees View on GitHub
Integration:claude_code Team:Security-Service Integrations
Dominant language
Handlebars
Stars
333
Forks
647
Avg merge
2d 18h
Merged PRs (30d)
182

Description

**Related issue:**
- https://github.com/elastic/integrations/issues/20737

Note: for this integration, it should be documented how to turn on `OTEL_LOG_RAW_API_BODIES=1` to collect input/output messages.

TRaDE is requesting that the following fields be added to this integration for security detections:

## Requested fields
| Field | Availability | Status |
|---|---|---|
| `gen_ai.operation.name` | ✅ `attributes.query_source` in `api_request` events (e.g., `"repl_main_thread"`, `"generate_session_title"`) | ⚠️ Semantically mismatched — `query_source` describes the internal Claude Code thread origin, not the LLM operation type; ECS/OTel expects values like `"chat"` or `"text_completion"` |
| `gen_ai.conversation.id` (OTel) | ✅ `attributes.session.id` (UUID) is emitted on all event types and represents a conversation session | ❌ Not implemented — `session.id` is stored as `claude_code.events.session.id` and not mapped to `gen_ai.conversation.id` |
| `gen_ai.input.messages` | ✅ Available via `OTEL_LOG_RAW_API_BODIES=1` | ❌ Not implemented |
| `gen_ai.output.messages` | ✅ Available via `OTEL_LOG_RAW_API_BODIES=1` | ❌ Not implemented |
| `gen_ai.tool.name` | ✅ `attributes.tool_name` for native tools; `mcp_tool_name` extracted from parsed `tool_parameters` JSON for MCP tools (raw `tool_name` is just `"mcp_tool"` for those) | ⚠️ Possibly partially implemented — pipeline correctly resolves MCP tool names from within the `tool_parameters` blob |
| `gen_ai.tool.call.result` | ⚠️ Result content is not logged; only `tool_result_size_bytes` is captured | ❌ Not implemented |
| `destination.address` | ⚠️ `url.full` is extracted from `tool_parameters_flattened.url` for URL-fetching tool calls, but `destination.address` (the hostname) is not separately parsed from it | ❌ Not implemented — `url.full` is populated but `destination.address` is not derived |

## Likely already implemented (verify on development)
| Field | Availability | Status |
|---|---|---|
| `gen_ai.provider.name` | ✅ Hardcoded as `"anthropic"` | ✅ Implemented — defined as `constant_keyword` with value `"anthropic"` |
| `gen_ai.request.model` | ✅ `attributes.model` in `api_request` events (e.g., `"claude-sonnet-4-6"`) | ✅ Implemented — copied from `gen_ai.response.model`; both map to the same source field |
| `gen_ai.response.model` | ✅ `attributes.model` in `api_request` events | ✅ Implemented — note: request and response model are always identical since Claude Code logs a single `model` attribute per API call |
| `gen_ai.usage.input_tokens` | ✅ `attributes.input_tokens` in `api_request` events | ✅ Implemented |
| `gen_ai.usage.output_tokens` | ✅ `attributes.output_tokens` in `api_request` events | ✅ Implemented |
| `gen_ai.response.id` | ✅ `attributes.request_id` in `api_request` events (Anthropic `req_*` identifier) | ✅ Implemented |
| `gen_ai.tool.call.id` | ✅ `attributes.tool_use_id` in `tool_result` and `tool_decision` events | ✅ Implemented |
| `gen_ai.tool.call.arguments` | ✅ `attributes.tool_input` (JSON string) for `tool_result` events; `attributes.tool_parameters` for `tool_decision` events | ✅ Implemented — note: on `tool_decision` events the fallback source is `tool_parameters`, which includes internal Claude Code metadata beyond the model's raw arguments |
| `file.path` | ✅ `file.path` extracted from `tool_parameters_flattened.file_path` (or `.path`) for file-related tool calls | ✅ Implemented — ECS `file.path` is populated from tool parameters |

## Likely not possible (verify on development)
| Field | Availability | Status |
|---|---|---|
| `gen_ai.request.max_tokens` | ❌ Not emitted by the Claude Code CLI; request parameters are not included in telemetry | ❌ Not implemented |
| `gen_ai.request.temperature` | ❌ Not emitted by the Claude Code CLI | ❌ Not implemented |
| `gen_ai.request.seed` | ❌ Not emitted by the Claude Code CLI | ❌ Not implemented |
| `gen_ai.request.stop_sequences` | ❌ Not emitted by the Claude Code CLI | ❌ Not implemented |
| `gen_ai.response.finish_reasons` | ❌ Stop reason is not emitted by the Claude Code CLI | ❌ Not implemented |
| `gen_ai.token.type` | ❌ Not a discrete field in Claude Code telemetry | ❌ Not implemented |
| `gen_ai.output.type` | ❌ Not logged | ❌ Not implemented |
| `gen_ai.system_instructions` | ❌ Not logged in Claude Code telemetry | ❌ Not implemented |
| `gen_ai.tool.definitions` | ❌ Tool schemas and descriptions are not emitted in Claude Code telemetry | ❌ Not implemented |
| `gen_ai.tool.type` | ❌ Not a discrete field; could be inferred (native vs. MCP) but is not logged | ❌ Not implemented |

Contributor guide

Open the contributing guide

Research direction

Start with related issue #20737 and the existing claude_code integration mappings, then verify the listed ECS GenAI fields against development telemetry. Document how to enable OTEL_LOG_RAW_API_BODIES=1, map the feasible fields, and clearly record fields that Claude Code does not emit as out of scope.

Written by the indexing model from the issue text.

Assessment

Tech stack
handlebars
Domain
observability, security
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.