Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@vasantteja
Copy link
Contributor

@vasantteja vasantteja commented Dec 16, 2025

Description

Implements OpenTelemetry instrumentation for Anthropic's Messages.create API (sync, non-streaming). This adds automatic tracing for Anthropic SDK calls, capturing GenAI semantic convention attributes for observability.

P.S: LLM help was used for writing the code.

What's Implemented

  • patch.py: Wrapper function for Messages.create that creates spans with request/response attributes
  • utils.py: Helper functions for attribute extraction, error handling, and content capture configuration
  • __init__.py: Wiring for patching/unpatching via wrapt
  • Tests: Comprehensive test suite with VCR cassettes for API mocking
  • Updated minimum anthropic version to 0.16.0 - the instrumentation requires the modern SDK structure (anthropic.resources.messages module) which doesn't exist in versions prior to 0.18.0.

Semantic Convention Attributes Captured

Request:

  • gen_ai.operation.name (chat)
  • gen_ai.system (anthropic)
  • gen_ai.request.model
  • gen_ai.request.max_tokens
  • gen_ai.request.temperature
  • gen_ai.request.top_p
  • gen_ai.request.top_k
  • gen_ai.request.stop_sequences
  • server.address

Response:

  • gen_ai.response.id
  • gen_ai.response.model
  • gen_ai.response.finish_reasons
  • gen_ai.usage.input_tokens
  • gen_ai.usage.output_tokens

Error:

  • error.type (on exceptions)

Fixes #(#3949)

Type of change

  • New feature (non-breaking change which adds functionality)

How Has This Been Tested?

Ran the full test suite with VCR cassettes for mocked API responses:

pytest instrumentation-genai/opentelemetry-instrumentation-anthropic/tests/ -v

Test cases:

  • Basic sync message creation with correct span attributes
  • All optional parameters (temperature, top_p, top_k, stop_sequences)
  • Token usage capture (input/output tokens)
  • Stop reason captured as finish_reasons array
  • Connection error handling (APIConnectionError)
  • API error handling (404 NotFoundError)
  • Uninstrumentation removes patching
  • Multiple instrument/uninstrument cycles

Results: 15 tests passed (8 new + 7 existing instrumentor tests)

Does This PR Require a Core Repo Change?

  • No.

Checklist:

  • Followed the style guidelines of this project
  • Changelogs have been updated
  • Unit tests have been added
  • Documentation has been updated

@vasantteja vasantteja removed their assignment Dec 16, 2025
@vasantteja vasantteja removed their assignment Dec 16, 2025
@vasantteja vasantteja removed their assignment Dec 16, 2025
@vasantteja vasantteja removed their assignment Dec 16, 2025
@vasantteja vasantteja removed their assignment Dec 16, 2025
@vasantteja vasantteja removed their assignment Dec 16, 2025
@vasantteja vasantteja removed their assignment Dec 16, 2025
@vasantteja vasantteja closed this Dec 16, 2025
@vasantteja vasantteja reopened this Dec 17, 2025
@vasantteja vasantteja removed their assignment Dec 17, 2025
Copy link
Member

@aabmass aabmass left a comment

Choose a reason for hiding this comment

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

A few suggestions, but looks pretty good, thanks

Comment on lines +85 to +92
GenAIAttributes.GEN_AI_REQUEST_MODEL: kwargs.get("model"),
GenAIAttributes.GEN_AI_REQUEST_MAX_TOKENS: kwargs.get("max_tokens"),
GenAIAttributes.GEN_AI_REQUEST_TEMPERATURE: kwargs.get("temperature"),
GenAIAttributes.GEN_AI_REQUEST_TOP_P: kwargs.get("top_p"),
GenAIAttributes.GEN_AI_REQUEST_TOP_K: kwargs.get("top_k"),
GenAIAttributes.GEN_AI_REQUEST_STOP_SEQUENCES: kwargs.get(
"stop_sequences"
),
Copy link
Member

Choose a reason for hiding this comment

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

For extracting parameters from the untyped kwargs dict, can you define a function with copied method signature from the Anthropic code being instrumented (and add a link to the code in a comment) and call it with *args, **kwargs? IMO it helps the reader and will let the type checker know the expected types

Example from Vertex:

return GenerateContentParams(
model=request.model,
contents=request.contents,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Awesome suggestion!! Added this snippet as we have in vertex ai.

Comment on lines 43 to 63
span_attributes = {**get_llm_request_attributes(kwargs, instance)}

span_name = f"{span_attributes[GenAIAttributes.GEN_AI_OPERATION_NAME]} {span_attributes[GenAIAttributes.GEN_AI_REQUEST_MODEL]}"
with tracer.start_as_current_span(
name=span_name,
kind=SpanKind.CLIENT,
attributes=span_attributes,
end_on_exit=False,
) as span:
try:
result = wrapped(*args, **kwargs)

if span.is_recording():
_set_response_attributes(span, result)

span.end()
return result

except Exception as error:
handle_span_exception(span, error)
raise
Copy link
Member

Choose a reason for hiding this comment

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

@keith-decker can TelemetryHandler cover all of the common code in this PR? This seems like a great PR to start integrating GenAI util with

Copy link
Contributor Author

@vasantteja vasantteja Dec 26, 2025

Choose a reason for hiding this comment

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

@aabmass @keith-decker I ported the code to use TelemetryHandler. I see that it is emitting only span attributes. Do we need implement log event emitter in TelemetryHandler? I see we have a pr for emitting log events here. I am going to update this codebase to emit logs once this pr is merged.

- Replaced direct tracer and logger initialization with TelemetryHandler in AnthropicInstrumentor.
- Updated messages_create function to utilize TelemetryHandler for LLM invocation tracking.
- Removed unused span handling functions and attributes to streamline code.
- Enhanced attribute capturing for LLM requests and responses.
- Removed unused trace import from conftest.py and updated tracer_provider fixture to return the provider instead of yielding it.
- Enhanced test_instrument_with_no_providers to ensure proper instrument/uninstrument cycle while passing providers for a clean test environment.
- Improved readability by restructuring the assignment of request_model in the messages_create function.
- Ensured consistent handling of model attributes from both the attributes dictionary and kwargs.
…s function

- Updated the return type to include AttributeValue for better type safety.
- Expanded the docstring to detail the OpenTelemetry semantic conventions for LLM requests and server attributes.
- Included descriptions for GenAI attributes and server attributes to improve clarity and documentation.
@vasantteja vasantteja force-pushed the feat/anthropic-messages-create-sync branch from e011a91 to 643a282 Compare December 27, 2025 02:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants