feat(gax): actionable errors logging in ApiTracer framework#4153
feat(gax): actionable errors logging in ApiTracer framework#4153westarle wants to merge 7 commits into
Conversation
ba3c2cd to
865c099
Compare
There was a problem hiding this comment.
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)
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)
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");
}af203ff to
ade532f
Compare
ade532f to
a3ed812
Compare
a3ed812 to
1548dce
Compare
1548dce to
983d57d
Compare
983d57d to
b87215a
Compare
76d0900 to
042c642
Compare
31ce3f0 to
269c749
Compare
eb6ef7c to
5d46299
Compare

This PR introduces SLF4J logging for "Actionable Errors" occurring at the RPC Attempt level.