Skip to content

Commit f8c0dc1

Browse files
Merge branch 'master' into feat-metric-utility-method
2 parents 10d7ff8 + 67e8b78 commit f8c0dc1

File tree

7 files changed

+138
-5
lines changed

7 files changed

+138
-5
lines changed

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ private LambdaHandlerProcessor() {
3737
}
3838

3939
public static boolean isHandlerMethod(final ProceedingJoinPoint pjp) {
40-
return "handleRequest".equals(pjp.getSignature().getName());
40+
return "handleRequest".equals(pjp.getSignature().getName()) ||
41+
// https://docs.aws.amazon.com/codeguru/latest/profiler-ug/lambda-custom.html
42+
"requestHandler".equals(pjp.getSignature().getName());
4143
}
4244

4345
public static boolean placedOnRequestHandler(final ProceedingJoinPoint pjp) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package software.amazon.lambda.powertools.core.internal;
2+
3+
import org.aspectj.lang.ProceedingJoinPoint;
4+
import org.aspectj.lang.Signature;
5+
import org.junit.jupiter.api.Test;
6+
7+
import static org.assertj.core.api.Assertions.assertThat;
8+
import static org.mockito.Mockito.mock;
9+
import static org.mockito.Mockito.when;
10+
11+
class LambdaHandlerProcessorTest {
12+
13+
@Test
14+
void shouldTreatProfilerHandlerMethodAsValid() {
15+
ProceedingJoinPoint pjpMock = mock(ProceedingJoinPoint.class);
16+
Signature signature = mock(Signature.class);
17+
when(signature.getName()).thenReturn("requestHandler");
18+
when(pjpMock.getSignature()).thenReturn(signature);
19+
20+
assertThat(LambdaHandlerProcessor.isHandlerMethod(pjpMock))
21+
.isTrue();
22+
}
23+
24+
@Test
25+
void shouldTreatDefaultHandlerMethodAsValid() {
26+
ProceedingJoinPoint pjpMock = mock(ProceedingJoinPoint.class);
27+
Signature signature = mock(Signature.class);
28+
when(signature.getName()).thenReturn("handleRequest");
29+
when(pjpMock.getSignature()).thenReturn(signature);
30+
31+
assertThat(LambdaHandlerProcessor.isHandlerMethod(pjpMock))
32+
.isTrue();
33+
}
34+
35+
@Test
36+
void shouldNotTreatOtherMethodNamesAsValidHandlerMethod() {
37+
ProceedingJoinPoint pjpMock = mock(ProceedingJoinPoint.class);
38+
Signature signature = mock(Signature.class);
39+
when(signature.getName()).thenReturn("handleRequestInvalid");
40+
when(pjpMock.getSignature()).thenReturn(signature);
41+
42+
assertThat(LambdaHandlerProcessor.isHandlerMethod(pjpMock))
43+
.isFalse();
44+
}
45+
}

powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java

+16
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import java.util.Map;
1717

18+
import com.fasterxml.jackson.databind.ObjectMapper;
1819
import org.apache.logging.log4j.ThreadContext;
1920

