Skip to content

Conversation

@DineshThumma9
Copy link

@DineshThumma9 DineshThumma9 commented Jan 8, 2026

Please ensure you have read the contribution guide before creating a pull request.


Link to Issue or Description of Change

1. Link to an existing issue (if applicable):

2. Or, if no issue exists, describe the change:

If applicable, please follow the issue templates to provide as much detail as possible.

Problem:
When ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS is set to false, the ADK telemetry code was setting span attributes to empty Python dicts ({}) instead of valid OpenTelemetry attribute types.

OpenTelemetry span attributes can only be primitives (bool, str, bytes, int, float) or sequences of those types. Setting a dict as an attribute value caused:

  1. Warnings in logs:
    Invalid type dict for attribute 'gcp.vertex.agent.llm_response' value...
  2. Crashes in opentelemetry-exporter-gcp-logging with:
    ValueError: Unexpected type
  3. No traces appearing in Vertex AI Agent Engine's trace viewer

Solution:
Changed all 6 instances of {} (Python dict) to '{}' (JSON string) in tracing.py. Strings are valid OpenTelemetry primitive types and correctly represent empty JSON objects.

Affected locations:

  • trace_tool_call – lines 152, 182
  • trace_merged_tool_calls – line 223
  • trace_call_llm – lines 268, 293
  • trace_send_data – line 349

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

Please include a summary of passed pytest results.

pytest tests/unittests/telemetry/ -v
# Result: 29 passed, 4 warnings in 9.66s

Updated 3 test functions to verify span attributes use JSON string '{}' instead of dict {}:

  • test_call_llm_disabling_request_response_content
  • test_trace_tool_call_disabling_request_response_content
  • test_trace_merged_tool_disabling_request_response_content

Manual End-to-End (E2E) Tests:

Please provide instructions on how to manually test your changes, including any necessary setup or configuration. Please provide logs or screenshots to help reviewers better understand the fix.

Setup:

$env:ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS="false"
python test_telemetry_fix.py

Result:

  • All span attributes use valid OpenTelemetry types
  • No Invalid type dict warnings
  • Telemetry exports without errors
  • Traces appear correctly in Vertex AI Agent Engine

Verified span attributes:

  • gcp.vertex.agent.tool_call_args: str = '{}'
  • gcp.vertex.agent.tool_response: str = '{}'
  • gcp.vertex.agent.llm_request: str = '{}'
  • gcp.vertex.agent.llm_response: str = '{}'

Checklist

  • I have read the [CONTRIBUTING.md](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

Additional context

This fix is critical for telemetry to work correctly in Vertex AI Agent Engine deployments where sensitive content capture is disabled. The change is minimal (6 characters changed across 6 lines) and low-risk, affecting only the literal values used for empty content placeholders.

Files changed:

  • tracing.py – 6 lines (dict → string)
  • test_spans.py – 3 test functions updated

@google-cla
Copy link

google-cla bot commented Jan 8, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @DineshThumma9, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves a critical bug in the telemetry system where disabled content capture led to invalid OpenTelemetry span attributes. By switching from Python dictionaries to JSON strings for empty attribute values, the system now adheres to OpenTelemetry standards, preventing errors and ensuring that traces are correctly exported and visible in the Vertex AI Agent Engine. The change is focused on maintaining data integrity and system stability under specific configuration settings.

Highlights

  • Critical Telemetry Fix: Addresses a critical issue where OpenTelemetry span attributes were incorrectly set to Python dictionaries ({}) instead of valid primitive types (JSON strings '{}') when content capture was disabled. This fix is essential for correct telemetry in Vertex AI Agent Engine deployments.
  • OpenTelemetry Compliance: Ensures compliance with OpenTelemetry specifications, which require span attributes to be primitives (bool, str, bytes, int, float) or sequences thereof. Using Python dicts previously caused warnings, exporter crashes, and prevented traces from appearing.
  • Minimal Code Change: The core fix involves changing 6 instances of {} to '{}' in src/google/adk/telemetry/tracing.py, a low-risk change with significant impact on telemetry reliability.
  • Enhanced Test Coverage: Existing unit tests were updated to specifically verify that span attributes are correctly set to JSON strings '{}' when content capture is disabled, reinforcing the robustness of the fix.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@adk-bot adk-bot added the tracing [Component] This issue is related to OpenTelemetry tracing label Jan 8, 2026
@adk-bot
Copy link
Collaborator

adk-bot commented Jan 8, 2026

Response from ADK Triaging Agent

Hello @DineshThumma9, thank you for your contribution!

Our records indicate that you haven't signed the Contributor License Agreement (CLA) yet. Please visit https://cla.developers.google.com/ to sign it.

Once the CLA is signed, we can proceed with reviewing your PR. Thanks!

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request correctly fixes a critical issue where using a Python dictionary for an OpenTelemetry span attribute caused crashes when content capture was disabled. The fix of using a JSON string '{}' is appropriate and well-tested. The updated unit tests are also a significant improvement in clarity and correctness. I've added a couple of suggestions to improve maintainability by using a constant for the empty JSON string and by refactoring duplicated test assertion logic into a helper function.

)
else:
span.set_attribute('gcp.vertex.agent.tool_call_args', {})
span.set_attribute('gcp.vertex.agent.tool_call_args', '{}')
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

