Skip to content

feat(gax): actionable errors logging in ApiTracer framework#4153

Draft
westarle wants to merge 2 commits intogoogleapis:mainfrom
westarle:feat/actionable-errors-api-tracer
Draft

feat(gax): actionable errors logging in ApiTracer framework#4153
westarle wants to merge 2 commits intogoogleapis:mainfrom
westarle:feat/actionable-errors-api-tracer

Conversation

@westarle
Copy link
Contributor

This PR introduces SLF4J logging for "Actionable Errors" occurring at the T4 (RPC attempt) level, directly answering the Application Centric Observability guidelines.

Changes:

  • Introduced LoggingTracer and LoggingTracerFactory as decorators for the ApiTracer interface.
  • Intercepts attemptFailed callbacks to extract the google.rpc.ErrorInfo payload and structured ApiTracerContext attributes (e.g., server.port, gcp.client.repo, rpc.method).
  • Emits an INFO level SLF4J log containing the "Actionable Error Message" natively tied to the active T4 span (ensuring OTel correlation).
  • Injected the LoggingTracerFactory decorator directly into ClientContext, ensuring it operates independently of whether a user has configured an OpenTelemetry or OpenCensus backend, but strictly gated behind the GOOGLE_SDK_JAVA_LOGGING=true environment variable.

@product-auto-label product-auto-label bot added the size: l Pull request size is large. label Mar 18, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, 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 significantly enhances the observability of RPC calls within the GAX framework by implementing structured logging for "Actionable Errors." It provides detailed context for failed RPC attempts, making it easier to diagnose and understand issues at the application level, aligning with Application Centric Observability guidelines. The new logging is conditionally enabled via an environment variable and integrates seamlessly with existing tracing infrastructure.

Highlights

  • Actionable Error Logging: Introduced a new mechanism to log "Actionable Errors" at the RPC attempt (T4) level using SLF4J, providing enhanced observability.
  • Structured Context: Enhanced error logging to include structured google.rpc.ErrorInfo payload and ApiTracerContext attributes (e.g., server.port, rpc.method) for better diagnostic information.
  • Tracing Integration: Ensured error messages are natively tied to the active T4 span, facilitating OpenTelemetry correlation and improved tracing.
  • Conditional Activation: Implemented logging activation via the GOOGLE_SDK_JAVA_LOGGING=true environment variable, ensuring it operates independently of OpenTelemetry/OpenCensus backend configuration.
  • API Tracer Decoration: Introduced LoggingTracer and LoggingTracerFactory to decorate the ApiTracer interface and intercept attemptFailed callbacks for error capture.
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.

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.

@westarle westarle force-pushed the feat/actionable-errors-api-tracer branch from ba3c2cd to 865c099 Compare March 18, 2026 04:52
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 introduces logging for actionable errors within the ApiTracer framework, which is a great step towards better observability. The implementation uses a decorator pattern with LoggingTracer and LoggingTracerFactory to intercept failed RPC attempts and log relevant context, gated by an environment variable. The changes are well-structured. I have a couple of suggestions to improve maintainability and test robustness.

I am having trouble creating individual review comments. Click here to see my feedback.

gax-java/gax/src/main/java/com/google/api/gax/tracing/LoggingTracer.java (186-190)

medium

The string literals for logging context keys like "error.type" are hardcoded. To improve maintainability and prevent potential typos, it's a good practice to define them as private static final constants at the top of the class and use them here.

For example, you could add:

private static final String ERROR_TYPE_ATTRIBUTE = "error.type";
private static final String GCP_ERRORS_DOMAIN_ATTRIBUTE = "gcp.errors.domain";
private static final String GCP_ERRORS_METADATA_PREFIX = "gcp.errors.metadata.";

And then use these constants in this block.

gax-java/gax/src/test/java/com/google/api/gax/logging/LoggingUtilsTest.java (120-137)

medium

The testLogActionableError_success test is a bit weak as it only verifies that getLogger() and isInfoEnabled() are called. It doesn't confirm that the logging context and message are correctly passed to the underlying logging framework. To make the test more robust, you should also verify that addKeyValue is called with the expected key-value pairs from the context and that log is called with the correct message on the LoggingEventBuilder.

  @Test
  void testLogActionableError_success() {
    LoggingUtils.setLoggingEnabled(true);
    LoggerProvider loggerProvider = mock(LoggerProvider.class);
    Logger logger = mock(Logger.class);
    when(loggerProvider.getLogger()).thenReturn(logger);
    when(logger.isInfoEnabled()).thenReturn(true);

    org.slf4j.spi.LoggingEventBuilder eventBuilder = mock(org.slf4j.spi.LoggingEventBuilder.class);
    when(logger.atInfo()).thenReturn(eventBuilder);
    when(eventBuilder.addKeyValue(anyString(), any())).thenReturn(eventBuilder);

    Map<String, Object> context = Collections.singletonMap("key", "value");
    LoggingUtils.logActionableError(context, loggerProvider, "message");

    verify(loggerProvider).getLogger();
    verify(logger).isInfoEnabled();
    verify(eventBuilder).addKeyValue("key", "value");
    verify(eventBuilder).log("message");
  }

if (apiTracerFactory instanceof SpanTracerFactory) {
apiTracerFactory = apiTracerFactory.withContext(apiTracerContext);
}
if (com.google.api.gax.logging.LoggingUtils.isLoggingEnabled()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

We plan to introduce a CompositeTracer and CompositeTracerFactory that could contain a list of tracer/facrtories, similar to what is already done in Spanner. Then require customers to create a CompositeTracerFactory that contains SpanFactory/MetricTracerFactory and potentially LoggingTracerFactory.

Can we still rely on the existence of a LoggingTracerFactory to enable this feature?

}
}

if (error instanceof ApiException) {
Copy link
Contributor

Choose a reason for hiding this comment

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

We have a util method to extract status

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

Labels

size: l Pull request size is large.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants