Skip to content

fix(gapic-generator): [Approach 2] attach _host via internal _TransportClientOptions subclass - #18934

Draft
chalmerlowe wants to merge 4 commits into
mainfrom
fix/otel-default-host-subclass
Draft

chalmerlowe wants to merge 4 commits into
mainfrom
fix/otel-default-host-subclass

Conversation

@chalmerlowe

Copy link
Copy Markdown
Contributor

Summary

Comparison prototype (Clone 2 of #18869) implementing Approach 2: wrapping client_options in an internal _TransportClientOptions(client_options_lib.ClientOptions) subclass that attaches _host separately while keeping api_endpoint pristine.

Changes on top of #18869

  1. Internal _TransportClientOptions subclass (gapic-generator & google-api-core):
    • Defines _TransportClientOptions(client_options_lib.ClientOptions) in transports/base.py.j2 to store _host separately without mutating api_endpoint or changing public wrap_method / interceptor signatures.
    • Updates _extract_endpoint_attributes in google/api_core/_observability.py to fall back to getattr(client_options, "_host", None) (or client_options.get("_host")) when api_endpoint is unset.
  2. Pre-constructed channel guard (_ignore_credentials):
    • Skips wrapping with _TransportClientOptions when self._ignore_credentials is True so pre-constructed grpc.Channel / grpc.aio.Channel instances do not falsely report DEFAULT_HOST.
    • Updates construct_observability_client in test_span_compliance.py to pass a callable channel factory (_insecure_channel_factory) so local Showcase gRPC compliance tests exercise the primary host-managed path (self._ignore_credentials = False).
  3. Upfront dict conversion:
    • Converts dict client_options upfront via client_options_lib.from_dict(client_options).

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

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.

Code Review

This pull request introduces a mechanism to attach the resolved transport host as a separate _host attribute on an internal _TransportClientOptions subclass without mutating api_endpoint. This allows OpenTelemetry spans to fall back to _host when api_endpoint is not set, which is also supported by updates to google-api-core's observability module. The changes include extensive updates to generated base transports, unit tests, and system tests. The reviewer suggests simplifying the conditional check for wrapping client_options to always wrap it when credentials are not ignored, ensuring robust support for dynamic OpenTelemetry enablement.

Comment on lines +189 to +195
if not self._ignore_credentials and (
client_options is not None
or (
_observability is not None
and _observability.is_otel_capabilities_enabled(None)
)
):

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.

medium

The current condition only wraps client_options when it is not None OR when OpenTelemetry is already enabled at startup.

This introduces an inconsistency:

  1. If a user passes client_options=ClientOptions(), it is always wrapped and _host is attached, even if OTEL is disabled at startup. If OTEL is enabled later dynamically, the host fallback works.
  2. If a user passes client_options=None and OTEL is disabled at startup, it is NOT wrapped. If OTEL is enabled later dynamically, the host fallback fails because self._client_options remains None.

To ensure consistent behavior and support dynamic OpenTelemetry enablement robustly, we should always wrap client_options in _TransportClientOptions when not self._ignore_credentials.

        if not self._ignore_credentials:

This branch has not been deployed

No deployments
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.

1 participant