By default {@code Logging} will also create keys for:
*
*
- *
coldStart - True if this is the first invocation of this Lambda execution environment; else False
+ *
cold_start - True if this is the first invocation of this Lambda execution environment; else False
*
service - The value of the 'POWER_TOOLS_SERVICE_NAME' environment variable or 'service_undefined'
- *
samplingRate - The value of the 'POWERTOOLS_LOGGER_SAMPLE_RATE' environment variable or value of samplingRate field or 0.
+ *
sampling_rate - The value of the 'POWERTOOLS_LOGGER_SAMPLE_RATE' environment variable or value of sampling_rate field or 0.
* Valid value is from 0.0 to 1.0. Value outside this range is silently ignored.
*
*
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java
index 6e11573cc..ed57df0fd 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java
@@ -14,11 +14,11 @@
package software.amazon.lambda.powertools.logging;
-import static java.util.Arrays.asList;
-
import com.fasterxml.jackson.databind.ObjectMapper;
+import org.slf4j.MDC;
+
+import java.util.Arrays;
import java.util.Map;
-import org.apache.logging.log4j.ThreadContext;
/**
* A class of helper functions to add additional functionality to Logging.
@@ -39,7 +39,7 @@ private LoggingUtils() {
* @param value The value to be logged
*/
public static void appendKey(String key, String value) {
- ThreadContext.put(key, value);
+ MDC.put(key, value);
}
@@ -50,7 +50,7 @@ public static void appendKey(String key, String value) {
* @param customKeys Map of custom keys values to be appended to logs
*/
public static void appendKeys(Map customKeys) {
- ThreadContext.putAll(customKeys);
+ customKeys.forEach(MDC::put);
}
/**
@@ -59,7 +59,7 @@ public static void appendKeys(Map customKeys) {
* @param customKey The name of the key to be logged
*/
public static void removeKey(String customKey) {
- ThreadContext.remove(customKey);
+ MDC.remove(customKey);
}
@@ -69,7 +69,7 @@ public static void removeKey(String customKey) {
* @param keys Map of custom keys values to be appended to logs
*/
public static void removeKeys(String... keys) {
- ThreadContext.removeAll(asList(keys));
+ Arrays.stream(keys).forEach(MDC::remove);
}
/**
@@ -78,7 +78,7 @@ public static void removeKeys(String... keys) {
* @param value The value of the correlation id
*/
public static void setCorrelationId(String value) {
- ThreadContext.put("correlation_id", value);
+ MDC.put("correlation_id", value);
}
/**
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/AbstractJacksonLayoutCopy.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/AbstractJacksonLayoutCopy.java
deleted file mode 100644
index 17d09729f..000000000
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/AbstractJacksonLayoutCopy.java
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- * Copyright 2023 Amazon.com, Inc. or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package software.amazon.lambda.powertools.logging.internal;
-
-import com.fasterxml.jackson.annotation.JsonAnyGetter;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonRootName;
-import com.fasterxml.jackson.annotation.JsonUnwrapped;
-import com.fasterxml.jackson.core.JsonGenerationException;
-import com.fasterxml.jackson.databind.JsonMappingException;
-import com.fasterxml.jackson.databind.ObjectWriter;
-import java.io.IOException;
-import java.io.Writer;
-import java.nio.charset.Charset;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.Marker;
-import org.apache.logging.log4j.ThreadContext;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.core.config.plugins.PluginElement;
-import org.apache.logging.log4j.core.impl.Log4jLogEvent;
-import org.apache.logging.log4j.core.impl.ThrowableProxy;
-import org.apache.logging.log4j.core.jackson.XmlConstants;
-import org.apache.logging.log4j.core.layout.AbstractStringLayout;
-import org.apache.logging.log4j.core.lookup.StrSubstitutor;
-import org.apache.logging.log4j.core.time.Instant;
-import org.apache.logging.log4j.core.util.KeyValuePair;
-import org.apache.logging.log4j.core.util.StringBuilderWriter;
-import org.apache.logging.log4j.message.Message;
-import org.apache.logging.log4j.util.ReadOnlyStringMap;
-import org.apache.logging.log4j.util.Strings;
-
-@Deprecated
-abstract class AbstractJacksonLayoutCopy extends AbstractStringLayout {
-
- protected static final String DEFAULT_EOL = "\r\n";
- protected static final String COMPACT_EOL = Strings.EMPTY;
- protected final String eol;
- protected final ObjectWriter objectWriter;
- protected final boolean compact;
- protected final boolean complete;
- protected final boolean includeNullDelimiter;
- protected final ResolvableKeyValuePair[] additionalFields;
-
- @Deprecated
- protected AbstractJacksonLayoutCopy(final Configuration config, final ObjectWriter objectWriter,
- final Charset charset,
- final boolean compact, final boolean complete, final boolean eventEol,
- final Serializer headerSerializer,
- final Serializer footerSerializer) {
- this(config, objectWriter, charset, compact, complete, eventEol, headerSerializer, footerSerializer, false);
- }
-
- @Deprecated
- protected AbstractJacksonLayoutCopy(final Configuration config, final ObjectWriter objectWriter,
- final Charset charset,
- final boolean compact, final boolean complete, final boolean eventEol,
- final Serializer headerSerializer,
- final Serializer footerSerializer, final boolean includeNullDelimiter) {
- this(config, objectWriter, charset, compact, complete, eventEol, null, headerSerializer, footerSerializer,
- includeNullDelimiter, null);
- }
-
- protected AbstractJacksonLayoutCopy(final Configuration config, final ObjectWriter objectWriter,
- final Charset charset,
- final boolean compact, final boolean complete, final boolean eventEol,
- final String endOfLine, final Serializer headerSerializer,
- final Serializer footerSerializer, final boolean includeNullDelimiter,
- final KeyValuePair[] additionalFields) {
- super(config, charset, headerSerializer, footerSerializer);
- this.objectWriter = objectWriter;
- this.compact = compact;
- this.complete = complete;
- this.eol = endOfLine != null ? endOfLine : compact && !eventEol ? COMPACT_EOL : DEFAULT_EOL;
- this.includeNullDelimiter = includeNullDelimiter;
- this.additionalFields = prepareAdditionalFields(config, additionalFields);
- }
-
- protected static boolean valueNeedsLookup(final String value) {
- return value != null && value.contains("${");
- }
-
- private static ResolvableKeyValuePair[] prepareAdditionalFields(final Configuration config,
- final KeyValuePair[] additionalFields) {
- if (additionalFields == null || additionalFields.length == 0) {
- // No fields set
- return ResolvableKeyValuePair.EMPTY_ARRAY;
- }
-
- // Convert to specific class which already determines whether values needs lookup during serialization
- final ResolvableKeyValuePair[] resolvableFields = new ResolvableKeyValuePair[additionalFields.length];
-
- for (int i = 0; i < additionalFields.length; i++) {
- final ResolvableKeyValuePair resolvable =
- resolvableFields[i] = new ResolvableKeyValuePair(additionalFields[i]);
-
- // Validate
- if (config == null && resolvable.valueNeedsLookup) {
- throw new IllegalArgumentException(
- "configuration needs to be set when there are additional fields with variables");
- }
- }
-
- return resolvableFields;
- }
-
- private static LogEvent convertMutableToLog4jEvent(final LogEvent event) {
- return event instanceof Log4jLogEvent ? event : Log4jLogEvent.createMemento(event);
- }
-
- /**
- * Formats a {@link org.apache.logging.log4j.core.LogEvent}.
- *
- * @param event The LogEvent.
- * @return The XML representation of the LogEvent.
- */
- @Override
- public String toSerializable(final LogEvent event) {
- final StringBuilderWriter writer = new StringBuilderWriter();
- try {
- toSerializable(event, writer);
- return writer.toString();
- } catch (final IOException e) {
- // Should this be an ISE or IAE?
- LOGGER.error(e);
- return Strings.EMPTY;
- }
- }
-
- protected Object wrapLogEvent(final LogEvent event) {
- if (additionalFields.length > 0) {
- // Construct map for serialization - note that we are intentionally using original LogEvent
- final Map additionalFieldsMap = resolveAdditionalFields(event);
- // This class combines LogEvent with AdditionalFields during serialization
- return new LogEventWithAdditionalFields(event, additionalFieldsMap);
- } else if (event instanceof Message) {
- // If the LogEvent implements the Messagee interface Jackson will not treat is as a LogEvent.
- return new ReadOnlyLogEventWrapper(event);
- } else {
- // No additional fields, return original object
- return event;
- }
- }
-
- private Map resolveAdditionalFields(final LogEvent logEvent) {
- // Note: LinkedHashMap retains order
- final Map additionalFieldsMap = new LinkedHashMap<>(additionalFields.length);
- final StrSubstitutor strSubstitutor = configuration.getStrSubstitutor();
-
- // Go over each field
- for (final ResolvableKeyValuePair pair : additionalFields) {
- if (pair.valueNeedsLookup) {
- // Resolve value
- additionalFieldsMap.put(pair.key, strSubstitutor.replace(logEvent, pair.value));
- } else {
- // Plain text value
- additionalFieldsMap.put(pair.key, pair.value);
- }
- }
-
- return additionalFieldsMap;
- }
-
- public void toSerializable(final LogEvent event, final Writer writer)
- throws JsonGenerationException, JsonMappingException, IOException {
- objectWriter.writeValue(writer, wrapLogEvent(convertMutableToLog4jEvent(event)));
- writer.write(eol);
- if (includeNullDelimiter) {
- writer.write('\0');
- }
- markEvent();
- }
-
- public static abstract class Builder> extends AbstractStringLayout.Builder {
-
- @PluginBuilderAttribute
- private boolean eventEol;
-
- @PluginBuilderAttribute
- private String endOfLine;
-
- @PluginBuilderAttribute
- private boolean compact;
-
- @PluginBuilderAttribute
- private boolean complete;
-
- @PluginBuilderAttribute
- private boolean locationInfo;
-
- @PluginBuilderAttribute
- private boolean properties;
-
- @PluginBuilderAttribute
- private boolean includeStacktrace = true;
-
- @PluginBuilderAttribute
- private boolean stacktraceAsString = false;
-
- @PluginBuilderAttribute
- private boolean includeNullDelimiter = false;
-
- @PluginBuilderAttribute
- private boolean includeTimeMillis = false;
-
- @PluginElement("AdditionalField")
- private KeyValuePair[] additionalFields;
-
- protected String toStringOrNull(final byte[] header) {
- return header == null ? null : new String(header, Charset.defaultCharset());
- }
-
- public boolean getEventEol() {
- return eventEol;
- }
-
- public B setEventEol(final boolean eventEol) {
- this.eventEol = eventEol;
- return asBuilder();
- }
-
- public String getEndOfLine() {
- return endOfLine;
- }
-
- public B setEndOfLine(final String endOfLine) {
- this.endOfLine = endOfLine;
- return asBuilder();
- }
-
- public boolean isCompact() {
- return compact;
- }
-
- public B setCompact(final boolean compact) {
- this.compact = compact;
- return asBuilder();
- }
-
- public boolean isComplete() {
- return complete;
- }
-
- public B setComplete(final boolean complete) {
- this.complete = complete;
- return asBuilder();
- }
-
- public boolean isLocationInfo() {
- return locationInfo;
- }
-
- public B setLocationInfo(final boolean locationInfo) {
- this.locationInfo = locationInfo;
- return asBuilder();
- }
-
- public boolean isProperties() {
- return properties;
- }
-
- public B setProperties(final boolean properties) {
- this.properties = properties;
- return asBuilder();
- }
-
- /**
- * If "true", includes the stacktrace of any Throwable in the generated data, defaults to "true".
- *
- * @return If "true", includes the stacktrace of any Throwable in the generated data, defaults to "true".
- */
- public boolean isIncludeStacktrace() {
- return includeStacktrace;
- }
-
- /**
- * If "true", includes the stacktrace of any Throwable in the generated JSON, defaults to "true".
- *
- * @param includeStacktrace If "true", includes the stacktrace of any Throwable in the generated JSON, defaults to "true".
- * @return this builder
- */
- public B setIncludeStacktrace(final boolean includeStacktrace) {
- this.includeStacktrace = includeStacktrace;
- return asBuilder();
- }
-
- public boolean isStacktraceAsString() {
- return stacktraceAsString;
- }
-
- /**
- * Whether to format the stacktrace as a string, and not a nested object (optional, defaults to false).
- *
- * @return this builder
- */
- public B setStacktraceAsString(final boolean stacktraceAsString) {
- this.stacktraceAsString = stacktraceAsString;
- return asBuilder();
- }
-
- public boolean isIncludeNullDelimiter() {
- return includeNullDelimiter;
- }
-
- /**
- * Whether to include NULL byte as delimiter after each event (optional, default to false).
- *
- * @return this builder
- */
- public B setIncludeNullDelimiter(final boolean includeNullDelimiter) {
- this.includeNullDelimiter = includeNullDelimiter;
- return asBuilder();
- }
-
- public boolean isIncludeTimeMillis() {
- return includeTimeMillis;
- }
-
- /**
- * Whether to include the timestamp (in addition to the Instant) (optional, default to false).
- *
- * @return this builder
- */
- public B setIncludeTimeMillis(final boolean includeTimeMillis) {
- this.includeTimeMillis = includeTimeMillis;
- return asBuilder();
- }
-
- public KeyValuePair[] getAdditionalFields() {
- return additionalFields;
- }
-
- /**
- * Additional fields to set on each log event.
- *
- * @return this builder
- */
- public B setAdditionalFields(final KeyValuePair[] additionalFields) {
- this.additionalFields = additionalFields;
- return asBuilder();
- }
- }
-
- @JsonRootName(XmlConstants.ELT_EVENT)
- public static class LogEventWithAdditionalFields {
-
- private final Object logEvent;
- private final Map additionalFields;
-
- public LogEventWithAdditionalFields(final Object logEvent, final Map additionalFields) {
- this.logEvent = logEvent;
- this.additionalFields = additionalFields;
- }
-
- @JsonUnwrapped
- public Object getLogEvent() {
- return logEvent;
- }
-
- @JsonAnyGetter
- @SuppressWarnings("unused")
- public Map getAdditionalFields() {
- return additionalFields;
- }
- }
-
- protected static class ResolvableKeyValuePair {
-
- /**
- * The empty array.
- */
- static final ResolvableKeyValuePair[] EMPTY_ARRAY = {};
-
- final String key;
- final String value;
- final boolean valueNeedsLookup;
-
- ResolvableKeyValuePair(final KeyValuePair pair) {
- this.key = pair.getKey();
- this.value = pair.getValue();
- this.valueNeedsLookup = AbstractJacksonLayoutCopy.valueNeedsLookup(this.value);
- }
- }
-
- private static class ReadOnlyLogEventWrapper implements LogEvent {
-
- @JsonIgnore
- private final LogEvent event;
-
- public ReadOnlyLogEventWrapper(LogEvent event) {
- this.event = event;
- }
-
- @Override
- public LogEvent toImmutable() {
- return event.toImmutable();
- }
-
- @Override
- public Map getContextMap() {
- return event.getContextMap();
- }
-
- @Override
- public ReadOnlyStringMap getContextData() {
- return event.getContextData();
- }
-
- @Override
- public ThreadContext.ContextStack getContextStack() {
- return event.getContextStack();
- }
-
- @Override
- public String getLoggerFqcn() {
- return event.getLoggerFqcn();
- }
-
- @Override
- public Level getLevel() {
- return event.getLevel();
- }
-
- @Override
- public String getLoggerName() {
- return event.getLoggerName();
- }
-
- @Override
- public Marker getMarker() {
- return event.getMarker();
- }
-
- @Override
- public Message getMessage() {
- return event.getMessage();
- }
-
- @Override
- public long getTimeMillis() {
- return event.getTimeMillis();
- }
-
- @Override
- public Instant getInstant() {
- return event.getInstant();
- }
-
- @Override
- public StackTraceElement getSource() {
- return event.getSource();
- }
-
- @Override
- public String getThreadName() {
- return event.getThreadName();
- }
-
- @Override
- public long getThreadId() {
- return event.getThreadId();
- }
-
- @Override
- public int getThreadPriority() {
- return event.getThreadPriority();
- }
-
- @Override
- public Throwable getThrown() {
- return event.getThrown();
- }
-
- @Override
- public ThrowableProxy getThrownProxy() {
- return event.getThrownProxy();
- }
-
- @Override
- public boolean isEndOfBatch() {
- return event.isEndOfBatch();
- }
-
- @Override
- public void setEndOfBatch(boolean endOfBatch) {
-
- }
-
- @Override
- public boolean isIncludeLocation() {
- return event.isIncludeLocation();
- }
-
- @Override
- public void setIncludeLocation(boolean locationRequired) {
-
- }
-
- @Override
- public long getNanoTime() {
- return event.getNanoTime();
- }
- }
-}
\ No newline at end of file
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/JacksonFactoryCopy.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/JacksonFactoryCopy.java
deleted file mode 100644
index 6b568be30..000000000
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/JacksonFactoryCopy.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright 2023 Amazon.com, Inc. or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package software.amazon.lambda.powertools.logging.internal;
-
-import com.fasterxml.jackson.core.PrettyPrinter;
-import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
-import com.fasterxml.jackson.core.util.MinimalPrettyPrinter;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.ObjectWriter;
-import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
-import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
-import java.util.HashSet;
-import java.util.Set;
-import org.apache.logging.log4j.core.impl.Log4jLogEvent;
-import org.apache.logging.log4j.core.jackson.JsonConstants;
-import org.apache.logging.log4j.core.jackson.Log4jJsonObjectMapper;
-
-@Deprecated
-abstract class JacksonFactoryCopy {
-
- abstract protected String getPropertyNameForTimeMillis();
-
- abstract protected String getPropertyNameForInstant();
-
- abstract protected String getPropertNameForContextMap();
-
- abstract protected String getPropertNameForSource();
-
- abstract protected String getPropertNameForNanoTime();
-
- abstract protected PrettyPrinter newCompactPrinter();
-
- abstract protected ObjectMapper newObjectMapper();
-
- abstract protected PrettyPrinter newPrettyPrinter();
-
- ObjectWriter newWriter(final boolean locationInfo, final boolean properties, final boolean compact) {
- return newWriter(locationInfo, properties, compact, false);
- }
-
- ObjectWriter newWriter(final boolean locationInfo, final boolean properties, final boolean compact,
- final boolean includeMillis) {
- final SimpleFilterProvider filters = new SimpleFilterProvider();
- final Set except = new HashSet<>(3);
- if (!locationInfo) {
- except.add(this.getPropertNameForSource());
- }
- if (!properties) {
- except.add(this.getPropertNameForContextMap());
- }
- if (includeMillis) {
- except.add(getPropertyNameForInstant());
- } else {
- except.add(getPropertyNameForTimeMillis());
- }
- except.add(this.getPropertNameForNanoTime());
- filters.addFilter(Log4jLogEvent.class.getName(), SimpleBeanPropertyFilter.serializeAllExcept(except));
- final ObjectWriter writer =
- this.newObjectMapper().writer(compact ? this.newCompactPrinter() : this.newPrettyPrinter());
- return writer.with(filters);
- }
-
- static class JSON extends JacksonFactoryCopy {
-
- private final boolean encodeThreadContextAsList;
- private final boolean includeStacktrace;
- private final boolean stacktraceAsString;
- private final boolean objectMessageAsJsonObject;
-
- public JSON(final boolean encodeThreadContextAsList, final boolean includeStacktrace,
- final boolean stacktraceAsString, final boolean objectMessageAsJsonObject) {
- this.encodeThreadContextAsList = encodeThreadContextAsList;
- this.includeStacktrace = includeStacktrace;
- this.stacktraceAsString = stacktraceAsString;
- this.objectMessageAsJsonObject = objectMessageAsJsonObject;
- }
-
- @Override
- protected String getPropertNameForContextMap() {
- return JsonConstants.ELT_CONTEXT_MAP;
- }
-
- @Override
- protected String getPropertyNameForTimeMillis() {
- return JsonConstants.ELT_TIME_MILLIS;
- }
-
- @Override
- protected String getPropertyNameForInstant() {
- return JsonConstants.ELT_INSTANT;
- }
-
- @Override
- protected String getPropertNameForSource() {
- return JsonConstants.ELT_SOURCE;
- }
-
- @Override
- protected String getPropertNameForNanoTime() {
- return JsonConstants.ELT_NANO_TIME;
- }
-
- @Override
- protected PrettyPrinter newCompactPrinter() {
- return new MinimalPrettyPrinter();
- }
-
- @Override
- protected ObjectMapper newObjectMapper() {
- return new Log4jJsonObjectMapper(encodeThreadContextAsList, includeStacktrace, stacktraceAsString,
- objectMessageAsJsonObject);
- }
-
- @Override
- protected PrettyPrinter newPrettyPrinter() {
- return new DefaultPrettyPrinter();
- }
-
- }
-
-}
\ No newline at end of file
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonLayout.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonLayout.java
deleted file mode 100644
index fd646ab50..000000000
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonLayout.java
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright 2023 Amazon.com, Inc. or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package software.amazon.lambda.powertools.logging.internal;
-
-import static java.time.Instant.ofEpochMilli;
-import static java.time.format.DateTimeFormatter.ISO_ZONED_DATE_TIME;
-
-import com.fasterxml.jackson.annotation.JsonAnyGetter;
-import com.fasterxml.jackson.annotation.JsonGetter;
-import com.fasterxml.jackson.annotation.JsonRootName;
-import com.fasterxml.jackson.annotation.JsonUnwrapped;
-import java.io.IOException;
-import java.io.Writer;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import org.apache.logging.log4j.core.Layout;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.config.DefaultConfiguration;
-import org.apache.logging.log4j.core.config.Node;
-import org.apache.logging.log4j.core.config.plugins.Plugin;
-import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.core.jackson.XmlConstants;
-import org.apache.logging.log4j.core.layout.PatternLayout;
-import org.apache.logging.log4j.core.util.KeyValuePair;
-import org.apache.logging.log4j.util.Strings;
-
-/***
- * Note: The LambdaJsonLayout should be considered to be deprecated. Please use JsonTemplateLayout instead.
- */
-@Deprecated
-@Plugin(name = "LambdaJsonLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
-public final class LambdaJsonLayout extends AbstractJacksonLayoutCopy {
- static final String CONTENT_TYPE = "application/json";
- private static final String DEFAULT_FOOTER = "]";
- private static final String DEFAULT_HEADER = "[";
-
- private LambdaJsonLayout(final Configuration config, final boolean locationInfo, final boolean properties,
- final boolean encodeThreadContextAsList,
- final boolean complete, final boolean compact, final boolean eventEol,
- final String headerPattern, final String footerPattern, final Charset charset,
- final boolean includeStacktrace, final boolean stacktraceAsString,
- final boolean includeNullDelimiter,
- final KeyValuePair[] additionalFields, final boolean objectMessageAsJsonObject) {
- super(config, new JacksonFactoryCopy.JSON(encodeThreadContextAsList, includeStacktrace, stacktraceAsString,
- objectMessageAsJsonObject).newWriter(
- locationInfo, properties, compact),
- charset, compact, complete, eventEol,
- null,
- PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(headerPattern)
- .setDefaultPattern(DEFAULT_HEADER).build(),
- PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(footerPattern)
- .setDefaultPattern(DEFAULT_FOOTER).build(),
- includeNullDelimiter,
- additionalFields);
- }
-
- @PluginBuilderFactory
- public static > B newBuilder() {
- return new Builder().asBuilder();
- }
-
- /**
- * Creates a JSON Layout using the default settings. Useful for testing.
- *
- * @return A JSON Layout.
- */
- public static LambdaJsonLayout createDefaultLayout() {
- return new LambdaJsonLayout(new DefaultConfiguration(), false, false, false, false, false, false,
- DEFAULT_HEADER, DEFAULT_FOOTER, StandardCharsets.UTF_8, true, false, false, null, false);
- }
-
- /**
- * Returns appropriate JSON header.
- *
- * @return a byte array containing the header, opening the JSON array.
- */
- @Override
- public byte[] getHeader() {
- if (!this.complete) {
- return null;
- }
- final StringBuilder buf = new StringBuilder();
- final String str = serializeToString(getHeaderSerializer());
- if (str != null) {
- buf.append(str);
- }
- buf.append(this.eol);
- return getBytes(buf.toString());
- }
-
- /**
- * Returns appropriate JSON footer.
- *
- * @return a byte array containing the footer, closing the JSON array.
- */
- @Override
- public byte[] getFooter() {
- if (!this.complete) {
- return null;
- }
- final StringBuilder buf = new StringBuilder();
- buf.append(this.eol);
- final String str = serializeToString(getFooterSerializer());
- if (str != null) {
- buf.append(str);
- }
- buf.append(this.eol);
- return getBytes(buf.toString());
- }
-
- @Override
- public Map getContentFormat() {
- final Map result = new HashMap<>();
- result.put("version", "2.0");
- return result;
- }
-
- /**
- * @return The content type.
- */
- @Override
- public String getContentType() {
- return CONTENT_TYPE + "; charset=" + this.getCharset();
- }
-
- @Override
- public Object wrapLogEvent(final LogEvent event) {
- Map additionalFieldsMap = resolveAdditionalFields(event);
- // This class combines LogEvent with AdditionalFields during serialization
- return new LogEventWithAdditionalFields(event, additionalFieldsMap);
- }
-
- @Override
- public void toSerializable(final LogEvent event, final Writer writer) throws IOException {
- if (complete && eventCount > 0) {
- writer.append(", ");
- }
- super.toSerializable(event, writer);
- }
-
- private Map resolveAdditionalFields(LogEvent logEvent) {
- // Note: LinkedHashMap retains order
- final Map additionalFieldsMap = new LinkedHashMap<>(additionalFields.length);
-
- // Go over MDC
- logEvent.getContextData().forEach((key, value) ->
- {
- if (Strings.isNotBlank(key) && value != null) {
- additionalFieldsMap.put(key, value);
- }
- });
-
- return additionalFieldsMap;
- }
-
- public static class Builder> extends AbstractJacksonLayoutCopy.Builder
- implements org.apache.logging.log4j.core.util.Builder {
-
- @PluginBuilderAttribute
- private boolean propertiesAsList;
-
- @PluginBuilderAttribute
- private boolean objectMessageAsJsonObject;
-
- public Builder() {
- super();
- setCharset(StandardCharsets.UTF_8);
- }
-
- @Override
- public LambdaJsonLayout build() {
- final boolean encodeThreadContextAsList = isProperties() && propertiesAsList;
- final String headerPattern = toStringOrNull(getHeader());
- final String footerPattern = toStringOrNull(getFooter());
- return new LambdaJsonLayout(getConfiguration(), isLocationInfo(), isProperties(), encodeThreadContextAsList,
- isComplete(), isCompact(), getEventEol(), headerPattern, footerPattern, getCharset(),
- isIncludeStacktrace(), isStacktraceAsString(), isIncludeNullDelimiter(),
- getAdditionalFields(), getObjectMessageAsJsonObject());
- }
-
- public boolean isPropertiesAsList() {
- return propertiesAsList;
- }
-
- public B setPropertiesAsList(final boolean propertiesAsList) {
- this.propertiesAsList = propertiesAsList;
- return asBuilder();
- }
-
- public boolean getObjectMessageAsJsonObject() {
- return objectMessageAsJsonObject;
- }
-
- public B setObjectMessageAsJsonObject(final boolean objectMessageAsJsonObject) {
- this.objectMessageAsJsonObject = objectMessageAsJsonObject;
- return asBuilder();
- }
- }
-
- @JsonRootName(XmlConstants.ELT_EVENT)
- public static class LogEventWithAdditionalFields {
-
- private final LogEvent logEvent;
- private final Map additionalFields;
-
- public LogEventWithAdditionalFields(LogEvent logEvent, Map additionalFields) {
- this.logEvent = logEvent;
- this.additionalFields = additionalFields;
- }
-
- @JsonUnwrapped
- public Object getLogEvent() {
- return logEvent;
- }
-
- @JsonAnyGetter
- public Map getAdditionalFields() {
- return additionalFields;
- }
-
- @JsonGetter("timestamp")
- public String getTimestamp() {
- return ISO_ZONED_DATE_TIME.format(
- ZonedDateTime.from(ofEpochMilli(logEvent.getTimeMillis()).atZone(ZoneId.systemDefault())));
- }
- }
-}
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
index 0a36723f6..c60a1c85c 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
@@ -54,26 +54,50 @@
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclarePrecedence;
import org.aspectj.lang.annotation.Pointcut;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+import org.slf4j.event.Level;
import software.amazon.lambda.powertools.logging.Logging;
import software.amazon.lambda.powertools.logging.LoggingUtils;
+
@Aspect
@DeclarePrecedence("*, software.amazon.lambda.powertools.logging.internal.LambdaLoggingAspect")
public final class LambdaLoggingAspect {
- private static final Logger LOG = LogManager.getLogger(LambdaLoggingAspect.class);
+ private static final Logger LOG = LoggerFactory.getLogger(LambdaLoggingAspect.class);
private static final Random SAMPLER = new Random();
private static final String LOG_LEVEL = System.getenv("POWERTOOLS_LOG_LEVEL");
private static final String SAMPLING_RATE = System.getenv("POWERTOOLS_LOGGER_SAMPLE_RATE");
- private static Level LEVEL_AT_INITIALISATION;
+ private static Level LEVEL_AT_INITIALISATION; /* not final for test purpose */
+
+ private static final LoggingManager loggingManager;
static {
+ loggingManager = loadLoggingManager();
+
+ LEVEL_AT_INITIALISATION = loggingManager.getLogLevel(LOG);
+
if (null != LOG_LEVEL) {
- resetLogLevels(Level.getLevel(LOG_LEVEL));
+ resetLogLevels(Level.valueOf(LOG_LEVEL));
}
+ }
- LEVEL_AT_INITIALISATION = LOG.getLevel();
+ private static LoggingManager loadLoggingManager() {
+ ServiceLoader loggingManagers = ServiceLoader.load(LoggingManager.class);
+ List loggingManagerList = new ArrayList<>();
+ for (LoggingManager loggingManager : loggingManagers) {
+ loggingManagerList.add(loggingManager);
+ }
+ if (loggingManagerList.isEmpty()) {
+ throw new IllegalStateException("No LoggingManager was found on the classpath");
+ } else if (loggingManagerList.size() > 1) {
+ throw new IllegalStateException("Multiple LoggingManagers were found on the classpath: " + loggingManagerList);
+ } else {
+ return loggingManagerList.get(0);
+ }
}
private static void resetLogLevels(Level logLevel) {
@@ -97,12 +121,12 @@ public Object around(ProceedingJoinPoint pjp,
Context extractedContext = extractContext(pjp);
if (null != extractedContext) {
- appendKeys(DefaultLambdaFields.values(extractedContext));
- appendKey("coldStart", isColdStart() ? "true" : "false");
- appendKey("service", serviceName());
+ appendKeys(PowertoolsLoggedFields.setValuesFromLambdaContext(extractedContext));
+ appendKey(FUNCTION_COLD_START.getName(), isColdStart() ? "true" : "false");
+ appendKey(SERVICE.getName(), serviceName());
}
- getXrayTraceId().ifPresent(xRayTraceId -> appendKey("xray_trace_id", xRayTraceId));
+ getXrayTraceId().ifPresent(xRayTraceId -> appendKey(FUNCTION_TRACE_ID.getName(), xRayTraceId));
if (logging.logEvent()) {
proceedArgs = logEvent(pjp);
@@ -115,13 +139,17 @@ public Object around(ProceedingJoinPoint pjp,
Object proceed = pjp.proceed(proceedArgs);
if (logging.clearState()) {
- ThreadContext.clearMap();
+ MDC.clear();
}
coldStartDone();
return proceed;
}
+ private static void resetLogLevels(Level logLevel) {
+ loggingManager.resetLogLevel(logLevel);
+ }
+
private void setLogLevelBasedOnSamplingRate(final ProceedingJoinPoint pjp,
final Logging logging) {
double samplingRate = samplingRate(logging);
@@ -134,7 +162,7 @@ private void setLogLevelBasedOnSamplingRate(final ProceedingJoinPoint pjp,
return;
}
- appendKey("samplingRate", String.valueOf(samplingRate));
+ appendKey(PowertoolsLoggedFields.SAMPLING_RATE.getName(), String.valueOf(samplingRate));
if (samplingRate == 0) {
return;
@@ -147,7 +175,7 @@ private void setLogLevelBasedOnSamplingRate(final ProceedingJoinPoint pjp,
LOG.debug("Changed log level to DEBUG based on Sampling configuration. " +
"Sampling Rate: {}, Sampler Value: {}.", samplingRate, sample);
- } else if (LEVEL_AT_INITIALISATION != LOG.getLevel()) {
+ } else if (LEVEL_AT_INITIALISATION != loggingManager.getLogLevel(LOG)) {
resetLogLevels(LEVEL_AT_INITIALISATION);
}
}
@@ -249,8 +277,11 @@ private byte[] bytesFromInputStreamSafely(final InputStream inputStream) throws
try (ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStreamReader reader = new InputStreamReader(inputStream, UTF_8)) {
OutputStreamWriter writer = new OutputStreamWriter(out, UTF_8);
-
- IOUtils.copy(reader, writer);
+ int n;
+ char[] buffer = new char[4096];
+ while (-1 != (n = reader.read(buffer))) {
+ writer.write(buffer, 0, n);
+ }
writer.flush();
return out.toByteArray();
}
@@ -267,6 +298,6 @@ private Optional asJson(final ProceedingJoinPoint pjp,
}
private Logger logger(final ProceedingJoinPoint pjp) {
- return LogManager.getLogger(pjp.getSignature().getDeclaringType());
+ return LoggerFactory.getLogger(pjp.getSignature().getDeclaringType());
}
}
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LoggingManager.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LoggingManager.java
new file mode 100644
index 000000000..4850c9413
--- /dev/null
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LoggingManager.java
@@ -0,0 +1,30 @@
+package software.amazon.lambda.powertools.logging.internal;
+
+import org.slf4j.Logger;
+import org.slf4j.event.Level;
+
+/**
+ * Due to limitations of SLF4J, we need to rely on implementations for some operations:
+ *
+ *
Accessing to all loggers and change their Level
+ *
Retrieving the log Level of a Logger
+ *
+ *
+ * Implementations are provided in submodules and loaded thanks to a {@link java.util.ServiceLoader}
+ * (define a file named software.amazon.lambda.powertools.logging.internal.LoggingManager in src/main/resources/META-INF/services with the qualified name of the implementation).
+ *
+ */
+public interface LoggingManager {
+ /**
+ * Change the log Level of all loggers (named and root)
+ * @param logLevel the log Level (slf4j) to apply
+ */
+ void resetLogLevel(Level logLevel);
+
+ /**
+ * Retrieve the log Level of a specific logger
+ * @param logger the logger (slf4j) for which to retrieve the log Level
+ * @return the Level (slf4j) of this logger. Note that SLF4J only support ERROR, WARN, INFO, DEBUG, TRACE while some frameworks may support others (OFF, FATAL, ...)
+ */
+ Level getLogLevel(Logger logger);
+}
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/DefaultLambdaFields.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/PowertoolsLoggedFields.java
similarity index 64%
rename from powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/DefaultLambdaFields.java
rename to powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/PowertoolsLoggedFields.java
index 2461ae771..1c64248f9 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/DefaultLambdaFields.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/PowertoolsLoggedFields.java
@@ -16,22 +16,34 @@
import com.amazonaws.services.lambda.runtime.Context;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
-
-enum DefaultLambdaFields {
- FUNCTION_NAME("functionName"),
- FUNCTION_VERSION("functionVersion"),
- FUNCTION_ARN("functionArn"),
- FUNCTION_MEMORY_SIZE("functionMemorySize"),
- FUNCTION_REQUEST_ID("function_request_id");
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public enum PowertoolsLoggedFields {
+ FUNCTION_NAME("function_name"),
+ FUNCTION_VERSION("function_version"),
+ FUNCTION_ARN("function_arn"),
+ FUNCTION_MEMORY_SIZE("function_memory_size"),
+ FUNCTION_REQUEST_ID("function_request_id"),
+ FUNCTION_COLD_START("cold_start"),
+ FUNCTION_TRACE_ID("xray_trace_id"),
+ SAMPLING_RATE("sampling_rate"),
+ SERVICE("service");
private final String name;
- DefaultLambdaFields(String name) {
+ PowertoolsLoggedFields(String name) {
this.name = name;
}
- static Map values(Context context) {
+ public static List stringValues() {
+ return Stream.of(values()).map(PowertoolsLoggedFields::getName).collect(Collectors.toList());
+ }
+
+
+ static Map setValuesFromLambdaContext(Context context) {
Map hashMap = new HashMap<>();
hashMap.put(FUNCTION_NAME.name, context.getFunctionName());
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/PowertoolsResolver.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/PowertoolsResolver.java
deleted file mode 100644
index dc9816932..000000000
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/PowertoolsResolver.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2023 Amazon.com, Inc. or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package software.amazon.lambda.powertools.logging.internal;
-
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.layout.template.json.resolver.EventResolver;
-import org.apache.logging.log4j.layout.template.json.util.JsonWriter;
-import org.apache.logging.log4j.util.ReadOnlyStringMap;
-
-final class PowertoolsResolver implements EventResolver {
-
- private final EventResolver internalResolver;
-
- PowertoolsResolver() {
- internalResolver = new EventResolver() {
- @Override
- public boolean isResolvable(LogEvent value) {
- ReadOnlyStringMap contextData = value.getContextData();
- return null != contextData && !contextData.isEmpty();
- }
-
- @Override
- public void resolve(LogEvent logEvent, JsonWriter jsonWriter) {
- StringBuilder stringBuilder = jsonWriter.getStringBuilder();
- // remove dummy field to kick inn powertools resolver
- stringBuilder.setLength(stringBuilder.length() - 4);
-
- // Inject all the context information.
- ReadOnlyStringMap contextData = logEvent.getContextData();
- contextData.forEach((key, value) ->
- {
- jsonWriter.writeSeparator();
- jsonWriter.writeString(key);
- stringBuilder.append(':');
- jsonWriter.writeValue(value);
- });
- }
- };
- }
-
- static String getName() {
- return "powertools";
- }
-
- @Override
- public void resolve(LogEvent value, JsonWriter jsonWriter) {
- internalResolver.resolve(value, jsonWriter);
- }
-
- @Override
- public boolean isResolvable(LogEvent value) {
- return internalResolver.isResolvable(value);
- }
-}
diff --git a/powertools-logging/src/main/resources/LambdaEcsLayout.json b/powertools-logging/src/main/resources/LambdaEcsLayout.json
deleted file mode 100644
index 4ab9c7ce2..000000000
--- a/powertools-logging/src/main/resources/LambdaEcsLayout.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "@timestamp": {
- "$resolver": "timestamp",
- "pattern": {
- "format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
- "timeZone": "UTC"
- }
- },
- "ecs.version": "1.2.0",
- "log.level": {
- "$resolver": "level",
- "field": "name"
- },
- "message": {
- "$resolver": "message",
- "stringified": true
- },
- "process.thread.name": {
- "$resolver": "thread",
- "field": "name"
- },
- "log.logger": {
- "$resolver": "logger",
- "field": "name"
- },
- "labels": {
- "$resolver": "mdc",
- "flatten": true,
- "stringified": true
- },
- "tags": {
- "$resolver": "ndc"
- },
- "error.type": {
- "$resolver": "exception",
- "field": "className"
- },
- "error.message": {
- "$resolver": "exception",
- "field": "message"
- },
- "error.stack_trace": {
- "$resolver": "exception",
- "field": "stackTrace",
- "stackTrace": {
- "stringified": true
- }
- },
- "": {
- "$resolver": "powertools"
- }
-}
\ No newline at end of file
diff --git a/powertools-logging/src/main/resources/LambdaJsonLayout.json b/powertools-logging/src/main/resources/LambdaJsonLayout.json
deleted file mode 100644
index dfc1fc78f..000000000
--- a/powertools-logging/src/main/resources/LambdaJsonLayout.json
+++ /dev/null
@@ -1,89 +0,0 @@
-{
- "timestamp": {
- "$resolver": "timestamp"
- },
- "instant": {
- "epochSecond": {
- "$resolver": "timestamp",
- "epoch": {
- "unit": "secs",
- "rounded": true
- }
- },
- "nanoOfSecond": {
- "$resolver": "timestamp",
- "epoch": {
- "unit": "secs.nanos"
- }
- }
- },
- "thread": {
- "$resolver": "thread",
- "field": "name"
- },
- "level": {
- "$resolver": "level",
- "field": "name"
- },
- "loggerName": {
- "$resolver": "logger",
- "field": "name"
- },
- "message": {
- "$resolver": "message",
- "stringified": true
- },
- "thrown": {
- "message": {
- "$resolver": "exception",
- "field": "message"
- },
- "name": {
- "$resolver": "exception",
- "field": "className"
- },
- "extendedStackTrace": {
- "$resolver": "exception",
- "field": "stackTrace"
- }
- },
- "contextStack": {
- "$resolver": "ndc"
- },
- "endOfBatch": {
- "$resolver": "endOfBatch"
- },
- "loggerFqcn": {
- "$resolver": "logger",
- "field": "fqcn"
- },
- "threadId": {
- "$resolver": "thread",
- "field": "id"
- },
- "threadPriority": {
- "$resolver": "thread",
- "field": "priority"
- },
- "source": {
- "class": {
- "$resolver": "source",
- "field": "className"
- },
- "method": {
- "$resolver": "source",
- "field": "methodName"
- },
- "file": {
- "$resolver": "source",
- "field": "fileName"
- },
- "line": {
- "$resolver": "source",
- "field": "lineNumber"
- }
- },
- "": {
- "$resolver": "powertools"
- }
-}
diff --git a/powertools-logging/src/main/resources/log4j2.component.properties b/powertools-logging/src/main/resources/log4j2.component.properties
deleted file mode 100644
index 3c392dd13..000000000
--- a/powertools-logging/src/main/resources/log4j2.component.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-log4j.layout.jsonTemplate.timestampFormatPattern=yyyy-MM-dd'T'HH:mm:ss.SSSZz
-#log4j.layout.jsonTemplate.timeZone=
\ No newline at end of file
diff --git a/powertools-logging/src/test/java/org/apache/logging/log4j/core/layout/LambdaJsonLayoutTest.java b/powertools-logging/src/test/java/org/apache/logging/log4j/core/layout/LambdaJsonLayoutTest.java
deleted file mode 100644
index 9b0c6165a..000000000
--- a/powertools-logging/src/test/java/org/apache/logging/log4j/core/layout/LambdaJsonLayoutTest.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2023 Amazon.com, Inc. or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.logging.log4j.core.layout;
-
-import static java.util.Collections.emptyMap;
-import static org.apache.commons.lang3.reflect.FieldUtils.writeStaticField;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.fail;
-import static org.mockito.Mockito.when;
-import static org.mockito.MockitoAnnotations.openMocks;
-
-import com.amazonaws.services.lambda.runtime.Context;
-import com.amazonaws.services.lambda.runtime.RequestHandler;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.nio.channels.FileChannel;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
-import java.util.Map;
-import org.apache.logging.log4j.Level;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.Mock;
-import software.amazon.lambda.powertools.logging.handlers.PowerLogToolEnabled;
-import software.amazon.lambda.powertools.logging.handlers.PowerLogToolSamplingEnabled;
-import software.amazon.lambda.powertools.logging.internal.LambdaLoggingAspect;
-
-class LambdaJsonLayoutTest {
-
- private RequestHandler
+ * @return an instance of {@link LoggingManager} or null
+ */
+ private static Optional getLoggingManagerFromSlf4jBinding() {
+ LoggingManager loggingManager = null;
+
String slf4jBinding = System.getProperty("slf4j.binding");
- System.out.println(slf4jBinding); // TODO
+ if (slf4jBinding != null) {
+ LOG.debug("slf4j.binding is set to {}", slf4jBinding);
+ try {
+ if ("org.apache.logging.slf4j.SLF4JServiceProvider".equals(slf4jBinding)) {
+ String managerClass = "software.amazon.lambda.powertools.logging.internal.Log4jLoggingManager";
+ LOG.debug("Loading {}", managerClass);
+ Class> log4jManagerClass = LambdaLoggingAspect.class.getClassLoader()
+ .loadClass(managerClass);
+ loggingManager = (LoggingManager) log4jManagerClass.newInstance();
+ } else if ("ch.qos.logback.classic.spi.LogbackServiceProvider".equals(slf4jBinding)) {
+ String managerClass = "software.amazon.lambda.powertools.logging.internal.LogbackLoggingManager";
+ LOG.debug("Loading {}", managerClass);
+ Class> log4backManagerClass = LambdaLoggingAspect.class.getClassLoader()
+ .loadClass(managerClass);
+ loggingManager = (LoggingManager) log4backManagerClass.newInstance();
+ } else {
+ LOG.warn("slf4j.binding {} not supported, fallback to Service Loader. " +
+ "Only log4j and logback are supported.", slf4jBinding);
+ }
+ } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
+ LOG.warn("Could not instantiate LoggingManager based on slf4j.binding {}, " +
+ "make sure to add either powertools-logging-log4j or powertools-logging-logback module",
+ slf4jBinding);
+ }
+ }
+ return Optional.ofNullable(loggingManager);
+ }
+
+ private static LoggingManager getLoggingManagerFromServiceLoader() {
+ LoggingManager loggingManager;
ServiceLoader loggingManagers = ServiceLoader.load(LoggingManager.class);
List loggingManagerList = new ArrayList<>();
- for (LoggingManager loggingManager : loggingManagers) {
- loggingManagerList.add(loggingManager);
+ for (LoggingManager lm : loggingManagers) {
+ loggingManagerList.add(lm);
}
if (loggingManagerList.isEmpty()) {
- throw new IllegalStateException("No LoggingManager was found on the classpath");
+ throw new IllegalStateException("No LoggingManager was found on the classpath, " +
+ "make sure to add either powertools-logging-log4j or powertools-logging-logback to your dependencies");
} else if (loggingManagerList.size() > 1) {
throw new IllegalStateException(
- "Multiple LoggingManagers were found on the classpath: " + loggingManagerList);
+ "Multiple LoggingManagers were found on the classpath: " + loggingManagerList +
+ ", make sure to have only one of powertools-logging-log4j OR powertools-logging-logback to your dependencies");
} else {
- return loggingManagerList.get(0);
+ loggingManager = loggingManagerList.get(0);
}
+ return loggingManager;
}
private static void resetLogLevels(Level logLevel) {
diff --git a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
index 0a6b86002..6d568f544 100644
--- a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
+++ b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
@@ -49,6 +49,7 @@
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Collections;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -92,9 +93,13 @@ void setUp() throws IllegalAccessException, IOException, NoSuchMethodException,
setupContext();
requestHandler = new PowertoolsLogEnabled();
requestStreamHandler = new PowertoolsLogEnabledForStream();
+ resetLogLevel(Level.INFO);
+ }
+
+ @AfterEach
+ void cleanUp() throws IOException {
//Make sure file is cleaned up before running full stack logging regression
FileChannel.open(Paths.get("target/logfile.json"), StandardOpenOption.WRITE).truncate(0).close();
- resetLogLevel(Level.INFO);
}
@Test
From bdee1f32d2ad795b0788b7e55e9c4bc9b078bec5 Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Thu, 21 Sep 2023 23:16:43 +0200
Subject: [PATCH 29/74] complete tests for logback
---
.../powertools-logging-logback/pom.xml | 43 ++++
.../powertools/logging/LambdaEcsEncoder.java | 111 ++++++++--
.../powertools/logging/LambdaJsonEncoder.java | 79 +++++++-
.../logging/internal/JsonUtils.java | 10 +-
.../logging/internal/LambdaEcsSerializer.java | 4 -
.../internal/LambdaJsonSerializer.java | 13 +-
.../logging/LogbackLoggingManagerTest.java | 54 +++++
.../internal/LambdaEcsEncoderTest.java | 179 +++++++++++++++++
.../internal/LambdaJsonEncoderTest.java | 190 ++++++++++++++++++
.../internal/LambdaLoggingAspectTest.java | 82 ++++++++
.../internal/LogbackLoggingManagerTest.java | 39 ----
.../handler/PowertoolsLogEnabled.java | 34 ++++
.../test/resources/junit-platform.properties | 17 ++
.../src/test/resources/logback-test.xml | 22 +-
14 files changed, 800 insertions(+), 77 deletions(-)
create mode 100644 powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/LogbackLoggingManagerTest.java
create mode 100644 powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsEncoderTest.java
create mode 100644 powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonEncoderTest.java
create mode 100644 powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
delete mode 100644 powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LogbackLoggingManagerTest.java
create mode 100644 powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/handler/PowertoolsLogEnabled.java
create mode 100644 powertools-logging/powertools-logging-logback/src/test/resources/junit-platform.properties
diff --git a/powertools-logging/powertools-logging-logback/pom.xml b/powertools-logging/powertools-logging-logback/pom.xml
index 7eea5f1d9..1fb473962 100644
--- a/powertools-logging/powertools-logging-logback/pom.xml
+++ b/powertools-logging/powertools-logging-logback/pom.xml
@@ -113,14 +113,57 @@
jsonasserttest
+
+ org.junit-pioneer
+ junit-pioneer
+ test
+
+
+ dev.aspectj
+ aspectj-maven-plugin
+ 1.13.1
+
+
+ ${maven.compiler.target}
+ ${maven.compiler.target}
+
+
+ software.amazon.lambda
+ powertools-logging
+
+
+
+
+
+
+ compile
+
+
+
+
+
+ org.aspectj
+ aspectjtools
+ ${aspectj.version}
+
+
+ org.apache.maven.pluginsmaven-checkstyle-plugin
+
+ maven-surefire-plugin
+
+
+ ch.qos.logback.classic.spi.LogbackServiceProvider
+
+
+
diff --git a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaEcsEncoder.java b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaEcsEncoder.java
index 7df62a91e..f83a43ef4 100644
--- a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaEcsEncoder.java
+++ b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaEcsEncoder.java
@@ -51,6 +51,8 @@ public class LambdaEcsEncoder extends EncoderBase {
private final ThrowableProxyConverter throwableProxyConverter = new ThrowableProxyConverter();
protected ThrowableHandlingConverter throwableConverter = null;
+ private boolean includeCloudInfo = true;
+ private boolean includeFaasInfo = true;
@Override
public byte[] headerBytes() {
@@ -67,12 +69,6 @@ public byte[] encode(ILoggingEvent event) {
LambdaEcsSerializer.serializeEcsVersion(builder, ECS_VERSION);
LambdaEcsSerializer.serializeLogLevel(builder, event.getLevel());
LambdaEcsSerializer.serializeFormattedMessage(builder, event.getFormattedMessage());
- LambdaEcsSerializer.serializeServiceName(builder, LambdaHandlerProcessor.serviceName());
- LambdaEcsSerializer.serializeServiceVersion(builder, mdcPropertyMap.get(FUNCTION_VERSION.getName()));
- // TODO : Environment ?
- LambdaEcsSerializer.serializeEventDataset(builder, LambdaHandlerProcessor.serviceName());
- LambdaEcsSerializer.serializeThreadName(builder, event.getThreadName());
- LambdaEcsSerializer.serializeLoggerName(builder, event.getLoggerName());
IThrowableProxy throwableProxy = event.getThrowableProxy();
if (throwableProxy != null) {
if (throwableConverter != null) {
@@ -85,22 +81,33 @@ public byte[] encode(ILoggingEvent event) {
throwableProxy.getMessage(), throwableProxyConverter.convert(event));
}
}
- LambdaEcsSerializer.serializeCloudProvider(builder, CLOUD_PROVIDER);
- LambdaEcsSerializer.serializeCloudService(builder, CLOUD_SERVICE);
+ LambdaEcsSerializer.serializeServiceName(builder, LambdaHandlerProcessor.serviceName());
+ LambdaEcsSerializer.serializeServiceVersion(builder, mdcPropertyMap.get(FUNCTION_VERSION.getName()));
+ LambdaEcsSerializer.serializeLoggerName(builder, event.getLoggerName());
+ LambdaEcsSerializer.serializeThreadName(builder, event.getThreadName());
String arn = mdcPropertyMap.get(FUNCTION_ARN.getName());
- if (arn != null) {
- String[] arnParts = arn.split(":");
- LambdaEcsSerializer.serializeCloudRegion(builder, arnParts[3]);
- LambdaEcsSerializer.serializeCloudAccountId(builder, arnParts[4]);
+
+ if (includeCloudInfo) {
+ LambdaEcsSerializer.serializeCloudProvider(builder, CLOUD_PROVIDER);
+ LambdaEcsSerializer.serializeCloudService(builder, CLOUD_SERVICE);
+ if (arn != null) {
+ String[] arnParts = arn.split(":");
+ LambdaEcsSerializer.serializeCloudRegion(builder, arnParts[3]);
+ LambdaEcsSerializer.serializeCloudAccountId(builder, arnParts[4]);
+ }
+ }
+
+ if (includeFaasInfo) {
+ LambdaEcsSerializer.serializeFunctionId(builder, arn);
+ LambdaEcsSerializer.serializeFunctionName(builder, mdcPropertyMap.get(FUNCTION_NAME.getName()));
+ LambdaEcsSerializer.serializeFunctionVersion(builder, mdcPropertyMap.get(FUNCTION_VERSION.getName()));
+ LambdaEcsSerializer.serializeFunctionMemory(builder, mdcPropertyMap.get(FUNCTION_MEMORY_SIZE.getName()));
+ LambdaEcsSerializer.serializeFunctionExecutionId(builder,
+ mdcPropertyMap.get(FUNCTION_REQUEST_ID.getName()));
+ LambdaEcsSerializer.serializeColdStart(builder, mdcPropertyMap.get(FUNCTION_COLD_START.getName()));
+ LambdaEcsSerializer.serializeTraceId(builder, mdcPropertyMap.get(FUNCTION_TRACE_ID.getName()));
}
- LambdaEcsSerializer.serializeFunctionId(builder, arn);
- LambdaEcsSerializer.serializeFunctionName(builder, mdcPropertyMap.get(FUNCTION_NAME.getName()));
- LambdaEcsSerializer.serializeFunctionVersion(builder, mdcPropertyMap.get(FUNCTION_VERSION.getName()));
- LambdaEcsSerializer.serializeFunctionMemory(builder, mdcPropertyMap.get(FUNCTION_MEMORY_SIZE.getName()));
- LambdaEcsSerializer.serializeFunctionExecutionId(builder, mdcPropertyMap.get(FUNCTION_REQUEST_ID.getName()));
- LambdaEcsSerializer.serializeColdStart(builder, mdcPropertyMap.get(FUNCTION_COLD_START.getName()));
LambdaEcsSerializer.serializeAdditionalFields(builder, event.getMDCPropertyMap());
- LambdaEcsSerializer.serializeTraceId(builder, mdcPropertyMap.get(FUNCTION_TRACE_ID.getName()));
LambdaEcsSerializer.serializeObjectEnd(builder);
return builder.toString().getBytes(UTF_8);
}
@@ -110,7 +117,73 @@ public byte[] footerBytes() {
return null;
}
+ /**
+ * Specify a throwable converter to format the stacktrace according to your need (default is null, no throwableConverter):
+ *
+ *
+ * @param throwableConverter
+ */
public void setThrowableConverter(ThrowableHandlingConverter throwableConverter) {
this.throwableConverter = throwableConverter;
}
+
+ /**
+ * Specify if cloud information should be logged (default is true):
+ *
+ *
cloud.provider
+ *
cloud.service.name
+ *
cloud.region
+ *
cloud.account.id
+ *
+ *
+ * We strongly recommend to keep these information.
+ *
+ *
{@code
+ *
+ * false
+ *
+ * }
+ * @param includeCloudInfo if thread information should be logged
+ */
+ public void setIncludeCloudInfo(boolean includeCloudInfo) {
+ this.includeCloudInfo = includeCloudInfo;
+ }
+
+ /**
+ * Specify if Lambda function information should be logged (default is true):
+ *
+ *
faas.id
+ *
faas.name
+ *
faas.version
+ *
faas.memory
+ *
faas.execution
+ *
faas.coldstart
+ *
trace.id
+ *
+ *
+ * We strongly recommend to keep these information.
+ *
+ *
{@code
+ *
+ * false
+ *
+ * }
+ * @param includeFaasInfo if function information should be logged
+ */
+ public void setIncludeFaasInfo(boolean includeFaasInfo) {
+ this.includeFaasInfo = includeFaasInfo;
+ }
}
diff --git a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaJsonEncoder.java b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaJsonEncoder.java
index a1a378605..2a901ebd4 100644
--- a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaJsonEncoder.java
+++ b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaJsonEncoder.java
@@ -35,6 +35,7 @@ public class LambdaJsonEncoder extends EncoderBase {
protected String timestampFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZz";
protected String timestampFormatTimezoneId = null;
private boolean includeThreadInfo = false;
+ private boolean includePowertoolsInfo = true;
@Override
public byte[] headerBytes() {
@@ -68,7 +69,7 @@ public byte[] encode(ILoggingEvent event) {
throwableProxy.getMessage(), throwableProxyConverter.convert(event));
}
}
- LambdaJsonSerializer.serializePowertools(builder, event.getMDCPropertyMap());
+ LambdaJsonSerializer.serializePowertools(builder, event.getMDCPropertyMap(), includePowertoolsInfo);
if (includeThreadInfo) {
LambdaJsonSerializer.serializeThreadName(builder, event.getThreadName());
LambdaJsonSerializer.serializeThreadId(builder, String.valueOf(Thread.currentThread().getId()));
@@ -85,19 +86,95 @@ public byte[] footerBytes() {
return null;
}
+ /**
+ * Specify the format of the timestamp (default is yyyy-MM-dd'T'HH:mm:ss.SSSZz):
+ *
+ *
+ * @param timestampFormat format of the timestamp (compatible with {@link java.text.SimpleDateFormat})
+ */
public void setTimestampFormat(String timestampFormat) {
this.timestampFormat = timestampFormat;
}
+ /**
+ * Specify the format of the time zone id for timestamp (default is null, no timezone):
+ *
+ *
{@code
+ *
+ * Europe/Paris
+ *
+ * }
+ * @param timestampFormatTimezoneId Zone Id (see {@link java.util.TimeZone})
+ */
public void setTimestampFormatTimezoneId(String timestampFormatTimezoneId) {
this.timestampFormatTimezoneId = timestampFormatTimezoneId;
}
+ /**
+ * Specify a throwable converter to format the stacktrace according to your need (default is null, no throwableConverter):
+ *
+ *
+ * @param throwableConverter
+ */
public void setThrowableConverter(ThrowableHandlingConverter throwableConverter) {
this.throwableConverter = throwableConverter;
}
+ /**
+ * Specify if thread information should be logged (default is false)
+ *
+ *
{@code
+ *
+ * true
+ *
+ * }
+ * @param includeThreadInfo if thread information should be logged
+ */
public void setIncludeThreadInfo(boolean includeThreadInfo) {
this.includeThreadInfo = includeThreadInfo;
}
+
+ /**
+ * Specify if Lambda function information should be logged (default is true):
+ *
+ *
function_name
+ *
function_version
+ *
function_arn
+ *
function_memory_size
+ *
function_request_id
+ *
cold_start
+ *
xray_trace_id
+ *
sampling_rate
+ *
service
+ *
+ *
+ * We strongly recommend to keep these information.
+ *
+ *
{@code
+ *
+ * false
+ *
+ * }
+ * @param includePowertoolsInfo if function information should be logged
+ */
+ public void setIncludePowertoolsInfo(boolean includePowertoolsInfo) {
+ this.includePowertoolsInfo = includePowertoolsInfo;
+ }
}
diff --git a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/JsonUtils.java b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/JsonUtils.java
index 97b49595b..fd895092b 100644
--- a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/JsonUtils.java
+++ b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/JsonUtils.java
@@ -19,9 +19,9 @@ public class JsonUtils {
protected static void serializeAttribute(StringBuilder builder, String attr, String value, boolean notBegin) {
if (value != null) {
if (notBegin) {
- builder.append(", ");
+ builder.append(",");
}
- builder.append("\"").append(attr).append("\": ");
+ builder.append("\"").append(attr).append("\":");
boolean isString = isString(value);
if (isString) {
builder.append("\"");
@@ -37,11 +37,11 @@ protected static void serializeAttributeAsString(StringBuilder builder, String a
boolean notBegin) {
if (value != null) {
if (notBegin) {
- builder.append(", ");
+ builder.append(",");
}
builder.append("\"")
.append(attr)
- .append("\": \"")
+ .append("\":\"")
.append(value)
.append("\"");
}
@@ -72,7 +72,7 @@ private static boolean isString(String str) {
* Taken from commons-lang3 NumberUtils to avoid include the library
*/
private static boolean isNumeric(final String str) {
- if (str == null || str.length() == 0) {
+ if (str == null || str.isEmpty()) {
return false;
}
if (str.charAt(str.length() - 1) == '.') {
diff --git a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsSerializer.java b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsSerializer.java
index 3a052e6a4..6bdc96221 100644
--- a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsSerializer.java
+++ b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsSerializer.java
@@ -137,10 +137,6 @@ public static void serializeServiceVersion(StringBuilder builder, String service
serializeAttributeAsString(builder, SERVICE_VERSION_ATTR_NAME, serviceVersion);
}
- public static void serializeEventDataset(StringBuilder builder, String serviceName) {
- serializeAttributeAsString(builder, EVENT_DATASET_ATTR_NAME, serviceName);
- }
-
public static void serializeLoggerName(StringBuilder builder, String loggerName) {
serializeAttributeAsString(builder, LOGGER_ATTR_NAME, loggerName);
}
diff --git a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonSerializer.java b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonSerializer.java
index c3a29ac6b..a2a6c2029 100644
--- a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonSerializer.java
+++ b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonSerializer.java
@@ -87,11 +87,11 @@ public static void serializeFormattedMessage(StringBuilder builder, String forma
}
public static void serializeException(StringBuilder builder, String className, String message, String stackTrace) {
- builder.append("\"").append(EXCEPTION_ATTR_NAME).append("\": {");
+ builder.append(",\"").append(EXCEPTION_ATTR_NAME).append("\":{");
serializeAttribute(builder, EXCEPTION_MSG_ATTR_NAME, message, false);
serializeAttribute(builder, EXCEPTION_CLASS_ATTR_NAME, className);
serializeAttribute(builder, EXCEPTION_STACK_ATTR_NAME, stackTrace);
- builder.append("},");
+ builder.append("}");
}
public static void serializeException(StringBuilder builder, Throwable throwable) {
@@ -107,10 +107,13 @@ public static void serializeThreadPriority(StringBuilder builder, String threadP
serializeAttribute(builder, THREAD_PRIORITY_ATTR_NAME, threadPriority);
}
- public static void serializePowertools(StringBuilder builder, Map mdc) {
+ public static void serializePowertools(StringBuilder builder, Map mdc, boolean includePowertoolsInfo) {
TreeMap sortedMap = new TreeMap<>(mdc);
- sortedMap.forEach((k, v) ->
- serializeAttribute(builder, k, v));
+ sortedMap.forEach((k, v) -> {
+ if ((PowertoolsLoggedFields.stringValues().contains(k) && includePowertoolsInfo) || !PowertoolsLoggedFields.stringValues().contains(k)) {
+ serializeAttribute(builder, k, v);
+ }
+ });
}
}
diff --git a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/LogbackLoggingManagerTest.java b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/LogbackLoggingManagerTest.java
new file mode 100644
index 000000000..e13e78eb4
--- /dev/null
+++ b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/LogbackLoggingManagerTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package software.amazon.lambda.powertools.logging;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.slf4j.event.Level.DEBUG;
+import static org.slf4j.event.Level.ERROR;
+import static org.slf4j.event.Level.WARN;
+
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.event.Level;
+import software.amazon.lambda.powertools.logging.internal.LogbackLoggingManager;
+
+class LogbackLoggingManagerTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(LogbackLoggingManagerTest.class);
+ private static final Logger ROOT = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
+
+ @Test
+ @Order(1)
+ void getLogLevel_shouldReturnConfiguredLogLevel() {
+ LogbackLoggingManager manager = new LogbackLoggingManager();
+ Level logLevel = manager.getLogLevel(LOG);
+ assertThat(logLevel).isEqualTo(DEBUG);
+
+ logLevel = manager.getLogLevel(ROOT);
+ assertThat(logLevel).isEqualTo(WARN);
+ }
+
+ @Test
+ @Order(2)
+ void resetLogLevel() {
+ LogbackLoggingManager manager = new LogbackLoggingManager();
+ manager.resetLogLevel(ERROR);
+
+ Level logLevel = manager.getLogLevel(LOG);
+ assertThat(logLevel).isEqualTo(ERROR);
+ }
+}
diff --git a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsEncoderTest.java b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsEncoderTest.java
new file mode 100644
index 000000000..908c5fa40
--- /dev/null
+++ b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsEncoderTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package software.amazon.lambda.powertools.logging.internal;
+
+import static org.apache.commons.lang3.reflect.FieldUtils.writeStaticField;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.contentOf;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.openMocks;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.pattern.RootCauseFirstThrowableProxyConverter;
+import ch.qos.logback.classic.spi.LoggingEvent;
+import com.amazonaws.services.lambda.runtime.Context;
+import java.io.File;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junitpioneer.jupiter.SetEnvironmentVariable;
+import org.mockito.Mock;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+import software.amazon.lambda.powertools.common.internal.LambdaHandlerProcessor;
+import software.amazon.lambda.powertools.logging.LambdaEcsEncoder;
+import software.amazon.lambda.powertools.logging.internal.handler.PowertoolsLogEnabled;
+
+@Order(3)
+class LambdaEcsEncoderTest {
+
+ private static final Logger logger = (Logger) LoggerFactory.getLogger(LambdaEcsEncoderTest.class.getName());
+
+
+ @Mock
+ private Context context;
+
+ @BeforeEach
+ void setUp() throws IllegalAccessException, IOException {
+ openMocks(this);
+ MDC.clear();
+ writeStaticField(LambdaHandlerProcessor.class, "IS_COLD_START", null, true);
+ setupContext();
+ // Make sure file is cleaned up before running tests
+ try {
+ FileChannel.open(Paths.get("target/ecslogfile.json"), StandardOpenOption.WRITE).truncate(0).close();
+ } catch (NoSuchFileException e) {
+ // file may not exist on the first launch
+ }
+ }
+
+ @AfterEach
+ void cleanUp() throws IOException{
+// FileChannel.open(Paths.get("target/ecslogfile.json"), StandardOpenOption.WRITE).truncate(0).close();
+ }
+
+ @Test
+ @SetEnvironmentVariable(key = "AWS_REGION", value = "eu-central-1")
+ @SetEnvironmentVariable(key = "_X_AMZN_TRACE_ID", value = "Root=1-63441c4a-abcdef012345678912345678")
+ void shouldLogInEcsFormat() {
+ PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
+ handler.handleRequest("Input", context);
+
+ File logFile = new File("target/ecslogfile.json");
+ assertThat(contentOf(logFile)).contains(
+ "\"ecs.version\":\"1.2.0\",\"log.level\":\"DEBUG\",\"message\":\"Test debug event\",\"service.name\":\"testLogback\",\"service.version\":\"1\",\"log.logger\":\"software.amazon.lambda.powertools.logging.internal.handler.PowertoolsLogEnabled\",\"process.thread.name\":\"main\",\"cloud.provider\":\"aws\",\"cloud.service.name\":\"lambda\",\"cloud.region\":\"eu-west-1\",\"cloud.account.id\":\"012345678910\",\"faas.id\":\"arn:aws:lambda:eu-west-1:012345678910:function:testFunction:1\",\"faas.name\":\"testFunction\",\"faas.version\":\"1\",\"faas.memory\":\"1024\",\"faas.execution\":\"RequestId\",\"faas.coldstart\":\"true\",\"trace.id\":\"1-63441c4a-abcdef012345678912345678\",\"myKey\":\"myValue\"}\n");
+ }
+
+ private final LoggingEvent loggingEvent = new LoggingEvent("fqcn", logger, Level.INFO, "message", null, null);
+
+ @Test
+ void shouldNotLogFunctionInfo() {
+ // GIVEN
+ LambdaEcsEncoder encoder = new LambdaEcsEncoder();
+ setMDC();
+
+ // WHEN
+ byte[] encoded = encoder.encode(loggingEvent);
+ String result = new String(encoded, StandardCharsets.UTF_8);
+
+ // THEN
+ assertThat(result).contains("\"faas.id\":\"arn:aws:lambda:eu-west-1:012345678910:function:testFunction:1\",\"faas.name\":\"testFunction\",\"faas.version\":\"1\",\"faas.memory\":\"1024\",\"faas.execution\":\"RequestId\",\"faas.coldstart\":\"false\"");
+
+ // WHEN (includeFaasInfo = false)
+ encoder.setIncludeFaasInfo(false);
+ encoded = encoder.encode(loggingEvent);
+ result = new String(encoded, StandardCharsets.UTF_8);
+
+ // THEN (no faas info in logs)
+ assertThat(result).doesNotContain("faas");
+ }
+
+ @Test
+ void shouldNotLogCloudInfo() {
+ // GIVEN
+ LambdaEcsEncoder encoder = new LambdaEcsEncoder();
+ setMDC();
+
+ // WHEN
+ byte[] encoded = encoder.encode(loggingEvent);
+ String result = new String(encoded, StandardCharsets.UTF_8);
+
+ // THEN
+ assertThat(result).contains("\"cloud.provider\":\"aws\",\"cloud.service.name\":\"lambda\",\"cloud.region\":\"eu-west-1\",\"cloud.account.id\":\"012345678910\"");
+
+ // WHEN (includeCloudInfo = false)
+ encoder.setIncludeCloudInfo(false);
+ encoded = encoder.encode(loggingEvent);
+ result = new String(encoded, StandardCharsets.UTF_8);
+
+ // THEN (no faas info in logs)
+ assertThat(result).doesNotContain("cloud");
+ }
+
+ @Test
+ void shouldLogException() {
+ // GIVEN
+ LambdaEcsEncoder encoder = new LambdaEcsEncoder();
+ encoder.start();
+ LoggingEvent errorloggingEvent = new LoggingEvent("fqcn", logger, Level.INFO, "Error", new IllegalStateException("Unexpected value"), null);
+
+ // WHEN
+ byte[] encoded = encoder.encode(errorloggingEvent);
+ String result = new String(encoded, StandardCharsets.UTF_8);
+
+ // THEN
+ assertThat(result).contains("\"message\":\"Error\",\"error.message\":\"Unexpected value\",\"error.type\":\"java.lang.IllegalStateException\",\"error.stack_trace\":\"[software.amazon.lambda.powertools.logging.internal.LambdaEcsEncoderTest.shouldLogException");
+
+ // WHEN (configure a custom throwableConverter)
+ encoder = new LambdaEcsEncoder();
+ RootCauseFirstThrowableProxyConverter throwableConverter = new RootCauseFirstThrowableProxyConverter();
+ encoder.setThrowableConverter(throwableConverter);
+ encoder.start();
+ encoded = encoder.encode(errorloggingEvent);
+ result = new String(encoded, StandardCharsets.UTF_8);
+
+ // THEN (stack is logged with root cause first)
+ assertThat(result).contains("\"message\":\"Error\",\"error.message\":\"Unexpected value\",\"error.type\":\"java.lang.IllegalStateException\",\"error.stack_trace\":\"java.lang.IllegalStateException: Unexpected value\n");
+ }
+
+ private void setMDC() {
+ MDC.put(PowertoolsLoggedFields.FUNCTION_NAME.getName(), context.getFunctionName());
+ MDC.put(PowertoolsLoggedFields.FUNCTION_ARN.getName(), context.getInvokedFunctionArn());
+ MDC.put(PowertoolsLoggedFields.FUNCTION_VERSION.getName(), context.getFunctionVersion());
+ MDC.put(PowertoolsLoggedFields.FUNCTION_MEMORY_SIZE.getName(),
+ String.valueOf(context.getMemoryLimitInMB()));
+ MDC.put(PowertoolsLoggedFields.FUNCTION_REQUEST_ID.getName(), context.getAwsRequestId());
+ MDC.put(PowertoolsLoggedFields.FUNCTION_COLD_START.getName(), "false");
+ MDC.put(PowertoolsLoggedFields.SAMPLING_RATE.getName(), "0.2");
+ MDC.put(PowertoolsLoggedFields.SERVICE.getName(), "Service");
+ }
+
+ private void setupContext() {
+ when(context.getFunctionName()).thenReturn("testFunction");
+ when(context.getInvokedFunctionArn()).thenReturn(
+ "arn:aws:lambda:eu-west-1:012345678910:function:testFunction:1");
+ when(context.getFunctionVersion()).thenReturn("1");
+ when(context.getMemoryLimitInMB()).thenReturn(1024);
+ when(context.getAwsRequestId()).thenReturn("RequestId");
+ }
+}
diff --git a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonEncoderTest.java b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonEncoderTest.java
new file mode 100644
index 000000000..c579e3b7c
--- /dev/null
+++ b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonEncoderTest.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package software.amazon.lambda.powertools.logging.internal;
+
+import static org.apache.commons.lang3.reflect.FieldUtils.writeStaticField;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.contentOf;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.openMocks;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.pattern.RootCauseFirstThrowableProxyConverter;
+import ch.qos.logback.classic.spi.LoggingEvent;
+import com.amazonaws.services.lambda.runtime.Context;
+import java.io.File;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junitpioneer.jupiter.SetEnvironmentVariable;
+import org.mockito.Mock;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+import software.amazon.lambda.powertools.common.internal.LambdaHandlerProcessor;
+import software.amazon.lambda.powertools.logging.LambdaJsonEncoder;
+import software.amazon.lambda.powertools.logging.internal.handler.PowertoolsLogEnabled;
+
+@Order(2)
+class LambdaJsonEncoderTest {
+ private static final Logger logger = (Logger) LoggerFactory.getLogger(LambdaJsonEncoderTest.class.getName());
+
+ @Mock
+ private Context context;
+
+ @BeforeEach
+ void setUp() throws IllegalAccessException, IOException {
+ openMocks(this);
+ MDC.clear();
+ writeStaticField(LambdaHandlerProcessor.class, "IS_COLD_START", null, true);
+ setupContext();
+ // Make sure file is cleaned up before running tests
+ try {
+ FileChannel.open(Paths.get("target/logfile.json"), StandardOpenOption.WRITE).truncate(0).close();
+ } catch (NoSuchFileException e) {
+ // file may not exist on the first launch
+ }
+ }
+
+ @AfterEach
+ void cleanUp() throws IOException{
+ FileChannel.open(Paths.get("target/logfile.json"), StandardOpenOption.WRITE).truncate(0).close();
+ }
+
+ @Test
+ @SetEnvironmentVariable(key = "POWERTOOLS_LOGGER_SAMPLE_RATE", value = "0.000000001")
+ @SetEnvironmentVariable(key = "_X_AMZN_TRACE_ID", value = "Root=1-63441c4a-abcdef012345678912345678")
+ void shouldLogInJsonFormat() {
+ // GIVEN
+ PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
+
+ // WHEN
+ handler.handleRequest("Input", context);
+
+ // THEN
+ File logFile = new File("target/logfile.json");
+ assertThat(contentOf(logFile)).contains(
+ "{\"level\":\"DEBUG\",\"message\":\"Test debug event\",\"cold_start\":true,\"function_arn\":\"arn:aws:lambda:eu-west-1:012345678910:function:testFunction:1\",\"function_memory_size\":1024,\"function_name\":\"testFunction\",\"function_request_id\":\"RequestId\",\"function_version\":1,\"myKey\":\"myValue\",\"sampling_rate\":\"1.0E-9\",\"service\":\"testLogback\",\"xray_trace_id\":\"1-63441c4a-abcdef012345678912345678\",\"timestamp\":");
+ }
+
+ private final LoggingEvent loggingEvent = new LoggingEvent("fqcn", logger, Level.INFO, "message", null, null);
+
+ @Test
+ void shouldNotLogPowertoolsInfo() {
+ // GIVEN
+ LambdaJsonEncoder encoder = new LambdaJsonEncoder();
+
+ MDC.put(PowertoolsLoggedFields.FUNCTION_NAME.getName(), context.getFunctionName());
+ MDC.put(PowertoolsLoggedFields.FUNCTION_ARN.getName(), context.getInvokedFunctionArn());
+ MDC.put(PowertoolsLoggedFields.FUNCTION_VERSION.getName(), context.getFunctionVersion());
+ MDC.put(PowertoolsLoggedFields.FUNCTION_MEMORY_SIZE.getName(),
+ String.valueOf(context.getMemoryLimitInMB()));
+ MDC.put(PowertoolsLoggedFields.FUNCTION_REQUEST_ID.getName(), context.getAwsRequestId());
+ MDC.put(PowertoolsLoggedFields.FUNCTION_COLD_START.getName(), "false");
+ MDC.put(PowertoolsLoggedFields.SAMPLING_RATE.getName(), "0.2");
+ MDC.put(PowertoolsLoggedFields.SERVICE.getName(), "Service");
+
+ // WHEN
+ byte[] encoded = encoder.encode(loggingEvent);
+ String result = new String(encoded, StandardCharsets.UTF_8);
+
+ // THEN
+ assertThat(result).contains("{\"level\":\"INFO\",\"message\":\"message\",\"cold_start\":false,\"function_arn\":\"arn:aws:lambda:eu-west-1:012345678910:function:testFunction:1\",\"function_memory_size\":1024,\"function_name\":\"testFunction\",\"function_request_id\":\"RequestId\",\"function_version\":1,\"sampling_rate\":0.2,\"service\":\"Service\",\"timestamp\":");
+
+ // WHEN (powertoolsInfo = false)
+ encoder.setIncludePowertoolsInfo(false);
+ encoded = encoder.encode(loggingEvent);
+ result = new String(encoded, StandardCharsets.UTF_8);
+
+ // THEN (no powertools info in logs)
+ assertThat(result).doesNotContain("cold_start", "function_arn", "function_memory_size", "function_name", "function_request_id", "function_version", "sampling_rate", "service");
+ }
+
+ @Test
+ void shouldLogThreadInfo() {
+ // GIVEN
+ LambdaJsonEncoder encoder = new LambdaJsonEncoder();
+ encoder.setIncludeThreadInfo(true);
+
+ // WHEN
+ byte[] encoded = encoder.encode(loggingEvent);
+ String result = new String(encoded, StandardCharsets.UTF_8);
+
+ // THEN
+ assertThat(result).contains("\"thread\":\"main\",\"thread_id\":1,\"thread_priority\":5");
+ }
+
+ @Test
+ void shouldLogTimestampDifferently() {
+ // GIVEN
+ LambdaJsonEncoder encoder = new LambdaJsonEncoder();
+ String pattern = "yyyy-MM-dd_HH";
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
+ encoder.setTimestampFormat(pattern);
+ encoder.setTimestampFormatTimezoneId("Europe/Paris");
+
+ // WHEN
+ Date date = new Date();
+ byte[] encoded = encoder.encode(loggingEvent);
+ String result = new String(encoded, StandardCharsets.UTF_8);
+
+ // THEN
+ assertThat(result).contains("\"timestamp\":\""+simpleDateFormat.format(date)+"\"");
+ }
+
+ @Test
+ void shouldLogException() {
+ // GIVEN
+ LambdaJsonEncoder encoder = new LambdaJsonEncoder();
+ encoder.start();
+ LoggingEvent errorloggingEvent = new LoggingEvent("fqcn", logger, Level.INFO, "Error", new IllegalStateException("Unexpected value"), null);
+
+ // WHEN
+ byte[] encoded = encoder.encode(errorloggingEvent);
+ String result = new String(encoded, StandardCharsets.UTF_8);
+
+ // THEN
+ assertThat(result).contains("\"message\":\"Error\",\"error\":{\"message\":\"Unexpected value\",\"name\":\"java.lang.IllegalStateException\",\"stack\":\"[software.amazon.lambda.powertools.logging.internal.LambdaJsonEncoderTest.shouldLogException");
+
+ // WHEN (configure a custom throwableConverter)
+ encoder = new LambdaJsonEncoder();
+ RootCauseFirstThrowableProxyConverter throwableConverter = new RootCauseFirstThrowableProxyConverter();
+ encoder.setThrowableConverter(throwableConverter);
+ encoder.start();
+ encoded = encoder.encode(errorloggingEvent);
+ result = new String(encoded, StandardCharsets.UTF_8);
+
+ // THEN (stack is logged with root cause first)
+ assertThat(result).contains("\"message\":\"Error\",\"error\":{\"message\":\"Unexpected value\",\"name\":\"java.lang.IllegalStateException\",\"stack\":\"java.lang.IllegalStateException: Unexpected value\n");
+ }
+
+ private void setupContext() {
+ when(context.getFunctionName()).thenReturn("testFunction");
+ when(context.getInvokedFunctionArn()).thenReturn(
+ "arn:aws:lambda:eu-west-1:012345678910:function:testFunction:1");
+ when(context.getFunctionVersion()).thenReturn("1");
+ when(context.getMemoryLimitInMB()).thenReturn(1024);
+ when(context.getAwsRequestId()).thenReturn("RequestId");
+ }
+}
diff --git a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
new file mode 100644
index 000000000..982ee86b7
--- /dev/null
+++ b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package software.amazon.lambda.powertools.logging.internal;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.contentOf;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.openMocks;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import java.io.File;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junitpioneer.jupiter.SetEnvironmentVariable;
+import org.mockito.Mock;
+import org.slf4j.MDC;
+import software.amazon.lambda.powertools.logging.internal.handler.PowertoolsLogEnabled;
+
+@Order(1)
+class LambdaLoggingAspectTest {
+
+ @Mock
+ private Context context;
+
+ @BeforeEach
+ void setUp() throws IOException {
+ openMocks(this);
+ MDC.clear();
+ setupContext();
+ //Make sure file is cleaned up before running full stack logging regression
+ try {
+ FileChannel.open(Paths.get("target/logfile.json"), StandardOpenOption.WRITE).truncate(0).close();
+ } catch (NoSuchFileException e) {
+ // file might not be there for the first run
+ }
+ }
+
+ @AfterEach
+ void cleanUp() throws IOException {
+// FileChannel.open(Paths.get("target/logfile.json"), StandardOpenOption.WRITE).truncate(0).close();
+ }
+
+ @Test
+ @SetEnvironmentVariable(key = "POWERTOOLS_SERVICE_NAME", value = "testLogback")
+ void testSlf4jBinding() {
+ PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
+ handler.handleRequest("Input", context);
+
+ File logFile = new File("target/logfile.json");
+ assertThat(contentOf(logFile))
+ .contains("slf4j.binding is set to ch.qos.logback.classic.spi.LogbackServiceProvider")
+ .contains("Loading software.amazon.lambda.powertools.logging.internal.LogbackLoggingManager");
+ }
+
+ private void setupContext() {
+ when(context.getFunctionName()).thenReturn("testFunction");
+ when(context.getInvokedFunctionArn()).thenReturn(
+ "arn:aws:lambda:eu-west-1:012345678910:function:testFunction:1");
+ when(context.getFunctionVersion()).thenReturn("1");
+ when(context.getMemoryLimitInMB()).thenReturn(1024);
+ when(context.getAwsRequestId()).thenReturn("RequestId");
+ }
+}
\ No newline at end of file
diff --git a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LogbackLoggingManagerTest.java b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LogbackLoggingManagerTest.java
deleted file mode 100644
index 2d70ab3ff..000000000
--- a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LogbackLoggingManagerTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package software.amazon.lambda.powertools.logging.internal;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.slf4j.event.Level.ERROR;
-import static org.slf4j.event.Level.INFO;
-import static org.slf4j.event.Level.WARN;
-
-import org.junit.jupiter.api.Order;
-import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.slf4j.event.Level;
-
-class LogbackLoggingManagerTest {
-
- private static Logger LOG = LoggerFactory.getLogger(LogbackLoggingManagerTest.class);
- private static Logger ROOT = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
-
- @Test
- @Order(1)
- void getLogLevel_shouldReturnConfiguredLogLevel() {
- LogbackLoggingManager manager = new LogbackLoggingManager();
- Level logLevel = manager.getLogLevel(LOG);
- assertThat(logLevel).isEqualTo(INFO);
-
- logLevel = manager.getLogLevel(ROOT);
- assertThat(logLevel).isEqualTo(WARN);
- }
-
- @Test
- @Order(2)
- void resetLogLevel() {
- LogbackLoggingManager manager = new LogbackLoggingManager();
- manager.resetLogLevel(ERROR);
-
- Level logLevel = manager.getLogLevel(LOG);
- assertThat(logLevel).isEqualTo(ERROR);
- }
-}
diff --git a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/handler/PowertoolsLogEnabled.java b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/handler/PowertoolsLogEnabled.java
new file mode 100644
index 000000000..faa722756
--- /dev/null
+++ b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/handler/PowertoolsLogEnabled.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package software.amazon.lambda.powertools.logging.internal.handler;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.RequestHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import software.amazon.lambda.powertools.logging.Logging;
+import software.amazon.lambda.powertools.logging.LoggingUtils;
+
+public class PowertoolsLogEnabled implements RequestHandler {
+ private final Logger LOG = LoggerFactory.getLogger(PowertoolsLogEnabled.class);
+
+ @Override
+ @Logging(clearState = true)
+ public Object handleRequest(Object input, Context context) {
+ LoggingUtils.appendKey("myKey", "myValue");
+ LOG.debug("Test debug event");
+ return null;
+ }
+}
diff --git a/powertools-logging/powertools-logging-logback/src/test/resources/junit-platform.properties b/powertools-logging/powertools-logging-logback/src/test/resources/junit-platform.properties
new file mode 100644
index 000000000..80a2481d7
--- /dev/null
+++ b/powertools-logging/powertools-logging-logback/src/test/resources/junit-platform.properties
@@ -0,0 +1,17 @@
+#
+# Copyright 2023 Amazon.com, Inc. or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+# http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+
+# because of LambdaLoggingAspect static initialization of the LoggingManager, we need to
+# set an order in the unit tests, especially LambdaLoggingAspectTest needs to be first
+junit.jupiter.testclass.order.default=org.junit.jupiter.api.ClassOrderer$OrderAnnotation
\ No newline at end of file
diff --git a/powertools-logging/powertools-logging-logback/src/test/resources/logback-test.xml b/powertools-logging/powertools-logging-logback/src/test/resources/logback-test.xml
index 116833c3f..7afc74026 100644
--- a/powertools-logging/powertools-logging-logback/src/test/resources/logback-test.xml
+++ b/powertools-logging/powertools-logging-logback/src/test/resources/logback-test.xml
@@ -1,13 +1,27 @@
-
+
-
-
+
+ target/logfile.json
+
+
+
+
+
+ target/ecslogfile.json
+
+
+
+
+
+
+
-
+
+
\ No newline at end of file
From 788dc97a95d5f672f97048221b55b57ebd5e3aa9 Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Thu, 21 Sep 2023 23:23:12 +0200
Subject: [PATCH 30/74] fixe timezone
---
.../powertools/logging/internal/LambdaJsonEncoderTest.java | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonEncoderTest.java b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonEncoderTest.java
index c579e3b7c..c2d11e162 100644
--- a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonEncoderTest.java
+++ b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonEncoderTest.java
@@ -34,6 +34,7 @@
import java.nio.file.StandardOpenOption;
import java.text.SimpleDateFormat;
import java.util.Date;
+import java.util.TimeZone;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order;
@@ -140,9 +141,9 @@ void shouldLogTimestampDifferently() {
// GIVEN
LambdaJsonEncoder encoder = new LambdaJsonEncoder();
String pattern = "yyyy-MM-dd_HH";
- SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
+ String timeZone = "Europe/Paris";
encoder.setTimestampFormat(pattern);
- encoder.setTimestampFormatTimezoneId("Europe/Paris");
+ encoder.setTimestampFormatTimezoneId(timeZone);
// WHEN
Date date = new Date();
@@ -150,6 +151,8 @@ void shouldLogTimestampDifferently() {
String result = new String(encoded, StandardCharsets.UTF_8);
// THEN
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
+ simpleDateFormat.setTimeZone(TimeZone.getTimeZone(timeZone));
assertThat(result).contains("\"timestamp\":\""+simpleDateFormat.format(date)+"\"");
}
From 895843e737b572df3258ff86c23c6b6631f3b1d0 Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Fri, 22 Sep 2023 09:30:48 +0200
Subject: [PATCH 31/74] fix checkstyle
---
.../resolver/PowertoolsResolverFactory.java | 3 ++
.../logging/internal/Log4jLoggingManager.java | 9 +++++
.../powertools/logging/LambdaEcsEncoder.java | 16 ++++++--
.../powertools/logging/LambdaJsonEncoder.java | 13 +++++--
.../logging/internal/JsonUtils.java | 18 ++++++---
.../internal/LambdaJsonSerializer.java | 6 ++-
.../internal/LogbackLoggingManager.java | 9 +++++
.../lambda/powertools/logging/Logging.java | 12 ++++--
.../logging/internal/LambdaLoggingAspect.java | 38 ++++++++++++-------
.../logging/internal/LoggingManager.java | 6 ++-
.../internal/PowertoolsLoggedFields.java | 4 +-
11 files changed, 101 insertions(+), 33 deletions(-)
diff --git a/powertools-logging/powertools-logging-log4j/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/PowertoolsResolverFactory.java b/powertools-logging/powertools-logging-log4j/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/PowertoolsResolverFactory.java
index 14d4f67aa..297c00691 100644
--- a/powertools-logging/powertools-logging-log4j/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/PowertoolsResolverFactory.java
+++ b/powertools-logging/powertools-logging-log4j/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/PowertoolsResolverFactory.java
@@ -18,6 +18,9 @@
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+/**
+ * Factory for {@link PowertoolsResolver}. Log4j plugin to process powertools fields in the layout.json
+ */
@Plugin(name = "PowertoolsResolverFactory", category = TemplateResolverFactory.CATEGORY)
public final class PowertoolsResolverFactory implements EventResolverFactory {
diff --git a/powertools-logging/powertools-logging-log4j/src/main/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManager.java b/powertools-logging/powertools-logging-log4j/src/main/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManager.java
index 1b49a1fb3..a086ff596 100644
--- a/powertools-logging/powertools-logging-log4j/src/main/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManager.java
+++ b/powertools-logging/powertools-logging-log4j/src/main/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManager.java
@@ -20,8 +20,14 @@
import org.apache.logging.log4j.core.config.Configurator;
import org.slf4j.Logger;
+/**
+ * LoggingManager for Log4j2 (see {@link LoggingManager}).
+ */
public class Log4jLoggingManager implements LoggingManager {
+ /**
+ * @inheritDoc
+ */
@Override
@SuppressWarnings("java:S4792")
public void resetLogLevel(org.slf4j.event.Level logLevel) {
@@ -30,6 +36,9 @@ public void resetLogLevel(org.slf4j.event.Level logLevel) {
ctx.updateLoggers();
}
+ /**
+ * @inheritDoc
+ */
@Override
public org.slf4j.event.Level getLogLevel(Logger logger) {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
diff --git a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaEcsEncoder.java b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaEcsEncoder.java
index f83a43ef4..4124180f0 100644
--- a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaEcsEncoder.java
+++ b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaEcsEncoder.java
@@ -59,9 +59,15 @@ public byte[] headerBytes() {
return null;
}
+ /**
+ * Main method of the encoder. Encode a logging event into Json format (with Elastic Search fields)
+ *
+ * @param event the logging event
+ * @return the encoded bytes
+ */
@Override
public byte[] encode(ILoggingEvent event) {
- Map mdcPropertyMap = event.getMDCPropertyMap();
+ final Map mdcPropertyMap = event.getMDCPropertyMap();
StringBuilder builder = new StringBuilder(256);
LambdaEcsSerializer.serializeObjectStart(builder);
@@ -118,7 +124,8 @@ public byte[] footerBytes() {
}
/**
- * Specify a throwable converter to format the stacktrace according to your need (default is null, no throwableConverter):
+ * Specify a throwable converter to format the stacktrace according to your need
+ * (default is null, no throwableConverter):
*
*
- * @param throwableConverter
+ *
+ * @param throwableConverter converter for the throwable
*/
public void setThrowableConverter(ThrowableHandlingConverter throwableConverter) {
this.throwableConverter = throwableConverter;
@@ -156,6 +164,7 @@ public void setThrowableConverter(ThrowableHandlingConverter throwableConverter)
* false
*
* }
+ *
* @param includeCloudInfo if thread information should be logged
*/
public void setIncludeCloudInfo(boolean includeCloudInfo) {
@@ -181,6 +190,7 @@ public void setIncludeCloudInfo(boolean includeCloudInfo) {
* false
*
* }
+ *
* @param includeFaasInfo if function information should be logged
*/
public void setIncludeFaasInfo(boolean includeFaasInfo) {
diff --git a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaJsonEncoder.java b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaJsonEncoder.java
index 2a901ebd4..a007045de 100644
--- a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaJsonEncoder.java
+++ b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaJsonEncoder.java
@@ -26,7 +26,8 @@
/**
* Custom encoder for logback that encodes logs in JSON format.
- * It does not use a JSON library but a custom serializer ({@link LambdaJsonSerializer}) to reduce the weight of the library.
+ * It does not use a JSON library but a custom serializer ({@link LambdaJsonSerializer})
+ * to reduce the weight of the library.
*/
public class LambdaJsonEncoder extends EncoderBase {
@@ -94,6 +95,7 @@ public byte[] footerBytes() {
* yyyy-MM-dd'T'HH:mm:ss.SSSZz
*
* }
+ *
* @param timestampFormat format of the timestamp (compatible with {@link java.text.SimpleDateFormat})
*/
public void setTimestampFormat(String timestampFormat) {
@@ -108,6 +110,7 @@ public void setTimestampFormat(String timestampFormat) {
* Europe/Paris
*
* }
+ *
* @param timestampFormatTimezoneId Zone Id (see {@link java.util.TimeZone})
*/
public void setTimestampFormatTimezoneId(String timestampFormatTimezoneId) {
@@ -115,7 +118,8 @@ public void setTimestampFormatTimezoneId(String timestampFormatTimezoneId) {
}
/**
- * Specify a throwable converter to format the stacktrace according to your need (default is null, no throwableConverter):
+ * Specify a throwable converter to format the stacktrace according to your need
+ * (default is null, no throwableConverter):
*
*
- * @param throwableConverter
+ *
+ * @param throwableConverter converter for the throwable
*/
public void setThrowableConverter(ThrowableHandlingConverter throwableConverter) {
this.throwableConverter = throwableConverter;
@@ -145,6 +150,7 @@ public void setThrowableConverter(ThrowableHandlingConverter throwableConverter)
* true
*
* }
+ *
* @param includeThreadInfo if thread information should be logged
*/
public void setIncludeThreadInfo(boolean includeThreadInfo) {
@@ -172,6 +178,7 @@ public void setIncludeThreadInfo(boolean includeThreadInfo) {
* false
*
* }
+ *
* @param includePowertoolsInfo if function information should be logged
*/
public void setIncludePowertoolsInfo(boolean includePowertoolsInfo) {
diff --git a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/JsonUtils.java b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/JsonUtils.java
index fd895092b..a31782b8e 100644
--- a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/JsonUtils.java
+++ b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/JsonUtils.java
@@ -14,8 +14,15 @@
package software.amazon.lambda.powertools.logging.internal;
+/**
+ * Json tools to serialize attributes manually, to avoid using further dependencies (jackson, gson...)
+ */
public class JsonUtils {
+ private JsonUtils() {
+ // static utils
+ }
+
protected static void serializeAttribute(StringBuilder builder, String attr, String value, boolean notBegin) {
if (value != null) {
if (notBegin) {
@@ -33,6 +40,10 @@ protected static void serializeAttribute(StringBuilder builder, String attr, Str
}
}
+ protected static void serializeAttribute(StringBuilder builder, String attr, String value) {
+ serializeAttribute(builder, attr, value, true);
+ }
+
protected static void serializeAttributeAsString(StringBuilder builder, String attr, String value,
boolean notBegin) {
if (value != null) {
@@ -47,16 +58,13 @@ protected static void serializeAttributeAsString(StringBuilder builder, String a
}
}
- protected static void serializeAttribute(StringBuilder builder, String attr, String value) {
- serializeAttribute(builder, attr, value, true);
- }
-
protected static void serializeAttributeAsString(StringBuilder builder, String attr, String value) {
serializeAttributeAsString(builder, attr, value, true);
}
/**
- * As MDC is a Map, we need to check the type to output numbers and booleans correctly (without quotes)
+ * As MDC is a {@code Map}, we need to check the type
+ * to output numbers and booleans correctly (without quotes)
*/
private static boolean isString(String str) {
if (str == null) {
diff --git a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonSerializer.java b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonSerializer.java
index a2a6c2029..c7738340c 100644
--- a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonSerializer.java
+++ b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonSerializer.java
@@ -107,10 +107,12 @@ public static void serializeThreadPriority(StringBuilder builder, String threadP
serializeAttribute(builder, THREAD_PRIORITY_ATTR_NAME, threadPriority);
}
- public static void serializePowertools(StringBuilder builder, Map mdc, boolean includePowertoolsInfo) {
+ public static void serializePowertools(StringBuilder builder, Map mdc,
+ boolean includePowertoolsInfo) {
TreeMap sortedMap = new TreeMap<>(mdc);
sortedMap.forEach((k, v) -> {
- if ((PowertoolsLoggedFields.stringValues().contains(k) && includePowertoolsInfo) || !PowertoolsLoggedFields.stringValues().contains(k)) {
+ if ((PowertoolsLoggedFields.stringValues().contains(k) && includePowertoolsInfo)
+ || !PowertoolsLoggedFields.stringValues().contains(k)) {
serializeAttribute(builder, k, v);
}
});
diff --git a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LogbackLoggingManager.java b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LogbackLoggingManager.java
index 222adf7e8..d010e2977 100644
--- a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LogbackLoggingManager.java
+++ b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LogbackLoggingManager.java
@@ -21,6 +21,9 @@
import org.slf4j.ILoggerFactory;
import org.slf4j.LoggerFactory;
+/**
+ * LoggingManager for Logback (see {@link LoggingManager}).
+ */
public class LogbackLoggingManager implements LoggingManager {
private final LoggerContext loggerContext;
@@ -33,6 +36,9 @@ public LogbackLoggingManager() {
loggerContext = (LoggerContext) loggerFactory;
}
+ /**
+ * @inheritDoc
+ */
@Override
@SuppressWarnings("java:S4792")
public void resetLogLevel(org.slf4j.event.Level logLevel) {
@@ -42,6 +48,9 @@ public void resetLogLevel(org.slf4j.event.Level logLevel) {
}
}
+ /**
+ * @inheritDoc
+ */
@Override
public org.slf4j.event.Level getLogLevel(org.slf4j.Logger logger) {
return org.slf4j.event.Level.valueOf(loggerContext.getLogger(logger.getName()).getEffectiveLevel().toString());
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/Logging.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/Logging.java
index 0790452cc..818b85ec9 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/Logging.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/Logging.java
@@ -37,7 +37,8 @@
*
function_name
*
function_version
*
function_arn
- *
MemoryLimitInMB
+ *
function_memory_size
+ *
function_request_id
*
*
*
By default {@code Logging} will also create keys for:
@@ -56,17 +57,20 @@
*
By default {@code Logging} will not log the event which has trigger the invoke of the Lambda function.
* This can be enabled using {@code @Logging(logEvent = true)}.
*
- *
By default {@code Logging} all debug logs will follow log4j2 configuration unless configured via
- * POWERTOOLS_LOGGER_SAMPLE_RATE environment variable {@code @Logging(samplingRate = <0.0-1.0>)}.
- *
*
To append additional keys to each log entry you can use {@link LoggingUtils#appendKey(String, String)}
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Logging {
+ /**
+ * Set to true if you want to log the event received by the Lambda function handler
+ */
boolean logEvent() default false;
+ /**
+ * Sampling rate to change log level to DEBUG. (values must be >=0.0, <=1.0)
+ */
double samplingRate() default 0;
/**
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
index c5fec317d..054b46201 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
@@ -93,6 +93,7 @@ private static LoggingManager loadLoggingManager() {
*
*
*
+ *
* @return an instance of {@link LoggingManager} or null
*/
private static Optional getLoggingManagerFromSlf4jBinding() {
@@ -115,18 +116,26 @@ private static Optional getLoggingManagerFromSlf4jBinding() {
.loadClass(managerClass);
loggingManager = (LoggingManager) log4backManagerClass.newInstance();
} else {
- LOG.warn("slf4j.binding {} not supported, fallback to Service Loader. " +
- "Only log4j and logback are supported.", slf4jBinding);
+ LOG.warn("slf4j.binding {} not supported, fallback to Service Loader. "
+ + "Only log4j and logback are supported.", slf4jBinding);
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
- LOG.warn("Could not instantiate LoggingManager based on slf4j.binding {}, " +
- "make sure to add either powertools-logging-log4j or powertools-logging-logback module",
+ LOG.warn("Could not instantiate LoggingManager based on slf4j.binding {}, "
+ + "make sure to add either powertools-logging-log4j or powertools-logging-logback module",
slf4jBinding);
}
}
return Optional.ofNullable(loggingManager);
}
+ /**
+ * Use {@link ServiceLoader} to lookup for a {@link LoggingManager}.
+ * A file software.amazon.lambda.powertools.logging.internal.LoggingManager must be created in
+ * META-INF/services/ folder with the appropriate implementation of the {@link LoggingManager}
+ *
+ * @return an instance of {@link LoggingManager}
+ * @throws IllegalStateException if no {@link LoggingManager} could be found
+ */
private static LoggingManager getLoggingManagerFromServiceLoader() {
LoggingManager loggingManager;
@@ -136,12 +145,12 @@ private static LoggingManager getLoggingManagerFromServiceLoader() {
loggingManagerList.add(lm);
}
if (loggingManagerList.isEmpty()) {
- throw new IllegalStateException("No LoggingManager was found on the classpath, " +
- "make sure to add either powertools-logging-log4j or powertools-logging-logback to your dependencies");
+ throw new IllegalStateException("No LoggingManager was found on the classpath, "
+ + "make sure to add either powertools-logging-log4j or powertools-logging-logback to your dependencies");
} else if (loggingManagerList.size() > 1) {
throw new IllegalStateException(
- "Multiple LoggingManagers were found on the classpath: " + loggingManagerList +
- ", make sure to have only one of powertools-logging-log4j OR powertools-logging-logback to your dependencies");
+ "Multiple LoggingManagers were found on the classpath: " + loggingManagerList
+ + ", make sure to have only one of powertools-logging-log4j OR powertools-logging-logback to your dependencies");
} else {
loggingManager = loggingManagerList.get(0);
}
@@ -157,6 +166,9 @@ private static void resetLogLevels(Level logLevel) {
public void callAt(Logging logging) {
}
+ /**
+ * Main method of the aspect
+ */
@Around(value = "callAt(logging) && execution(@Logging * *.*(..))", argNames = "pjp,logging")
public Object around(ProceedingJoinPoint pjp,
Logging logging) throws Throwable {
@@ -215,8 +227,8 @@ private void setLogLevelBasedOnSamplingRate(final ProceedingJoinPoint pjp,
if (samplingRate > sample) {
resetLogLevels(Level.DEBUG);
- LOG.debug("Changed log level to DEBUG based on Sampling configuration. " +
- "Sampling Rate: {}, Sampler Value: {}.", samplingRate, sample);
+ LOG.debug("Changed log level to DEBUG based on Sampling configuration. "
+ + "Sampling Rate: {}, Sampler Value: {}.", samplingRate, sample);
} else if (LEVEL_AT_INITIALISATION != loggingManager.getLogLevel(LOG)) {
resetLogLevels(LEVEL_AT_INITIALISATION);
}
@@ -229,8 +241,8 @@ private double samplingRate(final Logging logging) {
try {
return Double.parseDouble(sampleRate);
} catch (NumberFormatException e) {
- LOG.warn("Skipping sampling rate on environment variable configuration because of invalid " +
- "value. Sampling rate: {}", sampleRate);
+ LOG.warn("Skipping sampling rate on environment variable configuration because of invalid "
+ + "value. Sampling rate: {}", sampleRate);
}
}
return logging.samplingRate();
@@ -311,7 +323,7 @@ private Object[] logFromInputStream(final ProceedingJoinPoint pjp) {
private byte[] bytesFromInputStreamSafely(final InputStream inputStream) throws IOException {
try (ByteArrayOutputStream out = new ByteArrayOutputStream();
- InputStreamReader reader = new InputStreamReader(inputStream, UTF_8)) {
+ InputStreamReader reader = new InputStreamReader(inputStream, UTF_8)) {
OutputStreamWriter writer = new OutputStreamWriter(out, UTF_8);
int n;
char[] buffer = new char[4096];
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LoggingManager.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LoggingManager.java
index 1f4a4e636..a141910cb 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LoggingManager.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LoggingManager.java
@@ -25,7 +25,8 @@
*
*
* Implementations are provided in submodules and loaded thanks to a {@link java.util.ServiceLoader}
- * (define a file named software.amazon.lambda.powertools.logging.internal.LoggingManager in src/main/resources/META-INF/services with the qualified name of the implementation).
+ * (define a file named software.amazon.lambda.powertools.logging.internal.LoggingManager
+ * in src/main/resources/META-INF/services with the qualified name of the implementation).
*/
public interface LoggingManager {
/**
@@ -39,7 +40,8 @@ public interface LoggingManager {
* Retrieve the log Level of a specific logger
*
* @param logger the logger (slf4j) for which to retrieve the log Level
- * @return the Level (slf4j) of this logger. Note that SLF4J only support ERROR, WARN, INFO, DEBUG, TRACE while some frameworks may support others (OFF, FATAL, ...)
+ * @return the Level (slf4j) of this logger.
+ * Note that SLF4J only support ERROR, WARN, INFO, DEBUG, TRACE while some frameworks may support others (OFF, FATAL, ...)
*/
Level getLogLevel(Logger logger);
}
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/PowertoolsLoggedFields.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/PowertoolsLoggedFields.java
index 1c64248f9..686c8c0c2 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/PowertoolsLoggedFields.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/PowertoolsLoggedFields.java
@@ -21,6 +21,9 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
+/**
+ * Fields added in the logs by Powertools
+ */
public enum PowertoolsLoggedFields {
FUNCTION_NAME("function_name"),
FUNCTION_VERSION("function_version"),
@@ -42,7 +45,6 @@ public static List stringValues() {
return Stream.of(values()).map(PowertoolsLoggedFields::getName).collect(Collectors.toList());
}
-
static Map setValuesFromLambdaContext(Context context) {
Map hashMap = new HashMap<>();
From e5e3f187d81ce27398b4d2547d16f48f2b65562e Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Fri, 22 Sep 2023 10:10:31 +0200
Subject: [PATCH 32/74] improve correlationId: - use jmespath for correlationId
- add appsync + test - rename constant
---
docs/core/logging.md | 2 +-
...Constants.java => CorrelationIdPaths.java} | 14 ++++---
.../lambda/powertools/logging/Logging.java | 3 +-
.../logging/internal/LambdaLoggingAspect.java | 5 ++-
.../PowertoolsLogAlbCorrelationId.java | 2 +-
...oolsLogApiGatewayHttpApiCorrelationId.java | 2 +-
...oolsLogApiGatewayRestApiCorrelationId.java | 2 +-
.../PowertoolsLogAppSyncCorrelationId.java | 37 +++++++++++++++++++
...PowertoolsLogEventBridgeCorrelationId.java | 2 +-
.../internal/LambdaLoggingAspectTest.java | 15 +++++++-
10 files changed, 70 insertions(+), 14 deletions(-)
rename powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/{CorrelationIdPathConstants.java => CorrelationIdPaths.java} (69%)
create mode 100644 powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogAppSyncCorrelationId.java
diff --git a/docs/core/logging.md b/docs/core/logging.md
index 58e907906..9d4b73588 100644
--- a/docs/core/logging.md
+++ b/docs/core/logging.md
@@ -357,7 +357,7 @@ for known event sources, where either a request ID or X-Ray Trace ID are present
=== "App.java"
```java hl_lines="10"
- import software.amazon.lambda.powertools.logging.CorrelationIdPathConstants;
+ import software.amazon.lambda.powertools.logging.CorrelationIdPaths;
/**
* Handler for requests to Lambda function.
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/CorrelationIdPathConstants.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/CorrelationIdPaths.java
similarity index 69%
rename from powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/CorrelationIdPathConstants.java
rename to powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/CorrelationIdPaths.java
index ce43c9aa0..6fb38502f 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/CorrelationIdPathConstants.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/CorrelationIdPaths.java
@@ -17,21 +17,25 @@
/**
* Supported Event types from which Correlation ID can be extracted
*/
-public class CorrelationIdPathConstants {
+public class CorrelationIdPaths {
/**
* To use when function is expecting API Gateway Rest API Request event
*/
- public static final String API_GATEWAY_REST = "/requestContext/requestId";
+ public static final String API_GATEWAY_REST = "requestContext.requestId";
/**
* To use when function is expecting API Gateway HTTP API Request event
*/
- public static final String API_GATEWAY_HTTP = "/requestContext/requestId";
+ public static final String API_GATEWAY_HTTP = "requestContext.requestId";
/**
* To use when function is expecting Application Load balancer Request event
*/
- public static final String APPLICATION_LOAD_BALANCER = "/headers/x-amzn-trace-id";
+ public static final String APPLICATION_LOAD_BALANCER = "headers.\"x-amzn-trace-id\"";
/**
* To use when function is expecting Event Bridge Request event
*/
- public static final String EVENT_BRIDGE = "/id";
+ public static final String EVENT_BRIDGE = "id";
+ /**
+ * To use when function is expecting an AppSync request
+ */
+ public static final String APPSYNC_RESOLVER = "request.headers.\"x-amzn-trace-id\"";
}
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/Logging.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/Logging.java
index 818b85ec9..b9eab7da0 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/Logging.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/Logging.java
@@ -64,7 +64,8 @@
public @interface Logging {
/**
- * Set to true if you want to log the event received by the Lambda function handler
+ * Set to true if you want to log the event received by the Lambda function handler.
+ * Can also be configured with the 'POWERTOOLS_LOGGER_LOG_EVENT' environment variable
*/
boolean logEvent() default false;
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
index 054b46201..aebb6ab1d 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
@@ -32,9 +32,9 @@
import static software.amazon.lambda.powertools.logging.internal.PowertoolsLoggedFields.SERVICE;
import com.amazonaws.services.lambda.runtime.Context;
-import com.fasterxml.jackson.core.JsonPointer;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
+import io.burt.jmespath.Expression;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -292,7 +292,8 @@ private Object[] captureCorrelationId(final String correlationIdPath,
}
private void setCorrelationIdFromNode(String correlationIdPath, ProceedingJoinPoint pjp, JsonNode jsonNode) {
- JsonNode node = jsonNode.at(JsonPointer.compile(correlationIdPath));
+ Expression jmesExpression = JsonConfig.get().getJmesPath().compile(correlationIdPath);
+ JsonNode node = jmesExpression.search(jsonNode);
String asText = node.asText();
if (null != asText && !asText.isEmpty()) {
diff --git a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogAlbCorrelationId.java b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogAlbCorrelationId.java
index 021caf185..065d4c5b0 100644
--- a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogAlbCorrelationId.java
+++ b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogAlbCorrelationId.java
@@ -14,7 +14,7 @@
package software.amazon.lambda.powertools.logging.handlers;
-import static software.amazon.lambda.powertools.logging.CorrelationIdPathConstants.APPLICATION_LOAD_BALANCER;
+import static software.amazon.lambda.powertools.logging.CorrelationIdPaths.APPLICATION_LOAD_BALANCER;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
diff --git a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogApiGatewayHttpApiCorrelationId.java b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogApiGatewayHttpApiCorrelationId.java
index 010e68f0f..922a09f13 100644
--- a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogApiGatewayHttpApiCorrelationId.java
+++ b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogApiGatewayHttpApiCorrelationId.java
@@ -14,7 +14,7 @@
package software.amazon.lambda.powertools.logging.handlers;
-import static software.amazon.lambda.powertools.logging.CorrelationIdPathConstants.API_GATEWAY_HTTP;
+import static software.amazon.lambda.powertools.logging.CorrelationIdPaths.API_GATEWAY_HTTP;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
diff --git a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogApiGatewayRestApiCorrelationId.java b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogApiGatewayRestApiCorrelationId.java
index f0be69ae3..7271e1d24 100644
--- a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogApiGatewayRestApiCorrelationId.java
+++ b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogApiGatewayRestApiCorrelationId.java
@@ -14,7 +14,7 @@
package software.amazon.lambda.powertools.logging.handlers;
-import static software.amazon.lambda.powertools.logging.CorrelationIdPathConstants.API_GATEWAY_REST;
+import static software.amazon.lambda.powertools.logging.CorrelationIdPaths.API_GATEWAY_REST;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
diff --git a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogAppSyncCorrelationId.java b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogAppSyncCorrelationId.java
new file mode 100644
index 000000000..fbe2bc89b
--- /dev/null
+++ b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogAppSyncCorrelationId.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package software.amazon.lambda.powertools.logging.handlers;
+
+import static software.amazon.lambda.powertools.logging.CorrelationIdPaths.APPSYNC_RESOLVER;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import software.amazon.lambda.powertools.logging.Logging;
+
+public class PowertoolsLogAppSyncCorrelationId implements RequestStreamHandler {
+
+ private final Logger LOG = LoggerFactory.getLogger(PowertoolsLogAppSyncCorrelationId.class);
+
+ @Override
+ @Logging(correlationIdPath = APPSYNC_RESOLVER)
+ public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
+ LOG.info("Test event");
+ }
+}
\ No newline at end of file
diff --git a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogEventBridgeCorrelationId.java b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogEventBridgeCorrelationId.java
index 9f12247cd..04d56d38c 100644
--- a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogEventBridgeCorrelationId.java
+++ b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/handlers/PowertoolsLogEventBridgeCorrelationId.java
@@ -14,7 +14,7 @@
package software.amazon.lambda.powertools.logging.handlers;
-import static software.amazon.lambda.powertools.logging.CorrelationIdPathConstants.EVENT_BRIDGE;
+import static software.amazon.lambda.powertools.logging.CorrelationIdPaths.EVENT_BRIDGE;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
diff --git a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
index 6d568f544..bd0d61ba6 100644
--- a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
+++ b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
@@ -64,6 +64,7 @@
import software.amazon.lambda.powertools.logging.handlers.PowertoolsLogAlbCorrelationId;
import software.amazon.lambda.powertools.logging.handlers.PowertoolsLogApiGatewayHttpApiCorrelationId;
import software.amazon.lambda.powertools.logging.handlers.PowertoolsLogApiGatewayRestApiCorrelationId;
+import software.amazon.lambda.powertools.logging.handlers.PowertoolsLogAppSyncCorrelationId;
import software.amazon.lambda.powertools.logging.handlers.PowertoolsLogClearState;
import software.amazon.lambda.powertools.logging.handlers.PowertoolsLogDisabled;
import software.amazon.lambda.powertools.logging.handlers.PowertoolsLogDisabledForStream;
@@ -314,10 +315,22 @@ void shouldLogCorrelationIdOnALBEvent(ApplicationLoadBalancerRequestEvent event)
void shouldLogCorrelationIdOnStreamHandler() throws IOException {
RequestStreamHandler handler = new PowertoolsLogEventBridgeCorrelationId();
String eventId = "3";
- String event = "{\"id\":" + eventId + "}"; // CorrelationIdPathConstants.EVENT_BRIDGE
+ String event = "{\"id\":" + eventId + "}"; // CorrelationIdPath.EVENT_BRIDGE
ByteArrayInputStream inputStream = new ByteArrayInputStream(event.getBytes());
handler.handleRequest(inputStream, new ByteArrayOutputStream(), context);
+ assertThat(MDC.getCopyOfContextMap())
+ .hasSize(EXPECTED_CONTEXT_SIZE + 1)
+ .containsEntry("correlation_id", eventId);
+ }
+
+ @Test
+ void shouldLogCorrelationIdOnAppSyncEvent() throws IOException {
+ RequestStreamHandler handler = new PowertoolsLogAppSyncCorrelationId();
+ String eventId = "456";
+ String event = "{\"request\":{\"headers\":{\"x-amzn-trace-id\":" + eventId + "}}}"; // CorrelationIdPath.APPSYNC_RESOLVER
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(event.getBytes());
+ handler.handleRequest(inputStream, new ByteArrayOutputStream(), context);
assertThat(MDC.getCopyOfContextMap())
.hasSize(EXPECTED_CONTEXT_SIZE + 1)
From e13876b3a058cca2abe4a6acefc07ea210c94255 Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Fri, 22 Sep 2023 10:52:37 +0200
Subject: [PATCH 33/74] add support for environment variable
POWERTOOLS_LOGGER_LOG_EVENT
---
powertools-logging/pom.xml | 5 --
.../logging/internal/LambdaLoggingAspect.java | 5 +-
.../internal/LambdaLoggingAspectTest.java | 69 ++++++++++++++-----
3 files changed, 53 insertions(+), 26 deletions(-)
diff --git a/powertools-logging/pom.xml b/powertools-logging/pom.xml
index c042a8240..1a2db6a3e 100644
--- a/powertools-logging/pom.xml
+++ b/powertools-logging/pom.xml
@@ -89,11 +89,6 @@
junit-jupiter-enginetest
-
- org.junit-pioneer
- junit-pioneer
- test
- org.apache.commonscommons-lang3
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
index aebb6ab1d..ff2ee72ff 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
@@ -56,6 +56,7 @@
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.slf4j.event.Level;
+import software.amazon.lambda.powertools.common.internal.SystemWrapper;
import software.amazon.lambda.powertools.logging.Logging;
import software.amazon.lambda.powertools.logging.LoggingUtils;
import software.amazon.lambda.powertools.utilities.JsonConfig;
@@ -186,7 +187,7 @@ public Object around(ProceedingJoinPoint pjp,
getXrayTraceId().ifPresent(xRayTraceId -> appendKey(FUNCTION_TRACE_ID.getName(), xRayTraceId));
- if (logging.logEvent()) {
+ if (logging.logEvent() || "true".equals(SystemWrapper.getenv("POWERTOOLS_LOGGER_LOG_EVENT"))) {
proceedArgs = logEvent(pjp);
}
@@ -236,7 +237,7 @@ private void setLogLevelBasedOnSamplingRate(final ProceedingJoinPoint pjp,
}
private double samplingRate(final Logging logging) {
- String sampleRate = System.getenv("POWERTOOLS_LOGGER_SAMPLE_RATE");
+ String sampleRate = SystemWrapper.getenv("POWERTOOLS_LOGGER_SAMPLE_RATE");
if (null != sampleRate) {
try {
return Double.parseDouble(sampleRate);
diff --git a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
index bd0d61ba6..b7df0118f 100644
--- a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
+++ b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
@@ -46,6 +46,7 @@
import java.lang.reflect.Method;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
+import java.nio.file.NoSuchFileException;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Collections;
@@ -53,8 +54,6 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
-import org.junitpioneer.jupiter.ClearEnvironmentVariable;
-import org.junitpioneer.jupiter.SetEnvironmentVariable;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.slf4j.MDC;
@@ -86,8 +85,7 @@ class LambdaLoggingAspectTest {
private Context context;
@BeforeEach
- @ClearEnvironmentVariable(key = "POWERTOOLS_LOGGER_SAMPLE_RATE")
- void setUp() throws IllegalAccessException, IOException, NoSuchMethodException, InvocationTargetException {
+ void setUp() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, IOException {
openMocks(this);
MDC.clear();
writeStaticField(LambdaHandlerProcessor.class, "IS_COLD_START", null, true);
@@ -95,6 +93,11 @@ void setUp() throws IllegalAccessException, IOException, NoSuchMethodException,
requestHandler = new PowertoolsLogEnabled();
requestStreamHandler = new PowertoolsLogEnabledForStream();
resetLogLevel(Level.INFO);
+ try {
+ FileChannel.open(Paths.get("target/logfile.json"), StandardOpenOption.WRITE).truncate(0).close();
+ } catch (NoSuchFileException e) {
+ // may not be there in the first run
+ }
}
@AfterEach
@@ -188,29 +191,42 @@ void shouldLogDebugWhenSamplingEqualsOne() {
}
@Test
- @SetEnvironmentVariable(key = "POWERTOOLS_LOGGER_SAMPLE_RATE", value = "1")
void shouldLogDebugWhenSamplingEnvVarEqualsOne() {
- PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
- handler.handleRequest(new Object(), context);
- File logFile = new File("target/logfile.json");
- assertThat(contentOf(logFile)).contains("Test debug event");
+ try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
+ mocked.when(() -> getenv("POWERTOOLS_LOGGER_SAMPLE_RATE"))
+ .thenReturn("1");
+
+ PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
+ handler.handleRequest(new Object(), context);
+ File logFile = new File("target/logfile.json");
+ assertThat(contentOf(logFile)).contains("Test debug event");
+ }
}
@Test
- @SetEnvironmentVariable(key = "POWERTOOLS_LOGGER_SAMPLE_RATE", value = "42")
void shouldNotLogDebugWhenSamplingEnvVarIsTooBig() {
- requestHandler.handleRequest(new Object(), context);
- File logFile = new File("target/logfile.json");
- assertThat(contentOf(logFile)).doesNotContain("Test debug event");
+ try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
+ mocked.when(() -> getenv("POWERTOOLS_LOGGER_SAMPLE_RATE"))
+ .thenReturn("42");
+
+ requestHandler.handleRequest(new Object(), context);
+ File logFile = new File("target/logfile.json");
+ assertThat(contentOf(logFile)).doesNotContain("Test debug event");
+ }
}
@Test
- @SetEnvironmentVariable(key = "POWERTOOLS_LOGGER_SAMPLE_RATE", value = "NotANumber")
void shouldNotLogDebugWhenSamplingEnvVarIsInvalid() {
- requestHandler.handleRequest(new Object(), context);
- File logFile = new File("target/logfile.json");
- assertThat(contentOf(logFile)).doesNotContain("Test debug event");
- assertThat(contentOf(logFile)).contains("Skipping sampling rate on environment variable configuration because of invalid value");
+ try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
+ mocked.when(() -> getenv("POWERTOOLS_LOGGER_SAMPLE_RATE"))
+ .thenReturn("NotANumber");
+
+ requestHandler.handleRequest(new Object(), context);
+ File logFile = new File("target/logfile.json");
+ assertThat(contentOf(logFile)).doesNotContain("Test debug event");
+ assertThat(contentOf(logFile)).contains(
+ "Skipping sampling rate on environment variable configuration because of invalid value");
+ }
}
@Test
@@ -256,7 +272,7 @@ void shouldLogxRayTraceIdEnvVarSet() {
}
@Test
- void shouldLogEventForHandler() throws IOException {
+ void shouldLogEventForHandlerWithLogEventAnnotation() {
requestHandler = new PowertoolsLogEvent();
requestHandler.handleRequest(Collections.singletonList("ListOfOneElement"), context);
@@ -265,6 +281,21 @@ void shouldLogEventForHandler() throws IOException {
assertThat(contentOf(logFile)).contains("[\"ListOfOneElement\"]");
}
+ @Test
+ void shouldLogEventForHandlerWithLogEventEnvVar() {
+ requestHandler = new PowertoolsLogEnabled();
+
+ try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
+ mocked.when(() -> getenv("POWERTOOLS_LOGGER_LOG_EVENT"))
+ .thenReturn("true");
+
+ requestHandler.handleRequest(Collections.singletonList("ListOfOneElement"), context);
+
+ File logFile = new File("target/logfile.json");
+ assertThat(contentOf(logFile)).contains("[\"ListOfOneElement\"]");
+ }
+ }
+
@Test
void shouldLogEventForStreamHandler() throws IOException {
requestStreamHandler = new PowertoolsLogEventForStream();
From 988d46e7e8778af5dea312c512280b392d748a41 Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Fri, 22 Sep 2023 11:40:38 +0200
Subject: [PATCH 34/74] load env var at init
---
.../logging/internal/LambdaLoggingAspect.java | 8 +-
.../internal/LambdaLoggingAspectTest.java | 113 ++++++++++++------
2 files changed, 83 insertions(+), 38 deletions(-)
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
index ff2ee72ff..3f53ef67d 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
@@ -56,7 +56,6 @@
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.slf4j.event.Level;
-import software.amazon.lambda.powertools.common.internal.SystemWrapper;
import software.amazon.lambda.powertools.logging.Logging;
import software.amazon.lambda.powertools.logging.LoggingUtils;
import software.amazon.lambda.powertools.utilities.JsonConfig;
@@ -69,6 +68,9 @@ public final class LambdaLoggingAspect {
private static final Random SAMPLER = new Random();
private static final String LOG_LEVEL = System.getenv("POWERTOOLS_LOG_LEVEL");
private static final LoggingManager loggingManager;
+
+ private static String LOG_EVENT = System.getenv("POWERTOOLS_LOGGER_LOG_EVENT"); /* not final for test purpose */
+ private static String SAMPLING_RATE = System.getenv("POWERTOOLS_LOGGER_SAMPLE_RATE"); /* not final for test purpose */
private static Level LEVEL_AT_INITIALISATION; /* not final for test purpose */
static {
@@ -187,7 +189,7 @@ public Object around(ProceedingJoinPoint pjp,
getXrayTraceId().ifPresent(xRayTraceId -> appendKey(FUNCTION_TRACE_ID.getName(), xRayTraceId));
- if (logging.logEvent() || "true".equals(SystemWrapper.getenv("POWERTOOLS_LOGGER_LOG_EVENT"))) {
+ if (logging.logEvent() || "true".equals(LOG_EVENT)) {
proceedArgs = logEvent(pjp);
}
@@ -237,7 +239,7 @@ private void setLogLevelBasedOnSamplingRate(final ProceedingJoinPoint pjp,
}
private double samplingRate(final Logging logging) {
- String sampleRate = SystemWrapper.getenv("POWERTOOLS_LOGGER_SAMPLE_RATE");
+ String sampleRate = SAMPLING_RATE;
if (null != sampleRate) {
try {
return Double.parseDouble(sampleRate);
diff --git a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
index b7df0118f..d7d6b1775 100644
--- a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
+++ b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
@@ -93,6 +93,8 @@ void setUp() throws IllegalAccessException, NoSuchMethodException, InvocationTar
requestHandler = new PowertoolsLogEnabled();
requestStreamHandler = new PowertoolsLogEnabledForStream();
resetLogLevel(Level.INFO);
+ writeStaticField(LambdaLoggingAspect.class, "LOG_EVENT", null, true);
+ writeStaticField(LambdaLoggingAspect.class, "SAMPLING_RATE", null, true);
try {
FileChannel.open(Paths.get("target/logfile.json"), StandardOpenOption.WRITE).truncate(0).close();
} catch (NoSuchFileException e) {
@@ -186,58 +188,66 @@ void shouldClearStateWhenClearStateIsTrue() {
@Test
void shouldLogDebugWhenSamplingEqualsOne() {
PowertoolsLogSamplingEnabled handler = new PowertoolsLogSamplingEnabled();
+
Boolean debugEnabled = handler.handleRequest(new Object(), context);
+
assertThat(debugEnabled).isTrue();
}
@Test
- void shouldLogDebugWhenSamplingEnvVarEqualsOne() {
- try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
- mocked.when(() -> getenv("POWERTOOLS_LOGGER_SAMPLE_RATE"))
- .thenReturn("1");
+ void shouldLogDebugWhenSamplingEnvVarEqualsOne() throws IllegalAccessException {
+ // GIVEN
+ writeStaticField(LambdaLoggingAspect.class, "SAMPLING_RATE", "1", true);
+ PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
- PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
- handler.handleRequest(new Object(), context);
- File logFile = new File("target/logfile.json");
- assertThat(contentOf(logFile)).contains("Test debug event");
- }
+ // WHEN
+ handler.handleRequest(new Object(), context);
+
+ // THEN
+ File logFile = new File("target/logfile.json");
+ assertThat(contentOf(logFile)).contains("Test debug event");
}
@Test
- void shouldNotLogDebugWhenSamplingEnvVarIsTooBig() {
- try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
- mocked.when(() -> getenv("POWERTOOLS_LOGGER_SAMPLE_RATE"))
- .thenReturn("42");
+ void shouldNotLogDebugWhenSamplingEnvVarIsTooBig() throws IllegalAccessException {
+ // GIVEN
+ writeStaticField(LambdaLoggingAspect.class, "SAMPLING_RATE", "42", true);
- requestHandler.handleRequest(new Object(), context);
- File logFile = new File("target/logfile.json");
- assertThat(contentOf(logFile)).doesNotContain("Test debug event");
- }
+ // WHEN
+ requestHandler.handleRequest(new Object(), context);
+
+ // THEN
+ File logFile = new File("target/logfile.json");
+ assertThat(contentOf(logFile)).doesNotContain("Test debug event");
}
@Test
- void shouldNotLogDebugWhenSamplingEnvVarIsInvalid() {
- try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
- mocked.when(() -> getenv("POWERTOOLS_LOGGER_SAMPLE_RATE"))
- .thenReturn("NotANumber");
+ void shouldNotLogDebugWhenSamplingEnvVarIsInvalid() throws IllegalAccessException {
+ // GIVEN
+ writeStaticField(LambdaLoggingAspect.class, "SAMPLING_RATE", "NotANumber", true);
+ // WHEN
requestHandler.handleRequest(new Object(), context);
- File logFile = new File("target/logfile.json");
- assertThat(contentOf(logFile)).doesNotContain("Test debug event");
- assertThat(contentOf(logFile)).contains(
- "Skipping sampling rate on environment variable configuration because of invalid value");
- }
+
+ // THEN
+ File logFile = new File("target/logfile.json");
+ assertThat(contentOf(logFile)).doesNotContain("Test debug event");
+ assertThat(contentOf(logFile)).contains(
+ "Skipping sampling rate on environment variable configuration because of invalid value");
}
@Test
void shouldNotLogDebugWhenSamplingEqualsZero() {
PowertoolsLogSamplingDisabled handler = new PowertoolsLogSamplingDisabled();
+
Boolean debugEnabled = handler.handleRequest(new Object(), context);
+
assertThat(debugEnabled).isFalse();
}
@Test
void shouldHaveNoEffectIfNotUsedOnLambdaHandler() {
+ // GIVEN
PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
handler.anotherMethod();
@@ -247,9 +257,13 @@ void shouldHaveNoEffectIfNotUsedOnLambdaHandler() {
@Test
void shouldLogServiceNameWhenEnvVarSet() throws IllegalAccessException {
+ // GIVEN
writeStaticField(LambdaHandlerProcessor.class, "SERVICE_NAME", "testService", true);
+
+ // WHEN
requestHandler.handleRequest(new Object(), context);
+ // THEN
assertThat(MDC.getCopyOfContextMap())
.hasSize(EXPECTED_CONTEXT_SIZE)
.containsEntry(SERVICE.getName(), "testService");
@@ -257,14 +271,17 @@ void shouldLogServiceNameWhenEnvVarSet() throws IllegalAccessException {
@Test
void shouldLogxRayTraceIdEnvVarSet() {
+ // GIVEN
String xRayTraceId = "1-5759e988-bd862e3fe1be46a994272793";
try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
mocked.when(() -> getenv("_X_AMZN_TRACE_ID"))
.thenReturn("Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1\"");
+ // WHEN
requestHandler.handleRequest(new Object(), context);
+ // THEN
assertThat(MDC.getCopyOfContextMap())
.hasSize(EXPECTED_CONTEXT_SIZE + 1)
.containsEntry(FUNCTION_TRACE_ID.getName(), xRayTraceId);
@@ -273,35 +290,41 @@ void shouldLogxRayTraceIdEnvVarSet() {
@Test
void shouldLogEventForHandlerWithLogEventAnnotation() {
+ // GIVEN
requestHandler = new PowertoolsLogEvent();
+ // WHEN
requestHandler.handleRequest(Collections.singletonList("ListOfOneElement"), context);
+ // THEN
File logFile = new File("target/logfile.json");
assertThat(contentOf(logFile)).contains("[\"ListOfOneElement\"]");
}
@Test
- void shouldLogEventForHandlerWithLogEventEnvVar() {
+ void shouldLogEventForHandlerWithLogEventEnvVar() throws IllegalAccessException {
+ // GIVEN
+ writeStaticField(LambdaLoggingAspect.class, "LOG_EVENT", "true", true);
requestHandler = new PowertoolsLogEnabled();
- try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
- mocked.when(() -> getenv("POWERTOOLS_LOGGER_LOG_EVENT"))
- .thenReturn("true");
-
- requestHandler.handleRequest(Collections.singletonList("ListOfOneElement"), context);
+ // WHEN
+ requestHandler.handleRequest(Collections.singletonList("ListOfOneElement"), context);
- File logFile = new File("target/logfile.json");
- assertThat(contentOf(logFile)).contains("[\"ListOfOneElement\"]");
- }
+ // THEN
+ File logFile = new File("target/logfile.json");
+ assertThat(contentOf(logFile)).contains("[\"ListOfOneElement\"]");
}
@Test
void shouldLogEventForStreamHandler() throws IOException {
+ // GIVEN
requestStreamHandler = new PowertoolsLogEventForStream();
ByteArrayOutputStream output = new ByteArrayOutputStream();
+
+ // WHEN
requestStreamHandler.handleRequest(new ByteArrayInputStream(new ObjectMapper().writeValueAsBytes(Collections.singletonMap("key", "value"))), output, context);
+ // THEN
assertThat(new String(output.toByteArray(), StandardCharsets.UTF_8))
.isNotEmpty();
@@ -312,9 +335,13 @@ void shouldLogEventForStreamHandler() throws IOException {
@ParameterizedTest
@Event(value = "apiGatewayProxyEventV1.json", type = APIGatewayProxyRequestEvent.class)
void shouldLogCorrelationIdOnAPIGatewayProxyRequestEvent(APIGatewayProxyRequestEvent event) {
+ // GIVEN
RequestHandler handler = new PowertoolsLogApiGatewayRestApiCorrelationId();
+
+ // WHEN
handler.handleRequest(event, context);
+ // THEN
assertThat(MDC.getCopyOfContextMap())
.hasSize(EXPECTED_CONTEXT_SIZE + 1)
.containsEntry("correlation_id", event.getRequestContext().getRequestId());
@@ -323,9 +350,13 @@ void shouldLogCorrelationIdOnAPIGatewayProxyRequestEvent(APIGatewayProxyRequestE
@ParameterizedTest
@Event(value = "apiGatewayProxyEventV2.json", type = APIGatewayV2HTTPEvent.class)
void shouldLogCorrelationIdOnAPIGatewayV2HTTPEvent(APIGatewayV2HTTPEvent event) {
+ // GIVEN
RequestHandler handler = new PowertoolsLogApiGatewayHttpApiCorrelationId();
+
+ // WHEN
handler.handleRequest(event, context);
+ // THEN
assertThat(MDC.getCopyOfContextMap())
.hasSize(EXPECTED_CONTEXT_SIZE + 1)
.containsEntry("correlation_id", event.getRequestContext().getRequestId());
@@ -334,9 +365,13 @@ void shouldLogCorrelationIdOnAPIGatewayV2HTTPEvent(APIGatewayV2HTTPEvent event)
@ParameterizedTest
@Event(value = "albEvent.json", type = ApplicationLoadBalancerRequestEvent.class)
void shouldLogCorrelationIdOnALBEvent(ApplicationLoadBalancerRequestEvent event) {
+ // GIVEN
RequestHandler handler = new PowertoolsLogAlbCorrelationId();
+
+ // WHEN
handler.handleRequest(event, context);
+ // THEN
assertThat(MDC.getCopyOfContextMap())
.hasSize(EXPECTED_CONTEXT_SIZE + 1)
.containsEntry("correlation_id", event.getHeaders().get("x-amzn-trace-id"));
@@ -344,12 +379,16 @@ void shouldLogCorrelationIdOnALBEvent(ApplicationLoadBalancerRequestEvent event)
@Test
void shouldLogCorrelationIdOnStreamHandler() throws IOException {
+ // GIVEN
RequestStreamHandler handler = new PowertoolsLogEventBridgeCorrelationId();
String eventId = "3";
String event = "{\"id\":" + eventId + "}"; // CorrelationIdPath.EVENT_BRIDGE
ByteArrayInputStream inputStream = new ByteArrayInputStream(event.getBytes());
+
+ // WHEN
handler.handleRequest(inputStream, new ByteArrayOutputStream(), context);
+ // THEN
assertThat(MDC.getCopyOfContextMap())
.hasSize(EXPECTED_CONTEXT_SIZE + 1)
.containsEntry("correlation_id", eventId);
@@ -357,12 +396,16 @@ void shouldLogCorrelationIdOnStreamHandler() throws IOException {
@Test
void shouldLogCorrelationIdOnAppSyncEvent() throws IOException {
+ // GIVEN
RequestStreamHandler handler = new PowertoolsLogAppSyncCorrelationId();
String eventId = "456";
String event = "{\"request\":{\"headers\":{\"x-amzn-trace-id\":" + eventId + "}}}"; // CorrelationIdPath.APPSYNC_RESOLVER
ByteArrayInputStream inputStream = new ByteArrayInputStream(event.getBytes());
+
+ // WHEN
handler.handleRequest(inputStream, new ByteArrayOutputStream(), context);
+ // THEN
assertThat(MDC.getCopyOfContextMap())
.hasSize(EXPECTED_CONTEXT_SIZE + 1)
.containsEntry("correlation_id", eventId);
From 4a5d790079d48596e43dd3f36df2ca272bde74c2 Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Fri, 22 Sep 2023 12:14:08 +0200
Subject: [PATCH 35/74] remove junit-pioneer and mock env var
---
.../powertools-logging-log4j/pom.xml | 5 --
.../json/resolver/PowertoolsResolver.java | 3 +-
.../PowerToolsResolverFactoryTest.java | 49 ++++++++++++-------
.../json/resolver/PowertoolsResolverTest.java | 15 ++++--
.../internal/LambdaLoggingAspectTest.java | 23 ++++++---
.../powertools-logging-logback/pom.xml | 5 --
.../internal/LambdaEcsEncoderTest.java | 26 ++++++----
.../internal/LambdaJsonEncoderTest.java | 30 +++++++-----
.../internal/LambdaLoggingAspectTest.java | 23 ++++++---
.../logging/internal/LambdaLoggingAspect.java | 2 +-
10 files changed, 112 insertions(+), 69 deletions(-)
diff --git a/powertools-logging/powertools-logging-log4j/pom.xml b/powertools-logging/powertools-logging-log4j/pom.xml
index 3a9157271..3b14a0c66 100644
--- a/powertools-logging/powertools-logging-log4j/pom.xml
+++ b/powertools-logging/powertools-logging-log4j/pom.xml
@@ -117,11 +117,6 @@
jsonasserttest
-
- org.junit-pioneer
- junit-pioneer
- test
-
diff --git a/powertools-logging/powertools-logging-log4j/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/PowertoolsResolver.java b/powertools-logging/powertools-logging-log4j/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/PowertoolsResolver.java
index a02173c6b..327ed615b 100644
--- a/powertools-logging/powertools-logging-log4j/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/PowertoolsResolver.java
+++ b/powertools-logging/powertools-logging-log4j/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/PowertoolsResolver.java
@@ -18,6 +18,7 @@
import org.apache.logging.log4j.layout.template.json.util.JsonWriter;
import org.apache.logging.log4j.util.ReadOnlyStringMap;
import software.amazon.lambda.powertools.common.internal.LambdaConstants;
+import software.amazon.lambda.powertools.common.internal.SystemWrapper;
import software.amazon.lambda.powertools.logging.internal.PowertoolsLoggedFields;
/**
@@ -131,7 +132,7 @@ public void resolve(LogEvent logEvent, JsonWriter jsonWriter) {
private static final EventResolver REGION_RESOLVER =
(final LogEvent logEvent, final JsonWriter jsonWriter) ->
- jsonWriter.writeString(System.getenv(LambdaConstants.AWS_REGION_ENV));
+ jsonWriter.writeString(SystemWrapper.getenv(LambdaConstants.AWS_REGION_ENV));
private static final EventResolver ACCOUNT_ID_RESOLVER = new EventResolver() {
@Override
diff --git a/powertools-logging/powertools-logging-log4j/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/PowerToolsResolverFactoryTest.java b/powertools-logging/powertools-logging-log4j/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/PowerToolsResolverFactoryTest.java
index 29e063382..1f5c858af 100644
--- a/powertools-logging/powertools-logging-log4j/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/PowerToolsResolverFactoryTest.java
+++ b/powertools-logging/powertools-logging-log4j/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/PowerToolsResolverFactoryTest.java
@@ -17,8 +17,10 @@
import static org.apache.commons.lang3.reflect.FieldUtils.writeStaticField;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.contentOf;
+import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.openMocks;
+import static software.amazon.lambda.powertools.common.internal.SystemWrapper.getenv;
import com.amazonaws.services.lambda.runtime.Context;
import java.io.File;
@@ -31,10 +33,12 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
-import org.junitpioneer.jupiter.SetEnvironmentVariable;
import org.mockito.Mock;
+import org.mockito.MockedStatic;
import org.slf4j.MDC;
import software.amazon.lambda.powertools.common.internal.LambdaHandlerProcessor;
+import software.amazon.lambda.powertools.common.internal.SystemWrapper;
+import software.amazon.lambda.powertools.logging.internal.LambdaLoggingAspect;
import software.amazon.lambda.powertools.logging.internal.handler.PowertoolsLogEnabled;
@Order(2)
@@ -56,6 +60,7 @@ void setUp() throws IllegalAccessException, IOException {
} catch (NoSuchFileException e) {
// file may not exist on the first launch
}
+ writeStaticField(LambdaLoggingAspect.class, "SAMPLING_RATE", null, true);
}
@AfterEach
@@ -65,28 +70,38 @@ void cleanUp() throws IOException{
}
@Test
- @SetEnvironmentVariable(key = "POWERTOOLS_LOGGER_SAMPLE_RATE", value = "0.000000001")
- @SetEnvironmentVariable(key = "_X_AMZN_TRACE_ID", value = "Root=1-63441c4a-abcdef012345678912345678")
- void shouldLogInJsonFormat() {
- PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
- handler.handleRequest("Input", context);
+ void shouldLogInJsonFormat() throws IllegalAccessException {
+ try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
+ mocked.when(() -> getenv("_X_AMZN_TRACE_ID"))
+ .thenReturn("Root=1-63441c4a-abcdef012345678912345678");
- File logFile = new File("target/logfile.json");
- assertThat(contentOf(logFile)).contains(
- "{\"level\":\"DEBUG\",\"message\":\"Test debug event\",\"cold_start\":true,\"function_arn\":\"arn:aws:lambda:eu-west-1:012345678910:function:testFunction:1\",\"function_memory_size\":1024,\"function_name\":\"testFunction\",\"function_request_id\":\"RequestId\",\"function_version\":\"1\",\"sampling_rate\":1.0E-9,\"service\":\"testLog4j\",\"timestamp\":")
- .contains("\"xray_trace_id\":\"1-63441c4a-abcdef012345678912345678\",\"myKey\":\"myValue\"}\n");
+ writeStaticField(LambdaLoggingAspect.class, "SAMPLING_RATE", "0.000000001", true);
+
+ PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
+ handler.handleRequest("Input", context);
+
+ File logFile = new File("target/logfile.json");
+ assertThat(contentOf(logFile)).contains(
+ "{\"level\":\"DEBUG\",\"message\":\"Test debug event\",\"cold_start\":true,\"function_arn\":\"arn:aws:lambda:eu-west-1:012345678910:function:testFunction:1\",\"function_memory_size\":1024,\"function_name\":\"testFunction\",\"function_request_id\":\"RequestId\",\"function_version\":\"1\",\"sampling_rate\":1.0E-9,\"service\":\"testLog4j\",\"timestamp\":")
+ .contains("\"xray_trace_id\":\"1-63441c4a-abcdef012345678912345678\",\"myKey\":\"myValue\"}\n");
+ }
}
@Test
- @SetEnvironmentVariable(key = "AWS_REGION", value = "eu-central-1")
- @SetEnvironmentVariable(key = "_X_AMZN_TRACE_ID", value = "Root=1-63441c4a-abcdef012345678912345678")
void shouldLogInEcsFormat() {
- PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
- handler.handleRequest("Input", context);
+ try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
+ mocked.when(() -> getenv("_X_AMZN_TRACE_ID"))
+ .thenReturn("Root=1-63441c4a-abcdef012345678912345678");
+ mocked.when(() -> getenv("AWS_REGION"))
+ .thenReturn("eu-central-1");
- File logFile = new File("target/ecslogfile.json");
- assertThat(contentOf(logFile)).contains(
- "\"ecs.version\":\"1.2.0\",\"log.level\":\"DEBUG\",\"message\":\"Test debug event\",\"service.name\":\"testLog4j\",\"service.version\":\"1\",\"log.logger\":\"software.amazon.lambda.powertools.logging.internal.handler.PowertoolsLogEnabled\",\"process.thread.name\":\"main\",\"cloud.provider\":\"aws\",\"cloud.service.name\":\"lambda\",\"cloud.region\":\"eu-central-1\",\"cloud.account.id\":\"012345678910\",\"faas.id\":\"arn:aws:lambda:eu-west-1:012345678910:function:testFunction:1\",\"faas.name\":\"testFunction\",\"faas.version\":\"1\",\"faas.memory\":1024,\"faas.execution\":\"RequestId\",\"faas.coldstart\":true,\"trace.id\":\"1-63441c4a-abcdef012345678912345678\",\"myKey\":\"myValue\"}\n");
+ PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
+ handler.handleRequest("Input", context);
+
+ File logFile = new File("target/ecslogfile.json");
+ assertThat(contentOf(logFile)).contains(
+ "\"ecs.version\":\"1.2.0\",\"log.level\":\"DEBUG\",\"message\":\"Test debug event\",\"service.name\":\"testLog4j\",\"service.version\":\"1\",\"log.logger\":\"software.amazon.lambda.powertools.logging.internal.handler.PowertoolsLogEnabled\",\"process.thread.name\":\"main\",\"cloud.provider\":\"aws\",\"cloud.service.name\":\"lambda\",\"cloud.region\":\"eu-central-1\",\"cloud.account.id\":\"012345678910\",\"faas.id\":\"arn:aws:lambda:eu-west-1:012345678910:function:testFunction:1\",\"faas.name\":\"testFunction\",\"faas.version\":\"1\",\"faas.memory\":1024,\"faas.execution\":\"RequestId\",\"faas.coldstart\":true,\"trace.id\":\"1-63441c4a-abcdef012345678912345678\",\"myKey\":\"myValue\"}\n");
+ }
}
private void setupContext() {
diff --git a/powertools-logging/powertools-logging-log4j/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/PowertoolsResolverTest.java b/powertools-logging/powertools-logging-log4j/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/PowertoolsResolverTest.java
index 89380d703..bbe6f6b75 100644
--- a/powertools-logging/powertools-logging-log4j/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/PowertoolsResolverTest.java
+++ b/powertools-logging/powertools-logging-log4j/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/PowertoolsResolverTest.java
@@ -15,6 +15,8 @@
package org.apache.logging.log4j.layout.template.json.resolver;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mockStatic;
+import static software.amazon.lambda.powertools.common.internal.SystemWrapper.getenv;
import static software.amazon.lambda.powertools.logging.internal.PowertoolsLoggedFields.FUNCTION_ARN;
import static software.amazon.lambda.powertools.logging.internal.PowertoolsLoggedFields.FUNCTION_COLD_START;
import static software.amazon.lambda.powertools.logging.internal.PowertoolsLoggedFields.FUNCTION_MEMORY_SIZE;
@@ -29,7 +31,8 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
-import org.junitpioneer.jupiter.SetEnvironmentVariable;
+import org.mockito.MockedStatic;
+import software.amazon.lambda.powertools.common.internal.SystemWrapper;
import software.amazon.lambda.powertools.logging.internal.PowertoolsLoggedFields;
class PowertoolsResolverTest {
@@ -68,10 +71,14 @@ void shouldResolveAccountId() {
}
@Test
- @SetEnvironmentVariable(key = "AWS_REGION", value = "eu-central-2")
void shouldResolveRegion() {
- String result = resolveField("region", "dummy, will use the env var");
- assertThat(result).isEqualTo("\"eu-central-2\"");
+ try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
+ mocked.when(() -> getenv("AWS_REGION"))
+ .thenReturn("eu-central-2");
+
+ String result = resolveField("region", "dummy, will use the env var");
+ assertThat(result).isEqualTo("\"eu-central-2\"");
+ }
}
private static String resolveField(String field, String value) {
diff --git a/powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java b/powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
index f7563e2de..3f3272aa6 100644
--- a/powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
+++ b/powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
@@ -16,8 +16,10 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.contentOf;
+import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.openMocks;
+import static software.amazon.lambda.powertools.common.internal.SystemWrapper.getenv;
import com.amazonaws.services.lambda.runtime.Context;
import java.io.File;
@@ -30,9 +32,10 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
-import org.junitpioneer.jupiter.SetEnvironmentVariable;
import org.mockito.Mock;
+import org.mockito.MockedStatic;
import org.slf4j.MDC;
+import software.amazon.lambda.powertools.common.internal.SystemWrapper;
import software.amazon.lambda.powertools.logging.internal.handler.PowertoolsLogEnabled;
@Order(1)
@@ -60,15 +63,19 @@ void cleanUp() throws IOException {
}
@Test
- @SetEnvironmentVariable(key = "POWERTOOLS_SERVICE_NAME", value = "testLog4j")
void testSlf4jBinding() {
- PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
- handler.handleRequest("Input", context);
+ try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
+ mocked.when(() -> getenv("POWERTOOLS_SERVICE_NAME"))
+ .thenReturn("testLog4j");
- File logFile = new File("target/logfile.json");
- assertThat(contentOf(logFile))
- .contains("slf4j.binding is set to org.apache.logging.slf4j.SLF4JServiceProvider")
- .contains("Loading software.amazon.lambda.powertools.logging.internal.Log4jLoggingManager");
+ PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
+ handler.handleRequest("Input", context);
+
+ File logFile = new File("target/logfile.json");
+ assertThat(contentOf(logFile))
+ .contains("slf4j.binding is set to org.apache.logging.slf4j.SLF4JServiceProvider")
+ .contains("Loading software.amazon.lambda.powertools.logging.internal.Log4jLoggingManager");
+ }
}
private void setupContext() {
diff --git a/powertools-logging/powertools-logging-logback/pom.xml b/powertools-logging/powertools-logging-logback/pom.xml
index 1fb473962..1628428b4 100644
--- a/powertools-logging/powertools-logging-logback/pom.xml
+++ b/powertools-logging/powertools-logging-logback/pom.xml
@@ -113,11 +113,6 @@
jsonasserttest
-
- org.junit-pioneer
- junit-pioneer
- test
-
diff --git a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsEncoderTest.java b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsEncoderTest.java
index 908c5fa40..b28d83a3e 100644
--- a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsEncoderTest.java
+++ b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsEncoderTest.java
@@ -17,8 +17,10 @@
import static org.apache.commons.lang3.reflect.FieldUtils.writeStaticField;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.contentOf;
+import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.openMocks;
+import static software.amazon.lambda.powertools.common.internal.SystemWrapper.getenv;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
@@ -36,11 +38,12 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
-import org.junitpioneer.jupiter.SetEnvironmentVariable;
import org.mockito.Mock;
+import org.mockito.MockedStatic;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import software.amazon.lambda.powertools.common.internal.LambdaHandlerProcessor;
+import software.amazon.lambda.powertools.common.internal.SystemWrapper;
import software.amazon.lambda.powertools.logging.LambdaEcsEncoder;
import software.amazon.lambda.powertools.logging.internal.handler.PowertoolsLogEnabled;
@@ -73,15 +76,20 @@ void cleanUp() throws IOException{
}
@Test
- @SetEnvironmentVariable(key = "AWS_REGION", value = "eu-central-1")
- @SetEnvironmentVariable(key = "_X_AMZN_TRACE_ID", value = "Root=1-63441c4a-abcdef012345678912345678")
void shouldLogInEcsFormat() {
- PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
- handler.handleRequest("Input", context);
-
- File logFile = new File("target/ecslogfile.json");
- assertThat(contentOf(logFile)).contains(
- "\"ecs.version\":\"1.2.0\",\"log.level\":\"DEBUG\",\"message\":\"Test debug event\",\"service.name\":\"testLogback\",\"service.version\":\"1\",\"log.logger\":\"software.amazon.lambda.powertools.logging.internal.handler.PowertoolsLogEnabled\",\"process.thread.name\":\"main\",\"cloud.provider\":\"aws\",\"cloud.service.name\":\"lambda\",\"cloud.region\":\"eu-west-1\",\"cloud.account.id\":\"012345678910\",\"faas.id\":\"arn:aws:lambda:eu-west-1:012345678910:function:testFunction:1\",\"faas.name\":\"testFunction\",\"faas.version\":\"1\",\"faas.memory\":\"1024\",\"faas.execution\":\"RequestId\",\"faas.coldstart\":\"true\",\"trace.id\":\"1-63441c4a-abcdef012345678912345678\",\"myKey\":\"myValue\"}\n");
+ try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
+ mocked.when(() -> getenv("_X_AMZN_TRACE_ID"))
+ .thenReturn("Root=1-63441c4a-abcdef012345678912345678");
+ mocked.when(() -> getenv("AWS_REGION"))
+ .thenReturn("eu-central-1");
+
+ PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
+ handler.handleRequest("Input", context);
+
+ File logFile = new File("target/ecslogfile.json");
+ assertThat(contentOf(logFile)).contains(
+ "\"ecs.version\":\"1.2.0\",\"log.level\":\"DEBUG\",\"message\":\"Test debug event\",\"service.name\":\"testLogback\",\"service.version\":\"1\",\"log.logger\":\"software.amazon.lambda.powertools.logging.internal.handler.PowertoolsLogEnabled\",\"process.thread.name\":\"main\",\"cloud.provider\":\"aws\",\"cloud.service.name\":\"lambda\",\"cloud.region\":\"eu-west-1\",\"cloud.account.id\":\"012345678910\",\"faas.id\":\"arn:aws:lambda:eu-west-1:012345678910:function:testFunction:1\",\"faas.name\":\"testFunction\",\"faas.version\":\"1\",\"faas.memory\":\"1024\",\"faas.execution\":\"RequestId\",\"faas.coldstart\":\"true\",\"trace.id\":\"1-63441c4a-abcdef012345678912345678\",\"myKey\":\"myValue\"}\n");
+ }
}
private final LoggingEvent loggingEvent = new LoggingEvent("fqcn", logger, Level.INFO, "message", null, null);
diff --git a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonEncoderTest.java b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonEncoderTest.java
index c2d11e162..661ec879b 100644
--- a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonEncoderTest.java
+++ b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonEncoderTest.java
@@ -17,8 +17,10 @@
import static org.apache.commons.lang3.reflect.FieldUtils.writeStaticField;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.contentOf;
+import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.openMocks;
+import static software.amazon.lambda.powertools.common.internal.SystemWrapper.getenv;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
@@ -39,11 +41,12 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
-import org.junitpioneer.jupiter.SetEnvironmentVariable;
import org.mockito.Mock;
+import org.mockito.MockedStatic;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import software.amazon.lambda.powertools.common.internal.LambdaHandlerProcessor;
+import software.amazon.lambda.powertools.common.internal.SystemWrapper;
import software.amazon.lambda.powertools.logging.LambdaJsonEncoder;
import software.amazon.lambda.powertools.logging.internal.handler.PowertoolsLogEnabled;
@@ -59,6 +62,7 @@ void setUp() throws IllegalAccessException, IOException {
openMocks(this);
MDC.clear();
writeStaticField(LambdaHandlerProcessor.class, "IS_COLD_START", null, true);
+ writeStaticField(LambdaLoggingAspect.class, "SAMPLING_RATE", null, true);
setupContext();
// Make sure file is cleaned up before running tests
try {
@@ -74,19 +78,23 @@ void cleanUp() throws IOException{
}
@Test
- @SetEnvironmentVariable(key = "POWERTOOLS_LOGGER_SAMPLE_RATE", value = "0.000000001")
- @SetEnvironmentVariable(key = "_X_AMZN_TRACE_ID", value = "Root=1-63441c4a-abcdef012345678912345678")
- void shouldLogInJsonFormat() {
+ void shouldLogInJsonFormat() throws IllegalAccessException {
// GIVEN
- PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
+ try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
+ mocked.when(() -> getenv("_X_AMZN_TRACE_ID"))
+ .thenReturn("Root=1-63441c4a-abcdef012345678912345678");
+ writeStaticField(LambdaLoggingAspect.class, "SAMPLING_RATE", "0.000000001", true);
- // WHEN
- handler.handleRequest("Input", context);
+ PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
- // THEN
- File logFile = new File("target/logfile.json");
- assertThat(contentOf(logFile)).contains(
- "{\"level\":\"DEBUG\",\"message\":\"Test debug event\",\"cold_start\":true,\"function_arn\":\"arn:aws:lambda:eu-west-1:012345678910:function:testFunction:1\",\"function_memory_size\":1024,\"function_name\":\"testFunction\",\"function_request_id\":\"RequestId\",\"function_version\":1,\"myKey\":\"myValue\",\"sampling_rate\":\"1.0E-9\",\"service\":\"testLogback\",\"xray_trace_id\":\"1-63441c4a-abcdef012345678912345678\",\"timestamp\":");
+ // WHEN
+ handler.handleRequest("Input", context);
+
+ // THEN
+ File logFile = new File("target/logfile.json");
+ assertThat(contentOf(logFile)).contains(
+ "{\"level\":\"DEBUG\",\"message\":\"Test debug event\",\"cold_start\":true,\"function_arn\":\"arn:aws:lambda:eu-west-1:012345678910:function:testFunction:1\",\"function_memory_size\":1024,\"function_name\":\"testFunction\",\"function_request_id\":\"RequestId\",\"function_version\":1,\"myKey\":\"myValue\",\"sampling_rate\":\"1.0E-9\",\"service\":\"testLogback\",\"xray_trace_id\":\"1-63441c4a-abcdef012345678912345678\",\"timestamp\":");
+ }
}
private final LoggingEvent loggingEvent = new LoggingEvent("fqcn", logger, Level.INFO, "message", null, null);
diff --git a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
index 982ee86b7..85615c4a6 100644
--- a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
+++ b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
@@ -16,8 +16,10 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.contentOf;
+import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.openMocks;
+import static software.amazon.lambda.powertools.common.internal.SystemWrapper.getenv;
import com.amazonaws.services.lambda.runtime.Context;
import java.io.File;
@@ -30,9 +32,10 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
-import org.junitpioneer.jupiter.SetEnvironmentVariable;
import org.mockito.Mock;
+import org.mockito.MockedStatic;
import org.slf4j.MDC;
+import software.amazon.lambda.powertools.common.internal.SystemWrapper;
import software.amazon.lambda.powertools.logging.internal.handler.PowertoolsLogEnabled;
@Order(1)
@@ -60,15 +63,19 @@ void cleanUp() throws IOException {
}
@Test
- @SetEnvironmentVariable(key = "POWERTOOLS_SERVICE_NAME", value = "testLogback")
void testSlf4jBinding() {
- PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
- handler.handleRequest("Input", context);
+ try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
+ mocked.when(() -> getenv("POWERTOOLS_SERVICE_NAME"))
+ .thenReturn("testLogback");
- File logFile = new File("target/logfile.json");
- assertThat(contentOf(logFile))
- .contains("slf4j.binding is set to ch.qos.logback.classic.spi.LogbackServiceProvider")
- .contains("Loading software.amazon.lambda.powertools.logging.internal.LogbackLoggingManager");
+ PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
+ handler.handleRequest("Input", context);
+
+ File logFile = new File("target/logfile.json");
+ assertThat(contentOf(logFile))
+ .contains("slf4j.binding is set to ch.qos.logback.classic.spi.LogbackServiceProvider")
+ .contains("Loading software.amazon.lambda.powertools.logging.internal.LogbackLoggingManager");
+ }
}
private void setupContext() {
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
index 3f53ef67d..adf4d8615 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
@@ -70,7 +70,7 @@ public final class LambdaLoggingAspect {
private static final LoggingManager loggingManager;
private static String LOG_EVENT = System.getenv("POWERTOOLS_LOGGER_LOG_EVENT"); /* not final for test purpose */
- private static String SAMPLING_RATE = System.getenv("POWERTOOLS_LOGGER_SAMPLE_RATE"); /* not final for test purpose */
+ public static String SAMPLING_RATE = System.getenv("POWERTOOLS_LOGGER_SAMPLE_RATE"); /* not final for test purpose */
private static Level LEVEL_AT_INITIALISATION; /* not final for test purpose */
static {
From 0853b88e442c44796012b083f1dcaa2e5e5e2786 Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Fri, 22 Sep 2023 13:11:45 +0200
Subject: [PATCH 36/74] sampling rate should be final, maybe
---
spotbugs-exclude.xml | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml
index 2b75444c9..ce6dfb803 100644
--- a/spotbugs-exclude.xml
+++ b/spotbugs-exclude.xml
@@ -80,6 +80,15 @@
+
+
+
+
+
+
+
+
+
From f6dcad82246afb12fed86b78770e3571e102fb0b Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Fri, 22 Sep 2023 13:15:27 +0200
Subject: [PATCH 37/74] sonar lint
---
.../powertools/logging/internal/LambdaEcsSerializer.java | 4 +++-
.../powertools/logging/internal/LambdaJsonSerializer.java | 3 ++-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsSerializer.java b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsSerializer.java
index 6bdc96221..fabccf18b 100644
--- a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsSerializer.java
+++ b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsSerializer.java
@@ -59,6 +59,8 @@ public class LambdaEcsSerializer {
protected static final String FUNCTION_MEMORY_ATTR_NAME = "faas.memory";
protected static final String FUNCTION_TRACE_ID_ATTR_NAME = "trace.id";
+ private LambdaEcsSerializer() {}
+
public static void serializeObjectStart(StringBuilder builder) {
builder.append('{');
}
@@ -97,7 +99,7 @@ public static void serializeLogLevel(StringBuilder builder, Level level) {
public static void serializeFormattedMessage(StringBuilder builder, String formattedMessage) {
serializeAttributeAsString(builder, FORMATTED_MESSAGE_ATTR_NAME,
- formattedMessage.replaceAll("\"", Matcher.quoteReplacement("\\\"")));
+ formattedMessage.replace("\"", Matcher.quoteReplacement("\\\"")));
}
public static void serializeException(StringBuilder builder, String className, String message, String stackTrace) {
diff --git a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonSerializer.java b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonSerializer.java
index c7738340c..7ac64f546 100644
--- a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonSerializer.java
+++ b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonSerializer.java
@@ -44,6 +44,7 @@ public class LambdaJsonSerializer {
protected static final String EXCEPTION_STACK_ATTR_NAME = "stack";
protected static final String EXCEPTION_ATTR_NAME = "error";
+ private LambdaJsonSerializer() {}
public static void serializeObjectStart(StringBuilder builder) {
builder.append('{');
@@ -83,7 +84,7 @@ public static void serializeLogLevel(StringBuilder builder, Level level) {
public static void serializeFormattedMessage(StringBuilder builder, String formattedMessage) {
serializeAttribute(builder, FORMATTED_MESSAGE_ATTR_NAME,
- formattedMessage.replaceAll("\"", Matcher.quoteReplacement("\\\"")));
+ formattedMessage.replace("\"", Matcher.quoteReplacement("\\\"")));
}
public static void serializeException(StringBuilder builder, String className, String message, String stackTrace) {
From 7ef955b53a0c5287aa286c221a1ca0ff05ba45d6 Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Wed, 27 Sep 2023 11:56:30 +0200
Subject: [PATCH 38/74] remove slf4j binding (does not improve perfs)
---
pom.xml | 4 +-
.../powertools-logging-log4j/pom.xml | 8 --
.../PowerToolsResolverFactoryTest.java | 6 +-
.../internal/LambdaLoggingAspectTest.java | 89 -------------------
.../powertools-logging-logback/pom.xml | 8 --
.../internal/LambdaLoggingAspectTest.java | 89 -------------------
.../logging/internal/LambdaLoggingAspect.java | 50 +----------
7 files changed, 8 insertions(+), 246 deletions(-)
delete mode 100644 powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
delete mode 100644 powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
diff --git a/pom.xml b/pom.xml
index 01b0a6de7..72c67c4db 100644
--- a/pom.xml
+++ b/pom.xml
@@ -74,8 +74,8 @@
1.81.82.20.0
- 2.0.4
- 2.15.3
+ 2.0.7
+ 2.15.21.9.72.21.02.14.0
diff --git a/powertools-logging/powertools-logging-log4j/pom.xml b/powertools-logging/powertools-logging-log4j/pom.xml
index 3b14a0c66..28d2ec9f6 100644
--- a/powertools-logging/powertools-logging-log4j/pom.xml
+++ b/powertools-logging/powertools-logging-log4j/pom.xml
@@ -151,14 +151,6 @@
-
- maven-surefire-plugin
-
-
- org.apache.logging.slf4j.SLF4JServiceProvider
-
-
- org.apache.maven.pluginsmaven-checkstyle-plugin
diff --git a/powertools-logging/powertools-logging-log4j/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/PowerToolsResolverFactoryTest.java b/powertools-logging/powertools-logging-log4j/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/PowerToolsResolverFactoryTest.java
index 1f5c858af..b48368d86 100644
--- a/powertools-logging/powertools-logging-log4j/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/PowerToolsResolverFactoryTest.java
+++ b/powertools-logging/powertools-logging-log4j/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/PowerToolsResolverFactoryTest.java
@@ -41,7 +41,7 @@
import software.amazon.lambda.powertools.logging.internal.LambdaLoggingAspect;
import software.amazon.lambda.powertools.logging.internal.handler.PowertoolsLogEnabled;
-@Order(2)
+@Order(1)
class PowerToolsResolverFactoryTest {
@Mock
@@ -74,6 +74,8 @@ void shouldLogInJsonFormat() throws IllegalAccessException {
try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
mocked.when(() -> getenv("_X_AMZN_TRACE_ID"))
.thenReturn("Root=1-63441c4a-abcdef012345678912345678");
+ mocked.when(() -> getenv("POWERTOOLS_SERVICE_NAME"))
+ .thenReturn("testLog4j");
writeStaticField(LambdaLoggingAspect.class, "SAMPLING_RATE", "0.000000001", true);
@@ -94,6 +96,8 @@ void shouldLogInEcsFormat() {
.thenReturn("Root=1-63441c4a-abcdef012345678912345678");
mocked.when(() -> getenv("AWS_REGION"))
.thenReturn("eu-central-1");
+ mocked.when(() -> getenv("POWERTOOLS_SERVICE_NAME"))
+ .thenReturn("testLog4j");
PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
handler.handleRequest("Input", context);
diff --git a/powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java b/powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
deleted file mode 100644
index 3f3272aa6..000000000
--- a/powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2023 Amazon.com, Inc. or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package software.amazon.lambda.powertools.logging.internal;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.contentOf;
-import static org.mockito.Mockito.mockStatic;
-import static org.mockito.Mockito.when;
-import static org.mockito.MockitoAnnotations.openMocks;
-import static software.amazon.lambda.powertools.common.internal.SystemWrapper.getenv;
-
-import com.amazonaws.services.lambda.runtime.Context;
-import java.io.File;
-import java.io.IOException;
-import java.nio.channels.FileChannel;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Order;
-import org.junit.jupiter.api.Test;
-import org.mockito.Mock;
-import org.mockito.MockedStatic;
-import org.slf4j.MDC;
-import software.amazon.lambda.powertools.common.internal.SystemWrapper;
-import software.amazon.lambda.powertools.logging.internal.handler.PowertoolsLogEnabled;
-
-@Order(1)
-class LambdaLoggingAspectTest {
-
- @Mock
- private Context context;
-
- @BeforeEach
- void setUp() throws IOException {
- openMocks(this);
- MDC.clear();
- setupContext();
- //Make sure file is cleaned up before running full stack logging regression
- try {
- FileChannel.open(Paths.get("target/logfile.json"), StandardOpenOption.WRITE).truncate(0).close();
- } catch (NoSuchFileException e) {
- // file might not be there for the first run
- }
- }
-
- @AfterEach
- void cleanUp() throws IOException {
- FileChannel.open(Paths.get("target/logfile.json"), StandardOpenOption.WRITE).truncate(0).close();
- }
-
- @Test
- void testSlf4jBinding() {
- try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
- mocked.when(() -> getenv("POWERTOOLS_SERVICE_NAME"))
- .thenReturn("testLog4j");
-
- PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
- handler.handleRequest("Input", context);
-
- File logFile = new File("target/logfile.json");
- assertThat(contentOf(logFile))
- .contains("slf4j.binding is set to org.apache.logging.slf4j.SLF4JServiceProvider")
- .contains("Loading software.amazon.lambda.powertools.logging.internal.Log4jLoggingManager");
- }
- }
-
- private void setupContext() {
- when(context.getFunctionName()).thenReturn("testFunction");
- when(context.getInvokedFunctionArn()).thenReturn(
- "arn:aws:lambda:eu-west-1:012345678910:function:testFunction:1");
- when(context.getFunctionVersion()).thenReturn("1");
- when(context.getMemoryLimitInMB()).thenReturn(1024);
- when(context.getAwsRequestId()).thenReturn("RequestId");
- }
-}
\ No newline at end of file
diff --git a/powertools-logging/powertools-logging-logback/pom.xml b/powertools-logging/powertools-logging-logback/pom.xml
index 1628428b4..55a4a7627 100644
--- a/powertools-logging/powertools-logging-logback/pom.xml
+++ b/powertools-logging/powertools-logging-logback/pom.xml
@@ -151,14 +151,6 @@
org.apache.maven.pluginsmaven-checkstyle-plugin
-
- maven-surefire-plugin
-
-
- ch.qos.logback.classic.spi.LogbackServiceProvider
-
-
-
diff --git a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
deleted file mode 100644
index 85615c4a6..000000000
--- a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2023 Amazon.com, Inc. or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package software.amazon.lambda.powertools.logging.internal;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.contentOf;
-import static org.mockito.Mockito.mockStatic;
-import static org.mockito.Mockito.when;
-import static org.mockito.MockitoAnnotations.openMocks;
-import static software.amazon.lambda.powertools.common.internal.SystemWrapper.getenv;
-
-import com.amazonaws.services.lambda.runtime.Context;
-import java.io.File;
-import java.io.IOException;
-import java.nio.channels.FileChannel;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Order;
-import org.junit.jupiter.api.Test;
-import org.mockito.Mock;
-import org.mockito.MockedStatic;
-import org.slf4j.MDC;
-import software.amazon.lambda.powertools.common.internal.SystemWrapper;
-import software.amazon.lambda.powertools.logging.internal.handler.PowertoolsLogEnabled;
-
-@Order(1)
-class LambdaLoggingAspectTest {
-
- @Mock
- private Context context;
-
- @BeforeEach
- void setUp() throws IOException {
- openMocks(this);
- MDC.clear();
- setupContext();
- //Make sure file is cleaned up before running full stack logging regression
- try {
- FileChannel.open(Paths.get("target/logfile.json"), StandardOpenOption.WRITE).truncate(0).close();
- } catch (NoSuchFileException e) {
- // file might not be there for the first run
- }
- }
-
- @AfterEach
- void cleanUp() throws IOException {
-// FileChannel.open(Paths.get("target/logfile.json"), StandardOpenOption.WRITE).truncate(0).close();
- }
-
- @Test
- void testSlf4jBinding() {
- try (MockedStatic mocked = mockStatic(SystemWrapper.class)) {
- mocked.when(() -> getenv("POWERTOOLS_SERVICE_NAME"))
- .thenReturn("testLogback");
-
- PowertoolsLogEnabled handler = new PowertoolsLogEnabled();
- handler.handleRequest("Input", context);
-
- File logFile = new File("target/logfile.json");
- assertThat(contentOf(logFile))
- .contains("slf4j.binding is set to ch.qos.logback.classic.spi.LogbackServiceProvider")
- .contains("Loading software.amazon.lambda.powertools.logging.internal.LogbackLoggingManager");
- }
- }
-
- private void setupContext() {
- when(context.getFunctionName()).thenReturn("testFunction");
- when(context.getInvokedFunctionArn()).thenReturn(
- "arn:aws:lambda:eu-west-1:012345678910:function:testFunction:1");
- when(context.getFunctionVersion()).thenReturn("1");
- when(context.getMemoryLimitInMB()).thenReturn(1024);
- when(context.getAwsRequestId()).thenReturn("RequestId");
- }
-}
\ No newline at end of file
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
index adf4d8615..3680d001e 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
@@ -74,7 +74,7 @@ public final class LambdaLoggingAspect {
private static Level LEVEL_AT_INITIALISATION; /* not final for test purpose */
static {
- loggingManager = loadLoggingManager();
+ loggingManager = getLoggingManagerFromServiceLoader();
LEVEL_AT_INITIALISATION = loggingManager.getLogLevel(LOG);
@@ -83,54 +83,6 @@ public final class LambdaLoggingAspect {
}
}
- private static LoggingManager loadLoggingManager() {
- return getLoggingManagerFromSlf4jBinding().orElse(getLoggingManagerFromServiceLoader());
- }
-
- /**
- * To avoid Service Loader loading of the log provider, SLF4j provides a system property 'slf4j.binding'
- * that users can set. If this is set, we can also leverage it and avoid Service Loader for the {@link LoggingManager}.
- *
In Lambda, system properties can be set with JAVA_TOOL_OPTIONS:
- *
+
+ org.apache.logging.log4j
+ log4j-slf4j2-impl
+ ${log4j.version}
+
+
+ org.apache.logging.log4j
+ log4j-core
+ ${log4j.version}
+ software.amazon.lambdapowertools-batch
diff --git a/examples/powertools-examples-cloudformation/pom.xml b/examples/powertools-examples-cloudformation/pom.xml
index e93a455fc..9dd2163a4 100644
--- a/examples/powertools-examples-cloudformation/pom.xml
+++ b/examples/powertools-examples-cloudformation/pom.xml
@@ -7,7 +7,7 @@
powertools-examples-cloudformationjar
- Powertools for AWS Lambda (Java) library Examples - CloudFormation
+ Powertools for AWS Lambda (Java) - Examples - CloudFormation2.20.0
@@ -54,12 +54,12 @@
org.apache.logging.log4j
- log4j-core
+ log4j-slf4j2-impl${log4j.version}org.apache.logging.log4j
- log4j-api
+ log4j-core${log4j.version}
diff --git a/examples/powertools-examples-core-utilities/cdk/app/pom.xml b/examples/powertools-examples-core-utilities/cdk/app/pom.xml
index 822e87633..e6d6e7982 100644
--- a/examples/powertools-examples-core-utilities/cdk/app/pom.xml
+++ b/examples/powertools-examples-core-utilities/cdk/app/pom.xml
@@ -2,7 +2,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4.0.0
- Powertools for AWS Lambda (Java) library Examples - Core Utilities (logging, tracing, metrics) with CDK
+ Powertools for AWS Lambda (Java) - Examples - Core Utilities (logging, tracing, metrics) with CDKsoftware.amazon.lambda.examples
diff --git a/examples/powertools-examples-core-utilities/gradle/build.gradle b/examples/powertools-examples-core-utilities/gradle/build.gradle
index 32ac30d5d..ba38e83e8 100644
--- a/examples/powertools-examples-core-utilities/gradle/build.gradle
+++ b/examples/powertools-examples-core-utilities/gradle/build.gradle
@@ -28,7 +28,9 @@ dependencies {
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.2.2'
implementation 'com.amazonaws:aws-lambda-java-events:3.11.0'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.2'
- implementation 'org.aspectj:aspectjrt:1.9.7'
+ implementation 'org.apache.logging.log4:log4j-slf4j2-impl:2.20.0'
+ implementation 'org.apache.logging.log4j:log4j-core:2.20.0'
+ implementation 'org.aspectj:aspectjrt:1.9.20.1'
aspect 'software.amazon.lambda:powertools-tracing:2.0.0-SNAPSHOT'
aspect 'software.amazon.lambda:powertools-logging-log4j:2.0.0-SNAPSHOT'
aspect 'software.amazon.lambda:powertools-metrics:2.0.0-SNAPSHOT'
diff --git a/examples/powertools-examples-core-utilities/kotlin/build.gradle.kts b/examples/powertools-examples-core-utilities/kotlin/build.gradle.kts
index 4b4b6c18a..bef141a41 100644
--- a/examples/powertools-examples-core-utilities/kotlin/build.gradle.kts
+++ b/examples/powertools-examples-core-utilities/kotlin/build.gradle.kts
@@ -9,16 +9,18 @@ repositories {
}
dependencies {
- implementation("com.amazonaws:aws-lambda-java-core:1.2.2")
- implementation("com.fasterxml.jackson.core:jackson-annotations:2.13.2")
- implementation("com.fasterxml.jackson.core:jackson-databind:2.13.2.2")
- implementation("com.amazonaws:aws-lambda-java-events:3.11.0")
- implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.2")
- implementation("org.aspectj:aspectjrt:1.9.7")
+ implementation("com.amazonaws:aws-lambda-java-core:1.2.3")
+ implementation("com.fasterxml.jackson.core:jackson-annotations:2.15.1")
+ implementation("com.fasterxml.jackson.core:jackson-databind:2.15.3")
+ implementation("com.amazonaws:aws-lambda-java-events:3.11.3")
+ implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.15.2")
+ implementation("org.aspectj:aspectjrt:1.9.20.1")
+ implementation("org.apache.logging.log4:log4j-slf4j2-impl:2.20.0")
+ implementation("org.apache.logging.log4j:log4j-core:2.20.0")
aspect("software.amazon.lambda:powertools-tracing:2.0.0-SNAPSHOT")
aspect("software.amazon.lambda:powertools-logging-log4j:2.0.0-SNAPSHOT")
aspect("software.amazon.lambda:powertools-metrics:2.0.0-SNAPSHOT")
- implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
+ implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.10")
}
kotlin {
diff --git a/examples/powertools-examples-core-utilities/sam/pom.xml b/examples/powertools-examples-core-utilities/sam/pom.xml
index 289b7d18e..1489af9c3 100644
--- a/examples/powertools-examples-core-utilities/sam/pom.xml
+++ b/examples/powertools-examples-core-utilities/sam/pom.xml
@@ -2,7 +2,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4.0.0
- Powertools for AWS Lambda (Java) library Examples - Core Utilities (logging, tracing, metrics) with SAM
+ Powertools for AWS Lambda (Java) - Examples - Core Utilities (logging, tracing, metrics) with SAMsoftware.amazon.lambda.examples2.0.0-SNAPSHOTpowertools-examples-core-utilities-sam
diff --git a/examples/powertools-examples-core-utilities/serverless/pom.xml b/examples/powertools-examples-core-utilities/serverless/pom.xml
index e267e281a..d1fbc933c 100644
--- a/examples/powertools-examples-core-utilities/serverless/pom.xml
+++ b/examples/powertools-examples-core-utilities/serverless/pom.xml
@@ -2,7 +2,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4.0.0
- Powertools for AWS Lambda (Java) library Examples - Core Utilities (logging, tracing, metrics) with Serverless
+ Powertools for AWS Lambda (Java) - Examples - Core Utilities (logging, tracing, metrics) with Serverlesssoftware.amazon.lambda.examples2.0.0-SNAPSHOTpowertools-examples-core-utilities-serverless
@@ -26,6 +26,14 @@
powertools-logging-log4j${project.version}
+
+ org.apache.logging.log4j
+ log4j-slf4j2-impl
+
+
+ org.apache.logging.log4j
+ log4j-core
+ software.amazon.lambdapowertools-metrics
diff --git a/examples/powertools-examples-core-utilities/terraform/pom.xml b/examples/powertools-examples-core-utilities/terraform/pom.xml
index 68ee3b5d9..d0105c93f 100644
--- a/examples/powertools-examples-core-utilities/terraform/pom.xml
+++ b/examples/powertools-examples-core-utilities/terraform/pom.xml
@@ -2,7 +2,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4.0.0
- Powertools for AWS Lambda (Java) library Examples - Core Utilities (logging, tracing, metrics) with Terraform
+ Powertools for AWS Lambda (Java) - Examples - Core Utilities (logging, tracing, metrics) with Terraformsoftware.amazon.lambda.examples2.0.0-SNAPSHOTpowertools-examples-core-utilities-terraform
@@ -26,6 +26,14 @@
powertools-logging-log4j${project.version}
+
+ org.apache.logging.log4j
+ log4j-slf4j2-impl
+
+
+ org.apache.logging.log4j
+ log4j-core
+ software.amazon.lambdapowertools-metrics
diff --git a/examples/powertools-examples-idempotency/pom.xml b/examples/powertools-examples-idempotency/pom.xml
index 83905d195..122b7d0e8 100644
--- a/examples/powertools-examples-idempotency/pom.xml
+++ b/examples/powertools-examples-idempotency/pom.xml
@@ -20,7 +20,7 @@
2.0.0-SNAPSHOTpowertools-examples-idempotencyjar
- Powertools for AWS Lambda (Java) library Examples - Idempotency
+ Powertools for AWS Lambda (Java) - Examples - Idempotency2.20.0
@@ -40,6 +40,16 @@
powertools-logging-log4j${project.version}
+
+ org.apache.logging.log4j
+ log4j-slf4j2-impl
+ ${log4j.version}
+
+
+ org.apache.logging.log4j
+ log4j-core
+ ${log4j.version}
+ software.amazon.lambdapowertools-idempotency
diff --git a/examples/powertools-examples-parameters/pom.xml b/examples/powertools-examples-parameters/pom.xml
index 398815264..e041ab494 100644
--- a/examples/powertools-examples-parameters/pom.xml
+++ b/examples/powertools-examples-parameters/pom.xml
@@ -5,12 +5,13 @@
2.0.0-SNAPSHOTpowertools-examples-parametersjar
- Powertools for AWS Lambda (Java) library Examples - Parameters
+ Powertools for AWS Lambda (Java) - Examples - Parameters11111.9.20
+ 2.20.0
@@ -19,6 +20,16 @@
powertools-logging-log4j${project.version}
+
+ org.apache.logging.log4j
+ log4j-slf4j2-impl
+ ${log4j.version}
+
+
+ org.apache.logging.log4j
+ log4j-core
+ ${log4j.version}
+ software.amazon.lambdapowertools-parameters
diff --git a/examples/powertools-examples-serialization/pom.xml b/examples/powertools-examples-serialization/pom.xml
index b6374bcd6..c5678c879 100644
--- a/examples/powertools-examples-serialization/pom.xml
+++ b/examples/powertools-examples-serialization/pom.xml
@@ -5,11 +5,12 @@
2.0.0-SNAPSHOTpowertools-examples-serializationjar
- Powertools for AWS Lambda (Java) library Examples - Serialization
+ Powertools for AWS Lambda (Java) - Examples - Serialization1111
+ 2.20.0
@@ -18,6 +19,16 @@
powertools-logging-log4j${project.version}
+
+ org.apache.logging.log4j
+ log4j-slf4j2-impl
+ ${log4j.version}
+
+
+ org.apache.logging.log4j
+ log4j-core
+ ${log4j.version}
+ software.amazon.lambdapowertools-serialization
diff --git a/examples/powertools-examples-validation/pom.xml b/examples/powertools-examples-validation/pom.xml
index b8a6c8b7e..391936194 100644
--- a/examples/powertools-examples-validation/pom.xml
+++ b/examples/powertools-examples-validation/pom.xml
@@ -19,12 +19,13 @@
2.0.0-SNAPSHOTpowertools-examples-validationjar
- Powertools for AWS Lambda (Java) library Examples - Validation
+ Powertools for AWS Lambda (Java) - Examples - Validation1.81.81.9.20
+ 2.20.0
@@ -33,6 +34,16 @@
powertools-logging-log4j${project.version}
+
+ org.apache.logging.log4j
+ log4j-slf4j2-impl
+ ${log4j.version}
+
+
+ org.apache.logging.log4j
+ log4j-core
+ ${log4j.version}
+ software.amazon.lambdapowertools-validation
diff --git a/pom.xml b/pom.xml
index 4ed136d76..ca32c2785 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,7 +23,7 @@
2.0.0-SNAPSHOTpom
- Powertools for AWS Lambda (Java) library Parent
+ Powertools for AWS Lambda (Java) - Parent
A suite of utilities for AWS Lambda Functions that makes tracing with AWS X-Ray, structured logging and creating custom metrics asynchronously easier.
diff --git a/powertools-batch/pom.xml b/powertools-batch/pom.xml
index 309fac10c..eaafdb56e 100644
--- a/powertools-batch/pom.xml
+++ b/powertools-batch/pom.xml
@@ -10,7 +10,7 @@
A suite of utilities that makes batch message processing using AWS Lambda easier.
- Powertools for AWS Lambda (Java) library batch messages
+ Powertools for AWS Lambda (Java) - Batch messages
diff --git a/powertools-cloudformation/pom.xml b/powertools-cloudformation/pom.xml
index 0e6763e25..79071d532 100644
--- a/powertools-cloudformation/pom.xml
+++ b/powertools-cloudformation/pom.xml
@@ -27,7 +27,7 @@
2.0.0-SNAPSHOT
- Powertools for AWS Lambda (Java) library Cloudformation
+ Powertools for AWS Lambda (Java) - Cloudformation
A suite of utilities for AWS Lambda Functions that makes tracing with AWS X-Ray, structured logging and creating
custom metrics asynchronously easier.
diff --git a/powertools-common/pom.xml b/powertools-common/pom.xml
index 8f6752a4d..363d2e944 100644
--- a/powertools-common/pom.xml
+++ b/powertools-common/pom.xml
@@ -27,7 +27,7 @@
2.0.0-SNAPSHOT
- Powertools for AWS Lambda (Java) library Common Internal Utilities
+ Powertools for AWS Lambda (Java) - Common Internal UtilitiesInternal utilities shared by the Powertools for AWS Lambda (Java) modules. Do not use directly in your project.https://aws.amazon.com/lambda/
diff --git a/powertools-e2e-tests/handlers/batch/pom.xml b/powertools-e2e-tests/handlers/batch/pom.xml
index 62f43aa1b..024e2b609 100644
--- a/powertools-e2e-tests/handlers/batch/pom.xml
+++ b/powertools-e2e-tests/handlers/batch/pom.xml
@@ -21,6 +21,14 @@
software.amazon.lambdapowertools-logging-log4j
+
+ org.apache.logging.log4j
+ log4j-slf4j2-impl
+
+
+ org.apache.logging.log4j
+ log4j-core
+ com.amazonawsaws-lambda-java-events
diff --git a/powertools-e2e-tests/handlers/idempotency/pom.xml b/powertools-e2e-tests/handlers/idempotency/pom.xml
index ecc6190fe..bb4a0b49b 100644
--- a/powertools-e2e-tests/handlers/idempotency/pom.xml
+++ b/powertools-e2e-tests/handlers/idempotency/pom.xml
@@ -24,7 +24,6 @@
org.apache.logging.log4jlog4j-core
- 2.20.0org.apache.logging.log4j
diff --git a/powertools-e2e-tests/handlers/largemessage/pom.xml b/powertools-e2e-tests/handlers/largemessage/pom.xml
index e50695e8f..cd7b35240 100644
--- a/powertools-e2e-tests/handlers/largemessage/pom.xml
+++ b/powertools-e2e-tests/handlers/largemessage/pom.xml
@@ -28,16 +28,15 @@
org.apache.logging.log4jlog4j-core
- 2.20.0
-
-
- com.amazonaws
- aws-lambda-java-eventsorg.apache.logging.log4jlog4j-slf4j2-impl
+
+ com.amazonaws
+ aws-lambda-java-events
+ org.aspectjaspectjrt
diff --git a/powertools-e2e-tests/handlers/largemessage_idempotent/pom.xml b/powertools-e2e-tests/handlers/largemessage_idempotent/pom.xml
index 3306f055f..3e8366292 100644
--- a/powertools-e2e-tests/handlers/largemessage_idempotent/pom.xml
+++ b/powertools-e2e-tests/handlers/largemessage_idempotent/pom.xml
@@ -28,16 +28,15 @@
org.apache.logging.log4jlog4j-core
- 2.20.0
-
-
- com.amazonaws
- aws-lambda-java-eventsorg.apache.logging.log4jlog4j-slf4j2-impl
+
+ com.amazonaws
+ aws-lambda-java-events
+ org.aspectjaspectjrt
diff --git a/powertools-e2e-tests/handlers/logging/pom.xml b/powertools-e2e-tests/handlers/logging/pom.xml
index b3cad89a6..140f1d719 100644
--- a/powertools-e2e-tests/handlers/logging/pom.xml
+++ b/powertools-e2e-tests/handlers/logging/pom.xml
@@ -20,12 +20,10 @@
org.apache.logging.log4jlog4j-slf4j2-impl
- 2.20.0org.apache.logging.log4jlog4j-core
- 2.20.0org.apache.logging.log4j
diff --git a/powertools-e2e-tests/handlers/parameters/pom.xml b/powertools-e2e-tests/handlers/parameters/pom.xml
index ef08aa3a7..b48429aaa 100644
--- a/powertools-e2e-tests/handlers/parameters/pom.xml
+++ b/powertools-e2e-tests/handlers/parameters/pom.xml
@@ -17,10 +17,13 @@
software.amazon.lambdapowertools-logging-log4j
+
+ org.apache.logging.log4j
+ log4j-slf4j2-impl
+ org.apache.logging.log4jlog4j-core
- 2.20.0software.amazon.lambda
diff --git a/powertools-e2e-tests/handlers/pom.xml b/powertools-e2e-tests/handlers/pom.xml
index 2bf76d22c..9e7f4a702 100644
--- a/powertools-e2e-tests/handlers/pom.xml
+++ b/powertools-e2e-tests/handlers/pom.xml
@@ -58,6 +58,14 @@
powertools-logging-log4j${lambda.powertools.version}
+
+ org.apache.logging.log4j
+ log4j-slf4j2-impl
+
+
+ org.apache.logging.log4j
+ log4j-core
+ software.amazon.lambdapowertools-tracing
diff --git a/powertools-e2e-tests/pom.xml b/powertools-e2e-tests/pom.xml
index bea1648b3..a64e7a354 100644
--- a/powertools-e2e-tests/pom.xml
+++ b/powertools-e2e-tests/pom.xml
@@ -24,7 +24,7 @@
powertools-e2e-tests
- Powertools for AWS Lambda (Java) library End-to-end tests
+ Powertools for AWS Lambda (Java) - End-to-end testsPowertools for AWS Lambda (Java)End-To-End Tests
diff --git a/powertools-idempotency/pom.xml b/powertools-idempotency/pom.xml
index b53036399..eda7bd982 100644
--- a/powertools-idempotency/pom.xml
+++ b/powertools-idempotency/pom.xml
@@ -27,7 +27,7 @@
powertools-idempotencyjar
- Powertools for AWS Lambda (Java) library Idempotency
+ Powertools for AWS Lambda (Java) - Idempotency
diff --git a/powertools-large-messages/pom.xml b/powertools-large-messages/pom.xml
index 72e6e6f1a..af031ff21 100644
--- a/powertools-large-messages/pom.xml
+++ b/powertools-large-messages/pom.xml
@@ -29,7 +29,7 @@
powertools-large-messagesjar
- Powertools for AWS Lambda (Java) library Large messages
+ Powertools for AWS Lambda (Java) - Large messagesGitHub Issues
diff --git a/powertools-logging/pom.xml b/powertools-logging/pom.xml
index 67e92deda..56ca0e62b 100644
--- a/powertools-logging/pom.xml
+++ b/powertools-logging/pom.xml
@@ -25,31 +25,8 @@
powertools-loggingjar
-
- Powertools for AWS Lambda (Java) library Logging
- Set of utilities to improve Lambda function handler logging - common
- https://aws.amazon.com/lambda/
-
- GitHub Issues
- https://github.com/aws-powertools/powertools-lambda-java/issues
-
-
- https://github.com/aws-powertools/powertools-lambda-java.git
-
-
-
- Powertools for AWS Lambda team
- Amazon Web Services
- https://aws.amazon.com/
-
-
-
-
-
- ossrh
- https://aws.oss.sonatype.org/content/repositories/snapshots
-
-
+ Powertools for AWS Lambda (Java) - Logging
+ Set of utility for better logging - common
diff --git a/powertools-logging/powertools-logging-log4j/pom.xml b/powertools-logging/powertools-logging-log4j/pom.xml
index 6630f677f..626596cfe 100644
--- a/powertools-logging/powertools-logging-log4j/pom.xml
+++ b/powertools-logging/powertools-logging-log4j/pom.xml
@@ -13,32 +13,9 @@
powertools-logging-log4jjar
- Powertools for AWS Lambda (Java) library Logging with Log4j2
+ Powertools for AWS Lambda (Java) - Logging with Log4j2Set of utility for better logging with log4j
- https://aws.amazon.com/lambda/
-
- GitHub Issues
- https://github.com/awslabs/aws-lambda-powertools-java/issues
-
-
- https://github.com/awslabs/aws-lambda-powertools-java.git
-
-
-
- AWS Lambda Powertools team
- Amazon Web Services
- https://aws.amazon.com/
-
-
-
-
-
- ossrh
- https://aws.oss.sonatype.org/content/repositories/snapshots
-
-
-
software.amazon.lambda
@@ -53,10 +30,12 @@
org.apache.logging.log4jlog4j-slf4j2-impl
+ providedorg.apache.logging.log4jlog4j-core
+ providedorg.apache.logging.log4j
diff --git a/powertools-logging/powertools-logging-log4j/src/main/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManager.java b/powertools-logging/powertools-logging-log4j/src/main/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManager.java
index a086ff596..a20671739 100644
--- a/powertools-logging/powertools-logging-log4j/src/main/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManager.java
+++ b/powertools-logging/powertools-logging-log4j/src/main/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManager.java
@@ -30,7 +30,7 @@ public class Log4jLoggingManager implements LoggingManager {
*/
@Override
@SuppressWarnings("java:S4792")
- public void resetLogLevel(org.slf4j.event.Level logLevel) {
+ public void setLogLevel(org.slf4j.event.Level logLevel) {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configurator.setAllLevels(LogManager.getRootLogger().getName(), Level.getLevel(logLevel.toString()));
ctx.updateLoggers();
diff --git a/powertools-logging/powertools-logging-log4j/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/PowertoolsResolverTest.java b/powertools-logging/powertools-logging-log4j/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/PowertoolsResolverTest.java
index bbe6f6b75..1aa98fdef 100644
--- a/powertools-logging/powertools-logging-log4j/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/PowertoolsResolverTest.java
+++ b/powertools-logging/powertools-logging-log4j/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/PowertoolsResolverTest.java
@@ -40,7 +40,7 @@ class PowertoolsResolverTest {
@ParameterizedTest
@EnumSource(value = PowertoolsLoggedFields.class,
mode = EnumSource.Mode.EXCLUDE,
- names = {"FUNCTION_MEMORY_SIZE", "SAMPLING_RATE", "FUNCTION_COLD_START"})
+ names = {"FUNCTION_MEMORY_SIZE", "SAMPLING_RATE", "FUNCTION_COLD_START", "CORRELATION_ID"})
void shouldResolveFunctionStringInfo(PowertoolsLoggedFields field) {
String result = resolveField(field.getName(), "value");
assertThat(result).isEqualTo("\"value\"");
diff --git a/powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManagerTest.java b/powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManagerTest.java
index 0debf88e5..0942eca52 100644
--- a/powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManagerTest.java
+++ b/powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManagerTest.java
@@ -38,7 +38,7 @@ void resetLogLevel() {
// When
Log4jLoggingManager manager = new Log4jLoggingManager();
- manager.resetLogLevel(ERROR);
+ manager.setLogLevel(ERROR);
Level rootLevel = manager.getLogLevel(ROOT);
Level logLevel = manager.getLogLevel(LOG);
diff --git a/powertools-logging/powertools-logging-logback/pom.xml b/powertools-logging/powertools-logging-logback/pom.xml
index c47c94021..89ca7b7ca 100644
--- a/powertools-logging/powertools-logging-logback/pom.xml
+++ b/powertools-logging/powertools-logging-logback/pom.xml
@@ -2,42 +2,18 @@
+ 4.0.0powertools-parentsoftware.amazon.lambda2.0.0-SNAPSHOT../../pom.xml
- 4.0.0powertools-logging-logback
- Powertools for AWS Lambda (Java) library Logging with LogBack
+ Powertools for AWS Lambda (Java) - Logging with LogBackSet of utility for better logging with logback
- https://aws.amazon.com/lambda/
-
- GitHub Issues
- https://github.com/awslabs/aws-lambda-powertools-java/issues
-
-
- https://github.com/awslabs/aws-lambda-powertools-java.git
-
-
-
- AWS Lambda Powertools team
- Amazon Web Services
- https://aws.amazon.com/
-
-
-
-
-
- ossrh
- https://aws.oss.sonatype.org/content/repositories/snapshots
-
-
-
-
software.amazon.lambda
diff --git a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaEcsEncoder.java b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaEcsEncoder.java
index 4124180f0..1416c8192 100644
--- a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaEcsEncoder.java
+++ b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaEcsEncoder.java
@@ -35,7 +35,7 @@
/**
- * This class will encode the logback event into the format expected by the ECS service (ElasticSearch).
+ * This class will encode the logback event into the format expected by the Elastic Common Schema (ECS) service (for Elasticsearch).
*
* Inspired from co.elastic.logging.logback.EcsEncoder, this class doesn't use
* any JSON (de)serialization library (Jackson, Gson, etc.) or Elastic library to avoid the dependency.
diff --git a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LogbackLoggingManager.java b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LogbackLoggingManager.java
index d010e2977..43e534dd9 100644
--- a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LogbackLoggingManager.java
+++ b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LogbackLoggingManager.java
@@ -41,7 +41,7 @@ public LogbackLoggingManager() {
*/
@Override
@SuppressWarnings("java:S4792")
- public void resetLogLevel(org.slf4j.event.Level logLevel) {
+ public void setLogLevel(org.slf4j.event.Level logLevel) {
List loggers = loggerContext.getLoggerList();
for (Logger logger : loggers) {
logger.setLevel(Level.convertAnSLF4JLevel(logLevel));
diff --git a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/LogbackLoggingManagerTest.java b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/LogbackLoggingManagerTest.java
index e13e78eb4..311a77a50 100644
--- a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/LogbackLoggingManagerTest.java
+++ b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/LogbackLoggingManagerTest.java
@@ -46,7 +46,7 @@ void getLogLevel_shouldReturnConfiguredLogLevel() {
@Order(2)
void resetLogLevel() {
LogbackLoggingManager manager = new LogbackLoggingManager();
- manager.resetLogLevel(ERROR);
+ manager.setLogLevel(ERROR);
Level logLevel = manager.getLogLevel(LOG);
assertThat(logLevel).isEqualTo(ERROR);
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java
index 67eeb6af6..47bcedc52 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java
@@ -14,6 +14,8 @@
package software.amazon.lambda.powertools.logging;
+import static software.amazon.lambda.powertools.logging.internal.PowertoolsLoggedFields.CORRELATION_ID;
+
import java.util.Arrays;
import java.util.Map;
import org.slf4j.MDC;
@@ -77,7 +79,15 @@ public static void removeKeys(String... keys) {
* @param value The value of the correlation id
*/
public static void setCorrelationId(String value) {
- MDC.put("correlation_id", value);
+ MDC.put(CORRELATION_ID.getName(), value);
+ }
+
+ /**
+ * Get correlation id attribute. Maybe null.
+ * @return correlation id set `@Logging(correlationIdPath="JMESPATH Expression")` or `LoggingUtils.setCorrelationId("value")`
+ */
+ public static String getCorrelationId() {
+ return MDC.get(CORRELATION_ID.getName());
}
/**
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
index 1f78f6cd8..fc2d30de3 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
@@ -147,7 +147,7 @@ private static LoggingManager getLoggingManagerFromServiceLoader() {
}
private static void resetLogLevels(Level logLevel) {
- LOGGING_MANAGER.resetLogLevel(logLevel);
+ LOGGING_MANAGER.setLogLevel(logLevel);
}
@SuppressWarnings({"EmptyMethod"})
@@ -195,7 +195,7 @@ public Object around(ProceedingJoinPoint pjp,
} catch (Throwable t) {
if (logging.logError() || "true".equals(POWERTOOLS_LOG_ERROR)) {
// logging the exception with additional context
- logger(pjp).error(MarkerFactory.getMarker("FATAL"), "Exception", t);
+ logger(pjp).error(MarkerFactory.getMarker("FATAL"), "Exception in Lambda Handler", t);
}
throw t;
} finally {
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LoggingManager.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LoggingManager.java
index a141910cb..51d05b25d 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LoggingManager.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LoggingManager.java
@@ -23,8 +23,9 @@
*
Accessing to all loggers and change their Level
*
Retrieving the log Level of a Logger
*
+ *
*
- * Implementations are provided in submodules and loaded thanks to a {@link java.util.ServiceLoader}
+ * This interface is used for these operations and implementations are provided in submodules and loaded thanks to a {@link java.util.ServiceLoader}
* (define a file named software.amazon.lambda.powertools.logging.internal.LoggingManager
* in src/main/resources/META-INF/services with the qualified name of the implementation).
*/
@@ -34,7 +35,7 @@ public interface LoggingManager {
*
* @param logLevel the log Level (slf4j) to apply
*/
- void resetLogLevel(Level logLevel);
+ void setLogLevel(Level logLevel);
/**
* Retrieve the log Level of a specific logger
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/PowertoolsLoggedFields.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/PowertoolsLoggedFields.java
index 686c8c0c2..6e0047f4f 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/PowertoolsLoggedFields.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/PowertoolsLoggedFields.java
@@ -22,7 +22,8 @@
import java.util.stream.Stream;
/**
- * Fields added in the logs by Powertools
+ * Fields added in the logs by Powertools.
+ * Same as python
*/
public enum PowertoolsLoggedFields {
FUNCTION_NAME("function_name"),
@@ -33,6 +34,7 @@ public enum PowertoolsLoggedFields {
FUNCTION_COLD_START("cold_start"),
FUNCTION_TRACE_ID("xray_trace_id"),
SAMPLING_RATE("sampling_rate"),
+ CORRELATION_ID("correlation_id"),
SERVICE("service");
private final String name;
diff --git a/powertools-logging/src/test/java/org/slf4j/test/OutputChoice.java b/powertools-logging/src/test/java/org/slf4j/test/OutputChoice.java
index 164862e00..9a6d56b81 100644
--- a/powertools-logging/src/test/java/org/slf4j/test/OutputChoice.java
+++ b/powertools-logging/src/test/java/org/slf4j/test/OutputChoice.java
@@ -29,8 +29,7 @@
/**
* This class encapsulates the user's choice of output target.
*
- * @author Ceki Gülcü
- *
+ * @see ...
*/
class OutputChoice {
diff --git a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/TestLoggingManager.java b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/TestLoggingManager.java
index 03f992966..0958e0d3b 100644
--- a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/TestLoggingManager.java
+++ b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/TestLoggingManager.java
@@ -21,7 +21,7 @@ public TestLoggingManager() {
}
@Override
- public void resetLogLevel(Level logLevel) {
+ public void setLogLevel(Level logLevel) {
loggerFactory.getLoggers().forEach((key, logger) -> ((TestLogger) logger).setLogLevel(logLevel.toString()));
}
diff --git a/powertools-metrics/pom.xml b/powertools-metrics/pom.xml
index 142852299..7de1efa3f 100644
--- a/powertools-metrics/pom.xml
+++ b/powertools-metrics/pom.xml
@@ -27,7 +27,7 @@
2.0.0-SNAPSHOT
- Powertools for AWS Lambda (Java) library Metrics
+ Powertools for AWS Lambda (Java) - Metrics
A suite of utilities for AWS Lambda Functions that make creating custom metrics via AWS Embedded Metric Format
asynchronously easier.
diff --git a/powertools-parameters/pom.xml b/powertools-parameters/pom.xml
index 3895ef475..36f8e9aa7 100644
--- a/powertools-parameters/pom.xml
+++ b/powertools-parameters/pom.xml
@@ -26,7 +26,7 @@
powertools-parameters
- Powertools for AWS Lambda (Java) library Parameters
+ Powertools for AWS Lambda (Java) - Parameters
Set of utilities to retrieve parameters from Secrets Manager or SSM Parameter Store
diff --git a/powertools-serialization/pom.xml b/powertools-serialization/pom.xml
index 911663507..d1b2de826 100644
--- a/powertools-serialization/pom.xml
+++ b/powertools-serialization/pom.xml
@@ -27,7 +27,7 @@
powertools-serializationjar
- Powertools for AWS Lambda (Java) library Serialization Utilities
+ Powertools for AWS Lambda (Java) - Serialization Utilities
diff --git a/powertools-tracing/pom.xml b/powertools-tracing/pom.xml
index 273b807c8..1625fd0cb 100644
--- a/powertools-tracing/pom.xml
+++ b/powertools-tracing/pom.xml
@@ -27,7 +27,7 @@
2.0.0-SNAPSHOT
- Powertools for AWS Lambda (Java) library Tracing
+ Powertools for AWS Lambda (Java) - Tracing
A suite of utilities for AWS Lambda Functions that makes tracing with AWS X-Ray, structured logging and creating custom metrics asynchronously easier.
diff --git a/powertools-validation/pom.xml b/powertools-validation/pom.xml
index 269513a46..bd57fa6c5 100644
--- a/powertools-validation/pom.xml
+++ b/powertools-validation/pom.xml
@@ -27,7 +27,7 @@
2.0.0-SNAPSHOT
- Powertools for AWS Lambda (Java) validation library
+ Powertools for AWS Lambda (Java) - Validation
Json schema validation for Lambda events and responses
From cff2ee6bb820b3aec80dc2bf44a76ff70187b2f9 Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Thu, 7 Dec 2023 08:47:42 +0100
Subject: [PATCH 60/74] fix gradle build
---
examples/powertools-examples-core-utilities/gradle/build.gradle | 2 +-
.../powertools-examples-core-utilities/kotlin/build.gradle.kts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/examples/powertools-examples-core-utilities/gradle/build.gradle b/examples/powertools-examples-core-utilities/gradle/build.gradle
index ba38e83e8..d8184952e 100644
--- a/examples/powertools-examples-core-utilities/gradle/build.gradle
+++ b/examples/powertools-examples-core-utilities/gradle/build.gradle
@@ -28,7 +28,7 @@ dependencies {
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.2.2'
implementation 'com.amazonaws:aws-lambda-java-events:3.11.0'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.2'
- implementation 'org.apache.logging.log4:log4j-slf4j2-impl:2.20.0'
+ implementation 'org.apache.logging.log4j:log4j-slf4j2-impl:2.20.0'
implementation 'org.apache.logging.log4j:log4j-core:2.20.0'
implementation 'org.aspectj:aspectjrt:1.9.20.1'
aspect 'software.amazon.lambda:powertools-tracing:2.0.0-SNAPSHOT'
diff --git a/examples/powertools-examples-core-utilities/kotlin/build.gradle.kts b/examples/powertools-examples-core-utilities/kotlin/build.gradle.kts
index bef141a41..261161084 100644
--- a/examples/powertools-examples-core-utilities/kotlin/build.gradle.kts
+++ b/examples/powertools-examples-core-utilities/kotlin/build.gradle.kts
@@ -15,7 +15,7 @@ dependencies {
implementation("com.amazonaws:aws-lambda-java-events:3.11.3")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.15.2")
implementation("org.aspectj:aspectjrt:1.9.20.1")
- implementation("org.apache.logging.log4:log4j-slf4j2-impl:2.20.0")
+ implementation("org.apache.logging.log4j:log4j-slf4j2-impl:2.20.0")
implementation("org.apache.logging.log4j:log4j-core:2.20.0")
aspect("software.amazon.lambda:powertools-tracing:2.0.0-SNAPSHOT")
aspect("software.amazon.lambda:powertools-logging-log4j:2.0.0-SNAPSHOT")
From 4572bf46390489c54dd411579af17f44e7779a1b Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Thu, 7 Dec 2023 09:28:07 +0100
Subject: [PATCH 61/74] fix e2e tests
---
powertools-e2e-tests/handlers/batch/pom.xml | 4 ----
powertools-e2e-tests/handlers/logging/pom.xml | 4 ----
powertools-e2e-tests/handlers/pom.xml | 2 ++
3 files changed, 2 insertions(+), 8 deletions(-)
diff --git a/powertools-e2e-tests/handlers/batch/pom.xml b/powertools-e2e-tests/handlers/batch/pom.xml
index 024e2b609..6f98062ac 100644
--- a/powertools-e2e-tests/handlers/batch/pom.xml
+++ b/powertools-e2e-tests/handlers/batch/pom.xml
@@ -37,10 +37,6 @@
com.amazonawsaws-lambda-java-serialization
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
- software.amazon.awssdkdynamodb
diff --git a/powertools-e2e-tests/handlers/logging/pom.xml b/powertools-e2e-tests/handlers/logging/pom.xml
index 140f1d719..8257f7f30 100644
--- a/powertools-e2e-tests/handlers/logging/pom.xml
+++ b/powertools-e2e-tests/handlers/logging/pom.xml
@@ -38,10 +38,6 @@
com.amazonawsaws-lambda-java-events
-
- org.aspectj
- aspectjrt
-
diff --git a/powertools-e2e-tests/handlers/pom.xml b/powertools-e2e-tests/handlers/pom.xml
index 9e7f4a702..74aecbf80 100644
--- a/powertools-e2e-tests/handlers/pom.xml
+++ b/powertools-e2e-tests/handlers/pom.xml
@@ -61,10 +61,12 @@
org.apache.logging.log4jlog4j-slf4j2-impl
+ ${log4j.version}org.apache.logging.log4jlog4j-core
+ ${log4j.version}software.amazon.lambda
From 12b284475684c70a4ca3593c3100ee951e065b98 Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Thu, 7 Dec 2023 12:10:52 +0100
Subject: [PATCH 62/74] update poms (transitive dependency for log4j)
---
examples/powertools-examples-batch/pom.xml | 13 +----------
.../pom.xml | 21 +----------------
.../cdk/app/pom.xml | 2 +-
.../gradle/build.gradle | 2 --
.../kotlin/build.gradle.kts | 2 --
.../sam/pom.xml | 13 +----------
.../serverless/pom.xml | 21 +----------------
.../terraform/pom.xml | 21 +----------------
.../powertools-examples-idempotency/pom.xml | 23 +------------------
.../powertools-examples-parameters/pom.xml | 13 +----------
.../powertools-examples-serialization/pom.xml | 11 ---------
.../powertools-examples-validation/pom.xml | 13 +----------
powertools-e2e-tests/handlers/batch/pom.xml | 8 -------
.../handlers/idempotency/pom.xml | 8 -------
.../handlers/largemessage/pom.xml | 8 -------
.../handlers/largemessage_idempotent/pom.xml | 8 -------
powertools-e2e-tests/handlers/logging/pom.xml | 8 -------
.../handlers/parameters/pom.xml | 8 -------
powertools-e2e-tests/handlers/pom.xml | 18 +--------------
.../powertools-logging-log4j/pom.xml | 2 --
.../powertools-logging-logback/pom.xml | 1 +
.../powertools/logging/LoggingUtils.java | 21 +++++++++++++++++
.../logging/internal/LambdaLoggingAspect.java | 6 ++---
23 files changed, 35 insertions(+), 216 deletions(-)
diff --git a/examples/powertools-examples-batch/pom.xml b/examples/powertools-examples-batch/pom.xml
index 4187f0af5..a1b4c0bbc 100644
--- a/examples/powertools-examples-batch/pom.xml
+++ b/examples/powertools-examples-batch/pom.xml
@@ -11,10 +11,9 @@
Powertools for AWS Lambda (Java) - Examples - Batch
- 2.20.01111
- 1.9.20
+ 1.9.20.12.21.1
@@ -29,16 +28,6 @@
powertools-logging-log4j${project.version}
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
- ${log4j.version}
-
-
- org.apache.logging.log4j
- log4j-core
- ${log4j.version}
- software.amazon.lambdapowertools-batch
diff --git a/examples/powertools-examples-cloudformation/pom.xml b/examples/powertools-examples-cloudformation/pom.xml
index 9dd2163a4..bee97e52a 100644
--- a/examples/powertools-examples-cloudformation/pom.xml
+++ b/examples/powertools-examples-cloudformation/pom.xml
@@ -10,13 +10,12 @@
Powertools for AWS Lambda (Java) - Examples - CloudFormation
- 2.20.011111.2.33.11.32.21.0
- 1.9.20
+ 1.9.20.1
@@ -52,16 +51,6 @@
powertools-logging-log4j${project.version}
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
- ${log4j.version}
-
-
- org.apache.logging.log4j
- log4j-core
- ${log4j.version}
- org.aspectjaspectjrt
@@ -91,14 +80,6 @@
-
- org.apache.logging.log4j
- log4j-jcl
- ${log4j.version}
-
-
-
-
diff --git a/examples/powertools-examples-core-utilities/cdk/app/pom.xml b/examples/powertools-examples-core-utilities/cdk/app/pom.xml
index e6d6e7982..f8d340f3b 100644
--- a/examples/powertools-examples-core-utilities/cdk/app/pom.xml
+++ b/examples/powertools-examples-core-utilities/cdk/app/pom.xml
@@ -14,7 +14,7 @@
2.20.01111
- 1.9.20
+ 1.9.20.1
diff --git a/examples/powertools-examples-core-utilities/gradle/build.gradle b/examples/powertools-examples-core-utilities/gradle/build.gradle
index d8184952e..38cf96c1c 100644
--- a/examples/powertools-examples-core-utilities/gradle/build.gradle
+++ b/examples/powertools-examples-core-utilities/gradle/build.gradle
@@ -28,8 +28,6 @@ dependencies {
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.2.2'
implementation 'com.amazonaws:aws-lambda-java-events:3.11.0'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.2'
- implementation 'org.apache.logging.log4j:log4j-slf4j2-impl:2.20.0'
- implementation 'org.apache.logging.log4j:log4j-core:2.20.0'
implementation 'org.aspectj:aspectjrt:1.9.20.1'
aspect 'software.amazon.lambda:powertools-tracing:2.0.0-SNAPSHOT'
aspect 'software.amazon.lambda:powertools-logging-log4j:2.0.0-SNAPSHOT'
diff --git a/examples/powertools-examples-core-utilities/kotlin/build.gradle.kts b/examples/powertools-examples-core-utilities/kotlin/build.gradle.kts
index 261161084..b37ef6d31 100644
--- a/examples/powertools-examples-core-utilities/kotlin/build.gradle.kts
+++ b/examples/powertools-examples-core-utilities/kotlin/build.gradle.kts
@@ -15,8 +15,6 @@ dependencies {
implementation("com.amazonaws:aws-lambda-java-events:3.11.3")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.15.2")
implementation("org.aspectj:aspectjrt:1.9.20.1")
- implementation("org.apache.logging.log4j:log4j-slf4j2-impl:2.20.0")
- implementation("org.apache.logging.log4j:log4j-core:2.20.0")
aspect("software.amazon.lambda:powertools-tracing:2.0.0-SNAPSHOT")
aspect("software.amazon.lambda:powertools-logging-log4j:2.0.0-SNAPSHOT")
aspect("software.amazon.lambda:powertools-metrics:2.0.0-SNAPSHOT")
diff --git a/examples/powertools-examples-core-utilities/sam/pom.xml b/examples/powertools-examples-core-utilities/sam/pom.xml
index 1489af9c3..c9d90d281 100644
--- a/examples/powertools-examples-core-utilities/sam/pom.xml
+++ b/examples/powertools-examples-core-utilities/sam/pom.xml
@@ -9,10 +9,9 @@
jar
- 2.20.01111
- 1.9.20
+ 1.9.20.1
@@ -26,16 +25,6 @@
powertools-logging-log4j${project.version}
-
- org.apache.logging.log4j
- log4j-core
- ${log4j.version}
-
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
- ${log4j.version}
- software.amazon.lambdapowertools-metrics
diff --git a/examples/powertools-examples-core-utilities/serverless/pom.xml b/examples/powertools-examples-core-utilities/serverless/pom.xml
index d1fbc933c..32cca9bb4 100644
--- a/examples/powertools-examples-core-utilities/serverless/pom.xml
+++ b/examples/powertools-examples-core-utilities/serverless/pom.xml
@@ -9,10 +9,9 @@
jar
- 2.20.01111
- 1.9.20
+ 1.9.20.1
@@ -26,14 +25,6 @@
powertools-logging-log4j${project.version}
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
-
-
- org.apache.logging.log4j
- log4j-core
- software.amazon.lambdapowertools-metrics
@@ -49,16 +40,6 @@
aws-lambda-java-events3.11.3
-
- org.apache.logging.log4j
- log4j-core
- ${log4j.version}
-
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
- ${log4j.version}
- org.aspectjaspectjrt
diff --git a/examples/powertools-examples-core-utilities/terraform/pom.xml b/examples/powertools-examples-core-utilities/terraform/pom.xml
index d0105c93f..c6f838619 100644
--- a/examples/powertools-examples-core-utilities/terraform/pom.xml
+++ b/examples/powertools-examples-core-utilities/terraform/pom.xml
@@ -9,10 +9,9 @@
jar
- 2.20.01111
- 1.9.20
+ 1.9.20.1
@@ -26,14 +25,6 @@
powertools-logging-log4j${project.version}
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
-
-
- org.apache.logging.log4j
- log4j-core
- software.amazon.lambdapowertools-metrics
@@ -49,16 +40,6 @@
aws-lambda-java-events3.11.3
-
- org.apache.logging.log4j
- log4j-core
- ${log4j.version}
-
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
- ${log4j.version}
- org.aspectjaspectjrt
diff --git a/examples/powertools-examples-idempotency/pom.xml b/examples/powertools-examples-idempotency/pom.xml
index 122b7d0e8..13ea8dec1 100644
--- a/examples/powertools-examples-idempotency/pom.xml
+++ b/examples/powertools-examples-idempotency/pom.xml
@@ -23,10 +23,9 @@
Powertools for AWS Lambda (Java) - Examples - Idempotency
- 2.20.01111
- 1.9.20
+ 1.9.20.1
@@ -40,16 +39,6 @@
powertools-logging-log4j${project.version}
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
- ${log4j.version}
-
-
- org.apache.logging.log4j
- log4j-core
- ${log4j.version}
- software.amazon.lambdapowertools-idempotency
@@ -65,16 +54,6 @@
aws-lambda-java-events3.11.3
-
- org.apache.logging.log4j
- log4j-core
- ${log4j.version}
-
-
- org.apache.logging.log4j
- log4j-api
- ${log4j.version}
- org.aspectjaspectjrt
diff --git a/examples/powertools-examples-parameters/pom.xml b/examples/powertools-examples-parameters/pom.xml
index e041ab494..c16bbd41e 100644
--- a/examples/powertools-examples-parameters/pom.xml
+++ b/examples/powertools-examples-parameters/pom.xml
@@ -10,8 +10,7 @@
1111
- 1.9.20
- 2.20.0
+ 1.9.20.1
@@ -20,16 +19,6 @@
powertools-logging-log4j${project.version}
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
- ${log4j.version}
-
-
- org.apache.logging.log4j
- log4j-core
- ${log4j.version}
- software.amazon.lambdapowertools-parameters
diff --git a/examples/powertools-examples-serialization/pom.xml b/examples/powertools-examples-serialization/pom.xml
index c5678c879..2c8fc951a 100644
--- a/examples/powertools-examples-serialization/pom.xml
+++ b/examples/powertools-examples-serialization/pom.xml
@@ -10,7 +10,6 @@
1111
- 2.20.0
@@ -19,16 +18,6 @@
powertools-logging-log4j${project.version}
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
- ${log4j.version}
-
-
- org.apache.logging.log4j
- log4j-core
- ${log4j.version}
- software.amazon.lambdapowertools-serialization
diff --git a/examples/powertools-examples-validation/pom.xml b/examples/powertools-examples-validation/pom.xml
index 391936194..ed33568cb 100644
--- a/examples/powertools-examples-validation/pom.xml
+++ b/examples/powertools-examples-validation/pom.xml
@@ -24,8 +24,7 @@
1.81.8
- 1.9.20
- 2.20.0
+ 1.9.20.1
@@ -34,16 +33,6 @@
powertools-logging-log4j${project.version}
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
- ${log4j.version}
-
-
- org.apache.logging.log4j
- log4j-core
- ${log4j.version}
- software.amazon.lambdapowertools-validation
diff --git a/powertools-e2e-tests/handlers/batch/pom.xml b/powertools-e2e-tests/handlers/batch/pom.xml
index 6f98062ac..cab543f6c 100644
--- a/powertools-e2e-tests/handlers/batch/pom.xml
+++ b/powertools-e2e-tests/handlers/batch/pom.xml
@@ -21,14 +21,6 @@
software.amazon.lambdapowertools-logging-log4j
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
-
-
- org.apache.logging.log4j
- log4j-core
- com.amazonawsaws-lambda-java-events
diff --git a/powertools-e2e-tests/handlers/idempotency/pom.xml b/powertools-e2e-tests/handlers/idempotency/pom.xml
index bb4a0b49b..36cf74b3b 100644
--- a/powertools-e2e-tests/handlers/idempotency/pom.xml
+++ b/powertools-e2e-tests/handlers/idempotency/pom.xml
@@ -21,14 +21,6 @@
software.amazon.lambdapowertools-logging-log4j
-
- org.apache.logging.log4j
- log4j-core
-
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
- com.amazonawsaws-lambda-java-events
diff --git a/powertools-e2e-tests/handlers/largemessage/pom.xml b/powertools-e2e-tests/handlers/largemessage/pom.xml
index cd7b35240..e2b4f71d0 100644
--- a/powertools-e2e-tests/handlers/largemessage/pom.xml
+++ b/powertools-e2e-tests/handlers/largemessage/pom.xml
@@ -25,14 +25,6 @@
software.amazon.lambdapowertools-logging-log4j
-
- org.apache.logging.log4j
- log4j-core
-
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
- com.amazonawsaws-lambda-java-events
diff --git a/powertools-e2e-tests/handlers/largemessage_idempotent/pom.xml b/powertools-e2e-tests/handlers/largemessage_idempotent/pom.xml
index 3e8366292..25238e034 100644
--- a/powertools-e2e-tests/handlers/largemessage_idempotent/pom.xml
+++ b/powertools-e2e-tests/handlers/largemessage_idempotent/pom.xml
@@ -25,14 +25,6 @@
software.amazon.lambdapowertools-logging-log4j
-
- org.apache.logging.log4j
- log4j-core
-
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
- com.amazonawsaws-lambda-java-events
diff --git a/powertools-e2e-tests/handlers/logging/pom.xml b/powertools-e2e-tests/handlers/logging/pom.xml
index 8257f7f30..1375fcad8 100644
--- a/powertools-e2e-tests/handlers/logging/pom.xml
+++ b/powertools-e2e-tests/handlers/logging/pom.xml
@@ -17,14 +17,6 @@
software.amazon.lambdapowertools-logging-log4j
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
-
-
- org.apache.logging.log4j
- log4j-core
- org.apache.logging.log4jlog4j-layout-template-json
diff --git a/powertools-e2e-tests/handlers/parameters/pom.xml b/powertools-e2e-tests/handlers/parameters/pom.xml
index b48429aaa..d69856a10 100644
--- a/powertools-e2e-tests/handlers/parameters/pom.xml
+++ b/powertools-e2e-tests/handlers/parameters/pom.xml
@@ -17,14 +17,6 @@
software.amazon.lambdapowertools-logging-log4j
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
-
-
- org.apache.logging.log4j
- log4j-core
- software.amazon.lambdapowertools-parameters
diff --git a/powertools-e2e-tests/handlers/pom.xml b/powertools-e2e-tests/handlers/pom.xml
index 74aecbf80..beded56e0 100644
--- a/powertools-e2e-tests/handlers/pom.xml
+++ b/powertools-e2e-tests/handlers/pom.xml
@@ -22,8 +22,7 @@
1.13.13.11.02.20.108
- 2.20.0
- 1.9.20
+ 1.9.20.1
@@ -58,16 +57,6 @@
powertools-logging-log4j${lambda.powertools.version}
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
- ${log4j.version}
-
-
- org.apache.logging.log4j
- log4j-core
- ${log4j.version}
- software.amazon.lambdapowertools-tracing
@@ -118,11 +107,6 @@
aws-lambda-java-serialization${lambda.java.serialization}
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
- ${log4j.version}
-
diff --git a/powertools-logging/powertools-logging-log4j/pom.xml b/powertools-logging/powertools-logging-log4j/pom.xml
index 626596cfe..df6154560 100644
--- a/powertools-logging/powertools-logging-log4j/pom.xml
+++ b/powertools-logging/powertools-logging-log4j/pom.xml
@@ -30,12 +30,10 @@
org.apache.logging.log4jlog4j-slf4j2-impl
- providedorg.apache.logging.log4jlog4j-core
- providedorg.apache.logging.log4j
diff --git a/powertools-logging/powertools-logging-logback/pom.xml b/powertools-logging/powertools-logging-logback/pom.xml
index 89ca7b7ca..99fff3ab9 100644
--- a/powertools-logging/powertools-logging-logback/pom.xml
+++ b/powertools-logging/powertools-logging-logback/pom.xml
@@ -28,6 +28,7 @@
ch.qos.logbacklogback-classic
+
1.3.4provided
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java
index 47bcedc52..6b7298524 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java
@@ -16,9 +16,11 @@
import static software.amazon.lambda.powertools.logging.internal.PowertoolsLoggedFields.CORRELATION_ID;
+import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Arrays;
import java.util.Map;
import org.slf4j.MDC;
+import software.amazon.lambda.powertools.utilities.JsonConfig;
/**
* A class of helper functions to add additional functionality to Logging.
@@ -29,6 +31,8 @@ public final class LoggingUtils {
public static final String LOG_MESSAGES_AS_JSON = "PowertoolsLogMessagesAsJson";
+ private static ObjectMapper objectMapper;
+
private LoggingUtils() {
}
@@ -98,4 +102,21 @@ public static String getCorrelationId() {
public static void logMessagesAsJson(boolean value) {
MDC.put(LOG_MESSAGES_AS_JSON, String.valueOf(value));
}
+
+ /**
+ * Sets the instance of ObjectMapper object which is used for serialising event when
+ * {@code @Logging(logEvent = true)}.
+ *
+ * @param objectMapper Custom implementation of object mapper to be used for logging serialised event
+ */
+ public static void setObjectMapper(ObjectMapper objectMapper) {
+ LoggingUtils.objectMapper = objectMapper;
+ }
+
+ public static ObjectMapper getObjectMapper() {
+ if (null == objectMapper) {
+ objectMapper = JsonConfig.get().getObjectMapper();
+ }
+ return objectMapper;
+ }
}
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
index fc2d30de3..9ab53718d 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
@@ -336,12 +336,12 @@ private void captureCorrelationId(final String correlationIdPath,
final boolean isOnRequestHandler,
final boolean isOnRequestStreamHandler) {
if (isOnRequestHandler) {
- JsonNode jsonNode = JsonConfig.get().getObjectMapper().valueToTree(proceedArgs[0]);
+ JsonNode jsonNode = LoggingUtils.getObjectMapper().valueToTree(proceedArgs[0]);
setCorrelationIdFromNode(correlationIdPath, jsonNode);
} else if (isOnRequestStreamHandler) {
try {
byte[] bytes = bytesFromInputStreamSafely((InputStream) proceedArgs[0]);
- JsonNode jsonNode = JsonConfig.get().getObjectMapper().readTree(bytes);
+ JsonNode jsonNode = LoggingUtils.getObjectMapper().readTree(bytes);
proceedArgs[0] = new ByteArrayInputStream(bytes);
setCorrelationIdFromNode(correlationIdPath, jsonNode);
@@ -380,7 +380,7 @@ private byte[] bytesFromInputStreamSafely(final InputStream inputStream) throws
private Optional asJson(final Object target) {
try {
- return ofNullable(JsonConfig.get().getObjectMapper().writeValueAsString(target));
+ return ofNullable(LoggingUtils.getObjectMapper().writeValueAsString(target));
} catch (JsonProcessingException e) {
LOG.error("Failed logging object of type {}", target.getClass(), e);
return empty();
From 74b377ac3573562a8c7c4ce9a92abffe541693fd Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Thu, 7 Dec 2023 12:11:05 +0100
Subject: [PATCH 63/74] documentation
---
docs/core/logging.md | 1127 +++++++++++++++++++++++++-----------
docs/stylesheets/extra.css | 2 +-
mkdocs.yml | 2 +-
pom.xml | 2 +-
4 files changed, 788 insertions(+), 345 deletions(-)
diff --git a/docs/core/logging.md b/docs/core/logging.md
index 02dff401d..40880327c 100644
--- a/docs/core/logging.md
+++ b/docs/core/logging.md
@@ -5,24 +5,34 @@ description: Core utility
Logging provides an opinionated logger with output structured as JSON.
-**Key features**
+## Key features
+* Leverages standard logging libraries: _SLF4J_ as the API, and _log4j2_ or _logback_ for the implementation
* Capture key fields from Lambda context, cold start and structures logging output as JSON
-* Log Lambda event when instructed, disabled by default, can be enabled explicitly via annotation param
+* Log Lambda event when instructed, disabled by default
+* Log Lambda response when instructed, disabled by default
+* Log sampling enables DEBUG log level for a percentage of requests (disabled by default)
* Append additional keys to structured log at any point in time
-## Install
-Depending on your version of Java (either Java 1.8 or 11+), the configuration slightly changes.
+## Getting started
-=== "Maven Java 11+"
+???+ tip
+ You can find complete examples in the [project repository](https://github.com/aws-powertools/powertools-lambda-java/tree/v2/examples/powertools-examples-core-utilities){target="_blank"}.
- ```xml hl_lines="3-7 16 18 24-27"
+### Installation
+Depending on your preferences, you might choose to use _log4j2_ or _logback_. In both case you need to configure _aspectj_
+to weave the code and make sure the annotation is processed.
+
+#### Maven
+=== "log4j2"
+
+ ```xml hl_lines="3-7 24-27"
...
software.amazon.lambda
- powertools-logging
+ powertools-logging-log4j{{ powertools.version }}
...
@@ -60,14 +70,14 @@ Depending on your version of Java (either Java 1.8 or 11+), the configuration sl
```
-=== "Maven Java 1.8"
+=== "logback"
- ```xml hl_lines="3-7 16 18 24-27"
+ ```xml hl_lines="3-7 24-27"
...
software.amazon.lambda
- powertools-logging
+ powertools-logging-logback{{ powertools.version }}
...
@@ -78,13 +88,13 @@ Depending on your version of Java (either Java 1.8 or 11+), the configuration sl
...
- org.codehaus.mojo
+ dev.aspectjaspectj-maven-plugin
- 1.14.0
+ 1.13.1
-
- 1.8
- 1.8
+
+ 11
+ 11software.amazon.lambda
@@ -105,7 +115,9 @@ Depending on your version of Java (either Java 1.8 or 11+), the configuration sl
```
-=== "Gradle Java 11+"
+#### Gradle
+
+=== "log4j2"
```groovy hl_lines="3 11"
plugins {
@@ -118,19 +130,19 @@ Depending on your version of Java (either Java 1.8 or 11+), the configuration sl
}
dependencies {
- aspect 'software.amazon.lambda:powertools-logging:{{ powertools.version }}'
+ aspect 'software.amazon.lambda:powertools-logging-log4j:{{ powertools.version }}'
}
sourceCompatibility = 11
targetCompatibility = 11
```
-=== "Gradle Java 1.8"
+=== "logback"
```groovy hl_lines="3 11"
plugins {
id 'java'
- id 'io.freefair.aspectj.post-compile-weaving' version '6.6.3'
+ id 'io.freefair.aspectj.post-compile-weaving' version '8.1.0'
}
repositories {
@@ -138,27 +150,61 @@ Depending on your version of Java (either Java 1.8 or 11+), the configuration sl
}
dependencies {
- aspect 'software.amazon.lambda:powertools-logging:{{ powertools.version }}'
+ aspect 'software.amazon.lambda:powertools-logging-logback:{{ powertools.version }}'
}
- sourceCompatibility = 1.8
- targetCompatibility = 1.8
+ sourceCompatibility = 11
+ targetCompatibility = 11
```
-## Initialization
+### Configuration
-Powertools for AWS Lambda (Java) extends the functionality of Log4J. Below is an example `#!xml log4j2.xml` file, with the `JsonTemplateLayout` using `#!json LambdaJsonLayout.json` configured.
+#### Main environment variables
-!!! info "LambdaJsonLayout is now deprecated"
+The logging module requires two settings:
- Configuring utiltiy using `` plugin is deprecated now. While utility still supports the old configuration, we strongly recommend upgrading the
- `log4j2.xml` configuration to `JsonTemplateLayout` instead. [JsonTemplateLayout](https://logging.apache.org/log4j/2.x/manual/json-template-layout.html) is recommended way of doing structured logging.
-
- Please follow [this guide](#upgrade-to-jsontemplatelayout-from-deprecated-lambdajsonlayout-configuration-in-log4j2xml) for upgrade steps.
+| Environment variable | Setting | Description |
+|---------------------------|-------------------|-------------------------------------------------------------------------------------------------------------|
+| `POWERTOOLS_LOG_LEVEL` | **Logging level** | Sets how verbose Logger should be. If not set, will use the [Logging configuration](#logging-configuration) |
+| `POWERTOOLS_SERVICE_NAME` | **Service** | Sets service key that will be present across all log statements (Default is `service_undefined`) |
+
+Here is an example using AWS Serverless Application Model (SAM):
+
+=== "template.yaml"
+``` yaml hl_lines="10 11"
+Resources:
+ PaymentFunction:
+ Type: AWS::Serverless::Function
+ Properties:
+ MemorySize: 512
+ Timeout: 20
+ Runtime: java17
+ Environment:
+ Variables:
+ POWERTOOLS_LOG_LEVEL: WARN
+ POWERTOOLS_SERVICE_NAME: payment
+```
+
+There are some other environment variables which can be set to modify Logging's settings at a global scope:
+
+| Environment variable | Type | Description |
+|---------------------------------|----------|-------------------------------------------------------------------------------------------------------------------------|
+| `POWERTOOLS_LOGGER_SAMPLE_RATE` | float | Configure the sampling rate to set the log level at `DEBUG`. See [sampling rage](#sampling-debug-logs) |
+| `POWERTOOLS_LOG_EVENT` | boolean | Specify if the incoming Lambda event should be logged. See [Logging event](#logging-incoming-event) |
+| `POWERTOOLS_LOG_RESPONSE` | boolean | Specify if the Lambda response should be logged. See [logging response](#logging-handler-response) |
+| `POWERTOOLS_LOG_ERROR` | boolean | Specify if a Lambda uncaught exception should be logged. See [logging exception](#logging-handler-uncaught-exception ) |
+
+#### Logging configuration
+
+Powertools for AWS Lambda (Java) simply extends the functionality of the underlying library you choose (_log4j2_ or _logback_).
+You can leverage the standard configuration files (_log4j2.xml_ or _logback.xml_):
=== "log4j2.xml"
+ With log4j2, we leverage the [`JsonTemplateLayout`](https://logging.apache.org/log4j/2.x/manual/json-template-layout.html){target="_blank"}
+ to provide structured logging. A default template is provided in powertools ([_LambdaJsonLayout.json_](https://github.com/aws-powertools/powertools-lambda-java/tree/v2/powertools-logging/powertools-logging-log4j/src/main/resources/LambdaJsonLayout.json){target="_blank"}):
+
```xml hl_lines="5"
@@ -168,7 +214,7 @@ Powertools for AWS Lambda (Java) extends the functionality of Log4J. Below is an
-
+
@@ -178,148 +224,286 @@ Powertools for AWS Lambda (Java) extends the functionality of Log4J. Below is an
```
-You can also override log level by setting **`POWERTOOLS_LOG_LEVEL`** env var. Here is an example using AWS Serverless Application Model (SAM)
+=== "logback.xml"
-=== "template.yaml"
- ``` yaml hl_lines="9 10"
- Resources:
- HelloWorldFunction:
- Type: AWS::Serverless::Function
- Properties:
- ...
- Runtime: java8
- Environment:
- Variables:
- POWERTOOLS_LOG_LEVEL: DEBUG
- POWERTOOLS_SERVICE_NAME: example
+ With logback, we leverage a custom [Encoder](https://logback.qos.ch/manual/encoders.html){target="_blank"}
+ to provide structured logging:
+
+ ```xml hl_lines="4 5"
+
+
+
+
+
+
+
+
+
+
+
+
+
```
-You can also explicitly set a service name via **`POWERTOOLS_SERVICE_NAME`** env var. This sets **service** key that will be present across all log statements.
+## Log level
+Log level is generally configured in the `log4j2.xml` or `logback.xml`. But this level is static and needs a redeployment of the function to be changed.
+Powertools for AWS Lambda permits to change this level dynamically thanks to an environment variable `POWERTOOLS_LOG_LEVEL`.
-## Standard structured keys
+We support the following log levels (SLF4J levels): `TRACE` (0), `DEBUG` (10), `INFO` (20), `WARN` (30), `ERROR` (40).
+If the level is set to `CRITICAL` (supported in log4j but not logback), we revert it back to `ERROR`.
+If the level is set to any other value, we set it to the default value (`INFO`).
-Your logs will always include the following keys to your structured logging:
+### AWS Lambda Advanced Logging Controls (ALC)
-Key | Type | Example | Description
-------------------------------------------------- | ------------------------------------------------- | --------------------------------------------------------------------------------- | -------------------------------------------------
-**timestamp** | String | "2020-05-24 18:17:33,774" | Timestamp of actual log statement
-**level** | String | "INFO" | Logging level
-**cold_start** | Boolean | true| ColdStart value.
-**service** | String | "payment" | Service name defined. "service_undefined" will be used if unknown
-**sampling_rate** | int | 0.1 | Debug logging sampling rate in percentage e.g. 10% in this case
-**message** | String | "Collecting payment" | Log statement value. Unserializable JSON values will be casted to string
-**function_name**| String | "example-powertools-HelloWorldFunction-1P1Z6B39FLU73"
-**function_version**| String | "12"
-**function_memory_size**| String | "128"
-**function_arn**| String | "arn:aws:lambda:eu-west-1:012345678910:function:example-powertools-HelloWorldFunction-1P1Z6B39FLU73"
-**xray_trace_id**| String | "1-5759e988-bd862e3fe1be46a994272793" | X-Ray Trace ID when Lambda function has enabled Tracing
-**function_request_id**| String | "899856cb-83d1-40d7-8611-9e78f15f32f4"" | AWS Request ID from lambda context
+!!!question "When is it useful?"
+ When you want to set a logging policy to drop informational or verbose logs for one or all AWS Lambda functions, regardless of runtime and logger used.
-## Capturing context Lambda info
+
+With [AWS Lambda Advanced Logging Controls (ALC)](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs.html#monitoring-cloudwatchlogs-advanced){target="_blank"}, you can enforce a minimum log level that Lambda will accept from your application code.
-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.
+When enabled, you should keep Powertools and ALC log level in sync to avoid data loss.
-!!! warning
- Log event is disabled by default to prevent sensitive info being logged.
+Here's a sequence diagram to demonstrate how ALC will drop both `INFO` and `DEBUG` logs emitted from `Logger`, when ALC log level is stricter than `Logger`.
+
+```mermaid
+sequenceDiagram
+ participant Lambda service
+ participant Lambda function
+ participant Application Logger
-=== "App.java"
+ Note over Lambda service: AWS_LAMBDA_LOG_LEVEL="WARN"
+ Note over Application Logger: POWERTOOLS_LOG_LEVEL="DEBUG"
- ```java hl_lines="14"
- import org.apache.logging.log4j.LogManager;
- import org.apache.logging.log4j.Logger;
- import software.amazon.lambda.powertools.logging.LoggingUtils;
+ Lambda service->>Lambda function: Invoke (event)
+ Lambda function->>Lambda function: Calls handler
+ Lambda function->>Application Logger: logger.error("Something happened")
+ Lambda function-->>Application Logger: logger.debug("Something happened")
+ Lambda function-->>Application Logger: logger.info("Something happened")
+ Lambda service--xLambda service: DROP INFO and DEBUG logs
+ Lambda service->>CloudWatch Logs: Ingest error logs
+```
+
+### Priority of log level settings in Powertools for AWS Lambda
+
+We prioritise log level settings in this order:
+
+1. `AWS_LAMBDA_LOG_LEVEL` environment variable
+2. `POWERTOOLS_LOG_LEVEL` environment variable
+3. level defined in the `log4j2.xml` or `logback.xml` files
+
+If you set Powertools level lower than ALC, we will emit a warning informing you that your messages will be discarded by Lambda.
+
+> **NOTE**
+>
+> With ALC enabled, we are unable to increase the minimum log level below the `AWS_LAMBDA_LOG_LEVEL` environment variable value, see [AWS Lambda service documentation](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs.html#monitoring-cloudwatchlogs-log-level){target="_blank"} for more details.
+
+## Basic Usage
+
+To use Lambda Powertools for AWS Lambda Logging, use the `@Logging` annotation in your code and the standard _SLF4J_ logger:
+
+=== "PaymentFunction.java"
+
+ ```java hl_lines="8 10 12 14"
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
import software.amazon.lambda.powertools.logging.Logging;
- ...
-
- /**
- * Handler for requests to Lambda function.
- */
- public class App implements RequestHandler {
+ // ... other imports
+
+ public class PaymentFunction implements RequestHandler {
- Logger log = LogManager.getLogger(App.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(PaymentFunction.class);
+
+ @Logging
+ public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
+ LOGGER.info("Collecting payment");
+ // ...
+ LOGGER.debug("order={}, amount={}", order.getId(), order.getAmount());
+ // ...
+ }
+ }
+ ```
+
+## Standard structured keys
+
+Your logs will always include the following keys in your structured logging:
+
+| Key | Type | Example | Description |
+|-------------------|--------|-----------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------|
+| **timestamp** | String | "2023-12-01T14:49:19.293Z" | Timestamp of actual log statement, by default uses default AWS Lambda timezone (UTC) |
+| **level** | String | "INFO" | Logging level (any level supported by _SLF4J_ (i.e. `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`) |
+| **service** | String | "payment" | Service name defined, by default `service_undefined` |
+| **sampling_rate** | float | 0.1 | Debug logging sampling rate in percentage e.g. 10% in this case (logged if not 0) |
+| **message** | String | "Collecting payment" | Log statement value. Unserializable JSON values will be casted to string |
+| **xray_trace_id** | String | "1-5759e988-bd862e3fe1be46a994272793" | X-Ray Trace ID when [Tracing is enabled](https://docs.aws.amazon.com/lambda/latest/dg/services-xray.html){target="_blank"} |
+| **error** | Map | `{ "name": "InvalidAmountException", "message": "Amount must be superior to 0", "stack": "at..." }` | Eventual exception (e.g. when doing `logger.error("Error", new InvalidAmountException("Amount must be superior to 0"));`) |
+
+### Log messages as JSON
+By default, `message` is logged as a `String` (e.g `"message": "The message"`). When logging JSON content,
+you may want to avoid the escaped String (`"message:"{\"key\":\"value\"}"`) for better readability.
+You can use `LoggingUtils.logMessagesAsJson(true)` to enable this programmatically.
+
+=== "PaymentFunction.java"
+
+ ```java hl_lines="14 15 17-20"
+ import static software.amazon.lambda.powertools.utilities.EventDeserializer.extractDataFrom;
+ import software.amazon.lambda.powertools.logging.LoggingUtils;
+ import software.amazon.lambda.powertools.utilities.JsonConfig;
+ // ... other imports
+
+ public class PaymentFunction implements RequestHandler {
+ private static final Logger LOGGER = LoggerFactory.getLogger(PaymentFunction.class);
+
@Logging
public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
- ...
+ Order order = extractDataFrom(input).as(Order.class);
+
+ // logged as a String
+ LOGGER.debug("{}", JsonConfig.get().getObjectMapper().writeValueAsString(order));
+
+ // Logged as JSON
+ LoggingUtils.logMessagesAsJson(true);
+ LOGGER.debug("{}", JsonConfig.get().getObjectMapper().writeValueAsString(order));
+ LoggingUtils.logMessagesAsJson(false);
+
+ // ...
}
}
```
+=== "Order.java"
+
+ ```java
+ public class Order {
+ private String id;
+ private Date date;
+ private Double amount;
+ }
+ ```
+
+=== "Example CloudWatch Logs"
+
+ ```json hl_lines="3 9-13"
+ {
+ "level": "DEBUG",
+ "message": "{\"id\":\"435iuh2j3hb4\", \"date\":\"2023-12-01T14:48:59\", \"amount\":435.5}",
+ "timestamp": "2023-12-01T14:49:19.293Z",
+ "service": "payment",
+ }
+ {
+ "level": "DEBUG",
+ "message": {
+ "id": "435iuh2j3hb4",
+ "date": "2023-12-01T14:48:59",
+ "amount":435.5
+ },
+ "timestamp": "2023-12-01T14:49:19.312Z",
+ "service": "payment",
+ }
+ ```
+
+You can also achieve this more broadly for all JSON messages (see advanced configuration for [log4j](#log-messages-as-json-1) & [logback](#log-messages-as-json-2)).
+
+## Additional structured keys
+
+### Logging Lambda context information
+The following keys will also be added to your structured logs (unless [configured otherwise](#more-customization-1)):
+
+| Key | Type | Example | Description |
+|--------------------------|---------|----------------------------------------------------------------------------------------|------------------------------------|
+| **cold_start** | Boolean | false | ColdStart value |
+| **function_name** | String | "example-PaymentFunction-1P1Z6B39FLU73" | Name of the function |
+| **function_version** | String | "12" | Version of the function |
+| **function_memory_size** | String | "512" | Memory configure for the function |
+| **function_arn** | String | "arn:aws:lambda:eu-west-1:012345678910:function:example-PaymentFunction-1P1Z6B39FLU73" | ARN of the function |
+| **function_request_id** | String | "899856cb-83d1-40d7-8611-9e78f15f32f4"" | AWS Request ID from lambda context |
+
+
+### Logging incoming event
+
+When debugging in non-production environments, you can instruct the `@Logging` annotation to log the incoming event with `logEvent` param or via `POWERTOOLS_LOGGER_LOG_EVENT` env var.
+
+???+ warning
+ This is disabled by default to prevent sensitive info being logged
+
=== "AppLogEvent.java"
- ```java hl_lines="8"
- /**
- * Handler for requests to Lambda function.
- */
- public class AppLogEvent implements RequestHandler {
+ ```java hl_lines="5"
+ public class AppLogEvent implements RequestHandler {
- Logger log = LogManager.getLogger(AppLogEvent.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(AppLogEvent.class);
@Logging(logEvent = true)
public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
- ...
+ // ...
}
}
```
-### Customising fields in logs
+### Logging handler response
-- Utility by default emits `timestamp` field in the logs in format `yyyy-MM-dd'T'HH:mm:ss.SSSZz` and in system default timezone.
-If you need to customize format and timezone, you can do so by configuring `log4j2.component.properties` and configuring properties as shown in example below:
+When debugging in non-production environments, you can instruct the `@Logging` annotation to log the response with `logResponse` param or via `POWERTOOLS_LOGGER_LOG_RESPONSE` env var.
-=== "log4j2.component.properties"
+???+ warning
+ This is disabled by default to prevent sensitive info being logged
- ```properties hl_lines="1 2"
- log4j.layout.jsonTemplate.timestampFormatPattern=yyyy-MM-dd'T'HH:mm:ss.SSSZz
- log4j.layout.jsonTemplate.timeZone=Europe/Oslo
+=== "AppLogResponse.java"
+
+ ```java hl_lines="5"
+ public class AppLogResponse implements RequestHandler {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(AppLogResponse.class);
+
+ @Logging(logResponse = true)
+ public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
+ // ...
+ }
+ }
```
-- Utility also provides sample template for [Elastic Common Schema(ECS)](https://www.elastic.co/guide/en/ecs/current/ecs-reference.html) layout.
-The field emitted in logs will follow specs from [ECS](https://www.elastic.co/guide/en/ecs/current/ecs-reference.html) together with field captured by utility as mentioned [above](#standard-structured-keys).
+### Logging handler uncaught exception
+By default, AWS Lambda logs any uncaught exception that might happen in the handler. However, this log is not structured
+and does not contain any additional context. You can instruct the `@Logging` annotation to log this kind of exception
+with `logError` param or via `POWERTOOLS_LOGGER_LOG_ERROR` env var.
- Use `LambdaEcsLayout.json` as `eventTemplateUri` when configuring `JsonTemplateLayout`.
+???+ warning
+ This is disabled by default to prevent double logging
-=== "log4j2.xml"
+=== "AppLogResponse.java"
- ```xml hl_lines="5"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ ```java hl_lines="5"
+ public class AppLogError implements RequestHandler {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(AppLogError.class);
+
+ @Logging(logError = true)
+ public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
+ // ...
+ }
+ }
```
-## Setting a Correlation ID
+### Logging additional keys
-You can set a Correlation ID using `correlationIdPath` attribute by passing a [JSON Pointer expression](https://datatracker.ietf.org/doc/html/draft-ietf-appsawg-json-pointer-03){target="_blank"}.
+#### Logging a correlation ID
-=== "App.java"
+You can set a correlation ID using the `correlationIdPath` attribute of the `@Logging`annotation,
+by passing a [JMESPath expression](https://jmespath.org/tutorial.html){target="_blank"},
+including our custom [JMESPath Functions](../utilities/serialization.md#built-in-functions).
- ```java hl_lines="8"
- /**
- * Handler for requests to Lambda function.
- */
- public class App implements RequestHandler {
+=== "AppCorrelationId.java"
+
+ ```java hl_lines="5"
+ public class AppCorrelationId implements RequestHandler {
- Logger log = LogManager.getLogger(App.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(AppCorrelationId.class);
- @Logging(correlationIdPath = "/headers/my_request_id_header")
+ @Logging(correlationIdPath = "headers.my_request_id_header")
public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
- ...
- log.info("Collecting payment")
- ...
+ // ...
+ LOGGER.info("Collecting payment")
+ // ...
}
}
```
@@ -333,42 +517,89 @@ You can set a Correlation ID using `correlationIdPath` attribute by passing a [J
}
```
-=== "Example CloudWatch Logs excerpt"
+=== "Example CloudWatch Logs"
- ```json hl_lines="11"
+ ```json hl_lines="6"
{
"level": "INFO",
"message": "Collecting payment",
- "timestamp": "2021-05-03 11:47:12,494+0200",
+ "timestamp": "2023-12-01T14:49:19.293Z",
"service": "payment",
- "cold_start": true,
- "function_name": "test",
- "function_memory_size": 128,
- "function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
- "function_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72",
"correlation_id": "correlation_id_value"
}
```
-We provide [built-in JSON Pointer expression](https://datatracker.ietf.org/doc/html/draft-ietf-appsawg-json-pointer-03){target="_blank"}
-for known event sources, where either a request ID or X-Ray Trace ID are present.
-=== "App.java"
+** setCorrelationId method**
+
+You can also use `LoggingUtils.setCorrelationId()` method to inject it anywhere else in your code.
+
+=== "AppCorrelationId.java"
+
+ ```java hl_lines="8"
+ public class AppCorrelationId implements RequestHandler {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(AppCorrelationId.class);
+
+ @Logging
+ public String handleRequest(final ScheduledEvent event, final Context context) {
+ // ...
+ LoggingUtils.setCorrelationId(event.getId());
+ LOGGER.info("Scheduled Event")
+ // ...
+ }
+ }
+ ```
+
+=== "Example Event"
- ```java hl_lines="10"
+ ```json hl_lines="2"
+ {
+ "id": "cdc73f9d-aea9-11e3-9d5a-835b769c0d9c",
+ "detail-type": "Scheduled Event",
+ "source": "aws.events",
+ "account": "123456789012",
+ "time": "2023-12-01T14:49:19Z",
+ "region": "us-east-1",
+ "resources": [
+ "arn:aws:events:us-east-1:123456789012:rule/ExampleRule"
+ ],
+ "detail": {}
+ }
+ ```
+
+=== "Example CloudWatch Logs"
+
+ ```json hl_lines="6"
+ {
+ "level": "INFO",
+ "message": "Scheduled Event",
+ "timestamp": "2023-12-01T14:49:19.293Z",
+ "service": "payment",
+ "correlation_id": "cdc73f9d-aea9-11e3-9d5a-835b769c0d9c"
+ }
+ ```
+???+ tip
+ You can retrieve correlation IDs via `LoggingUtils.getCorrelationId()` method if needed.
+
+** Known correlation IDs **
+
+To ease routine tasks like extracting correlation ID from popular event sources,
+we provide [built-in JMESPath expressions](#built-in-correlation-id-expressions).
+
+=== "AppCorrelationId.java"
+
+ ```java hl_lines="1 7"
import software.amazon.lambda.powertools.logging.CorrelationIdPaths;
- /**
- * Handler for requests to Lambda function.
- */
- public class App implements RequestHandler {
+ public class AppCorrelationId implements RequestHandler {
- Logger log = LogManager.getLogger(App.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(AppCorrelationId.class);
- @Logging(correlationIdPath = CorrelationIdPathConstants.API_GATEWAY_REST)
+ @Logging(correlationIdPath = CorrelationIdPaths.API_GATEWAY_REST)
public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
- ...
- log.info("Collecting payment")
- ...
+ // ...
+ LOGGER.info("Collecting payment")
+ // ...
}
}
```
@@ -377,316 +608,511 @@ for known event sources, where either a request ID or X-Ray Trace ID are present
```json hl_lines="3"
{
- "requestContext": {
- "requestId": "correlation_id_value"
- }
+ "requestContext": {
+ "requestId": "correlation_id_value"
+ }
}
```
-=== "Example CloudWatch Logs excerpt"
+=== "Example CloudWatch Logs"
- ```json hl_lines="11"
+ ```json hl_lines="6"
{
"level": "INFO",
"message": "Collecting payment",
- "timestamp": "2021-05-03 11:47:12,494+0200",
+ "timestamp": "2023-12-01T14:49:19.293Z",
"service": "payment",
- "cold_start": true,
- "function_name": "test",
- "function_memory_size": 128,
- "function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
- "function_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72",
"correlation_id": "correlation_id_value"
}
```
-
-## Appending additional keys
-!!! info "Custom keys are persisted across warm invocations"
- Always set additional keys as part of your handler to ensure they have the latest value, or explicitly clear them with [`clearState=true`](#clearing-all-state).
+#### Custom keys
-You can append your own keys to your existing logs via `appendKey`.
+???+ warning "Custom keys are persisted across warm invocations"
+ Always set additional keys as part of your handler method to ensure they have the latest value, or explicitly clear them with [`clearState=true`](#clearing-state).
-=== "App.java"
+To append an additional key in your logs, you can use the `LoggingUtils.appendKey()` or `LoggingUtils.appendKeys()` for multiple keys:
- ```java hl_lines="11 19"
- /**
- * Handler for requests to Lambda function.
- */
- public class App implements RequestHandler {
+=== "PaymentFunction.java"
+
+ ```java hl_lines="8 9 15 16"
+ public class PaymentFunction implements RequestHandler {
- Logger log = LogManager.getLogger(App.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(AppLogResponse.class);
- @Logging(logEvent = true)
+ @Logging
public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
- ...
- LoggingUtils.appendKey("test", "willBeLogged");
- ...
-
- ...
- Map customKeys = new HashMap<>();
- customKeys.put("test", "value");
- customKeys.put("test1", "value1");
+ // ...
+ LoggingUtils.appendKey("orderId", order.getId());
+ LOGGER.info("Collecting payment");
- LoggingUtils.appendKeys(customKeys);
- ...
+ // ...
+ Map customKeys = new HashMap<>();
+ customKeys.put("paymentId", payment.getId());
+ customKeys.put("amount", payment.getAmount);
+ LoggingUtils.appendKeys(customKeys);
+ LOGGER.info("Payment successful");
}
}
```
+=== "Example CloudWatch Logs"
+
+ ```json hl_lines="7 16-18"
+ {
+ "level": "INFO",
+ "message": "Collecting payment",
+ "service": "payment",
+ "timestamp": "2023-12-01T14:49:19.293Z",
+ "xray_trace_id": "1-6569f266-4b0c7f97280dcd8428d3c9b5",
+ "orderId": "41376"
+ }
+ ...
+ {
+ "level": "INFO",
+ "message": "Payment successful",
+ "service": "payment",
+ "timestamp": "2023-12-01T14:49:20.118Z",
+ "xray_trace_id": "1-6569f266-4b0c7f97280dcd8428d3c9b5",
+ "orderId": "41376",
+ "paymentId": "3245",
+ "amount": 345.99
+ }
+ ```
+
+???+ tip "Additional keys are based on the MDC"
+ Mapped Diagnostic Context (MDC) is essentially a Key-Value store. It is supported by the [SLF4J API](https://www.slf4j.org/manual.html#mdc){target="_blank"},
+ [logback](https://logback.qos.ch/manual/mdc.html){target="_blank"} and log4j (known as [ThreadContext](https://logging.apache.org/log4j/2.x/manual/thread-context.html){target="_blank"}).
+
+ `LoggingUtils.appendKey("key", "value")` is equivalent to `MDC.put("key", "value")`.
+
### Removing additional keys
-You can remove any additional key from entry using `LoggingUtils.removeKeys()`.
+You can remove any additional key from entry using `LoggingUtils.removeKey()` or `LoggingUtils.removeKeys()` for multiple keys:
-=== "App.java"
+=== "PaymentFunction.java"
```java hl_lines="19 20"
- /**
- * Handler for requests to Lambda function.
- */
- public class App implements RequestHandler {
+ public class PaymentFunction implements RequestHandler {
- Logger log = LogManager.getLogger(App.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(AppLogResponse.class);
- @Logging(logEvent = true)
+ @Logging(logResponse = true)
public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
- ...
- LoggingUtils.appendKey("test", "willBeLogged");
- ...
- Map customKeys = new HashMap<>();
- customKeys.put("test1", "value");
- customKeys.put("test2", "value1");
+ // ...
+ LoggingUtils.appendKey("orderId", order.getId());
+ LOGGER.info("Collecting payment");
+ // ...
+ Map customKeys = new HashMap<>();
+ customKeys.put("paymentId", payment.getId());
+ customKeys.put("amount", payment.getAmount);
LoggingUtils.appendKeys(customKeys);
- ...
- LoggingUtils.removeKey("test");
- LoggingUtils.removeKeys("test1", "test2");
- ...
+ LOGGER.info("Payment successful");
+
+ // ...
+ LoggingUtils.removeKey("orderId");
+ LoggingUtils.removeKeys("paymentId", "amount");
+
+ return response;
}
}
```
-### Clearing all state
+=== "Example CloudWatch Logs"
+ Response is logged (`logResponse=true`) without the additional keys:
-Logger is commonly initialized in the global scope. Due to [Lambda Execution Context reuse](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-context.html),
-this means that custom keys can be persisted across invocations. If you want all custom keys to be deleted, you can use
-`clearState=true` attribute on `@Logging` annotation.
+ ```json
+ ...
+ {
+ "level": "INFO",
+ "message": {
+ "statusCode": 200,
+ "isBase64Encoded": false,
+ "body": ...,
+ "headers": ...,
+ "multiValueHeaders": ...
+ },
+ "service": "payment",
+ "timestamp": "2023-12-01T14:49:20.118Z",
+ "xray_trace_id": "1-6569f266-4b0c7f97280dcd8428d3c9b5"
+ }
+ ```
+???+ tip "Additional keys are based on the MDC"
+ `LoggingUtils.removeKey("key")` is equivalent to `MDC.remove("key")`.
-=== "App.java"
+#### Clearing state
- ```java hl_lines="8 12"
- /**
- * Handler for requests to Lambda function.
- */
- public class App implements RequestHandler {
+Logger is commonly initialized in the global scope. Due to [Lambda Execution Context reuse](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-context.html){target="_blank"},
+this means that custom keys can be persisted across invocations. If you want all custom keys to be deleted, you can use
+`clearState=true` attribute on the `@Logging` annotation.
+
+=== "CreditCardFunction.java"
+
+ ```java hl_lines="5 8"
+ public class CreditCardFunction implements RequestHandler {
- Logger log = LogManager.getLogger(App.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(CreditCardFunction.class);
@Logging(clearState = true)
public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
- ...
- if(input.getHeaders().get("someSpecialHeader")) {
- LoggingUtils.appendKey("specialKey", "value");
- }
-
- log.info("Collecting payment");
- ...
+ // ...
+ LoggingUtils.appendKey("cardNumber", card.getId());
+ LOGGER.info("Updating card information");
+ // ...
}
}
```
+
=== "#1 Request"
- ```json hl_lines="11"
- {
- "level": "INFO",
- "message": "Collecting payment",
- "timestamp": "2021-05-03 11:47:12,494+0200",
- "service": "payment",
- "cold_start": true,
- "function_name": "test",
- "function_memory_size": 128,
- "function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
- "function_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72",
- "specialKey": "value"
- }
+ ```json hl_lines="7"
+ {
+ "level": "INFO",
+ "message": "Updating card information",
+ "service": "card",
+ "timestamp": "2023-12-01T14:49:19.293Z",
+ "xray_trace_id": "1-6569f266-4b0c7f97280dcd8428d3c9b5",
+ "cardNumber": "6818 8419 9395 5322"
+ }
```
=== "#2 Request"
- ```json
- {
- "level": "INFO",
- "message": "Collecting payment",
- "timestamp": "2021-05-03 11:47:12,494+0200",
- "service": "payment",
- "cold_start": true,
- "function_name": "test",
- "function_memory_size": 128,
- "function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
- "function_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72"
- }
+ ```json hl_lines="7"
+ {
+ "level": "INFO",
+ "message": "Updating card information",
+ "service": "card",
+ "timestamp": "2023-12-01T14:49:20.213Z",
+ "xray_trace_id": "2-7a518f43-5e9d2b1f6cfd5e8b3a4e1f9c",
+ "cardNumber": "7201 6897 6685 3285"
+ }
```
-## Override default object mapper
-
-You can optionally choose to override default object mapper which is used to serialize lambda function events. You might
-want to supply custom object mapper in order to control how serialisation is done, for example, when you want to log only
-specific fields from received event due to security.
+???+ tip "Additional keys are based on the MDC"
+ `clearState` is based on `MDC.clear()`. State clearing is automatically done at the end of the execution of the handler if set to `true`.
-=== "App.java"
- ```java hl_lines="9 10"
- /**
- * Handler for requests to Lambda function.
- */
- public class App implements RequestHandler {
-
- Logger log = LogManager.getLogger(App.class);
-
- static {
- ObjectMapper objectMapper = new ObjectMapper();
- LoggingUtils.defaultObjectMapper(objectMapper);
- }
-
- @Logging(logEvent = true)
- public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
- ...
- }
- }
- ```
+# Advanced
## Sampling debug logs
You can dynamically set a percentage of your logs to **DEBUG** level via env var `POWERTOOLS_LOGGER_SAMPLE_RATE` or
-via `samplingRate` attribute on annotation.
+via `samplingRate` attribute on the `@Logging` annotation.
!!! info
Configuration on environment variable is given precedence over sampling rate configuration on annotation, provided it's in valid value range.
=== "Sampling via annotation attribute"
- ```java hl_lines="8"
- /**
- * Handler for requests to Lambda function.
- */
+ ```java hl_lines="5"
public class App implements RequestHandler {
- Logger log = LogManager.getLogger(App.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
@Logging(samplingRate = 0.5)
public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
- ...
+ // will eventually be logged based on the sampling rate
+ LOGGER.debug("Handle payment");
}
}
```
=== "Sampling via environment variable"
- ```yaml hl_lines="9"
+ ```yaml hl_lines="8"
Resources:
- HelloWorldFunction:
- Type: AWS::Serverless::Function
- Properties:
- ...
- Runtime: java8
- Environment:
- Variables:
- POWERTOOLS_LOGGER_SAMPLE_RATE: 0.5
+ PaymentFunction:
+ Type: AWS::Serverless::Function
+ Properties:
+ ...
+ Environment:
+ Variables:
+ POWERTOOLS_LOGGER_SAMPLE_RATE: 0.5
+
```
-## AWS Lambda Advanced Logging Controls (ALC)
+## Built-in Correlation ID expressions
-!!!question "When is it useful?"
- When you want to set a logging policy to drop informational or verbose logs for one or all AWS Lambda functions, regardless of runtime and logger used.
+You can use any of the following built-in JMESPath expressions as part of `@Logging(correlationIdPath = ...)`:
-
-With [AWS Lambda Advanced Logging Controls (ALC)](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs.html#monitoring-cloudwatchlogs-advanced){target="_blank"}, you can enforce a minimum log level that Lambda will accept from your application code.
+???+ note "Note: Any object key named with `-` must be escaped"
+ For example, **`request.headers."x-amzn-trace-id"`**.
-When enabled, you should keep `Logger` and ALC log level in sync to avoid data loss.
+| Name | Expression | Description |
+|-------------------------------|-------------------------------------|---------------------------------|
+| **API_GATEWAY_REST** | `"requestContext.requestId"` | API Gateway REST API request ID |
+| **API_GATEWAY_HTTP** | `"requestContext.requestId"` | API Gateway HTTP API request ID |
+| **APPSYNC_RESOLVER** | `request.headers."x-amzn-trace-id"` | AppSync X-Ray Trace ID |
+| **APPLICATION_LOAD_BALANCER** | `headers."x-amzn-trace-id"` | ALB X-Ray Trace ID |
+| **EVENT_BRIDGE** | `"id"` | EventBridge Event ID |
-Here's a sequence diagram to demonstrate how ALC will drop both `INFO` and `DEBUG` logs emitted from `Logger`, when ALC log level is stricter than `Logger`.
-
-```mermaid
-sequenceDiagram
- participant Lambda service
- participant Lambda function
- participant Application Logger
+## Customising fields in logs
- Note over Lambda service: AWS_LAMBDA_LOG_LEVEL="WARN"
- Note over Application Logger: POWERTOOLS_LOG_LEVEL="DEBUG"
+Powertools for AWS Lambda comes with default json structure ([standard fields](#standard-structured-keys) & [lambda context fields](#logging-lambda-context-information)).
- Lambda service->>Lambda function: Invoke (event)
- Lambda function->>Lambda function: Calls handler
- Lambda function->>Application Logger: logger.error("Something happened")
- Lambda function-->>Application Logger: logger.debug("Something happened")
- Lambda function-->>Application Logger: logger.info("Something happened")
- Lambda service--xLambda service: DROP INFO and DEBUG logs
- Lambda service->>CloudWatch Logs: Ingest error logs
+You can go further and customize which fields you want to keep in your logs or not. The configuration varies according to the underlying logging library.
+
+### Log4j2 configuration
+Log4j2 configuration is done in _log4j2.xml_ and leverages `JsonTemplateLayout`:
+
+```xml
+
+
+
```
-### Priority of log level settings in Powertools for AWS Lambda
+The `JsonTemplateLayout` is configured with the provided template:
-We prioritise log level settings in this order:
+??? example "LambdaJsonLayout.json"
+ ```json
+ {
+ "level": {
+ "$resolver": "level",
+ "field": "name"
+ },
+ "message": {
+ "$resolver": "powertools",
+ "field": "message"
+ },
+ "error": {
+ "message": {
+ "$resolver": "exception",
+ "field": "message"
+ },
+ "name": {
+ "$resolver": "exception",
+ "field": "className"
+ },
+ "stack": {
+ "$resolver": "exception",
+ "field": "stackTrace",
+ "stackTrace": {
+ "stringified": true
+ }
+ }
+ },
+ "cold_start": {
+ "$resolver": "powertools",
+ "field": "cold_start"
+ },
+ "function_arn": {
+ "$resolver": "powertools",
+ "field": "function_arn"
+ },
+ "function_memory_size": {
+ "$resolver": "powertools",
+ "field": "function_memory_size"
+ },
+ "function_name": {
+ "$resolver": "powertools",
+ "field": "function_name"
+ },
+ "function_request_id": {
+ "$resolver": "powertools",
+ "field": "function_request_id"
+ },
+ "function_version": {
+ "$resolver": "powertools",
+ "field": "function_version"
+ },
+ "sampling_rate": {
+ "$resolver": "powertools",
+ "field": "sampling_rate"
+ },
+ "service": {
+ "$resolver": "powertools",
+ "field": "service"
+ },
+ "timestamp": {
+ "$resolver": "timestamp",
+ "pattern": {
+ "format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
+ }
+ },
+ "xray_trace_id": {
+ "$resolver": "powertools",
+ "field": "xray_trace_id"
+ },
+ "": {
+ "$resolver": "powertools"
+ }
+ }
+ ```
-1. `AWS_LAMBDA_LOG_LEVEL` environment variable
-2. `POWERTOOLS_LOG_LEVEL` environment variable
+You can create your own template and leverage the [PowertoolsResolver](https://github.com/aws-powertools/powertools-lambda-java/tree/v2/powertools-logging/powertools-logging-log4j/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/PowertoolsResolver.java){target="_blank"}
+and any other resolver to log the desired fields with the desired format. Some examples of customization are given below:
-If you set `Logger` level lower than ALC, we will emit a warning informing you that your messages will be discarded by Lambda.
+#### Log messages as JSON
+`message` field is not handled with the standard [`MessageResolver`](https://logging.apache.org/log4j/2.x/manual/json-template-layout.html#event-template-resolver-message){target="_blank"} but by the `PowertoolsResolver`.
+With this resolver, you can choose to log all the JSON messages as JSON and not as String.
-> **NOTE**
->
-> With ALC enabled, we are unable to increase the minimum log level below the `AWS_LAMBDA_LOG_LEVEL` environment variable value, see [AWS Lambda service documentation](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs.html#monitoring-cloudwatchlogs-log-level){target="_blank"} for more details.
+=== "my-custom-template.json"
-### Timestamp format
+ ```json
+ {
+ "message": {
+ "$resolver": "powertools",
+ "field": "message",
+ "asJson": true
+ }
+ }
+ ```
-When the Advanced Logging Controls feature is enabled, Powertools for AWS Lambda must comply with the timestamp format required by AWS Lambda, which is [RFC3339](https://www.rfc-editor.org/rfc/rfc3339).
-In this case the format will be `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'`.
+#### Customising date format
-## Upgrade to JsonTemplateLayout from deprecated LambdaJsonLayout configuration in log4j2.xml
+Utility by default emits `timestamp` field in the logs in format `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'` and in system default timezone.
+If you need to customize format and timezone, you can update your template.json or by configuring `log4j2.component.properties` as shown in examples below:
-Prior to version [1.10.0](https://github.com/aws-powertools/powertools-lambda-java/releases/tag/v1.10.0), only supported way of configuring `log4j2.xml` was via ``. This plugin is
-deprecated now and will be removed in future version. Switching to `JsonTemplateLayout` is straight forward.
+=== "my-custom-template.json"
-Below examples shows deprecated and new configuration of `log4j2.xml`.
+ ```json
+ {
+ "timestamp": {
+ "$resolver": "timestamp",
+ "pattern": {
+ "format": "yyyy-MM-dd HH:mm:ss",
+ "timeZone": "Europe/Paris",
+ }
+ },
+ }
+ ```
-=== "Deprecated configuration of log4j2.xml"
+=== "log4j2.component.properties"
- ```xml hl_lines="5"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ ```properties hl_lines="1 2"
+ log4j.layout.jsonTemplate.timestampFormatPattern=yyyy-MM-dd'T'HH:mm:ss.SSSZz
+ log4j.layout.jsonTemplate.timeZone=Europe/Oslo
+ ```
+
+See [`TimestampResolver` documentation](https://logging.apache.org/log4j/2.x/manual/json-template-layout.html#event-template-resolver-timestamp){target="_blank"} for more details.
+
+???+ warning "Lambda Advanced Logging Controls date format"
+ When using the Lambda ALC, you must have a date format compatible with the [RFC3339](https://www.rfc-editor.org/rfc/rfc3339)
+
+#### More customization
+You can also customize how [exceptions are logged](https://logging.apache.org/log4j/2.x/manual/json-template-layout.html#event-template-resolver-exception){target="_blank"}, and much more.
+See the [JSON Layout template documentation](https://logging.apache.org/log4j/2.x/manual/json-template-layout.html){target="_blank"} for more details.
+
+### Logback configuration
+Logback configuration is done in _logback.xml_ and the Powertools [`LambdaJsonEncoder`]():
+
+```xml
+
+
+
+
+```
+
+The `LambdaJsonEncoder` can be customized in different ways:
+
+#### Log messages as JSON
+
+With the following configuration, you choose to log all the JSON messages as JSON and not as String (default is `false`):
+
+```xml
+
+ true
+
+```
+
+#### Customising date format
+Utility by default emits `timestamp` field in the logs in format `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'` and in system default timezone.
+If you need to customize format and timezone, you can change use the following:
+
+```xml
+
+ yyyy-MM-dd HH:mm:ss
+ Europe/Paris
+
+```
+
+#### More customization
+
+- You can use a standard `ThrowableHandlingConverter` to customize the exception format (default is no converter). Example:
+
+```xml
+
+
+ 30
+ 2048
+ 20
+ sun\.reflect\..*\.invoke.*
+ net\.sf\.cglib\.proxy\.MethodProxy\.invoke
+
+ true
+ true
+
+
+```
+
+- You can choose to add information about threads (default is `false`):
+
+```xml
+
+ true
+
+```
+
+- You can even choose to remove Powertools information from the logs like function name, arn:
+
+```xml
+
+ false
+
+```
+
+## Override default object mapper
+
+You can optionally choose to override default object mapper which is used to serialize lambda function events. You might
+want to supply custom object mapper in order to control how serialisation is done, for example, when you want to log only
+specific fields from received event due to security.
+
+=== "App.java"
+
+ ```java hl_lines="6-10"
+ public class App implements RequestHandler {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
+
+ static {
+ ObjectMapper objectMapper = new ObjectMapper()
+ .enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)
+ .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+ LoggingUtils.setObjectMapper(objectMapper);
+ }
+
+ @Logging(logEvent = true)
+ public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
+ // ...
+ }
+ }
```
-=== "New configuration of log4j2.xml"
+## Elastic Common Schema (ECS) Support
+
+Utility also supports [Elastic Common Schema(ECS)](https://www.elastic.co/guide/en/ecs/current/ecs-reference.html){target="_blank"} format.
+The field emitted in logs will follow specs from [ECS](https://www.elastic.co/guide/en/ecs/current/ecs-reference.html){target="_blank"} together with field captured by utility as mentioned [above](#standard-structured-keys).
+
+### Log4j2 configuration
+
+Use `LambdaEcsLayout.json` as `eventTemplateUri` when configuring `JsonTemplateLayout`.
+
+=== "log4j2.xml"
```xml hl_lines="5"
-
+
-
-
-
@@ -694,3 +1120,20 @@ Below examples shows deprecated and new configuration of `log4j2.xml`.
```
+### Logback configuration
+
+=== "logback.xml"
+
+Use the `LambdaEcsEncoder` rather than the `LambdaJsonEncoder` when configuring the appender:
+
+ ```xml
+
+
+
+
+
+
+
+
+
+ ```
\ No newline at end of file
diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css
index d135d7210..dc08ef51e 100644
--- a/docs/stylesheets/extra.css
+++ b/docs/stylesheets/extra.css
@@ -1,5 +1,5 @@
.md-grid {
- max-width: 81vw
+ max-width: 90vw
}
.highlight .hll {
diff --git a/mkdocs.yml b/mkdocs.yml
index a8569f664..b7f793e18 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -85,7 +85,7 @@ extra_javascript:
extra:
powertools:
- version: 1.18.0 # to update after each release (we do not want snapshot version here)
+ version: 2.0.0 # to update after each release (we do not want snapshot version here)
repo_url: https://github.com/aws-powertools/powertools-lambda-java
edit_uri: edit/main/docs
diff --git a/pom.xml b/pom.xml
index ca32c2785..6b8776822 100644
--- a/pom.xml
+++ b/pom.xml
@@ -73,7 +73,7 @@
1.81.8
- 2.20.0
+ 2.22.02.0.72.15.32.21.0
From 8cc5c665b26bc515480c2dfe98098dcbf4a39752 Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Thu, 7 Dec 2023 13:10:53 +0100
Subject: [PATCH 64/74] spotbugs
---
powertools-logging/spotbugs-exclude.xml | 19 -------------------
.../powertools/logging/LoggingUtils.java | 6 +++---
spotbugs-exclude.xml | 4 ++--
3 files changed, 5 insertions(+), 24 deletions(-)
diff --git a/powertools-logging/spotbugs-exclude.xml b/powertools-logging/spotbugs-exclude.xml
index 339d30a91..30a9c8557 100644
--- a/powertools-logging/spotbugs-exclude.xml
+++ b/powertools-logging/spotbugs-exclude.xml
@@ -21,25 +21,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java
index 6b7298524..4b280bbb7 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java
@@ -114,9 +114,9 @@ public static void setObjectMapper(ObjectMapper objectMapper) {
}
public static ObjectMapper getObjectMapper() {
- if (null == objectMapper) {
- objectMapper = JsonConfig.get().getObjectMapper();
+ if (null == LoggingUtils.objectMapper) {
+ LoggingUtils.objectMapper = JsonConfig.get().getObjectMapper();
}
- return objectMapper;
+ return LoggingUtils.objectMapper;
}
}
diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml
index ce6dfb803..a2559017c 100644
--- a/spotbugs-exclude.xml
+++ b/spotbugs-exclude.xml
@@ -94,7 +94,7 @@
-
+
@@ -115,7 +115,7 @@
-
+
From 13e18dccf88580cc18b0607f7bc46147126c4e87 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Van=20Der=20Linden?=
<117538+jeromevdl@users.noreply.github.com>
Date: Fri, 8 Dec 2023 14:59:14 +0100
Subject: [PATCH 65/74] Apply suggestions from code review on documentation
Co-authored-by: Scott Gerring
---
docs/core/logging.md | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/docs/core/logging.md b/docs/core/logging.md
index 40880327c..3f9df128f 100644
--- a/docs/core/logging.md
+++ b/docs/core/logging.md
@@ -7,12 +7,12 @@ Logging provides an opinionated logger with output structured as JSON.
## Key features
-* Leverages standard logging libraries: _SLF4J_ as the API, and _log4j2_ or _logback_ for the implementation
-* Capture key fields from Lambda context, cold start and structures logging output as JSON
-* Log Lambda event when instructed, disabled by default
-* Log Lambda response when instructed, disabled by default
-* Log sampling enables DEBUG log level for a percentage of requests (disabled by default)
-* Append additional keys to structured log at any point in time
+* Leverages standard logging libraries: [_SLF4J_](https://www.slf4j.org/){target="_blank"} as the API, and [_log4j2_](https://logging.apache.org/log4j/2.x/){target="_blank"} or [_logback_](https://logback.qos.ch/){target="_blank"} for the implementation
+* Captures key fields from Lambda context, cold start and structures logging output as JSON
+* Optionally logs Lambda request
+* Optionally logs Lambda response
+* Optionally supports log sampling by including a configurable percentage of DEBUG logs in logging output
+* Allows additional keys to be appended to the structured log at any point in time
## Getting started
@@ -21,7 +21,7 @@ Logging provides an opinionated logger with output structured as JSON.
You can find complete examples in the [project repository](https://github.com/aws-powertools/powertools-lambda-java/tree/v2/examples/powertools-examples-core-utilities){target="_blank"}.
### Installation
-Depending on your preferences, you might choose to use _log4j2_ or _logback_. In both case you need to configure _aspectj_
+Depending on preference, you must choose to use either _log4j2_ or _logback_ as your log provider. In both cases you need to configure _aspectj_
to weave the code and make sure the annotation is processed.
#### Maven
@@ -167,7 +167,7 @@ The logging module requires two settings:
| Environment variable | Setting | Description |
|---------------------------|-------------------|-------------------------------------------------------------------------------------------------------------|
| `POWERTOOLS_LOG_LEVEL` | **Logging level** | Sets how verbose Logger should be. If not set, will use the [Logging configuration](#logging-configuration) |
-| `POWERTOOLS_SERVICE_NAME` | **Service** | Sets service key that will be present across all log statements (Default is `service_undefined`) |
+| `POWERTOOLS_SERVICE_NAME` | **Service** | Sets service key that will be included in all log statements (Default is `service_undefined`) |
Here is an example using AWS Serverless Application Model (SAM):
@@ -190,7 +190,7 @@ There are some other environment variables which can be set to modify Logging's
| Environment variable | Type | Description |
|---------------------------------|----------|-------------------------------------------------------------------------------------------------------------------------|
-| `POWERTOOLS_LOGGER_SAMPLE_RATE` | float | Configure the sampling rate to set the log level at `DEBUG`. See [sampling rage](#sampling-debug-logs) |
+| `POWERTOOLS_LOGGER_SAMPLE_RATE` | float | Configure the sampling rate at which `DEBUG` logs should be included. See [sampling rate](#sampling-debug-logs) |
| `POWERTOOLS_LOG_EVENT` | boolean | Specify if the incoming Lambda event should be logged. See [Logging event](#logging-incoming-event) |
| `POWERTOOLS_LOG_RESPONSE` | boolean | Specify if the Lambda response should be logged. See [logging response](#logging-handler-response) |
| `POWERTOOLS_LOG_ERROR` | boolean | Specify if a Lambda uncaught exception should be logged. See [logging exception](#logging-handler-uncaught-exception ) |
@@ -249,7 +249,7 @@ You can leverage the standard configuration files (_log4j2.xml_ or _logback.xml_
Log level is generally configured in the `log4j2.xml` or `logback.xml`. But this level is static and needs a redeployment of the function to be changed.
Powertools for AWS Lambda permits to change this level dynamically thanks to an environment variable `POWERTOOLS_LOG_LEVEL`.
-We support the following log levels (SLF4J levels): `TRACE` (0), `DEBUG` (10), `INFO` (20), `WARN` (30), `ERROR` (40).
+We support the following log levels (SLF4J levels): `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`.
If the level is set to `CRITICAL` (supported in log4j but not logback), we revert it back to `ERROR`.
If the level is set to any other value, we set it to the default value (`INFO`).
@@ -408,7 +408,7 @@ You can also achieve this more broadly for all JSON messages (see advanced confi
## Additional structured keys
### Logging Lambda context information
-The following keys will also be added to your structured logs (unless [configured otherwise](#more-customization-1)):
+The following keys will also be added to all your structured logs (unless [configured otherwise](#more-customization-1)):
| Key | Type | Example | Description |
|--------------------------|---------|----------------------------------------------------------------------------------------|------------------------------------|
@@ -529,7 +529,7 @@ including our custom [JMESPath Functions](../utilities/serialization.md#built-in
}
```
-** setCorrelationId method**
+**setCorrelationId method**
You can also use `LoggingUtils.setCorrelationId()` method to inject it anywhere else in your code.
@@ -581,7 +581,7 @@ You can also use `LoggingUtils.setCorrelationId()` method to inject it anywhere
???+ tip
You can retrieve correlation IDs via `LoggingUtils.getCorrelationId()` method if needed.
-** Known correlation IDs **
+**Known correlation IDs**
To ease routine tasks like extracting correlation ID from popular event sources,
we provide [built-in JMESPath expressions](#built-in-correlation-id-expressions).
@@ -800,7 +800,7 @@ this means that custom keys can be persisted across invocations. If you want all
## Sampling debug logs
-You can dynamically set a percentage of your logs to **DEBUG** level via env var `POWERTOOLS_LOGGER_SAMPLE_RATE` or
+You can dynamically set a percentage of your logs to`DEBUG` level to be included in the logger output, regardless of configured log leve, using the`POWERTOOLS_LOGGER_SAMPLE_RATE` environment variable or
via `samplingRate` attribute on the `@Logging` annotation.
!!! info
@@ -866,7 +866,7 @@ Log4j2 configuration is done in _log4j2.xml_ and leverages `JsonTemplateLayout`
```
-The `JsonTemplateLayout` is configured with the provided template:
+The `JsonTemplateLayout` is automatically configured with the provided template:
??? example "LambdaJsonLayout.json"
```json
From b1d94a22b53b00586b98745c849ae0181f6f4f7d Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Thu, 7 Dec 2023 15:38:53 +0100
Subject: [PATCH 66/74] cleanup
---
.../powertools-examples-idempotency/pom.xml | 17 -----------------
.../logging/internal/LambdaEcsSerializer.java | 3 +--
2 files changed, 1 insertion(+), 19 deletions(-)
diff --git a/examples/powertools-examples-idempotency/pom.xml b/examples/powertools-examples-idempotency/pom.xml
index 13ea8dec1..5a040fec0 100644
--- a/examples/powertools-examples-idempotency/pom.xml
+++ b/examples/powertools-examples-idempotency/pom.xml
@@ -72,23 +72,6 @@
5.9.3test
-
- com.amazonaws
- DynamoDBLocal
- 1.23.0
- test
-
-
- com.fasterxml.jackson.datatype
- jackson-datatype-jsr310
- 2.15.2
- test
-
-
- com.amazonaws
- aws-lambda-java-tests
- 1.1.1
-
diff --git a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsSerializer.java b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsSerializer.java
index fabccf18b..124e0b5c6 100644
--- a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsSerializer.java
+++ b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaEcsSerializer.java
@@ -29,8 +29,7 @@
/**
* This class will serialize the log events in ecs format (ElasticSearch).
*
- * Inspired from the ElasticSearch Serializer co.elastic.logging.EcsJsonSerializer, this class doesn't use
- * any JSON (de)serialization library (Jackson, Gson, etc.) to avoid the dependency
+ * Inspired from the ElasticSearch Serializer co.elastic.logging.EcsJsonSerializer
*/
public class LambdaEcsSerializer {
protected static final String TIMESTAMP_ATTR_NAME = "@timestamp";
From 4d783080bd194b8745737fd35c5d25d2b32f3170 Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Thu, 7 Dec 2023 15:56:08 +0100
Subject: [PATCH 67/74] doc and test completion
---
.../powertools/logging/LoggingUtils.java | 11 +++++-----
.../logging/internal/LambdaLoggingAspect.java | 5 +++--
.../powertools/logging/LoggingUtilsTest.java | 21 +++++++++++++++++--
3 files changed, 28 insertions(+), 9 deletions(-)
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java
index 4b280bbb7..d7ceb8ccd 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/LoggingUtils.java
@@ -23,9 +23,8 @@
import software.amazon.lambda.powertools.utilities.JsonConfig;
/**
- * A class of helper functions to add additional functionality to Logging.
- *
- * {@see Logging}
+ * A class of helper functions to add functionality to Logging.
+ * Adding/removing keys is based on MDC, which is ThreadSafe.
*/
public final class LoggingUtils {
@@ -105,7 +104,9 @@ public static void logMessagesAsJson(boolean value) {
/**
* Sets the instance of ObjectMapper object which is used for serialising event when
- * {@code @Logging(logEvent = true)}.
+ * {@code @Logging(logEvent = true, logResponse = true)}.
+ *
+ * Not Thread Safe, the object mapper is static, changing it in different threads can lead to unexpected behaviour
*
* @param objectMapper Custom implementation of object mapper to be used for logging serialised event
*/
@@ -114,7 +115,7 @@ public static void setObjectMapper(ObjectMapper objectMapper) {
}
public static ObjectMapper getObjectMapper() {
- if (null == LoggingUtils.objectMapper) {
+ if (LoggingUtils.objectMapper == null) {
LoggingUtils.objectMapper = JsonConfig.get().getObjectMapper();
}
return LoggingUtils.objectMapper;
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
index 9ab53718d..c371ead06 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
@@ -303,7 +303,8 @@ private Object[] logRequestStreamHandlerEvent(final ProceedingJoinPoint pjp) {
try {
byte[] bytes = bytesFromInputStreamSafely((InputStream) pjp.getArgs()[0]);
args[0] = new ByteArrayInputStream(bytes);
- log.info("{}", new String(bytes, UTF_8)); // do not log asJson as it can be something else (String, XML...)
+ // do not log asJson as it can be something else (String, XML...)
+ log.info("{}", new String(bytes, UTF_8));
} catch (IOException e) {
LOG.warn("Failed to log event from supplied input stream.", e);
}
@@ -325,7 +326,7 @@ private void logRequestStreamHandlerResponse(final ProceedingJoinPoint pjp, fina
Logger log = logger(pjp);
if (log.isInfoEnabled()) {
LoggingUtils.logMessagesAsJson(true);
- // we do not log with asJson as it can be something else (string, xml, ...)
+ // we do not log with asJson as it can be something else (String, XML, ...)
log.info("{}", new String(bytes, UTF_8));
LoggingUtils.logMessagesAsJson(false);
}
diff --git a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/LoggingUtilsTest.java b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/LoggingUtilsTest.java
index c06b69767..04e977c58 100644
--- a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/LoggingUtilsTest.java
+++ b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/LoggingUtilsTest.java
@@ -16,11 +16,14 @@
import static org.assertj.core.api.Assertions.assertThat;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.MDC;
+import software.amazon.lambda.powertools.utilities.JsonConfig;
class LoggingUtilsTest {
@@ -88,10 +91,24 @@ void shouldRemoveCustomKeysInLoggingContext() {
@Test
void shouldAddCorrelationIdToLoggingContext() {
- LoggingUtils.setCorrelationId("correlationID_12345");
+ String id = "correlationID_12345";
+ LoggingUtils.setCorrelationId(id);
assertThat(MDC.getCopyOfContextMap())
.hasSize(1)
- .containsEntry("correlation_id", "correlationID_12345");
+ .containsEntry("correlation_id", id);
+
+ assertThat(LoggingUtils.getCorrelationId()).isEqualTo(id);
+ }
+
+ @Test
+ void shouldGetObjectMapper() {
+ assertThat(LoggingUtils.getObjectMapper()).isNotNull();
+ assertThat(LoggingUtils.getObjectMapper()).isEqualTo(JsonConfig.get().getObjectMapper());
+
+ ObjectMapper mapper = new ObjectMapper().disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
+ LoggingUtils.setObjectMapper(mapper);
+ assertThat(LoggingUtils.getObjectMapper()).isEqualTo(mapper);
+
}
}
\ No newline at end of file
From 11efab33fef1230ed3e1e98a0634164a043298d1 Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Fri, 8 Dec 2023 14:59:59 +0100
Subject: [PATCH 68/74] update elastic doc
---
docs/core/logging.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/core/logging.md b/docs/core/logging.md
index 3f9df128f..e33e9a332 100644
--- a/docs/core/logging.md
+++ b/docs/core/logging.md
@@ -1122,11 +1122,11 @@ Use `LambdaEcsLayout.json` as `eventTemplateUri` when configuring `JsonTemplateL
### Logback configuration
-=== "logback.xml"
-
Use the `LambdaEcsEncoder` rather than the `LambdaJsonEncoder` when configuring the appender:
- ```xml
+=== "logback.xml"
+
+ ```xml hl_lines="3"
From 83233c701dfc5cc21c15ce40e81b87ae06d92f57 Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Fri, 8 Dec 2023 15:14:29 +0100
Subject: [PATCH 69/74] improve doc
---
docs/core/logging.md | 153 +++++++++++++++++++++----------------------
1 file changed, 76 insertions(+), 77 deletions(-)
diff --git a/docs/core/logging.md b/docs/core/logging.md
index e33e9a332..cff12d34c 100644
--- a/docs/core/logging.md
+++ b/docs/core/logging.md
@@ -403,12 +403,12 @@ You can use `LoggingUtils.logMessagesAsJson(true)` to enable this programmatical
}
```
-You can also achieve this more broadly for all JSON messages (see advanced configuration for [log4j](#log-messages-as-json-1) & [logback](#log-messages-as-json-2)).
+You can also achieve this more broadly for all JSON messages (see advanced configuration for [log4j](#log-messages-as-json_1) & [logback](#log-messages-as-json_2)).
## Additional structured keys
### Logging Lambda context information
-The following keys will also be added to all your structured logs (unless [configured otherwise](#more-customization-1)):
+The following keys will also be added to all your structured logs (unless [configured otherwise](#more-customization_1)):
| Key | Type | Example | Description |
|--------------------------|---------|----------------------------------------------------------------------------------------|------------------------------------|
@@ -419,71 +419,6 @@ The following keys will also be added to all your structured logs (unless [confi
| **function_arn** | String | "arn:aws:lambda:eu-west-1:012345678910:function:example-PaymentFunction-1P1Z6B39FLU73" | ARN of the function |
| **function_request_id** | String | "899856cb-83d1-40d7-8611-9e78f15f32f4"" | AWS Request ID from lambda context |
-
-### Logging incoming event
-
-When debugging in non-production environments, you can instruct the `@Logging` annotation to log the incoming event with `logEvent` param or via `POWERTOOLS_LOGGER_LOG_EVENT` env var.
-
-???+ warning
- This is disabled by default to prevent sensitive info being logged
-
-=== "AppLogEvent.java"
-
- ```java hl_lines="5"
- public class AppLogEvent implements RequestHandler {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(AppLogEvent.class);
-
- @Logging(logEvent = true)
- public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
- // ...
- }
- }
- ```
-
-### Logging handler response
-
-When debugging in non-production environments, you can instruct the `@Logging` annotation to log the response with `logResponse` param or via `POWERTOOLS_LOGGER_LOG_RESPONSE` env var.
-
-???+ warning
- This is disabled by default to prevent sensitive info being logged
-
-=== "AppLogResponse.java"
-
- ```java hl_lines="5"
- public class AppLogResponse implements RequestHandler {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(AppLogResponse.class);
-
- @Logging(logResponse = true)
- public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
- // ...
- }
- }
- ```
-
-### Logging handler uncaught exception
-By default, AWS Lambda logs any uncaught exception that might happen in the handler. However, this log is not structured
-and does not contain any additional context. You can instruct the `@Logging` annotation to log this kind of exception
-with `logError` param or via `POWERTOOLS_LOGGER_LOG_ERROR` env var.
-
-???+ warning
- This is disabled by default to prevent double logging
-
-=== "AppLogResponse.java"
-
- ```java hl_lines="5"
- public class AppLogError implements RequestHandler {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(AppLogError.class);
-
- @Logging(logError = true)
- public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
- // ...
- }
- }
- ```
-
### Logging additional keys
#### Logging a correlation ID
@@ -492,12 +427,12 @@ You can set a correlation ID using the `correlationIdPath` attribute of the `@Lo
by passing a [JMESPath expression](https://jmespath.org/tutorial.html){target="_blank"},
including our custom [JMESPath Functions](../utilities/serialization.md#built-in-functions).
-=== "AppCorrelationId.java"
+=== "AppCorrelationIdPath.java"
```java hl_lines="5"
- public class AppCorrelationId implements RequestHandler {
+ public class AppCorrelationIdPath implements RequestHandler {
- private static final Logger LOGGER = LoggerFactory.getLogger(AppCorrelationId.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(AppCorrelationIdPath.class);
@Logging(correlationIdPath = "headers.my_request_id_header")
public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
@@ -507,7 +442,7 @@ including our custom [JMESPath Functions](../utilities/serialization.md#built-in
}
}
```
-=== "Example Event"
+=== "Example HTTP Event"
```json hl_lines="3"
{
@@ -517,7 +452,7 @@ including our custom [JMESPath Functions](../utilities/serialization.md#built-in
}
```
-=== "Example CloudWatch Logs"
+=== "CloudWatch Logs"
```json hl_lines="6"
{
@@ -533,12 +468,12 @@ including our custom [JMESPath Functions](../utilities/serialization.md#built-in
You can also use `LoggingUtils.setCorrelationId()` method to inject it anywhere else in your code.
-=== "AppCorrelationId.java"
+=== "AppSetCorrelationId.java"
```java hl_lines="8"
- public class AppCorrelationId implements RequestHandler {
+ public class AppSetCorrelationId implements RequestHandler {
- private static final Logger LOGGER = LoggerFactory.getLogger(AppCorrelationId.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(AppSetCorrelationId.class);
@Logging
public String handleRequest(final ScheduledEvent event, final Context context) {
@@ -550,7 +485,7 @@ You can also use `LoggingUtils.setCorrelationId()` method to inject it anywhere
}
```
-=== "Example Event"
+=== "Example Schedule Event"
```json hl_lines="2"
{
@@ -567,7 +502,7 @@ You can also use `LoggingUtils.setCorrelationId()` method to inject it anywhere
}
```
-=== "Example CloudWatch Logs"
+=== "CloudWatch Logs with correlation id"
```json hl_lines="6"
{
@@ -796,6 +731,70 @@ this means that custom keys can be persisted across invocations. If you want all
`clearState` is based on `MDC.clear()`. State clearing is automatically done at the end of the execution of the handler if set to `true`.
+## Logging incoming event
+
+When debugging in non-production environments, you can instruct the `@Logging` annotation to log the incoming event with `logEvent` param or via `POWERTOOLS_LOGGER_LOG_EVENT` env var.
+
+???+ warning
+ This is disabled by default to prevent sensitive info being logged
+
+=== "AppLogEvent.java"
+
+ ```java hl_lines="5"
+ public class AppLogEvent implements RequestHandler {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(AppLogEvent.class);
+
+ @Logging(logEvent = true)
+ public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
+ // ...
+ }
+ }
+ ```
+
+## Logging handler response
+
+When debugging in non-production environments, you can instruct the `@Logging` annotation to log the response with `logResponse` param or via `POWERTOOLS_LOGGER_LOG_RESPONSE` env var.
+
+???+ warning
+ This is disabled by default to prevent sensitive info being logged
+
+=== "AppLogResponse.java"
+
+ ```java hl_lines="5"
+ public class AppLogResponse implements RequestHandler {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(AppLogResponse.class);
+
+ @Logging(logResponse = true)
+ public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
+ // ...
+ }
+ }
+ ```
+
+## Logging handler uncaught exception
+By default, AWS Lambda logs any uncaught exception that might happen in the handler. However, this log is not structured
+and does not contain any additional context. You can instruct the `@Logging` annotation to log this kind of exception
+with `logError` param or via `POWERTOOLS_LOGGER_LOG_ERROR` env var.
+
+???+ warning
+ This is disabled by default to prevent double logging
+
+=== "AppLogResponse.java"
+
+ ```java hl_lines="5"
+ public class AppLogError implements RequestHandler {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(AppLogError.class);
+
+ @Logging(logError = true)
+ public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
+ // ...
+ }
+ }
+ ```
+
# Advanced
## Sampling debug logs
From 3f6412c3853086705efdb9cd71882a5ee9715b1a Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Fri, 8 Dec 2023 15:20:39 +0100
Subject: [PATCH 70/74] improve doc
---
docs/core/logging.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/docs/core/logging.md b/docs/core/logging.md
index cff12d34c..3c2475b34 100644
--- a/docs/core/logging.md
+++ b/docs/core/logging.md
@@ -752,6 +752,9 @@ When debugging in non-production environments, you can instruct the `@Logging` a
}
```
+???+ note
+ If you use this on a RequestStreamHandler, Powertools must duplicate input streams in order to log them.
+
## Logging handler response
When debugging in non-production environments, you can instruct the `@Logging` annotation to log the response with `logResponse` param or via `POWERTOOLS_LOGGER_LOG_RESPONSE` env var.
@@ -773,6 +776,9 @@ When debugging in non-production environments, you can instruct the `@Logging` a
}
```
+???+ note
+ If you use this on a RequestStreamHandler, Powertools must duplicate output streams in order to log them.
+
## Logging handler uncaught exception
By default, AWS Lambda logs any uncaught exception that might happen in the handler. However, this log is not structured
and does not contain any additional context. You can instruct the `@Logging` annotation to log this kind of exception
From 64e79dd00a51343276d4837da9d67e57c79be8c8 Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Mon, 11 Dec 2023 09:00:34 +0100
Subject: [PATCH 71/74] code review
---
.../logging/internal/LambdaLoggingAspect.java | 18 +++++++++---------
.../internal/LambdaLoggingAspectTest.java | 2 +-
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
index c371ead06..efda042ef 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
@@ -74,7 +74,7 @@
public final class LambdaLoggingAspect {
private static final Logger LOG = LoggerFactory.getLogger(LambdaLoggingAspect.class);
private static final Random SAMPLER = new Random();
- static Level LEVEL_AT_INITIALISATION; /* not final for test purpose */
+ private static Level LEVEL_AT_INITIALISATION; /* not final for test purpose */
private static final LoggingManager LOGGING_MANAGER;
@@ -88,21 +88,21 @@ public final class LambdaLoggingAspect {
static void setLogLevel() {
if (POWERTOOLS_LOG_LEVEL != null) {
- Level powertoolsLevel = getLevelFromEnvironmentVariable(POWERTOOLS_LOG_LEVEL);
+ Level powertoolsLevel = getLevelFromString(POWERTOOLS_LOG_LEVEL);
if (LAMBDA_LOG_LEVEL != null) {
- Level lambdaLevel = getLevelFromEnvironmentVariable(LAMBDA_LOG_LEVEL);
+ Level lambdaLevel = getLevelFromString(LAMBDA_LOG_LEVEL);
if (powertoolsLevel.toInt() < lambdaLevel.toInt()) {
LOG.warn("Current log level ({}) does not match AWS Lambda Advanced Logging Controls minimum log level ({}). This can lead to data loss, consider adjusting them.",
POWERTOOLS_LOG_LEVEL, LAMBDA_LOG_LEVEL);
}
}
- resetLogLevels(powertoolsLevel);
+ setLogLevels(powertoolsLevel);
} else if (LAMBDA_LOG_LEVEL != null) {
- resetLogLevels(getLevelFromEnvironmentVariable(LAMBDA_LOG_LEVEL));
+ setLogLevels(getLevelFromString(LAMBDA_LOG_LEVEL));
}
}
- private static Level getLevelFromEnvironmentVariable(String level) {
+ private static Level getLevelFromString(String level) {
if (Arrays.stream(Level.values()).anyMatch(slf4jLevel -> slf4jLevel.name().equalsIgnoreCase(level))) {
return Level.valueOf(level.toUpperCase());
} else {
@@ -146,7 +146,7 @@ private static LoggingManager getLoggingManagerFromServiceLoader() {
return loggingManager;
}
- private static void resetLogLevels(Level logLevel) {
+ private static void setLogLevels(Level logLevel) {
LOGGING_MANAGER.setLogLevel(logLevel);
}
@@ -263,12 +263,12 @@ private void setLogLevelBasedOnSamplingRate(final ProceedingJoinPoint pjp,
float sample = SAMPLER.nextFloat();
if (samplingRate > sample) {
- resetLogLevels(Level.DEBUG);
+ setLogLevels(Level.DEBUG);
LOG.debug("Changed log level to DEBUG based on Sampling configuration. "
+ "Sampling Rate: {}, Sampler Value: {}.", samplingRate, sample);
} else if (LEVEL_AT_INITIALISATION != LOGGING_MANAGER.getLogLevel(LOG)) {
- resetLogLevels(LEVEL_AT_INITIALISATION);
+ setLogLevels(LEVEL_AT_INITIALISATION);
}
}
}
diff --git a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
index 47c98c88e..88df818f2 100644
--- a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
+++ b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
@@ -707,6 +707,6 @@ private void resetLogLevel(Level level)
Method resetLogLevels = LambdaLoggingAspect.class.getDeclaredMethod("resetLogLevels", Level.class);
resetLogLevels.setAccessible(true);
resetLogLevels.invoke(null, level);
- LambdaLoggingAspect.LEVEL_AT_INITIALISATION = level;
+ writeStaticField(LambdaLoggingAspect.class, "LEVEL_AT_INITIALISATION", level, true);
}
}
\ No newline at end of file
From e7edb576b7ec7059a21528c145c51dc4a44193a8 Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Mon, 11 Dec 2023 10:16:52 +0100
Subject: [PATCH 72/74] fix tests
---
.../logging/internal/LambdaLoggingAspectTest.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
index 88df818f2..fcf3dea36 100644
--- a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
+++ b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
@@ -704,9 +704,9 @@ private void setupContext() {
private void resetLogLevel(Level level)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
- Method resetLogLevels = LambdaLoggingAspect.class.getDeclaredMethod("resetLogLevels", Level.class);
- resetLogLevels.setAccessible(true);
- resetLogLevels.invoke(null, level);
+ Method setLogLevels = LambdaLoggingAspect.class.getDeclaredMethod("setLogLevels", Level.class);
+ setLogLevels.setAccessible(true);
+ setLogLevels.invoke(null, level);
writeStaticField(LambdaLoggingAspect.class, "LEVEL_AT_INITIALISATION", level, true);
}
}
\ No newline at end of file
From fd334db561cb417d91e885cb134dd8fd8396bd41 Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Mon, 11 Dec 2023 14:36:01 +0100
Subject: [PATCH 73/74] code review
---
.../internal/DefautlLoggingManager.java | 35 +++++++++++
.../logging/internal/LambdaLoggingAspect.java | 47 +++++++++-----
.../logging/internal/LoggingConstants.java | 6 +-
.../internal/LambdaLoggingAspectTest.java | 62 ++++++++++++++++---
4 files changed, 125 insertions(+), 25 deletions(-)
create mode 100644 powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/DefautlLoggingManager.java
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/DefautlLoggingManager.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/DefautlLoggingManager.java
new file mode 100644
index 000000000..5326f53e6
--- /dev/null
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/DefautlLoggingManager.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package software.amazon.lambda.powertools.logging.internal;
+
+import org.slf4j.Logger;
+import org.slf4j.event.Level;
+
+/**
+ * When no LoggingManager is found, setting a default one with no action on logging implementation
+ * Powertools cannot change the log level based on the environment variable, will use the logger configuration
+ */
+public class DefautlLoggingManager implements LoggingManager {
+
+ @Override
+ public void setLogLevel(Level logLevel) {
+ // do nothing
+ }
+
+ @Override
+ public Level getLogLevel(Logger logger) {
+ return Level.ERROR;
+ }
+}
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
index efda042ef..48f67700d 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspect.java
@@ -48,6 +48,9 @@
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -123,24 +126,40 @@ private static Level getLevelFromString(String level) {
* @return an instance of {@link LoggingManager}
* @throws IllegalStateException if no {@link LoggingManager} could be found
*/
+ @SuppressWarnings("java:S106") // S106: System.err is used rather than logger to make sure message is printed
private static LoggingManager getLoggingManagerFromServiceLoader() {
- LoggingManager loggingManager;
+ ServiceLoader loggingManagers;
+ SecurityManager securityManager = System.getSecurityManager();
+ if (securityManager == null) {
+ loggingManagers = ServiceLoader.load(LoggingManager.class);
+ } else {
+ final PrivilegedAction> action = () -> ServiceLoader.load(LoggingManager.class);
+ loggingManagers = AccessController.doPrivileged(action);
+ }
- ServiceLoader loggingManagers = ServiceLoader.load(LoggingManager.class);
List loggingManagerList = new ArrayList<>();
for (LoggingManager lm : loggingManagers) {
loggingManagerList.add(lm);
}
+ return getLoggingManager(loggingManagerList, System.err);
+ }
+
+ static LoggingManager getLoggingManager(List loggingManagerList, PrintStream printStream) {
+ LoggingManager loggingManager;
if (loggingManagerList.isEmpty()) {
- throw new IllegalStateException("No LoggingManager was found on the classpath, "
- +
- "make sure to add either powertools-logging-log4j or powertools-logging-logback to your dependencies");
- } else if (loggingManagerList.size() > 1) {
- throw new IllegalStateException(
- "Multiple LoggingManagers were found on the classpath: " + loggingManagerList
- +
- ", make sure to have only one of powertools-logging-log4j OR powertools-logging-logback to your dependencies");
+ printStream.println("ERROR. No LoggingManager was found on the classpath");
+ printStream.println("ERROR. Applying default LoggingManager: POWERTOOLS_LOG_LEVEL variable is ignored");
+ printStream.println("ERROR. Make sure to add either powertools-logging-log4j or powertools-logging-logback to your dependencies");
+ loggingManager = new DefautlLoggingManager();
} else {
+ if (loggingManagerList.size() > 1) {
+ printStream.println("WARN. Multiple LoggingManagers were found on the classpath");
+ for (LoggingManager manager : loggingManagerList) {
+ printStream.println("WARN. Found LoggingManager: [" + manager + "]");
+ }
+ printStream.println("WARN. Make sure to have only one of powertools-logging-log4j OR powertools-logging-logback to your dependencies");
+ printStream.println("WARN. Using the first LoggingManager found on the classpath: [" + loggingManagerList.get(0) + "]");
+ }
loggingManager = loggingManagerList.get(0);
}
return loggingManager;
@@ -183,7 +202,7 @@ public Object around(ProceedingJoinPoint pjp,
// 3. retrieve this temporary stream to log it (if enabled)
// 4. write it back to the OutputStream provided by Lambda
OutputStream backupOutputStream = null;
- if ((logging.logResponse() || "true".equals(POWERTOOLS_LOG_RESPONSE)) && isOnRequestStreamHandler) {
+ if ((logging.logResponse() || POWERTOOLS_LOG_RESPONSE) && isOnRequestStreamHandler) {
backupOutputStream = (OutputStream) proceedArgs[1];
proceedArgs[1] = new ByteArrayOutputStream();
}
@@ -193,7 +212,7 @@ public Object around(ProceedingJoinPoint pjp,
try {
lambdaFunctionResponse = pjp.proceed(proceedArgs);
} catch (Throwable t) {
- if (logging.logError() || "true".equals(POWERTOOLS_LOG_ERROR)) {
+ if (logging.logError() || POWERTOOLS_LOG_ERROR) {
// logging the exception with additional context
logger(pjp).error(MarkerFactory.getMarker("FATAL"), "Exception in Lambda Handler", t);
}
@@ -205,7 +224,7 @@ public Object around(ProceedingJoinPoint pjp,
coldStartDone();
}
- if ((logging.logResponse() || "true".equals(POWERTOOLS_LOG_RESPONSE))) {
+ if ((logging.logResponse() || POWERTOOLS_LOG_RESPONSE)) {
if (isOnRequestHandler) {
logRequestHandlerResponse(pjp, lambdaFunctionResponse);
} else if (isOnRequestStreamHandler && backupOutputStream != null) {
@@ -222,7 +241,7 @@ private Object[] logEvent(ProceedingJoinPoint pjp, Logging logging,
boolean isOnRequestHandler, boolean isOnRequestStreamHandler) {
Object[] proceedArgs = pjp.getArgs();
- if (logging.logEvent() || "true".equals(POWERTOOLS_LOG_EVENT)) {
+ if (logging.logEvent() || POWERTOOLS_LOG_EVENT) {
if (isOnRequestHandler) {
logRequestHandlerEvent(pjp, pjp.getArgs()[0]);
} else if (isOnRequestStreamHandler) {
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LoggingConstants.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LoggingConstants.java
index 09d834dc9..989608a77 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LoggingConstants.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/LoggingConstants.java
@@ -21,11 +21,11 @@ class LoggingConstants {
static String POWERTOOLS_SAMPLING_RATE = System.getenv("POWERTOOLS_LOGGER_SAMPLE_RATE"); /* not final for test purpose */
- static String POWERTOOLS_LOG_EVENT = System.getenv("POWERTOOLS_LOGGER_LOG_EVENT"); /* not final for test purpose */
+ static boolean POWERTOOLS_LOG_EVENT = "true".equals(System.getenv("POWERTOOLS_LOGGER_LOG_EVENT")); /* not final for test purpose */
- static String POWERTOOLS_LOG_RESPONSE = System.getenv("POWERTOOLS_LOGGER_LOG_RESPONSE"); /* not final for test purpose */
+ static boolean POWERTOOLS_LOG_RESPONSE = "true".equals(System.getenv("POWERTOOLS_LOGGER_LOG_RESPONSE")); /* not final for test purpose */
- static String POWERTOOLS_LOG_ERROR = System.getenv("POWERTOOLS_LOGGER_LOG_ERROR"); /* not final for test purpose */
+ static boolean POWERTOOLS_LOG_ERROR = "true".equals(System.getenv("POWERTOOLS_LOGGER_LOG_ERROR")); /* not final for test purpose */
private LoggingConstants() {
// constants
diff --git a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
index fcf3dea36..bc5e53675 100644
--- a/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
+++ b/powertools-logging/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaLoggingAspectTest.java
@@ -46,6 +46,8 @@
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.channels.FileChannel;
@@ -54,7 +56,9 @@
import java.nio.file.NoSuchFileException;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
@@ -108,7 +112,7 @@ void setUp() throws IllegalAccessException, NoSuchMethodException, InvocationTar
resetLogLevel(Level.INFO);
writeStaticField(LoggingConstants.class, "LAMBDA_LOG_LEVEL", null, true);
writeStaticField(LoggingConstants.class, "POWERTOOLS_LOG_LEVEL", null, true);
- writeStaticField(LoggingConstants.class, "POWERTOOLS_LOG_EVENT", null, true);
+ writeStaticField(LoggingConstants.class, "POWERTOOLS_LOG_EVENT", false, true);
writeStaticField(LoggingConstants.class, "POWERTOOLS_SAMPLING_RATE", null, true);
try {
FileChannel.open(Paths.get("target/logfile.json"), StandardOpenOption.WRITE).truncate(0).close();
@@ -475,7 +479,7 @@ void shouldLogEventForHandlerWithLogEventAnnotation() {
void shouldLogEventForHandlerWhenEnvVariableSetToTrue() throws IllegalAccessException {
try {
// GIVEN
- LoggingConstants.POWERTOOLS_LOG_EVENT = "true";
+ LoggingConstants.POWERTOOLS_LOG_EVENT = true;
requestHandler = new PowertoolsLogEnabled();
@@ -491,14 +495,14 @@ void shouldLogEventForHandlerWhenEnvVariableSetToTrue() throws IllegalAccessExce
File logFile = new File("target/logfile.json");
assertThat(contentOf(logFile)).contains("\"body\":\"body\"").contains("\"messageId\":\"1234abcd\"").contains("\"awsRegion\":\"eu-west-1\"");
} finally {
- writeStaticField(LoggingConstants.class, "POWERTOOLS_LOG_EVENT", "false", true);
+ LoggingConstants.POWERTOOLS_LOG_EVENT = false;
}
}
@Test
void shouldNotLogEventForHandlerWhenEnvVariableSetToFalse() throws IOException {
// GIVEN
- LoggingConstants.POWERTOOLS_LOG_EVENT = "false";
+ LoggingConstants.POWERTOOLS_LOG_EVENT = false;
// WHEN
requestHandler = new PowertoolsLogEventDisabled();
@@ -543,7 +547,7 @@ void shouldLogResponseForHandlerWithLogResponseAnnotation() {
void shouldLogResponseForHandlerWhenEnvVariableSetToTrue() throws IllegalAccessException {
try {
// GIVEN
- LoggingConstants.POWERTOOLS_LOG_RESPONSE = "true";
+ LoggingConstants.POWERTOOLS_LOG_RESPONSE = true;
requestHandler = new PowertoolsLogEnabled();
@@ -554,7 +558,7 @@ void shouldLogResponseForHandlerWhenEnvVariableSetToTrue() throws IllegalAccessE
File logFile = new File("target/logfile.json");
assertThat(contentOf(logFile)).contains("Bonjour le monde");
} finally {
- writeStaticField(LoggingConstants.class, "POWERTOOLS_LOG_RESPONSE", "false", true);
+ LoggingConstants.POWERTOOLS_LOG_RESPONSE = false;
}
}
@@ -597,7 +601,7 @@ void shouldLogErrorForHandlerWithLogErrorAnnotation() {
void shouldLogErrorForHandlerWhenEnvVariableSetToTrue() throws IllegalAccessException {
try {
// GIVEN
- LoggingConstants.POWERTOOLS_LOG_ERROR = "true";
+ LoggingConstants.POWERTOOLS_LOG_ERROR = true;
requestHandler = new PowertoolsLogEnabled(true);
@@ -611,7 +615,7 @@ void shouldLogErrorForHandlerWhenEnvVariableSetToTrue() throws IllegalAccessExce
File logFile = new File("target/logfile.json");
assertThat(contentOf(logFile)).contains("Something went wrong");
} finally {
- writeStaticField(LoggingConstants.class, "POWERTOOLS_LOG_ERROR", "false", true);
+ LoggingConstants.POWERTOOLS_LOG_ERROR = false;
}
}
@@ -694,6 +698,48 @@ void shouldLogCorrelationIdOnAppSyncEvent() throws IOException {
.containsEntry("correlation_id", eventId);
}
+ @Test
+ void testMultipleLoggingManagers_shouldWarnAndSelectFirstOne() throws UnsupportedEncodingException {
+ // GIVEN
+ List list = new ArrayList<>();
+ list.add(new TestLoggingManager());
+ list.add(new DefautlLoggingManager());
+
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ PrintStream stream = new PrintStream(outputStream);
+
+ // WHEN
+ LambdaLoggingAspect.getLoggingManager(list, stream);
+
+ // THEN
+ String output = outputStream.toString("UTF-8");
+ assertThat(output)
+ .contains("WARN. Multiple LoggingManagers were found on the classpath")
+ .contains("WARN. Make sure to have only one of powertools-logging-log4j OR powertools-logging-logback to your dependencies")
+ .contains("WARN. Using the first LoggingManager found on the classpath: [" + list.get(0) + "]");
+ }
+
+ @Test
+ void testNoLoggingManagers_shouldWarnAndCreateDefault() throws UnsupportedEncodingException {
+ // GIVEN
+ List list = new ArrayList<>();
+
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ PrintStream stream = new PrintStream(outputStream);
+
+ // WHEN
+ LoggingManager loggingManager = LambdaLoggingAspect.getLoggingManager(list, stream);
+
+ // THEN
+ String output = outputStream.toString("UTF-8");
+ assertThat(output)
+ .contains("ERROR. No LoggingManager was found on the classpath")
+ .contains("ERROR. Applying default LoggingManager: POWERTOOLS_LOG_LEVEL variable is ignored")
+ .contains("ERROR. Make sure to add either powertools-logging-log4j or powertools-logging-logback to your dependencies");
+
+ assertThat(loggingManager).isExactlyInstanceOf(DefautlLoggingManager.class);
+ }
+
private void setupContext() {
when(context.getFunctionName()).thenReturn("testFunction");
when(context.getInvokedFunctionArn()).thenReturn("testArn");
From 634d13e60ce5594f9f5f50e767b9a6655edbc45f Mon Sep 17 00:00:00 2001
From: Jerome Van Der Linden
Date: Mon, 11 Dec 2023 15:03:48 +0100
Subject: [PATCH 74/74] code review last episode
---
docs/core/logging.md | 16 +++---
.../internal/Log4jLoggingManager.java | 3 +-
...powertools.logging.internal.LoggingManager | 2 +-
.../internal/Log4jLoggingManagerTest.java | 1 +
.../{ => logback}/LambdaEcsEncoder.java | 10 ++--
.../{ => logback}/LambdaJsonEncoder.java | 16 +++---
.../{ => logback}/internal/JsonUtils.java | 2 +-
.../internal/LambdaEcsSerializer.java | 53 +++++++++----------
.../internal/LambdaJsonSerializer.java | 25 +++++----
.../internal/LogbackLoggingManager.java | 3 +-
...powertools.logging.internal.LoggingManager | 2 +-
.../logging/LogbackLoggingManagerTest.java | 2 +-
.../internal/LambdaEcsEncoderTest.java | 2 +-
.../internal/LambdaJsonEncoderTest.java | 2 +-
.../src/test/resources/logback-test.xml | 6 +--
powertools-logging/spotbugs-exclude.xml | 4 +-
spotbugs-exclude.xml | 4 +-
17 files changed, 77 insertions(+), 76 deletions(-)
rename powertools-logging/powertools-logging-log4j/src/main/java/software/amazon/lambda/powertools/logging/{ => log4}/internal/Log4jLoggingManager.java (92%)
rename powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/{ => logback}/LambdaEcsEncoder.java (97%)
rename powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/{ => logback}/LambdaJsonEncoder.java (96%)
rename powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/{ => logback}/internal/JsonUtils.java (98%)
rename powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/{ => logback}/internal/LambdaEcsSerializer.java (73%)
rename powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/{ => logback}/internal/LambdaJsonSerializer.java (84%)
rename powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/{ => logback}/internal/LogbackLoggingManager.java (93%)
diff --git a/docs/core/logging.md b/docs/core/logging.md
index 3c2475b34..f0fba760a 100644
--- a/docs/core/logging.md
+++ b/docs/core/logging.md
@@ -233,7 +233,7 @@ You can leverage the standard configuration files (_log4j2.xml_ or _logback.xml_
-
+
@@ -1008,7 +1008,7 @@ Logback configuration is done in _logback.xml_ and the Powertools [`LambdaJsonEn
```xml
-
+
```
@@ -1020,7 +1020,7 @@ The `LambdaJsonEncoder` can be customized in different ways:
With the following configuration, you choose to log all the JSON messages as JSON and not as String (default is `false`):
```xml
-
+ true
```
@@ -1030,7 +1030,7 @@ Utility by default emits `timestamp` field in the logs in format `yyyy-MM-dd'T'H
If you need to customize format and timezone, you can change use the following:
```xml
-
+ yyyy-MM-dd HH:mm:ssEurope/Paris
@@ -1041,7 +1041,7 @@ If you need to customize format and timezone, you can change use the following:
- You can use a standard `ThrowableHandlingConverter` to customize the exception format (default is no converter). Example:
```xml
-
+ 302048
@@ -1058,7 +1058,7 @@ If you need to customize format and timezone, you can change use the following:
- You can choose to add information about threads (default is `false`):
```xml
-
+ true
```
@@ -1066,7 +1066,7 @@ If you need to customize format and timezone, you can change use the following:
- You can even choose to remove Powertools information from the logs like function name, arn:
```xml
-
+ false
```
@@ -1134,7 +1134,7 @@ Use the `LambdaEcsEncoder` rather than the `LambdaJsonEncoder` when configuring
```xml hl_lines="3"
-
+
diff --git a/powertools-logging/powertools-logging-log4j/src/main/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManager.java b/powertools-logging/powertools-logging-log4j/src/main/java/software/amazon/lambda/powertools/logging/log4/internal/Log4jLoggingManager.java
similarity index 92%
rename from powertools-logging/powertools-logging-log4j/src/main/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManager.java
rename to powertools-logging/powertools-logging-log4j/src/main/java/software/amazon/lambda/powertools/logging/log4/internal/Log4jLoggingManager.java
index a20671739..4e57a8e45 100644
--- a/powertools-logging/powertools-logging-log4j/src/main/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManager.java
+++ b/powertools-logging/powertools-logging-log4j/src/main/java/software/amazon/lambda/powertools/logging/log4/internal/Log4jLoggingManager.java
@@ -12,13 +12,14 @@
*
*/
-package software.amazon.lambda.powertools.logging.internal;
+package software.amazon.lambda.powertools.logging.log4.internal;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configurator;
import org.slf4j.Logger;
+import software.amazon.lambda.powertools.logging.internal.LoggingManager;
/**
* LoggingManager for Log4j2 (see {@link LoggingManager}).
diff --git a/powertools-logging/powertools-logging-log4j/src/main/resources/META-INF/services/software.amazon.lambda.powertools.logging.internal.LoggingManager b/powertools-logging/powertools-logging-log4j/src/main/resources/META-INF/services/software.amazon.lambda.powertools.logging.internal.LoggingManager
index ae2ec0cba..d444c5525 100644
--- a/powertools-logging/powertools-logging-log4j/src/main/resources/META-INF/services/software.amazon.lambda.powertools.logging.internal.LoggingManager
+++ b/powertools-logging/powertools-logging-log4j/src/main/resources/META-INF/services/software.amazon.lambda.powertools.logging.internal.LoggingManager
@@ -1 +1 @@
-software.amazon.lambda.powertools.logging.internal.Log4jLoggingManager
\ No newline at end of file
+software.amazon.lambda.powertools.logging.log4.internal.Log4jLoggingManager
\ No newline at end of file
diff --git a/powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManagerTest.java b/powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManagerTest.java
index 0942eca52..69e1ee710 100644
--- a/powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManagerTest.java
+++ b/powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/internal/Log4jLoggingManagerTest.java
@@ -10,6 +10,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
+import software.amazon.lambda.powertools.logging.log4.internal.Log4jLoggingManager;
class Log4jLoggingManagerTest {
diff --git a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaEcsEncoder.java b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/logback/LambdaEcsEncoder.java
similarity index 97%
rename from powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaEcsEncoder.java
rename to powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/logback/LambdaEcsEncoder.java
index 1416c8192..1fc98ec67 100644
--- a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaEcsEncoder.java
+++ b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/logback/LambdaEcsEncoder.java
@@ -12,7 +12,7 @@
*
*/
-package software.amazon.lambda.powertools.logging;
+package software.amazon.lambda.powertools.logging.logback;
import static java.nio.charset.StandardCharsets.UTF_8;
import static software.amazon.lambda.powertools.logging.internal.PowertoolsLoggedFields.FUNCTION_ARN;
@@ -31,7 +31,7 @@
import ch.qos.logback.core.encoder.EncoderBase;
import java.util.Map;
import software.amazon.lambda.powertools.common.internal.LambdaHandlerProcessor;
-import software.amazon.lambda.powertools.logging.internal.LambdaEcsSerializer;
+import software.amazon.lambda.powertools.logging.logback.internal.LambdaEcsSerializer;
/**
@@ -128,7 +128,7 @@ public byte[] footerBytes() {
* (default is null, no throwableConverter):
*
*
{@code
- *
+ *
*
* 30
* 2048
@@ -160,7 +160,7 @@ public void setThrowableConverter(ThrowableHandlingConverter throwableConverter)
* We strongly recommend to keep these information.
*
*
{@code
- *
+ *
* false
*
* }
@@ -186,7 +186,7 @@ public void setIncludeCloudInfo(boolean includeCloudInfo) {
* We strongly recommend to keep these information.
*
*
{@code
- *
+ *
* false
*
* }
diff --git a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaJsonEncoder.java b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/logback/LambdaJsonEncoder.java
similarity index 96%
rename from powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaJsonEncoder.java
rename to powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/logback/LambdaJsonEncoder.java
index 9d375089d..b951e266e 100644
--- a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/LambdaJsonEncoder.java
+++ b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/logback/LambdaJsonEncoder.java
@@ -12,7 +12,7 @@
*
*/
-package software.amazon.lambda.powertools.logging;
+package software.amazon.lambda.powertools.logging.logback;
import static java.nio.charset.StandardCharsets.UTF_8;
import static software.amazon.lambda.powertools.logging.LoggingUtils.LOG_MESSAGES_AS_JSON;
@@ -23,7 +23,7 @@
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.classic.spi.ThrowableProxy;
import ch.qos.logback.core.encoder.EncoderBase;
-import software.amazon.lambda.powertools.logging.internal.LambdaJsonSerializer;
+import software.amazon.lambda.powertools.logging.logback.internal.LambdaJsonSerializer;
/**
* Custom encoder for logback that encodes logs in JSON format.
@@ -97,7 +97,7 @@ public byte[] footerBytes() {
* Note that if you use the Lambda Advanced Logging Configuration, you should keep the default format.
*
*
@@ -112,7 +112,7 @@ public void setTimestampFormat(String timestampFormat) {
* Specify the format of the time zone id for timestamp (default is null, no timezone):
*
*
{@code
- *
+ *
* Europe/Paris
*
* }
@@ -128,7 +128,7 @@ public void setTimestampFormatTimezoneId(String timestampFormatTimezoneId) {
* (default is null, no throwableConverter):
*
*
{@code
- *
+ *
*
* 30
* 2048
@@ -152,7 +152,7 @@ public void setThrowableConverter(ThrowableHandlingConverter throwableConverter)
* Specify if thread information should be logged (default is false)
*
*
{@code
- *
+ *
* true
*
* }
@@ -180,7 +180,7 @@ public void setIncludeThreadInfo(boolean includeThreadInfo) {
* We strongly recommend to keep these information.
*
*
{@code
- *
+ *
* false
*
* }
@@ -195,7 +195,7 @@ public void setIncludePowertoolsInfo(boolean includePowertoolsInfo) {
* Specify if messages should be logged as JSON, without escaping string (default is false):
*
*