Skip to content

Commit 1681e19

Browse files
committed
PoC for Metrics and Logging UA Configuration.
1 parent 006f8ff commit 1681e19

File tree

11 files changed

+156
-12
lines changed

11 files changed

+156
-12
lines changed

examples/powertools-examples-core-utilities/sam/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@
4545
<artifactId>aspectjrt</artifactId>
4646
<version>${aspectj.version}</version>
4747
</dependency>
48+
<dependency>
49+
<groupId>software.amazon.awssdk</groupId>
50+
<artifactId>s3</artifactId>
51+
<version>2.32.8</version>
52+
</dependency>
4853
</dependencies>
4954

5055
<build>

examples/powertools-examples-core-utilities/sam/src/main/java/helloworld/App.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@
3434
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
3535
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
3636

37+
import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
38+
import software.amazon.awssdk.core.SdkSystemSetting;
39+
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
40+
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
41+
import software.amazon.awssdk.http.SdkHttpRequest;
42+
import software.amazon.awssdk.regions.Region;
43+
import software.amazon.awssdk.services.s3.S3Client;
3744
import software.amazon.lambda.powertools.logging.Logging;
3845
import software.amazon.lambda.powertools.metrics.FlushMetrics;
3946
import software.amazon.lambda.powertools.metrics.Metrics;
@@ -50,13 +57,32 @@
5057
*/
5158
public class App implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
5259
private static final Logger log = LoggerFactory.getLogger(App.class);
60+
private static final S3Client s3Client = S3Client.builder()
61+
.region(Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable())))
62+
.credentialsProvider(EnvironmentVariableCredentialsProvider.create())
63+
.overrideConfiguration(c -> c.addExecutionInterceptor(new ExecutionInterceptor() {
64+
@Override
65+
public void beforeTransmission(
66+
software.amazon.awssdk.core.interceptor.Context.BeforeTransmission context,
67+
ExecutionAttributes executionAttributes) {
68+
SdkHttpRequest request = context.httpRequest();
69+
log.info("User-Agent header: {}", request.headers().get("User-Agent"));
70+
}
71+
}))
72+
.build();
5373
private static final Metrics metrics = MetricsFactory.getMetricsInstance();
5474

75+
public App() {
76+
log.info("sdk.ua.appId system property: {}", System.getProperty("sdk.ua.appId"));
77+
s3Client.listBuckets();
78+
}
79+
5580
@Logging(logEvent = true, samplingRate = 0.7)
5681
@Tracing(captureMode = CaptureMode.RESPONSE_AND_ERROR)
5782
@FlushMetrics(namespace = "ServerlessAirline", service = "payment", captureColdStart = true)
5883
public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
5984
Map<String, String> headers = new HashMap<>();
85+
s3Client.listBuckets();
6086

6187
headers.put("Content-Type", "application/json");
6288
headers.put("X-Custom-Header", "application/json");

examples/powertools-examples-core-utilities/sam/template.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,22 @@ Globals:
1919
POWERTOOLS_METRICS_NAMESPACE: Coreutilities
2020

2121
Resources:
22+
TestBucket:
23+
Type: AWS::S3::Bucket
24+
2225
HelloWorldFunction:
2326
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
2427
Properties:
2528
CodeUri: .
2629
Handler: helloworld.App::handleRequest
30+
Policies:
31+
- S3ReadPolicy:
32+
BucketName: !Ref TestBucket
33+
- Statement:
34+
- Effect: Allow
35+
Action:
36+
- s3:ListAllMyBuckets
37+
Resource: "*"
2738
Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object
2839
Variables:
2940
POWERTOOLS_SERVICE_NAME: hello

powertools-common/src/main/java/software/amazon/lambda/powertools/common/internal/UserAgentConfigurator.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@
1919
import java.io.IOException;
2020
import java.io.InputStream;
2121
import java.util.Properties;
22+
2223
import org.slf4j.Logger;
2324
import org.slf4j.LoggerFactory;
2425

