diff --git a/examples/README.md b/examples/README.md
index 0744c2bb1..52dc0c1e9 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -8,6 +8,7 @@ Each example can be copied from its subdirectory and used independently of the r
* [powertools-examples-core](powertools-examples-core) - Demonstrates the core logging, tracing, and metrics modules with different build tools
* [SAM](./powertools-examples-core/sam)
* [CDK](./powertools-examples-core/cdk)
+ * [Serverless](./powertools-examples-core/serverless)
* [powertools-examples-idempotency](powertools-examples-idempotency) - An idempotent HTTP API
* [powertools-examples-parameters](powertools-examples-parameters) - Uses the parameters module to provide runtime parameters to a function
* [powertools-examples-serialization](powertools-examples-serialization) - Uses the serialization module to serialize and deserialize API Gateway & SQS payloads
diff --git a/examples/pom.xml b/examples/pom.xml
index eae9e10e5..810ec1b36 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -32,6 +32,7 @@
powertools-examples-core/sam
powertools-examples-core/cdk/app
powertools-examples-core/cdk/infra
+ powertools-examples-core/serverless
powertools-examples-idempotency
powertools-examples-parameters
powertools-examples-serialization
diff --git a/examples/powertools-examples-core/README.md b/examples/powertools-examples-core/README.md
index d690b01c5..1d1dd031f 100644
--- a/examples/powertools-examples-core/README.md
+++ b/examples/powertools-examples-core/README.md
@@ -9,6 +9,7 @@ We provide examples for the following infrastructure-as-code tools:
* [AWS SAM](sam/)
* [AWS CDK](cdk/)
+* [Serverless framework](serverless/)
We also provide an example showing the integration of SAM, Powertools, and Gradle:
diff --git a/examples/powertools-examples-core/serverless/README.md b/examples/powertools-examples-core/serverless/README.md
new file mode 100644
index 000000000..aec093182
--- /dev/null
+++ b/examples/powertools-examples-core/serverless/README.md
@@ -0,0 +1,26 @@
+# Powertools for AWS Lambda (Java) - Core Utilities Example with Serverless Framework
+
+This project demonstrates the Lambda for Powertools Java module deployed using [Serverless Framework](https://www.serverless.com/framework).
+For general information on the deployed example itself, you can refer to the parent [README](../README.md).
+To install Serverless Framework if you don't have it yet, you can follow the [Getting Started Guide](https://www.serverless.com/framework/docs/getting-started).
+
+## Configuration
+Serverless Framework uses [serverless.yml](./serverless.yml) to define the application's AWS resources.
+This file defines the Lambda function to be deployed as well as API Gateway for it.
+
+It is a [Maven](https://maven.apache.org/) based project, so you can open this project with any Maven compatible Java IDE to build and run tests.
+
+
+## Deploy the sample application
+
+To deploy the app, simply run the following commands:
+```bash
+mvn package && sls deploy
+```
+
+## Useful commands
+
+Deploy a single function
+```bash
+sls deploy function -f hello
+```
\ No newline at end of file
diff --git a/examples/powertools-examples-core/serverless/pom.xml b/examples/powertools-examples-core/serverless/pom.xml
new file mode 100644
index 000000000..793318da3
--- /dev/null
+++ b/examples/powertools-examples-core/serverless/pom.xml
@@ -0,0 +1,209 @@
+
+ 4.0.0
+
+ software.amazon.lambda.examples
+ 1.18.0-SNAPSHOT
+ powertools-examples-core-serverless
+ jar
+
+ Powertools for AWS Lambda (Java) library Examples - Core
+
+
+ 2.20.0
+ 1.8
+ 1.8
+
+
+
+
+ software.amazon.lambda
+ powertools-tracing
+ ${project.version}
+
+
+ software.amazon.lambda
+ powertools-logging
+ ${project.version}
+
+
+ software.amazon.lambda
+ powertools-metrics
+ ${project.version}
+
+
+ com.amazonaws
+ aws-lambda-java-core
+ 1.2.2
+
+
+ com.amazonaws
+ aws-lambda-java-events
+ 3.11.2
+
+
+ org.apache.logging.log4j
+ log4j-core
+ ${log4j.version}
+
+
+ org.apache.logging.log4j
+ log4j-api
+ ${log4j.version}
+
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
+
+
+ helloworld-lambda
+
+
+ dev.aspectj
+ aspectj-maven-plugin
+ 1.13.1
+
+
+ ${maven.compiler.target}
+ ${maven.compiler.target}
+
+
+ software.amazon.lambda
+ powertools-tracing
+
+
+ software.amazon.lambda
+ powertools-logging
+
+
+ software.amazon.lambda
+ powertools-metrics
+
+
+
+
+
+
+ compile
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.5.0
+
+
+ package
+
+ shade
+
+
+
+
+
+
+
+
+
+
+
+ com.github.edwgiz
+ maven-shade-plugin.log4j2-cachefile-transformer
+ 2.15
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+
+ true
+
+
+
+
+
+
+
+ jdk8
+
+ (,11)
+
+
+ 1.9.7
+
+
+
+
+ org.aspectj
+ aspectjtools
+ ${aspectj.version}
+
+
+
+
+
+
+
+ dev.aspectj
+ aspectj-maven-plugin
+ ${aspectj.plugin.version}
+
+
+ ${maven.compiler.target}
+ ${maven.compiler.target}
+
+
+ software.amazon.lambda
+ powertools-tracing
+
+
+ software.amazon.lambda
+ powertools-logging
+
+
+ software.amazon.lambda
+ powertools-metrics
+
+
+
+
+
+
+ compile
+ test-compile
+
+
+
+
+
+
+ org.aspectj
+ aspectjtools
+ ${aspectj.version}
+
+
+
+
+
+
+
+
+
diff --git a/examples/powertools-examples-core/serverless/serverless.yml b/examples/powertools-examples-core/serverless/serverless.yml
new file mode 100644
index 000000000..d8dec8080
--- /dev/null
+++ b/examples/powertools-examples-core/serverless/serverless.yml
@@ -0,0 +1,40 @@
+service: hello
+# app and org for use with dashboard.serverless.com
+#app: your-app-name
+#org: your-org-name
+
+# You can pin your service to only deploy with a specific Serverless version
+# Check out our docs for more details
+frameworkVersion: '3'
+
+provider:
+ name: aws
+ runtime: java11
+
+# you can overwrite defaults here
+# stage: dev
+# region: us-east-1
+
+# you can define service wide environment variables here
+ environment:
+ POWERTOOLS_LOG_LEVEL: INFO
+ POWERTOOLS_LOGGER_SAMPLE_RATE: 0.1
+ POWERTOOLS_METRICS_NAMESPACE: Coreutilities
+
+# you can add packaging information here
+package:
+ artifact: target/helloworld-lambda.jar
+
+functions:
+ hello:
+ handler: helloworld.App
+ memorySize: 512
+ timeout: 20
+ tracing: "Active"
+ events:
+ - httpApi:
+ path: /hello
+ method: get
+# Define function environment variables here
+ environment:
+ POWERTOOLS_SERVICE_NAME: hello
diff --git a/examples/powertools-examples-core/serverless/src/main/java/helloworld/App.java b/examples/powertools-examples-core/serverless/src/main/java/helloworld/App.java
new file mode 100644
index 000000000..dacd7f1d4
--- /dev/null
+++ b/examples/powertools-examples-core/serverless/src/main/java/helloworld/App.java
@@ -0,0 +1,105 @@
+/*
+ * 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 helloworld;
+
+import static software.amazon.lambda.powertools.metrics.MetricsUtils.metricsLogger;
+import static software.amazon.lambda.powertools.metrics.MetricsUtils.withSingleMetric;
+import static software.amazon.lambda.powertools.tracing.TracingUtils.putMetadata;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.RequestHandler;
+import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import software.amazon.cloudwatchlogs.emf.model.DimensionSet;
+import software.amazon.cloudwatchlogs.emf.model.Unit;
+import software.amazon.lambda.powertools.logging.Logging;
+import software.amazon.lambda.powertools.logging.LoggingUtils;
+import software.amazon.lambda.powertools.metrics.Metrics;
+import software.amazon.lambda.powertools.tracing.CaptureMode;
+import software.amazon.lambda.powertools.tracing.Tracing;
+import software.amazon.lambda.powertools.tracing.TracingUtils;
+
+/**
+ * Handler for requests to Lambda function.
+ */
+public class App implements RequestHandler {
+ private final static Logger log = LogManager.getLogger(App.class);
+
+ // This is controlled by POWERTOOLS_LOGGER_SAMPLE_RATE environment variable
+ // @Logging(logEvent = true, samplingRate = 0.7)
+ // This is controlled by POWERTOOLS_METRICS_NAMESPACE environment variable
+ // @Metrics(namespace = "ServerlessAirline", service = "payment", captureColdStart = true)
+ // This is controlled by POWERTOOLS_TRACER_CAPTURE_ERROR environment variable
+ @Tracing(captureMode = CaptureMode.RESPONSE_AND_ERROR)
+ public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
+ Map headers = new HashMap<>();
+
+ headers.put("Content-Type", "application/json");
+ headers.put("X-Custom-Header", "application/json");
+
+ metricsLogger().putMetric("CustomMetric1", 1, Unit.COUNT);
+
+ withSingleMetric("CustomMetrics2", 1, Unit.COUNT, "Another", (metric) ->
+ {
+ metric.setDimensions(DimensionSet.of("AnotherService", "CustomService"));
+ metric.setDimensions(DimensionSet.of("AnotherService1", "CustomService1"));
+ });
+
+ LoggingUtils.appendKey("test", "willBeLogged");
+
+ APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent()
+ .withHeaders(headers);
+ try {
+ final String pageContents = this.getPageContents("https://checkip.amazonaws.com");
+ log.info(pageContents);
+ TracingUtils.putAnnotation("Test", "New");
+ String output = String.format("{ \"message\": \"hello world\", \"location\": \"%s\" }", pageContents);
+
+ TracingUtils.withSubsegment("loggingResponse", subsegment ->
+ {
+ String sampled = "log something out";
+ log.info(sampled);
+ log.info(output);
+ });
+
+ log.info("After output");
+ return response
+ .withStatusCode(200)
+ .withBody(output);
+ } catch (RuntimeException | IOException e) {
+ return response
+ .withBody("{}")
+ .withStatusCode(500);
+ }
+ }
+
+ @Tracing(namespace = "getPageContents", captureMode = CaptureMode.DISABLED)
+ private String getPageContents(String address) throws IOException {
+ URL url = new URL(address);
+ putMetadata("getPageContents", address);
+ try (BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()))) {
+ return br.lines().collect(Collectors.joining(System.lineSeparator()));
+ }
+ }
+}
diff --git a/examples/powertools-examples-core/serverless/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/serverless/src/main/java/helloworld/AppStream.java
new file mode 100644
index 000000000..401ef8c48
--- /dev/null
+++ b/examples/powertools-examples-core/serverless/src/main/java/helloworld/AppStream.java
@@ -0,0 +1,38 @@
+/*
+ * 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 helloworld;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Map;
+import software.amazon.lambda.powertools.logging.Logging;
+import software.amazon.lambda.powertools.metrics.Metrics;
+
+public class AppStream implements RequestStreamHandler {
+ private static final ObjectMapper mapper = new ObjectMapper();
+
+ @Override
+ @Logging(logEvent = true)
+ @Metrics(namespace = "ServerlessAirline", service = "payment", captureColdStart = true)
+ public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
+ Map map = mapper.readValue(input, Map.class);
+
+ System.out.println(map.size());
+ }
+}
diff --git a/examples/powertools-examples-core/serverless/src/main/resources/log4j2.xml b/examples/powertools-examples-core/serverless/src/main/resources/log4j2.xml
new file mode 100644
index 000000000..0cc0953f0
--- /dev/null
+++ b/examples/powertools-examples-core/serverless/src/main/resources/log4j2.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/powertools-examples-core/serverless/src/test/java/helloworld/AppTest.java b/examples/powertools-examples-core/serverless/src/test/java/helloworld/AppTest.java
new file mode 100644
index 000000000..70dad8d71
--- /dev/null
+++ b/examples/powertools-examples-core/serverless/src/test/java/helloworld/AppTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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 helloworld;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
+import com.amazonaws.xray.AWSXRay;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class AppTest {
+
+ @Before
+ public void setup() {
+ if (null == System.getenv("LAMBDA_TASK_ROOT")) {
+ AWSXRay.beginSegment("test");
+ }
+ }
+
+ @After
+ public void tearDown() {
+ if (AWSXRay.getCurrentSubsegmentOptional().isPresent()) {
+ AWSXRay.endSubsegment();
+ }
+
+ if (null == System.getenv("LAMBDA_TASK_ROOT")) {
+ AWSXRay.endSegment();
+ }
+ }
+
+ @Test
+ public void successfulResponse() {
+ App app = new App();
+ APIGatewayProxyResponseEvent result = app.handleRequest(null, null);
+ assertEquals(result.getStatusCode().intValue(), 200);
+ assertEquals(result.getHeaders().get("Content-Type"), "application/json");
+ String content = result.getBody();
+ assertNotNull(content);
+ assertTrue(content.contains("\"message\""));
+ assertTrue(content.contains("\"hello world\""));
+ assertTrue(content.contains("\"location\""));
+ }
+}