Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ async def _aset_token_usage(
token_histogram: Histogram = None,
choice_counter: Counter = None,
):
if not isinstance(response, dict):
response = response.__dict__
from opentelemetry.instrumentation.anthropic.utils import _extract_response_data
response = _extract_response_data(response)

if usage := response.get("usage"):
prompt_tokens = usage.input_tokens
Expand Down Expand Up @@ -223,8 +223,8 @@ def _set_token_usage(
token_histogram: Histogram = None,
choice_counter: Counter = None,
):
if not isinstance(response, dict):
response = response.__dict__
from opentelemetry.instrumentation.anthropic.utils import _extract_response_data
response = _extract_response_data(response)

if usage := response.get("usage"):
prompt_tokens = usage.input_tokens
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
dont_throw,
model_as_dict,
should_send_prompts,
_extract_response_data,
)
from opentelemetry.semconv._incubating.attributes.gen_ai_attributes import (
GEN_AI_RESPONSE_ID,
Expand Down Expand Up @@ -170,6 +171,7 @@ def _set_span_completions(span, response):
return
from opentelemetry.instrumentation.anthropic import set_span_attribute

response = _extract_response_data(response)
index = 0
prefix = f"{SpanAttributes.LLM_COMPLETIONS}.{index}"
set_span_attribute(span, f"{prefix}.finish_reason", response.get("stop_reason"))
Expand Down Expand Up @@ -236,8 +238,7 @@ def _set_span_completions(span, response):
def set_response_attributes(span, response):
from opentelemetry.instrumentation.anthropic import set_span_attribute

if not isinstance(response, dict):
response = response.__dict__
response = _extract_response_data(response)
set_span_attribute(span, SpanAttributes.LLM_RESPONSE_MODEL, response.get("model"))
set_span_attribute(span, GEN_AI_RESPONSE_ID, response.get("id"))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,32 @@ def _handle_exception(e, func, logger):
return async_wrapper if asyncio.iscoroutinefunction(func) else sync_wrapper


def _extract_response_data(response):
"""Extract the actual response data from both regular and with_raw_response wrapped responses."""
if isinstance(response, dict):
return response

# Handle with_raw_response wrapped responses
if hasattr(response, 'parse') and callable(response.parse):
try:
# For with_raw_response, parse() gives us the actual response object
parsed_response = response.parse()
if not isinstance(parsed_response, dict):
parsed_response = parsed_response.__dict__
return parsed_response
except Exception:
pass

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _extract_response_data helper centralizes response extraction. Consider logging the exception inside the try/except block (instead of silently passing) to aid debugging potential parsing issues.

Suggested change
pass
logging.debug("Failed to parse response in _extract_response_data", exc_info=True)


# Fallback to __dict__ for regular response objects
if hasattr(response, '__dict__'):
return response.__dict__

return {}


@dont_throw
def shared_metrics_attributes(response):
if not isinstance(response, dict):
response = response.__dict__
response = _extract_response_data(response)

common_attributes = Config.get_common_metrics_attributes()

Expand Down
128 changes: 115 additions & 13 deletions packages/opentelemetry-instrumentation-anthropic/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pytest = "^8.2.2"
pytest-sugar = "1.0.0"

[tool.poetry.group.test.dependencies]
anthropic = ">=0.36.0"
anthropic = {extras = ["bedrock"], version = ">=0.36.0"}
pytest = "^8.2.2"
pytest-sugar = "1.0.0"
vcrpy = "^6.0.1"
Expand Down
Loading
Loading