diff --git a/sentry_sdk/ai/monitoring.py b/sentry_sdk/ai/monitoring.py index dfadc290db..ee64477f65 100644 --- a/sentry_sdk/ai/monitoring.py +++ b/sentry_sdk/ai/monitoring.py @@ -24,13 +24,13 @@ def record_token_usage( if input_tokens_cached is not None: span.set_attribute( - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, input_tokens_cached, ) if input_tokens_cache_write is not None: span.set_attribute( - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE, + SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS, input_tokens_cache_write, ) @@ -39,7 +39,7 @@ def record_token_usage( if output_tokens_reasoning is not None: span.set_attribute( - SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, output_tokens_reasoning, ) diff --git a/sentry_sdk/integrations/google_genai/streaming.py b/sentry_sdk/integrations/google_genai/streaming.py index 3f44585f82..e8e329e662 100644 --- a/sentry_sdk/integrations/google_genai/streaming.py +++ b/sentry_sdk/integrations/google_genai/streaming.py @@ -131,7 +131,7 @@ def set_span_data_for_streaming_response( if accumulated_response["usage_metadata"]["input_tokens_cached"]: span.set_attribute( - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, accumulated_response["usage_metadata"]["input_tokens_cached"], ) @@ -143,7 +143,7 @@ def set_span_data_for_streaming_response( if accumulated_response["usage_metadata"]["output_tokens_reasoning"]: span.set_attribute( - SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, accumulated_response["usage_metadata"]["output_tokens_reasoning"], ) diff --git a/sentry_sdk/integrations/google_genai/utils.py b/sentry_sdk/integrations/google_genai/utils.py index 6d075edb8f..b795e7fa83 100644 --- a/sentry_sdk/integrations/google_genai/utils.py +++ b/sentry_sdk/integrations/google_genai/utils.py @@ -1021,7 +1021,7 @@ def set_span_data_for_response( if usage_data["input_tokens_cached"]: span.set_attribute( - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, usage_data["input_tokens_cached"], ) @@ -1032,7 +1032,7 @@ def set_span_data_for_response( if usage_data["output_tokens_reasoning"]: span.set_attribute( - SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, usage_data["output_tokens_reasoning"], ) diff --git a/sentry_sdk/integrations/openai_agents/utils.py b/sentry_sdk/integrations/openai_agents/utils.py index 3e384d745b..6a772a15cf 100644 --- a/sentry_sdk/integrations/openai_agents/utils.py +++ b/sentry_sdk/integrations/openai_agents/utils.py @@ -93,12 +93,12 @@ def _set_agent_data(span: "StreamedSpan", agent: "agents.Agent") -> None: def _set_usage_data(span: "StreamedSpan", usage: "Usage") -> None: span.set_attribute(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, usage.input_tokens) span.set_attribute( - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, usage.input_tokens_details.cached_tokens, ) span.set_attribute(SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, usage.output_tokens) span.set_attribute( - SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, usage.output_tokens_details.reasoning_tokens, ) span.set_attribute(SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, usage.total_tokens) diff --git a/sentry_sdk/integrations/pydantic_ai/spans/utils.py b/sentry_sdk/integrations/pydantic_ai/spans/utils.py index 05e34aaa4d..ba77b05b5a 100644 --- a/sentry_sdk/integrations/pydantic_ai/spans/utils.py +++ b/sentry_sdk/integrations/pydantic_ai/spans/utils.py @@ -68,13 +68,13 @@ def _set_usage_data( # Pydantic AI uses cache_read_tokens (not input_tokens_cached) if hasattr(usage, "cache_read_tokens") and usage.cache_read_tokens is not None: span.set_attribute( - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED, usage.cache_read_tokens + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, usage.cache_read_tokens ) # Pydantic AI uses cache_write_tokens (not input_tokens_cache_write) if hasattr(usage, "cache_write_tokens") and usage.cache_write_tokens is not None: span.set_attribute( - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE, + SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS, usage.cache_write_tokens, ) diff --git a/tests/integrations/anthropic/test_anthropic.py b/tests/integrations/anthropic/test_anthropic.py index b8dcb6245c..70b332d309 100644 --- a/tests/integrations/anthropic/test_anthropic.py +++ b/tests/integrations/anthropic/test_anthropic.py @@ -4960,8 +4960,8 @@ def test_cache_tokens_nonstreaming( assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 200 assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 50 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 250 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 80 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 80 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 20 def test_input_tokens_include_cache_write_nonstreaming( @@ -5017,8 +5017,8 @@ def test_input_tokens_include_cache_write_nonstreaming( # input_tokens should be total: 19 (non-cached) + 2846 (cache_write) = 2865 assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 0 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 2846 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 0 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 2846 def test_input_tokens_include_cache_read_nonstreaming( @@ -5074,8 +5074,8 @@ def test_input_tokens_include_cache_read_nonstreaming( # input_tokens should be total: 19 (non-cached) + 2846 (cache_read) = 2865 assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 2846 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 0 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 2846 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 0 def test_input_tokens_include_cache_read_streaming( @@ -5146,8 +5146,8 @@ def test_input_tokens_include_cache_read_streaming( # input_tokens should be total: 19 + 2846 = test_stream_messages_input_tokens_include_cache_read_streaming assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 2846 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 0 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 2846 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 0 def test_stream_messages_input_tokens_include_cache_read_streaming( @@ -5216,8 +5216,8 @@ def test_stream_messages_input_tokens_include_cache_read_streaming( # input_tokens should be total: 19 + 2846 = 2865 assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 2846 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 0 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 2846 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 0 def test_input_tokens_unchanged_without_caching( @@ -5331,8 +5331,8 @@ def test_cache_tokens_streaming( assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 200 assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 210 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 80 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 80 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 20 def test_stream_messages_cache_tokens( @@ -5398,5 +5398,5 @@ def test_stream_messages_cache_tokens( assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 200 assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 210 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 80 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 80 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 20 diff --git a/tests/integrations/google_genai/test_google_genai.py b/tests/integrations/google_genai/test_google_genai.py index e2332770b6..4b5ca20670 100644 --- a/tests/integrations/google_genai/test_google_genai.py +++ b/tests/integrations/google_genai/test_google_genai.py @@ -201,8 +201,8 @@ def test_nonstreaming_generate_content( # Output tokens now include reasoning tokens: candidates_token_count (20) + thoughts_token_count (3) = 23 assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 23 assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 5 - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING] == 3 + assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 5 + assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] == 3 @pytest.mark.parametrize("generate_content_config", (False, True)) @@ -582,8 +582,8 @@ def test_streaming_generate_content( assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 25 - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 5 - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING] == 3 + assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 5 + assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] == 3 # Verify model name assert chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "gemini-1.5-flash" diff --git a/tests/integrations/openai/test_openai.py b/tests/integrations/openai/test_openai.py index ba5b2ffb65..851671ecf8 100644 --- a/tests/integrations/openai/test_openai.py +++ b/tests/integrations/openai/test_openai.py @@ -3682,9 +3682,9 @@ def test_ai_client_span_responses_api_no_pii( "gen_ai.response.streaming": False, SPANDATA.GEN_AI_PROVIDER_NAME: "openai", "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS: 5, "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS: 8, "gen_ai.usage.total_tokens": 30, "sentry.op": "gen_ai.responses", "sentry.origin": "auto.ai.openai", @@ -3955,9 +3955,9 @@ def test_ai_client_span_responses_api( "gen_ai.response.model": "response-model-id", "gen_ai.response.streaming": False, "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS: 5, "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS: 8, "gen_ai.usage.total_tokens": 30, "gen_ai.request.messages": safe_serialize(expected_request_messages), "gen_ai.request.model": "gpt-4o", @@ -4765,9 +4765,9 @@ async def test_ai_client_span_responses_async_api( "gen_ai.response.streaming": False, SPANDATA.GEN_AI_PROVIDER_NAME: "openai", "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS: 5, "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS: 8, "gen_ai.usage.total_tokens": 30, "gen_ai.response.text": "the model response", "sentry.op": "gen_ai.responses", @@ -4993,9 +4993,9 @@ async def test_ai_client_span_streaming_responses_async_api( SPANDATA.GEN_AI_PROVIDER_NAME: "openai", SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK: mock.ANY, "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS: 5, "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS: 8, "gen_ai.usage.total_tokens": 30, "gen_ai.request.model": "gpt-4o", "gen_ai.response.text": "hello world", diff --git a/tests/integrations/openai_agents/test_openai_agents.py b/tests/integrations/openai_agents/test_openai_agents.py index 0789d3d2e2..47e2b3d332 100644 --- a/tests/integrations/openai_agents/test_openai_agents.py +++ b/tests/integrations/openai_agents/test_openai_agents.py @@ -2066,9 +2066,15 @@ async def test_tool_execution_span( assert ai_client_span1["attributes"]["gen_ai.request.temperature"] == 0.7 assert ai_client_span1["attributes"]["gen_ai.request.top_p"] == 1.0 assert ai_client_span1["attributes"]["gen_ai.usage.input_tokens"] == 10 - assert ai_client_span1["attributes"]["gen_ai.usage.input_tokens.cached"] == 0 + assert ( + ai_client_span1["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] + == 0 + ) assert ai_client_span1["attributes"]["gen_ai.usage.output_tokens"] == 5 - assert ai_client_span1["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 0 + assert ( + ai_client_span1["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] + == 0 + ) assert ai_client_span1["attributes"]["gen_ai.usage.total_tokens"] == 15 tool_call = { @@ -2155,9 +2161,15 @@ async def test_tool_execution_span( == "Task completed using the tool" ) assert ai_client_span2["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" - assert ai_client_span2["attributes"]["gen_ai.usage.input_tokens.cached"] == 0 + assert ( + ai_client_span2["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] + == 0 + ) assert ai_client_span2["attributes"]["gen_ai.usage.input_tokens"] == 15 - assert ai_client_span2["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 0 + assert ( + ai_client_span2["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] + == 0 + ) assert ai_client_span2["attributes"]["gen_ai.usage.output_tokens"] == 10 assert ai_client_span2["attributes"]["gen_ai.usage.total_tokens"] == 25 @@ -3379,8 +3391,14 @@ async def test_invoke_agent_span_includes_usage_data( assert invoke_agent_span["attributes"]["gen_ai.usage.input_tokens"] == 10 assert invoke_agent_span["attributes"]["gen_ai.usage.output_tokens"] == 20 assert invoke_agent_span["attributes"]["gen_ai.usage.total_tokens"] == 30 - assert invoke_agent_span["attributes"]["gen_ai.usage.input_tokens.cached"] == 0 - assert invoke_agent_span["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 5 + assert ( + invoke_agent_span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] + == 0 + ) + assert ( + invoke_agent_span["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] + == 5 + ) @pytest.mark.asyncio @@ -3690,9 +3708,15 @@ def calculator(a: int, b: int) -> int: assert invoke_agent_span["attributes"]["gen_ai.usage.output_tokens"] == 20 assert invoke_agent_span["attributes"]["gen_ai.usage.total_tokens"] == 50 # Cached tokens should be aggregated: 0 + 5 = 5 - assert invoke_agent_span["attributes"]["gen_ai.usage.input_tokens.cached"] == 5 + assert ( + invoke_agent_span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] + == 5 + ) # Reasoning tokens should be aggregated: 0 + 3 = 3 - assert invoke_agent_span["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 3 + assert ( + invoke_agent_span["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] + == 3 + ) @pytest.mark.asyncio diff --git a/tests/integrations/pydantic_ai/test_pydantic_ai.py b/tests/integrations/pydantic_ai/test_pydantic_ai.py index 36c009cfe3..c17d34bb13 100644 --- a/tests/integrations/pydantic_ai/test_pydantic_ai.py +++ b/tests/integrations/pydantic_ai/test_pydantic_ai.py @@ -2706,8 +2706,10 @@ async def test_set_usage_data_with_cache_tokens( sentry_sdk.flush() spans = [item.payload for item in items] - assert spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 80 - assert spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 + assert spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 80 + assert ( + spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 20 + ) @pytest.mark.parametrize(