From e66095e098a678cc9e61c5a2db02a39cd5380d18 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Mon, 2 Oct 2023 13:39:41 +0100 Subject: [PATCH 01/40] Setting up Kotlin environment. Converting test to Kotlin. --- .../powertools-examples-core/kotlin/README.md | 38 +++ .../kotlin/build.gradle | 47 ++++ .../kotlin/events/event.json | 62 +++++ .../kotlin/gradle/wrapper/.gitignore | 2 + .../kotlin/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 63375 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + .../powertools-examples-core/kotlin/gradlew | 248 ++++++++++++++++++ .../kotlin/gradlew.bat | 92 +++++++ .../kotlin/src/main/java/helloworld/App.java | 107 ++++++++ .../src/main/java/helloworld/AppStream.java | 38 +++ .../src/test/kotlin/helloworld/AppTest.kt | 19 ++ .../kotlin/template.yaml | 71 +++++ 12 files changed, 731 insertions(+) create mode 100644 examples/powertools-examples-core/kotlin/README.md create mode 100644 examples/powertools-examples-core/kotlin/build.gradle create mode 100644 examples/powertools-examples-core/kotlin/events/event.json create mode 100644 examples/powertools-examples-core/kotlin/gradle/wrapper/.gitignore create mode 100644 examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.jar create mode 100644 examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.properties create mode 100755 examples/powertools-examples-core/kotlin/gradlew create mode 100644 examples/powertools-examples-core/kotlin/gradlew.bat create mode 100644 examples/powertools-examples-core/kotlin/src/main/java/helloworld/App.java create mode 100644 examples/powertools-examples-core/kotlin/src/main/java/helloworld/AppStream.java create mode 100644 examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt create mode 100644 examples/powertools-examples-core/kotlin/template.yaml diff --git a/examples/powertools-examples-core/kotlin/README.md b/examples/powertools-examples-core/kotlin/README.md new file mode 100644 index 000000000..c7c798d5d --- /dev/null +++ b/examples/powertools-examples-core/kotlin/README.md @@ -0,0 +1,38 @@ +# Powertools for AWS Lambda (Java) - Core Utilities Example with Gradle + +This project demonstrates the Lambda for Powertools Java module deployed using [Serverless Application Model](https://aws.amazon.com/serverless/sam/) with +[Gradle](https://gradle.org/) running the build. This example is configured for Java 1.8 only; in order to use a newer version, check out the Gradle +configuration guide [in the main project README](../../../README.md). + +You can also use `sam init` to create a new Gradle-powered Powertools application - choose to use the **AWS Quick Start Templates**, +and then **Hello World Example with Powertools for AWS Lambda**, **Java 17** runtime, and finally **gradle**. + + +For general information on the deployed example itself, you can refer to the parent [README](../README.md) + +## Configuration +SAM uses [template.yaml](template.yaml) to define the application's AWS resources. +This file defines the Lambda function to be deployed as well as API Gateway for it. + +The build of the project is managed by Gradle, and configured in [build.gradle](build.gradle). + +## Deploy the sample application +To get started, you can use the Gradle wrapper to bootstrap Gradle and run the build: + +```bash +./gradlew build +``` + +Once this is done to deploy the example, check out the instructions for getting started with SAM in +[the examples directory](../../README.md) + +## Additional notes + +You can watch the trace information or log information using the SAM CLI: +```bash +# Tail the logs +sam logs --tail $MY_STACK + +# Tail the traces +sam traces --tail +``` \ No newline at end of file diff --git a/examples/powertools-examples-core/kotlin/build.gradle b/examples/powertools-examples-core/kotlin/build.gradle new file mode 100644 index 000000000..885de6f43 --- /dev/null +++ b/examples/powertools-examples-core/kotlin/build.gradle @@ -0,0 +1,47 @@ + +plugins { + id 'java' + id "io.freefair.aspectj.post-compile-weaving" version "6.6.3" + id 'org.jetbrains.kotlin.jvm' version '1.9.10' +} + +wrapper { + gradleVersion = "7.6.1" +} + +compileJava { + sourceCompatibility = "1.8" + targetCompatibility = "1.8" + + ajc { + enabled = true + } +} + +repositories { + mavenCentral() +} + +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' + aspect 'software.amazon.lambda:powertools-tracing:1.17.0' + aspect 'software.amazon.lambda:powertools-logging:1.17.0' + aspect 'software.amazon.lambda:powertools-metrics:1.17.0' + testImplementation 'junit:junit:4.13.2' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" +} +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} + diff --git a/examples/powertools-examples-core/kotlin/events/event.json b/examples/powertools-examples-core/kotlin/events/event.json new file mode 100644 index 000000000..070ad8e01 --- /dev/null +++ b/examples/powertools-examples-core/kotlin/events/event.json @@ -0,0 +1,62 @@ +{ + "body": "{\"message\": \"hello world\"}", + "resource": "/{proxy+}", + "path": "/path/to/resource", + "httpMethod": "POST", + "isBase64Encoded": false, + "queryStringParameters": { + "foo": "bar" + }, + "pathParameters": { + "proxy": "/path/to/resource" + }, + "stageVariables": { + "baz": "qux" + }, + "headers": { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", + "Accept-Encoding": "gzip, deflate, sdch", + "Accept-Language": "en-US,en;q=0.8", + "Cache-Control": "max-age=0", + "CloudFront-Forwarded-Proto": "https", + "CloudFront-Is-Desktop-Viewer": "true", + "CloudFront-Is-Mobile-Viewer": "false", + "CloudFront-Is-SmartTV-Viewer": "false", + "CloudFront-Is-Tablet-Viewer": "false", + "CloudFront-Viewer-Country": "US", + "Host": "1234567890.execute-api.us-east-1.amazonaws.com", + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Custom User Agent String", + "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==", + "X-Forwarded-For": "127.0.0.1, 127.0.0.2", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https" + }, + "requestContext": { + "accountId": "123456789012", + "resourceId": "123456", + "stage": "prod", + "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", + "requestTime": "09/Apr/2015:12:34:56 +0000", + "requestTimeEpoch": 1428582896000, + "identity": { + "cognitoIdentityPoolId": null, + "accountId": null, + "cognitoIdentityId": null, + "caller": null, + "accessKey": null, + "sourceIp": "127.0.0.1", + "cognitoAuthenticationType": null, + "cognitoAuthenticationProvider": null, + "userArn": null, + "userAgent": "Custom User Agent String", + "user": null + }, + "path": "/prod/path/to/resource", + "resourcePath": "/{proxy+}", + "httpMethod": "POST", + "apiId": "1234567890", + "protocol": "HTTP/1.1" + } +} diff --git a/examples/powertools-examples-core/kotlin/gradle/wrapper/.gitignore b/examples/powertools-examples-core/kotlin/gradle/wrapper/.gitignore new file mode 100644 index 000000000..59c09e205 --- /dev/null +++ b/examples/powertools-examples-core/kotlin/gradle/wrapper/.gitignore @@ -0,0 +1,2 @@ +!gradle-wrapper.jar + diff --git a/examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.jar b/examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..033e24c4cdf41af1ab109bc7f253b2b887023340 GIT binary patch literal 63375 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≫L+crb^Bz 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 '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/examples/powertools-examples-core/kotlin/gradlew.bat b/examples/powertools-examples-core/kotlin/gradlew.bat new file mode 100644 index 000000000..6689b85be --- /dev/null +++ b/examples/powertools-examples-core/kotlin/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/examples/powertools-examples-core/kotlin/src/main/java/helloworld/App.java b/examples/powertools-examples-core/kotlin/src/main/java/helloworld/App.java new file mode 100644 index 000000000..fccc63b9a --- /dev/null +++ b/examples/powertools-examples-core/kotlin/src/main/java/helloworld/App.java @@ -0,0 +1,107 @@ +/* + * 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); + + @Logging(logEvent = true, samplingRate = 0.7) + @Tracing(captureMode = CaptureMode.RESPONSE_AND_ERROR) + @Metrics(namespace = "ServerlessAirline", service = "payment", captureColdStart = true) + 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 + private void log() { + log.info("inside threaded logging for function"); + } + + @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/kotlin/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/kotlin/src/main/java/helloworld/AppStream.java new file mode 100644 index 000000000..401ef8c48 --- /dev/null +++ b/examples/powertools-examples-core/kotlin/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/kotlin/src/test/kotlin/helloworld/AppTest.kt b/examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt new file mode 100644 index 000000000..b137aecce --- /dev/null +++ b/examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt @@ -0,0 +1,19 @@ +package helloworld + +import org.junit.Assert +import org.junit.Test + +class AppTest { + @Test + fun successfulResponse() { + val app = App() + val result = app.handleRequest(null, null) + Assert.assertEquals(200, result.statusCode.toLong()) + Assert.assertEquals("application/json", result.headers["Content-Type"]) + val content = result.body + Assert.assertNotNull(content) + Assert.assertTrue(""""message"""" in content) + Assert.assertTrue(""""hello world"""" in content) + Assert.assertTrue(""""location"""" in content) + } +} diff --git a/examples/powertools-examples-core/kotlin/template.yaml b/examples/powertools-examples-core/kotlin/template.yaml new file mode 100644 index 000000000..a717c2998 --- /dev/null +++ b/examples/powertools-examples-core/kotlin/template.yaml @@ -0,0 +1,71 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + gradle + + Sample SAM Template for gradle + +# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst +Globals: + Function: + Timeout: 20 + Runtime: java11 + MemorySize: 512 + Tracing: Active # https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html + Environment: + Variables: + # Powertools for AWS Lambda (Java) env vars: https://docs.powertools.aws.dev/lambda/java/#environment-variables + POWERTOOLS_LOG_LEVEL: INFO + POWERTOOLS_LOGGER_SAMPLE_RATE: 0.1 + POWERTOOLS_LOGGER_LOG_EVENT: true + POWERTOOLS_METRICS_NAMESPACE: Coreutilities + +Resources: + HelloWorldFunction: + Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction + Properties: + CodeUri: . + Handler: helloworld.App::handleRequest + Runtime: java8 + MemorySize: 512 + Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object + Variables: + POWERTOOLS_SERVICE_NAME: hello + Events: + HelloWorld: + Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api + Properties: + Path: /hello + Method: get + + HelloWorldStreamFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: . + Handler: helloworld.AppStream::handleRequest + Runtime: java8 + MemorySize: 512 + Tracing: Active + Environment: + Variables: + POWERTOOLS_LOGGER_SAMPLE_RATE: 0.7 + Events: + HelloWorld: + Type: Api + Properties: + Path: /hellostream + Method: get + +Outputs: + # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function + # Find out more about other implicit resources you can reference within SAM + # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api + HelloWorldApi: + Description: "API Gateway endpoint URL for Prod stage for Hello World function" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/" + HelloWorldFunction: + Description: "Hello World Lambda Function ARN" + Value: !GetAtt HelloWorldFunction.Arn + HelloWorldFunctionIamRole: + Description: "Implicit IAM Role created for Hello World function" + Value: !GetAtt HelloWorldFunctionRole.Arn From ea0b496d79a89e1fe2119236fb1093a93cb85e12 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Mon, 2 Oct 2023 14:54:10 +0100 Subject: [PATCH 02/40] Deploying via SAM successfully. --- .../kotlin/src/main/java/helloworld/App.java | 107 ------------------ .../kotlin/src/main/kotlin/helloworld/App.kt | 100 ++++++++++++++++ .../helloworld/AppStream.kt} | 35 +++--- .../src/test/kotlin/helloworld/AppTest.kt | 1 + 4 files changed, 118 insertions(+), 125 deletions(-) delete mode 100644 examples/powertools-examples-core/kotlin/src/main/java/helloworld/App.java create mode 100644 examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt rename examples/powertools-examples-core/kotlin/src/main/{java/helloworld/AppStream.java => kotlin/helloworld/AppStream.kt} (53%) diff --git a/examples/powertools-examples-core/kotlin/src/main/java/helloworld/App.java b/examples/powertools-examples-core/kotlin/src/main/java/helloworld/App.java deleted file mode 100644 index fccc63b9a..000000000 --- a/examples/powertools-examples-core/kotlin/src/main/java/helloworld/App.java +++ /dev/null @@ -1,107 +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 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); - - @Logging(logEvent = true, samplingRate = 0.7) - @Tracing(captureMode = CaptureMode.RESPONSE_AND_ERROR) - @Metrics(namespace = "ServerlessAirline", service = "payment", captureColdStart = true) - 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 - private void log() { - log.info("inside threaded logging for function"); - } - - @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/kotlin/src/main/kotlin/helloworld/App.kt b/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt new file mode 100644 index 000000000..1084b5791 --- /dev/null +++ b/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt @@ -0,0 +1,100 @@ +/* + * 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.RequestHandler +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent +import com.amazonaws.xray.entities.Subsegment +import org.apache.logging.log4j.LogManager +import software.amazon.cloudwatchlogs.emf.logger.MetricsLogger +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.metrics.MetricsUtils +import software.amazon.lambda.powertools.tracing.CaptureMode +import software.amazon.lambda.powertools.tracing.Tracing +import software.amazon.lambda.powertools.tracing.TracingUtils +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader +import java.net.URL +import java.util.stream.Collectors + +/** + * Handler for requests to Lambda function. + */ + +// TODO: Update context so not optional - this was changed to satisfy test +class App : RequestHandler { + @Logging(logEvent = true, samplingRate = 0.7) + @Tracing(captureMode = CaptureMode.RESPONSE_AND_ERROR) + @Metrics(namespace = "ServerlessAirline", service = "payment", captureColdStart = true) + override fun handleRequest(input: APIGatewayProxyRequestEvent?, context: Context?): APIGatewayProxyResponseEvent { // changed context to be optional so can pass null from test + val headers: MutableMap = HashMap() + headers["Content-Type"] = "application/json" + headers["X-Custom-Header"] = "application/json" + MetricsUtils.metricsLogger().putMetric("CustomMetric1", 1.0, Unit.COUNT) + MetricsUtils.withSingleMetric("CustomMetrics2", 1.0, Unit.COUNT, "Another") { metric: MetricsLogger -> + metric.setDimensions(DimensionSet.of("AnotherService", "CustomService")) + metric.setDimensions(DimensionSet.of("AnotherService1", "CustomService1")) + } + LoggingUtils.appendKey("test", "willBeLogged") + val response = APIGatewayProxyResponseEvent() + .withHeaders(headers) + return try { + val pageContents = getPageContents("https://checkip.amazonaws.com") + log.info(pageContents) + TracingUtils.putAnnotation("Test", "New") + val output = String.format("{ \"message\": \"hello world\", \"location\": \"%s\" }", pageContents) + TracingUtils.withSubsegment("loggingResponse") { subsegment: Subsegment? -> + val sampled = "log something out" + log.info(sampled) + log.info(output) + } + log.info("After output") + response + .withStatusCode(200) + .withBody(output) + } catch (e: RuntimeException) { + response + .withBody("{}") + .withStatusCode(500) + } catch (e: IOException) { + response + .withBody("{}") + .withStatusCode(500) + } + } + + @Tracing + private fun log() { + log.info("inside threaded logging for function") + } + + @Tracing(namespace = "getPageContents", captureMode = CaptureMode.DISABLED) + @Throws(IOException::class) + private fun getPageContents(address: String): String { + val url = URL(address) + TracingUtils.putMetadata("getPageContents", address) + BufferedReader(InputStreamReader(url.openStream())).use { br -> return br.lines().collect(Collectors.joining(System.lineSeparator())) } + } + + companion object { + private val log = LogManager.getLogger(App::class.java) + } +} diff --git a/examples/powertools-examples-core/kotlin/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/AppStream.kt similarity index 53% rename from examples/powertools-examples-core/kotlin/src/main/java/helloworld/AppStream.java rename to examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/AppStream.kt index 401ef8c48..99f6bbfa0 100644 --- a/examples/powertools-examples-core/kotlin/src/main/java/helloworld/AppStream.java +++ b/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/AppStream.kt @@ -11,28 +11,27 @@ * limitations under the License. * */ +package helloworld -package helloworld; +import com.amazonaws.services.lambda.runtime.Context +import com.amazonaws.services.lambda.runtime.RequestStreamHandler +import com.fasterxml.jackson.databind.ObjectMapper +import software.amazon.lambda.powertools.logging.Logging +import software.amazon.lambda.powertools.metrics.Metrics +import java.io.IOException +import java.io.InputStream +import java.io.OutputStream -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 +class AppStream : RequestStreamHandler { @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); + @Throws(IOException::class) + override fun handleRequest(input: InputStream, output: OutputStream, context: Context) { + val map: Map<*, *> = mapper.readValue(input, MutableMap::class.java) + println(map.size) + } - System.out.println(map.size()); + companion object { + private val mapper = ObjectMapper() } } diff --git a/examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt b/examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt index b137aecce..8aae081e8 100644 --- a/examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt +++ b/examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt @@ -1,5 +1,6 @@ package helloworld + import org.junit.Assert import org.junit.Test From 615a0952b056a5053d93e41e77bbc3592ddc1a0d Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Tue, 3 Oct 2023 16:46:04 +0100 Subject: [PATCH 03/40] Added Kotlin example. --- examples/powertools-examples-core/README.md | 10 +++++++ .../powertools-examples-core/kotlin/README.md | 6 ++-- .../kotlin/{build.gradle => _build.gradle} | 0 .../kotlin/build.gradle.kts | 28 +++++++++++++++++++ .../kotlin/src/main/kotlin/helloworld/App.kt | 26 ++++++++--------- 5 files changed, 53 insertions(+), 17 deletions(-) rename examples/powertools-examples-core/kotlin/{build.gradle => _build.gradle} (100%) create mode 100644 examples/powertools-examples-core/kotlin/build.gradle.kts diff --git a/examples/powertools-examples-core/README.md b/examples/powertools-examples-core/README.md index 1d1dd031f..f2af999b9 100644 --- a/examples/powertools-examples-core/README.md +++ b/examples/powertools-examples-core/README.md @@ -15,6 +15,7 @@ We also provide an example showing the integration of SAM, Powertools, and Gradl * [AWS SAM with a Gradle build](gradle/) +## Java For each of the tools, the example application is the same, and consists of the following files: - [App.java](sam/src/main/java/helloworld/App.java) - Code for the application's Lambda function. @@ -23,6 +24,15 @@ For each of the tools, the example application is the same, and consists of the Configuration files and deployment process for each tool are described in corresponding README files. +## Kotlin +For each of the tools, the example application is the same, and consists of the following files: + +- [App.kt](kotlin/src/main/kotlin/helloworld/App.kt) - Code for the application's Lambda function. +- [AppTests.kt](kotlin/src/test/kotlin/helloworld/AppTest.kt) - Unit tests for the application code. +- [events](kotlin/events/event.json) - Invocation events that you can use to invoke the function. + +Configuration files and deployment process for each tool are described in corresponding README files. + ## Test the application Once the app is deployed, you can invoke the endpoint like this: diff --git a/examples/powertools-examples-core/kotlin/README.md b/examples/powertools-examples-core/kotlin/README.md index c7c798d5d..6f0510c48 100644 --- a/examples/powertools-examples-core/kotlin/README.md +++ b/examples/powertools-examples-core/kotlin/README.md @@ -1,6 +1,6 @@ -# Powertools for AWS Lambda (Java) - Core Utilities Example with Gradle +# Powertools for AWS Lambda (Kotlin) - Core Utilities Example -This project demonstrates the Lambda for Powertools Java module deployed using [Serverless Application Model](https://aws.amazon.com/serverless/sam/) with +This project demonstrates the Lambda for Powertools Kotlin module deployed using [Serverless Application Model](https://aws.amazon.com/serverless/sam/) with [Gradle](https://gradle.org/) running the build. This example is configured for Java 1.8 only; in order to use a newer version, check out the Gradle configuration guide [in the main project README](../../../README.md). @@ -14,7 +14,7 @@ For general information on the deployed example itself, you can refer to the par SAM uses [template.yaml](template.yaml) to define the application's AWS resources. This file defines the Lambda function to be deployed as well as API Gateway for it. -The build of the project is managed by Gradle, and configured in [build.gradle](build.gradle). +The build of the project is managed by Gradle, and configured in [build.gradle](_build.gradle). ## Deploy the sample application To get started, you can use the Gradle wrapper to bootstrap Gradle and run the build: diff --git a/examples/powertools-examples-core/kotlin/build.gradle b/examples/powertools-examples-core/kotlin/_build.gradle similarity index 100% rename from examples/powertools-examples-core/kotlin/build.gradle rename to examples/powertools-examples-core/kotlin/_build.gradle diff --git a/examples/powertools-examples-core/kotlin/build.gradle.kts b/examples/powertools-examples-core/kotlin/build.gradle.kts new file mode 100644 index 000000000..a1a9e29da --- /dev/null +++ b/examples/powertools-examples-core/kotlin/build.gradle.kts @@ -0,0 +1,28 @@ +plugins { + java + id("io.freefair.aspectj.post-compile-weaving") version "6.6.3" + kotlin("jvm") version "1.9.10" +} + +repositories { + mavenCentral() +} + +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") + aspect("software.amazon.lambda:powertools-tracing:1.17.0") + aspect("software.amazon.lambda:powertools-logging:1.17.0") + aspect("software.amazon.lambda:powertools-metrics:1.17.0") + testImplementation("junit:junit:4.13.2") + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") +} + +tasks.compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} diff --git a/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt b/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt index 1084b5791..5b6a45ce8 100644 --- a/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt +++ b/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt @@ -39,12 +39,12 @@ import java.util.stream.Collectors * Handler for requests to Lambda function. */ -// TODO: Update context so not optional - this was changed to satisfy test class App : RequestHandler { @Logging(logEvent = true, samplingRate = 0.7) @Tracing(captureMode = CaptureMode.RESPONSE_AND_ERROR) @Metrics(namespace = "ServerlessAirline", service = "payment", captureColdStart = true) - override fun handleRequest(input: APIGatewayProxyRequestEvent?, context: Context?): APIGatewayProxyResponseEvent { // changed context to be optional so can pass null from test + + override fun handleRequest(input: APIGatewayProxyRequestEvent?, context: Context?): APIGatewayProxyResponseEvent { // changed context to be optional so can pass null val headers: MutableMap = HashMap() headers["Content-Type"] = "application/json" headers["X-Custom-Header"] = "application/json" @@ -54,30 +54,28 @@ class App : RequestHandler val sampled = "log something out" log.info(sampled) log.info(output) } log.info("After output") - response - .withStatusCode(200) - .withBody(output) + response.withStatusCode(200).withBody(output) } catch (e: RuntimeException) { - response - .withBody("{}") - .withStatusCode(500) + response.withBody("{}").withStatusCode(500) } catch (e: IOException) { - response - .withBody("{}") - .withStatusCode(500) + response.withBody("{}").withStatusCode(500) } } From 51991056697424e728d285c8ca9fa99857c50667 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Tue, 3 Oct 2023 16:55:55 +0100 Subject: [PATCH 04/40] Removing unused Gradle build file. --- .../kotlin/_build.gradle | 47 ------------------- .../kotlin/build.gradle.kts | 1 - 2 files changed, 48 deletions(-) delete mode 100644 examples/powertools-examples-core/kotlin/_build.gradle diff --git a/examples/powertools-examples-core/kotlin/_build.gradle b/examples/powertools-examples-core/kotlin/_build.gradle deleted file mode 100644 index 885de6f43..000000000 --- a/examples/powertools-examples-core/kotlin/_build.gradle +++ /dev/null @@ -1,47 +0,0 @@ - -plugins { - id 'java' - id "io.freefair.aspectj.post-compile-weaving" version "6.6.3" - id 'org.jetbrains.kotlin.jvm' version '1.9.10' -} - -wrapper { - gradleVersion = "7.6.1" -} - -compileJava { - sourceCompatibility = "1.8" - targetCompatibility = "1.8" - - ajc { - enabled = true - } -} - -repositories { - mavenCentral() -} - -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' - aspect 'software.amazon.lambda:powertools-tracing:1.17.0' - aspect 'software.amazon.lambda:powertools-logging:1.17.0' - aspect 'software.amazon.lambda:powertools-metrics:1.17.0' - testImplementation 'junit:junit:4.13.2' - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" -} -compileKotlin { - kotlinOptions { - jvmTarget = "1.8" - } -} -compileTestKotlin { - kotlinOptions { - jvmTarget = "1.8" - } -} - diff --git a/examples/powertools-examples-core/kotlin/build.gradle.kts b/examples/powertools-examples-core/kotlin/build.gradle.kts index a1a9e29da..81237f07a 100644 --- a/examples/powertools-examples-core/kotlin/build.gradle.kts +++ b/examples/powertools-examples-core/kotlin/build.gradle.kts @@ -1,5 +1,4 @@ plugins { - java id("io.freefair.aspectj.post-compile-weaving") version "6.6.3" kotlin("jvm") version "1.9.10" } From 6386358e444b0b868a92b71e0758e6417417e60f Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Wed, 4 Oct 2023 13:54:01 +0100 Subject: [PATCH 05/40] Adding SAM template so can be used as an existing project and Java target compatibility --- .../kotlin/build.gradle.kts | 4 ++ .../kotlin/template.yaml | 71 ------------------- 2 files changed, 4 insertions(+), 71 deletions(-) delete mode 100644 examples/powertools-examples-core/kotlin/template.yaml diff --git a/examples/powertools-examples-core/kotlin/build.gradle.kts b/examples/powertools-examples-core/kotlin/build.gradle.kts index 81237f07a..b89b93526 100644 --- a/examples/powertools-examples-core/kotlin/build.gradle.kts +++ b/examples/powertools-examples-core/kotlin/build.gradle.kts @@ -25,3 +25,7 @@ tasks.compileKotlin { jvmTarget = "1.8" } } + +java { + targetCompatibility = JavaVersion.VERSION_1_8 +} diff --git a/examples/powertools-examples-core/kotlin/template.yaml b/examples/powertools-examples-core/kotlin/template.yaml deleted file mode 100644 index a717c2998..000000000 --- a/examples/powertools-examples-core/kotlin/template.yaml +++ /dev/null @@ -1,71 +0,0 @@ -AWSTemplateFormatVersion: '2010-09-09' -Transform: AWS::Serverless-2016-10-31 -Description: > - gradle - - Sample SAM Template for gradle - -# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst -Globals: - Function: - Timeout: 20 - Runtime: java11 - MemorySize: 512 - Tracing: Active # https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html - Environment: - Variables: - # Powertools for AWS Lambda (Java) env vars: https://docs.powertools.aws.dev/lambda/java/#environment-variables - POWERTOOLS_LOG_LEVEL: INFO - POWERTOOLS_LOGGER_SAMPLE_RATE: 0.1 - POWERTOOLS_LOGGER_LOG_EVENT: true - POWERTOOLS_METRICS_NAMESPACE: Coreutilities - -Resources: - HelloWorldFunction: - Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction - Properties: - CodeUri: . - Handler: helloworld.App::handleRequest - Runtime: java8 - MemorySize: 512 - Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object - Variables: - POWERTOOLS_SERVICE_NAME: hello - Events: - HelloWorld: - Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api - Properties: - Path: /hello - Method: get - - HelloWorldStreamFunction: - Type: AWS::Serverless::Function - Properties: - CodeUri: . - Handler: helloworld.AppStream::handleRequest - Runtime: java8 - MemorySize: 512 - Tracing: Active - Environment: - Variables: - POWERTOOLS_LOGGER_SAMPLE_RATE: 0.7 - Events: - HelloWorld: - Type: Api - Properties: - Path: /hellostream - Method: get - -Outputs: - # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function - # Find out more about other implicit resources you can reference within SAM - # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api - HelloWorldApi: - Description: "API Gateway endpoint URL for Prod stage for Hello World function" - Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/" - HelloWorldFunction: - Description: "Hello World Lambda Function ARN" - Value: !GetAtt HelloWorldFunction.Arn - HelloWorldFunctionIamRole: - Description: "Implicit IAM Role created for Hello World function" - Value: !GetAtt HelloWorldFunctionRole.Arn From 19679dacaa2d6eae8ebdfb6a6baaae43b312c624 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Wed, 4 Oct 2023 13:57:03 +0100 Subject: [PATCH 06/40] Adding SAM template so can be used as an existing project --- .../kotlin/template.yaml | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 examples/powertools-examples-core/kotlin/template.yaml diff --git a/examples/powertools-examples-core/kotlin/template.yaml b/examples/powertools-examples-core/kotlin/template.yaml new file mode 100644 index 000000000..1a1572fca --- /dev/null +++ b/examples/powertools-examples-core/kotlin/template.yaml @@ -0,0 +1,71 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + gradle + + Sample SAM Template for gradle + +# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst +Globals: + Function: + Timeout: 20 + Runtime: java11 + MemorySize: 512 + Tracing: Active # https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html + Environment: + Variables: + # Powertools for AWS Lambda (Java) env vars: https://docs.powertools.aws.dev/lambda/java/#environment-variables + POWERTOOLS_LOG_LEVEL: INFO + POWERTOOLS_LOGGER_SAMPLE_RATE: 0.1 + POWERTOOLS_LOGGER_LOG_EVENT: true + POWERTOOLS_METRICS_NAMESPACE: Coreutilities + +Resources: + HelloWorldFunction: + Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction + Properties: + CodeUri: . + Handler: helloworld.App::handleRequest + Runtime: java11 + MemorySize: 512 + Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object + Variables: + POWERTOOLS_SERVICE_NAME: hello + Events: + HelloWorld: + Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api + Properties: + Path: /hello + Method: get + + HelloWorldStreamFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: . + Handler: helloworld.AppStream::handleRequest + Runtime: java11 + MemorySize: 512 + Tracing: Active + Environment: + Variables: + POWERTOOLS_LOGGER_SAMPLE_RATE: 0.7 + Events: + HelloWorld: + Type: Api + Properties: + Path: /hellostream + Method: get + +Outputs: + # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function + # Find out more about other implicit resources you can reference within SAM + # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api + HelloWorldApi: + Description: "API Gateway endpoint URL for Prod stage for Hello World function" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/" + HelloWorldFunction: + Description: "Hello World Lambda Function ARN" + Value: !GetAtt HelloWorldFunction.Arn + HelloWorldFunctionIamRole: + Description: "Implicit IAM Role created for Hello World function" + Value: !GetAtt HelloWorldFunctionRole.Arn From 17c3a5e1fb4bb139d2304dd6a6ecd4b9472efbc5 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Wed, 4 Oct 2023 15:19:15 +0100 Subject: [PATCH 07/40] Updating guidance to use SAM for build and deploy --- examples/powertools-examples-core/kotlin/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/powertools-examples-core/kotlin/README.md b/examples/powertools-examples-core/kotlin/README.md index 6f0510c48..ac1138f4d 100644 --- a/examples/powertools-examples-core/kotlin/README.md +++ b/examples/powertools-examples-core/kotlin/README.md @@ -7,7 +7,6 @@ configuration guide [in the main project README](../../../README.md). You can also use `sam init` to create a new Gradle-powered Powertools application - choose to use the **AWS Quick Start Templates**, and then **Hello World Example with Powertools for AWS Lambda**, **Java 17** runtime, and finally **gradle**. - For general information on the deployed example itself, you can refer to the parent [README](../README.md) ## Configuration @@ -17,10 +16,10 @@ This file defines the Lambda function to be deployed as well as API Gateway for The build of the project is managed by Gradle, and configured in [build.gradle](_build.gradle). ## Deploy the sample application -To get started, you can use the Gradle wrapper to bootstrap Gradle and run the build: +To get started, you can use the included template with SAM to run the build and deploy to your AWS environment: ```bash -./gradlew build +sam build && sam deploy --guided ``` Once this is done to deploy the example, check out the instructions for getting started with SAM in From 1312c0274d853c229d638761a41723335c8e7587 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Wed, 4 Oct 2023 15:29:52 +0100 Subject: [PATCH 08/40] Restructuring separate Java and Kotlin examples. --- examples/README.md | 2 +- .../{ => java}/cdk/README.md | 8 ++++---- .../{ => java}/cdk/app/events/event.json | 0 .../{ => java}/cdk/app/pom.xml | 0 .../cdk/app/src/main/java/helloworld/App.java | 0 .../cdk/app/src/main/java/helloworld/AppStream.java | 0 .../cdk/app/src/main/resources/log4j2.xml | 0 .../cdk/app/src/test/java/helloworld/AppTest.java | 0 .../{ => java}/cdk/infra/cdk.json | 0 .../{ => java}/cdk/infra/pom.xml | 0 .../cdk/infra/src/main/java/cdk/CdkApp.java | 0 .../cdk/infra/src/main/java/cdk/CdkStack.java | 0 .../cdk/infra/src/test/java/cdk/CdkStackTest.java | 0 .../{ => java}/gradle/README.md | 6 +++--- .../{ => java}/gradle/build.gradle | 0 .../{ => java}/gradle/events/event.json | 0 .../{ => java}/gradle/gradle/wrapper/.gitignore | 0 .../gradle/gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/gradle/wrapper/gradle-wrapper.properties | 0 .../{ => java}/gradle/gradlew | 0 .../{ => java}/gradle/gradlew.bat | 0 .../gradle/src/main/java/helloworld/App.java | 0 .../gradle/src/main/java/helloworld/AppStream.java | 0 .../gradle/src/test/java/helloworld/AppTest.java | 0 .../{ => java}/gradle/template.yaml | 0 .../{ => java}/sam/README.md | 4 ++-- .../{ => java}/sam/events/event.json | 0 .../powertools-examples-core/{ => java}/sam/pom.xml | 0 .../sam/src/main/java/helloworld/App.java | 0 .../sam/src/main/java/helloworld/AppStream.java | 0 .../{ => java}/sam/src/main/resources/log4j2.xml | 0 .../sam/src/test/java/helloworld/AppTest.java | 0 .../{ => java}/sam/template.yaml | 0 .../{ => java}/serverless/README.md | 4 ++-- .../{ => java}/serverless/pom.xml | 0 .../{ => java}/serverless/serverless.yml | 0 .../serverless/src/main/java/helloworld/App.java | 0 .../src/main/java/helloworld/AppStream.java | 0 .../serverless/src/main/resources/log4j2.xml | 0 .../src/test/java/helloworld/AppTest.java | 0 .../kotlin/{ => gradle}/README.md | 6 +++--- .../kotlin/{ => gradle}/build.gradle.kts | 0 .../kotlin/{ => gradle}/events/event.json | 0 .../kotlin/gradle/{ => gradle}/wrapper/.gitignore | 0 .../gradle/{ => gradle}/wrapper/gradle-wrapper.jar | Bin .../{ => gradle}/wrapper/gradle-wrapper.properties | 0 .../kotlin/{ => gradle}/gradlew | 0 .../kotlin/{ => gradle}/gradlew.bat | 0 .../{ => gradle}/src/main/kotlin/helloworld/App.kt | 0 .../src/main/kotlin/helloworld/AppStream.kt | 0 .../src/test/kotlin/helloworld/AppTest.kt | 0 .../kotlin/{ => gradle}/template.yaml | 0 52 files changed, 15 insertions(+), 15 deletions(-) rename examples/powertools-examples-core/{ => java}/cdk/README.md (81%) rename examples/powertools-examples-core/{ => java}/cdk/app/events/event.json (100%) rename examples/powertools-examples-core/{ => java}/cdk/app/pom.xml (100%) rename examples/powertools-examples-core/{ => java}/cdk/app/src/main/java/helloworld/App.java (100%) rename examples/powertools-examples-core/{ => java}/cdk/app/src/main/java/helloworld/AppStream.java (100%) rename examples/powertools-examples-core/{ => java}/cdk/app/src/main/resources/log4j2.xml (100%) rename examples/powertools-examples-core/{ => java}/cdk/app/src/test/java/helloworld/AppTest.java (100%) rename examples/powertools-examples-core/{ => java}/cdk/infra/cdk.json (100%) rename examples/powertools-examples-core/{ => java}/cdk/infra/pom.xml (100%) rename examples/powertools-examples-core/{ => java}/cdk/infra/src/main/java/cdk/CdkApp.java (100%) rename examples/powertools-examples-core/{ => java}/cdk/infra/src/main/java/cdk/CdkStack.java (100%) rename examples/powertools-examples-core/{ => java}/cdk/infra/src/test/java/cdk/CdkStackTest.java (100%) rename examples/powertools-examples-core/{ => java}/gradle/README.md (89%) rename examples/powertools-examples-core/{ => java}/gradle/build.gradle (100%) rename examples/powertools-examples-core/{ => java}/gradle/events/event.json (100%) rename examples/powertools-examples-core/{ => java}/gradle/gradle/wrapper/.gitignore (100%) rename examples/powertools-examples-core/{ => java}/gradle/gradle/wrapper/gradle-wrapper.jar (100%) rename examples/powertools-examples-core/{ => java}/gradle/gradle/wrapper/gradle-wrapper.properties (100%) rename examples/powertools-examples-core/{ => java}/gradle/gradlew (100%) rename examples/powertools-examples-core/{ => java}/gradle/gradlew.bat (100%) rename examples/powertools-examples-core/{ => java}/gradle/src/main/java/helloworld/App.java (100%) rename examples/powertools-examples-core/{ => java}/gradle/src/main/java/helloworld/AppStream.java (100%) rename examples/powertools-examples-core/{ => java}/gradle/src/test/java/helloworld/AppTest.java (100%) rename examples/powertools-examples-core/{ => java}/gradle/template.yaml (100%) rename examples/powertools-examples-core/{ => java}/sam/README.md (87%) rename examples/powertools-examples-core/{ => java}/sam/events/event.json (100%) rename examples/powertools-examples-core/{ => java}/sam/pom.xml (100%) rename examples/powertools-examples-core/{ => java}/sam/src/main/java/helloworld/App.java (100%) rename examples/powertools-examples-core/{ => java}/sam/src/main/java/helloworld/AppStream.java (100%) rename examples/powertools-examples-core/{ => java}/sam/src/main/resources/log4j2.xml (100%) rename examples/powertools-examples-core/{ => java}/sam/src/test/java/helloworld/AppTest.java (100%) rename examples/powertools-examples-core/{ => java}/sam/template.yaml (100%) rename examples/powertools-examples-core/{ => java}/serverless/README.md (86%) rename examples/powertools-examples-core/{ => java}/serverless/pom.xml (100%) rename examples/powertools-examples-core/{ => java}/serverless/serverless.yml (100%) rename examples/powertools-examples-core/{ => java}/serverless/src/main/java/helloworld/App.java (100%) rename examples/powertools-examples-core/{ => java}/serverless/src/main/java/helloworld/AppStream.java (100%) rename examples/powertools-examples-core/{ => java}/serverless/src/main/resources/log4j2.xml (100%) rename examples/powertools-examples-core/{ => java}/serverless/src/test/java/helloworld/AppTest.java (100%) rename examples/powertools-examples-core/kotlin/{ => gradle}/README.md (89%) rename examples/powertools-examples-core/kotlin/{ => gradle}/build.gradle.kts (100%) rename examples/powertools-examples-core/kotlin/{ => gradle}/events/event.json (100%) rename examples/powertools-examples-core/kotlin/gradle/{ => gradle}/wrapper/.gitignore (100%) rename examples/powertools-examples-core/kotlin/gradle/{ => gradle}/wrapper/gradle-wrapper.jar (100%) rename examples/powertools-examples-core/kotlin/gradle/{ => gradle}/wrapper/gradle-wrapper.properties (100%) rename examples/powertools-examples-core/kotlin/{ => gradle}/gradlew (100%) rename examples/powertools-examples-core/kotlin/{ => gradle}/gradlew.bat (100%) rename examples/powertools-examples-core/kotlin/{ => gradle}/src/main/kotlin/helloworld/App.kt (100%) rename examples/powertools-examples-core/kotlin/{ => gradle}/src/main/kotlin/helloworld/AppStream.kt (100%) rename examples/powertools-examples-core/kotlin/{ => gradle}/src/test/kotlin/helloworld/AppTest.kt (100%) rename examples/powertools-examples-core/kotlin/{ => gradle}/template.yaml (100%) diff --git a/examples/README.md b/examples/README.md index 52dc0c1e9..73dc7a1bf 100644 --- a/examples/README.md +++ b/examples/README.md @@ -7,7 +7,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) + * [CDK](powertools-examples-core/java/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 diff --git a/examples/powertools-examples-core/cdk/README.md b/examples/powertools-examples-core/java/cdk/README.md similarity index 81% rename from examples/powertools-examples-core/cdk/README.md rename to examples/powertools-examples-core/java/cdk/README.md index f15a24168..f53936b40 100644 --- a/examples/powertools-examples-core/cdk/README.md +++ b/examples/powertools-examples-core/java/cdk/README.md @@ -2,13 +2,13 @@ This project demonstrates the Lambda for Powertools Java module deployed using [Cloud Development Kit](https://aws.amazon.com/cdk/). -For general information on the deployed example itself, you can refer to the parent [README](../README.md) +For general information on the deployed example itself, you can refer to the parent [README](../../README.md) ## Configuration CDK uses the following project structure: -- [app](./app) - stores the source code of your application, which is similar between all examples -- [infra](./infra) - stores the definition of your infrastructure - - [cdk.json](./infra/cdk.json) - tells the CDK Toolkit how to execute your app +- [app](app) - stores the source code of your application, which is similar between all examples +- [infra](infra) - stores the definition of your infrastructure + - [cdk.json](infra/cdk.json) - tells the CDK Toolkit how to execute your app - [CdkApp](./infra/src/main/java/cdk/CdkApp.java) - bootstraps your stack, taking AWS `account` and `region` as input - [CdkStack](./infra/src/main/java/cdk/CdkStack.java) - defines the Lambda function to be deployed as well as API Gateway for it. diff --git a/examples/powertools-examples-core/cdk/app/events/event.json b/examples/powertools-examples-core/java/cdk/app/events/event.json similarity index 100% rename from examples/powertools-examples-core/cdk/app/events/event.json rename to examples/powertools-examples-core/java/cdk/app/events/event.json diff --git a/examples/powertools-examples-core/cdk/app/pom.xml b/examples/powertools-examples-core/java/cdk/app/pom.xml similarity index 100% rename from examples/powertools-examples-core/cdk/app/pom.xml rename to examples/powertools-examples-core/java/cdk/app/pom.xml diff --git a/examples/powertools-examples-core/cdk/app/src/main/java/helloworld/App.java b/examples/powertools-examples-core/java/cdk/app/src/main/java/helloworld/App.java similarity index 100% rename from examples/powertools-examples-core/cdk/app/src/main/java/helloworld/App.java rename to examples/powertools-examples-core/java/cdk/app/src/main/java/helloworld/App.java diff --git a/examples/powertools-examples-core/cdk/app/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/java/cdk/app/src/main/java/helloworld/AppStream.java similarity index 100% rename from examples/powertools-examples-core/cdk/app/src/main/java/helloworld/AppStream.java rename to examples/powertools-examples-core/java/cdk/app/src/main/java/helloworld/AppStream.java diff --git a/examples/powertools-examples-core/cdk/app/src/main/resources/log4j2.xml b/examples/powertools-examples-core/java/cdk/app/src/main/resources/log4j2.xml similarity index 100% rename from examples/powertools-examples-core/cdk/app/src/main/resources/log4j2.xml rename to examples/powertools-examples-core/java/cdk/app/src/main/resources/log4j2.xml diff --git a/examples/powertools-examples-core/cdk/app/src/test/java/helloworld/AppTest.java b/examples/powertools-examples-core/java/cdk/app/src/test/java/helloworld/AppTest.java similarity index 100% rename from examples/powertools-examples-core/cdk/app/src/test/java/helloworld/AppTest.java rename to examples/powertools-examples-core/java/cdk/app/src/test/java/helloworld/AppTest.java diff --git a/examples/powertools-examples-core/cdk/infra/cdk.json b/examples/powertools-examples-core/java/cdk/infra/cdk.json similarity index 100% rename from examples/powertools-examples-core/cdk/infra/cdk.json rename to examples/powertools-examples-core/java/cdk/infra/cdk.json diff --git a/examples/powertools-examples-core/cdk/infra/pom.xml b/examples/powertools-examples-core/java/cdk/infra/pom.xml similarity index 100% rename from examples/powertools-examples-core/cdk/infra/pom.xml rename to examples/powertools-examples-core/java/cdk/infra/pom.xml diff --git a/examples/powertools-examples-core/cdk/infra/src/main/java/cdk/CdkApp.java b/examples/powertools-examples-core/java/cdk/infra/src/main/java/cdk/CdkApp.java similarity index 100% rename from examples/powertools-examples-core/cdk/infra/src/main/java/cdk/CdkApp.java rename to examples/powertools-examples-core/java/cdk/infra/src/main/java/cdk/CdkApp.java diff --git a/examples/powertools-examples-core/cdk/infra/src/main/java/cdk/CdkStack.java b/examples/powertools-examples-core/java/cdk/infra/src/main/java/cdk/CdkStack.java similarity index 100% rename from examples/powertools-examples-core/cdk/infra/src/main/java/cdk/CdkStack.java rename to examples/powertools-examples-core/java/cdk/infra/src/main/java/cdk/CdkStack.java diff --git a/examples/powertools-examples-core/cdk/infra/src/test/java/cdk/CdkStackTest.java b/examples/powertools-examples-core/java/cdk/infra/src/test/java/cdk/CdkStackTest.java similarity index 100% rename from examples/powertools-examples-core/cdk/infra/src/test/java/cdk/CdkStackTest.java rename to examples/powertools-examples-core/java/cdk/infra/src/test/java/cdk/CdkStackTest.java diff --git a/examples/powertools-examples-core/gradle/README.md b/examples/powertools-examples-core/java/gradle/README.md similarity index 89% rename from examples/powertools-examples-core/gradle/README.md rename to examples/powertools-examples-core/java/gradle/README.md index c7c798d5d..a13e8fd3d 100644 --- a/examples/powertools-examples-core/gradle/README.md +++ b/examples/powertools-examples-core/java/gradle/README.md @@ -2,13 +2,13 @@ This project demonstrates the Lambda for Powertools Java module deployed using [Serverless Application Model](https://aws.amazon.com/serverless/sam/) with [Gradle](https://gradle.org/) running the build. This example is configured for Java 1.8 only; in order to use a newer version, check out the Gradle -configuration guide [in the main project README](../../../README.md). +configuration guide [in the main project README](../../../../README.md). You can also use `sam init` to create a new Gradle-powered Powertools application - choose to use the **AWS Quick Start Templates**, and then **Hello World Example with Powertools for AWS Lambda**, **Java 17** runtime, and finally **gradle**. -For general information on the deployed example itself, you can refer to the parent [README](../README.md) +For general information on the deployed example itself, you can refer to the parent [README](../../README.md) ## Configuration SAM uses [template.yaml](template.yaml) to define the application's AWS resources. @@ -24,7 +24,7 @@ To get started, you can use the Gradle wrapper to bootstrap Gradle and run the b ``` Once this is done to deploy the example, check out the instructions for getting started with SAM in -[the examples directory](../../README.md) +[the examples directory](../../../README.md) ## Additional notes diff --git a/examples/powertools-examples-core/gradle/build.gradle b/examples/powertools-examples-core/java/gradle/build.gradle similarity index 100% rename from examples/powertools-examples-core/gradle/build.gradle rename to examples/powertools-examples-core/java/gradle/build.gradle diff --git a/examples/powertools-examples-core/gradle/events/event.json b/examples/powertools-examples-core/java/gradle/events/event.json similarity index 100% rename from examples/powertools-examples-core/gradle/events/event.json rename to examples/powertools-examples-core/java/gradle/events/event.json diff --git a/examples/powertools-examples-core/gradle/gradle/wrapper/.gitignore b/examples/powertools-examples-core/java/gradle/gradle/wrapper/.gitignore similarity index 100% rename from examples/powertools-examples-core/gradle/gradle/wrapper/.gitignore rename to examples/powertools-examples-core/java/gradle/gradle/wrapper/.gitignore diff --git a/examples/powertools-examples-core/gradle/gradle/wrapper/gradle-wrapper.jar b/examples/powertools-examples-core/java/gradle/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from examples/powertools-examples-core/gradle/gradle/wrapper/gradle-wrapper.jar rename to examples/powertools-examples-core/java/gradle/gradle/wrapper/gradle-wrapper.jar diff --git a/examples/powertools-examples-core/gradle/gradle/wrapper/gradle-wrapper.properties b/examples/powertools-examples-core/java/gradle/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from examples/powertools-examples-core/gradle/gradle/wrapper/gradle-wrapper.properties rename to examples/powertools-examples-core/java/gradle/gradle/wrapper/gradle-wrapper.properties diff --git a/examples/powertools-examples-core/gradle/gradlew b/examples/powertools-examples-core/java/gradle/gradlew similarity index 100% rename from examples/powertools-examples-core/gradle/gradlew rename to examples/powertools-examples-core/java/gradle/gradlew diff --git a/examples/powertools-examples-core/gradle/gradlew.bat b/examples/powertools-examples-core/java/gradle/gradlew.bat similarity index 100% rename from examples/powertools-examples-core/gradle/gradlew.bat rename to examples/powertools-examples-core/java/gradle/gradlew.bat diff --git a/examples/powertools-examples-core/gradle/src/main/java/helloworld/App.java b/examples/powertools-examples-core/java/gradle/src/main/java/helloworld/App.java similarity index 100% rename from examples/powertools-examples-core/gradle/src/main/java/helloworld/App.java rename to examples/powertools-examples-core/java/gradle/src/main/java/helloworld/App.java diff --git a/examples/powertools-examples-core/gradle/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/java/gradle/src/main/java/helloworld/AppStream.java similarity index 100% rename from examples/powertools-examples-core/gradle/src/main/java/helloworld/AppStream.java rename to examples/powertools-examples-core/java/gradle/src/main/java/helloworld/AppStream.java diff --git a/examples/powertools-examples-core/gradle/src/test/java/helloworld/AppTest.java b/examples/powertools-examples-core/java/gradle/src/test/java/helloworld/AppTest.java similarity index 100% rename from examples/powertools-examples-core/gradle/src/test/java/helloworld/AppTest.java rename to examples/powertools-examples-core/java/gradle/src/test/java/helloworld/AppTest.java diff --git a/examples/powertools-examples-core/gradle/template.yaml b/examples/powertools-examples-core/java/gradle/template.yaml similarity index 100% rename from examples/powertools-examples-core/gradle/template.yaml rename to examples/powertools-examples-core/java/gradle/template.yaml diff --git a/examples/powertools-examples-core/sam/README.md b/examples/powertools-examples-core/java/sam/README.md similarity index 87% rename from examples/powertools-examples-core/sam/README.md rename to examples/powertools-examples-core/java/sam/README.md index 7a4279ae3..3b8c31ebc 100644 --- a/examples/powertools-examples-core/sam/README.md +++ b/examples/powertools-examples-core/java/sam/README.md @@ -2,7 +2,7 @@ This project demonstrates the Lambda for Powertools Java module deployed using [Serverless Application Model](https://aws.amazon.com/serverless/sam/). -For general information on the deployed example itself, you can refer to the parent [README](../README.md) +For general information on the deployed example itself, you can refer to the parent [README](../../README.md) ## Configuration SAM uses [template.yaml](template.yaml) to define the application's AWS resources. @@ -10,7 +10,7 @@ This file defines the Lambda function to be deployed as well as API Gateway for ## Deploy the sample application To deploy the example, check out the instructions for getting -started with SAM in [the examples directory](../../README.md) +started with SAM in [the examples directory](../../../README.md) ## Additional notes diff --git a/examples/powertools-examples-core/sam/events/event.json b/examples/powertools-examples-core/java/sam/events/event.json similarity index 100% rename from examples/powertools-examples-core/sam/events/event.json rename to examples/powertools-examples-core/java/sam/events/event.json diff --git a/examples/powertools-examples-core/sam/pom.xml b/examples/powertools-examples-core/java/sam/pom.xml similarity index 100% rename from examples/powertools-examples-core/sam/pom.xml rename to examples/powertools-examples-core/java/sam/pom.xml diff --git a/examples/powertools-examples-core/sam/src/main/java/helloworld/App.java b/examples/powertools-examples-core/java/sam/src/main/java/helloworld/App.java similarity index 100% rename from examples/powertools-examples-core/sam/src/main/java/helloworld/App.java rename to examples/powertools-examples-core/java/sam/src/main/java/helloworld/App.java diff --git a/examples/powertools-examples-core/sam/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/java/sam/src/main/java/helloworld/AppStream.java similarity index 100% rename from examples/powertools-examples-core/sam/src/main/java/helloworld/AppStream.java rename to examples/powertools-examples-core/java/sam/src/main/java/helloworld/AppStream.java diff --git a/examples/powertools-examples-core/sam/src/main/resources/log4j2.xml b/examples/powertools-examples-core/java/sam/src/main/resources/log4j2.xml similarity index 100% rename from examples/powertools-examples-core/sam/src/main/resources/log4j2.xml rename to examples/powertools-examples-core/java/sam/src/main/resources/log4j2.xml diff --git a/examples/powertools-examples-core/sam/src/test/java/helloworld/AppTest.java b/examples/powertools-examples-core/java/sam/src/test/java/helloworld/AppTest.java similarity index 100% rename from examples/powertools-examples-core/sam/src/test/java/helloworld/AppTest.java rename to examples/powertools-examples-core/java/sam/src/test/java/helloworld/AppTest.java diff --git a/examples/powertools-examples-core/sam/template.yaml b/examples/powertools-examples-core/java/sam/template.yaml similarity index 100% rename from examples/powertools-examples-core/sam/template.yaml rename to examples/powertools-examples-core/java/sam/template.yaml diff --git a/examples/powertools-examples-core/serverless/README.md b/examples/powertools-examples-core/java/serverless/README.md similarity index 86% rename from examples/powertools-examples-core/serverless/README.md rename to examples/powertools-examples-core/java/serverless/README.md index aec093182..d97e7465a 100644 --- a/examples/powertools-examples-core/serverless/README.md +++ b/examples/powertools-examples-core/java/serverless/README.md @@ -1,11 +1,11 @@ # 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). +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. +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. diff --git a/examples/powertools-examples-core/serverless/pom.xml b/examples/powertools-examples-core/java/serverless/pom.xml similarity index 100% rename from examples/powertools-examples-core/serverless/pom.xml rename to examples/powertools-examples-core/java/serverless/pom.xml diff --git a/examples/powertools-examples-core/serverless/serverless.yml b/examples/powertools-examples-core/java/serverless/serverless.yml similarity index 100% rename from examples/powertools-examples-core/serverless/serverless.yml rename to examples/powertools-examples-core/java/serverless/serverless.yml diff --git a/examples/powertools-examples-core/serverless/src/main/java/helloworld/App.java b/examples/powertools-examples-core/java/serverless/src/main/java/helloworld/App.java similarity index 100% rename from examples/powertools-examples-core/serverless/src/main/java/helloworld/App.java rename to examples/powertools-examples-core/java/serverless/src/main/java/helloworld/App.java diff --git a/examples/powertools-examples-core/serverless/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/java/serverless/src/main/java/helloworld/AppStream.java similarity index 100% rename from examples/powertools-examples-core/serverless/src/main/java/helloworld/AppStream.java rename to examples/powertools-examples-core/java/serverless/src/main/java/helloworld/AppStream.java diff --git a/examples/powertools-examples-core/serverless/src/main/resources/log4j2.xml b/examples/powertools-examples-core/java/serverless/src/main/resources/log4j2.xml similarity index 100% rename from examples/powertools-examples-core/serverless/src/main/resources/log4j2.xml rename to examples/powertools-examples-core/java/serverless/src/main/resources/log4j2.xml diff --git a/examples/powertools-examples-core/serverless/src/test/java/helloworld/AppTest.java b/examples/powertools-examples-core/java/serverless/src/test/java/helloworld/AppTest.java similarity index 100% rename from examples/powertools-examples-core/serverless/src/test/java/helloworld/AppTest.java rename to examples/powertools-examples-core/java/serverless/src/test/java/helloworld/AppTest.java diff --git a/examples/powertools-examples-core/kotlin/README.md b/examples/powertools-examples-core/kotlin/gradle/README.md similarity index 89% rename from examples/powertools-examples-core/kotlin/README.md rename to examples/powertools-examples-core/kotlin/gradle/README.md index ac1138f4d..14059f178 100644 --- a/examples/powertools-examples-core/kotlin/README.md +++ b/examples/powertools-examples-core/kotlin/gradle/README.md @@ -2,12 +2,12 @@ This project demonstrates the Lambda for Powertools Kotlin module deployed using [Serverless Application Model](https://aws.amazon.com/serverless/sam/) with [Gradle](https://gradle.org/) running the build. This example is configured for Java 1.8 only; in order to use a newer version, check out the Gradle -configuration guide [in the main project README](../../../README.md). +configuration guide [in the main project README](../../../../README.md). You can also use `sam init` to create a new Gradle-powered Powertools application - choose to use the **AWS Quick Start Templates**, and then **Hello World Example with Powertools for AWS Lambda**, **Java 17** runtime, and finally **gradle**. -For general information on the deployed example itself, you can refer to the parent [README](../README.md) +For general information on the deployed example itself, you can refer to the parent [README](../../README.md) ## Configuration SAM uses [template.yaml](template.yaml) to define the application's AWS resources. @@ -23,7 +23,7 @@ sam build && sam deploy --guided ``` Once this is done to deploy the example, check out the instructions for getting started with SAM in -[the examples directory](../../README.md) +[the examples directory](../../../README.md) ## Additional notes diff --git a/examples/powertools-examples-core/kotlin/build.gradle.kts b/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts similarity index 100% rename from examples/powertools-examples-core/kotlin/build.gradle.kts rename to examples/powertools-examples-core/kotlin/gradle/build.gradle.kts diff --git a/examples/powertools-examples-core/kotlin/events/event.json b/examples/powertools-examples-core/kotlin/gradle/events/event.json similarity index 100% rename from examples/powertools-examples-core/kotlin/events/event.json rename to examples/powertools-examples-core/kotlin/gradle/events/event.json diff --git a/examples/powertools-examples-core/kotlin/gradle/wrapper/.gitignore b/examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/.gitignore similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/wrapper/.gitignore rename to examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/.gitignore diff --git a/examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.jar b/examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.jar rename to examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/gradle-wrapper.jar diff --git a/examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.properties b/examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.properties rename to examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/gradle-wrapper.properties diff --git a/examples/powertools-examples-core/kotlin/gradlew b/examples/powertools-examples-core/kotlin/gradle/gradlew similarity index 100% rename from examples/powertools-examples-core/kotlin/gradlew rename to examples/powertools-examples-core/kotlin/gradle/gradlew diff --git a/examples/powertools-examples-core/kotlin/gradlew.bat b/examples/powertools-examples-core/kotlin/gradle/gradlew.bat similarity index 100% rename from examples/powertools-examples-core/kotlin/gradlew.bat rename to examples/powertools-examples-core/kotlin/gradle/gradlew.bat diff --git a/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt b/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt similarity index 100% rename from examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt rename to examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt diff --git a/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/AppStream.kt b/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/AppStream.kt similarity index 100% rename from examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/AppStream.kt rename to examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/AppStream.kt diff --git a/examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt b/examples/powertools-examples-core/kotlin/gradle/src/test/kotlin/helloworld/AppTest.kt similarity index 100% rename from examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt rename to examples/powertools-examples-core/kotlin/gradle/src/test/kotlin/helloworld/AppTest.kt diff --git a/examples/powertools-examples-core/kotlin/template.yaml b/examples/powertools-examples-core/kotlin/gradle/template.yaml similarity index 100% rename from examples/powertools-examples-core/kotlin/template.yaml rename to examples/powertools-examples-core/kotlin/gradle/template.yaml From 18c7f48c0484aca9387c383013d3019a7dcdf30a Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Wed, 4 Oct 2023 15:30:50 +0100 Subject: [PATCH 09/40] Updating core examples readme to represent new structure for Java and Kotlin examples. --- examples/powertools-examples-core/README.md | 41 +++++++++------------ 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/examples/powertools-examples-core/README.md b/examples/powertools-examples-core/README.md index f2af999b9..787b691ab 100644 --- a/examples/powertools-examples-core/README.md +++ b/examples/powertools-examples-core/README.md @@ -1,35 +1,29 @@ -# Powertools for AWS Lambda (Java) - Core Utilities Example +# Powertools for AWS Lambda - Core Utilities Example -This project demonstrates the Lambda for Powertools Java module - including +This project demonstrates the Lambda for Powertools Java module - including [logging](https://docs.powertools.aws.dev/lambda/java/core/logging/), [tracing](https://docs.powertools.aws.dev/lambda/java/core/tracing/), and [metrics](https://docs.powertools.aws.dev/lambda/java/core/metrics/). -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: - -* [AWS SAM with a Gradle build](gradle/) - ## Java -For each of the tools, the example application is the same, and consists of the following files: +* [CDK](java/cdk/) +* [Gradle](java/gradle/) +* [SAM](java/sam/) +* [Serverless](java/serverless/) -- [App.java](sam/src/main/java/helloworld/App.java) - Code for the application's Lambda function. -- [AppTests.java](sam/src/test/java/helloworld/AppTest.java) - Unit tests for the application code. -- [events](sam/events/event.json) - Invocation events that you can use to invoke the function. +For each of the tools, the example application is the same, and consists of the following files: +- App.java - Code for the application's Lambda function. +- AppTests.java - Unit tests for the application code. +- events - Invocation events that you can use to invoke the function. Configuration files and deployment process for each tool are described in corresponding README files. ## Kotlin -For each of the tools, the example application is the same, and consists of the following files: +* [Gradle](java/gradle/) -- [App.kt](kotlin/src/main/kotlin/helloworld/App.kt) - Code for the application's Lambda function. -- [AppTests.kt](kotlin/src/test/kotlin/helloworld/AppTest.kt) - Unit tests for the application code. -- [events](kotlin/events/event.json) - Invocation events that you can use to invoke the function. +- App.kt - Code for the application's Lambda function. +- AppTests.kt - Unit tests for the application code. +- events - Invocation events that you can use to invoke the function. Configuration files and deployment process for each tool are described in corresponding README files. @@ -41,14 +35,13 @@ Once the app is deployed, you can invoke the endpoint like this: curl https://[REST-API-ID].execute-api.[REGION].amazonaws.com/Prod/hello/ ``` -The response itself isn't particularly interesting - you will get back some information about your IP address. If +The response itself isn't particularly interesting - you will get back some information about your IP address. If you go to the Lambda Console and locate the lambda you have deployed, then click the "Monitoring" tab you will be able to find: * **View X-Ray traces** - Display the traces captured by the traces module. These include subsegments for the -different function calls within the example + different function calls within the example * **View Cloudwatch logs** - Display the structured logging output of the example Likewise, from the CloudWatch dashboard, under **Metrics**, **all metrics**, you will find the namespaces `Another` -and `ServerlessAirline`. The values in each of these are published by the code in -[App.java](sam/src/main/java/helloworld/App.java). +and `ServerlessAirline`. The values in each of these are published by the code in the respective application's Lambda function. From d968f3cce8d566f3e1d587dc5eb6b2bd5f58b11c Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Wed, 4 Oct 2023 16:11:12 +0100 Subject: [PATCH 10/40] Refactoring application code for efficiency, updating build to cover tests too and is more idiomatic and readme to be more descriptive --- examples/powertools-examples-core/README.md | 5 ++++- .../kotlin/gradle/build.gradle.kts | 4 ++-- .../kotlin/gradle/src/main/kotlin/helloworld/App.kt | 8 +++----- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/examples/powertools-examples-core/README.md b/examples/powertools-examples-core/README.md index 787b691ab..3fa3628b8 100644 --- a/examples/powertools-examples-core/README.md +++ b/examples/powertools-examples-core/README.md @@ -5,13 +5,15 @@ This project demonstrates the Lambda for Powertools Java module - including [tracing](https://docs.powertools.aws.dev/lambda/java/core/tracing/), and [metrics](https://docs.powertools.aws.dev/lambda/java/core/metrics/). +The example application is the same, and you can now also use Kotlin! + ## Java * [CDK](java/cdk/) * [Gradle](java/gradle/) * [SAM](java/sam/) * [Serverless](java/serverless/) -For each of the tools, the example application is the same, and consists of the following files: +Example application consists of the following files: - App.java - Code for the application's Lambda function. - AppTests.java - Unit tests for the application code. - events - Invocation events that you can use to invoke the function. @@ -21,6 +23,7 @@ Configuration files and deployment process for each tool are described in corres ## Kotlin * [Gradle](java/gradle/) +Example application consists of the following files: - App.kt - Code for the application's Lambda function. - AppTests.kt - Unit tests for the application code. - events - Invocation events that you can use to invoke the function. diff --git a/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts b/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts index b89b93526..a6e831d9a 100644 --- a/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts +++ b/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts @@ -26,6 +26,6 @@ tasks.compileKotlin { } } -java { - targetCompatibility = JavaVersion.VERSION_1_8 +kotlin { + jvmToolchain(8) } diff --git a/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt b/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt index 5b6a45ce8..796f6f999 100644 --- a/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt +++ b/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt @@ -45,7 +45,7 @@ class App : RequestHandler = HashMap() + val headers = mutableMapOf() headers["Content-Type"] = "application/json" headers["X-Custom-Header"] = "application/json" MetricsUtils.metricsLogger().putMetric("CustomMetric1", 1.0, Unit.COUNT) @@ -65,7 +65,7 @@ class App : RequestHandler + TracingUtils.withSubsegment("loggingResponse") { _: Subsegment? -> val sampled = "log something out" log.info(sampled) log.info(output) @@ -92,7 +92,5 @@ class App : RequestHandler return br.lines().collect(Collectors.joining(System.lineSeparator())) } } - companion object { - private val log = LogManager.getLogger(App::class.java) - } + private val log = LogManager.getLogger(App::class) } From 5ce71f7c475b746142b14247d0e83d9a1c7c69d0 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Wed, 4 Oct 2023 16:34:44 +0100 Subject: [PATCH 11/40] Updating to fix trailing \n --- .../kotlin/gradle/src/main/kotlin/helloworld/App.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt b/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt index 796f6f999..0cc8d1098 100644 --- a/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt +++ b/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt @@ -89,7 +89,9 @@ class App : RequestHandler return br.lines().collect(Collectors.joining(System.lineSeparator())) } + return InputStreamReader(url.openStream()).use { reader -> + reader.readText().trim() + } } private val log = LogManager.getLogger(App::class) From 35fbbaceb1acba3832d4b0ec73377bf524e22b61 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Wed, 4 Oct 2023 16:45:49 +0100 Subject: [PATCH 12/40] Updating guidance to be more specific for examples --- examples/README.md | 12 ++++++++---- .../powertools-examples-core/kotlin/gradle/README.md | 3 ++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/examples/README.md b/examples/README.md index 73dc7a1bf..7d779f8f1 100644 --- a/examples/README.md +++ b/examples/README.md @@ -5,10 +5,14 @@ Each example can be copied from its subdirectory and used independently of the r ## Examples -* [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/java/cdk) - * [Serverless](./powertools-examples-core/serverless) +* [powertools-examples-core](powertools-examples-core) - Demonstrates the core logging, tracing, and metrics modules with different build tools and languages + * [Java](./powertools-examples-core/java) + * [CDK](./powertools-examples-core/java/cdk) + * [Gradle](./powertools-examples-core/java/gradle) + * [SAM](./powertools-examples-core/java/sam) + * [Serverless](./powertools-examples-core/java/serverless) + * [Kotlin](./powertools-examples-core/kotlin) + * [Gradle](./powertools-examples-core/kotlin/gradle) * [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/powertools-examples-core/kotlin/gradle/README.md b/examples/powertools-examples-core/kotlin/gradle/README.md index 14059f178..d40397a4b 100644 --- a/examples/powertools-examples-core/kotlin/gradle/README.md +++ b/examples/powertools-examples-core/kotlin/gradle/README.md @@ -13,7 +13,8 @@ For general information on the deployed example itself, you can refer to the par SAM uses [template.yaml](template.yaml) to define the application's AWS resources. This file defines the Lambda function to be deployed as well as API Gateway for it. -The build of the project is managed by Gradle, and configured in [build.gradle](_build.gradle). +The build of the project is managed by Gradle, and configured in [build.gradle.kts](build.gradle.kts) +. ## Deploy the sample application To get started, you can use the included template with SAM to run the build and deploy to your AWS environment: From d277c5c4e8ce23a3b3f0e1bb0d317317a1817b33 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Fri, 6 Oct 2023 13:17:01 +0100 Subject: [PATCH 13/40] Adopting new mechanism for specifying jvm target. --- .../kotlin/gradle/build.gradle.kts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts b/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts index a6e831d9a..68ff9b6d4 100644 --- a/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts +++ b/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts @@ -26,6 +26,12 @@ tasks.compileKotlin { } } -kotlin { - jvmToolchain(8) +tasks.compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } } +// If using JDK 11 or higher, use the following instead: +//kotlin { +// jvmToolchain(8) +//} \ No newline at end of file From 6c4646e079d23e680bfad8b4a0eacf96a5dcadcd Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Fri, 6 Oct 2023 13:35:59 +0100 Subject: [PATCH 14/40] accommodating new project structure --- examples/README.md | 2 +- examples/pom.xml | 8 ++++---- examples/powertools-examples-core/README.md | 2 +- .../kotlin/{gradle => }/README.md | 6 +++--- .../kotlin/{gradle => }/build.gradle.kts | 1 + .../kotlin/{gradle => }/events/event.json | 0 .../kotlin/gradle/{gradle => }/wrapper/.gitignore | 0 .../gradle/{gradle => }/wrapper/gradle-wrapper.jar | Bin .../{gradle => }/wrapper/gradle-wrapper.properties | 0 .../kotlin/{gradle => }/gradlew | 0 .../kotlin/{gradle => }/gradlew.bat | 0 .../{gradle => }/src/main/kotlin/helloworld/App.kt | 0 .../src/main/kotlin/helloworld/AppStream.kt | 0 .../src/test/kotlin/helloworld/AppTest.kt | 0 .../kotlin/{gradle => }/template.yaml | 0 15 files changed, 10 insertions(+), 9 deletions(-) rename examples/powertools-examples-core/kotlin/{gradle => }/README.md (89%) rename examples/powertools-examples-core/kotlin/{gradle => }/build.gradle.kts (99%) rename examples/powertools-examples-core/kotlin/{gradle => }/events/event.json (100%) rename examples/powertools-examples-core/kotlin/gradle/{gradle => }/wrapper/.gitignore (100%) rename examples/powertools-examples-core/kotlin/gradle/{gradle => }/wrapper/gradle-wrapper.jar (100%) rename examples/powertools-examples-core/kotlin/gradle/{gradle => }/wrapper/gradle-wrapper.properties (100%) rename examples/powertools-examples-core/kotlin/{gradle => }/gradlew (100%) rename examples/powertools-examples-core/kotlin/{gradle => }/gradlew.bat (100%) rename examples/powertools-examples-core/kotlin/{gradle => }/src/main/kotlin/helloworld/App.kt (100%) rename examples/powertools-examples-core/kotlin/{gradle => }/src/main/kotlin/helloworld/AppStream.kt (100%) rename examples/powertools-examples-core/kotlin/{gradle => }/src/test/kotlin/helloworld/AppTest.kt (100%) rename examples/powertools-examples-core/kotlin/{gradle => }/template.yaml (100%) diff --git a/examples/README.md b/examples/README.md index 7d779f8f1..cd5c32fa4 100644 --- a/examples/README.md +++ b/examples/README.md @@ -12,7 +12,7 @@ Each example can be copied from its subdirectory and used independently of the r * [SAM](./powertools-examples-core/java/sam) * [Serverless](./powertools-examples-core/java/serverless) * [Kotlin](./powertools-examples-core/kotlin) - * [Gradle](./powertools-examples-core/kotlin/gradle) + * [Gradle](powertools-examples-core/kotlin/gradle1) * [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 810ec1b36..ba7b5ff65 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -29,10 +29,10 @@ - powertools-examples-core/sam - powertools-examples-core/cdk/app - powertools-examples-core/cdk/infra - powertools-examples-core/serverless + powertools-examples-core/java/sam + powertools-examples-core/java/cdk/app + powertools-examples-core/java/cdk/infra + powertools-examples-core/java/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 3fa3628b8..0c9a44a36 100644 --- a/examples/powertools-examples-core/README.md +++ b/examples/powertools-examples-core/README.md @@ -21,7 +21,7 @@ Example application consists of the following files: Configuration files and deployment process for each tool are described in corresponding README files. ## Kotlin -* [Gradle](java/gradle/) +* [Gradle](kotlin/) Example application consists of the following files: - App.kt - Code for the application's Lambda function. diff --git a/examples/powertools-examples-core/kotlin/gradle/README.md b/examples/powertools-examples-core/kotlin/README.md similarity index 89% rename from examples/powertools-examples-core/kotlin/gradle/README.md rename to examples/powertools-examples-core/kotlin/README.md index d40397a4b..da9ec5b52 100644 --- a/examples/powertools-examples-core/kotlin/gradle/README.md +++ b/examples/powertools-examples-core/kotlin/README.md @@ -2,12 +2,12 @@ This project demonstrates the Lambda for Powertools Kotlin module deployed using [Serverless Application Model](https://aws.amazon.com/serverless/sam/) with [Gradle](https://gradle.org/) running the build. This example is configured for Java 1.8 only; in order to use a newer version, check out the Gradle -configuration guide [in the main project README](../../../../README.md). +configuration guide [in the main project README](../../../README.md). You can also use `sam init` to create a new Gradle-powered Powertools application - choose to use the **AWS Quick Start Templates**, and then **Hello World Example with Powertools for AWS Lambda**, **Java 17** runtime, and finally **gradle**. -For general information on the deployed example itself, you can refer to the parent [README](../../README.md) +For general information on the deployed example itself, you can refer to the parent [README](../README.md) ## Configuration SAM uses [template.yaml](template.yaml) to define the application's AWS resources. @@ -24,7 +24,7 @@ sam build && sam deploy --guided ``` Once this is done to deploy the example, check out the instructions for getting started with SAM in -[the examples directory](../../../README.md) +[the examples directory](../../README.md) ## Additional notes diff --git a/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts b/examples/powertools-examples-core/kotlin/build.gradle.kts similarity index 99% rename from examples/powertools-examples-core/kotlin/gradle/build.gradle.kts rename to examples/powertools-examples-core/kotlin/build.gradle.kts index 68ff9b6d4..2a11034b6 100644 --- a/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts +++ b/examples/powertools-examples-core/kotlin/build.gradle.kts @@ -31,6 +31,7 @@ tasks.compileTestKotlin { jvmTarget = "1.8" } } + // If using JDK 11 or higher, use the following instead: //kotlin { // jvmToolchain(8) diff --git a/examples/powertools-examples-core/kotlin/gradle/events/event.json b/examples/powertools-examples-core/kotlin/events/event.json similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/events/event.json rename to examples/powertools-examples-core/kotlin/events/event.json diff --git a/examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/.gitignore b/examples/powertools-examples-core/kotlin/gradle/wrapper/.gitignore similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/.gitignore rename to examples/powertools-examples-core/kotlin/gradle/wrapper/.gitignore diff --git a/examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/gradle-wrapper.jar b/examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/gradle-wrapper.jar rename to examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.jar diff --git a/examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/gradle-wrapper.properties b/examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/gradle-wrapper.properties rename to examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.properties diff --git a/examples/powertools-examples-core/kotlin/gradle/gradlew b/examples/powertools-examples-core/kotlin/gradlew similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/gradlew rename to examples/powertools-examples-core/kotlin/gradlew diff --git a/examples/powertools-examples-core/kotlin/gradle/gradlew.bat b/examples/powertools-examples-core/kotlin/gradlew.bat similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/gradlew.bat rename to examples/powertools-examples-core/kotlin/gradlew.bat diff --git a/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt b/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt rename to examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt diff --git a/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/AppStream.kt b/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/AppStream.kt similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/AppStream.kt rename to examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/AppStream.kt diff --git a/examples/powertools-examples-core/kotlin/gradle/src/test/kotlin/helloworld/AppTest.kt b/examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/src/test/kotlin/helloworld/AppTest.kt rename to examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt diff --git a/examples/powertools-examples-core/kotlin/gradle/template.yaml b/examples/powertools-examples-core/kotlin/template.yaml similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/template.yaml rename to examples/powertools-examples-core/kotlin/template.yaml From 6eecb90a515b4b6459897616302b000cd36020c3 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Fri, 6 Oct 2023 13:41:06 +0100 Subject: [PATCH 15/40] Fixing link typo after refactoring --- examples/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/README.md b/examples/README.md index cd5c32fa4..d593e1f06 100644 --- a/examples/README.md +++ b/examples/README.md @@ -12,7 +12,7 @@ Each example can be copied from its subdirectory and used independently of the r * [SAM](./powertools-examples-core/java/sam) * [Serverless](./powertools-examples-core/java/serverless) * [Kotlin](./powertools-examples-core/kotlin) - * [Gradle](powertools-examples-core/kotlin/gradle1) + * [Gradle](powertools-examples-core/kotlin/) * [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 From 1431899069e8839cb15406ce436017f14b8d2386 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Mon, 2 Oct 2023 13:39:41 +0100 Subject: [PATCH 16/40] Setting up Kotlin environment. Converting test to Kotlin. --- .../powertools-examples-core/kotlin/README.md | 38 +++ .../kotlin/build.gradle | 47 ++++ .../kotlin/events/event.json | 62 +++++ .../kotlin/gradle/wrapper/.gitignore | 2 + .../kotlin/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 63375 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + .../powertools-examples-core/kotlin/gradlew | 248 ++++++++++++++++++ .../kotlin/gradlew.bat | 92 +++++++ .../kotlin/src/main/java/helloworld/App.java | 107 ++++++++ .../src/main/java/helloworld/AppStream.java | 38 +++ .../src/test/kotlin/helloworld/AppTest.kt | 19 ++ .../kotlin/template.yaml | 71 +++++ 12 files changed, 731 insertions(+) create mode 100644 examples/powertools-examples-core/kotlin/README.md create mode 100644 examples/powertools-examples-core/kotlin/build.gradle create mode 100644 examples/powertools-examples-core/kotlin/events/event.json create mode 100644 examples/powertools-examples-core/kotlin/gradle/wrapper/.gitignore create mode 100644 examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.jar create mode 100644 examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.properties create mode 100755 examples/powertools-examples-core/kotlin/gradlew create mode 100644 examples/powertools-examples-core/kotlin/gradlew.bat create mode 100644 examples/powertools-examples-core/kotlin/src/main/java/helloworld/App.java create mode 100644 examples/powertools-examples-core/kotlin/src/main/java/helloworld/AppStream.java create mode 100644 examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt create mode 100644 examples/powertools-examples-core/kotlin/template.yaml diff --git a/examples/powertools-examples-core/kotlin/README.md b/examples/powertools-examples-core/kotlin/README.md new file mode 100644 index 000000000..c7c798d5d --- /dev/null +++ b/examples/powertools-examples-core/kotlin/README.md @@ -0,0 +1,38 @@ +# Powertools for AWS Lambda (Java) - Core Utilities Example with Gradle + +This project demonstrates the Lambda for Powertools Java module deployed using [Serverless Application Model](https://aws.amazon.com/serverless/sam/) with +[Gradle](https://gradle.org/) running the build. This example is configured for Java 1.8 only; in order to use a newer version, check out the Gradle +configuration guide [in the main project README](../../../README.md). + +You can also use `sam init` to create a new Gradle-powered Powertools application - choose to use the **AWS Quick Start Templates**, +and then **Hello World Example with Powertools for AWS Lambda**, **Java 17** runtime, and finally **gradle**. + + +For general information on the deployed example itself, you can refer to the parent [README](../README.md) + +## Configuration +SAM uses [template.yaml](template.yaml) to define the application's AWS resources. +This file defines the Lambda function to be deployed as well as API Gateway for it. + +The build of the project is managed by Gradle, and configured in [build.gradle](build.gradle). + +## Deploy the sample application +To get started, you can use the Gradle wrapper to bootstrap Gradle and run the build: + +```bash +./gradlew build +``` + +Once this is done to deploy the example, check out the instructions for getting started with SAM in +[the examples directory](../../README.md) + +## Additional notes + +You can watch the trace information or log information using the SAM CLI: +```bash +# Tail the logs +sam logs --tail $MY_STACK + +# Tail the traces +sam traces --tail +``` \ No newline at end of file diff --git a/examples/powertools-examples-core/kotlin/build.gradle b/examples/powertools-examples-core/kotlin/build.gradle new file mode 100644 index 000000000..885de6f43 --- /dev/null +++ b/examples/powertools-examples-core/kotlin/build.gradle @@ -0,0 +1,47 @@ + +plugins { + id 'java' + id "io.freefair.aspectj.post-compile-weaving" version "6.6.3" + id 'org.jetbrains.kotlin.jvm' version '1.9.10' +} + +wrapper { + gradleVersion = "7.6.1" +} + +compileJava { + sourceCompatibility = "1.8" + targetCompatibility = "1.8" + + ajc { + enabled = true + } +} + +repositories { + mavenCentral() +} + +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' + aspect 'software.amazon.lambda:powertools-tracing:1.17.0' + aspect 'software.amazon.lambda:powertools-logging:1.17.0' + aspect 'software.amazon.lambda:powertools-metrics:1.17.0' + testImplementation 'junit:junit:4.13.2' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" +} +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} + diff --git a/examples/powertools-examples-core/kotlin/events/event.json b/examples/powertools-examples-core/kotlin/events/event.json new file mode 100644 index 000000000..070ad8e01 --- /dev/null +++ b/examples/powertools-examples-core/kotlin/events/event.json @@ -0,0 +1,62 @@ +{ + "body": "{\"message\": \"hello world\"}", + "resource": "/{proxy+}", + "path": "/path/to/resource", + "httpMethod": "POST", + "isBase64Encoded": false, + "queryStringParameters": { + "foo": "bar" + }, + "pathParameters": { + "proxy": "/path/to/resource" + }, + "stageVariables": { + "baz": "qux" + }, + "headers": { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", + "Accept-Encoding": "gzip, deflate, sdch", + "Accept-Language": "en-US,en;q=0.8", + "Cache-Control": "max-age=0", + "CloudFront-Forwarded-Proto": "https", + "CloudFront-Is-Desktop-Viewer": "true", + "CloudFront-Is-Mobile-Viewer": "false", + "CloudFront-Is-SmartTV-Viewer": "false", + "CloudFront-Is-Tablet-Viewer": "false", + "CloudFront-Viewer-Country": "US", + "Host": "1234567890.execute-api.us-east-1.amazonaws.com", + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Custom User Agent String", + "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==", + "X-Forwarded-For": "127.0.0.1, 127.0.0.2", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https" + }, + "requestContext": { + "accountId": "123456789012", + "resourceId": "123456", + "stage": "prod", + "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", + "requestTime": "09/Apr/2015:12:34:56 +0000", + "requestTimeEpoch": 1428582896000, + "identity": { + "cognitoIdentityPoolId": null, + "accountId": null, + "cognitoIdentityId": null, + "caller": null, + "accessKey": null, + "sourceIp": "127.0.0.1", + "cognitoAuthenticationType": null, + "cognitoAuthenticationProvider": null, + "userArn": null, + "userAgent": "Custom User Agent String", + "user": null + }, + "path": "/prod/path/to/resource", + "resourcePath": "/{proxy+}", + "httpMethod": "POST", + "apiId": "1234567890", + "protocol": "HTTP/1.1" + } +} diff --git a/examples/powertools-examples-core/kotlin/gradle/wrapper/.gitignore b/examples/powertools-examples-core/kotlin/gradle/wrapper/.gitignore new file mode 100644 index 000000000..59c09e205 --- /dev/null +++ b/examples/powertools-examples-core/kotlin/gradle/wrapper/.gitignore @@ -0,0 +1,2 @@ +!gradle-wrapper.jar + diff --git a/examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.jar b/examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..033e24c4cdf41af1ab109bc7f253b2b887023340 GIT binary patch literal 63375 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≫L+crb^Bz zc+Nw%zgpZ6>!A3%lau!Pw6`Y#WPVBtAfKSsqwYDWQK-~ zz(mx=nJ6-8t`YXB{6gaZ%G}Dmn&o500Y}2Rd?e&@=hBEmB1C=$OMBfxX__2c2O4K2#(0ksclP$SHp*8jq-1&(<6(#=6&H`Nlc2RVC4->r6U}sTY<1? zn@tv7XwUs-c>Lcmrm5AE0jHI5={WgHIow6cX=UK)>602(=arbuAPZ37;{HTJSIO%9EL`Et5%J7$u_NaC(55x zH^qX^H}*RPDx)^c46x>js=%&?y?=iFs^#_rUl@*MgLD92E5y4B7#EDe9yyn*f-|pQ zi>(!bIg6zY5fLSn@;$*sN|D2A{}we*7+2(4&EhUV%Qqo5=uuN^xt_hll7=`*mJq6s zCWUB|s$)AuS&=)T&_$w>QXHqCWB&ndQ$y4-9fezybZb0bYD^zeuZ>WZF{rc>c4s`` zgKdppTB|o>L1I1hAbnW%H%EkFt%yWC|0~+o7mIyFCTyb?@*Ho)eu(x`PuO8pLikN> z6YeI`V?AUWD(~3=8>}a6nZTu~#QCK(H0+4!ql3yS`>JX;j4+YkeG$ZTm33~PLa3L} zksw7@%e-mBM*cGfz$tS4LC^SYVdBLsR}nAprwg8h2~+Cv*W0%izK+WPVK}^SsL5R_ zpA}~G?VNhJhqx2he2;2$>7>DUB$wN9_-adL@TqVLe=*F8Vsw-yho@#mTD6*2WAr6B zjtLUh`E(;#p0-&$FVw(r$hn+5^Z~9J0}k;j$jL1;?2GN9s?}LASm?*Rvo@?E+(}F& z+=&M-n`5EIz%%F^e)nnWjkQUdG|W^~O|YeY4Fz}>qH2juEere}vN$oJN~9_Th^&b{ z%IBbET*E8%C@jLTxV~h#mxoRrJCF{!CJOghjuKOyl_!Jr?@4Upo7u>fTGtfm|CH2v z&9F+>;6aFbYXLj3{yZ~Yn1J2%!)A3~j2$`jOy{XavW@t)g}}KUVjCWG0OUc7aBc=2 zR3^u=dT47=5SmT{K1aGaVZkOx|24T-J0O$b9dfB25J|7yb6frwS6wZ1^y%EWOm}S< zc1SdYhfsdLG*FB-;!QLV3D!d~hnXTGVQVck9x%=B(Kk8c3y%f0nR95_TbY;l=obSl zEE@fp0|8Q$b3(+DXh?d0FEloGhO0#11CLQT5qtEckBLe-VN-I>9ys}PVK0r;0!jIG zH_q$;a`3Xv9P_V2ekV1SMzd#SKo<1~Dq2?M{(V;AwhH_2x@mN$=|=cG0<3o^j_0OF z7|WJ-f2G=7sA4NVGU2X5`o*D2T7(MbmZ2(oipooE{R?9!{WxX!%ofhsrPAxoIk!Kr z>I$a{Zq=%KaLrDCIL^gmA3z{2z%Wkr)b$QHcNUA^QwydWMJmxymO0QS22?mo%4(Md zgME(zE}ub--3*wGjV`3eBMCQG-@Gel1NKZDGuqobN|mAt0{@ZC9goI|BSmGBTUZ(`Xt z^e2LiMg?6E?G*yw(~K8lO(c4)RY7UWxrXzW^iCg-P41dUiE(i+gDmmAoB?XOB}+Ln z_}rApiR$sqNaT4frw69Wh4W?v(27IlK$Toy<1o)GeF+sGzYVeJ`F)3`&2WDi^_v67 zg;@ehwl3=t+}(DJtOYO!s`jHyo-}t@X|U*9^sIfaZfh;YLqEFmZ^E;$_XK}%eq;>0 zl?+}*kh)5jGA}3daJ*v1knbW0GusR1+_xD`MFPZc3qqYMXd>6*5?%O5pC7UVs!E-` zuMHc6igdeFQ`plm+3HhP)+3I&?5bt|V8;#1epCsKnz0%7m9AyBmz06r90n~9o;K30 z=fo|*`Qq%dG#23bVV9Jar*zRcV~6fat9_w;x-quAwv@BkX0{9e@y0NB(>l3#>82H6 z^US2<`=M@6zX=Pz>kb8Yt4wmeEo%TZ=?h+KP2e3U9?^Nm+OTx5+mVGDvgFee%}~~M zK+uHmj44TVs}!A}0W-A92LWE%2=wIma(>jYx;eVB*%a>^WqC7IVN9{o?iw{e4c=CG zC#i=cRJZ#v3 zF^9V+7u?W=xCY%2dvV_0dCP%5)SH*Xm|c#rXhwEl*^{Ar{NVoK*H6f5qCSy`+|85e zjGaKqB)p7zKNKI)iWe6A9qkl=rTjs@W1Crh(3G57qdT0w2ig^{*xerzm&U>YY{+fZbkQ#;^<$JniUifmAuEd^_M(&?sTrd(a*cD! zF*;`m80MrZ^> zaF{}rDhEFLeH#`~rM`o903FLO?qw#_Wyb5}13|0agjSTVkSI6Uls)xAFZifu@N~PM zQ%o?$k)jbY0u|45WTLAirUg3Zi1E&=G#LnSa89F3t3>R?RPcmkF}EL-R!OF_r1ZN` z?x-uHH+4FEy>KrOD-$KHg3$-Xl{Cf0;UD4*@eb~G{CK-DXe3xpEEls?SCj^p z$Uix(-j|9f^{z0iUKXcZQen}*`Vhqq$T?^)Ab2i|joV;V-qw5reCqbh(8N)c%!aB< zVs+l#_)*qH_iSZ_32E~}>=wUO$G_~k0h@ch`a6Wa zsk;<)^y=)cPpHt@%~bwLBy;>TNrTf50BAHUOtt#9JRq1ro{w80^sm-~fT>a$QC;<| zZIN%&Uq>8`Js_E((_1sewXz3VlX|-n8XCfScO`eL|H&2|BPZhDn}UAf_6s}|!XpmUr90v|nCutzMjb9|&}#Y7fj_)$alC zM~~D6!dYxhQof{R;-Vp>XCh1AL@d-+)KOI&5uKupy8PryjMhTpCZnSIQ9^Aq+7=Mb zCYCRvm4;H=Q8nZWkiWdGspC_Wvggg|7N`iED~Eap)Th$~wsxc(>(KI>{i#-~Dd8iQ zzonqc9DW1w4a*}k`;rxykUk+~N)|*I?@0901R`xy zN{20p@Ls<%`1G1Bx87Vm6Z#CA`QR(x@t8Wc?tpaunyV^A*-9K9@P>hAWW9Ev)E$gb z<(t?Te6GcJX2&0% z403pe>e)>m-^qlJU^kYIH)AutgOnq!J>FoMXhA-aEx-((7|(*snUyxa+5$wx8FNxS zKuVAVWArlK#kDzEM zqR?&aXIdyvxq~wF?iYPho*(h?k zD(SBpRDZ}z$A})*Qh!9&pZZRyNixD!8)B5{SK$PkVET(yd<8kImQ3ILe%jhx8Ga-1 zE}^k+Eo^?c4Y-t2_qXiVwW6i9o2qosBDj%DRPNT*UXI0=D9q{jB*22t4HHcd$T&Xi zT=Vte*Gz2E^qg%b7ev04Z&(;=I4IUtVJkg<`N6i7tjUn-lPE(Y4HPyJKcSjFnEzCH zPO(w%LmJ_=D~}PyfA91H4gCaf-qur3_KK}}>#9A}c5w@N;-#cHph=x}^mQ3`oo`Y$ope#)H9(kQK zGyt<7eNPuSAs$S%O>2ElZ{qtDIHJ!_THqTwcc-xfv<@1>IJ;YTv@!g-zDKBKAH<

