Skip to content

Commit 5a94e19

Browse files
authored
[alc] Log4j2 support (#37) (#454)
* [alc] Log4j2 support * [log4j2] bump aws-lambda-java-core deps to 1.2.3 * [log4j2] version bump and doc updates --------- Co-authored-by: Daniel Torok <[email protected]>
1 parent 04b6e96 commit 5a94e19

File tree

8 files changed

+169
-19
lines changed

8 files changed

+169
-19
lines changed

README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Example request handler
2121
public class Handler implements RequestHandler<Map<String, String>, String>{
2222
@Override
2323
public String handleRequest(Map<String, String> event, Context context) {
24-
24+
2525
}
2626
}
2727
```
@@ -32,7 +32,7 @@ Example request stream handler
3232
public class HandlerStream implements RequestStreamHandler {
3333
@Override
3434
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
35-
35+
3636
}
3737
}
3838
```
@@ -101,7 +101,7 @@ public void testInjectSQSEvent(SQSEvent event) {
101101
## aws-lambda-java-events-sdk-transformer
102102

103103
This package provides helper classes/methods to use alongside `aws-lambda-java-events` in order to transform
104-
Lambda input event model objects into SDK-compatible output model objects.
104+
Lambda input event model objects into SDK-compatible output model objects.
105105
See the [documentation](aws-lambda-java-events-sdk-transformer/README.md) for more information.
106106

107107
- [Release Notes](aws-lambda-java-events-sdk-transformer/RELEASE.CHANGELOG.md)
@@ -125,7 +125,7 @@ See the [README](aws-lambda-java-log4j2/README.md) or the [official documentatio
125125
<dependency>
126126
<groupId>com.amazonaws</groupId>
127127
<artifactId>aws-lambda-java-log4j2</artifactId>
128-
<version>1.5.1</version>
128+
<version>1.6.0</version>
129129
</dependency>
130130
```
131131

aws-lambda-java-log4j2/README.md

+16-9
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Example for Maven pom.xml
1010
<dependency>
1111
<groupId>com.amazonaws</groupId>
1212
<artifactId>aws-lambda-java-log4j2</artifactId>
13-
<version>1.5.1</version>
13+
<version>1.6.0</version>
1414
</dependency>
1515
<dependency>
1616
<groupId>org.apache.logging.log4j</groupId>
@@ -65,10 +65,10 @@ If using maven shade plugin, set the plugin configuration as follows
6565
If you are using the [John Rengelman](https://github.com/johnrengelman/shadow) Gradle shadow plugin, then the plugin configuration is as follows:
6666

6767
```groovy
68-
68+
6969
dependencies{
7070
...
71-
implementation group: 'com.amazonaws', name: 'aws-lambda-java-log4j2', version: '1.5.1'
71+
implementation group: 'com.amazonaws', name: 'aws-lambda-java-log4j2', version: '1.6.0'
7272
implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: log4jVersion
7373
implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: log4jVersion
7474
}
@@ -83,8 +83,8 @@ shadowJar {
8383
build.dependsOn(shadowJar)
8484
8585
```
86-
87-
If you are using the `sam build` and `sam deploy` commands to deploy your lambda function, then you don't
86+
87+
If you are using the `sam build` and `sam deploy` commands to deploy your lambda function, then you don't
8888
need to use the shadow jar plugin. The `sam` cli-tool merges itself the `Log4j2Plugins.dat`
8989
files.
9090

@@ -94,12 +94,17 @@ Add the following file `<project-dir>/src/main/resources/log4j2.xml`
9494

9595
```xml
9696
<?xml version="1.0" encoding="UTF-8"?>
97-
<Configuration packages="com.amazonaws.services.lambda.runtime.log4j2">
97+
<Configuration>
9898
<Appenders>
99-
<Lambda name="Lambda">
100-
<PatternLayout>
99+
<Lambda name="Lambda" format="${env:AWS_LAMBDA_LOG_FORMAT:-TEXT}">
100+
<LambdaTextFormat>
101+
<PatternLayout>
101102
<pattern>%d{yyyy-MM-dd HH:mm:ss} %X{AWSRequestId} %-5p %c{1}:%L - %m%n</pattern>
102-
</PatternLayout>
103+
</PatternLayout>
104+
</LambdaTextFormat>
105+
<LambdaJSONFormat>
106+
<JsonTemplateLayout eventTemplateUri="classpath:LambdaLayout.json" />
107+
</LambdaJSONFormat>
103108
</Lambda>
104109
</Appenders>
105110
<Loggers>
@@ -110,6 +115,8 @@ Add the following file `<project-dir>/src/main/resources/log4j2.xml`
110115
</Configuration>
111116
```
112117

118+
If the `AWS_LAMBDA_LOG_FORMAT` is set to `JSON`, the `LambdaJSONFormat` formatter will be applied, otherwise the `LambdaTextFormat`.
119+
113120
### 3. Example code
114121

115122
```java

aws-lambda-java-log4j2/RELEASE.CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
### October 24, 2023
2+
`1.6.0`:
3+
- Log level and log format support
4+
15
### January 04, 2022
26
`1.5.1`:
37
- Updated `log4j-core` and `log4j-api` dependencies to `2.17.1`

aws-lambda-java-log4j2/pom.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
<groupId>com.amazonaws</groupId>
77
<artifactId>aws-lambda-java-log4j2</artifactId>
8-
<version>1.5.1</version>
8+
<version>1.6.0</version>
99
<packaging>jar</packaging>
1010

1111
<name>AWS Lambda Java Log4j 2.x Libraries</name>
@@ -48,7 +48,7 @@
4848
<dependency>
4949
<groupId>com.amazonaws</groupId>
5050
<artifactId>aws-lambda-java-core</artifactId>
51-
<version>1.2.2</version>
51+
<version>1.2.3</version>
5252
</dependency>
5353
<dependency>
5454
<groupId>org.apache.logging.log4j</groupId>

aws-lambda-java-log4j2/src/main/java/com/amazonaws/services/lambda/runtime/log4j2/LambdaAppender.java

+46-4
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,24 @@
22

33
import com.amazonaws.services.lambda.runtime.LambdaRuntime;
44
import com.amazonaws.services.lambda.runtime.LambdaRuntimeInternal;
5+
56
import com.amazonaws.services.lambda.runtime.LambdaLogger;
7+
import com.amazonaws.services.lambda.runtime.logging.LogFormat;
8+
import com.amazonaws.services.lambda.runtime.logging.LogLevel;
69

10+
import org.apache.logging.log4j.Level;
711
import org.apache.logging.log4j.core.Filter;
812
import org.apache.logging.log4j.core.Layout;
913
import org.apache.logging.log4j.core.LogEvent;
1014
import org.apache.logging.log4j.core.appender.AbstractAppender;
1115
import org.apache.logging.log4j.core.config.plugins.Plugin;
16+
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
1217
import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
18+
import org.apache.logging.log4j.core.config.plugins.PluginElement;
1319

1420
import java.io.Serializable;
21+
import java.util.HashMap;
22+
import java.util.Map;
1523

1624
/**
1725
* Class to append log4j2 logs from AWS Lambda function to CloudWatch
@@ -20,27 +28,53 @@
2028
@Plugin(name = LambdaAppender.PLUGIN_NAME, category = LambdaAppender.PLUGIN_CATEGORY,
2129
elementType = LambdaAppender.PLUGIN_TYPE, printObject = true)
2230
public class LambdaAppender extends AbstractAppender {
31+
static {
32+
LambdaRuntimeInternal.setUseLog4jAppender(true);
33+
}
2334

2435
public static final String PLUGIN_NAME = "Lambda";
2536
public static final String PLUGIN_CATEGORY = "Core";
2637
public static final String PLUGIN_TYPE = "appender";
2738

2839
private LambdaLogger logger = LambdaRuntime.getLogger();
2940

41+
private static LogFormat logFormat = LogFormat.TEXT;
42+
43+
private static final Map<Level, LogLevel> logLevelMapper = new HashMap<Level, LogLevel>() {{
44+
put(Level.TRACE, LogLevel.TRACE);
45+
put(Level.DEBUG, LogLevel.DEBUG);
46+
put(Level.INFO, LogLevel.INFO);
47+
put(Level.WARN, LogLevel.WARN);
48+
put(Level.ERROR, LogLevel.ERROR);
49+
put(Level.FATAL, LogLevel.FATAL);
50+
}};
51+
3052
/**
3153
* Builder class that follows log4j2 plugin convention
3254
* @param <B> Generic Builder class
3355
*/
3456
public static class Builder<B extends Builder<B>> extends AbstractAppender.Builder<B>
3557
implements org.apache.logging.log4j.core.util.Builder<LambdaAppender> {
3658

59+
@PluginAttribute(value = "format", defaultString = "TEXT")
60+
LogFormat logFormat;
61+
@PluginElement("LambdaTextFormat")
62+
private LambdaTextFormat lambdaTextFormat;
63+
@PluginElement("LambdaJsonFormat")
64+
private LambdaJsonFormat lambdaJsonFormat;
65+
3766
/**
3867
* creates a new LambdaAppender
3968
* @return a new LambdaAppender
4069
*/
4170
public LambdaAppender build() {
42-
return new LambdaAppender(super.getName(), super.getFilter(), super.getOrCreateLayout(),
43-
super.isIgnoreExceptions());
71+
Layout<?> layout;
72+
if (logFormat == LogFormat.TEXT) {
73+
layout = lambdaTextFormat != null ? lambdaTextFormat.getLayout() : super.getOrCreateLayout();
74+
} else {
75+
layout = lambdaJsonFormat != null ? lambdaJsonFormat.getLayout() : super.getOrCreateLayout();
76+
}
77+
return new LambdaAppender(super.getName(), super.getFilter(), layout, super.isIgnoreExceptions());
4478
}
4579
}
4680

@@ -63,14 +97,22 @@ public static <B extends Builder<B>> B newBuilder() {
6397
*/
6498
private LambdaAppender(String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions) {
6599
super(name, filter, layout, ignoreExceptions);
66-
LambdaRuntimeInternal.setUseLog4jAppender(true);
100+
}
101+
102+
/**
103+
* Converts log4j Level into Lambda LogLevel
104+
* @param level the log4j log level
105+
* @return Lambda log leve
106+
*/
107+
private LogLevel toLambdaLogLevel(Level level) {
108+
return logLevelMapper.getOrDefault(level, LogLevel.UNDEFINED);
67109
}
68110

69111
/**
70112
* Append log event to System.out
71113
* @param event log4j event
72114
*/
73115
public void append(LogEvent event) {
74-
logger.log(super.getLayout().toByteArray(event));
116+
logger.log(getLayout().toByteArray(event), toLambdaLogLevel(event.getLevel()));
75117
}
76118
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. */
2+
3+
package com.amazonaws.services.lambda.runtime.log4j2;
4+
5+
import org.apache.logging.log4j.core.Layout;
6+
import org.apache.logging.log4j.core.config.plugins.Plugin;
7+
import org.apache.logging.log4j.core.config.plugins.PluginElement;
8+
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
9+
10+
import java.io.Serializable;
11+
12+
@Plugin(name = "LambdaJsonFormat", category = "core", printObject = true)
13+
public class LambdaJsonFormat {
14+
15+
private Layout layout;
16+
17+
@PluginFactory
18+
public static LambdaJsonFormat createNode(@PluginElement("Layout") Layout<? extends Serializable> layout) {
19+
return new LambdaJsonFormat(layout);
20+
}
21+
22+
private LambdaJsonFormat(Layout layout) {
23+
this.layout = layout;
24+
}
25+
26+
public Layout getLayout() {
27+
return layout;
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. */
2+
3+
package com.amazonaws.services.lambda.runtime.log4j2;
4+
5+
import org.apache.logging.log4j.core.Layout;
6+
import org.apache.logging.log4j.core.config.plugins.Plugin;
7+
import org.apache.logging.log4j.core.config.plugins.PluginElement;
8+
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
9+
10+
import java.io.Serializable;
11+
12+
@Plugin(name = "LambdaTextFormat", category = "core", printObject = true)
13+
public class LambdaTextFormat {
14+
15+
private Layout layout;
16+
17+
@PluginFactory
18+
public static LambdaTextFormat createNode(@PluginElement("Layout") Layout<? extends Serializable> layout) {
19+
return new LambdaTextFormat(layout);
20+
}
21+
22+
private LambdaTextFormat(Layout layout) {
23+
this.layout = layout;
24+
}
25+
26+
public Layout getLayout() {
27+
return layout;
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"timestamp": {
3+
"$resolver": "timestamp",
4+
"pattern": {
5+
"format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
6+
"timeZone": "UTC"
7+
}
8+
},
9+
"level": {
10+
"$resolver": "level",
11+
"field": "name"
12+
},
13+
"message": {
14+
"$resolver": "message"
15+
},
16+
"logger": {
17+
"$resolver": "logger",
18+
"field": "name"
19+
},
20+
21+
"errorType": {
22+
"$resolver": "exception",
23+
"field": "className"
24+
},
25+
"errorMessage": {
26+
"$resolver": "exception",
27+
"field": "message"
28+
},
29+
"stackTrace": {
30+
"$resolver": "exception",
31+
"field": "stackTrace"
32+
},
33+
34+
"labels": {
35+
"$resolver": "mdc",
36+
"flatten": true,
37+
"stringified": true
38+
}
39+
}

0 commit comments

Comments
 (0)