2021
/**
@@ -23,6 +24,7 @@
2324
* {@see Logging}
2425
*/
2526
public final class LoggingUtils {
27+
private static ObjectMapper objectMapper = new ObjectMapper();
2628

2729
private LoggingUtils() {
2830
}
@@ -48,4 +50,18 @@ public static void appendKey(String key, String value) {
4850
public static void appendKeys(Map<String, String> customKeys) {
4951
ThreadContext.putAll(customKeys);
5052
}
53+
54+
/**
55+
* Sets the instance of ObjectMapper object which is used for serialising event when
56+
* {@code @Logging(logEvent = true)}.
57+
*
58+
* @param objectMapper Custom implementation of object mapper to be used for logging serialised event
59+
*/
60+
public static void defaultObjectMapper(ObjectMapper objectMapper) {
61+
LoggingUtils.objectMapper = objectMapper;
62+
}
63+
64+
public static ObjectMapper objectMapper() {
65+
return objectMapper;
66+
}
5167
}

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import java.util.Random;
2525

2626
import com.fasterxml.jackson.core.JsonProcessingException;
27-
import com.fasterxml.jackson.databind.ObjectMapper;
2827
import org.apache.logging.log4j.Level;
2928
import org.apache.logging.log4j.LogManager;
3029
import org.apache.logging.log4j.Logger;
@@ -50,11 +49,12 @@
5049
import static software.amazon.lambda.powertools.core.internal.LambdaHandlerProcessor.serviceName;
5150
import static software.amazon.lambda.powertools.logging.LoggingUtils.appendKey;
5251
import static software.amazon.lambda.powertools.logging.LoggingUtils.appendKeys;
52+
import static software.amazon.lambda.powertools.logging.LoggingUtils.objectMapper;
53+
import static software.amazon.lambda.powertools.logging.internal.SystemWrapper.getenv;
5354

5455
@Aspect
5556
public final class LambdaLoggingAspect {
5657
private static final Logger LOG = LogManager.getLogger(LambdaLoggingAspect.class);
57-
private static final ObjectMapper MAPPER = new ObjectMapper();
5858
private static final Random SAMPLER = new Random();
5959

6060
private static final String LOG_LEVEL = System.getenv("LOG_LEVEL");
@@ -175,7 +175,7 @@ private Object[] logFromInputStream(final ProceedingJoinPoint pjp) {
175175

176176
Logger log = logger(pjp);
177177

178-
asJson(pjp, MAPPER.readValue(bytes, Map.class))
178+
asJson(pjp, objectMapper().readValue(bytes, Map.class))
179179
.ifPresent(log::info);
180180

181181
} catch (IOException e) {
@@ -189,7 +189,7 @@ private Object[] logFromInputStream(final ProceedingJoinPoint pjp) {
189189
private Optional<String> asJson(final ProceedingJoinPoint pjp,
190190
final Object target) {
191191
try {
192-
return ofNullable(MAPPER.writeValueAsString(target));
192+
return ofNullable(objectMapper().writeValueAsString(target));
193193
} catch (JsonProcessingException e) {
194194
logger(pjp).error("Failed logging event of type {}", target.getClass(), e);
195195
return empty();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package software.amazon.lambda.powertools.logging.handlers;
2+
3+
import java.io.IOException;
4+
5+
import com.amazonaws.services.lambda.runtime.Context;
6+
import com.amazonaws.services.lambda.runtime.RequestHandler;
7+
import com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification;
8+
import com.fasterxml.jackson.core.JsonGenerator;
9+
import com.fasterxml.jackson.databind.ObjectMapper;
10+
import com.fasterxml.jackson.databind.SerializerProvider;
11+
import com.fasterxml.jackson.databind.module.SimpleModule;
12+
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
13+
import software.amazon.lambda.powertools.logging.Logging;
14+
import software.amazon.lambda.powertools.logging.LoggingUtils;
15+
16+
public class PowerToolLogEventEnabledWithCustomMapper implements RequestHandler<S3EventNotification, Object> {
17+
18+
static {
19+
ObjectMapper objectMapper = new ObjectMapper();
20+
SimpleModule module = new SimpleModule();
21+
module.addSerializer(S3EventNotification.class, new S3EventNotificationSerializer());
22+
objectMapper.registerModule(module);
23+
LoggingUtils.defaultObjectMapper(objectMapper);
24+
}
25+
26+
@Logging(logEvent = true)
27+
@Override
28+
public Object handleRequest(S3EventNotification input, Context context) {
29+
return null;
30+
}
31+
32+
static class S3EventNotificationSerializer extends StdSerializer<S3EventNotification> {
33+
34+
public S3EventNotificationSerializer() {
35+
this(null);
36+
}
37+
38+
public S3EventNotificationSerializer(Class<S3EventNotification> t) {
39+
super(t);
40+
}
41+
42+
@Override
43+
public void serialize(S3EventNotification o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
44+
jsonGenerator.writeStartObject();
45+
jsonGenerator.writeStringField("eventSource", o.getRecords().get(0).getEventSource());
46+
jsonGenerator.writeEndObject();
47+
}
48+
}
49+
}

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

+18
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import software.amazon.lambda.powertools.logging.handlers.PowerToolDisabledForStream;
4949
import software.amazon.lambda.powertools.logging.handlers.PowerToolLogEventEnabled;
5050
import software.amazon.lambda.powertools.logging.handlers.PowerToolLogEventEnabledForStream;
51+
import software.amazon.lambda.powertools.logging.handlers.PowerToolLogEventEnabledWithCustomMapper;
5152

5253
import static com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.RequestParametersEntity;
5354
import static com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.ResponseElementsEntity;
@@ -184,6 +185,23 @@ void shouldLogEventForHandler() throws IOException, JSONException {
184185
assertEquals(expectEvent, event, false);
185186
}
186187

188+
@Test
189+
void shouldLogEventForHandlerWithOverriddenObjectMapper() throws IOException, JSONException {
190+
RequestHandler<S3EventNotification, Object> handler = new PowerToolLogEventEnabledWithCustomMapper();
191+
S3EventNotification s3EventNotification = s3EventNotification();
192+
193+
handler.handleRequest(s3EventNotification, context);
194+
195+
Map<String, Object> log = parseToMap(Files.lines(Paths.get("target/logfile.json")).collect(joining()));
196+
197+
String event = (String) log.get("message");
198+
199+
String expectEvent = new BufferedReader(new InputStreamReader(this.getClass().getResourceAsStream("/customizedLogEvent.json")))
200+
.lines().collect(joining("\n"));
201+
202+
assertEquals(expectEvent, event, false);
203+
}
204+
187205
@Test
188206
void shouldLogEventForStreamAndLambdaStreamIsValid() throws IOException, JSONException {
189207
requestStreamHandler = new PowerToolLogEventEnabledForStream();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"eventSource": "aws:s3"
3+
}

0 commit comments

Comments
 (0)