Zet1e^8c}8fE97XH}+lF{qbF<`Y%dU|I!~Y`ZrVfKX82i z)(%!Tcf~eE^%2_`{WBPGPU@1NB5SCXe1sAI<4&n1IwO{&S$ThWn37heGOSW%nW7*L zxh0WK!E7zh%6yF-7%~l@I~b`2=*$;RYbi(I#zp$gL_d39U4A)KuB( zcS0bt48&%G_I~( zL(}w&2NA6#$=|g)J+-?ehHflD^lr77ngdz=dszFI;?~ZxeJv=gsm?4$$6#V==H{fa zqO!EkT>1-OQSJoX)cN}XsB;shvrHRwTH(I2^Ah4|rizn!V7T7fLh~Z<`Q+?zEMVxh z$=-x^RR*PlhkV_8mshTvs+zmZWY&Jk{9LX0Nx|+NAEq-^+Rh|ZlinVZ=e8=`WQt;e@= zPU}^1cG*O;G7l{Y#nl znp`y%CO_SC7gk0i0gY&phM04Y)~vU0!3$V$2T+h(1ZS+cCgc zaC?3M;B48^faGo>h~--#FNFauH?0BJJ6_nG5qOlr>k~%DCSJaOfl%KWHusw>tGrTxAhlEVDxc8R2C-)LCt&$Rt9IKor=ml7jirX@?WW+M z^I{b}MD5r$s>^^sN@&g`cXD~S_u09xo;{;noKZatIuzqd zW1e7oTl9>g8opPBT(p+&fo0F#!c{NFYYpIZ6u8hOB{F#{nP)@})X20$3iJtG$cO zJ$Oxl_qH{sL5d?=D$2M4C3Ajc;GN0(B-HVT;@pJ-LvIrN%|SY?t}g!J>ufQrR%hoY z!nr$tq~N%)9}^tEip93XW=MQ1@XovSvn`PTqXeT9@_7hGv4%LK1M**Q%UKi|(v@1_ zKGe*@+1%Y4v&`;5vUL`C&{tc+_7HFs7*OtjY8@Gg`C4O&#An{0xOvgNSehTHS~_1V z=daxCMzI5b_ydM5$z zZl`a{mM}i@x;=QyaqJY&{Q^R*^1Yzq!dHH~UwCCga+Us~2wk59ArIYtSw9}tEmjbo z5!JA=`=HP*Ae~Z4Pf7sC^A3@Wfa0Ax!8@H_&?WVe*)9B2y!8#nBrP!t1fqhI9jNMd zM_5I)M5z6Ss5t*f$Eh{aH&HBeh310Q~tRl3wCEcZ>WCEq%3tnoHE)eD=)XFQ7NVG5kM zaUtbnq2LQomJSWK)>Zz1GBCIHL#2E>T8INWuN4O$fFOKe$L|msB3yTUlXES68nXRX zP6n*zB+kXqqkpQ3OaMc9GqepmV?Ny!T)R@DLd`|p5ToEvBn(~aZ%+0q&vK1)w4v0* zgW44F2ixZj0!oB~^3k|vni)wBh$F|xQN>~jNf-wFstgiAgB!=lWzM&7&&OYS=C{ce zRJw|)PDQ@3koZfm`RQ$^_hEN$GuTIwoTQIDb?W&wEo@c75$dW(ER6q)qhF`{#7UTuPH&)w`F!w z0EKs}=33m}_(cIkA2rBWvApydi0HSOgc>6tu&+hmRSB%)s`v_NujJNhKLS3r6hv~- z)Hm@?PU{zd0Tga)cJWb2_!!9p3sP%Z zAFT|jy;k>4X)E>4fh^6=SxV5w6oo`mus&nWo*gJL zZH{SR!x)V)y=Qc7WEv-xLR zhD4OcBwjW5r+}pays`o)i$rcJb2MHLGPmeOmt5XJDg@(O3PCbxdDn{6qqb09X44T zh6I|s=lM6Nr#cGaA5-eq*T=LQ6SlRq*`~`b+dVi5^>el1p;#si6}kK}>w;1 z6B1dz{q_;PY{>DBQ+v@1pfXTd5a*^H9U*;qdj@XBF}MoSSQxVXeUpEM5Z0909&8$pRfR|B(t0ox&xl8{8mUNd#(zWONW{oycv$VjP1>q;jU@ z@+8E~fjz*I54OFFaQ{A5jn1w>r;l!NRlI(8q3*%&+tM?lov_G3wB`<}bQ>1=&xUht zmti5VZzV1Cx006Yzt|%Vwid>QPX8Nfa8|sue7^un@C+!3h!?-YK>lSfNIHh|0kL8v zbv_BklQ4HOqje|@Fyxn%IvL$N&?m(KN;%`I$N|muStjSsgG;gP4Smgz$2u(mG;DXP zf~uQ z212x^l6!MW>V@ORUGSFLAAjz3i5zO$=UmD_zhIk2OXUz^LkDLWjla*PW?l;`LLos> z7FBvCr)#)XBByDm(=n%{D>BcUq>0GOV9`i-(ZSI;RH1rdrAJ--f0uuAQ4odl z_^$^U_)0BBJwl@6R#&ZtJN+@a(4~@oYF)yG+G#3=)ll8O#Zv3SjV#zSXTW3h9kqn* z@AHL=vf~KMas}6{+u=}QFumr-!c=(BFP_dwvrdehzTyqco)m@xRc=6b#Dy+KD*-Bq zK=y*1VAPJ;d(b?$2cz{CUeG(0`k9_BIuUki@iRS5lp3=1#g)A5??1@|p=LOE|FNd; z-?5MLKd-5>yQ7n__5W^3C!_`hP(o%_E3BKEmo1h=H(7;{6$XRRW6{u+=oQX<((xAJ zNRY`Egtn#B1EBGHLy^eM5y}Jy0h!GAGhb7gZJoZI-9WuSRw)GVQAAcKd4Qm)pH`^3 zq6EIM}Q zxZGx%aLnNP1an=;o8p9+U^>_Bi`e23E^X|}MB&IkS+R``plrRzTE%ncmfvEW#AHJ~ znmJ`x&ez6eT21aLnoI`%pYYj zzQ?f^ob&Il;>6Fe>HPhAtTZa*B*!;;foxS%NGYmg!#X%)RBFe-acahHs3nkV61(E= zhekiPp1d@ACtA=cntbjuv+r-Zd`+lwKFdqZuYba_ey`&H<Psu;Tzwt;-LQxvv<_D5;ik7 zwETZe`+voUhk%$s2-7Rqfl`Ti_{(fydI(DAHKr<66;rYa6p8AD+NEc@Fd@%m`tiK% z=Mebzrtp=*Q%a}2UdK4J&5#tCN5PX>W=(9rUEXZ8yjRu+7)mFpKh{6;n%!bI(qA9kfyOtstGtOl zX!@*O0fly*L4k##fsm&V0j9Lj<_vu1)i?!#xTB7@2H&)$Kzt@r(GH=xRZlIimTDd_o(%9xO388LwC#;vQ?7OvRU_s< zDS@6@g}VnvQ+tn(C#sx0`J^T4WvFxYI17;uPs-Ub{R`J-NTdtBGl+Q>e81Z3#tDUr ztnVc*p{o|RNnMYts4pdw=P!uJkF@8~h)oV4dXu5F7-j0AW|=mt!QhP&ZV!!82*c7t zuOm>B*2gFtq;A8ynZ~Ms?!gEi5<{R_8tRN%aGM!saR4LJQ|?9w>Ff_61(+|ol_vL4 z-+N>fushRbkB4(e{{SQ}>6@m}s1L!-#20N&h%srA=L50?W9skMF9NGfQ5wU*+0<@> zLww8%f+E0Rc81H3e_5^DB@Dn~TWYk}3tqhO{7GDY;K7b*WIJ-tXnYM@z4rn(LGi?z z8%$wivs)fC#FiJh?(SbH-1bgdmHw&--rn7zBWe1xAhDdv#IRB@DGy}}zS%M0(F_3_ zLb-pWsdJ@xXE;=tpRAw?yj(Gz=i$;bsh&o2XN%24b6+?_gJDBeY zws3PE2u!#Cec>aFMk#ECxDlAs;|M7@LT8)Y4(`M}N6IQ{0YtcA*8e42!n^>`0$LFU zUCq2IR2(L`f++=85M;}~*E($nE&j;p{l%xchiTau*tB9bI= zn~Ygd@<+9DrXxoGPq}@vI1Q3iEfKRleuy*)_$+hg?+GOgf1r?d@Or42|s|D>XMa;ebr1uiTNUq@heusd6%WwJqyCCv!L*qou9l!B22H$bQ z)<)IA>Yo77S;|`fqBk!_PhLJEQb0wd1Z|`pCF;hol!34iQYtqu3K=$QxLW7(HFx~v>`vVRr zyqk^B4~!3F8t8Q_D|GLRrAbbQDf??D&Jd|mgw*t1YCd)CM2$76#Cqj1bD*vADwavp zS<`n@gLU4pwCqNPsIfHKl{5}gu9t-o+O< z??!fMqMrt$s}02pdBbOScUrc1T*{*-ideR6(1q4@oC6mxg8v8Y^h^^hfx6| z|Mld6Ax1CuSlmSJmHwdOix?$8emihK#&8&}u8m!#T1+c5u!H)>QW<7&R$eih)xkov zHvvEIJHbkt+2KQ<-bMR;2SYX?8SI=_<-J!GD5@P2FJ}K z5u82YFotCJF(dUeJFRX_3u8%iIYbRS??A?;iVO?84c}4Du9&jG<#urlZ_Unrcg8dR z!5I3%9F*`qwk#joKG_Q%5_xpU7|jm4h0+l$p;g%Tr>i74#3QnMXdz|1l2MQN$yw|5 zThMw15BxjWf2{KM)XtZ+e#N)ihlkxPe=5ymT9>@Ym%_LF}o z1XhCP`3E1A{iVoHA#|O|&5=w;=j*Qf`;{mBAK3={y-YS$`!0UmtrvzHBfR*s{z<0m zW>4C=%N98hZlUhwAl1X`rR)oL0&A`gv5X79??p_==g*n4$$8o5g9V<)F^u7v0Vv^n z1sp8{W@g6eWv2;A31Rhf5j?KJhITYfXWZsl^`7z`CFtnFrHUWiD?$pwU6|PQjs|7RA0o9ARk^9$f`u3&C|#Z3iYdh<0R`l2`)6+ z6tiDj@xO;Q5PDTYSxsx6n>bj+$JK8IPJ=U5#dIOS-zwyK?+t^V`zChdW|jpZuReE_ z)e~ywgFe!0q|jzsBn&(H*N`%AKpR@qM^|@qFai0};6mG_TvXjJ`;qZ{lGDZHScZk( z>pO+%icp)SaPJUwtIPo1BvGyP8E@~w2y}=^PnFJ$iHod^JH%j1>nXl<3f!nY9K$e` zq-?XYl)K`u*cVXM=`ym{N?z=dHQNR23M8uA-(vsA$6(xn+#B-yY!CB2@`Uz({}}w+ z0sni*39>rMC!Ay|1B@;al%T&xE(wCf+`3w>N)*LxZZZYi{5sqiVWgbNd>W*X?V}C- zjQ4F7e_uCUOHbtewQkq?m$*#@ZvWbu{4i$`aeKM8tc^ zL5!GL8gX}c+qNUtUIcps1S)%Gsx*MQLlQeoZz2y2OQb(A73Jc3`LmlQf0N{RTt;wa`6h|ljX1V7UugML=W5-STDbeWTiEMjPQ$({hn_s&NDXzs6?PLySp$?L`0ilH3vCUO{JS0Dp`z;Ry$6}R@1NdY7rxccbm$+;ApSe=2q!0 z()3$vYN0S$Cs)#-OBs{_2uFf}L4h$;7^2w20=l%5r9ui&pTEgg4U!FoCqyA6r2 zC5s72l}i*9y|KTjDE5gVlYe4I2gGZD)e`Py2gq7cK4at{bT~DSbQQ4Z4sl)kqXbbr zqvXtSqMrDdT2qt-%-HMoqeFEMsv~u)-NJ%Z*ipSJUm$)EJ+we|4*-Mi900K{K|e0; z1_j{X5)a%$+vM7;3j>skgrji92K1*Ip{SfM)=ob^E374JaF!C(cZ$R_E>Wv+?Iy9M z?@`#XDy#=z%3d9&)M=F8Xq5Zif%ldIT#wrlw(D_qOKo4wD(fyDHM5(wm1%7hy6euJ z%Edg!>Egs;ZC6%ktLFtyN0VvxN?*4C=*tOEw`{KQvS7;c514!FP98Nf#d#)+Y-wsl zP3N^-Pnk*{o(3~m=3DX$b76Clu=jMf9E?c^cbUk_h;zMF&EiVz*4I(rFoaHK7#5h0 zW7CQx+xhp}Ev+jw;SQ6P$QHINCxeF8_VX=F3&BWUd(|PVViKJl@-sYiUp@xLS2NuF z8W3JgUSQ&lUp@2E(7MG`sh4X!LQFa6;lInWqx}f#Q z4xhgK1%}b(Z*rZn=W{wBOe7YQ@1l|jQ|9ELiXx+}aZ(>{c7Ltv4d>PJf7f+qjRU8i%XZZFJkj&6D^s;!>`u%OwLa*V5Js9Y$b-mc!t@{C415$K38iVu zP7!{3Ff%i_e!^LzJWhBgQo=j5k<<($$b&%%Xm_f8RFC_(97&nk83KOy@I4k?(k<(6 zthO$3yl&0x!Pz#!79bv^?^85K5e7uS$ zJ33yka2VzOGUhQXeD{;?%?NTYmN3{b0|AMtr(@bCx+c=F)&_>PXgAG}4gwi>g82n> zL3DlhdL|*^WTmn;XPo62HhH-e*XIPSTF_h{#u=NY8$BUW=5@PD{P5n~g5XDg?Fzvb_u ziK&CJqod4srfY2T?+4x@)g9%3%*(Q2%YdCA3yM{s=+QD0&IM`8k8N&-6%iIL3kon> z0>p3BUe!lrz&_ZX2FiP%MeuQY-xVV%K?=bGPOM&XM0XRd7or< zy}jn_eEzuQ>t2fM9ict#ZNxD7HUycsq76IavfoNl$G1|t*qpUSX;YgpmJrr_8yOJ2 z(AwL;Ugi{gJ29@!G-mD82Z)46T`E+s86Qw|YSPO*OoooraA!8x_jQXYq5vUw!5f_x zubF$}lHjIWxFar8)tTg8z-FEz)a=xa`xL~^)jIdezZsg4%ePL$^`VN#c!c6`NHQ9QU zkC^<0f|Ksp45+YoX!Sv>+57q}Rwk*2)f{j8`d8Ctz^S~me>RSakEvxUa^Pd~qe#fb zN7rnAQc4u$*Y9p~li!Itp#iU=*D4>dvJ{Z~}kqAOBcL8ln3YjR{Sp!O`s=5yM zWRNP#;2K#+?I&?ZSLu)^z-|*$C}=0yi7&~vZE$s``IE^PY|dj^HcWI$9ZRm>3w(u` z-1%;;MJbzHFNd^!Ob!^PLO-xhhj@XrI81Y)x4@FdsI( za`o4Gy(`T$P?PB?s>o+eIOtuirMykbuAi65Y_UN1(?jTCy@J8Px`%;bcNmPm#Fr!= z5V!YViFJ!FBfEq>nJFk0^RAV1(7w+X`HRgP;nJHJdMa!}&vvduCMoslwHTes_I76|h>;(-9lbfGnt zoZomakOt759AuTX4b$)G8TzJ&m*BV8!vMs9#=e0tWa z%)84R=3?tfh72~=Rc;fXwj+x z+25xapYK@2@;}6)@8IL+F6iuJ_B{&A-0=U=U6WMbY>~ykVFp$XkH)f**b>TE5)shN z39E2L@JPCSl!?pkvFeh@6dCv9oE}|{GbbVM!XIgByN#md&tXy@>QscU0#z!I&X4;d z&B&ZA4lbrHJ!x4lCN4KC-)u#gT^cE{Xnhu`0RXVKn|j$vz8m}v^%*cQ{(h%FW8_8a zFM{$PirSI8@#*xg2T){A+EKX(eTC66Fb})w{vg%Vw)hvV-$tttI^V5wvU?a{(G}{G z@ob7Urk1@hDN&C$N!Nio9YrkiUC{5qA`KH*7CriaB;2~2Od>2l=WytBRl#~j`EYsj}jqK2xD*3 ztEUiPZzEJC??#Tj^?f)=sRXOJ_>5aO(|V#Yqro05p6)F$j5*wYr1zz|T4qz$0K(5! zr`6Pqd+)%a9Xq3aNKrY9843)O56F%=j_Yy_;|w8l&RU1+B4;pP*O_}X8!qD?IMiyT zLXBOOPg<*BZtT4LJ7DfyghK|_*mMP7a1>zS{8>?}#_XXaLoUBAz(Wi>$Q!L;oQ&cL z6O|T6%Dxq3E35$0g5areq9$2+R(911!Z9=wRPq-pju7DnN9LAfOu3%&onnfx^Px5( zT2^sU>Y)88F5#ATiVoS$jzC-M`vY8!{8#9O#3c&{7J1lo-rcNK7rlF0Zt*AKE(WN* z*o?Tv?Sdz<1v6gfCok8MG6Pzecx9?C zrQG5j^2{V556Hj=xTiU-seOCr2ni@b<&!j>GyHbv!&uBbHjH-U5Ai-UuXx0lcz$D7%=! z&zXD#Jqzro@R=hy8bv>D_CaOdqo6)vFjZldma5D+R;-)y1NGOFYqEr?h zd_mTwQ@K2veZTxh1aaV4F;YnaWA~|<8$p}-eFHashbWW6Dzj=3L=j-C5Ta`w-=QTw zA*k9!Ua~-?eC{Jc)xa;PzkUJ#$NfGJOfbiV^1au;`_Y8|{eJ(~W9pP9q?gLl5E6|e{xkT@s|Ac;yk01+twk_3nuk|lRu{7-zOjLAGe!)j?g+@-;wC_=NPIhk(W zfEpQrdRy z^Q$YBs%>$=So>PAMkrm%yc28YPi%&%=c!<}a=)sVCM51j+x#<2wz?2l&UGHhOv-iu z64x*^E1$55$wZou`E=qjP1MYz0xErcpMiNYM4+Qnb+V4MbM;*7vM_Yp^uXUuf`}-* z_2CnbQ);j5;Rz?7q)@cGmwE^P>4_u9;K|BFlOz_|c^1n~%>!uO#nA?5o4A>XLO{X2 z=8M%*n=IdnXQ}^+`DXRKM;3juVrXdgv79;E=ovQa^?d7wuw~nbu%%lsjUugE8HJ9zvZIM^nWvjLc-HKc2 zbj{paA}ub~4N4Vw5oY{wyop9SqPbWRq=i@Tbce`r?6e`?`iOoOF;~pRyJlKcIJf~G z)=BF$B>YF9>qV#dK^Ie#{0X(QPnOuu((_-u?(mxB7c9;LSS-DYJ8Wm4gz1&DPQ8;0 z=Wao(zb1RHXjwbu_Zv<=9njK28sS}WssjOL!3-E5>d17Lfnq0V$+IU84N z-4i$~!$V-%Ik;`Z3MOqYZdiZ^3nqqzIjLE+zpfQC+LlomQu-uNCStj%MsH(hsimN# z%l4vpJBs_2t7C)x@6*-k_2v0FOk<1nIRO3F{E?2DnS}w> z#%9Oa{`RB5FL5pKLkg59#x~)&I7GzfhiVC@LVFSmxZuiRUPVW*&2ToCGST0K`kRK) z02#c8W{o)w1|*YmjGSUO?`}ukX*rHIqGtFH#!5d1Jd}&%4Kc~Vz`S7_M;wtM|6PgI zNb-Dy-GI%dr3G3J?_yBX#NevuYzZgzZ!vN>$-aWOGXqX!3qzCIOzvA5PLC6GLIo|8 zQP^c)?NS29hPmk5WEP>cHV!6>u-2rR!tit#F6`_;%4{q^6){_CHGhvAs=1X8Fok+l zt&mk>{4ARXVvE-{^tCO?inl{)o}8(48az1o=+Y^r*AIe%0|{D_5_e>nUu`S%zR6|1 zu0$ov7c`pQEKr0sIIdm7hm{4K_s0V%M-_Mh;^A0*=$V9G1&lzvN9(98PEo=Zh$`Vj zXh?fZ;9$d!6sJRSjTkOhb7@jgSV^2MOgU^s2Z|w*e*@;4h?A8?;v8JaLPCoKP_1l- z=Jp0PYDf(d2Z`;O7mb6(_X_~z0O2yq?H`^c=h|8%gfywg#}wIyv&_uW{-e8e)YmGR zI0NNSDoJWa%0ztGzkwl>IYW*DesPRY?oH+ow^(>(47XUm^F`fAa0B~ja-ae$e>4-A z64lb_;|W0ppKI+ zxu2VLZzv4?Mr~mi?WlS-1L4a^5k+qb5#C)ktAYGUE1H?Vbg9qsRDHAvwJUN=w~AuT zUXYioFg2Dx-W)}w9VdFK#vpjoSc!WcvRZ_;TgHu;LSY*i7K_>Px{%C4-IL?6q?Qa_ zL7l=EEo|@X&$gX;fYP02qJF~LN9?E-OL2G(Fo4hW)G{`qnW zTIuc+-1VJvKgph0jAc(LzM);Pg$MPln?U|ek{_5nNJHfm-Y#ec+n#Yf_e>XfbLbN)eqHEDr0#?<;TskL5-0JGv|Ut{=$Xk8hlwbaMXdcI3GL zY-hykR{zX9liy$Z2F3!z346uu%9@-y6Gda`X2*ixlD_P@<}K?AoV?(%lM%* z(xNk=|A()443aGj)-~IDf3J+UA2p2lh6ei^pG*HL#SiThnIr5WZDXebI)F7X zGmP-3bH$i$+(IwqgbM7h%G5oJ@4{Z~qZ#Zs*k7eXJIqg;@0kAGV|b=F#hZs)2BYu1 zr8sj#Zd+Iu^G}|@-dR5S*U-;DqzkX3V0@q-k8&VHW?h0b0?tJ-Atqmg^J8iF7DP6k z)W{g?5~F*$5x?6W)3YKcrNu8%%(DglnzMx5rsU{#AD+WPpRBf``*<8F-x75D$$13U zcaNXYC0|;r&(F@!+E=%+;bFKwKAB$?6R%E_QG5Yn5xX#h+zeI-=mdXD5+D+lEuM`M ze+*G!zX^xbnA?~LnPI=D2`825Ax8rM()i*{G0gcV5MATV?<7mh+HDA7-f6nc@95st zzC_si${|&=$MUj@nLxl_HwEXb2PDH+V?vg zA^DJ%dn069O9TNK-jV}cQKh|$L4&Uh`?(z$}#d+{X zm&=KTJ$+KvLZv-1GaHJm{>v=zXW%NSDr8$0kSQx(DQ)6S?%sWSHUazXSEg_g3agt2@0nyD?A?B%9NYr(~CYX^&U#B4XwCg{%YMYo%e68HVJ7`9KR`mE*Wl7&5t71*R3F>*&hVIaZXaI;2a$?;{Ew{e3Hr1* zbf$&Fyhnrq7^hNC+0#%}n^U2{ma&eS)7cWH$bA@)m59rXlh96piJu@lcKl<>+!1#s zW#6L5Ov%lS(?d66-(n`A%UuiIqs|J|Ulq0RYq-m&RR0>wfA1?<34tI?MBI#a8lY{m z{F2m|A@=`DpZpwdIH#4)9$#H3zr4kn2OX!UE=r8FEUFAwq6VB?DJ8h59z$GXud$#+ zjneIq8uSi&rnG0IR8}UEn5OcZC?@-;$&Ry9hG{-1ta`8aAcOe1|82R7EH`$Qd3sf* zbrOk@G%H7R`j;hOosRVIP_2_-TuyB@rdj?(+k-qQwnhV3niH+CMl>ELX(;X3VzZVJ ztRais0C^L*lmaE(nmhvep+peCqr!#|F?iVagZcL>NKvMS_=*Yl%*OASDl3(mMOY9! z=_J$@nWpA-@><43m4olSQV8(PwhsO@+7#qs@0*1fDj70^UfQ(ORV0N?H{ceLX4<43 zEn)3CGoF&b{t2hbIz;Og+$+WiGf+x5mdWASEWIA*HQ9K9a?-Pf9f1gO6LanVTls)t z^f6_SD|>2Kx8mdQuiJwc_SmZOZP|wD7(_ti#0u=io|w~gq*Odv>@8JBblRCzMKK_4 zM-uO0Ud9>VD>J;zZzueo#+jbS7k#?W%`AF1@ZPI&q%}beZ|ThISf-ly)}HsCS~b^g zktgqOZ@~}1h&x50UQD~!xsW-$K~whDQNntLW=$oZDClUJeSr2$r3}94Wk1>co3beS zoY-7t{rGv|6T?5PNkY zj*XjF()ybvnVz5=BFnLO=+1*jG>E7F%&vm6up*QgyNcJJPD|pHoZ!H6?o3Eig0>-! zt^i-H@bJ;^!$6ZSH}@quF#RO)j>7A5kq4e+7gK=@g;POXcGV28Zv$jybL1J`g@wC# z_DW1ck}3+n@h2LFQhwVfaV@D+-kff4celZC0;0ef?pA#*PPd8Kk8sO1wza&BHQFblVU8P1=-qScHff^^fR zycH!hlHQs7iejITpc4UaBxzqTJ}Z#^lk{W(cr`qtW~Ap;HvuUf#MxgEG?tEU+B?G% znub0I(s@XvI(lva}$Z7<}Qg=rWd5n)}rX{nb+Aw;}?l9LZI-`N-*hts=c6XgjfJs ztp>-686v6ug{glEZ}K=jVG|N1WSWrU*&ue|4Q|O@;s0#L5P*U%Vx;)w7S0ZmLuvwA z@zs2Kut)n1K7qaywO#TbBR`Q~%mdr`V)D`|gN0!07C1!r3{+!PYf9*;h?;dE@#z(k z;o`g~<>P|Sy$ldHTUR3v=_X0Iw6F>3GllrFXVW?gU0q6|ocjd!glA)#f0G7i20ly>qxRljgfO2)RVpvmg#BSrN)GbGsrIb}9 z1t+r;Q>?MGLk#LI5*vR*C8?McB|=AoAjuDk&Pn`KQo z`!|mi{Cz@BGJ!TwMUUTkKXKNtS#OVNxfFI_Gfq3Kpw0`2AsJv9PZPq9x?~kNNR9BR zw#2jp%;FJNoOzW>tE#zskPICp>XSs?|B0E%DaJH)rtLA}$Y>?P+vEOvr#8=pylh zch;H3J`RE1{97O+1(1msdshZx$it^VfM$`-Gw>%NN`K|Tr$0}U`J?EBgR%bg=;et0 z_en)!x`~3so^V9-jffh3G*8Iy6sUq=uFq%=OkYvHaL~#3jHtr4sGM?&uY&U8N1G}QTMdqBM)#oLTLdKYOdOY%{5#Tgy$7QA! zWQmP!Wny$3YEm#Lt8TA^CUlTa{Cpp=x<{9W$A9fyKD0ApHfl__Dz4!HVVt(kseNzV z5Fb`|7Mo>YDTJ>g;7_MOpRi?kl>n(ydAf7~`Y6wBVEaxqK;l;}6x8(SD7}Tdhe2SR zncsdn&`eI}u}@^~_9(0^r!^wuKTKbs-MYjXy#-_#?F=@T*vUG@p4X+l^SgwF>TM}d zr2Ree{TP5x@ZtVcWd3++o|1`BCFK(ja-QP?zj6=ZOq)xf$CfSv{v;jCcNt4{r8f+m zz#dP|-~weHla%rsyYhB_&LHkwuj83RuCO0p;wyXsxW5o6{)zFAC~2%&NL? z=mA}szjHKsVSSnH#hM|C%;r0D$7)T`HQ1K5vZGOyUbgXjxD%4xbs$DAEz)-;iO?3& zXcyU*Z8zm?pP}w&9ot_5I;x#jIn^Joi5jBDOBP1)+p@G1U)pL6;SIO>Nhw?9St2UN zMedM(m(T6bNcPPD`%|9dvXAB&IS=W4?*7-tqldqALH=*UapL!4`2TM_{`W&pm*{?| z0DcsaTdGA%RN={Ikvaa&6p=Ux5ycM){F1OgOh(^Yk-T}a5zHH|=%Jk)S^vv9dY~`x zG+!=lsDjp!D}7o94RSQ-o_g#^CnBJlJ@?saH&+j0P+o=eKqrIApyR7ttQu*0 z1f;xPyH2--)F9uP2#Mw}OQhOFqXF#)W#BAxGP8?an<=JBiokg;21gKG_G8X!&Hv;7 zP9Vpzm#@;^-lf=6POs>UrGm-F>-! zm;3qp!Uw?VuXW~*Fw@LC)M%cvbe9!F(Oa^Y6~mb=8%$lg=?a0KcGtC$5y?`L5}*-j z7KcU8WT>2PpKx<58`m((l9^aYa3uP{PMb)nvu zgt;ia9=ZofxkrW7TfSrQf4(2juZRBgcE1m;WF{v1Fbm}zqsK^>sj=yN(x}v9#_{+C zR4r7abT2cS%Wz$RVt!wp;9U7FEW&>T>YAjpIm6ZSM4Q<{Gy+aN`Vb2_#Q5g@62uR_>II@eiHaay+JU$J=#>DY9jX*2A=&y8G%b zIY6gcJ@q)uWU^mSK$Q}?#Arq;HfChnkAOZ6^002J>fjPyPGz^D5p}o;h2VLNTI{HGg!obo3K!*I~a7)p-2Z3hCV_hnY?|6i`29b zoszLpkmch$mJeupLbt4_u-<3k;VivU+ww)a^ekoIRj4IW4S z{z%4_dfc&HAtm(o`d{CZ^AAIE5XCMvwQSlkzx3cLi?`4q8;iFTzuBAddTSWjfcZp* zn{@Am!pl&fv#k|kj86e$2%NK1G4kU=E~z9L^`@%2<%Dx%1TKk_hb-K>tq8A9bCDfW z@;Dc3KqLafkhN6414^46Hl8Tcv1+$q_sYjj%oHz)bsoGLEY1)ia5p=#eii(5AM|TW zA8=;pt?+U~>`|J(B85BKE0cB4n> zWrgZ)Rbu}^A=_oz65LfebZ(1xMjcj_g~eeoj74-Ex@v-q9`Q{J;M!mITVEfk6cn!u zn;Mj8C&3^8Kn%<`Di^~Y%Z$0pb`Q3TA}$TiOnRd`P1XM=>5)JN9tyf4O_z}-cN|i> zwpp9g`n%~CEa!;)nW@WUkF&<|wcWqfL35A}<`YRxV~$IpHnPQs2?+Fg3)wOHqqAA* zPv<6F6s)c^o%@YqS%P{tB%(Lxm`hsKv-Hb}MM3=U|HFgh8R-|-K(3m(eU$L@sg=uW zB$vAK`@>E`iM_rSo;Cr*?&wss@UXi19B9*0m3t3q^<)>L%4j(F85Ql$i^;{3UIP0c z*BFId*_mb>SC)d#(WM1%I}YiKoleKqQswkdhRt9%_dAnDaKM4IEJ|QK&BnQ@D;i-ame%MR5XbAfE0K1pcxt z{B5_&OhL2cx9@Sso@u2T56tE0KC`f4IXd_R3ymMZ%-!e^d}v`J?XC{nv1mAbaNJX| zXau+s`-`vAuf+&yi2bsd5%xdqyi&9o;h&fcO+W|XsKRFOD+pQw-p^pnwwYGu=hF7& z{cZj$O5I)4B1-dEuG*tU7wgYxNEhqAxH?p4Y1Naiu8Lt>FD%AxJ811`W5bveUp%*e z9H+S}!nLI;j$<*Dn~I*_H`zM^j;!rYf!Xf#X;UJW<0gic?y>NoFw}lBB6f#rl%t?k zm~}eCw{NR_%aosL*t$bmlf$u|U2hJ*_rTcTwgoi_N=wDhpimYnf5j!bj0lQ*Go`F& z6Wg+xRv55a(|?sCjOIshTEgM}2`dN-yV>)Wf$J58>lNVhjRagGZw?U9#2p!B5C3~Nc%S>p`H4PK z7vX@|Uo^*F4GXiFnMf4gwHB;Uk8X4TaLX4A>B&L?mw4&`XBnLCBrK2FYJLrA{*))0 z$*~X?2^Q0KS?Yp##T#ohH1B)y4P+rR7Ut^7(kCwS8QqgjP!aJ89dbv^XBbLhTO|=A z|3FNkH1{2Nh*j{p-58N=KA#6ZS}Ir&QWV0CU)a~{P%yhd-!ehF&~gkMh&Slo9gAT+ zM_&3ms;1Um8Uy0S|0r{{8xCB&Tg{@xotF!nU=YOpug~QlZRKR{DHGDuk(l{)d$1VD zj)3zgPeP%wb@6%$zYbD;Uhvy4(D|u{Q_R=fC+9z#sJ|I<$&j$|kkJiY?AY$ik9_|% z?Z;gOQG5I%{2{-*)Bk|Tia8n>TbrmjnK+8u*_cS%*;%>R|K|?urtIdgTM{&}Yn1;| zk`xq*Bn5HP5a`ANv`B$IKaqA4e-XC`sRn3Z{h!hN0=?x(kTP+fE1}-<3eL+QDFXN- z1JmcDt0|7lZN8sh^=$e;P*8;^33pN>?S7C0BqS)ow4{6ODm~%3018M6P^b~(Gos!k z2AYScAdQf36C)D`w&p}V89Lh1s88Dw@zd27Rv0iE7k#|U4jWDqoUP;-He5cd4V7Ql)4S+t>u9W;R-8#aee-Ct1{fPD+jv&zV(L&k z)!65@R->DB?K6Aml57?psj5r;%w9Vc3?zzGs&kTA>J9CmtMp^Wm#1a@cCG!L46h-j z8ZUL4#HSfW;2DHyGD|cXHNARk*{ql-J2W`9DMxzI0V*($9{tr|O3c;^)V4jwp^RvW z2wzIi`B8cYISb;V5lK}@xtm3NB;88)Kn}2fCH(WRH1l@3XaO7{R*Lc7{ZN1m+#&diI7_qzE z?BS+v<)xVMwt{IJ4yS2Q4(77II<>kqm$Jc3yWL42^gG6^Idg+y3)q$-(m2>E49-fV zyvsCzJ5EM4hyz1r#cOh5vgrzNGCBS}(Bupe`v6z{e z)cP*a8VCbRuhPp%BUwIRvj-$`3vrbp;V3wmAUt{?F z0OO?Mw`AS?y@>w%(pBO=0lohnxFWx`>Hs}V$j{XI2?}BtlvIl7!ZMZukDF7 z^6Rq2H*36KHxJ1xWm5uTy@%7;N0+|<>Up>MmxKhb;WbH1+=S94nOS-qN(IKDIw-yr zi`Ll^h%+%k`Yw?o3Z|ObJWtfO|AvPOc96m5AIw;4;USG|6jQKr#QP}+BLy*5%pnG2 zyN@VMHkD`(66oJ!GvsiA`UP;0kTmUST4|P>jTRfbf&Wii8~a`wMwVZoJ@waA{(t(V zwoc9l*4F>YUM8!aE1{?%{P4IM=;NUF|8YkmG0^Y_jTJtKClDV3D3~P7NSm7BO^r7& zWn!YrNc-ryEvhN$$!P%l$Y_P$s8E>cdAe3=@!Igo^0diL6`y}enr`+mQD;RC?w zb8}gXT!aC`%rdxx2_!`Qps&&w4i0F95>;6;NQ-ys;?j#Gt~HXzG^6j=Pv{3l1x{0( z4~&GNUEbH=9_^f@%o&BADqxb54EAq=8rKA~4~A!iDp9%eFHeA1L!Bb8Lz#kF(p#)X zn`CglEJ(+tr=h4bIIHlLkxP>exGw~{Oe3@L^zA)|Vx~2yNuPKtF^cV6X^5lw8hU*b zK-w6x4l&YWVB%0SmN{O|!`Sh6H45!7}oYPOc+a#a|n3f%G@eO)N>W!C|!FNXV3taFdpEK*A1TFGcRK zV$>xN%??ii7jx5D69O>W6O`$M)iQU7o!TPG*+>v6{TWI@p)Yg$;8+WyE9DVBMB=vnONSQ6k1v z;u&C4wZ_C`J-M0MV&MpOHuVWbq)2LZGR0&@A!4fZwTM^i;GaN?xA%0)q*g(F0PIB( zwGrCC#}vtILC_irDXI5{vuVO-(`&lf2Q4MvmXuU8G0+oVvzZp0Y)zf}Co0D+mUEZz zgwR+5y!d(V>s1} zji+mrd_6KG;$@Le2Ic&am6O+Rk1+QS?urB4$FQNyg2%9t%!*S5Ts{8j*&(H1+W;0~ z$frd%jJjlV;>bXD7!a-&!n52H^6Yp}2h3&v=}xyi>EXXZDtOIq@@&ljEJG{D`7Bjr zaibxip6B6Mf3t#-*Tn7p z96yx1Qv-&r3)4vg`)V~f8>>1_?E4&$bR~uR;$Nz=@U(-vyap|Jx zZ;6Ed+b#GXN+gN@ICTHx{=c@J|97TIPWs(_kjEIwZFHfc!rl8Ep-ZALBEZEr3^R-( z7ER1YXOgZ)&_=`WeHfWsWyzzF&a;AwTqzg~m1lOEJ0Su=C2<{pjK;{d#;E zr2~LgXN?ol2ua5Y*1)`(be0tpiFpKbRG+IK(`N?mIgdd9&e6vxzqxzaa`e7zKa3D_ zHi+c1`|720|dn(z4Qos^e7sn(PU%NYLv$&!|4kEse%DK;YAD06@XO3!EpKpz!^*?(?-Ip zC_Zlb(-_as+-D?0Ag9`|4?)bN)5o(J=&udAY|YgV(YuK9k=E>0z`$dSaL(wmxd!1f zME&3wwv@#{dgeMlZ4}GL!I`VZxtdQY$lmauCN_|mGXqEEj@i~du$|>5UvLjsbq!{; z@jEf;21iC1jFEmIPE^4gykHQzCMLj=2Ek4&FvlpqTlS(0YT%*W<>XgH$4ww`D`aihBGkPM(&EG};Cl&wzg8!jL z`rkqPzvH(0Kd{2n=?Bt8aAU&0IyiA+V-qnXVId^qG!SWZ7%_f&i!D{R#7Jo$%tICxY%j)ebORE>3H_c|to}c#HX;HAC?~B;2mmQrMp2;8T zmzde!k7BYg^Z1r|DUvSD3@{6S<1kndb%Qt%GA# z+sB2&F5L`R&fLRdAlpU_pVsJsYDEz{^ zKGaAz#%W+MPGT+D$+xowMY0=ipM)0p?zym&Aoi)qL(pO_weO(k?s|ELHl^W zviJiFUXRL&?`;3_;mvc02A@sbsW9}#{anvGafZ#ST;}za?XS3}ZG3B4m(SW{>w}Fh z)T5Yi*``Tstmi9SHXmuWSND@cj}qtY!`tuD29Dpu+-D3$h<5FY>jE>YJvqBmhw?oll`x7Ono(}R~P zle_eBwYy0Rr7kmf_SEt_gn4)AO-r`}^Z5Y%Rm8)K-?X>rvDL+QT?#)QwDsQ2c$tc* z&#hbgkL6}GnBDH;+lREM6MGIskRa@r>5Iq(ll2IepuhW86w@14=E{6$cz*cBDQ)CT>}v-DLM-v8)xaPBnmGBKM63RgDGqh!<*j90tSE4|G^+r@#-7g2 zs8KE8eZPZhQuN>wBU%8CmkE9LH1%O;-*ty0&K~01>F3XB>6sAm*m3535)9T&Fz}A4 zwGjZYVea@Fesd=Rv?ROE#q=}yfvQEP8*4zoEw4@^Qvw54utUfaR1T6gLmq?c9sON> z>Np6|0hdP_VURy81;`8{ZYS)EpU9-3;huFq)N3r{yP1ZBCHH7=b?Ig6OFK~%!GwtQ z3`RLKe8O&%^V`x=J4%^Oqg4ZN9rW`UQN^rslcr_Utzd-@u-Sm{rphS-y}{k41)Y4E zfzu}IC=J0JmRCV6a3E38nWl1G495grsDDc^H0Fn%^E0FZ=CSHB4iG<6jW1dY`2gUr zF>nB!y@2%rouAUe9m0VQIg$KtA~k^(f{C*Af_tOl=>vz>$>7qh+fPrSD0YVUnTt)? z;@1E0a*#AT{?oUs#bol@SPm0U5g<`AEF^=b-~&4Er)MsNnPsLb^;fL2kwp|$dwiE3 zNc5VDOQ%Q8j*d5vY##)PGXx51s8`0}2_X9u&r(k?s7|AgtW0LYbtlh!KJ;C9QZuz< zq>??uxAI1YP|JpN$+{X=97Cdu^mkwlB={`aUp+Uyu1P139=t%pSVKo7ZGi_v(0z>l zHLGxV%0w&#xvev)KCQ{7GC$nc3H?1VOsYGgjTK;Px(;o0`lerxB<+EJX9G9f8b+)VJdm(Ia)xjD&5ZL45Np?9 zB%oU;z05XN7zt{Q!#R~gcV^5~Y^gn+Lbad7C{UDX2Nznj8e{)TLH|zEc|{a#idm@z z6(zon+{a>FopmQsCXIs*4-dLGgTc)iOhO3r=l?imNUR-pWl!ktO0r_a0Nqo@bu8MzyjSq9zkqPe*`Sxz75rZ zr9X%(=PVqCRB=zfX+_u&*k4#s1k4OV11YgkCrlr6V;vz<{99HKC@qQ+H8xv5)sc63 z69;U4O&{fb5(fN``jJH#3=GHsV56@{d@7`VhA$K^;GU+R-V%%cnmjYs?>c5^6Ugv} zn<}L&i;2`zzW@(kxf$$gVH@7nh}2%G%ciQ_B?r{13?Q@=Q+6msQGtnyY%Gkjeor?g z7F*tMqLdhcq+LCCo^D;CtOACCBhXgK-M&w{*dcUdmtv@XFTofmmpcWKtCn^`#?oZC zUOm52 z7sK$hR|Vh6y&pfIUK&!`8HH*>12$nWA)Ynp+XwOj=jNLD z{QA4gezbe>wiP?`jJO;c&EId;=2u80s_r97;TX!6@*(<%WL+^bmxheMB3pKx0OpH^ zPs}knV+jpJ4TaD@r^V`mTsjf`7!z^H}eHQ#Rp z72(>Dm#QO!ZYR*O@yHic`3*T^t7jc=d`Jz6Lk@Y-bL%cOp_~=#xzIJl?`{Qu;$uC~NkePE+7wSW_FM`&V{gFN zl;lq@;FtAsl!h;tnOvj z#gYx!q$5MdZ0Jxjy=t*q)HFeeyI-vgaGdh1QNhqGRy8qS)|6S0QK7Gj9R?Co{Knh> za>xkQZ0}bBx!9@EUxRBYGm25^G}&j-`0VWX04E|J!kJ8^WoZ(jbhU_twFwWIH32fv zi=pg~(b#ajW=`)Vikwwe39lpML?|sY$?*6*kYBxku_<=#$gfTqQ_F!9F0=OkHnzBo zEwR!H_h|MNjuG$Tj6zaaouO}HYWCF8vN4C%EX-%Iu%ho;q$G#ErnafhXR*4J2Rp5* zhsi0;wlSwE*inVFO>{(8?N~82zijpt+9Y_-^>xnE%T*zk9gi|j7b@s<5{|qEquUD( zS;-%RySZOCOEh*>!kvbsQ265* z>X8*_Wy&~FB@aDHz%glyiAujXq-|2kDUjFTn9Rafsl+XNyFP%PG|l&ZGWBcEXxy=9 zeDn2PIoVuL$gX0RgVK1O$x3%pOzS7x^U5Pi;mtT)%cY;&e&M7GLM}zP+IPbqLt=^5 z7qLfri8myf;~2psc@^cA6mG&{C%e_(M$$!wC^5p^T1QzrS%I?(U{qcd+oJJkQxe10 zON{Q*?iz%F4MbEsoEc+x3E?&2wVR^v3|Q0lDaMvgS7mNjI{2w! z9|~=!83T%GW*iaChSS!`Xd^beFp9N4%K+k*j#jFumk}U?=WKL_kJAltxnxp~+lZzT zp@&&kSPTg3oSGos`rVBhK0|4NdHM_hnKuw1#0JV{gi_dKDJLB+ix~~HpU9%jD)@YY zOK)L7kgbLyN2%Dx#fuY}8swh4ACk7%BpP-n5(RhDq{gEHP*Fo4IviX{C49|B5h~SC zFr`=0)=h2^F5UpCAgt?R5u{6VvpUf#*nC zCQ`$!|C;L2lpjlG?(>T$(_$O3_YNNbPT~(?!j3aD8k=yu^ogw4bkjvgF|3BOq(hB& zG;^cPXmcUP$ox8zElCJ-zMbK9q^8{rri#8Cek5Ydr0YT-KTh@J z6^AcB9ejew8BY5kzZUZX(7Po==eW<(;uV~E7(BY5c0^xr`cuRwn)47bN?zOb!0?cw z#v}R$z66&m#+AHfo@(^V2#S~bhoUkkTArg+6w>JzZ52r96^({1W!?>4$h0l|-jDfj z>7(<+%67#(A|4hZ3>Y;hd&S?}F;`Vtqz|pK&B>NJ=Faci;gkf-+GmfQR8^zo_vul2 zB!)kfu4Dq_g)8TBBo52*sB6F`qa&JCR=_A$QWgX_K}fZm{Cb2#1q`^S3+WaS>sS#@ z-4k*G=#?z6d_e7JJ+Z8^(t0tNdL{K5F;2nfQbXgld}a(X)Gr;WojOy`^?es~AClT$ z5^lD{WJek0!p-QEH5E7n6DKQ0%_ZBZ=|jfV_MM{VmL8y-Wd|>OmeemP=C@xI@@M~1 zW2S*im@Rc=O>V886_UJ@oh1!2H$Ku&U*Hh_oxd{32)vf1$cRiepv28ricM;}#p!+k zaK{z1I=9Y%3m4|Pj*BD*Fn5Vh?O@oD^1UcjyeNh0fbhh~V6xb#4njlGW8OehUe!MnoR(wn#nsoyL1m!Rov)Nv4~&JEVl7L z#^qYdTpNI#u`N0UbVMiDmD>g2VQcG3>4D6gErgddZnSQTs){BExxRJRB?bIxTdZa z;!S8FHJPPiIDQ*FAUiWSYnjILFjDvxvSC zk z=j4Kx@Pg~&2Z?cmMDa;)#xVeorJrxDBqy{+`kG+ZPQqC@#ku-c3ucU+69$#q_*se` z-H#PFW^>-C0>++|6r=<$Z8)ZFaK=ZjwsNYXqRpl9G|yme@Eld5B-*I69Nx_TResHi z!5nm+>6zaJYQO#%D{~o-oOJ;q`fa5}l!8G*U-E$OM&7@dqciBCWtd}|SrDXz$TB($&m*=Epuolu2k`KUwO7maP3P0ok zmF57lSh0Ba@&sO1iZ5^+3s8{B8t|M;Pg&O+{tZJCiLWd6H@{b~9{CLF9s3Kn zt5)Rs9ejne?o{%f>B$Dl%X7fd~KY)I|(pxUeHj;gNsK6;ZR>`ciu;GxvhDUt!+31Knss2U(%ts8K z18)8;<2ax9RG?!|Lwdt^i5L^&O788roKmVAB)=EdK~HqR2Q=)H_VW}xY=95MP_Ov< zPEz3%DRK}+(aUBwsr83H8>`H^v~|A_t}0vPmRwKPt1{|qOY|PZu}j9+{ZhF&-H_TB zU9xWLpNTc`enI|)h9jQeqf5RfGLFk_vfX`40iMpd%KZF!lKbZTdBw$<^G6nuS+$fT zrbK)xo&;buPJcpOZ=x>n+bRXVFDs(23Xr=rDE&!)pVXZ;;A07NXGl_0m`{Z)DQIu$ zFDvY4xu-ifTe_$|n2B83eI;KUg6pVbw+N!nyLj~wnRi{4mNy{WDV)G1!6$y=+x6U{ z%4_9=Q^L!x_gAYp?J3+u5hA5cO8aHeI=6AC8^S{mzhqCBvBLYEutUC(X0>hKg|AvN zvkmJCQNA45_KjW{aEcyrBppcO6G0zTy%v1&@~+2!n?kA9?>0>AjFN|JdCnHQ8$hEU zw#mwGifHppLP?89LMb(Y3Li9iCPx7W%ek}2FgD2YSzjsR4Xj<=zN{Yo@7s7(k%mP4 znT2p&4EQ@q_chd-E z78uvD*C@oba`U3W2Iw`M#`5C8jOHv8^Li<|j^SI>>>`77Dp71Vtz=J?4Zck4SdRbd zfF}C_>Y(#)r@y!Q0`tMlG#b9>5`fAI$B&tWJfbGlYW$J4V+-s=HH!`+;1XeL@USdx zR0$G&&XBf9lQtkH5)p=U!8J!1{oc4E!N-~Abxl6E;;=3-hMYZ+44?u}zabmCE)yB?*_w91m$n1Yskp&@ z;kxeJX-#ioX^{elyLu~gzx|_KxLpX62MF%Axq3$!Z_P`pBWR?zP8OI`PV~6Aa0Oi0 zv_Ot1m&plf-ZF{e(z(Ms3*S5q$e|j;gOwGrmWsCHfLi(h8y?gc$(2H{884C1FvHQQ12tX=qFUsK~zM!W=K>;zaRsu4Xmcc@8nSs!vK+{ z?}bq}-m&p5jRSam67n>yG9ez=I^|J1O;Np8s=P~9MXYLxD+cFQK7PhG=bkjo{Naae zjp3NWWrlFWDb3Z5D07Q|WjZ=wOQ=aKA%en=O@hL$QCKpIXNZE=InFk|Fhq-&H!6&X z*MVy8=hL7Aw&pQjHrFf27C%3B<>FX{@fOLNhUoxL4*@nY}&M3G*T-p67a zo}~_&yGOB)#vbU|Q3FA8S^X)c-yBlmN(_%}`7Ha3uWFe?>9f=3hlO{^gv~$p`v?vk z_P*r43|(S{%ihs;)YH|jAMpP=-Ms7Ne75_YZZiL3CHVjSU`X1|?Ehh&gA=Xn7W7d@ zf8bM9Y>lG!`PWFDDA9G;x*{1Eh^55u66*9D+-4^dYZ{xXP@?sQLVrY%(azM;C^4FuN7CQ%$!3sr1JL=!Be& zuOZL^bLp$Qo2rL=WDzQIls%s!Go z{s}Q0b#+#8bKga|01t%^9Z=wEsevvXM_{$dCR97ed3@1kX)mtSS!JN^rtqKOj}p~> zfpCI@DX*DqcB6ZnBcl~}sGO~1s$AtfkX6fy3N8*ebvZc*KBW;dA=)?#BE&}-or74i zZUt5;{FBPnkZD8YUXDsx&2LvSziAlec3oc>&Lf1Doc3g?H9{OO_$M4B0qTat0UsWP zTlxUeQ3B;oJ%en4n?zQB6*Fb#wH7`$SQN5GI|=DnJKiYm{?-?#-H;#sIjz7kQ4&VW zN9d1(1$_W~S=<%qDD!mwRytas=eqX^iW}YSx3;wJ#)Xp_`Qk1DFiXac$-3;jQbCif zLA-T_s~5yP@Q@W>pXKl^gipQ>gp@HlBB>WDVpW199;V%?N1`U$ovLE;NI2?|_q2~5 zlg>xT9NADWkv5-*FjS~nP^7$k!N2z?dr!)&l0+4xDK7=-6Rkd$+_^`{bVx!5LgC#N z-dv-k@OlYCEvBfcr1*RsNwcV?QT0bm(q-IyJJ$hm2~mq{6zIn!D20k5)fe(+iM6DJ ze-w_*F|c%@)HREgpRrl@W5;_J5vB4c?UW8~%o0)(A4`%-yNk1(H z5CGuzH(uHQ`&j+IRmTOKoJ?#Ct$+1grR|IitpDGt!~ZdqSJ?cOtw-R=EQ+q4UvclH zdX=xlK-fhQKoKCPBoFAZ*(~11O6-tXo>i0w!T$u{lg!#itEUX3V{$S*naW!C@%rll zS{L(1t%xz(*B`{1NL!*aMc<~fE=g;gXi&Gb$HpD!P)8?JzfN;4F&wv(5HH<=c>>)n z({271)xREH89=C(5YKL{mmJJ_d>qHz;;gTvTlgM*vz9@YTTYZ#%_2A zS0G-t9oMQEpvfv(UjfQ8T$vAHi)zOj3>D*{xSRiu3acc=7cvLyD?_ZObdu$5@b*!y zaZ#u?7uF}SrHVQa=sTOhGW{6WUlq#RhPPm^GsRH#qlX8{Kq-i~98l;eq>KdCnWyKl zUu&UWBqu#Tt9jQ97U4}3)&(p2-eCLznXMEm!>i^EMpeVzPg%p;?@O;dJBQQY(vV;d z3v+-3oTPC!2LTUAx^S2t{v;S_h(EZ^0_dS5g^F*m{TEIy^Qal~%mu3h7*o`jWOH}i ztv8M)3X3a*+ry_KkYXYE4dB0?M|t}#Tp+(}6CQ zBbq;xhoHj}b@j-@koDB#XcCY~>_x&Y;i%MH|3tF^X2h{36UCVfQ-;oEA+4ZkJ`^Qi zQf^8}6eFO$Z+Dj-F1wkG##tTx>FjR2oOXFmbKFj6K3+=kePQ<4d7%z5R5cOB;zO6| zm9^m#U4lcA;7t&*=q|a-!`!)}SgYXT#i8hnxtx@kaoBF$QAS-hT7N5kH^l zB^i+})V>L;9_0Qqf-dyF%ky8Mp-dp#%!Nls3vCt}q3QLM3M-(Zs1k}1bqQ9PVU)U` ztE=?;^6=x}_VD%N@${>qhpkU*)AuUBu_cqYiY&@;O$HV*z@~#Tzh?#=CK`=KwBv+o zh%zu%0xPKYtyC)DaQ zpDW}*86g%>BH3IcWMq`g$j()0kWE(qkIL8A&A0mf&+BzxpKF}=`#jG% z&*wa!&pGFLs5_b#QTZE4Bp+})qzyPQ7B4Z7Y*&?0PSX&|FIR;WBP1|coF9ZeP*$9w z!6aJ_3%Sh=HY3FAt8V144|yfu}IAyYHr1OYKIZ51F>_uY^%N#!k~eU53at-_E-Gh?ahmM5y* z+BTIbeH;%v1}Cjo{8d%UeSMWg(nphxEU`sL< zQR~LrTq>Da(FqSP2%&^1ZL#DTo5Sbl9;&57tQ-@U&I#lj)aNSkcfEJwQD!33?anVU z?pw2q7WtMvfji493`rSFnyp7{w87cW`ak=UEYlk5PCB1K6UDVKXyozOChH4yHh~Q< zv>yvKw6WLfi!PZUx60JZcTNM7jo{ww9b8Q+S7C3WA5&llSwdwh$=Q(*(f3ofqcz=nwOmOy z(J!K=*wNoRU*${{Mbwapi9pTB(&VVKefqd-qrUb9*Eyr2E@oZ9Cgf}Mc;QP<0D)R4 zz=!*^VIG4T*7Xl=sJxrWv9hW^eJ%qYp5(d0?E6LZzJ}=7E+1{?GQA;z+!^VBD81}O z0kJ^dKy&WMw+1+aGVYY-v@i28@Gm+sX5=@U%F=Z?W)oar}2~Rc&F|+3A)n-U2GF10+QdxDb^iA@7eL$c7yhBtL z>lABrh^qy9XZ${E1}Ss5!N4;ig0-pUh6@|RPCHOWvgG{|l}2enRgJftsN%D|ck0YO zuAQd2aMPSyGuJ~jm)aY=+p~mGudw4erwE%P^)5f<*$$2C-4^I=e8-}7##ZQ!8!Tep z+Z_!}CAI~sry$|XK$ktXaxP*x<_ijCPp`2=6sNLZU<@9Sz-rz7^BCE9yh0jV4(I!Z zxmA4d;>B-!vD}Xp*&*N%`b^e&R;D97WS}{~{O-EtXeZNfdf51tw!WR6Noo4hjHPv5 z?heYYRSBPjMc}tFEU^|U8a1CxxK%)WTcn9P%`wR^I$QSeMn6=w>Z9OoVvcrl`zYlZ z2y`mAu0bV(Scc>G_EmIo_4 zm*~h`mxYZC&+U>C5G1FZH5L^U>Cq-9UDRQa35jz&NBj*0{uJKfZs5=Fn@&)Xh6aX(H3w9m9BGLePqVotxTeSPh5-mc7$# z-80t6yB0$Nx<54ohdO*QL7m_(&+#*=eoNiYDB4rE4Cag@qfyZS};Fx;Vf1;oync2k z9v#-w?d6R& zOI`CCS_d=tf3|?g3Z}b6-_Rdg3y~enQhmgkni0Cvf9m6%Ft8r;NC5|b%t&?lkl*4{ z8Ui^;Ds^gq6ti(1xB7y_$zA!i-M~#!!tl$ErTR>P~>T=Yky)8(uvPbvLmB=UfoD zrfl}8<1OQrm?8#j1!?s*T>AoectQl&m!o&*^JcIW`_&bk3tN}k^0rjl=HL$z*uIYt z?7l?^Dqr?q1210Sp$xoAy!&{2^{^Anl460 zI&7urrc&|Y{rjv04VOl{y7c82N6xzg5ueYmQ(q(zC3w_C#x*~%yf5j7MI{W`tsoxzA*PrmK)cTskU| zf2C}Bq$>S$-1JgIh0aW@LxI|-8(OGuD#^M01ghh}&#ObO>tZgSw_LW`zdf&IN$YO# z)|X_9m#JwLW5pErZB3ScggKcNzxA9(hyKkK9I#pR&79&*+SV_eu={00{HF=Bb+AEe znaSof+r1jZ!EL5XgqXWkckaFSSyEk}o!%p8XsD}O>borZ6x%X2b&q!s&1-O(>`kZ$ zB2l^5Cx9xQx9)PXN1xPM)@+LxACH_iZ8zGc(>wnFS_O|@hKsxpMjXOzLEa7OvSlM&&G9ioQw9~RsD4F zK7Q+_&|Q6{eZ^8Rx@pKL`le6kH+(fLc{=V&{b%I5=n}VHV4)X_2Y!pYxgC8wU)yP! zPF3t$?(jsC>Ge=&{kmPGUEETpaw(QTAl)m#{qR3_aq9!wK%6XHfV4C>Y^>Z|%ns7j z{Ja?^IA{+@;kR#IjHxkar%3$eJT4?xNBKUVmoO z`A8Zo-{~_;vcikZ(p}EZzU4kO6WPqkMyE{VvS?;44Z@lj zz^fKX9UL!8Wc(9VgI?P4*zpis8dzl};I>yr1>dtXU=FTAlx}Eht4-*7RACL^AflGh zyZb1hTf(~CkMo%#Q%NMgM9tE2D+)joqbtHYA89Ql1nqVTt+MxZ^*FRd&n5YlIi!8m z>$Ysd!l{+C)y;Wa(ZV-=<+NZKV;v4mt}v2m>`v$-$3b;GsLxf= zd~f(rmfpl``{0aVwN7y!>eGyJFP`L+TxHjHTOS{K^$L2`@6(Rli`{EFwpH@R%eZ6g zwf7rc43Yk!=k;{ z-Rn%~B3amGr}}SxfE$vS8FIPL=Qt57$|R#sSoFgdNUT?fYOYjPl%ZBFpi=jq=DWby7Zxm@y;B<89!9= zbgEH*Uy)~iq5kJLX$+ps$kV`#6jW#|9BGz^`ivNeid(wVbk4jl)VBpW&~;eXNi{#` zwx?{DXR~*sqQcFhY0XCfQ4-*2aN1BGX>$_swtKEqnd>j6vcZ!#0)pXRi?<{!P?tGw z2x_`RD$W)qD{?z}VDPt?+)8*rqLWFIPQ(9-VbBdf{7ff?w9CZ{sIi_gnuC$I0(+P8 zms9XB%}VQ>>pve##}jog6+cD?v~n4Pa9Vmc zg#K$|+`adO=B7`uj35Y}6EZ z{dY`x@w8;R-7zrsr1O_~Jvl*|o-x%jF=Rr1C}GXP^|IYN`1sqmG-oI@R#%X66c#5W z$$tQB)sqwiVm;Y^`Dw3mo|firP{*HsOQJre5%Dm^H@we0FN88VWJ0dja?_U38z73f zrCV!b3qNP0kM#%9T!W5`ynGcg%BL28FW1J-J1_S`BJGCaReQ!am(2%qZ3lLgzq|ns z!!fF@`0=*z)J2BwZ*hO|Yu^cI_nF$9l-Pb3jE7=P8gZ#!xiuZ7-cSa`gb`6mxGTgg z-DLdID?M!Z%+hHB#{?&0$GFRpf+_}q<_wbzX6K?w;%6szz1RbySDSr2r^h_qi$khs zXdZ9A0!_Bf)TR2-^-K~q`FQ!#1x(U4VbV%AA@Ei{%cA(EwC{XfjRi?`&9rav5;Q5% zO1`Rn@OA_ZB@N*mC#)?d3P!}Eh;=NgpIKsy{(yr`hv=aouwt@r&P&}Z3DNWo9ro30 zX52~(aTV$*HHlgB66-4GQru!_AZ|)V*I5X=WG)`N@U&D>e@@C#V@JwEL*L`7#$yes z62C^5%Qniaow2$3HrAc7U{qzpb&FA*xLI1JSWR@`RF=JCcvTI)%dH7;sWInt9JLu# z|Ao|Q?K)cDg_JKsym=joo5gR80wtv01N`um1nQ@Ms0Y*bVzxL34} zo?gizp?`=Y{*W>^Hy2%Jl)y?A+&7s1UVHFixuIy~sawXjcDCL`129cK7|ZQS0u;A} zTJC#WNmqkIrnHpAhHVcM(U^vJA~dl@jf_bs*3?i+=&vuC?Aiy_pcB~=1syDni4 zw+FLuz>F773u#$;NUQ9WDtUPY@+rA3WBhQdKFKOyzkA(URa7;4tW>3jQIfi8v0h3g zJC_HVDXS#>DWb|&se7FHnr=q&l#xg9o02}}u=b-R>@sw={Z zHF*?t2FmhqZ=|qa>x=A!*$S+0T zhO*D*M?NTf-eX`eO)9TIQu{7Dm77Acnj4b1jI9@c*ZL8wL%8kLEhd$KM8=Y!fbN@9 zC7B5#y>JM1n5M)!&im==EgHs2j+xCZG~+~QWCi?s!QyFo2kqx{%jE2n3^N*Ayz6Lp zhg5g^3# z+5FoJ@$u@9WJgPKpUWEd4}4AK9TJKU8W%ms!d0p%OIOX+bY+55zl!vIaz$XFI9Ep+ z;bL_}7PDI2Y`Ng*XY(65 zh0%`@Lve%fc;)N4_g12bNrt6gH=N#OHtxO`$lpWlw=Z6MF+E@;>GkZ#lAZTn`aHwf z&I1|aV#b_VHMIgBN*RzU9i@Z@m}0i>o?({&%fpEfaOpFeaJ7V37;m0?kzd}}Lk@9$ zL}8TEo7WZAcRi%zFZxkr6<0k#X-;lTD`Oc~cDb@olwgWCewvk{GJ}hCXbF!AdiLpd z|Cck$ZTKI?Ack{34Lva7+k=H8K2HTZiurox6F+>dy+@R9T^awxj590D$|kXUg+Ygc z(f)jlRwN(4z$#%PnOVc;#Fv{nAi{#UcXPNcmP#5O{zh_*`=q^JCeia{sN4zHjk2*y zqUVh{Ya{j>SPmP^i#Qfcq_MTqo8g52Fi^F zKBc$$HVI!xFx*4Y9l+nt)$AoZORD}%5I10oI3kx`-N30QueiwIw#0VV2E*Fb-nKW% z=+r^hos`Y-7~{cA1FVbK$_=~*z53+Q8KGjg;>ztg((H12%QTf4OYU8y)C}h5yo#$% z&Q$`vMM*g?ZcatAn2j!hFv8KuN(dw)T*}sF#THDHxo8xC^?vJ zc`U6bVo~hOr6I!8*GTZ<^D~;unKjK=!IR|GB4E>Mcvt*2GK);93jIDd<(nNjHO z4Hi@2^%Uyx=^Z~5eZ!5rO5%4H|eFoNjD#+Kcu%_57zZb4Z@Ak#X6txD^{U3wBl^r+W- zLorkK;uc;NgTj7dGxHQS+@T*T>Q*j4^Ll$ejQqWrwcHyG9y%Mk%m8nBVG5hvSaYm5 zJN^#-Q46kZG)@T8n2^QCjxIwxUVi%s>EY`E?#@_(A~njFrTiDq;8v|W-1jT|ROlNI zU$h|YoD4PVTE^&NC6_m{EAFBVqsM`P*`-AcDGWQygURzM32Xeq2xng~XQsYeTZ5v$ zQLaa2M_Iplw}4eL6fLPu`6`PYcVMysO>`{8CB~glD=TX7?JZcHfHNmykBM?QD)#D) zGp>R*<^D?WhFQKRc^}22l6F=D2RPrxaX2ZF!b1X0XF*d4%=!sbNcS1q2WOUE(7e4$ z^L8f;F)__d3>&KQFE8%$I4h^y5FYBfB&fWzn71_OSrPe-DHV{O#Q;GP z+Tw!J?eVjX19RKH?*hKQWQt8r7B#lYX8xoSHFGCW-*DSQ4EM4M3Mw%gkSYNK18@(e zfzMF}WWaCyS@1y%-~Xg0ry~tkQkUmKuI5lGAua{{vn22V!2T()AU5FpKh@Nv)s^Js zv~@VuUG;=CnLmQR{PeUBQf2;lAV!vG>^Z0N zL88rrjL-*J!43;7C=w9xhcw`yjRKq7o4L9=0SmR9PA-nX12@#h(iIu-0N_xm2OV)( zU_raT0y>$wm^oMi2|U3N;OhF9uy}`<-xVka#DV*l{O0yHzi9vUxa1Qtpi$buR*8cU zd4~lS1pT$L^!0=6qUKOpM+XPsy{f7W#1bjrEwaeN!Ik9(zySIT^pEHvHgJUneFN4) zk=k|$55(g8slmS|@+*4fr2urd3LwjIIZA**g+%l(SZNn4HwQ}y6o`vw>2&mR1X+&q zDa1Af0B;4rAMZMOlHbAqK|R_xuwJ7ANARtFE({-P2o{tJJR<>2KVp)ZK-M;)ejx zd*E~Mka<{OL7%CAhk4n|1qg?97-I!l0rOinjVi#arbgg4bi5;nY5oFL`UWtPk5&L#grSxv zE3!}=1px!ZTLT90aYc^s`~{VojjJml&<`@e41dFP+XU6D0AOkbn2rlI3>^LcqauG& zc$m3Z{!u8LvUrm^fT{qX5yD9{?r(CCiUdck%!T`KIZd2oQJz1joB&M(Teg_>;yS<2-5>BWfSPpG`Rt{!j6>kqMAvl^zk0JUEfy$HVJMkxP-GkwZuxL62me2#pj_5*ZIU zP~#C^OZLfl$HO)v;~~c&JHivn|1I9H5y_CDkt0JLLGKm(4*KLVhJ2jh2#vJuM6`b& zE==-lvME^Oj022xF&IV*? '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/examples/powertools-examples-core/kotlin/gradlew.bat b/examples/powertools-examples-core/kotlin/gradlew.bat new file mode 100644 index 000000000..6689b85be --- /dev/null +++ b/examples/powertools-examples-core/kotlin/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/examples/powertools-examples-core/kotlin/src/main/java/helloworld/App.java b/examples/powertools-examples-core/kotlin/src/main/java/helloworld/App.java new file mode 100644 index 000000000..fccc63b9a --- /dev/null +++ b/examples/powertools-examples-core/kotlin/src/main/java/helloworld/App.java @@ -0,0 +1,107 @@ +/* + * 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); + + @Logging(logEvent = true, samplingRate = 0.7) + @Tracing(captureMode = CaptureMode.RESPONSE_AND_ERROR) + @Metrics(namespace = "ServerlessAirline", service = "payment", captureColdStart = true) + 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 + private void log() { + log.info("inside threaded logging for function"); + } + + @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/kotlin/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/kotlin/src/main/java/helloworld/AppStream.java new file mode 100644 index 000000000..401ef8c48 --- /dev/null +++ b/examples/powertools-examples-core/kotlin/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/kotlin/src/test/kotlin/helloworld/AppTest.kt b/examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt new file mode 100644 index 000000000..b137aecce --- /dev/null +++ b/examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt @@ -0,0 +1,19 @@ +package helloworld + +import org.junit.Assert +import org.junit.Test + +class AppTest { + @Test + fun successfulResponse() { + val app = App() + val result = app.handleRequest(null, null) + Assert.assertEquals(200, result.statusCode.toLong()) + Assert.assertEquals("application/json", result.headers["Content-Type"]) + val content = result.body + Assert.assertNotNull(content) + Assert.assertTrue(""""message"""" in content) + Assert.assertTrue(""""hello world"""" in content) + Assert.assertTrue(""""location"""" in content) + } +} diff --git a/examples/powertools-examples-core/kotlin/template.yaml b/examples/powertools-examples-core/kotlin/template.yaml new file mode 100644 index 000000000..a717c2998 --- /dev/null +++ b/examples/powertools-examples-core/kotlin/template.yaml @@ -0,0 +1,71 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + gradle + + Sample SAM Template for gradle + +# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst +Globals: + Function: + Timeout: 20 + Runtime: java11 + MemorySize: 512 + Tracing: Active # https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html + Environment: + Variables: + # Powertools for AWS Lambda (Java) env vars: https://docs.powertools.aws.dev/lambda/java/#environment-variables + POWERTOOLS_LOG_LEVEL: INFO + POWERTOOLS_LOGGER_SAMPLE_RATE: 0.1 + POWERTOOLS_LOGGER_LOG_EVENT: true + POWERTOOLS_METRICS_NAMESPACE: Coreutilities + +Resources: + HelloWorldFunction: + Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction + Properties: + CodeUri: . + Handler: helloworld.App::handleRequest + Runtime: java8 + MemorySize: 512 + Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object + Variables: + POWERTOOLS_SERVICE_NAME: hello + Events: + HelloWorld: + Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api + Properties: + Path: /hello + Method: get + + HelloWorldStreamFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: . + Handler: helloworld.AppStream::handleRequest + Runtime: java8 + MemorySize: 512 + Tracing: Active + Environment: + Variables: + POWERTOOLS_LOGGER_SAMPLE_RATE: 0.7 + Events: + HelloWorld: + Type: Api + Properties: + Path: /hellostream + Method: get + +Outputs: + # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function + # Find out more about other implicit resources you can reference within SAM + # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api + HelloWorldApi: + Description: "API Gateway endpoint URL for Prod stage for Hello World function" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/" + HelloWorldFunction: + Description: "Hello World Lambda Function ARN" + Value: !GetAtt HelloWorldFunction.Arn + HelloWorldFunctionIamRole: + Description: "Implicit IAM Role created for Hello World function" + Value: !GetAtt HelloWorldFunctionRole.Arn From 339676697f010f4a8f7c176dcf4e3bab727fd13e Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Mon, 2 Oct 2023 14:54:10 +0100 Subject: [PATCH 17/40] Deploying via SAM successfully. --- .../kotlin/src/main/java/helloworld/App.java | 107 ------------------ .../kotlin/src/main/kotlin/helloworld/App.kt | 100 ++++++++++++++++ .../helloworld/AppStream.kt} | 35 +++--- .../src/test/kotlin/helloworld/AppTest.kt | 1 + 4 files changed, 118 insertions(+), 125 deletions(-) delete mode 100644 examples/powertools-examples-core/kotlin/src/main/java/helloworld/App.java create mode 100644 examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt rename examples/powertools-examples-core/kotlin/src/main/{java/helloworld/AppStream.java => kotlin/helloworld/AppStream.kt} (53%) diff --git a/examples/powertools-examples-core/kotlin/src/main/java/helloworld/App.java b/examples/powertools-examples-core/kotlin/src/main/java/helloworld/App.java deleted file mode 100644 index fccc63b9a..000000000 --- a/examples/powertools-examples-core/kotlin/src/main/java/helloworld/App.java +++ /dev/null @@ -1,107 +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 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); - - @Logging(logEvent = true, samplingRate = 0.7) - @Tracing(captureMode = CaptureMode.RESPONSE_AND_ERROR) - @Metrics(namespace = "ServerlessAirline", service = "payment", captureColdStart = true) - 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 - private void log() { - log.info("inside threaded logging for function"); - } - - @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/kotlin/src/main/kotlin/helloworld/App.kt b/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt new file mode 100644 index 000000000..1084b5791 --- /dev/null +++ b/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt @@ -0,0 +1,100 @@ +/* + * 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.RequestHandler +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent +import com.amazonaws.xray.entities.Subsegment +import org.apache.logging.log4j.LogManager +import software.amazon.cloudwatchlogs.emf.logger.MetricsLogger +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.metrics.MetricsUtils +import software.amazon.lambda.powertools.tracing.CaptureMode +import software.amazon.lambda.powertools.tracing.Tracing +import software.amazon.lambda.powertools.tracing.TracingUtils +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader +import java.net.URL +import java.util.stream.Collectors + +/** + * Handler for requests to Lambda function. + */ + +// TODO: Update context so not optional - this was changed to satisfy test +class App : RequestHandler { + @Logging(logEvent = true, samplingRate = 0.7) + @Tracing(captureMode = CaptureMode.RESPONSE_AND_ERROR) + @Metrics(namespace = "ServerlessAirline", service = "payment", captureColdStart = true) + override fun handleRequest(input: APIGatewayProxyRequestEvent?, context: Context?): APIGatewayProxyResponseEvent { // changed context to be optional so can pass null from test + val headers: MutableMap = HashMap() + headers["Content-Type"] = "application/json" + headers["X-Custom-Header"] = "application/json" + MetricsUtils.metricsLogger().putMetric("CustomMetric1", 1.0, Unit.COUNT) + MetricsUtils.withSingleMetric("CustomMetrics2", 1.0, Unit.COUNT, "Another") { metric: MetricsLogger -> + metric.setDimensions(DimensionSet.of("AnotherService", "CustomService")) + metric.setDimensions(DimensionSet.of("AnotherService1", "CustomService1")) + } + LoggingUtils.appendKey("test", "willBeLogged") + val response = APIGatewayProxyResponseEvent() + .withHeaders(headers) + return try { + val pageContents = getPageContents("https://checkip.amazonaws.com") + log.info(pageContents) + TracingUtils.putAnnotation("Test", "New") + val output = String.format("{ \"message\": \"hello world\", \"location\": \"%s\" }", pageContents) + TracingUtils.withSubsegment("loggingResponse") { subsegment: Subsegment? -> + val sampled = "log something out" + log.info(sampled) + log.info(output) + } + log.info("After output") + response + .withStatusCode(200) + .withBody(output) + } catch (e: RuntimeException) { + response + .withBody("{}") + .withStatusCode(500) + } catch (e: IOException) { + response + .withBody("{}") + .withStatusCode(500) + } + } + + @Tracing + private fun log() { + log.info("inside threaded logging for function") + } + + @Tracing(namespace = "getPageContents", captureMode = CaptureMode.DISABLED) + @Throws(IOException::class) + private fun getPageContents(address: String): String { + val url = URL(address) + TracingUtils.putMetadata("getPageContents", address) + BufferedReader(InputStreamReader(url.openStream())).use { br -> return br.lines().collect(Collectors.joining(System.lineSeparator())) } + } + + companion object { + private val log = LogManager.getLogger(App::class.java) + } +} diff --git a/examples/powertools-examples-core/kotlin/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/AppStream.kt similarity index 53% rename from examples/powertools-examples-core/kotlin/src/main/java/helloworld/AppStream.java rename to examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/AppStream.kt index 401ef8c48..99f6bbfa0 100644 --- a/examples/powertools-examples-core/kotlin/src/main/java/helloworld/AppStream.java +++ b/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/AppStream.kt @@ -11,28 +11,27 @@ * limitations under the License. * */ +package helloworld -package helloworld; +import com.amazonaws.services.lambda.runtime.Context +import com.amazonaws.services.lambda.runtime.RequestStreamHandler +import com.fasterxml.jackson.databind.ObjectMapper +import software.amazon.lambda.powertools.logging.Logging +import software.amazon.lambda.powertools.metrics.Metrics +import java.io.IOException +import java.io.InputStream +import java.io.OutputStream -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 +class AppStream : RequestStreamHandler { @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); + @Throws(IOException::class) + override fun handleRequest(input: InputStream, output: OutputStream, context: Context) { + val map: Map<*, *> = mapper.readValue(input, MutableMap::class.java) + println(map.size) + } - System.out.println(map.size()); + companion object { + private val mapper = ObjectMapper() } } diff --git a/examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt b/examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt index b137aecce..8aae081e8 100644 --- a/examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt +++ b/examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt @@ -1,5 +1,6 @@ package helloworld + import org.junit.Assert import org.junit.Test From baa0e3f3974530b56e5f280132d8f716b3c35d62 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Tue, 3 Oct 2023 16:46:04 +0100 Subject: [PATCH 18/40] Added Kotlin example. --- examples/powertools-examples-core/README.md | 10 +++++++ .../powertools-examples-core/kotlin/README.md | 6 ++-- .../kotlin/{build.gradle => _build.gradle} | 0 .../kotlin/build.gradle.kts | 28 +++++++++++++++++++ .../kotlin/src/main/kotlin/helloworld/App.kt | 26 ++++++++--------- 5 files changed, 53 insertions(+), 17 deletions(-) rename examples/powertools-examples-core/kotlin/{build.gradle => _build.gradle} (100%) create mode 100644 examples/powertools-examples-core/kotlin/build.gradle.kts diff --git a/examples/powertools-examples-core/README.md b/examples/powertools-examples-core/README.md index 1d1dd031f..f2af999b9 100644 --- a/examples/powertools-examples-core/README.md +++ b/examples/powertools-examples-core/README.md @@ -15,6 +15,7 @@ We also provide an example showing the integration of SAM, Powertools, and Gradl * [AWS SAM with a Gradle build](gradle/) +## Java For each of the tools, the example application is the same, and consists of the following files: - [App.java](sam/src/main/java/helloworld/App.java) - Code for the application's Lambda function. @@ -23,6 +24,15 @@ For each of the tools, the example application is the same, and consists of the Configuration files and deployment process for each tool are described in corresponding README files. +## Kotlin +For each of the tools, the example application is the same, and consists of the following files: + +- [App.kt](kotlin/src/main/kotlin/helloworld/App.kt) - Code for the application's Lambda function. +- [AppTests.kt](kotlin/src/test/kotlin/helloworld/AppTest.kt) - Unit tests for the application code. +- [events](kotlin/events/event.json) - Invocation events that you can use to invoke the function. + +Configuration files and deployment process for each tool are described in corresponding README files. + ## Test the application Once the app is deployed, you can invoke the endpoint like this: diff --git a/examples/powertools-examples-core/kotlin/README.md b/examples/powertools-examples-core/kotlin/README.md index c7c798d5d..6f0510c48 100644 --- a/examples/powertools-examples-core/kotlin/README.md +++ b/examples/powertools-examples-core/kotlin/README.md @@ -1,6 +1,6 @@ -# Powertools for AWS Lambda (Java) - Core Utilities Example with Gradle +# Powertools for AWS Lambda (Kotlin) - Core Utilities Example -This project demonstrates the Lambda for Powertools Java module deployed using [Serverless Application Model](https://aws.amazon.com/serverless/sam/) with +This project demonstrates the Lambda for Powertools Kotlin module deployed using [Serverless Application Model](https://aws.amazon.com/serverless/sam/) with [Gradle](https://gradle.org/) running the build. This example is configured for Java 1.8 only; in order to use a newer version, check out the Gradle configuration guide [in the main project README](../../../README.md). @@ -14,7 +14,7 @@ For general information on the deployed example itself, you can refer to the par SAM uses [template.yaml](template.yaml) to define the application's AWS resources. This file defines the Lambda function to be deployed as well as API Gateway for it. -The build of the project is managed by Gradle, and configured in [build.gradle](build.gradle). +The build of the project is managed by Gradle, and configured in [build.gradle](_build.gradle). ## Deploy the sample application To get started, you can use the Gradle wrapper to bootstrap Gradle and run the build: diff --git a/examples/powertools-examples-core/kotlin/build.gradle b/examples/powertools-examples-core/kotlin/_build.gradle similarity index 100% rename from examples/powertools-examples-core/kotlin/build.gradle rename to examples/powertools-examples-core/kotlin/_build.gradle diff --git a/examples/powertools-examples-core/kotlin/build.gradle.kts b/examples/powertools-examples-core/kotlin/build.gradle.kts new file mode 100644 index 000000000..a1a9e29da --- /dev/null +++ b/examples/powertools-examples-core/kotlin/build.gradle.kts @@ -0,0 +1,28 @@ +plugins { + java + id("io.freefair.aspectj.post-compile-weaving") version "6.6.3" + kotlin("jvm") version "1.9.10" +} + +repositories { + mavenCentral() +} + +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") + aspect("software.amazon.lambda:powertools-tracing:1.17.0") + aspect("software.amazon.lambda:powertools-logging:1.17.0") + aspect("software.amazon.lambda:powertools-metrics:1.17.0") + testImplementation("junit:junit:4.13.2") + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") +} + +tasks.compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} diff --git a/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt b/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt index 1084b5791..5b6a45ce8 100644 --- a/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt +++ b/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt @@ -39,12 +39,12 @@ import java.util.stream.Collectors * Handler for requests to Lambda function. */ -// TODO: Update context so not optional - this was changed to satisfy test class App : RequestHandler { @Logging(logEvent = true, samplingRate = 0.7) @Tracing(captureMode = CaptureMode.RESPONSE_AND_ERROR) @Metrics(namespace = "ServerlessAirline", service = "payment", captureColdStart = true) - override fun handleRequest(input: APIGatewayProxyRequestEvent?, context: Context?): APIGatewayProxyResponseEvent { // changed context to be optional so can pass null from test + + override fun handleRequest(input: APIGatewayProxyRequestEvent?, context: Context?): APIGatewayProxyResponseEvent { // changed context to be optional so can pass null val headers: MutableMap = HashMap() headers["Content-Type"] = "application/json" headers["X-Custom-Header"] = "application/json" @@ -54,30 +54,28 @@ class App : RequestHandler val sampled = "log something out" log.info(sampled) log.info(output) } log.info("After output") - response - .withStatusCode(200) - .withBody(output) + response.withStatusCode(200).withBody(output) } catch (e: RuntimeException) { - response - .withBody("{}") - .withStatusCode(500) + response.withBody("{}").withStatusCode(500) } catch (e: IOException) { - response - .withBody("{}") - .withStatusCode(500) + response.withBody("{}").withStatusCode(500) } } From 16380a89bb27c72d8dd49a12282d6e16d96d258c Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Tue, 3 Oct 2023 16:55:55 +0100 Subject: [PATCH 19/40] Removing unused Gradle build file. --- .../kotlin/_build.gradle | 47 ------------------- .../kotlin/build.gradle.kts | 1 - 2 files changed, 48 deletions(-) delete mode 100644 examples/powertools-examples-core/kotlin/_build.gradle diff --git a/examples/powertools-examples-core/kotlin/_build.gradle b/examples/powertools-examples-core/kotlin/_build.gradle deleted file mode 100644 index 885de6f43..000000000 --- a/examples/powertools-examples-core/kotlin/_build.gradle +++ /dev/null @@ -1,47 +0,0 @@ - -plugins { - id 'java' - id "io.freefair.aspectj.post-compile-weaving" version "6.6.3" - id 'org.jetbrains.kotlin.jvm' version '1.9.10' -} - -wrapper { - gradleVersion = "7.6.1" -} - -compileJava { - sourceCompatibility = "1.8" - targetCompatibility = "1.8" - - ajc { - enabled = true - } -} - -repositories { - mavenCentral() -} - -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' - aspect 'software.amazon.lambda:powertools-tracing:1.17.0' - aspect 'software.amazon.lambda:powertools-logging:1.17.0' - aspect 'software.amazon.lambda:powertools-metrics:1.17.0' - testImplementation 'junit:junit:4.13.2' - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" -} -compileKotlin { - kotlinOptions { - jvmTarget = "1.8" - } -} -compileTestKotlin { - kotlinOptions { - jvmTarget = "1.8" - } -} - diff --git a/examples/powertools-examples-core/kotlin/build.gradle.kts b/examples/powertools-examples-core/kotlin/build.gradle.kts index a1a9e29da..81237f07a 100644 --- a/examples/powertools-examples-core/kotlin/build.gradle.kts +++ b/examples/powertools-examples-core/kotlin/build.gradle.kts @@ -1,5 +1,4 @@ plugins { - java id("io.freefair.aspectj.post-compile-weaving") version "6.6.3" kotlin("jvm") version "1.9.10" } From 3f3f4e8b43129b23197a4e40974745224fd3746f Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Wed, 4 Oct 2023 13:54:01 +0100 Subject: [PATCH 20/40] Adding SAM template so can be used as an existing project and Java target compatibility --- .../kotlin/build.gradle.kts | 4 ++ .../kotlin/template.yaml | 71 ------------------- 2 files changed, 4 insertions(+), 71 deletions(-) delete mode 100644 examples/powertools-examples-core/kotlin/template.yaml diff --git a/examples/powertools-examples-core/kotlin/build.gradle.kts b/examples/powertools-examples-core/kotlin/build.gradle.kts index 81237f07a..b89b93526 100644 --- a/examples/powertools-examples-core/kotlin/build.gradle.kts +++ b/examples/powertools-examples-core/kotlin/build.gradle.kts @@ -25,3 +25,7 @@ tasks.compileKotlin { jvmTarget = "1.8" } } + +java { + targetCompatibility = JavaVersion.VERSION_1_8 +} diff --git a/examples/powertools-examples-core/kotlin/template.yaml b/examples/powertools-examples-core/kotlin/template.yaml deleted file mode 100644 index a717c2998..000000000 --- a/examples/powertools-examples-core/kotlin/template.yaml +++ /dev/null @@ -1,71 +0,0 @@ -AWSTemplateFormatVersion: '2010-09-09' -Transform: AWS::Serverless-2016-10-31 -Description: > - gradle - - Sample SAM Template for gradle - -# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst -Globals: - Function: - Timeout: 20 - Runtime: java11 - MemorySize: 512 - Tracing: Active # https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html - Environment: - Variables: - # Powertools for AWS Lambda (Java) env vars: https://docs.powertools.aws.dev/lambda/java/#environment-variables - POWERTOOLS_LOG_LEVEL: INFO - POWERTOOLS_LOGGER_SAMPLE_RATE: 0.1 - POWERTOOLS_LOGGER_LOG_EVENT: true - POWERTOOLS_METRICS_NAMESPACE: Coreutilities - -Resources: - HelloWorldFunction: - Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction - Properties: - CodeUri: . - Handler: helloworld.App::handleRequest - Runtime: java8 - MemorySize: 512 - Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object - Variables: - POWERTOOLS_SERVICE_NAME: hello - Events: - HelloWorld: - Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api - Properties: - Path: /hello - Method: get - - HelloWorldStreamFunction: - Type: AWS::Serverless::Function - Properties: - CodeUri: . - Handler: helloworld.AppStream::handleRequest - Runtime: java8 - MemorySize: 512 - Tracing: Active - Environment: - Variables: - POWERTOOLS_LOGGER_SAMPLE_RATE: 0.7 - Events: - HelloWorld: - Type: Api - Properties: - Path: /hellostream - Method: get - -Outputs: - # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function - # Find out more about other implicit resources you can reference within SAM - # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api - HelloWorldApi: - Description: "API Gateway endpoint URL for Prod stage for Hello World function" - Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/" - HelloWorldFunction: - Description: "Hello World Lambda Function ARN" - Value: !GetAtt HelloWorldFunction.Arn - HelloWorldFunctionIamRole: - Description: "Implicit IAM Role created for Hello World function" - Value: !GetAtt HelloWorldFunctionRole.Arn From 9d70b5791194972dec1673c0338b8c8635de2168 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Wed, 4 Oct 2023 13:57:03 +0100 Subject: [PATCH 21/40] Adding SAM template so can be used as an existing project --- .../kotlin/template.yaml | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 examples/powertools-examples-core/kotlin/template.yaml diff --git a/examples/powertools-examples-core/kotlin/template.yaml b/examples/powertools-examples-core/kotlin/template.yaml new file mode 100644 index 000000000..1a1572fca --- /dev/null +++ b/examples/powertools-examples-core/kotlin/template.yaml @@ -0,0 +1,71 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + gradle + + Sample SAM Template for gradle + +# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst +Globals: + Function: + Timeout: 20 + Runtime: java11 + MemorySize: 512 + Tracing: Active # https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html + Environment: + Variables: + # Powertools for AWS Lambda (Java) env vars: https://docs.powertools.aws.dev/lambda/java/#environment-variables + POWERTOOLS_LOG_LEVEL: INFO + POWERTOOLS_LOGGER_SAMPLE_RATE: 0.1 + POWERTOOLS_LOGGER_LOG_EVENT: true + POWERTOOLS_METRICS_NAMESPACE: Coreutilities + +Resources: + HelloWorldFunction: + Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction + Properties: + CodeUri: . + Handler: helloworld.App::handleRequest + Runtime: java11 + MemorySize: 512 + Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object + Variables: + POWERTOOLS_SERVICE_NAME: hello + Events: + HelloWorld: + Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api + Properties: + Path: /hello + Method: get + + HelloWorldStreamFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: . + Handler: helloworld.AppStream::handleRequest + Runtime: java11 + MemorySize: 512 + Tracing: Active + Environment: + Variables: + POWERTOOLS_LOGGER_SAMPLE_RATE: 0.7 + Events: + HelloWorld: + Type: Api + Properties: + Path: /hellostream + Method: get + +Outputs: + # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function + # Find out more about other implicit resources you can reference within SAM + # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api + HelloWorldApi: + Description: "API Gateway endpoint URL for Prod stage for Hello World function" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/" + HelloWorldFunction: + Description: "Hello World Lambda Function ARN" + Value: !GetAtt HelloWorldFunction.Arn + HelloWorldFunctionIamRole: + Description: "Implicit IAM Role created for Hello World function" + Value: !GetAtt HelloWorldFunctionRole.Arn From bcff275fd3ce72a75c9da9e0e5e2b059ae37309d Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Wed, 4 Oct 2023 15:19:15 +0100 Subject: [PATCH 22/40] Updating guidance to use SAM for build and deploy --- examples/powertools-examples-core/kotlin/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/powertools-examples-core/kotlin/README.md b/examples/powertools-examples-core/kotlin/README.md index 6f0510c48..ac1138f4d 100644 --- a/examples/powertools-examples-core/kotlin/README.md +++ b/examples/powertools-examples-core/kotlin/README.md @@ -7,7 +7,6 @@ configuration guide [in the main project README](../../../README.md). You can also use `sam init` to create a new Gradle-powered Powertools application - choose to use the **AWS Quick Start Templates**, and then **Hello World Example with Powertools for AWS Lambda**, **Java 17** runtime, and finally **gradle**. - For general information on the deployed example itself, you can refer to the parent [README](../README.md) ## Configuration @@ -17,10 +16,10 @@ This file defines the Lambda function to be deployed as well as API Gateway for The build of the project is managed by Gradle, and configured in [build.gradle](_build.gradle). ## Deploy the sample application -To get started, you can use the Gradle wrapper to bootstrap Gradle and run the build: +To get started, you can use the included template with SAM to run the build and deploy to your AWS environment: ```bash -./gradlew build +sam build && sam deploy --guided ``` Once this is done to deploy the example, check out the instructions for getting started with SAM in From 84935c976e9c5750ca608debbf462c4d604b8222 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Wed, 4 Oct 2023 15:29:52 +0100 Subject: [PATCH 23/40] Restructuring separate Java and Kotlin examples. --- examples/README.md | 2 +- .../{ => java}/cdk/README.md | 8 ++++---- .../{ => java}/cdk/app/events/event.json | 0 .../{ => java}/cdk/app/pom.xml | 0 .../cdk/app/src/main/java/helloworld/App.java | 0 .../cdk/app/src/main/java/helloworld/AppStream.java | 0 .../cdk/app/src/main/resources/log4j2.xml | 0 .../cdk/app/src/test/java/helloworld/AppTest.java | 0 .../{ => java}/cdk/infra/cdk.json | 0 .../{ => java}/cdk/infra/pom.xml | 0 .../cdk/infra/src/main/java/cdk/CdkApp.java | 0 .../cdk/infra/src/main/java/cdk/CdkStack.java | 0 .../cdk/infra/src/test/java/cdk/CdkStackTest.java | 0 .../{ => java}/gradle/README.md | 6 +++--- .../{ => java}/gradle/build.gradle | 0 .../{ => java}/gradle/events/event.json | 0 .../{ => java}/gradle/gradle/wrapper/.gitignore | 0 .../gradle/gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/gradle/wrapper/gradle-wrapper.properties | 0 .../{ => java}/gradle/gradlew | 0 .../{ => java}/gradle/gradlew.bat | 0 .../gradle/src/main/java/helloworld/App.java | 0 .../gradle/src/main/java/helloworld/AppStream.java | 0 .../gradle/src/test/java/helloworld/AppTest.java | 0 .../{ => java}/gradle/template.yaml | 0 .../{ => java}/sam/README.md | 4 ++-- .../{ => java}/sam/events/event.json | 0 .../powertools-examples-core/{ => java}/sam/pom.xml | 0 .../sam/src/main/java/helloworld/App.java | 0 .../sam/src/main/java/helloworld/AppStream.java | 0 .../{ => java}/sam/src/main/resources/log4j2.xml | 0 .../sam/src/test/java/helloworld/AppTest.java | 0 .../{ => java}/sam/template.yaml | 0 .../{ => java}/serverless/README.md | 4 ++-- .../{ => java}/serverless/pom.xml | 0 .../{ => java}/serverless/serverless.yml | 0 .../serverless/src/main/java/helloworld/App.java | 0 .../src/main/java/helloworld/AppStream.java | 0 .../serverless/src/main/resources/log4j2.xml | 0 .../src/test/java/helloworld/AppTest.java | 0 .../kotlin/{ => gradle}/README.md | 6 +++--- .../kotlin/{ => gradle}/build.gradle.kts | 0 .../kotlin/{ => gradle}/events/event.json | 0 .../kotlin/gradle/{ => gradle}/wrapper/.gitignore | 0 .../gradle/{ => gradle}/wrapper/gradle-wrapper.jar | Bin .../{ => gradle}/wrapper/gradle-wrapper.properties | 0 .../kotlin/{ => gradle}/gradlew | 0 .../kotlin/{ => gradle}/gradlew.bat | 0 .../{ => gradle}/src/main/kotlin/helloworld/App.kt | 0 .../src/main/kotlin/helloworld/AppStream.kt | 0 .../src/test/kotlin/helloworld/AppTest.kt | 0 .../kotlin/{ => gradle}/template.yaml | 0 52 files changed, 15 insertions(+), 15 deletions(-) rename examples/powertools-examples-core/{ => java}/cdk/README.md (81%) rename examples/powertools-examples-core/{ => java}/cdk/app/events/event.json (100%) rename examples/powertools-examples-core/{ => java}/cdk/app/pom.xml (100%) rename examples/powertools-examples-core/{ => java}/cdk/app/src/main/java/helloworld/App.java (100%) rename examples/powertools-examples-core/{ => java}/cdk/app/src/main/java/helloworld/AppStream.java (100%) rename examples/powertools-examples-core/{ => java}/cdk/app/src/main/resources/log4j2.xml (100%) rename examples/powertools-examples-core/{ => java}/cdk/app/src/test/java/helloworld/AppTest.java (100%) rename examples/powertools-examples-core/{ => java}/cdk/infra/cdk.json (100%) rename examples/powertools-examples-core/{ => java}/cdk/infra/pom.xml (100%) rename examples/powertools-examples-core/{ => java}/cdk/infra/src/main/java/cdk/CdkApp.java (100%) rename examples/powertools-examples-core/{ => java}/cdk/infra/src/main/java/cdk/CdkStack.java (100%) rename examples/powertools-examples-core/{ => java}/cdk/infra/src/test/java/cdk/CdkStackTest.java (100%) rename examples/powertools-examples-core/{ => java}/gradle/README.md (89%) rename examples/powertools-examples-core/{ => java}/gradle/build.gradle (100%) rename examples/powertools-examples-core/{ => java}/gradle/events/event.json (100%) rename examples/powertools-examples-core/{ => java}/gradle/gradle/wrapper/.gitignore (100%) rename examples/powertools-examples-core/{ => java}/gradle/gradle/wrapper/gradle-wrapper.jar (100%) rename examples/powertools-examples-core/{ => java}/gradle/gradle/wrapper/gradle-wrapper.properties (100%) rename examples/powertools-examples-core/{ => java}/gradle/gradlew (100%) rename examples/powertools-examples-core/{ => java}/gradle/gradlew.bat (100%) rename examples/powertools-examples-core/{ => java}/gradle/src/main/java/helloworld/App.java (100%) rename examples/powertools-examples-core/{ => java}/gradle/src/main/java/helloworld/AppStream.java (100%) rename examples/powertools-examples-core/{ => java}/gradle/src/test/java/helloworld/AppTest.java (100%) rename examples/powertools-examples-core/{ => java}/gradle/template.yaml (100%) rename examples/powertools-examples-core/{ => java}/sam/README.md (87%) rename examples/powertools-examples-core/{ => java}/sam/events/event.json (100%) rename examples/powertools-examples-core/{ => java}/sam/pom.xml (100%) rename examples/powertools-examples-core/{ => java}/sam/src/main/java/helloworld/App.java (100%) rename examples/powertools-examples-core/{ => java}/sam/src/main/java/helloworld/AppStream.java (100%) rename examples/powertools-examples-core/{ => java}/sam/src/main/resources/log4j2.xml (100%) rename examples/powertools-examples-core/{ => java}/sam/src/test/java/helloworld/AppTest.java (100%) rename examples/powertools-examples-core/{ => java}/sam/template.yaml (100%) rename examples/powertools-examples-core/{ => java}/serverless/README.md (86%) rename examples/powertools-examples-core/{ => java}/serverless/pom.xml (100%) rename examples/powertools-examples-core/{ => java}/serverless/serverless.yml (100%) rename examples/powertools-examples-core/{ => java}/serverless/src/main/java/helloworld/App.java (100%) rename examples/powertools-examples-core/{ => java}/serverless/src/main/java/helloworld/AppStream.java (100%) rename examples/powertools-examples-core/{ => java}/serverless/src/main/resources/log4j2.xml (100%) rename examples/powertools-examples-core/{ => java}/serverless/src/test/java/helloworld/AppTest.java (100%) rename examples/powertools-examples-core/kotlin/{ => gradle}/README.md (89%) rename examples/powertools-examples-core/kotlin/{ => gradle}/build.gradle.kts (100%) rename examples/powertools-examples-core/kotlin/{ => gradle}/events/event.json (100%) rename examples/powertools-examples-core/kotlin/gradle/{ => gradle}/wrapper/.gitignore (100%) rename examples/powertools-examples-core/kotlin/gradle/{ => gradle}/wrapper/gradle-wrapper.jar (100%) rename examples/powertools-examples-core/kotlin/gradle/{ => gradle}/wrapper/gradle-wrapper.properties (100%) rename examples/powertools-examples-core/kotlin/{ => gradle}/gradlew (100%) rename examples/powertools-examples-core/kotlin/{ => gradle}/gradlew.bat (100%) rename examples/powertools-examples-core/kotlin/{ => gradle}/src/main/kotlin/helloworld/App.kt (100%) rename examples/powertools-examples-core/kotlin/{ => gradle}/src/main/kotlin/helloworld/AppStream.kt (100%) rename examples/powertools-examples-core/kotlin/{ => gradle}/src/test/kotlin/helloworld/AppTest.kt (100%) rename examples/powertools-examples-core/kotlin/{ => gradle}/template.yaml (100%) diff --git a/examples/README.md b/examples/README.md index 52dc0c1e9..73dc7a1bf 100644 --- a/examples/README.md +++ b/examples/README.md @@ -7,7 +7,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) + * [CDK](powertools-examples-core/java/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 diff --git a/examples/powertools-examples-core/cdk/README.md b/examples/powertools-examples-core/java/cdk/README.md similarity index 81% rename from examples/powertools-examples-core/cdk/README.md rename to examples/powertools-examples-core/java/cdk/README.md index f15a24168..f53936b40 100644 --- a/examples/powertools-examples-core/cdk/README.md +++ b/examples/powertools-examples-core/java/cdk/README.md @@ -2,13 +2,13 @@ This project demonstrates the Lambda for Powertools Java module deployed using [Cloud Development Kit](https://aws.amazon.com/cdk/). -For general information on the deployed example itself, you can refer to the parent [README](../README.md) +For general information on the deployed example itself, you can refer to the parent [README](../../README.md) ## Configuration CDK uses the following project structure: -- [app](./app) - stores the source code of your application, which is similar between all examples -- [infra](./infra) - stores the definition of your infrastructure - - [cdk.json](./infra/cdk.json) - tells the CDK Toolkit how to execute your app +- [app](app) - stores the source code of your application, which is similar between all examples +- [infra](infra) - stores the definition of your infrastructure + - [cdk.json](infra/cdk.json) - tells the CDK Toolkit how to execute your app - [CdkApp](./infra/src/main/java/cdk/CdkApp.java) - bootstraps your stack, taking AWS `account` and `region` as input - [CdkStack](./infra/src/main/java/cdk/CdkStack.java) - defines the Lambda function to be deployed as well as API Gateway for it. diff --git a/examples/powertools-examples-core/cdk/app/events/event.json b/examples/powertools-examples-core/java/cdk/app/events/event.json similarity index 100% rename from examples/powertools-examples-core/cdk/app/events/event.json rename to examples/powertools-examples-core/java/cdk/app/events/event.json diff --git a/examples/powertools-examples-core/cdk/app/pom.xml b/examples/powertools-examples-core/java/cdk/app/pom.xml similarity index 100% rename from examples/powertools-examples-core/cdk/app/pom.xml rename to examples/powertools-examples-core/java/cdk/app/pom.xml diff --git a/examples/powertools-examples-core/cdk/app/src/main/java/helloworld/App.java b/examples/powertools-examples-core/java/cdk/app/src/main/java/helloworld/App.java similarity index 100% rename from examples/powertools-examples-core/cdk/app/src/main/java/helloworld/App.java rename to examples/powertools-examples-core/java/cdk/app/src/main/java/helloworld/App.java diff --git a/examples/powertools-examples-core/cdk/app/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/java/cdk/app/src/main/java/helloworld/AppStream.java similarity index 100% rename from examples/powertools-examples-core/cdk/app/src/main/java/helloworld/AppStream.java rename to examples/powertools-examples-core/java/cdk/app/src/main/java/helloworld/AppStream.java diff --git a/examples/powertools-examples-core/cdk/app/src/main/resources/log4j2.xml b/examples/powertools-examples-core/java/cdk/app/src/main/resources/log4j2.xml similarity index 100% rename from examples/powertools-examples-core/cdk/app/src/main/resources/log4j2.xml rename to examples/powertools-examples-core/java/cdk/app/src/main/resources/log4j2.xml diff --git a/examples/powertools-examples-core/cdk/app/src/test/java/helloworld/AppTest.java b/examples/powertools-examples-core/java/cdk/app/src/test/java/helloworld/AppTest.java similarity index 100% rename from examples/powertools-examples-core/cdk/app/src/test/java/helloworld/AppTest.java rename to examples/powertools-examples-core/java/cdk/app/src/test/java/helloworld/AppTest.java diff --git a/examples/powertools-examples-core/cdk/infra/cdk.json b/examples/powertools-examples-core/java/cdk/infra/cdk.json similarity index 100% rename from examples/powertools-examples-core/cdk/infra/cdk.json rename to examples/powertools-examples-core/java/cdk/infra/cdk.json diff --git a/examples/powertools-examples-core/cdk/infra/pom.xml b/examples/powertools-examples-core/java/cdk/infra/pom.xml similarity index 100% rename from examples/powertools-examples-core/cdk/infra/pom.xml rename to examples/powertools-examples-core/java/cdk/infra/pom.xml diff --git a/examples/powertools-examples-core/cdk/infra/src/main/java/cdk/CdkApp.java b/examples/powertools-examples-core/java/cdk/infra/src/main/java/cdk/CdkApp.java similarity index 100% rename from examples/powertools-examples-core/cdk/infra/src/main/java/cdk/CdkApp.java rename to examples/powertools-examples-core/java/cdk/infra/src/main/java/cdk/CdkApp.java diff --git a/examples/powertools-examples-core/cdk/infra/src/main/java/cdk/CdkStack.java b/examples/powertools-examples-core/java/cdk/infra/src/main/java/cdk/CdkStack.java similarity index 100% rename from examples/powertools-examples-core/cdk/infra/src/main/java/cdk/CdkStack.java rename to examples/powertools-examples-core/java/cdk/infra/src/main/java/cdk/CdkStack.java diff --git a/examples/powertools-examples-core/cdk/infra/src/test/java/cdk/CdkStackTest.java b/examples/powertools-examples-core/java/cdk/infra/src/test/java/cdk/CdkStackTest.java similarity index 100% rename from examples/powertools-examples-core/cdk/infra/src/test/java/cdk/CdkStackTest.java rename to examples/powertools-examples-core/java/cdk/infra/src/test/java/cdk/CdkStackTest.java diff --git a/examples/powertools-examples-core/gradle/README.md b/examples/powertools-examples-core/java/gradle/README.md similarity index 89% rename from examples/powertools-examples-core/gradle/README.md rename to examples/powertools-examples-core/java/gradle/README.md index c7c798d5d..a13e8fd3d 100644 --- a/examples/powertools-examples-core/gradle/README.md +++ b/examples/powertools-examples-core/java/gradle/README.md @@ -2,13 +2,13 @@ This project demonstrates the Lambda for Powertools Java module deployed using [Serverless Application Model](https://aws.amazon.com/serverless/sam/) with [Gradle](https://gradle.org/) running the build. This example is configured for Java 1.8 only; in order to use a newer version, check out the Gradle -configuration guide [in the main project README](../../../README.md). +configuration guide [in the main project README](../../../../README.md). You can also use `sam init` to create a new Gradle-powered Powertools application - choose to use the **AWS Quick Start Templates**, and then **Hello World Example with Powertools for AWS Lambda**, **Java 17** runtime, and finally **gradle**. -For general information on the deployed example itself, you can refer to the parent [README](../README.md) +For general information on the deployed example itself, you can refer to the parent [README](../../README.md) ## Configuration SAM uses [template.yaml](template.yaml) to define the application's AWS resources. @@ -24,7 +24,7 @@ To get started, you can use the Gradle wrapper to bootstrap Gradle and run the b ``` Once this is done to deploy the example, check out the instructions for getting started with SAM in -[the examples directory](../../README.md) +[the examples directory](../../../README.md) ## Additional notes diff --git a/examples/powertools-examples-core/gradle/build.gradle b/examples/powertools-examples-core/java/gradle/build.gradle similarity index 100% rename from examples/powertools-examples-core/gradle/build.gradle rename to examples/powertools-examples-core/java/gradle/build.gradle diff --git a/examples/powertools-examples-core/gradle/events/event.json b/examples/powertools-examples-core/java/gradle/events/event.json similarity index 100% rename from examples/powertools-examples-core/gradle/events/event.json rename to examples/powertools-examples-core/java/gradle/events/event.json diff --git a/examples/powertools-examples-core/gradle/gradle/wrapper/.gitignore b/examples/powertools-examples-core/java/gradle/gradle/wrapper/.gitignore similarity index 100% rename from examples/powertools-examples-core/gradle/gradle/wrapper/.gitignore rename to examples/powertools-examples-core/java/gradle/gradle/wrapper/.gitignore diff --git a/examples/powertools-examples-core/gradle/gradle/wrapper/gradle-wrapper.jar b/examples/powertools-examples-core/java/gradle/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from examples/powertools-examples-core/gradle/gradle/wrapper/gradle-wrapper.jar rename to examples/powertools-examples-core/java/gradle/gradle/wrapper/gradle-wrapper.jar diff --git a/examples/powertools-examples-core/gradle/gradle/wrapper/gradle-wrapper.properties b/examples/powertools-examples-core/java/gradle/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from examples/powertools-examples-core/gradle/gradle/wrapper/gradle-wrapper.properties rename to examples/powertools-examples-core/java/gradle/gradle/wrapper/gradle-wrapper.properties diff --git a/examples/powertools-examples-core/gradle/gradlew b/examples/powertools-examples-core/java/gradle/gradlew similarity index 100% rename from examples/powertools-examples-core/gradle/gradlew rename to examples/powertools-examples-core/java/gradle/gradlew diff --git a/examples/powertools-examples-core/gradle/gradlew.bat b/examples/powertools-examples-core/java/gradle/gradlew.bat similarity index 100% rename from examples/powertools-examples-core/gradle/gradlew.bat rename to examples/powertools-examples-core/java/gradle/gradlew.bat diff --git a/examples/powertools-examples-core/gradle/src/main/java/helloworld/App.java b/examples/powertools-examples-core/java/gradle/src/main/java/helloworld/App.java similarity index 100% rename from examples/powertools-examples-core/gradle/src/main/java/helloworld/App.java rename to examples/powertools-examples-core/java/gradle/src/main/java/helloworld/App.java diff --git a/examples/powertools-examples-core/gradle/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/java/gradle/src/main/java/helloworld/AppStream.java similarity index 100% rename from examples/powertools-examples-core/gradle/src/main/java/helloworld/AppStream.java rename to examples/powertools-examples-core/java/gradle/src/main/java/helloworld/AppStream.java diff --git a/examples/powertools-examples-core/gradle/src/test/java/helloworld/AppTest.java b/examples/powertools-examples-core/java/gradle/src/test/java/helloworld/AppTest.java similarity index 100% rename from examples/powertools-examples-core/gradle/src/test/java/helloworld/AppTest.java rename to examples/powertools-examples-core/java/gradle/src/test/java/helloworld/AppTest.java diff --git a/examples/powertools-examples-core/gradle/template.yaml b/examples/powertools-examples-core/java/gradle/template.yaml similarity index 100% rename from examples/powertools-examples-core/gradle/template.yaml rename to examples/powertools-examples-core/java/gradle/template.yaml diff --git a/examples/powertools-examples-core/sam/README.md b/examples/powertools-examples-core/java/sam/README.md similarity index 87% rename from examples/powertools-examples-core/sam/README.md rename to examples/powertools-examples-core/java/sam/README.md index 7a4279ae3..3b8c31ebc 100644 --- a/examples/powertools-examples-core/sam/README.md +++ b/examples/powertools-examples-core/java/sam/README.md @@ -2,7 +2,7 @@ This project demonstrates the Lambda for Powertools Java module deployed using [Serverless Application Model](https://aws.amazon.com/serverless/sam/). -For general information on the deployed example itself, you can refer to the parent [README](../README.md) +For general information on the deployed example itself, you can refer to the parent [README](../../README.md) ## Configuration SAM uses [template.yaml](template.yaml) to define the application's AWS resources. @@ -10,7 +10,7 @@ This file defines the Lambda function to be deployed as well as API Gateway for ## Deploy the sample application To deploy the example, check out the instructions for getting -started with SAM in [the examples directory](../../README.md) +started with SAM in [the examples directory](../../../README.md) ## Additional notes diff --git a/examples/powertools-examples-core/sam/events/event.json b/examples/powertools-examples-core/java/sam/events/event.json similarity index 100% rename from examples/powertools-examples-core/sam/events/event.json rename to examples/powertools-examples-core/java/sam/events/event.json diff --git a/examples/powertools-examples-core/sam/pom.xml b/examples/powertools-examples-core/java/sam/pom.xml similarity index 100% rename from examples/powertools-examples-core/sam/pom.xml rename to examples/powertools-examples-core/java/sam/pom.xml diff --git a/examples/powertools-examples-core/sam/src/main/java/helloworld/App.java b/examples/powertools-examples-core/java/sam/src/main/java/helloworld/App.java similarity index 100% rename from examples/powertools-examples-core/sam/src/main/java/helloworld/App.java rename to examples/powertools-examples-core/java/sam/src/main/java/helloworld/App.java diff --git a/examples/powertools-examples-core/sam/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/java/sam/src/main/java/helloworld/AppStream.java similarity index 100% rename from examples/powertools-examples-core/sam/src/main/java/helloworld/AppStream.java rename to examples/powertools-examples-core/java/sam/src/main/java/helloworld/AppStream.java diff --git a/examples/powertools-examples-core/sam/src/main/resources/log4j2.xml b/examples/powertools-examples-core/java/sam/src/main/resources/log4j2.xml similarity index 100% rename from examples/powertools-examples-core/sam/src/main/resources/log4j2.xml rename to examples/powertools-examples-core/java/sam/src/main/resources/log4j2.xml diff --git a/examples/powertools-examples-core/sam/src/test/java/helloworld/AppTest.java b/examples/powertools-examples-core/java/sam/src/test/java/helloworld/AppTest.java similarity index 100% rename from examples/powertools-examples-core/sam/src/test/java/helloworld/AppTest.java rename to examples/powertools-examples-core/java/sam/src/test/java/helloworld/AppTest.java diff --git a/examples/powertools-examples-core/sam/template.yaml b/examples/powertools-examples-core/java/sam/template.yaml similarity index 100% rename from examples/powertools-examples-core/sam/template.yaml rename to examples/powertools-examples-core/java/sam/template.yaml diff --git a/examples/powertools-examples-core/serverless/README.md b/examples/powertools-examples-core/java/serverless/README.md similarity index 86% rename from examples/powertools-examples-core/serverless/README.md rename to examples/powertools-examples-core/java/serverless/README.md index aec093182..d97e7465a 100644 --- a/examples/powertools-examples-core/serverless/README.md +++ b/examples/powertools-examples-core/java/serverless/README.md @@ -1,11 +1,11 @@ # 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). +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. +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. diff --git a/examples/powertools-examples-core/serverless/pom.xml b/examples/powertools-examples-core/java/serverless/pom.xml similarity index 100% rename from examples/powertools-examples-core/serverless/pom.xml rename to examples/powertools-examples-core/java/serverless/pom.xml diff --git a/examples/powertools-examples-core/serverless/serverless.yml b/examples/powertools-examples-core/java/serverless/serverless.yml similarity index 100% rename from examples/powertools-examples-core/serverless/serverless.yml rename to examples/powertools-examples-core/java/serverless/serverless.yml diff --git a/examples/powertools-examples-core/serverless/src/main/java/helloworld/App.java b/examples/powertools-examples-core/java/serverless/src/main/java/helloworld/App.java similarity index 100% rename from examples/powertools-examples-core/serverless/src/main/java/helloworld/App.java rename to examples/powertools-examples-core/java/serverless/src/main/java/helloworld/App.java diff --git a/examples/powertools-examples-core/serverless/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/java/serverless/src/main/java/helloworld/AppStream.java similarity index 100% rename from examples/powertools-examples-core/serverless/src/main/java/helloworld/AppStream.java rename to examples/powertools-examples-core/java/serverless/src/main/java/helloworld/AppStream.java diff --git a/examples/powertools-examples-core/serverless/src/main/resources/log4j2.xml b/examples/powertools-examples-core/java/serverless/src/main/resources/log4j2.xml similarity index 100% rename from examples/powertools-examples-core/serverless/src/main/resources/log4j2.xml rename to examples/powertools-examples-core/java/serverless/src/main/resources/log4j2.xml diff --git a/examples/powertools-examples-core/serverless/src/test/java/helloworld/AppTest.java b/examples/powertools-examples-core/java/serverless/src/test/java/helloworld/AppTest.java similarity index 100% rename from examples/powertools-examples-core/serverless/src/test/java/helloworld/AppTest.java rename to examples/powertools-examples-core/java/serverless/src/test/java/helloworld/AppTest.java diff --git a/examples/powertools-examples-core/kotlin/README.md b/examples/powertools-examples-core/kotlin/gradle/README.md similarity index 89% rename from examples/powertools-examples-core/kotlin/README.md rename to examples/powertools-examples-core/kotlin/gradle/README.md index ac1138f4d..14059f178 100644 --- a/examples/powertools-examples-core/kotlin/README.md +++ b/examples/powertools-examples-core/kotlin/gradle/README.md @@ -2,12 +2,12 @@ This project demonstrates the Lambda for Powertools Kotlin module deployed using [Serverless Application Model](https://aws.amazon.com/serverless/sam/) with [Gradle](https://gradle.org/) running the build. This example is configured for Java 1.8 only; in order to use a newer version, check out the Gradle -configuration guide [in the main project README](../../../README.md). +configuration guide [in the main project README](../../../../README.md). You can also use `sam init` to create a new Gradle-powered Powertools application - choose to use the **AWS Quick Start Templates**, and then **Hello World Example with Powertools for AWS Lambda**, **Java 17** runtime, and finally **gradle**. -For general information on the deployed example itself, you can refer to the parent [README](../README.md) +For general information on the deployed example itself, you can refer to the parent [README](../../README.md) ## Configuration SAM uses [template.yaml](template.yaml) to define the application's AWS resources. @@ -23,7 +23,7 @@ sam build && sam deploy --guided ``` Once this is done to deploy the example, check out the instructions for getting started with SAM in -[the examples directory](../../README.md) +[the examples directory](../../../README.md) ## Additional notes diff --git a/examples/powertools-examples-core/kotlin/build.gradle.kts b/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts similarity index 100% rename from examples/powertools-examples-core/kotlin/build.gradle.kts rename to examples/powertools-examples-core/kotlin/gradle/build.gradle.kts diff --git a/examples/powertools-examples-core/kotlin/events/event.json b/examples/powertools-examples-core/kotlin/gradle/events/event.json similarity index 100% rename from examples/powertools-examples-core/kotlin/events/event.json rename to examples/powertools-examples-core/kotlin/gradle/events/event.json diff --git a/examples/powertools-examples-core/kotlin/gradle/wrapper/.gitignore b/examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/.gitignore similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/wrapper/.gitignore rename to examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/.gitignore diff --git a/examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.jar b/examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.jar rename to examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/gradle-wrapper.jar diff --git a/examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.properties b/examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.properties rename to examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/gradle-wrapper.properties diff --git a/examples/powertools-examples-core/kotlin/gradlew b/examples/powertools-examples-core/kotlin/gradle/gradlew similarity index 100% rename from examples/powertools-examples-core/kotlin/gradlew rename to examples/powertools-examples-core/kotlin/gradle/gradlew diff --git a/examples/powertools-examples-core/kotlin/gradlew.bat b/examples/powertools-examples-core/kotlin/gradle/gradlew.bat similarity index 100% rename from examples/powertools-examples-core/kotlin/gradlew.bat rename to examples/powertools-examples-core/kotlin/gradle/gradlew.bat diff --git a/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt b/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt similarity index 100% rename from examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt rename to examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt diff --git a/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/AppStream.kt b/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/AppStream.kt similarity index 100% rename from examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/AppStream.kt rename to examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/AppStream.kt diff --git a/examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt b/examples/powertools-examples-core/kotlin/gradle/src/test/kotlin/helloworld/AppTest.kt similarity index 100% rename from examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt rename to examples/powertools-examples-core/kotlin/gradle/src/test/kotlin/helloworld/AppTest.kt diff --git a/examples/powertools-examples-core/kotlin/template.yaml b/examples/powertools-examples-core/kotlin/gradle/template.yaml similarity index 100% rename from examples/powertools-examples-core/kotlin/template.yaml rename to examples/powertools-examples-core/kotlin/gradle/template.yaml From bf6da0d11c2108abde85066923be254d8e338872 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Wed, 4 Oct 2023 15:30:50 +0100 Subject: [PATCH 24/40] Updating core examples readme to represent new structure for Java and Kotlin examples. --- examples/powertools-examples-core/README.md | 41 +++++++++------------ 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/examples/powertools-examples-core/README.md b/examples/powertools-examples-core/README.md index f2af999b9..787b691ab 100644 --- a/examples/powertools-examples-core/README.md +++ b/examples/powertools-examples-core/README.md @@ -1,35 +1,29 @@ -# Powertools for AWS Lambda (Java) - Core Utilities Example +# Powertools for AWS Lambda - Core Utilities Example -This project demonstrates the Lambda for Powertools Java module - including +This project demonstrates the Lambda for Powertools Java module - including [logging](https://docs.powertools.aws.dev/lambda/java/core/logging/), [tracing](https://docs.powertools.aws.dev/lambda/java/core/tracing/), and [metrics](https://docs.powertools.aws.dev/lambda/java/core/metrics/). -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: - -* [AWS SAM with a Gradle build](gradle/) - ## Java -For each of the tools, the example application is the same, and consists of the following files: +* [CDK](java/cdk/) +* [Gradle](java/gradle/) +* [SAM](java/sam/) +* [Serverless](java/serverless/) -- [App.java](sam/src/main/java/helloworld/App.java) - Code for the application's Lambda function. -- [AppTests.java](sam/src/test/java/helloworld/AppTest.java) - Unit tests for the application code. -- [events](sam/events/event.json) - Invocation events that you can use to invoke the function. +For each of the tools, the example application is the same, and consists of the following files: +- App.java - Code for the application's Lambda function. +- AppTests.java - Unit tests for the application code. +- events - Invocation events that you can use to invoke the function. Configuration files and deployment process for each tool are described in corresponding README files. ## Kotlin -For each of the tools, the example application is the same, and consists of the following files: +* [Gradle](java/gradle/) -- [App.kt](kotlin/src/main/kotlin/helloworld/App.kt) - Code for the application's Lambda function. -- [AppTests.kt](kotlin/src/test/kotlin/helloworld/AppTest.kt) - Unit tests for the application code. -- [events](kotlin/events/event.json) - Invocation events that you can use to invoke the function. +- App.kt - Code for the application's Lambda function. +- AppTests.kt - Unit tests for the application code. +- events - Invocation events that you can use to invoke the function. Configuration files and deployment process for each tool are described in corresponding README files. @@ -41,14 +35,13 @@ Once the app is deployed, you can invoke the endpoint like this: curl https://[REST-API-ID].execute-api.[REGION].amazonaws.com/Prod/hello/ ``` -The response itself isn't particularly interesting - you will get back some information about your IP address. If +The response itself isn't particularly interesting - you will get back some information about your IP address. If you go to the Lambda Console and locate the lambda you have deployed, then click the "Monitoring" tab you will be able to find: * **View X-Ray traces** - Display the traces captured by the traces module. These include subsegments for the -different function calls within the example + different function calls within the example * **View Cloudwatch logs** - Display the structured logging output of the example Likewise, from the CloudWatch dashboard, under **Metrics**, **all metrics**, you will find the namespaces `Another` -and `ServerlessAirline`. The values in each of these are published by the code in -[App.java](sam/src/main/java/helloworld/App.java). +and `ServerlessAirline`. The values in each of these are published by the code in the respective application's Lambda function. From f67f59af4e3541068c915c63f9e61ffedbc13998 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Wed, 4 Oct 2023 16:11:12 +0100 Subject: [PATCH 25/40] Refactoring application code for efficiency, updating build to cover tests too and is more idiomatic and readme to be more descriptive --- examples/powertools-examples-core/README.md | 5 ++++- .../kotlin/gradle/build.gradle.kts | 4 ++-- .../kotlin/gradle/src/main/kotlin/helloworld/App.kt | 8 +++----- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/examples/powertools-examples-core/README.md b/examples/powertools-examples-core/README.md index 787b691ab..3fa3628b8 100644 --- a/examples/powertools-examples-core/README.md +++ b/examples/powertools-examples-core/README.md @@ -5,13 +5,15 @@ This project demonstrates the Lambda for Powertools Java module - including [tracing](https://docs.powertools.aws.dev/lambda/java/core/tracing/), and [metrics](https://docs.powertools.aws.dev/lambda/java/core/metrics/). +The example application is the same, and you can now also use Kotlin! + ## Java * [CDK](java/cdk/) * [Gradle](java/gradle/) * [SAM](java/sam/) * [Serverless](java/serverless/) -For each of the tools, the example application is the same, and consists of the following files: +Example application consists of the following files: - App.java - Code for the application's Lambda function. - AppTests.java - Unit tests for the application code. - events - Invocation events that you can use to invoke the function. @@ -21,6 +23,7 @@ Configuration files and deployment process for each tool are described in corres ## Kotlin * [Gradle](java/gradle/) +Example application consists of the following files: - App.kt - Code for the application's Lambda function. - AppTests.kt - Unit tests for the application code. - events - Invocation events that you can use to invoke the function. diff --git a/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts b/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts index b89b93526..a6e831d9a 100644 --- a/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts +++ b/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts @@ -26,6 +26,6 @@ tasks.compileKotlin { } } -java { - targetCompatibility = JavaVersion.VERSION_1_8 +kotlin { + jvmToolchain(8) } diff --git a/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt b/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt index 5b6a45ce8..796f6f999 100644 --- a/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt +++ b/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt @@ -45,7 +45,7 @@ class App : RequestHandler = HashMap() + val headers = mutableMapOf() headers["Content-Type"] = "application/json" headers["X-Custom-Header"] = "application/json" MetricsUtils.metricsLogger().putMetric("CustomMetric1", 1.0, Unit.COUNT) @@ -65,7 +65,7 @@ class App : RequestHandler + TracingUtils.withSubsegment("loggingResponse") { _: Subsegment? -> val sampled = "log something out" log.info(sampled) log.info(output) @@ -92,7 +92,5 @@ class App : RequestHandler return br.lines().collect(Collectors.joining(System.lineSeparator())) } } - companion object { - private val log = LogManager.getLogger(App::class.java) - } + private val log = LogManager.getLogger(App::class) } From f7288d5b31d33a58a822086d1fffeeffafde6f9b Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Wed, 4 Oct 2023 16:34:44 +0100 Subject: [PATCH 26/40] Updating to fix trailing \n --- .../kotlin/gradle/src/main/kotlin/helloworld/App.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt b/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt index 796f6f999..0cc8d1098 100644 --- a/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt +++ b/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt @@ -89,7 +89,9 @@ class App : RequestHandler return br.lines().collect(Collectors.joining(System.lineSeparator())) } + return InputStreamReader(url.openStream()).use { reader -> + reader.readText().trim() + } } private val log = LogManager.getLogger(App::class) From f03b01b3c3f6b3968d26506c6abf8782c7facb24 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Wed, 4 Oct 2023 16:45:49 +0100 Subject: [PATCH 27/40] Updating guidance to be more specific for examples --- examples/README.md | 12 ++++++++---- .../powertools-examples-core/kotlin/gradle/README.md | 3 ++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/examples/README.md b/examples/README.md index 73dc7a1bf..7d779f8f1 100644 --- a/examples/README.md +++ b/examples/README.md @@ -5,10 +5,14 @@ Each example can be copied from its subdirectory and used independently of the r ## Examples -* [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/java/cdk) - * [Serverless](./powertools-examples-core/serverless) +* [powertools-examples-core](powertools-examples-core) - Demonstrates the core logging, tracing, and metrics modules with different build tools and languages + * [Java](./powertools-examples-core/java) + * [CDK](./powertools-examples-core/java/cdk) + * [Gradle](./powertools-examples-core/java/gradle) + * [SAM](./powertools-examples-core/java/sam) + * [Serverless](./powertools-examples-core/java/serverless) + * [Kotlin](./powertools-examples-core/kotlin) + * [Gradle](./powertools-examples-core/kotlin/gradle) * [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/powertools-examples-core/kotlin/gradle/README.md b/examples/powertools-examples-core/kotlin/gradle/README.md index 14059f178..d40397a4b 100644 --- a/examples/powertools-examples-core/kotlin/gradle/README.md +++ b/examples/powertools-examples-core/kotlin/gradle/README.md @@ -13,7 +13,8 @@ For general information on the deployed example itself, you can refer to the par SAM uses [template.yaml](template.yaml) to define the application's AWS resources. This file defines the Lambda function to be deployed as well as API Gateway for it. -The build of the project is managed by Gradle, and configured in [build.gradle](_build.gradle). +The build of the project is managed by Gradle, and configured in [build.gradle.kts](build.gradle.kts) +. ## Deploy the sample application To get started, you can use the included template with SAM to run the build and deploy to your AWS environment: From e523554db3c7b0e2b3aa0ccef4b382cfe4c2ba83 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Fri, 6 Oct 2023 13:17:01 +0100 Subject: [PATCH 28/40] Adopting new mechanism for specifying jvm target. --- .../kotlin/gradle/build.gradle.kts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts b/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts index a6e831d9a..68ff9b6d4 100644 --- a/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts +++ b/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts @@ -26,6 +26,12 @@ tasks.compileKotlin { } } -kotlin { - jvmToolchain(8) +tasks.compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } } +// If using JDK 11 or higher, use the following instead: +//kotlin { +// jvmToolchain(8) +//} \ No newline at end of file From a71e263684d972387471a76ab7a0166374357fb9 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Fri, 6 Oct 2023 13:35:59 +0100 Subject: [PATCH 29/40] accommodating new project structure --- examples/README.md | 2 +- examples/pom.xml | 8 ++++---- examples/powertools-examples-core/README.md | 2 +- .../kotlin/{gradle => }/README.md | 6 +++--- .../kotlin/{gradle => }/build.gradle.kts | 1 + .../kotlin/{gradle => }/events/event.json | 0 .../kotlin/gradle/{gradle => }/wrapper/.gitignore | 0 .../gradle/{gradle => }/wrapper/gradle-wrapper.jar | Bin .../{gradle => }/wrapper/gradle-wrapper.properties | 0 .../kotlin/{gradle => }/gradlew | 0 .../kotlin/{gradle => }/gradlew.bat | 0 .../{gradle => }/src/main/kotlin/helloworld/App.kt | 0 .../src/main/kotlin/helloworld/AppStream.kt | 0 .../src/test/kotlin/helloworld/AppTest.kt | 0 .../kotlin/{gradle => }/template.yaml | 0 15 files changed, 10 insertions(+), 9 deletions(-) rename examples/powertools-examples-core/kotlin/{gradle => }/README.md (89%) rename examples/powertools-examples-core/kotlin/{gradle => }/build.gradle.kts (99%) rename examples/powertools-examples-core/kotlin/{gradle => }/events/event.json (100%) rename examples/powertools-examples-core/kotlin/gradle/{gradle => }/wrapper/.gitignore (100%) rename examples/powertools-examples-core/kotlin/gradle/{gradle => }/wrapper/gradle-wrapper.jar (100%) rename examples/powertools-examples-core/kotlin/gradle/{gradle => }/wrapper/gradle-wrapper.properties (100%) rename examples/powertools-examples-core/kotlin/{gradle => }/gradlew (100%) rename examples/powertools-examples-core/kotlin/{gradle => }/gradlew.bat (100%) rename examples/powertools-examples-core/kotlin/{gradle => }/src/main/kotlin/helloworld/App.kt (100%) rename examples/powertools-examples-core/kotlin/{gradle => }/src/main/kotlin/helloworld/AppStream.kt (100%) rename examples/powertools-examples-core/kotlin/{gradle => }/src/test/kotlin/helloworld/AppTest.kt (100%) rename examples/powertools-examples-core/kotlin/{gradle => }/template.yaml (100%) diff --git a/examples/README.md b/examples/README.md index 7d779f8f1..cd5c32fa4 100644 --- a/examples/README.md +++ b/examples/README.md @@ -12,7 +12,7 @@ Each example can be copied from its subdirectory and used independently of the r * [SAM](./powertools-examples-core/java/sam) * [Serverless](./powertools-examples-core/java/serverless) * [Kotlin](./powertools-examples-core/kotlin) - * [Gradle](./powertools-examples-core/kotlin/gradle) + * [Gradle](powertools-examples-core/kotlin/gradle1) * [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 810ec1b36..ba7b5ff65 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -29,10 +29,10 @@ - powertools-examples-core/sam - powertools-examples-core/cdk/app - powertools-examples-core/cdk/infra - powertools-examples-core/serverless + powertools-examples-core/java/sam + powertools-examples-core/java/cdk/app + powertools-examples-core/java/cdk/infra + powertools-examples-core/java/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 3fa3628b8..0c9a44a36 100644 --- a/examples/powertools-examples-core/README.md +++ b/examples/powertools-examples-core/README.md @@ -21,7 +21,7 @@ Example application consists of the following files: Configuration files and deployment process for each tool are described in corresponding README files. ## Kotlin -* [Gradle](java/gradle/) +* [Gradle](kotlin/) Example application consists of the following files: - App.kt - Code for the application's Lambda function. diff --git a/examples/powertools-examples-core/kotlin/gradle/README.md b/examples/powertools-examples-core/kotlin/README.md similarity index 89% rename from examples/powertools-examples-core/kotlin/gradle/README.md rename to examples/powertools-examples-core/kotlin/README.md index d40397a4b..da9ec5b52 100644 --- a/examples/powertools-examples-core/kotlin/gradle/README.md +++ b/examples/powertools-examples-core/kotlin/README.md @@ -2,12 +2,12 @@ This project demonstrates the Lambda for Powertools Kotlin module deployed using [Serverless Application Model](https://aws.amazon.com/serverless/sam/) with [Gradle](https://gradle.org/) running the build. This example is configured for Java 1.8 only; in order to use a newer version, check out the Gradle -configuration guide [in the main project README](../../../../README.md). +configuration guide [in the main project README](../../../README.md). You can also use `sam init` to create a new Gradle-powered Powertools application - choose to use the **AWS Quick Start Templates**, and then **Hello World Example with Powertools for AWS Lambda**, **Java 17** runtime, and finally **gradle**. -For general information on the deployed example itself, you can refer to the parent [README](../../README.md) +For general information on the deployed example itself, you can refer to the parent [README](../README.md) ## Configuration SAM uses [template.yaml](template.yaml) to define the application's AWS resources. @@ -24,7 +24,7 @@ sam build && sam deploy --guided ``` Once this is done to deploy the example, check out the instructions for getting started with SAM in -[the examples directory](../../../README.md) +[the examples directory](../../README.md) ## Additional notes diff --git a/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts b/examples/powertools-examples-core/kotlin/build.gradle.kts similarity index 99% rename from examples/powertools-examples-core/kotlin/gradle/build.gradle.kts rename to examples/powertools-examples-core/kotlin/build.gradle.kts index 68ff9b6d4..2a11034b6 100644 --- a/examples/powertools-examples-core/kotlin/gradle/build.gradle.kts +++ b/examples/powertools-examples-core/kotlin/build.gradle.kts @@ -31,6 +31,7 @@ tasks.compileTestKotlin { jvmTarget = "1.8" } } + // If using JDK 11 or higher, use the following instead: //kotlin { // jvmToolchain(8) diff --git a/examples/powertools-examples-core/kotlin/gradle/events/event.json b/examples/powertools-examples-core/kotlin/events/event.json similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/events/event.json rename to examples/powertools-examples-core/kotlin/events/event.json diff --git a/examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/.gitignore b/examples/powertools-examples-core/kotlin/gradle/wrapper/.gitignore similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/.gitignore rename to examples/powertools-examples-core/kotlin/gradle/wrapper/.gitignore diff --git a/examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/gradle-wrapper.jar b/examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/gradle-wrapper.jar rename to examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.jar diff --git a/examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/gradle-wrapper.properties b/examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/gradle/wrapper/gradle-wrapper.properties rename to examples/powertools-examples-core/kotlin/gradle/wrapper/gradle-wrapper.properties diff --git a/examples/powertools-examples-core/kotlin/gradle/gradlew b/examples/powertools-examples-core/kotlin/gradlew similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/gradlew rename to examples/powertools-examples-core/kotlin/gradlew diff --git a/examples/powertools-examples-core/kotlin/gradle/gradlew.bat b/examples/powertools-examples-core/kotlin/gradlew.bat similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/gradlew.bat rename to examples/powertools-examples-core/kotlin/gradlew.bat diff --git a/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt b/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/App.kt rename to examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt diff --git a/examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/AppStream.kt b/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/AppStream.kt similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/src/main/kotlin/helloworld/AppStream.kt rename to examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/AppStream.kt diff --git a/examples/powertools-examples-core/kotlin/gradle/src/test/kotlin/helloworld/AppTest.kt b/examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/src/test/kotlin/helloworld/AppTest.kt rename to examples/powertools-examples-core/kotlin/src/test/kotlin/helloworld/AppTest.kt diff --git a/examples/powertools-examples-core/kotlin/gradle/template.yaml b/examples/powertools-examples-core/kotlin/template.yaml similarity index 100% rename from examples/powertools-examples-core/kotlin/gradle/template.yaml rename to examples/powertools-examples-core/kotlin/template.yaml From 51fc239dc8553722dce8b7c8043b0aad015d18eb Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Fri, 6 Oct 2023 13:41:06 +0100 Subject: [PATCH 30/40] Fixing link typo after refactoring --- examples/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/README.md b/examples/README.md index cd5c32fa4..d593e1f06 100644 --- a/examples/README.md +++ b/examples/README.md @@ -12,7 +12,7 @@ Each example can be copied from its subdirectory and used independently of the r * [SAM](./powertools-examples-core/java/sam) * [Serverless](./powertools-examples-core/java/serverless) * [Kotlin](./powertools-examples-core/kotlin) - * [Gradle](powertools-examples-core/kotlin/gradle1) + * [Gradle](powertools-examples-core/kotlin/) * [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 From 6cef711d22700353b420c90f20e2ed90ccb98398 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Fri, 13 Oct 2023 14:54:13 +0100 Subject: [PATCH 31/40] Flattening structure back to original to make merging easier for v2 --- examples/README.md | 10 +- examples/pom.xml | 8 +- .../{java => }/cdk/README.md | 0 .../{java => }/cdk/app/events/event.json | 0 .../{java => }/cdk/app/pom.xml | 0 .../cdk/app/src/main/java/helloworld/App.java | 0 .../src/main/java/helloworld/AppStream.java | 0 .../cdk/app/src/main/resources/log4j2.xml | 0 .../app/src/test/java/helloworld/AppTest.java | 0 .../{java => }/cdk/infra/cdk.json | 0 .../{java => }/cdk/infra/pom.xml | 0 .../cdk/infra/src/main/java/cdk/CdkApp.java | 0 .../cdk/infra/src/main/java/cdk/CdkStack.java | 0 .../infra/src/test/java/cdk/CdkStackTest.java | 0 .../{java => }/gradle/README.md | 0 .../{java => }/gradle/build.gradle | 0 .../{java => }/gradle/events/event.json | 0 .../gradle/gradle/wrapper/.gitignore | 0 .../gradle/gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 .../{java => }/gradle/gradlew | 0 .../{java => }/gradle/gradlew.bat | 184 +++++++++--------- .../gradle/src/main/java/helloworld/App.java | 0 .../src/main/java/helloworld/AppStream.java | 0 .../src/test/java/helloworld/AppTest.java | 0 .../{java => }/gradle/template.yaml | 0 .../{java => }/sam/README.md | 0 .../{java => }/sam/events/event.json | 0 .../{java => }/sam/pom.xml | 0 .../sam/src/main/java/helloworld/App.java | 0 .../src/main/java/helloworld/AppStream.java | 0 .../sam/src/main/resources/log4j2.xml | 0 .../sam/src/test/java/helloworld/AppTest.java | 0 .../{java => }/sam/template.yaml | 0 .../{java => }/serverless/README.md | 0 .../{java => }/serverless/pom.xml | 0 .../{java => }/serverless/serverless.yml | 0 .../src/main/java/helloworld/App.java | 0 .../src/main/java/helloworld/AppStream.java | 0 .../serverless/src/main/resources/log4j2.xml | 0 .../src/test/java/helloworld/AppTest.java | 0 41 files changed, 100 insertions(+), 102 deletions(-) rename examples/powertools-examples-core/{java => }/cdk/README.md (100%) rename examples/powertools-examples-core/{java => }/cdk/app/events/event.json (100%) rename examples/powertools-examples-core/{java => }/cdk/app/pom.xml (100%) rename examples/powertools-examples-core/{java => }/cdk/app/src/main/java/helloworld/App.java (100%) rename examples/powertools-examples-core/{java => }/cdk/app/src/main/java/helloworld/AppStream.java (100%) rename examples/powertools-examples-core/{java => }/cdk/app/src/main/resources/log4j2.xml (100%) rename examples/powertools-examples-core/{java => }/cdk/app/src/test/java/helloworld/AppTest.java (100%) rename examples/powertools-examples-core/{java => }/cdk/infra/cdk.json (100%) rename examples/powertools-examples-core/{java => }/cdk/infra/pom.xml (100%) rename examples/powertools-examples-core/{java => }/cdk/infra/src/main/java/cdk/CdkApp.java (100%) rename examples/powertools-examples-core/{java => }/cdk/infra/src/main/java/cdk/CdkStack.java (100%) rename examples/powertools-examples-core/{java => }/cdk/infra/src/test/java/cdk/CdkStackTest.java (100%) rename examples/powertools-examples-core/{java => }/gradle/README.md (100%) rename examples/powertools-examples-core/{java => }/gradle/build.gradle (100%) rename examples/powertools-examples-core/{java => }/gradle/events/event.json (100%) rename examples/powertools-examples-core/{java => }/gradle/gradle/wrapper/.gitignore (100%) rename examples/powertools-examples-core/{java => }/gradle/gradle/wrapper/gradle-wrapper.jar (100%) rename examples/powertools-examples-core/{java => }/gradle/gradle/wrapper/gradle-wrapper.properties (100%) rename examples/powertools-examples-core/{java => }/gradle/gradlew (100%) rename examples/powertools-examples-core/{java => }/gradle/gradlew.bat (96%) rename examples/powertools-examples-core/{java => }/gradle/src/main/java/helloworld/App.java (100%) rename examples/powertools-examples-core/{java => }/gradle/src/main/java/helloworld/AppStream.java (100%) rename examples/powertools-examples-core/{java => }/gradle/src/test/java/helloworld/AppTest.java (100%) rename examples/powertools-examples-core/{java => }/gradle/template.yaml (100%) rename examples/powertools-examples-core/{java => }/sam/README.md (100%) rename examples/powertools-examples-core/{java => }/sam/events/event.json (100%) rename examples/powertools-examples-core/{java => }/sam/pom.xml (100%) rename examples/powertools-examples-core/{java => }/sam/src/main/java/helloworld/App.java (100%) rename examples/powertools-examples-core/{java => }/sam/src/main/java/helloworld/AppStream.java (100%) rename examples/powertools-examples-core/{java => }/sam/src/main/resources/log4j2.xml (100%) rename examples/powertools-examples-core/{java => }/sam/src/test/java/helloworld/AppTest.java (100%) rename examples/powertools-examples-core/{java => }/sam/template.yaml (100%) rename examples/powertools-examples-core/{java => }/serverless/README.md (100%) rename examples/powertools-examples-core/{java => }/serverless/pom.xml (100%) rename examples/powertools-examples-core/{java => }/serverless/serverless.yml (100%) rename examples/powertools-examples-core/{java => }/serverless/src/main/java/helloworld/App.java (100%) rename examples/powertools-examples-core/{java => }/serverless/src/main/java/helloworld/AppStream.java (100%) rename examples/powertools-examples-core/{java => }/serverless/src/main/resources/log4j2.xml (100%) rename examples/powertools-examples-core/{java => }/serverless/src/test/java/helloworld/AppTest.java (100%) diff --git a/examples/README.md b/examples/README.md index d593e1f06..6dbe00185 100644 --- a/examples/README.md +++ b/examples/README.md @@ -6,13 +6,11 @@ Each example can be copied from its subdirectory and used independently of the r ## Examples * [powertools-examples-core](powertools-examples-core) - Demonstrates the core logging, tracing, and metrics modules with different build tools and languages - * [Java](./powertools-examples-core/java) - * [CDK](./powertools-examples-core/java/cdk) - * [Gradle](./powertools-examples-core/java/gradle) - * [SAM](./powertools-examples-core/java/sam) - * [Serverless](./powertools-examples-core/java/serverless) + * [CDK](./powertools-examples-core/cdk) + * [Gradle](./powertools-examples-core/gradle) + * [SAM](./powertools-examples-core/sam) + * [Serverless](./powertools-examples-core/serverless) * [Kotlin](./powertools-examples-core/kotlin) - * [Gradle](powertools-examples-core/kotlin/) * [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 ba7b5ff65..810ec1b36 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -29,10 +29,10 @@ - powertools-examples-core/java/sam - powertools-examples-core/java/cdk/app - powertools-examples-core/java/cdk/infra - powertools-examples-core/java/serverless + 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/java/cdk/README.md b/examples/powertools-examples-core/cdk/README.md similarity index 100% rename from examples/powertools-examples-core/java/cdk/README.md rename to examples/powertools-examples-core/cdk/README.md diff --git a/examples/powertools-examples-core/java/cdk/app/events/event.json b/examples/powertools-examples-core/cdk/app/events/event.json similarity index 100% rename from examples/powertools-examples-core/java/cdk/app/events/event.json rename to examples/powertools-examples-core/cdk/app/events/event.json diff --git a/examples/powertools-examples-core/java/cdk/app/pom.xml b/examples/powertools-examples-core/cdk/app/pom.xml similarity index 100% rename from examples/powertools-examples-core/java/cdk/app/pom.xml rename to examples/powertools-examples-core/cdk/app/pom.xml diff --git a/examples/powertools-examples-core/java/cdk/app/src/main/java/helloworld/App.java b/examples/powertools-examples-core/cdk/app/src/main/java/helloworld/App.java similarity index 100% rename from examples/powertools-examples-core/java/cdk/app/src/main/java/helloworld/App.java rename to examples/powertools-examples-core/cdk/app/src/main/java/helloworld/App.java diff --git a/examples/powertools-examples-core/java/cdk/app/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/cdk/app/src/main/java/helloworld/AppStream.java similarity index 100% rename from examples/powertools-examples-core/java/cdk/app/src/main/java/helloworld/AppStream.java rename to examples/powertools-examples-core/cdk/app/src/main/java/helloworld/AppStream.java diff --git a/examples/powertools-examples-core/java/cdk/app/src/main/resources/log4j2.xml b/examples/powertools-examples-core/cdk/app/src/main/resources/log4j2.xml similarity index 100% rename from examples/powertools-examples-core/java/cdk/app/src/main/resources/log4j2.xml rename to examples/powertools-examples-core/cdk/app/src/main/resources/log4j2.xml diff --git a/examples/powertools-examples-core/java/cdk/app/src/test/java/helloworld/AppTest.java b/examples/powertools-examples-core/cdk/app/src/test/java/helloworld/AppTest.java similarity index 100% rename from examples/powertools-examples-core/java/cdk/app/src/test/java/helloworld/AppTest.java rename to examples/powertools-examples-core/cdk/app/src/test/java/helloworld/AppTest.java diff --git a/examples/powertools-examples-core/java/cdk/infra/cdk.json b/examples/powertools-examples-core/cdk/infra/cdk.json similarity index 100% rename from examples/powertools-examples-core/java/cdk/infra/cdk.json rename to examples/powertools-examples-core/cdk/infra/cdk.json diff --git a/examples/powertools-examples-core/java/cdk/infra/pom.xml b/examples/powertools-examples-core/cdk/infra/pom.xml similarity index 100% rename from examples/powertools-examples-core/java/cdk/infra/pom.xml rename to examples/powertools-examples-core/cdk/infra/pom.xml diff --git a/examples/powertools-examples-core/java/cdk/infra/src/main/java/cdk/CdkApp.java b/examples/powertools-examples-core/cdk/infra/src/main/java/cdk/CdkApp.java similarity index 100% rename from examples/powertools-examples-core/java/cdk/infra/src/main/java/cdk/CdkApp.java rename to examples/powertools-examples-core/cdk/infra/src/main/java/cdk/CdkApp.java diff --git a/examples/powertools-examples-core/java/cdk/infra/src/main/java/cdk/CdkStack.java b/examples/powertools-examples-core/cdk/infra/src/main/java/cdk/CdkStack.java similarity index 100% rename from examples/powertools-examples-core/java/cdk/infra/src/main/java/cdk/CdkStack.java rename to examples/powertools-examples-core/cdk/infra/src/main/java/cdk/CdkStack.java diff --git a/examples/powertools-examples-core/java/cdk/infra/src/test/java/cdk/CdkStackTest.java b/examples/powertools-examples-core/cdk/infra/src/test/java/cdk/CdkStackTest.java similarity index 100% rename from examples/powertools-examples-core/java/cdk/infra/src/test/java/cdk/CdkStackTest.java rename to examples/powertools-examples-core/cdk/infra/src/test/java/cdk/CdkStackTest.java diff --git a/examples/powertools-examples-core/java/gradle/README.md b/examples/powertools-examples-core/gradle/README.md similarity index 100% rename from examples/powertools-examples-core/java/gradle/README.md rename to examples/powertools-examples-core/gradle/README.md diff --git a/examples/powertools-examples-core/java/gradle/build.gradle b/examples/powertools-examples-core/gradle/build.gradle similarity index 100% rename from examples/powertools-examples-core/java/gradle/build.gradle rename to examples/powertools-examples-core/gradle/build.gradle diff --git a/examples/powertools-examples-core/java/gradle/events/event.json b/examples/powertools-examples-core/gradle/events/event.json similarity index 100% rename from examples/powertools-examples-core/java/gradle/events/event.json rename to examples/powertools-examples-core/gradle/events/event.json diff --git a/examples/powertools-examples-core/java/gradle/gradle/wrapper/.gitignore b/examples/powertools-examples-core/gradle/gradle/wrapper/.gitignore similarity index 100% rename from examples/powertools-examples-core/java/gradle/gradle/wrapper/.gitignore rename to examples/powertools-examples-core/gradle/gradle/wrapper/.gitignore diff --git a/examples/powertools-examples-core/java/gradle/gradle/wrapper/gradle-wrapper.jar b/examples/powertools-examples-core/gradle/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from examples/powertools-examples-core/java/gradle/gradle/wrapper/gradle-wrapper.jar rename to examples/powertools-examples-core/gradle/gradle/wrapper/gradle-wrapper.jar diff --git a/examples/powertools-examples-core/java/gradle/gradle/wrapper/gradle-wrapper.properties b/examples/powertools-examples-core/gradle/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from examples/powertools-examples-core/java/gradle/gradle/wrapper/gradle-wrapper.properties rename to examples/powertools-examples-core/gradle/gradle/wrapper/gradle-wrapper.properties diff --git a/examples/powertools-examples-core/java/gradle/gradlew b/examples/powertools-examples-core/gradle/gradlew similarity index 100% rename from examples/powertools-examples-core/java/gradle/gradlew rename to examples/powertools-examples-core/gradle/gradlew diff --git a/examples/powertools-examples-core/java/gradle/gradlew.bat b/examples/powertools-examples-core/gradle/gradlew.bat similarity index 96% rename from examples/powertools-examples-core/java/gradle/gradlew.bat rename to examples/powertools-examples-core/gradle/gradlew.bat index 6689b85be..93e3f59f1 100644 --- a/examples/powertools-examples-core/java/gradle/gradlew.bat +++ b/examples/powertools-examples-core/gradle/gradlew.bat @@ -1,92 +1,92 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/examples/powertools-examples-core/java/gradle/src/main/java/helloworld/App.java b/examples/powertools-examples-core/gradle/src/main/java/helloworld/App.java similarity index 100% rename from examples/powertools-examples-core/java/gradle/src/main/java/helloworld/App.java rename to examples/powertools-examples-core/gradle/src/main/java/helloworld/App.java diff --git a/examples/powertools-examples-core/java/gradle/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/gradle/src/main/java/helloworld/AppStream.java similarity index 100% rename from examples/powertools-examples-core/java/gradle/src/main/java/helloworld/AppStream.java rename to examples/powertools-examples-core/gradle/src/main/java/helloworld/AppStream.java diff --git a/examples/powertools-examples-core/java/gradle/src/test/java/helloworld/AppTest.java b/examples/powertools-examples-core/gradle/src/test/java/helloworld/AppTest.java similarity index 100% rename from examples/powertools-examples-core/java/gradle/src/test/java/helloworld/AppTest.java rename to examples/powertools-examples-core/gradle/src/test/java/helloworld/AppTest.java diff --git a/examples/powertools-examples-core/java/gradle/template.yaml b/examples/powertools-examples-core/gradle/template.yaml similarity index 100% rename from examples/powertools-examples-core/java/gradle/template.yaml rename to examples/powertools-examples-core/gradle/template.yaml diff --git a/examples/powertools-examples-core/java/sam/README.md b/examples/powertools-examples-core/sam/README.md similarity index 100% rename from examples/powertools-examples-core/java/sam/README.md rename to examples/powertools-examples-core/sam/README.md diff --git a/examples/powertools-examples-core/java/sam/events/event.json b/examples/powertools-examples-core/sam/events/event.json similarity index 100% rename from examples/powertools-examples-core/java/sam/events/event.json rename to examples/powertools-examples-core/sam/events/event.json diff --git a/examples/powertools-examples-core/java/sam/pom.xml b/examples/powertools-examples-core/sam/pom.xml similarity index 100% rename from examples/powertools-examples-core/java/sam/pom.xml rename to examples/powertools-examples-core/sam/pom.xml diff --git a/examples/powertools-examples-core/java/sam/src/main/java/helloworld/App.java b/examples/powertools-examples-core/sam/src/main/java/helloworld/App.java similarity index 100% rename from examples/powertools-examples-core/java/sam/src/main/java/helloworld/App.java rename to examples/powertools-examples-core/sam/src/main/java/helloworld/App.java diff --git a/examples/powertools-examples-core/java/sam/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/sam/src/main/java/helloworld/AppStream.java similarity index 100% rename from examples/powertools-examples-core/java/sam/src/main/java/helloworld/AppStream.java rename to examples/powertools-examples-core/sam/src/main/java/helloworld/AppStream.java diff --git a/examples/powertools-examples-core/java/sam/src/main/resources/log4j2.xml b/examples/powertools-examples-core/sam/src/main/resources/log4j2.xml similarity index 100% rename from examples/powertools-examples-core/java/sam/src/main/resources/log4j2.xml rename to examples/powertools-examples-core/sam/src/main/resources/log4j2.xml diff --git a/examples/powertools-examples-core/java/sam/src/test/java/helloworld/AppTest.java b/examples/powertools-examples-core/sam/src/test/java/helloworld/AppTest.java similarity index 100% rename from examples/powertools-examples-core/java/sam/src/test/java/helloworld/AppTest.java rename to examples/powertools-examples-core/sam/src/test/java/helloworld/AppTest.java diff --git a/examples/powertools-examples-core/java/sam/template.yaml b/examples/powertools-examples-core/sam/template.yaml similarity index 100% rename from examples/powertools-examples-core/java/sam/template.yaml rename to examples/powertools-examples-core/sam/template.yaml diff --git a/examples/powertools-examples-core/java/serverless/README.md b/examples/powertools-examples-core/serverless/README.md similarity index 100% rename from examples/powertools-examples-core/java/serverless/README.md rename to examples/powertools-examples-core/serverless/README.md diff --git a/examples/powertools-examples-core/java/serverless/pom.xml b/examples/powertools-examples-core/serverless/pom.xml similarity index 100% rename from examples/powertools-examples-core/java/serverless/pom.xml rename to examples/powertools-examples-core/serverless/pom.xml diff --git a/examples/powertools-examples-core/java/serverless/serverless.yml b/examples/powertools-examples-core/serverless/serverless.yml similarity index 100% rename from examples/powertools-examples-core/java/serverless/serverless.yml rename to examples/powertools-examples-core/serverless/serverless.yml diff --git a/examples/powertools-examples-core/java/serverless/src/main/java/helloworld/App.java b/examples/powertools-examples-core/serverless/src/main/java/helloworld/App.java similarity index 100% rename from examples/powertools-examples-core/java/serverless/src/main/java/helloworld/App.java rename to examples/powertools-examples-core/serverless/src/main/java/helloworld/App.java diff --git a/examples/powertools-examples-core/java/serverless/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/serverless/src/main/java/helloworld/AppStream.java similarity index 100% rename from examples/powertools-examples-core/java/serverless/src/main/java/helloworld/AppStream.java rename to examples/powertools-examples-core/serverless/src/main/java/helloworld/AppStream.java diff --git a/examples/powertools-examples-core/java/serverless/src/main/resources/log4j2.xml b/examples/powertools-examples-core/serverless/src/main/resources/log4j2.xml similarity index 100% rename from examples/powertools-examples-core/java/serverless/src/main/resources/log4j2.xml rename to examples/powertools-examples-core/serverless/src/main/resources/log4j2.xml diff --git a/examples/powertools-examples-core/java/serverless/src/test/java/helloworld/AppTest.java b/examples/powertools-examples-core/serverless/src/test/java/helloworld/AppTest.java similarity index 100% rename from examples/powertools-examples-core/java/serverless/src/test/java/helloworld/AppTest.java rename to examples/powertools-examples-core/serverless/src/test/java/helloworld/AppTest.java From c24ee6d9c0677dcb11f29575d873a3190b114027 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Fri, 13 Oct 2023 15:06:41 +0100 Subject: [PATCH 32/40] Adding build for Kotlin Gradle --- .github/workflows/pr_build.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr_build.yml b/.github/workflows/pr_build.yml index 73ae67553..0a9988712 100644 --- a/.github/workflows/pr_build.yml +++ b/.github/workflows/pr_build.yml @@ -63,11 +63,15 @@ jobs: cache: 'maven' - name: Build with Maven run: mvn -B install --file pom.xml - - name: Build Gradle Example + - name: Build Gradle Example - Java if: ${{ matrix.java == '8' }} # Gradle example can only be built on Java 8 run: | cd examples/powertools-examples-core/gradle ./gradlew build + - name: Build Gradle Example - Kotlin + run: | + cd examples/powertools-examples-core/kotlin + ./gradlew build - name: Upload coverage to Codecov uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1 if: ${{ matrix.java == '11' }} # publish results once From de19b56e9e0a443af868db9e28809e57957641a6 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Fri, 13 Oct 2023 15:21:19 +0100 Subject: [PATCH 33/40] Adding build for Kotlin Gradle - Restructuring Java examples to v1 approach --- examples/powertools-examples-core/README.md | 8 +- .../{java => }/cdk/README.md | 2 +- .../{java => }/cdk/app/events/event.json | 0 .../{java => }/cdk/app/pom.xml | 0 .../cdk/app/src/main/java/helloworld/App.java | 0 .../src/main/java/helloworld/AppStream.java | 0 .../cdk/app/src/main/resources/log4j2.xml | 0 .../app/src/test/java/helloworld/AppTest.java | 0 .../{java => }/cdk/infra/cdk.json | 0 .../{java => }/cdk/infra/pom.xml | 0 .../cdk/infra/src/main/java/cdk/CdkApp.java | 0 .../cdk/infra/src/main/java/cdk/CdkStack.java | 0 .../infra/src/test/java/cdk/CdkStackTest.java | 0 .../{java => }/gradle/README.md | 6 +- .../{java => }/gradle/build.gradle | 0 .../{java => }/gradle/events/event.json | 0 .../gradle/gradle/wrapper/.gitignore | 0 .../gradle/gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 .../{java => }/gradle/gradlew | 0 .../{java => }/gradle/gradlew.bat | 184 +++++++++--------- .../gradle/src/main/java/helloworld/App.java | 0 .../src/main/java/helloworld/AppStream.java | 0 .../src/test/java/helloworld/AppTest.java | 0 .../{java => }/gradle/template.yaml | 0 .../kotlin/build.gradle.kts | 6 +- .../{java => }/sam/README.md | 4 +- .../{java => }/sam/events/event.json | 0 .../{java => }/sam/pom.xml | 0 .../sam/src/main/java/helloworld/App.java | 0 .../src/main/java/helloworld/AppStream.java | 0 .../sam/src/main/resources/log4j2.xml | 0 .../sam/src/test/java/helloworld/AppTest.java | 0 .../{java => }/sam/template.yaml | 0 .../{java => }/serverless/README.md | 2 +- .../{java => }/serverless/pom.xml | 0 .../{java => }/serverless/serverless.yml | 0 .../src/main/java/helloworld/App.java | 0 .../src/main/java/helloworld/AppStream.java | 0 .../serverless/src/main/resources/log4j2.xml | 0 .../src/test/java/helloworld/AppTest.java | 0 41 files changed, 106 insertions(+), 106 deletions(-) rename examples/powertools-examples-core/{java => }/cdk/README.md (97%) rename examples/powertools-examples-core/{java => }/cdk/app/events/event.json (100%) rename examples/powertools-examples-core/{java => }/cdk/app/pom.xml (100%) rename examples/powertools-examples-core/{java => }/cdk/app/src/main/java/helloworld/App.java (100%) rename examples/powertools-examples-core/{java => }/cdk/app/src/main/java/helloworld/AppStream.java (100%) rename examples/powertools-examples-core/{java => }/cdk/app/src/main/resources/log4j2.xml (100%) rename examples/powertools-examples-core/{java => }/cdk/app/src/test/java/helloworld/AppTest.java (100%) rename examples/powertools-examples-core/{java => }/cdk/infra/cdk.json (100%) rename examples/powertools-examples-core/{java => }/cdk/infra/pom.xml (100%) rename examples/powertools-examples-core/{java => }/cdk/infra/src/main/java/cdk/CdkApp.java (100%) rename examples/powertools-examples-core/{java => }/cdk/infra/src/main/java/cdk/CdkStack.java (100%) rename examples/powertools-examples-core/{java => }/cdk/infra/src/test/java/cdk/CdkStackTest.java (100%) rename examples/powertools-examples-core/{java => }/gradle/README.md (89%) rename examples/powertools-examples-core/{java => }/gradle/build.gradle (100%) rename examples/powertools-examples-core/{java => }/gradle/events/event.json (100%) rename examples/powertools-examples-core/{java => }/gradle/gradle/wrapper/.gitignore (100%) rename examples/powertools-examples-core/{java => }/gradle/gradle/wrapper/gradle-wrapper.jar (100%) rename examples/powertools-examples-core/{java => }/gradle/gradle/wrapper/gradle-wrapper.properties (100%) rename examples/powertools-examples-core/{java => }/gradle/gradlew (100%) rename examples/powertools-examples-core/{java => }/gradle/gradlew.bat (96%) rename examples/powertools-examples-core/{java => }/gradle/src/main/java/helloworld/App.java (100%) rename examples/powertools-examples-core/{java => }/gradle/src/main/java/helloworld/AppStream.java (100%) rename examples/powertools-examples-core/{java => }/gradle/src/test/java/helloworld/AppTest.java (100%) rename examples/powertools-examples-core/{java => }/gradle/template.yaml (100%) rename examples/powertools-examples-core/{java => }/sam/README.md (87%) rename examples/powertools-examples-core/{java => }/sam/events/event.json (100%) rename examples/powertools-examples-core/{java => }/sam/pom.xml (100%) rename examples/powertools-examples-core/{java => }/sam/src/main/java/helloworld/App.java (100%) rename examples/powertools-examples-core/{java => }/sam/src/main/java/helloworld/AppStream.java (100%) rename examples/powertools-examples-core/{java => }/sam/src/main/resources/log4j2.xml (100%) rename examples/powertools-examples-core/{java => }/sam/src/test/java/helloworld/AppTest.java (100%) rename examples/powertools-examples-core/{java => }/sam/template.yaml (100%) rename examples/powertools-examples-core/{java => }/serverless/README.md (95%) rename examples/powertools-examples-core/{java => }/serverless/pom.xml (100%) rename examples/powertools-examples-core/{java => }/serverless/serverless.yml (100%) rename examples/powertools-examples-core/{java => }/serverless/src/main/java/helloworld/App.java (100%) rename examples/powertools-examples-core/{java => }/serverless/src/main/java/helloworld/AppStream.java (100%) rename examples/powertools-examples-core/{java => }/serverless/src/main/resources/log4j2.xml (100%) rename examples/powertools-examples-core/{java => }/serverless/src/test/java/helloworld/AppTest.java (100%) diff --git a/examples/powertools-examples-core/README.md b/examples/powertools-examples-core/README.md index 0c9a44a36..b2dd7bf21 100644 --- a/examples/powertools-examples-core/README.md +++ b/examples/powertools-examples-core/README.md @@ -8,10 +8,10 @@ This project demonstrates the Lambda for Powertools Java module - including The example application is the same, and you can now also use Kotlin! ## Java -* [CDK](java/cdk/) -* [Gradle](java/gradle/) -* [SAM](java/sam/) -* [Serverless](java/serverless/) +* [CDK](cdk/) +* [Gradle](gradle/) +* [SAM](sam/) +* [Serverless](serverless/) Example application consists of the following files: - App.java - Code for the application's Lambda function. diff --git a/examples/powertools-examples-core/java/cdk/README.md b/examples/powertools-examples-core/cdk/README.md similarity index 97% rename from examples/powertools-examples-core/java/cdk/README.md rename to examples/powertools-examples-core/cdk/README.md index f53936b40..fbc558943 100644 --- a/examples/powertools-examples-core/java/cdk/README.md +++ b/examples/powertools-examples-core/cdk/README.md @@ -2,7 +2,7 @@ This project demonstrates the Lambda for Powertools Java module deployed using [Cloud Development Kit](https://aws.amazon.com/cdk/). -For general information on the deployed example itself, you can refer to the parent [README](../../README.md) +For general information on the deployed example itself, you can refer to the parent [README](../README.md) ## Configuration CDK uses the following project structure: diff --git a/examples/powertools-examples-core/java/cdk/app/events/event.json b/examples/powertools-examples-core/cdk/app/events/event.json similarity index 100% rename from examples/powertools-examples-core/java/cdk/app/events/event.json rename to examples/powertools-examples-core/cdk/app/events/event.json diff --git a/examples/powertools-examples-core/java/cdk/app/pom.xml b/examples/powertools-examples-core/cdk/app/pom.xml similarity index 100% rename from examples/powertools-examples-core/java/cdk/app/pom.xml rename to examples/powertools-examples-core/cdk/app/pom.xml diff --git a/examples/powertools-examples-core/java/cdk/app/src/main/java/helloworld/App.java b/examples/powertools-examples-core/cdk/app/src/main/java/helloworld/App.java similarity index 100% rename from examples/powertools-examples-core/java/cdk/app/src/main/java/helloworld/App.java rename to examples/powertools-examples-core/cdk/app/src/main/java/helloworld/App.java diff --git a/examples/powertools-examples-core/java/cdk/app/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/cdk/app/src/main/java/helloworld/AppStream.java similarity index 100% rename from examples/powertools-examples-core/java/cdk/app/src/main/java/helloworld/AppStream.java rename to examples/powertools-examples-core/cdk/app/src/main/java/helloworld/AppStream.java diff --git a/examples/powertools-examples-core/java/cdk/app/src/main/resources/log4j2.xml b/examples/powertools-examples-core/cdk/app/src/main/resources/log4j2.xml similarity index 100% rename from examples/powertools-examples-core/java/cdk/app/src/main/resources/log4j2.xml rename to examples/powertools-examples-core/cdk/app/src/main/resources/log4j2.xml diff --git a/examples/powertools-examples-core/java/cdk/app/src/test/java/helloworld/AppTest.java b/examples/powertools-examples-core/cdk/app/src/test/java/helloworld/AppTest.java similarity index 100% rename from examples/powertools-examples-core/java/cdk/app/src/test/java/helloworld/AppTest.java rename to examples/powertools-examples-core/cdk/app/src/test/java/helloworld/AppTest.java diff --git a/examples/powertools-examples-core/java/cdk/infra/cdk.json b/examples/powertools-examples-core/cdk/infra/cdk.json similarity index 100% rename from examples/powertools-examples-core/java/cdk/infra/cdk.json rename to examples/powertools-examples-core/cdk/infra/cdk.json diff --git a/examples/powertools-examples-core/java/cdk/infra/pom.xml b/examples/powertools-examples-core/cdk/infra/pom.xml similarity index 100% rename from examples/powertools-examples-core/java/cdk/infra/pom.xml rename to examples/powertools-examples-core/cdk/infra/pom.xml diff --git a/examples/powertools-examples-core/java/cdk/infra/src/main/java/cdk/CdkApp.java b/examples/powertools-examples-core/cdk/infra/src/main/java/cdk/CdkApp.java similarity index 100% rename from examples/powertools-examples-core/java/cdk/infra/src/main/java/cdk/CdkApp.java rename to examples/powertools-examples-core/cdk/infra/src/main/java/cdk/CdkApp.java diff --git a/examples/powertools-examples-core/java/cdk/infra/src/main/java/cdk/CdkStack.java b/examples/powertools-examples-core/cdk/infra/src/main/java/cdk/CdkStack.java similarity index 100% rename from examples/powertools-examples-core/java/cdk/infra/src/main/java/cdk/CdkStack.java rename to examples/powertools-examples-core/cdk/infra/src/main/java/cdk/CdkStack.java diff --git a/examples/powertools-examples-core/java/cdk/infra/src/test/java/cdk/CdkStackTest.java b/examples/powertools-examples-core/cdk/infra/src/test/java/cdk/CdkStackTest.java similarity index 100% rename from examples/powertools-examples-core/java/cdk/infra/src/test/java/cdk/CdkStackTest.java rename to examples/powertools-examples-core/cdk/infra/src/test/java/cdk/CdkStackTest.java diff --git a/examples/powertools-examples-core/java/gradle/README.md b/examples/powertools-examples-core/gradle/README.md similarity index 89% rename from examples/powertools-examples-core/java/gradle/README.md rename to examples/powertools-examples-core/gradle/README.md index a13e8fd3d..c7c798d5d 100644 --- a/examples/powertools-examples-core/java/gradle/README.md +++ b/examples/powertools-examples-core/gradle/README.md @@ -2,13 +2,13 @@ This project demonstrates the Lambda for Powertools Java module deployed using [Serverless Application Model](https://aws.amazon.com/serverless/sam/) with [Gradle](https://gradle.org/) running the build. This example is configured for Java 1.8 only; in order to use a newer version, check out the Gradle -configuration guide [in the main project README](../../../../README.md). +configuration guide [in the main project README](../../../README.md). You can also use `sam init` to create a new Gradle-powered Powertools application - choose to use the **AWS Quick Start Templates**, and then **Hello World Example with Powertools for AWS Lambda**, **Java 17** runtime, and finally **gradle**. -For general information on the deployed example itself, you can refer to the parent [README](../../README.md) +For general information on the deployed example itself, you can refer to the parent [README](../README.md) ## Configuration SAM uses [template.yaml](template.yaml) to define the application's AWS resources. @@ -24,7 +24,7 @@ To get started, you can use the Gradle wrapper to bootstrap Gradle and run the b ``` Once this is done to deploy the example, check out the instructions for getting started with SAM in -[the examples directory](../../../README.md) +[the examples directory](../../README.md) ## Additional notes diff --git a/examples/powertools-examples-core/java/gradle/build.gradle b/examples/powertools-examples-core/gradle/build.gradle similarity index 100% rename from examples/powertools-examples-core/java/gradle/build.gradle rename to examples/powertools-examples-core/gradle/build.gradle diff --git a/examples/powertools-examples-core/java/gradle/events/event.json b/examples/powertools-examples-core/gradle/events/event.json similarity index 100% rename from examples/powertools-examples-core/java/gradle/events/event.json rename to examples/powertools-examples-core/gradle/events/event.json diff --git a/examples/powertools-examples-core/java/gradle/gradle/wrapper/.gitignore b/examples/powertools-examples-core/gradle/gradle/wrapper/.gitignore similarity index 100% rename from examples/powertools-examples-core/java/gradle/gradle/wrapper/.gitignore rename to examples/powertools-examples-core/gradle/gradle/wrapper/.gitignore diff --git a/examples/powertools-examples-core/java/gradle/gradle/wrapper/gradle-wrapper.jar b/examples/powertools-examples-core/gradle/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from examples/powertools-examples-core/java/gradle/gradle/wrapper/gradle-wrapper.jar rename to examples/powertools-examples-core/gradle/gradle/wrapper/gradle-wrapper.jar diff --git a/examples/powertools-examples-core/java/gradle/gradle/wrapper/gradle-wrapper.properties b/examples/powertools-examples-core/gradle/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from examples/powertools-examples-core/java/gradle/gradle/wrapper/gradle-wrapper.properties rename to examples/powertools-examples-core/gradle/gradle/wrapper/gradle-wrapper.properties diff --git a/examples/powertools-examples-core/java/gradle/gradlew b/examples/powertools-examples-core/gradle/gradlew similarity index 100% rename from examples/powertools-examples-core/java/gradle/gradlew rename to examples/powertools-examples-core/gradle/gradlew diff --git a/examples/powertools-examples-core/java/gradle/gradlew.bat b/examples/powertools-examples-core/gradle/gradlew.bat similarity index 96% rename from examples/powertools-examples-core/java/gradle/gradlew.bat rename to examples/powertools-examples-core/gradle/gradlew.bat index 6689b85be..93e3f59f1 100644 --- a/examples/powertools-examples-core/java/gradle/gradlew.bat +++ b/examples/powertools-examples-core/gradle/gradlew.bat @@ -1,92 +1,92 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/examples/powertools-examples-core/java/gradle/src/main/java/helloworld/App.java b/examples/powertools-examples-core/gradle/src/main/java/helloworld/App.java similarity index 100% rename from examples/powertools-examples-core/java/gradle/src/main/java/helloworld/App.java rename to examples/powertools-examples-core/gradle/src/main/java/helloworld/App.java diff --git a/examples/powertools-examples-core/java/gradle/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/gradle/src/main/java/helloworld/AppStream.java similarity index 100% rename from examples/powertools-examples-core/java/gradle/src/main/java/helloworld/AppStream.java rename to examples/powertools-examples-core/gradle/src/main/java/helloworld/AppStream.java diff --git a/examples/powertools-examples-core/java/gradle/src/test/java/helloworld/AppTest.java b/examples/powertools-examples-core/gradle/src/test/java/helloworld/AppTest.java similarity index 100% rename from examples/powertools-examples-core/java/gradle/src/test/java/helloworld/AppTest.java rename to examples/powertools-examples-core/gradle/src/test/java/helloworld/AppTest.java diff --git a/examples/powertools-examples-core/java/gradle/template.yaml b/examples/powertools-examples-core/gradle/template.yaml similarity index 100% rename from examples/powertools-examples-core/java/gradle/template.yaml rename to examples/powertools-examples-core/gradle/template.yaml diff --git a/examples/powertools-examples-core/kotlin/build.gradle.kts b/examples/powertools-examples-core/kotlin/build.gradle.kts index 2a11034b6..7b2342e98 100644 --- a/examples/powertools-examples-core/kotlin/build.gradle.kts +++ b/examples/powertools-examples-core/kotlin/build.gradle.kts @@ -13,9 +13,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") - aspect("software.amazon.lambda:powertools-tracing:1.17.0") - aspect("software.amazon.lambda:powertools-logging:1.17.0") - aspect("software.amazon.lambda:powertools-metrics:1.17.0") + aspect("software.amazon.lambda:powertools-tracing:1.18.0-SNAPSHOT") + aspect("software.amazon.lambda:powertools-logging:1.18.0-SNAPSHOT") + aspect("software.amazon.lambda:powertools-metrics:1.18.0-SNAPSHOT") testImplementation("junit:junit:4.13.2") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") } diff --git a/examples/powertools-examples-core/java/sam/README.md b/examples/powertools-examples-core/sam/README.md similarity index 87% rename from examples/powertools-examples-core/java/sam/README.md rename to examples/powertools-examples-core/sam/README.md index 3b8c31ebc..7a4279ae3 100644 --- a/examples/powertools-examples-core/java/sam/README.md +++ b/examples/powertools-examples-core/sam/README.md @@ -2,7 +2,7 @@ This project demonstrates the Lambda for Powertools Java module deployed using [Serverless Application Model](https://aws.amazon.com/serverless/sam/). -For general information on the deployed example itself, you can refer to the parent [README](../../README.md) +For general information on the deployed example itself, you can refer to the parent [README](../README.md) ## Configuration SAM uses [template.yaml](template.yaml) to define the application's AWS resources. @@ -10,7 +10,7 @@ This file defines the Lambda function to be deployed as well as API Gateway for ## Deploy the sample application To deploy the example, check out the instructions for getting -started with SAM in [the examples directory](../../../README.md) +started with SAM in [the examples directory](../../README.md) ## Additional notes diff --git a/examples/powertools-examples-core/java/sam/events/event.json b/examples/powertools-examples-core/sam/events/event.json similarity index 100% rename from examples/powertools-examples-core/java/sam/events/event.json rename to examples/powertools-examples-core/sam/events/event.json diff --git a/examples/powertools-examples-core/java/sam/pom.xml b/examples/powertools-examples-core/sam/pom.xml similarity index 100% rename from examples/powertools-examples-core/java/sam/pom.xml rename to examples/powertools-examples-core/sam/pom.xml diff --git a/examples/powertools-examples-core/java/sam/src/main/java/helloworld/App.java b/examples/powertools-examples-core/sam/src/main/java/helloworld/App.java similarity index 100% rename from examples/powertools-examples-core/java/sam/src/main/java/helloworld/App.java rename to examples/powertools-examples-core/sam/src/main/java/helloworld/App.java diff --git a/examples/powertools-examples-core/java/sam/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/sam/src/main/java/helloworld/AppStream.java similarity index 100% rename from examples/powertools-examples-core/java/sam/src/main/java/helloworld/AppStream.java rename to examples/powertools-examples-core/sam/src/main/java/helloworld/AppStream.java diff --git a/examples/powertools-examples-core/java/sam/src/main/resources/log4j2.xml b/examples/powertools-examples-core/sam/src/main/resources/log4j2.xml similarity index 100% rename from examples/powertools-examples-core/java/sam/src/main/resources/log4j2.xml rename to examples/powertools-examples-core/sam/src/main/resources/log4j2.xml diff --git a/examples/powertools-examples-core/java/sam/src/test/java/helloworld/AppTest.java b/examples/powertools-examples-core/sam/src/test/java/helloworld/AppTest.java similarity index 100% rename from examples/powertools-examples-core/java/sam/src/test/java/helloworld/AppTest.java rename to examples/powertools-examples-core/sam/src/test/java/helloworld/AppTest.java diff --git a/examples/powertools-examples-core/java/sam/template.yaml b/examples/powertools-examples-core/sam/template.yaml similarity index 100% rename from examples/powertools-examples-core/java/sam/template.yaml rename to examples/powertools-examples-core/sam/template.yaml diff --git a/examples/powertools-examples-core/java/serverless/README.md b/examples/powertools-examples-core/serverless/README.md similarity index 95% rename from examples/powertools-examples-core/java/serverless/README.md rename to examples/powertools-examples-core/serverless/README.md index d97e7465a..9e33aa9ff 100644 --- a/examples/powertools-examples-core/java/serverless/README.md +++ b/examples/powertools-examples-core/serverless/README.md @@ -1,7 +1,7 @@ # 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). +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 diff --git a/examples/powertools-examples-core/java/serverless/pom.xml b/examples/powertools-examples-core/serverless/pom.xml similarity index 100% rename from examples/powertools-examples-core/java/serverless/pom.xml rename to examples/powertools-examples-core/serverless/pom.xml diff --git a/examples/powertools-examples-core/java/serverless/serverless.yml b/examples/powertools-examples-core/serverless/serverless.yml similarity index 100% rename from examples/powertools-examples-core/java/serverless/serverless.yml rename to examples/powertools-examples-core/serverless/serverless.yml diff --git a/examples/powertools-examples-core/java/serverless/src/main/java/helloworld/App.java b/examples/powertools-examples-core/serverless/src/main/java/helloworld/App.java similarity index 100% rename from examples/powertools-examples-core/java/serverless/src/main/java/helloworld/App.java rename to examples/powertools-examples-core/serverless/src/main/java/helloworld/App.java diff --git a/examples/powertools-examples-core/java/serverless/src/main/java/helloworld/AppStream.java b/examples/powertools-examples-core/serverless/src/main/java/helloworld/AppStream.java similarity index 100% rename from examples/powertools-examples-core/java/serverless/src/main/java/helloworld/AppStream.java rename to examples/powertools-examples-core/serverless/src/main/java/helloworld/AppStream.java diff --git a/examples/powertools-examples-core/java/serverless/src/main/resources/log4j2.xml b/examples/powertools-examples-core/serverless/src/main/resources/log4j2.xml similarity index 100% rename from examples/powertools-examples-core/java/serverless/src/main/resources/log4j2.xml rename to examples/powertools-examples-core/serverless/src/main/resources/log4j2.xml diff --git a/examples/powertools-examples-core/java/serverless/src/test/java/helloworld/AppTest.java b/examples/powertools-examples-core/serverless/src/test/java/helloworld/AppTest.java similarity index 100% rename from examples/powertools-examples-core/java/serverless/src/test/java/helloworld/AppTest.java rename to examples/powertools-examples-core/serverless/src/test/java/helloworld/AppTest.java From 6e23b2697a41a05fc01fa2b0ceb06b6322f6c85d Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Fri, 13 Oct 2023 15:25:17 +0100 Subject: [PATCH 34/40] Correcting paths --- examples/pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index ba7b5ff65..810ec1b36 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -29,10 +29,10 @@ - powertools-examples-core/java/sam - powertools-examples-core/java/cdk/app - powertools-examples-core/java/cdk/infra - powertools-examples-core/java/serverless + 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 From 480dd8b93d61098af7a07b5a0a202a9d6d7dd7ba Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Fri, 13 Oct 2023 16:10:33 +0100 Subject: [PATCH 35/40] Adding SNAPSHOT support and local capability for Maven. Testing using Java 1.8 --- examples/powertools-examples-core/kotlin/build.gradle.kts | 1 + pom.xml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/powertools-examples-core/kotlin/build.gradle.kts b/examples/powertools-examples-core/kotlin/build.gradle.kts index 7b2342e98..77cffbb06 100644 --- a/examples/powertools-examples-core/kotlin/build.gradle.kts +++ b/examples/powertools-examples-core/kotlin/build.gradle.kts @@ -4,6 +4,7 @@ plugins { } repositories { + mavenLocal() mavenCentral() } diff --git a/pom.xml b/pom.xml index fd31bef37..e6ddbf371 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ powertools-large-messages powertools-e2e-tests powertools-batch - examples + From 7a8dc166b18383b54009e78110f3ddb969c250c6 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Fri, 20 Oct 2023 14:54:23 +0100 Subject: [PATCH 36/40] Reviewed and updated against PR comments. --- examples/powertools-examples-core/README.md | 24 +++++++++++-------- .../kotlin/build.gradle.kts | 2 +- .../kotlin/src/main/kotlin/helloworld/App.kt | 6 ++--- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/examples/powertools-examples-core/README.md b/examples/powertools-examples-core/README.md index b2dd7bf21..108187640 100644 --- a/examples/powertools-examples-core/README.md +++ b/examples/powertools-examples-core/README.md @@ -1,4 +1,4 @@ -# Powertools for AWS Lambda - Core Utilities Example +# Powertools for AWS Lambda (Java) - Core Utilities Example This project demonstrates the Lambda for Powertools Java module - including [logging](https://docs.powertools.aws.dev/lambda/java/core/logging/), @@ -8,12 +8,14 @@ This project demonstrates the Lambda for Powertools Java module - including The example application is the same, and you can now also use Kotlin! ## Java -* [CDK](cdk/) -* [Gradle](gradle/) -* [SAM](sam/) -* [Serverless](serverless/) + +- [CDK](cdk/) +- [Gradle](gradle/) +- [SAM](sam/) +- [Serverless](serverless/) Example application consists of the following files: + - App.java - Code for the application's Lambda function. - AppTests.java - Unit tests for the application code. - events - Invocation events that you can use to invoke the function. @@ -21,9 +23,11 @@ Example application consists of the following files: Configuration files and deployment process for each tool are described in corresponding README files. ## Kotlin -* [Gradle](kotlin/) + +- [Gradle](kotlin/) Example application consists of the following files: + - App.kt - Code for the application's Lambda function. - AppTests.kt - Unit tests for the application code. - events - Invocation events that you can use to invoke the function. @@ -38,13 +42,13 @@ Once the app is deployed, you can invoke the endpoint like this: curl https://[REST-API-ID].execute-api.[REGION].amazonaws.com/Prod/hello/ ``` -The response itself isn't particularly interesting - you will get back some information about your IP address. If +The response itself isn't particularly interesting - you will get back some information about your IP address. If you go to the Lambda Console and locate the lambda you have deployed, then click the "Monitoring" tab you will be able to find: -* **View X-Ray traces** - Display the traces captured by the traces module. These include subsegments for the +- **View X-Ray traces** - Display the traces captured by the traces module. These include subsegments for the different function calls within the example -* **View Cloudwatch logs** - Display the structured logging output of the example +- **View Cloudwatch logs** - Display the structured logging output of the example -Likewise, from the CloudWatch dashboard, under **Metrics**, **all metrics**, you will find the namespaces `Another` +Likewise, from the CloudWatch dashboard, under **Metrics**, **all metrics**, you will find the namespaces `Another` and `ServerlessAirline`. The values in each of these are published by the code in the respective application's Lambda function. diff --git a/examples/powertools-examples-core/kotlin/build.gradle.kts b/examples/powertools-examples-core/kotlin/build.gradle.kts index 77cffbb06..fc363c1b9 100644 --- a/examples/powertools-examples-core/kotlin/build.gradle.kts +++ b/examples/powertools-examples-core/kotlin/build.gradle.kts @@ -35,5 +35,5 @@ tasks.compileTestKotlin { // If using JDK 11 or higher, use the following instead: //kotlin { -// jvmToolchain(8) +// jvmToolchain(11) //} \ No newline at end of file diff --git a/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt b/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt index 0cc8d1098..ed4cf267a 100644 --- a/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt +++ b/examples/powertools-examples-core/kotlin/src/main/kotlin/helloworld/App.kt @@ -44,10 +44,8 @@ class App : RequestHandler() - headers["Content-Type"] = "application/json" - headers["X-Custom-Header"] = "application/json" + override fun handleRequest(input: APIGatewayProxyRequestEvent?, context: Context?): APIGatewayProxyResponseEvent { + val headers = mapOf("Content-Type" to "application/json", "X-Custom-Header" to "application/json") MetricsUtils.metricsLogger().putMetric("CustomMetric1", 1.0, Unit.COUNT) MetricsUtils.withSingleMetric("CustomMetrics2", 1.0, Unit.COUNT, "Another") { metric: MetricsLogger -> metric.setDimensions(DimensionSet.of("AnotherService", "CustomService")) From 9a154dd52dfc14a41a36907719020f7a3db5dc3b Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Mon, 23 Oct 2023 16:45:11 +0100 Subject: [PATCH 37/40] Un-commenting examples --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 20342aac1..823b09d61 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ powertools-large-messages powertools-e2e-tests powertools-batch - + examples From e8ddb455b0345ba98ae816ed89b797245227cb33 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Tue, 31 Oct 2023 14:31:38 +0000 Subject: [PATCH 38/40] Adding validation step for IaC SAM --- .github/workflows/pr_iac_lint_.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/pr_iac_lint_.yml diff --git a/.github/workflows/pr_iac_lint_.yml b/.github/workflows/pr_iac_lint_.yml new file mode 100644 index 000000000..8aa239afb --- /dev/null +++ b/.github/workflows/pr_iac_lint_.yml @@ -0,0 +1,24 @@ +name: Validate IaC + +on: + pull_request: + branches: + - main + - v2 + paths: + - 'examples/**' +jobs: + linter: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - name: Setup java JDK 1.8 + uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2 # v3.11.0 + with: + distribution: 'corretto' + java-version: 8 + - name: Run SAM validator to check syntax of IaC templates + working-directory: examples/powertools-examples-core/sam + run: | + sam build + sam validate --lint From ec17480b80f1d37023ee221b2ba29c9cc42a1657 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Wed, 1 Nov 2023 14:53:27 +0000 Subject: [PATCH 39/40] Adding Terraform for Java projects IaC validator and linter --- .github/workflows/pr_build.yml | 21 --------------------- .github/workflows/pr_iac_lint_.yml | 20 +++++++++++++++++++- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/.github/workflows/pr_build.yml b/.github/workflows/pr_build.yml index c316c0073..ea336f468 100644 --- a/.github/workflows/pr_build.yml +++ b/.github/workflows/pr_build.yml @@ -79,33 +79,12 @@ jobs: if: ${{ matrix.java == '8' }} # Gradle example can only be built on Java 8 working-directory: examples/powertools-examples-core/kotlin run: ./gradlew build - - name: Setup Terraform - if: ${{ matrix.java == '11' }} - uses: hashicorp/setup-terraform@633666f66e0061ca3b725c73b2ec20cd13a8fdd1 #v2.0.3 - name: Setup AWS credentials if: ${{ matrix.java == '11' }} uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN_TO_ASSUME }} aws-region: ${{ env.AWS_REGION }} - - name: Terraform validate - working-directory: examples/powertools-examples-core/terraform - if: ${{ matrix.java == '11' }} - run: | - terraform -version - terraform init -backend=false - terraform validate - terraform plan - - name: Setup Terraform lint - if: ${{ matrix.java == '11' }} - uses: terraform-linters/setup-tflint@a5a1af8c6551fb10c53f1cd4ba62359f1973746f # v3.1.1 - - name: Terraform lint - working-directory: examples/powertools-examples-core/terraform - if: ${{ matrix.java == '11' }} - run: | - tflint --version - tflint --init - tflint -f compact - name: Upload coverage to Codecov uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1 if: ${{ matrix.java == '11' }} # publish results once diff --git a/.github/workflows/pr_iac_lint_.yml b/.github/workflows/pr_iac_lint_.yml index 8aa239afb..5f86005a5 100644 --- a/.github/workflows/pr_iac_lint_.yml +++ b/.github/workflows/pr_iac_lint_.yml @@ -16,9 +16,27 @@ jobs: uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2 # v3.11.0 with: distribution: 'corretto' - java-version: 8 + java-version: 11 - name: Run SAM validator to check syntax of IaC templates working-directory: examples/powertools-examples-core/sam run: | sam build sam validate --lint + - name: Setup Terraform + uses: hashicorp/setup-terraform@633666f66e0061ca3b725c73b2ec20cd13a8fdd1 #v2.0.3 + - name: Run Terraform validator to check syntax of IaC templates and produce a plan of changes + working-directory: examples/powertools-examples-core/terraform + run: | + mvn install + terraform -version + terraform init -backend=false + terraform validate + terraform plan + - name: Setup Terraform lint + uses: terraform-linters/setup-tflint@a5a1af8c6551fb10c53f1cd4ba62359f1973746f # v3.1.1 + - name: Run Terraform lint to check for best practices, errors, deprecated syntax etc. + working-directory: examples/powertools-examples-core/terraform + run: | + tflint --version + tflint --init + tflint -f compact From 7d11fac3a3bea8784d71c07be9ad5c70dc542451 Mon Sep 17 00:00:00 2001 From: Jason Harris Date: Wed, 1 Nov 2023 16:03:29 +0000 Subject: [PATCH 40/40] Adding additional projects for SAM validation and matrix approach --- .github/workflows/pr_iac_lint_.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr_iac_lint_.yml b/.github/workflows/pr_iac_lint_.yml index 5f86005a5..209072b02 100644 --- a/.github/workflows/pr_iac_lint_.yml +++ b/.github/workflows/pr_iac_lint_.yml @@ -10,15 +10,18 @@ on: jobs: linter: runs-on: ubuntu-latest + strategy: + matrix: + project: ["sam", "gradle", "kotlin"] steps: - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - - name: Setup java JDK 1.8 + - name: Setup java JDK uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2 # v3.11.0 with: distribution: 'corretto' java-version: 11 - - name: Run SAM validator to check syntax of IaC templates - working-directory: examples/powertools-examples-core/sam + - name: Run SAM validator to check syntax of IaC templates - Java + working-directory: examples/powertools-examples-core/${{ matrix.project }} run: | sam build sam validate --lint