25-
2626
/**
2727
* Can be used to create a string that can server as a User-Agent suffix in requests made with the AWS SDK clients
2828
*/
29-
public class UserAgentConfigurator {
29+
public final class UserAgentConfigurator {
3030

3131
public static final String NA = "NA";
3232
public static final String VERSION_KEY = "powertools.version";
@@ -37,7 +37,7 @@ public class UserAgentConfigurator {
3737
private static final Logger LOG = LoggerFactory.getLogger(UserAgentConfigurator.class);
3838
private static final String NO_OP = "no-op";
3939
private static final String POWERTOOLS_VERSION = getProjectVersion();
40-
private static final String USER_AGENT_PATTERN = "PT/" + PT_FEATURE_VARIABLE + "/" + POWERTOOLS_VERSION + " PTEnv/"
40+
private static final String USER_AGENT_PATTERN = "PT/" + PT_FEATURE_VARIABLE + "/" + POWERTOOLS_VERSION + " PTENV/"
4141
+ PT_EXEC_ENV_VARIABLE;
4242

4343
private UserAgentConfigurator() {
@@ -53,7 +53,6 @@ static String getProjectVersion() {
5353
return getVersionFromProperties(VERSION_PROPERTIES_FILENAME, VERSION_KEY);
5454
}
5555

56-
5756
/**
5857
* Retrieves the project version from a properties file.
5958
* The file should be in the resources folder.
@@ -83,9 +82,18 @@ static String getVersionFromProperties(String propertyFileName, String versionKe
8382
return NA;
8483
}
8584

85+
/**
86+
* Configures the AWS SDK to use Powertools user agent by setting the sdk.ua.appId system property.
87+
* This should be called during library initialization to ensure the user agent is properly configured.
88+
*/
89+
public static void configureUserAgent(String ptFeature) {
90+
System.out.println("CONFIGURE UA " + ptFeature);
91+
System.setProperty("sdk.ua.appId", getUserAgent(ptFeature));
92+
}
93+
8694
/**
8795
* Retrieves the user agent string for the Powertools for AWS Lambda.
88-
* It follows the pattern PT/{PT_FEATURE}/{PT_VERSION} PTEnv/{PT_EXEC_ENV}
96+
* It follows the pattern PT/{PT_FEATURE}/{PT_VERSION} PTENV/{PT_EXEC_ENV}
8997
* The version of the project is automatically retrieved.
9098
* The PT_EXEC_ENV is automatically retrieved from the AWS_EXECUTION_ENV environment variable.
9199
* If it AWS_EXECUTION_ENV is not set, PT_EXEC_ENV defaults to "NA"
@@ -105,7 +113,7 @@ public static String getUserAgent(String ptFeature) {
105113
ptFeature = NO_OP;
106114
}
107115
return userAgent
108-
.replace(PT_FEATURE_VARIABLE, ptFeature)
116+
.replace(PT_FEATURE_VARIABLE, ptFeature.toUpperCase())
109117
.replace(PT_EXEC_ENV_VARIABLE, ptExecEnv);
110118
}
111119
}

powertools-common/src/test/java/software/amazon/lambda/powertools/common/internal/UserAgentConfiguratorTest.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ void testGetUserAgent() {
9191

9292
assertThat(userAgent)
9393
.isNotNull()
94-
.isEqualTo("PT/test-feature/" + VERSION + " PTEnv/NA");
94+
.isEqualTo("PT/TEST-FEATURE/" + VERSION + " PTENV/NA");
9595

9696
}
9797

@@ -101,7 +101,7 @@ void testGetUserAgent_NoFeature() {
101101

102102
assertThat(userAgent)
103103
.isNotNull()
104-
.isEqualTo("PT/no-op/" + VERSION + " PTEnv/NA");
104+
.isEqualTo("PT/NO-OP/" + VERSION + " PTENV/NA");
105105
}
106106

107107
@Test
@@ -110,7 +110,7 @@ void testGetUserAgent_NullFeature() {
110110

111111
assertThat(userAgent)
112112
.isNotNull()
113-
.isEqualTo("PT/no-op/" + VERSION + " PTEnv/NA");
113+
.isEqualTo("PT/NO-OP/" + VERSION + " PTENV/NA");
114114
}
115115

116116
@Test
@@ -120,7 +120,15 @@ void testGetUserAgent_SetAWSExecutionEnv() {
120120

121121
assertThat(userAgent)
122122
.isNotNull()
123-
.isEqualTo("PT/test-feature/" + VERSION + " PTEnv/AWS_Lambda_java8");
123+
.isEqualTo("PT/TEST-FEATURE/" + VERSION + " PTENV/AWS_Lambda_java8");
124+
}
125+
126+
@Test
127+
void testConfigureUserAgent() {
128+
UserAgentConfigurator.configureUserAgent("test-feature");
129+
130+
assertThat(System.getProperty("sdk.ua.appId"))
131+
.isEqualTo("PT/TEST-FEATURE/" + VERSION + " PTENV/NA");
124132
}
125133

126134
}

powertools-logging/powertools-logging-log4j/pom.xml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<project xmlns="http://maven.apache.org/POM/4.0.0"
3-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4-
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
55
<modelVersion>4.0.0</modelVersion>
66

77
<parent>
@@ -39,6 +39,11 @@
3939
<groupId>org.apache.logging.log4j</groupId>
4040
<artifactId>log4j-layout-template-json</artifactId>
4141
</dependency>
42+
<dependency>
43+
<groupId>software.amazon.awssdk</groupId>
44+
<artifactId>sdk-core</artifactId>
45+
<scope>provided</scope>
46+
</dependency>
4247

4348
<!-- Test dependencies -->
4449
<dependency>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2023 Amazon.com, Inc. or its affiliates.
3+
* Licensed under the Apache License, Version 2.0 (the
4+
* "License"); you may not use this file except in compliance
5+
* with the License. You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*
13+
*/
14+
package software.amazon.lambda.powertools.logging.log4.internal;
15+
16+
import software.amazon.awssdk.core.SdkRequest;
17+
import software.amazon.awssdk.core.interceptor.Context;
18+
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
19+
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
20+
import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator;
21+
22+
/**
23+
* Global interceptor that configures the User-Agent for all AWS SDK clients
24+
* when the metrics module is on the classpath.
25+
*/
26+
public final class LoggingUserAgentInterceptor implements ExecutionInterceptor {
27+
static {
28+
UserAgentConfigurator.configureUserAgent("logging");
29+
}
30+
31+
@Override
32+
public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) {
33+
// This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is
34+
// loaded by AWS SDK Global Interceptors.
35+
return context.request();
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
software.amazon.lambda.powertools.logging.log4.internal.LoggingUserAgentInterceptor

powertools-metrics/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@
7373
<groupId>org.apache.commons</groupId>
7474
<artifactId>commons-lang3</artifactId>
7575
</dependency>
76+
<dependency>
77+
<groupId>software.amazon.awssdk</groupId>
78+
<artifactId>sdk-core</artifactId>
79+
<scope>provided</scope>
80+
</dependency>
7681

7782
<!-- Test dependencies -->
7883
<dependency>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2023 Amazon.com, Inc. or its affiliates.
3+
* Licensed under the Apache License, Version 2.0 (the
4+
* "License"); you may not use this file except in compliance
5+
* with the License. You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*
13+
*/
14+
package software.amazon.lambda.powertools.metrics.internal;
15+
16+
import software.amazon.awssdk.core.SdkRequest;
17+
import software.amazon.awssdk.core.interceptor.Context;
18+
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
19+
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
20+
import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator;
21+
22+
/**
23+
* Global interceptor that configures the User-Agent for all AWS SDK clients
24+
* when the metrics module is on the classpath.
25+
*/
26+
public final class MetricsUserAgentInterceptor implements ExecutionInterceptor {
27+
static {
28+
UserAgentConfigurator.configureUserAgent("metrics");
29+
}
30+
31+
@Override
32+
public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) {
33+
// This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is
34+
// loaded by AWS SDK Global Interceptors.
35+
return context.request();
36+
}
37+
}

0 commit comments

Comments
 (0)