diff --git a/README.md b/README.md index 61bce30e..22cebffe 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Example request handler public class Handler implements RequestHandler, String>{ @Override public String handleRequest(Map event, Context context) { - + } } ``` @@ -32,7 +32,7 @@ Example request stream handler public class HandlerStream implements RequestStreamHandler { @Override public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException { - + } } ``` @@ -101,7 +101,7 @@ public void testInjectSQSEvent(SQSEvent event) { ## aws-lambda-java-events-sdk-transformer This package provides helper classes/methods to use alongside `aws-lambda-java-events` in order to transform -Lambda input event model objects into SDK-compatible output model objects. +Lambda input event model objects into SDK-compatible output model objects. See the [documentation](aws-lambda-java-events-sdk-transformer/README.md) for more information. - [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 com.amazonaws aws-lambda-java-log4j2 - 1.5.1 + 1.6.0 ``` diff --git a/aws-lambda-java-log4j2/README.md b/aws-lambda-java-log4j2/README.md index 3ccb0769..6f792131 100644 --- a/aws-lambda-java-log4j2/README.md +++ b/aws-lambda-java-log4j2/README.md @@ -10,7 +10,7 @@ Example for Maven pom.xml com.amazonaws aws-lambda-java-log4j2 - 1.5.1 + 1.6.0 org.apache.logging.log4j @@ -65,10 +65,10 @@ If using maven shade plugin, set the plugin configuration as follows If you are using the [John Rengelman](https://github.com/johnrengelman/shadow) Gradle shadow plugin, then the plugin configuration is as follows: ```groovy - + dependencies{ ... - implementation group: 'com.amazonaws', name: 'aws-lambda-java-log4j2', version: '1.5.1' + implementation group: 'com.amazonaws', name: 'aws-lambda-java-log4j2', version: '1.6.0' implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: log4jVersion implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: log4jVersion } @@ -83,8 +83,8 @@ shadowJar { build.dependsOn(shadowJar) ``` - -If you are using the `sam build` and `sam deploy` commands to deploy your lambda function, then you don't + +If you are using the `sam build` and `sam deploy` commands to deploy your lambda function, then you don't need to use the shadow jar plugin. The `sam` cli-tool merges itself the `Log4j2Plugins.dat` files. @@ -94,12 +94,17 @@ Add the following file `/src/main/resources/log4j2.xml` ```xml - + - - + + + %d{yyyy-MM-dd HH:mm:ss} %X{AWSRequestId} %-5p %c{1}:%L - %m%n - + + + + + @@ -110,6 +115,8 @@ Add the following file `/src/main/resources/log4j2.xml` ``` +If the `AWS_LAMBDA_LOG_FORMAT` is set to `JSON`, the `LambdaJSONFormat` formatter will be applied, otherwise the `LambdaTextFormat`. + ### 3. Example code ```java diff --git a/aws-lambda-java-log4j2/RELEASE.CHANGELOG.md b/aws-lambda-java-log4j2/RELEASE.CHANGELOG.md index 2277b792..49535d38 100644 --- a/aws-lambda-java-log4j2/RELEASE.CHANGELOG.md +++ b/aws-lambda-java-log4j2/RELEASE.CHANGELOG.md @@ -1,3 +1,7 @@ +### October 24, 2023 +`1.6.0`: +- Log level and log format support + ### January 04, 2022 `1.5.1`: - Updated `log4j-core` and `log4j-api` dependencies to `2.17.1` diff --git a/aws-lambda-java-log4j2/pom.xml b/aws-lambda-java-log4j2/pom.xml index a1ea80e5..b33300ef 100644 --- a/aws-lambda-java-log4j2/pom.xml +++ b/aws-lambda-java-log4j2/pom.xml @@ -5,7 +5,7 @@ com.amazonaws aws-lambda-java-log4j2 - 1.5.1 + 1.6.0 jar AWS Lambda Java Log4j 2.x Libraries @@ -48,7 +48,7 @@ com.amazonaws aws-lambda-java-core - 1.2.2 + 1.2.3 org.apache.logging.log4j diff --git a/aws-lambda-java-log4j2/src/main/java/com/amazonaws/services/lambda/runtime/log4j2/LambdaAppender.java b/aws-lambda-java-log4j2/src/main/java/com/amazonaws/services/lambda/runtime/log4j2/LambdaAppender.java index 5c1dd315..a511c8de 100755 --- a/aws-lambda-java-log4j2/src/main/java/com/amazonaws/services/lambda/runtime/log4j2/LambdaAppender.java +++ b/aws-lambda-java-log4j2/src/main/java/com/amazonaws/services/lambda/runtime/log4j2/LambdaAppender.java @@ -2,16 +2,24 @@ import com.amazonaws.services.lambda.runtime.LambdaRuntime; import com.amazonaws.services.lambda.runtime.LambdaRuntimeInternal; + import com.amazonaws.services.lambda.runtime.LambdaLogger; +import com.amazonaws.services.lambda.runtime.logging.LogFormat; +import com.amazonaws.services.lambda.runtime.logging.LogLevel; +import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.appender.AbstractAppender; import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginAttribute; import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; +import org.apache.logging.log4j.core.config.plugins.PluginElement; import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; /** * Class to append log4j2 logs from AWS Lambda function to CloudWatch @@ -20,6 +28,9 @@ @Plugin(name = LambdaAppender.PLUGIN_NAME, category = LambdaAppender.PLUGIN_CATEGORY, elementType = LambdaAppender.PLUGIN_TYPE, printObject = true) public class LambdaAppender extends AbstractAppender { + static { + LambdaRuntimeInternal.setUseLog4jAppender(true); + } public static final String PLUGIN_NAME = "Lambda"; public static final String PLUGIN_CATEGORY = "Core"; @@ -27,6 +38,17 @@ public class LambdaAppender extends AbstractAppender { private LambdaLogger logger = LambdaRuntime.getLogger(); + private static LogFormat logFormat = LogFormat.TEXT; + + private static final Map logLevelMapper = new HashMap() {{ + put(Level.TRACE, LogLevel.TRACE); + put(Level.DEBUG, LogLevel.DEBUG); + put(Level.INFO, LogLevel.INFO); + put(Level.WARN, LogLevel.WARN); + put(Level.ERROR, LogLevel.ERROR); + put(Level.FATAL, LogLevel.FATAL); + }}; + /** * Builder class that follows log4j2 plugin convention * @param Generic Builder class @@ -34,13 +56,25 @@ public class LambdaAppender extends AbstractAppender { public static class Builder> extends AbstractAppender.Builder implements org.apache.logging.log4j.core.util.Builder { + @PluginAttribute(value = "format", defaultString = "TEXT") + LogFormat logFormat; + @PluginElement("LambdaTextFormat") + private LambdaTextFormat lambdaTextFormat; + @PluginElement("LambdaJsonFormat") + private LambdaJsonFormat lambdaJsonFormat; + /** * creates a new LambdaAppender * @return a new LambdaAppender */ public LambdaAppender build() { - return new LambdaAppender(super.getName(), super.getFilter(), super.getOrCreateLayout(), - super.isIgnoreExceptions()); + Layout layout; + if (logFormat == LogFormat.TEXT) { + layout = lambdaTextFormat != null ? lambdaTextFormat.getLayout() : super.getOrCreateLayout(); + } else { + layout = lambdaJsonFormat != null ? lambdaJsonFormat.getLayout() : super.getOrCreateLayout(); + } + return new LambdaAppender(super.getName(), super.getFilter(), layout, super.isIgnoreExceptions()); } } @@ -63,7 +97,15 @@ public static > B newBuilder() { */ private LambdaAppender(String name, Filter filter, Layout layout, boolean ignoreExceptions) { super(name, filter, layout, ignoreExceptions); - LambdaRuntimeInternal.setUseLog4jAppender(true); + } + + /** + * Converts log4j Level into Lambda LogLevel + * @param level the log4j log level + * @return Lambda log leve + */ + private LogLevel toLambdaLogLevel(Level level) { + return logLevelMapper.getOrDefault(level, LogLevel.UNDEFINED); } /** @@ -71,6 +113,6 @@ private LambdaAppender(String name, Filter filter, Layout layout) { + return new LambdaJsonFormat(layout); + } + + private LambdaJsonFormat(Layout layout) { + this.layout = layout; + } + + public Layout getLayout() { + return layout; + } +} diff --git a/aws-lambda-java-log4j2/src/main/java/com/amazonaws/services/lambda/runtime/log4j2/LambdaTextFormat.java b/aws-lambda-java-log4j2/src/main/java/com/amazonaws/services/lambda/runtime/log4j2/LambdaTextFormat.java new file mode 100644 index 00000000..0bd0304a --- /dev/null +++ b/aws-lambda-java-log4j2/src/main/java/com/amazonaws/services/lambda/runtime/log4j2/LambdaTextFormat.java @@ -0,0 +1,29 @@ +/* Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +package com.amazonaws.services.lambda.runtime.log4j2; + +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginElement; +import org.apache.logging.log4j.core.config.plugins.PluginFactory; + +import java.io.Serializable; + +@Plugin(name = "LambdaTextFormat", category = "core", printObject = true) +public class LambdaTextFormat { + + private Layout layout; + + @PluginFactory + public static LambdaTextFormat createNode(@PluginElement("Layout") Layout layout) { + return new LambdaTextFormat(layout); + } + + private LambdaTextFormat(Layout layout) { + this.layout = layout; + } + + public Layout getLayout() { + return layout; + } +} diff --git a/aws-lambda-java-log4j2/src/main/resources/LambdaLayout.json b/aws-lambda-java-log4j2/src/main/resources/LambdaLayout.json new file mode 100644 index 00000000..975f4b52 --- /dev/null +++ b/aws-lambda-java-log4j2/src/main/resources/LambdaLayout.json @@ -0,0 +1,39 @@ +{ + "timestamp": { + "$resolver": "timestamp", + "pattern": { + "format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", + "timeZone": "UTC" + } + }, + "level": { + "$resolver": "level", + "field": "name" + }, + "message": { + "$resolver": "message" + }, + "logger": { + "$resolver": "logger", + "field": "name" + }, + + "errorType": { + "$resolver": "exception", + "field": "className" + }, + "errorMessage": { + "$resolver": "exception", + "field": "message" + }, + "stackTrace": { + "$resolver": "exception", + "field": "stackTrace" + }, + + "labels": { + "$resolver": "mdc", + "flatten": true, + "stringified": true + } +} \ No newline at end of file