To improve maintainability and avoid using a magic string, consider defining a constant for '{}' at the module level and reusing it here and in other similar places.

For example:

EMPTY_JSON_STRING = '{}'
...
span.set_attribute('gcp.vertex.agent.tool_call_args', EMPTY_JSON_STRING)

This change would apply to all 6 locations modified in this PR (lines 152, 182, 222, 268, 293, 349) and could also replace other existing instances of the '{}' literal in this file for consistency.

Comment on lines 477 to 501
llm_request_calls = [
call
for call in mock_span_fixture.set_attribute.call_args_list
if call.args[0] == 'gcp.vertex.agent.llm_request'
]
assert (
len(llm_request_calls) == 1
), "Expected 'gcp.vertex.agent.llm_request' to be set exactly once"
assert llm_request_calls[0].args[1] == '{}', (
"Expected JSON string '{}' for llm_request when content capture is"
f' disabled, got {llm_request_calls[0].args[1]!r}'
)

llm_response_calls = [
call
for call in mock_span_fixture.set_attribute.call_args_list
if call.args[0] == 'gcp.vertex.agent.llm_response'
]
assert (
len(llm_response_calls) == 1
), "Expected 'gcp.vertex.agent.llm_response' to be set exactly once"
assert llm_response_calls[0].args[1] == '{}', (
"Expected JSON string '{}' for llm_response when content capture is"
f' disabled, got {llm_response_calls[0].args[1]!r}'
)
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The new assertions are much clearer than the previous ones. To further improve the tests and reduce code duplication, you could extract this assertion logic into a helper function. This pattern is repeated for llm_request and llm_response here, and also in test_trace_tool_call_disabling_request_response_content and test_trace_merged_tool_disabling_request_response_content.

A helper could look something like this:

def _assert_span_attribute_set_to_empty_json(mock_span, attribute_name: str):
    calls = [
        call
        for call in mock_span.set_attribute.call_args_list
        if call.args[0] == attribute_name
    ]
    assert (
        len(calls) == 1
    ), f"Expected '{attribute_name}' to be set exactly once"
    assert calls[0].args[1] == '{}', (
        f"Expected JSON string '{{}}' for {attribute_name} when content capture is"
        f' disabled, got {calls[0].args[1]!r}'
    )

# Then in your test:
_assert_span_attribute_set_to_empty_json(mock_span_fixture, 'gcp.vertex.agent.llm_request')
_assert_span_attribute_set_to_empty_json(mock_span_fixture, 'gcp.vertex.agent.llm_response')

This would make the tests more concise and easier to maintain.

@ryanaiagent ryanaiagent self-assigned this Jan 9, 2026
@ryanaiagent
Copy link
Collaborator

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This is an excellent pull request that addresses a critical bug causing crashes when telemetry content capture is disabled. The solution of replacing empty Python dictionaries with an empty JSON string for span attributes is correct and effectively resolves the issue. The introduction of the EMPTY_JSON_STRING constant is a great improvement for code maintainability and consistency. Furthermore, the unit tests have been thoughtfully updated with a new helper function, which not only verifies the fix but also enhances the readability and robustness of the test suite. The changes are well-executed and thoroughly tested.

@ryanaiagent
Copy link
Collaborator

Hi @DineshThumma9 , Thank you for your contribution! We appreciate you taking the time to submit this pull request.
Can you quickly fix the failing pyink test you can run autoformat.sh to fix this. Let us know once you are done so that we can proceed with the review

@ryanaiagent ryanaiagent added the request clarification [Status] The maintainer need clarification or more information from the author label Jan 9, 2026
@DineshThumma9
Copy link
Author

Hi @DineshThumma9 , Thank you for your contribution! We appreciate you taking the time to submit this pull request. Can you quickly fix the failing pyink test you can run autoformat.sh to fix this. Let us know once you are done so that we can proceed with the review

I fixed linting now procced with review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

request clarification [Status] The maintainer need clarification or more information from the author tracing [Component] This issue is related to OpenTelemetry tracing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants