Skip to content

Commit de547d0

Browse files
authored
feat: Add support for POWERTOOLS_LOGGER_LOG_EVENT (#1510)
1 parent 0f3e896 commit de547d0

File tree

6 files changed

+127
-47
lines changed

6 files changed

+127
-47
lines changed

Diff for: docs/core/logging.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -217,9 +217,7 @@ Key | Type | Example | Description
217217

218218
## Capturing context Lambda info
219219

220-
You can enrich your structured logs with key Lambda context information via `logEvent` annotation parameter.
221-
You can also explicitly log any incoming event using `logEvent` param. Refer [Override default object mapper](#override-default-object-mapper)
222-
to customise what is logged.
220+
When debugging in non-production environments, you can instruct Logger to log the incoming event with `@Logger(logEvent = true)` or via `POWERTOOLS_LOGGER_LOG_EVENT=true` environment variable.
223221

224222
!!! warning
225223
Log event is disabled by default to prevent sensitive info being logged.

Diff for: docs/index.md

+2
Original file line numberDiff line numberDiff line change
@@ -285,5 +285,7 @@ Depending on your version of Java (either Java 1.8 or 11+), the configuration sl
285285
| **POWERTOOLS_METRICS_NAMESPACE** | Sets namespace used for metrics | [Metrics](./core/metrics) |
286286
| **POWERTOOLS_LOGGER_SAMPLE_RATE** | Debug log sampling | [Logging](./core/logging) |
287287
| **POWERTOOLS_LOG_LEVEL** | Sets logging level | [Logging](./core/logging) |
288+
| **POWERTOOLS_LOGGER_LOG_EVENT** | Enables/Disables whether to log the incoming event when using the aspect | [Logging](./core/logging) |
288289
| **POWERTOOLS_TRACER_CAPTURE_RESPONSE** | Enables/Disables tracing mode to capture method response | [Tracing](./core/tracing) |
289290
| **POWERTOOLS_TRACER_CAPTURE_ERROR** | Enables/Disables tracing mode to capture method error | [Tracing](./core/tracing) |
291+

Diff for: powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/LambdaHandlerProcessor.java

+7
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ public static boolean isHandlerMethod(final ProceedingJoinPoint pjp) {
4747
return placedOnRequestHandler(pjp) || placedOnStreamHandler(pjp);
4848
}
4949

50+
/**
51+
* The class needs to implement RequestHandler interface
52+
* The function needs to have exactly two arguments
53+
* The second argument needs to be of type com.amazonaws.services.lambda.runtime.Context
54+
* @param pjp
55+
* @return
56+
*/
5057
public static boolean placedOnRequestHandler(final ProceedingJoinPoint pjp) {
5158
return RequestHandler.class.isAssignableFrom(pjp.getSignature().getDeclaringType())
5259
&& pjp.getArgs().length == 2

Diff for: powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java

+13-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import com.fasterxml.jackson.core.JsonPointer;
3434
import com.fasterxml.jackson.core.JsonProcessingException;
3535
import com.fasterxml.jackson.databind.JsonNode;
36+
3637
import java.io.ByteArrayInputStream;
3738
import java.io.ByteArrayOutputStream;
3839
import java.io.IOException;
@@ -42,6 +43,7 @@
4243
import java.util.Map;
4344
import java.util.Optional;
4445
import java.util.Random;
46+
4547
import org.apache.logging.log4j.Level;
4648
import org.apache.logging.log4j.LogManager;
4749
import org.apache.logging.log4j.Logger;
@@ -65,6 +67,7 @@ public final class LambdaLoggingAspect {
6567

6668
private static final String LOG_LEVEL = System.getenv("POWERTOOLS_LOG_LEVEL");
6769
private static final String SAMPLING_RATE = System.getenv("POWERTOOLS_LOGGER_SAMPLE_RATE");
70+
private static Boolean LOG_EVENT;
6871

6972
private static Level LEVEL_AT_INITIALISATION;
7073

@@ -74,6 +77,13 @@ public final class LambdaLoggingAspect {
7477
}
7578

7679
LEVEL_AT_INITIALISATION = LOG.getLevel();
80+
81+
String logEvent = System.getenv("POWERTOOLS_LOGGER_LOG_EVENT");
82+
if (logEvent != null) {
83+
LOG_EVENT = Boolean.parseBoolean(logEvent);
84+
} else {
85+
LOG_EVENT = false;
86+
}
7787
}
7888

7989
private static void resetLogLevels(Level logLevel) {
@@ -104,7 +114,9 @@ public Object around(ProceedingJoinPoint pjp,
104114

105115
getXrayTraceId().ifPresent(xRayTraceId -> appendKey("xray_trace_id", xRayTraceId));
106116

107-
if (logging.logEvent()) {
117+
// Check that the environment variable was enabled explicitly
118+
// Or that the handler was annotated with @Logging(logEvent = true)
119+
if (LOG_EVENT || logging.logEvent()) {
108120
proceedArgs = logEvent(pjp);
109121
}
110122

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2023 Amazon.com, Inc. or its affiliates.
3+
* Licensed under the Apache License, Version 2.0 (the
4+
* "License"); you may not use this file except in compliance
5+
* with the License. You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*
13+
*/
14+
15+
package software.amazon.lambda.powertools.logging.handlers;
16+
17+
import com.amazonaws.services.lambda.runtime.Context;
18+
import com.amazonaws.services.lambda.runtime.RequestHandler;
19+
import software.amazon.lambda.powertools.logging.Logging;
20+
21+
public class PowerToolLogEventDisabled implements RequestHandler<Object, Object> {
22+
23+
@Logging(logEvent = false)
24+
@Override
25+
public Object handleRequest(Object input, Context context) {
26+
return null;
27+
}
28+
}

Diff for: powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java

+76-43
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,6 @@
1414

1515
package software.amazon.lambda.powertools.logging.internal;
1616

17-
import static java.util.Collections.emptyMap;
18-
import static java.util.Collections.singletonList;
19-
import static java.util.stream.Collectors.joining;
20-
import static org.apache.commons.lang3.reflect.FieldUtils.writeStaticField;
21-
import static org.assertj.core.api.Assertions.assertThat;
22-
import static org.assertj.core.api.Assertions.fail;
23-
import static org.mockito.Mockito.mockStatic;
24-
import static org.mockito.Mockito.when;
25-
import static org.mockito.MockitoAnnotations.openMocks;
26-
import static org.skyscreamer.jsonassert.JSONAssert.assertEquals;
27-
import static software.amazon.lambda.powertools.core.internal.SystemWrapper.getProperty;
28-
import static software.amazon.lambda.powertools.core.internal.SystemWrapper.getenv;
29-
3017
import com.amazonaws.services.lambda.runtime.Context;
3118
import com.amazonaws.services.lambda.runtime.RequestHandler;
3219
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
@@ -37,43 +24,44 @@
3724
import com.amazonaws.services.lambda.runtime.tests.annotations.Event;
3825
import com.fasterxml.jackson.core.JsonProcessingException;
3926
import com.fasterxml.jackson.databind.ObjectMapper;
40-
import java.io.BufferedReader;
41-
import java.io.ByteArrayInputStream;
42-
import java.io.ByteArrayOutputStream;
43-
import java.io.IOException;
44-
import java.io.InputStreamReader;
45-
import java.lang.reflect.InvocationTargetException;
46-
import java.lang.reflect.Method;
47-
import java.nio.channels.FileChannel;
48-
import java.nio.charset.StandardCharsets;
49-
import java.nio.file.Files;
50-
import java.nio.file.Paths;
51-
import java.nio.file.StandardOpenOption;
52-
import java.util.List;
53-
import java.util.Map;
54-
import java.util.stream.Collectors;
5527
import org.apache.logging.log4j.Level;
5628
import org.apache.logging.log4j.ThreadContext;
5729
import org.json.JSONException;
30+
import org.junit.jupiter.api.Assertions;
5831
import org.junit.jupiter.api.BeforeEach;
5932
import org.junit.jupiter.api.Test;
6033
import org.junit.jupiter.params.ParameterizedTest;
6134
import org.mockito.Mock;
6235
import org.mockito.MockedStatic;
6336
import software.amazon.lambda.powertools.core.internal.LambdaHandlerProcessor;
6437
import software.amazon.lambda.powertools.core.internal.SystemWrapper;
65-
import software.amazon.lambda.powertools.logging.handlers.PowerLogToolApiGatewayHttpApiCorrelationId;
66-
import software.amazon.lambda.powertools.logging.handlers.PowerLogToolApiGatewayRestApiCorrelationId;
67-
import software.amazon.lambda.powertools.logging.handlers.PowerLogToolEnabled;
68-
import software.amazon.lambda.powertools.logging.handlers.PowerLogToolEnabledForStream;
69-
import software.amazon.lambda.powertools.logging.handlers.PowerToolDisabled;
70-
import software.amazon.lambda.powertools.logging.handlers.PowerToolDisabledForStream;
71-
import software.amazon.lambda.powertools.logging.handlers.PowerToolLogEventEnabled;
72-
import software.amazon.lambda.powertools.logging.handlers.PowerToolLogEventEnabledForStream;
73-
import software.amazon.lambda.powertools.logging.handlers.PowerToolLogEventEnabledWithCustomMapper;
74-
import software.amazon.lambda.powertools.logging.handlers.PowertoolsLogAlbCorrelationId;
75-
import software.amazon.lambda.powertools.logging.handlers.PowertoolsLogEnabledWithClearState;
76-
import software.amazon.lambda.powertools.logging.handlers.PowertoolsLogEventBridgeCorrelationId;
38+
import software.amazon.lambda.powertools.logging.handlers.*;
39+
40+
import java.io.*;
41+
import java.lang.reflect.InvocationTargetException;
42+
import java.lang.reflect.Method;
43+
import java.nio.channels.FileChannel;
44+
import java.nio.charset.StandardCharsets;
45+
import java.nio.file.Files;
46+
import java.nio.file.Paths;
47+
import java.nio.file.StandardOpenOption;
48+
import java.util.List;
49+
import java.util.Map;
50+
import java.util.stream.Collectors;
51+
52+
import static java.util.Collections.emptyMap;
53+
import static java.util.Collections.singletonList;
54+
import static java.util.stream.Collectors.joining;
55+
import static org.apache.commons.lang3.reflect.FieldUtils.writeStaticField;
56+
import static org.assertj.core.api.Assertions.assertThat;
57+
import static org.assertj.core.api.Assertions.fail;
58+
import static org.junit.jupiter.api.Assertions.assertTrue;
59+
import static org.mockito.Mockito.mockStatic;
60+
import static org.mockito.Mockito.when;
61+
import static org.mockito.MockitoAnnotations.openMocks;
62+
import static org.skyscreamer.jsonassert.JSONAssert.assertEquals;
63+
import static software.amazon.lambda.powertools.core.internal.SystemWrapper.getProperty;
64+
import static software.amazon.lambda.powertools.core.internal.SystemWrapper.getenv;
7765

7866
class LambdaLoggingAspectTest {
7967

@@ -116,7 +104,7 @@ void shouldSetLambdaContextWhenEnabled() {
116104
void shouldSetLambdaContextForStreamHandlerWhenEnabled() throws IOException {
117105
requestStreamHandler = new PowerLogToolEnabledForStream();
118106

119-
requestStreamHandler.handleRequest(new ByteArrayInputStream(new byte[] {}), new ByteArrayOutputStream(),
107+
requestStreamHandler.handleRequest(new ByteArrayInputStream(new byte[]{}), new ByteArrayOutputStream(),
120108
context);
121109

122110
assertThat(ThreadContext.getImmutableContext())
@@ -132,14 +120,14 @@ void shouldSetLambdaContextForStreamHandlerWhenEnabled() throws IOException {
132120

133121
@Test
134122
void shouldSetColdStartFlag() throws IOException {
135-
requestStreamHandler.handleRequest(new ByteArrayInputStream(new byte[] {}), new ByteArrayOutputStream(),
123+
requestStreamHandler.handleRequest(new ByteArrayInputStream(new byte[]{}), new ByteArrayOutputStream(),
136124
context);
137125

138126
assertThat(ThreadContext.getImmutableContext())
139127
.hasSize(EXPECTED_CONTEXT_SIZE)
140128
.containsEntry("coldStart", "true");
141129

142-
requestStreamHandler.handleRequest(new ByteArrayInputStream(new byte[] {}), new ByteArrayOutputStream(),
130+
requestStreamHandler.handleRequest(new ByteArrayInputStream(new byte[]{}), new ByteArrayOutputStream(),
143131
context);
144132

145133
assertThat(ThreadContext.getImmutableContext())
@@ -195,6 +183,51 @@ void shouldLogEventForHandler() throws IOException, JSONException {
195183
assertEquals(expectEvent, event, false);
196184
}
197185

186+
/**
187+
* If POWERTOOLS_LOGGER_LOG_EVENT was set to true, the handler should log, despite @Logging(logEvent=false)
188+
*
189+
* @throws IOException
190+
*/
191+
@Test
192+
void shouldLogEventForHandlerWhenEnvVariableSetToTrue() throws IOException, IllegalAccessException, JSONException {
193+
try {
194+
writeStaticField(LambdaLoggingAspect.class, "LOG_EVENT", Boolean.TRUE, true);
195+
196+
requestHandler = new PowerToolLogEventDisabled();
197+
S3EventNotification s3EventNotification = s3EventNotification();
198+
199+
requestHandler.handleRequest(s3EventNotification, context);
200+
201+
Map<String, Object> log = parseToMap(Files.lines(Paths.get("target/logfile.json")).collect(joining()));
202+
203+
String event = (String) log.get("message");
204+
205+
String expectEvent = new BufferedReader(
206+
new InputStreamReader(this.getClass().getResourceAsStream("/s3EventNotification.json")))
207+
.lines().collect(joining("\n"));
208+
209+
assertEquals(expectEvent, event, false);
210+
} finally {
211+
writeStaticField(LambdaLoggingAspect.class, "LOG_EVENT", Boolean.FALSE, true);
212+
}
213+
}
214+
215+
/**
216+
* If POWERTOOLS_LOGGER_LOG_EVENT was set to false and @Logging(logEvent=false), the handler shouldn't log
217+
*
218+
* @throws IOException
219+
*/
220+
@Test
221+
void shouldNotLogEventForHandlerWhenEnvVariableSetToFalse() throws IOException {
222+
requestHandler = new PowerToolLogEventDisabled();
223+
S3EventNotification s3EventNotification = s3EventNotification();
224+
225+
requestHandler.handleRequest(s3EventNotification, context);
226+
227+
Assertions.assertEquals(0,
228+
Files.lines(Paths.get("target/logfile.json")).collect(joining()).length());
229+
}
230+
198231
@Test
199232
void shouldLogEventForHandlerWithOverriddenObjectMapper() throws IOException, JSONException {
200233
RequestHandler<S3EventNotification, Object> handler = new PowerToolLogEventEnabledWithCustomMapper();

0 commit comments

Comments
 (0)