Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import static software.amazon.lambda.powertools.logging.internal.PowertoolsLoggedFields.FUNCTION_VERSION;
import static software.amazon.lambda.powertools.logging.internal.PowertoolsLoggedFields.SAMPLING_RATE;
import static software.amazon.lambda.powertools.logging.internal.PowertoolsLoggedFields.SERVICE;
import static software.amazon.lambda.powertools.logging.internal.PowertoolsLoggedFields.TENANT_ID;

import java.io.IOException;
import java.util.Collections;
Expand Down Expand Up @@ -168,6 +169,22 @@ public void resolve(LogEvent logEvent, JsonWriter jsonWriter) {
private static final EventResolver REGION_RESOLVER =
(final LogEvent logEvent, final JsonWriter jsonWriter) ->
jsonWriter.writeString(SystemWrapper.getenv(LambdaConstants.AWS_REGION_ENV));

private static final EventResolver TENANT_ID_RESOLVER = new EventResolver() {
@Override
public boolean isResolvable(LogEvent logEvent) {
final String tenantId =
logEvent.getContextData().getValue(PowertoolsLoggedFields.TENANT_ID.getName());
return null != tenantId;
}

@Override
public void resolve(LogEvent logEvent, JsonWriter jsonWriter) {
final String tenantId =
logEvent.getContextData().getValue(PowertoolsLoggedFields.TENANT_ID.getName());
jsonWriter.writeString(tenantId);
}
};

public static final String LAMBDA_ARN_REGEX =
"^arn:(aws|aws-us-gov|aws-cn):lambda:[a-zA-Z0-9-]+:\\d{12}:function:[a-zA-Z0-9-_]+(:[a-zA-Z0-9-_]+)?$";
Expand Down Expand Up @@ -233,6 +250,7 @@ public void resolve(LogEvent logEvent, JsonWriter jsonWriter) {
{ FUNCTION_TRACE_ID.getName(), XRAY_TRACE_RESOLVER },
{ CORRELATION_ID.getName(), CORRELATION_ID_RESOLVER },
{ SAMPLING_RATE.getName(), SAMPLING_RATE_RESOLVER },
{ TENANT_ID.getName(), TENANT_ID_RESOLVER },
{ "region", REGION_RESOLVER },
{ "account_id", ACCOUNT_ID_RESOLVER }
}).collect(Collectors.toMap(data -> (String) data[0], data -> (EventResolver) data[1])));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@
"$resolver": "powertools",
"field": "correlation_id"
},
"tenant.id": {
"$resolver": "powertools",
"field": "tenant_id"
},
"": {
"$resolver": "powertools"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@
"$resolver": "powertools",
"field": "correlation_id"
},
"tenant_id": {
"$resolver": "powertools",
"field": "tenant_id"
},
"": {
"$resolver": "powertools"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import static software.amazon.lambda.powertools.logging.internal.PowertoolsLoggedFields.FUNCTION_REQUEST_ID;
import static software.amazon.lambda.powertools.logging.internal.PowertoolsLoggedFields.FUNCTION_TRACE_ID;
import static software.amazon.lambda.powertools.logging.internal.PowertoolsLoggedFields.FUNCTION_VERSION;
import static software.amazon.lambda.powertools.logging.internal.PowertoolsLoggedFields.TENANT_ID;
import static software.amazon.lambda.powertools.logging.logback.JsonUtils.serializeArguments;
import static software.amazon.lambda.powertools.logging.logback.JsonUtils.serializeMDCEntries;
import static software.amazon.lambda.powertools.logging.logback.JsonUtils.serializeTimestamp;
Expand Down Expand Up @@ -74,6 +75,7 @@ public class LambdaEcsEncoder extends EncoderBase<ILoggingEvent> {
protected static final String FUNCTION_MEMORY_ATTR_NAME = "faas.memory";
protected static final String FUNCTION_TRACE_ID_ATTR_NAME = "trace.id";
protected static final String CORRELATION_ID_ATTR_NAME = "correlation.id";
protected static final String TENANT_ID_ATTR_NAME = "tenant.id";

protected static final String ECS_VERSION = "1.2.0";
protected static final String CLOUD_PROVIDER = "aws";
Expand Down Expand Up @@ -163,6 +165,11 @@ private void serializeFunctionInfo(JsonSerializer serializer, String arn, Map<St
serializer.writeRaw(',');
serializer.writeStringField(CORRELATION_ID_ATTR_NAME, correlationId);
}
String tenantId = mdcPropertyMap.get(TENANT_ID.getName());
if (tenantId != null) {
serializer.writeRaw(',');
serializer.writeStringField(TENANT_ID_ATTR_NAME, tenantId);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@

serializeException(event, serializer);

TreeMap<String, String> sortedMap = new TreeMap<>(event.getMDCPropertyMap());

Check failure on line 86 in powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/logback/LambdaJsonEncoder.java

View workflow job for this annotation

GitHub Actions / pmd_analyse

Avoid using implementation types like 'TreeMap'; use the interface instead

Excessive coupling to implementation types (e.g., `HashSet`) limits your ability to use alternate implementations in the future as requirements change. Whenever available, declare variables and parameters using a more general type (e.g, `Set`). This rule reports uses of concrete collection types. User-defined types that should be treated the same as interfaces can be configured with the property `allowedTypes`. LooseCoupling (Priority: 1, Ruleset: Best Practices) https://docs.pmd-code.org/snapshot/pmd_rules_java_bestpractices.html#loosecoupling
serializePowertools(sortedMap, serializer);

serializeMDCEntries(sortedMap, serializer);
Expand Down Expand Up @@ -117,11 +117,11 @@
}
}

private void serializePowertools(TreeMap<String, String> sortedMap, JsonSerializer serializer) {

Check failure on line 120 in powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/logback/LambdaJsonEncoder.java

View workflow job for this annotation

GitHub Actions / pmd_analyse

Avoid using implementation types like 'TreeMap'; use the interface instead

Excessive coupling to implementation types (e.g., `HashSet`) limits your ability to use alternate implementations in the future as requirements change. Whenever available, declare variables and parameters using a more general type (e.g, `Set`). This rule reports uses of concrete collection types. User-defined types that should be treated the same as interfaces can be configured with the property `allowedTypes`. LooseCoupling (Priority: 1, Ruleset: Best Practices) https://docs.pmd-code.org/snapshot/pmd_rules_java_bestpractices.html#loosecoupling
if (includePowertoolsInfo) {
for (Map.Entry<String, String> entry : sortedMap.entrySet()) {
if (PowertoolsLoggedFields.stringValues().contains(entry.getKey())
&& !(entry.getKey().equals(PowertoolsLoggedFields.SAMPLING_RATE.getName()) && entry.getValue().equals("0.0"))) {

Check failure on line 124 in powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/logback/LambdaJsonEncoder.java

View workflow job for this annotation

GitHub Actions / pmd_analyse

Position literals first in String comparisons

Position literals first in all String comparisons, if the second argument is null then NullPointerExceptions can be avoided, they will just return false. Note that switching literal positions for compareTo and compareToIgnoreCase may change the result, see examples. Note that compile-time constant strings are treated like literals. This is because they are inlined into the class file, are necessarily non-null, and therefore cannot cause an NPE at runtime. LiteralsFirstInComparisons (Priority: 1, Ruleset: Best Practices) https://docs.pmd-code.org/snapshot/pmd_rules_java_bestpractices.html#literalsfirstincomparisons
serializeMDCEntry(entry, serializer);
}
}
Expand Down Expand Up @@ -233,6 +233,7 @@
* <li>xray_trace_id</li>
* <li>sampling_rate</li>
* <li>service</li>
* <li>tenant_id</li>
* </ul>
* <br/>
* We strongly recommend to keep these information.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package software.amazon.lambda.powertools.logging.internal;

import com.amazonaws.services.lambda.runtime.Context;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -35,7 +36,8 @@ public enum PowertoolsLoggedFields {
FUNCTION_TRACE_ID("xray_trace_id"),
SAMPLING_RATE("sampling_rate"),
CORRELATION_ID("correlation_id"),
SERVICE("service");
SERVICE("service"),
TENANT_ID("tenant_id");

private final String name;

Expand All @@ -55,9 +57,26 @@ public static Map<String, String> setValuesFromLambdaContext(Context context) {
hashMap.put(FUNCTION_ARN.name, context.getInvokedFunctionArn());
hashMap.put(FUNCTION_MEMORY_SIZE.name, String.valueOf(context.getMemoryLimitInMB()));
hashMap.put(FUNCTION_REQUEST_ID.name, String.valueOf(context.getAwsRequestId()));

// Add TenantId if available (Lambda Tenant Isolation feature)
String tenantId = getTenantId(context);
if (tenantId != null) {
hashMap.put(TENANT_ID.name, tenantId);
}

return hashMap;
}

private static String getTenantId(Context context) {
try {
Method getTenantIdMethod = context.getClass().getMethod("getTenantId");
Object tenantId = getTenantIdMethod.invoke(context);
return tenantId != null ? tenantId.toString() : null;
} catch (Exception e) {
// TenantId method not available or failed to invoke
return null;
}
}

public String getName() {
return name;
Expand Down