Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions sentry_sdk/ai/monitoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)

Expand All @@ -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,
)

Expand Down
4 changes: 2 additions & 2 deletions sentry_sdk/integrations/google_genai/streaming.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
)

Expand All @@ -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"],
)

Expand Down
4 changes: 2 additions & 2 deletions sentry_sdk/integrations/google_genai/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
)

Expand All @@ -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"],
)

Expand Down
4 changes: 2 additions & 2 deletions sentry_sdk/integrations/openai_agents/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions sentry_sdk/integrations/pydantic_ai/spans/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)

Expand Down
28 changes: 14 additions & 14 deletions tests/integrations/anthropic/test_anthropic.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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
8 changes: 4 additions & 4 deletions tests/integrations/google_genai/test_google_genai.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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"
Expand Down
16 changes: 8 additions & 8 deletions tests/integrations/openai/test_openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Comment thread
alexander-alderman-webb marked this conversation as resolved.
Resolved
"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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
40 changes: 32 additions & 8 deletions tests/integrations/openai_agents/test_openai_agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions tests/integrations/pydantic_ai/test_pydantic_ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading