Migrate google GenAi instrumentation to use the GenAi utils package#10
Migrate google GenAi instrumentation to use the GenAi utils package#10DylanRussell wants to merge 4 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR migrates Google GenAI instrumentation toward the shared GenAI utility package, especially for inference and tool-call telemetry.
Changes:
- Routes experimental
generate_contentinstrumentation throughTelemetryHandler. - Refactors tool-call wrapping to use shared GenAI tool invocation spans.
- Updates/removes tests and documents execute-tool attribute changes.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
util/opentelemetry-util-genai/src/opentelemetry/util/genai/handler.py |
Adds operation_name passthrough for inference context manager. |
util/opentelemetry-util-genai/src/opentelemetry/util/genai/_tool_invocation.py |
Adds JSON serialization for tool arguments/results. |
instrumentation/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/tool_call_wrapper.py |
Refactors tool wrapping to use TelemetryHandler. |
instrumentation/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/instrumentor.py |
Creates and passes a shared GenAI telemetry handler. |
instrumentation/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/generate_content.py |
Migrates experimental generate-content telemetry to GenAI utils. |
instrumentation/opentelemetry-instrumentation-google-genai/tests/utils/test_tool_call_wrapper.py |
Updates tool wrapper tests for new attributes. |
instrumentation/opentelemetry-instrumentation-google-genai/tests/generate_content/test_tool_call_instrumentation.py |
Removes generate-content tool-call instrumentation tests. |
instrumentation/opentelemetry-instrumentation-google-genai/CHANGELOG.md |
Notes migration and execute-tool attribute changes. |
Comments suppressed due to low confidence (10)
instrumentation/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/generate_content.py:1098
response.candidatescan be absent for blocked/no-candidate responses, butcandidates += response.candidatesraisesTypeErrorin that case and changes the SDK result into an instrumentation exception.
helper._update_response(response)
candidates += response.candidates
return response
instrumentation/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/tool_call_wrapper.py:73
- Storing the raw tool result lets telemetry finalization raise
TypeErrorfor non-JSON-serializable return values, which can replace a successful tool call with an instrumentation exception. Coerce or safely fall back before assigning the result used forgen_ai.tool.call.result.
if capture_content_on_span:
tool_invocation.arguments = _get_function_args(
tool_function, args, kwargs
)
tool_invocation.tool_result = result
instrumentation/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/tool_call_wrapper.py:59
- The async wrapper stores the raw tool result for
gen_ai.tool.call.result; if the coroutine returns a non-JSON-serializable object,ToolInvocationwill raise during span finalization and turn a successful tool call into an instrumentation error.
if capture_content_on_span:
tool_invocation.arguments = _get_function_args(
tool_function, args, kwargs
)
tool_invocation.tool_result = result
instrumentation/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/generate_content.py:890
generate_contentis a semconv operation value, so this should use the generatedGenAiOperationNameValuesenum instead of a string literal to stay aligned with the semconv package.
with telemetry_handler.inference(
provider=helper._genai_system,
request_model=model,
operation_name="generate_content",
) as invocation:
instrumentation/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/generate_content.py:981
generate_contentis a semconv operation value, so this should use the generatedGenAiOperationNameValuesenum instead of a string literal to stay aligned with the semconv package.
with telemetry_handler.inference(
provider=helper._genai_system,
request_model=model,
operation_name="generate_content",
) as invocation:
instrumentation/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/generate_content.py:1073
generate_contentis a semconv operation value, so this should use the generatedGenAiOperationNameValuesenum instead of a string literal to stay aligned with the semconv package.
with telemetry_handler.inference(
provider=helper._genai_system,
request_model=model,
operation_name="generate_content",
) as invocation:
instrumentation/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/generate_content.py:1167
generate_contentis a semconv operation value, so this should use the generatedGenAiOperationNameValuesenum instead of a string literal to stay aligned with the semconv package.
invocation = telemetry_handler.start_inference(
provider=helper._genai_system,
request_model=model,
operation_name="generate_content",
)
instrumentation/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/generate_content.py:979
TelemetryHandler.inference(provider=...)writes this value togen_ai.provider.name, but_genai_systemcontains the legacygen_ai.systemvalues (gemini/vertex_ai). The new semconv provider values aregcp.gemini/gcp.vertex_ai, so stream spans and metrics use the wrong provider name.
with telemetry_handler.inference(
provider=helper._genai_system,
request_model=model,
instrumentation/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/generate_content.py:1071
TelemetryHandler.inference(provider=...)writes this value togen_ai.provider.name, but_genai_systemcontains the legacygen_ai.systemvalues (gemini/vertex_ai). The new semconv provider values aregcp.gemini/gcp.vertex_ai, so async spans and metrics use the wrong provider name.
with telemetry_handler.inference(
provider=helper._genai_system,
request_model=model,
instrumentation/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/generate_content.py:1165
TelemetryHandler.start_inference(provider=...)writes this value togen_ai.provider.name, but_genai_systemcontains the legacygen_ai.systemvalues (gemini/vertex_ai). The new semconv provider values aregcp.gemini/gcp.vertex_ai, so async stream spans and metrics use the wrong provider name.
invocation = telemetry_handler.start_inference(
provider=helper._genai_system,
request_model=model,
Refactor code to make use of the shared GenAi Utils package. This shared package is used by multiple GenAI instrumentations, and ensures sem convs are followed and up to date. This does result in some span attributes on the
execute_toolspan being removed (code.function.parameters.someparam.type,code.function.parameters.someparam.valueetc.), and other sem conv compliant attributes being added ti the span (specifically:gen_ai.tool.call.arguments,gen_ai.tool.call.resultetc.), it also correctly changes theSpanKindfromINTERNALtoCLIENT. Thegenerate_contentspan also is switched toSpanKindCLIENT, and thegen_ai.provider.nameattribute which was missing has been added, it's value isvertex_ai. TheInstrumentationScopeof the log and trace will also change, as theTelemetryHandlerclass in the utils package is now used to write the logs and traces.This requires open-telemetry/opentelemetry-python-contrib#4570 to get merged and then a release of the GenAi utils package, but I want to get input on this and make sure no additional changes would be needed to the GenAi utils package.. Some tests will fail until that's merged and released..