Skip to content

Commit 61153ad

Browse files
committed
log4j2 implementation of the logging module
1 parent 7af12b0 commit 61153ad

File tree

8 files changed

+539
-10
lines changed

8 files changed

+539
-10
lines changed

powertools-logging-log4j/pom.xml

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<artifactId>powertools-parent</artifactId>
9+
<groupId>software.amazon.lambda</groupId>
10+
<version>1.12.3</version>
11+
</parent>
12+
13+
<artifactId>powertools-logging-log4j</artifactId>
14+
<packaging>jar</packaging>
15+
16+
<name>AWS Lambda Powertools for Java library Logging with Log4j2</name>
17+
<description>
18+
A suite of utilities for AWS Lambda Functions that makes tracing with AWS X-Ray, structured logging and creating custom metrics asynchronously easier.
19+
</description>
20+
<url>https://aws.amazon.com/lambda/</url>
21+
<issueManagement>
22+
<system>GitHub Issues</system>
23+
<url>https://github.com/awslabs/aws-lambda-powertools-java/issues</url>
24+
</issueManagement>
25+
<scm>
26+
<url>https://github.com/awslabs/aws-lambda-powertools-java.git</url>
27+
</scm>
28+
<developers>
29+
<developer>
30+
<name>AWS Lambda Powertools team</name>
31+
<organization>Amazon Web Services</organization>
32+
<organizationUrl>https://aws.amazon.com/</organizationUrl>
33+
</developer>
34+
</developers>
35+
36+
<distributionManagement>
37+
<snapshotRepository>
38+
<id>ossrh</id>
39+
<url>https://aws.oss.sonatype.org/content/repositories/snapshots</url>
40+
</snapshotRepository>
41+
</distributionManagement>
42+
43+
<dependencies>
44+
<dependency>
45+
<groupId>software.amazon.lambda</groupId>
46+
<artifactId>powertools-logging</artifactId>
47+
<version>${version}</version>
48+
</dependency>
49+
<dependency>
50+
<groupId>org.apache.logging.log4j</groupId>
51+
<artifactId>log4j-slf4j2-impl</artifactId>
52+
<scope>provided</scope>
53+
</dependency>
54+
<dependency>
55+
<groupId>org.apache.logging.log4j</groupId>
56+
<artifactId>log4j-core</artifactId>
57+
<scope>provided</scope>
58+
</dependency>
59+
<dependency>
60+
<groupId>org.apache.logging.log4j</groupId>
61+
<artifactId>log4j-layout-template-json</artifactId>
62+
<scope>provided</scope>
63+
</dependency>
64+
65+
<!-- Test dependencies -->
66+
<dependency>
67+
<groupId>org.junit.jupiter</groupId>
68+
<artifactId>junit-jupiter-api</artifactId>
69+
<scope>test</scope>
70+
</dependency>
71+
<dependency>
72+
<groupId>org.junit.jupiter</groupId>
73+
<artifactId>junit-jupiter-engine</artifactId>
74+
<scope>test</scope>
75+
</dependency>
76+
<dependency>
77+
<groupId>org.apache.commons</groupId>
78+
<artifactId>commons-lang3</artifactId>
79+
<scope>test</scope>
80+
</dependency>
81+
<dependency>
82+
<groupId>org.mockito</groupId>
83+
<artifactId>mockito-core</artifactId>
84+
<scope>test</scope>
85+
</dependency>
86+
<dependency>
87+
<groupId>org.mockito</groupId>
88+
<artifactId>mockito-inline</artifactId>
89+
<scope>test</scope>
90+
</dependency>
91+
<dependency>
92+
<groupId>org.aspectj</groupId>
93+
<artifactId>aspectjweaver</artifactId>
94+
<scope>test</scope>
95+
</dependency>
96+
<dependency>
97+
<groupId>org.assertj</groupId>
98+
<artifactId>assertj-core</artifactId>
99+
<scope>test</scope>
100+
</dependency>
101+
<dependency>
102+
<groupId>com.amazonaws</groupId>
103+
<artifactId>aws-lambda-java-events</artifactId>
104+
<scope>test</scope>
105+
</dependency>
106+
<dependency>
107+
<groupId>com.amazonaws</groupId>
108+
<artifactId>aws-lambda-java-tests</artifactId>
109+
<scope>test</scope>
110+
</dependency>
111+
<dependency>
112+
<groupId>org.skyscreamer</groupId>
113+
<artifactId>jsonassert</artifactId>
114+
<scope>test</scope>
115+
</dependency>
116+
</dependencies>
117+
118+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package software.amazon.lambda.powertools.logging.internal;
2+
3+
import org.apache.logging.log4j.Level;
4+
import org.apache.logging.log4j.LogManager;
5+
import org.apache.logging.log4j.core.LoggerContext;
6+
import org.apache.logging.log4j.core.config.Configurator;
7+
import org.slf4j.Logger;
8+
9+
public class Log4jLoggingManager implements LoggingManager {
10+
11+
@Override
12+
public void resetLogLevel(org.slf4j.event.Level logLevel) {
13+
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
14+
Configurator.setAllLevels(LogManager.getRootLogger().getName(), Level.getLevel(logLevel.toString()));
15+
ctx.updateLoggers();
16+
}
17+
18+
@Override
19+
public org.slf4j.event.Level getLogLevel(Logger logger) {
20+
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
21+
return org.slf4j.event.Level.valueOf(ctx.getLogger(logger.getName()).getLevel().toString());
22+
}
23+
24+
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
package software.amazon.lambda.powertools.logging.internal;
2+
3+
import org.apache.logging.log4j.core.LogEvent;
4+
import org.apache.logging.log4j.layout.template.json.resolver.EventResolver;
5+
import org.apache.logging.log4j.layout.template.json.resolver.TemplateResolverConfig;
6+
import org.apache.logging.log4j.layout.template.json.util.JsonWriter;
7+
import org.apache.logging.log4j.util.ReadOnlyStringMap;
8+
9+
final class PowertoolsResolver implements EventResolver {
10+
11+
private static final EventResolver COLD_START_RESOLVER = new EventResolver() {
12+
@Override
13+
public boolean isResolvable(LogEvent logEvent) {
14+
final String coldStart = logEvent.getContextData().getValue(PowertoolsLoggedFields.FUNCTION_COLD_START.getName());
15+
return null != coldStart;
16+
}
17+
18+
@Override
19+
public void resolve(LogEvent logEvent, JsonWriter jsonWriter) {
20+
final String coldStart = logEvent.getContextData().getValue(PowertoolsLoggedFields.FUNCTION_COLD_START.getName());
21+
jsonWriter.writeBoolean(Boolean.parseBoolean(coldStart));
22+
}
23+
};
24+
25+
private static final EventResolver FUNCTION_NAME_RESOLVER =
26+
(final LogEvent logEvent, final JsonWriter jsonWriter) -> {
27+
final String functionName = logEvent.getContextData().getValue(PowertoolsLoggedFields.FUNCTION_NAME.getName());
28+
jsonWriter.writeString(functionName);
29+
};
30+
31+
private static final EventResolver FUNCTION_VERSION_RESOLVER =
32+
(final LogEvent logEvent, final JsonWriter jsonWriter) -> {
33+
final String functionVersion = logEvent.getContextData().getValue(PowertoolsLoggedFields.FUNCTION_VERSION.getName());
34+
jsonWriter.writeString(functionVersion);
35+
};
36+
37+
private static final EventResolver FUNCTION_ARN_RESOLVER =
38+
(final LogEvent logEvent, final JsonWriter jsonWriter) -> {
39+
final String functionArn = logEvent.getContextData().getValue(PowertoolsLoggedFields.FUNCTION_ARN.getName());
40+
jsonWriter.writeString(functionArn);
41+
};
42+
43+
private static final EventResolver FUNCTION_REQ_RESOLVER =
44+
(final LogEvent logEvent, final JsonWriter jsonWriter) -> {
45+
final String functionRequestId = logEvent.getContextData().getValue(PowertoolsLoggedFields.FUNCTION_REQUEST_ID.getName());
46+
jsonWriter.writeString(functionRequestId);
47+
};
48+
49+
private static final EventResolver FUNCTION_MEMORY_RESOLVER = new EventResolver() {
50+
@Override
51+
public boolean isResolvable(LogEvent logEvent) {
52+
final String functionMemory = logEvent.getContextData().getValue(PowertoolsLoggedFields.FUNCTION_MEMORY_SIZE.getName());
53+
return null != functionMemory;
54+
}
55+
56+
@Override
57+
public void resolve(LogEvent logEvent, JsonWriter jsonWriter) {
58+
final String functionMemory = logEvent.getContextData().getValue(PowertoolsLoggedFields.FUNCTION_MEMORY_SIZE.getName());
59+
jsonWriter.writeNumber(Integer.parseInt(functionMemory));
60+
}
61+
};
62+
63+
private static final EventResolver SAMPLING_RATE_RESOLVER = new EventResolver() {
64+
@Override
65+
public boolean isResolvable(LogEvent logEvent) {
66+
final String samplingRate = logEvent.getContextData().getValue(PowertoolsLoggedFields.SAMPLING_RATE.getName());
67+
return null != samplingRate;
68+
}
69+
70+
@Override
71+
public void resolve(LogEvent logEvent, JsonWriter jsonWriter) {
72+
final String samplingRate = logEvent.getContextData().getValue(PowertoolsLoggedFields.SAMPLING_RATE.getName());
73+
jsonWriter.writeNumber(Float.parseFloat(samplingRate));
74+
}
75+
};
76+
77+
private static final EventResolver XRAY_TRACE_RESOLVER =
78+
(final LogEvent logEvent, final JsonWriter jsonWriter) -> {
79+
final String traceId = logEvent.getContextData().getValue(PowertoolsLoggedFields.FUNCTION_TRACE_ID.getName());
80+
jsonWriter.writeString(traceId);
81+
};
82+
83+
private static final EventResolver SERVICE_RESOLVER =
84+
(final LogEvent logEvent, final JsonWriter jsonWriter) -> {
85+
final String service = logEvent.getContextData().getValue(PowertoolsLoggedFields.SERVICE.getName());
86+
jsonWriter.writeString(service);
87+
};
88+
89+
private static final EventResolver REGION_RESOLVER =
90+
(final LogEvent logEvent, final JsonWriter jsonWriter) ->
91+
jsonWriter.writeString(System.getenv("AWS_REGION"));
92+
93+
private static final EventResolver ACCOUNT_ID_RESOLVER = new EventResolver() {
94+
@Override
95+
public boolean isResolvable(LogEvent logEvent) {
96+
final String arn = logEvent.getContextData().getValue(PowertoolsLoggedFields.FUNCTION_ARN.getName());
97+
return null != arn && !arn.isEmpty();
98+
}
99+
100+
@Override
101+
public void resolve(LogEvent logEvent, JsonWriter jsonWriter) {
102+
final String arn = logEvent.getContextData().getValue(PowertoolsLoggedFields.FUNCTION_ARN.getName());
103+
jsonWriter.writeString(arn.split(":")[4]);
104+
}
105+
};
106+
107+
private static final EventResolver NON_POWERTOOLS_FIELD_RESOLVER =
108+
(LogEvent logEvent, JsonWriter jsonWriter) -> {
109+
StringBuilder stringBuilder = jsonWriter.getStringBuilder();
110+
// remove dummy field to kick inn powertools resolver
111+
stringBuilder.setLength(stringBuilder.length() - 4);
112+
113+
// Inject all the context information.
114+
ReadOnlyStringMap contextData = logEvent.getContextData();
115+
contextData.forEach((key, value) -> {
116+
if (!PowertoolsLoggedFields.stringValues().contains(key)) {
117+
jsonWriter.writeSeparator();
118+
jsonWriter.writeString(key);
119+
stringBuilder.append(':');
120+
jsonWriter.writeValue(value);
121+
}
122+
});
123+
};
124+
125+
private final EventResolver internalResolver;
126+
127+
PowertoolsResolver(final TemplateResolverConfig config) {
128+
final String fieldName = config.getString("field");
129+
if (fieldName == null) {
130+
internalResolver = NON_POWERTOOLS_FIELD_RESOLVER;
131+
} else {
132+
switch (fieldName) {
133+
case "service":
134+
internalResolver = SERVICE_RESOLVER;
135+
break;
136+
case "function_name":
137+
internalResolver = FUNCTION_NAME_RESOLVER;
138+
break;
139+
case "function_version":
140+
case "service_version":
141+
internalResolver = FUNCTION_VERSION_RESOLVER;
142+
break;
143+
case "function_arn":
144+
internalResolver = FUNCTION_ARN_RESOLVER;
145+
break;
146+
case "function_memory_size":
147+
internalResolver = FUNCTION_MEMORY_RESOLVER;
148+
break;
149+
case "function_request_id":
150+
internalResolver = FUNCTION_REQ_RESOLVER;
151+
break;
152+
case "cold_start":
153+
internalResolver = COLD_START_RESOLVER;
154+
break;
155+
case "xray_trace_id":
156+
internalResolver = XRAY_TRACE_RESOLVER;
157+
break;
158+
case "region":
159+
internalResolver = REGION_RESOLVER;
160+
break;
161+
case "account_id":
162+
internalResolver = ACCOUNT_ID_RESOLVER;
163+
break;
164+
case "sampling_rate":
165+
internalResolver = SAMPLING_RATE_RESOLVER;
166+
break;
167+
default:
168+
throw new IllegalArgumentException("unknown field: " + fieldName);
169+
}
170+
}
171+
}
172+
173+
static String getName() {
174+
return "powertools";
175+
}
176+
177+
@Override
178+
public void resolve(LogEvent value, JsonWriter jsonWriter) {
179+
internalResolver.resolve(value, jsonWriter);
180+
}
181+
182+
@Override
183+
public boolean isResolvable(LogEvent value) {
184+
ReadOnlyStringMap contextData = value.getContextData();
185+
return null != contextData && !contextData.isEmpty() && internalResolver.isResolvable();
186+
}
187+
}
Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@
33
import org.apache.logging.log4j.core.LogEvent;
44
import org.apache.logging.log4j.core.config.plugins.Plugin;
55
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
6-
import org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext;
7-
import org.apache.logging.log4j.layout.template.json.resolver.EventResolverFactory;
8-
import org.apache.logging.log4j.layout.template.json.resolver.TemplateResolver;
9-
import org.apache.logging.log4j.layout.template.json.resolver.TemplateResolverConfig;
10-
import org.apache.logging.log4j.layout.template.json.resolver.TemplateResolverFactory;
6+
import org.apache.logging.log4j.layout.template.json.resolver.*;
117

128
@Plugin(name = "PowertoolsResolverFactory", category = TemplateResolverFactory.CATEGORY)
139
public final class PowertoolsResolverFactory implements EventResolverFactory {
@@ -29,6 +25,6 @@ public String getName() {
2925
@Override
3026
public TemplateResolver<LogEvent> create(EventResolverContext context,
3127
TemplateResolverConfig config) {
32-
return new PowertoolsResolver();
28+
return new PowertoolsResolver(config);
3329
}
3430
}

0 commit comments

Comments
 (0)