Skip to content

Migrate google GenAi instrumentation to use the GenAi utils package#10

Open
DylanRussell wants to merge 4 commits into
open-telemetry:mainfrom
DylanRussell:google_to_utils
Open

Migrate google GenAi instrumentation to use the GenAi utils package#10
DylanRussell wants to merge 4 commits into
open-telemetry:mainfrom
DylanRussell:google_to_utils

Conversation

@DylanRussell
Copy link
Copy Markdown
Contributor

@DylanRussell DylanRussell commented May 13, 2026

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_tool span being removed (code.function.parameters.someparam.type, code.function.parameters.someparam.value etc.), and other sem conv compliant attributes being added ti the span (specifically: gen_ai.tool.call.arguments, gen_ai.tool.call.result etc.), it also correctly changes the SpanKind from INTERNAL to CLIENT. The generate_content span also is switched to SpanKind CLIENT, and the gen_ai.provider.name attribute which was missing has been added, it's value is vertex_ai. The InstrumentationScope of the log and trace will also change, as the TelemetryHandler class 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..

@DylanRussell DylanRussell requested a review from a team as a code owner May 13, 2026 15:27
Copilot AI review requested due to automatic review settings May 13, 2026 15:27
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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_content instrumentation through TelemetryHandler.
  • 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.candidates can be absent for blocked/no-candidate responses, but candidates += response.candidates raises TypeError in 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 TypeError for 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 for gen_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, ToolInvocation will 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_content is a semconv operation value, so this should use the generated GenAiOperationNameValues enum 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_content is a semconv operation value, so this should use the generated GenAiOperationNameValues enum 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_content is a semconv operation value, so this should use the generated GenAiOperationNameValues enum 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_content is a semconv operation value, so this should use the generated GenAiOperationNameValues enum 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 to gen_ai.provider.name, but _genai_system contains the legacy gen_ai.system values (gemini/vertex_ai). The new semconv provider values are gcp.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 to gen_ai.provider.name, but _genai_system contains the legacy gen_ai.system values (gemini/vertex_ai). The new semconv provider values are gcp.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 to gen_ai.provider.name, but _genai_system contains the legacy gen_ai.system values (gemini/vertex_ai). The new semconv provider values are gcp.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,

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.

4 participants