diff --git a/docs/content/core/logging.mdx b/docs/content/core/logging.mdx index 865b73432..a5e33c352 100644 --- a/docs/content/core/logging.mdx +++ b/docs/content/core/logging.mdx @@ -69,7 +69,7 @@ Key | Type | Example | Description **functionVersion**| String | "12" **functionMemorySize**| String | "128" **functionArn**| String | "arn:aws:lambda:eu-west-1:012345678910:function:example-powertools-HelloWorldFunction-1P1Z6B39FLU73" - +**xray_trace_id**| String | "1-5759e988-bd862e3fe1be46a994272793" | X-Ray Trace ID when Lambda function has enabled Tracing ## Capturing context Lambda info diff --git a/powertools-logging/pom.xml b/powertools-logging/pom.xml index 4e521cc9a..038f6a31d 100644 --- a/powertools-logging/pom.xml +++ b/powertools-logging/pom.xml @@ -88,6 +88,11 @@ mockito-core test + + org.mockito + mockito-inline + test + org.aspectj aspectjweaver diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java index 7c9b1a3e1..ec3f64165 100644 --- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java +++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java @@ -20,6 +20,7 @@ import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.Map; +import java.util.Optional; import java.util.Random; import com.fasterxml.jackson.databind.ObjectMapper; @@ -35,6 +36,8 @@ import org.aspectj.lang.annotation.Pointcut; import software.amazon.lambda.powertools.logging.PowertoolsLogging; +import static java.util.Optional.empty; +import static java.util.Optional.ofNullable; import static software.amazon.lambda.powertools.core.internal.LambdaHandlerProcessor.coldStartDone; import static software.amazon.lambda.powertools.core.internal.LambdaHandlerProcessor.extractContext; import static software.amazon.lambda.powertools.core.internal.LambdaHandlerProcessor.isColdStart; @@ -44,6 +47,7 @@ import static software.amazon.lambda.powertools.core.internal.LambdaHandlerProcessor.serviceName; import static software.amazon.lambda.powertools.logging.PowertoolsLogger.appendKey; import static software.amazon.lambda.powertools.logging.PowertoolsLogger.appendKeys; +import static software.amazon.lambda.powertools.logging.internal.SystemWrapper.getenv; @Aspect public final class LambdaLoggingAspect { @@ -83,6 +87,7 @@ public Object around(ProceedingJoinPoint pjp, appendKey("service", serviceName()); }); + getXrayTraceId().ifPresent(xRayTraceId -> appendKey("xray_trace_id", xRayTraceId)); if (powertoolsLogging.logEvent()) { proceedArgs = logEvent(pjp); @@ -179,4 +184,12 @@ private Object[] logFromInputStream(final ProceedingJoinPoint pjp) { private Logger logger(final ProceedingJoinPoint pjp) { return LogManager.getLogger(pjp.getSignature().getDeclaringType()); } + + private static Optional getXrayTraceId() { + final String X_AMZN_TRACE_ID = getenv("_X_AMZN_TRACE_ID"); + if(X_AMZN_TRACE_ID != null) { + return ofNullable(X_AMZN_TRACE_ID.split(";")[0].replace("Root=", "")); + } + return empty(); + } } diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/SystemWrapper.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/SystemWrapper.java new file mode 100644 index 000000000..c521fe77f --- /dev/null +++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/SystemWrapper.java @@ -0,0 +1,10 @@ +package software.amazon.lambda.powertools.logging.internal; + +class SystemWrapper { + private SystemWrapper() { + } + + public static String getenv(String name) { + return System.getenv(name); + } +} diff --git a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java index c99fdabe5..91e76a154 100644 --- a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java +++ b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java @@ -28,6 +28,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import software.amazon.lambda.powertools.core.internal.LambdaHandlerProcessor; import software.amazon.lambda.powertools.logging.handlers.PowerLogToolEnabled; import software.amazon.lambda.powertools.logging.handlers.PowerLogToolEnabledForStream; @@ -38,8 +40,10 @@ import static org.apache.commons.lang3.reflect.FieldUtils.writeStaticField; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; +import static org.mockito.MockitoAnnotations.openMocks; +import static software.amazon.lambda.powertools.logging.internal.SystemWrapper.getenv; class LambdaLoggingAspectTest { @@ -52,7 +56,7 @@ class LambdaLoggingAspectTest { @BeforeEach void setUp() throws IllegalAccessException { - initMocks(this); + openMocks(this); ThreadContext.clearAll(); writeStaticField(LambdaHandlerProcessor.class, "IS_COLD_START", null, true); setupContext(); @@ -172,6 +176,21 @@ void shouldLogServiceNameWhenEnvVarSet() throws IllegalAccessException { .containsEntry("service", "testService"); } + @Test + void shouldLogxRayTraceIdEnvVarSet() { + String xRayTraceId = "1-5759e988-bd862e3fe1be46a994272793"; + + try (MockedStatic mocked = mockStatic(SystemWrapper.class)) { + mocked.when(() -> getenv("_X_AMZN_TRACE_ID")).thenReturn("Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1\""); + + requestHandler.handleRequest(new Object(), context); + + assertThat(ThreadContext.getImmutableContext()) + .hasSize(EXPECTED_CONTEXT_SIZE + 1) + .containsEntry("xray_trace_id", xRayTraceId); + } + } + private void setupContext() { when(context.getFunctionName()).thenReturn("testFunction"); when(context.getInvokedFunctionArn()).thenReturn("testArn");