From dd9c3612d4577107c71eb3ebc63b56bb4602329a Mon Sep 17 00:00:00 2001 From: msailes Date: Tue, 25 Aug 2020 14:49:37 +0100 Subject: [PATCH] refactor: consistent naming of powertools tracing and initial docs. --- docs/content/core/{logger.mdx => logging.mdx} | 2 +- docs/content/core/tracer.mdx | 12 --- docs/content/core/tracing.mdx | 58 +++++++++++++++ docs/gatsby-config.js | 4 +- .../src/main/java/helloworld/App.java | 8 +- .../powertools/logging/PowertoolsLogging.java | 2 +- .../powertools/tracing/PowerToolsTracing.java | 27 ------- .../powertools/tracing/PowerTracer.java | 74 ++++++++++++++++++- .../powertools/tracing/PowertoolsTracing.java | 53 +++++++++++++ .../tracing/internal/LambdaTracingAspect.java | 18 ++--- .../handlers/PowerTracerToolEnabled.java | 4 +- .../PowerTracerToolEnabledForStream.java | 10 +-- ...cerToolEnabledForStreamWithNoMetaData.java | 10 +-- .../PowerTracerToolEnabledWithException.java | 4 +- .../PowerTracerToolEnabledWithNoMetaData.java | 4 +- 15 files changed, 214 insertions(+), 76 deletions(-) rename docs/content/core/{logger.mdx => logging.mdx} (99%) delete mode 100644 docs/content/core/tracer.mdx create mode 100644 docs/content/core/tracing.mdx delete mode 100644 powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/PowerToolsTracing.java create mode 100644 powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/PowertoolsTracing.java diff --git a/docs/content/core/logger.mdx b/docs/content/core/logging.mdx similarity index 99% rename from docs/content/core/logger.mdx rename to docs/content/core/logging.mdx index dcf56cd44..4e6590582 100644 --- a/docs/content/core/logger.mdx +++ b/docs/content/core/logging.mdx @@ -1,5 +1,5 @@ --- -title: Logger +title: Logging description: Core utility --- diff --git a/docs/content/core/tracer.mdx b/docs/content/core/tracer.mdx deleted file mode 100644 index daeb3557c..000000000 --- a/docs/content/core/tracer.mdx +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: Tracer -description: Core utility ---- - -import Note from "../../src/components/Note" - -Tracer is an opinionated thin wrapper for [AWS X-Ray Java SDK](https://github.com/aws/aws-xray-sdk-java/). - -**Key features** - -* Support tracing async methods \ No newline at end of file diff --git a/docs/content/core/tracing.mdx b/docs/content/core/tracing.mdx new file mode 100644 index 000000000..554147514 --- /dev/null +++ b/docs/content/core/tracing.mdx @@ -0,0 +1,58 @@ +--- +title: Tracing +description: Core utility +--- + +import Note from "../../src/components/Note" + +Powertools tracing is an opinionated thin wrapper for [AWS X-Ray Java SDK](https://github.com/aws/aws-xray-sdk-java/) +a provides functionality to reduce the overhead of performing common tracing tasks. + + ** Key Features + + * Capture cold start as annotation, and responses as well as full exceptions as metadata + * Helper methods to improve the developer experience of creating new X-Ray subsegments. + * Better developer experience when developing with multiple threads. + +Initialization +Your AWS Lambda function must have permission to send traces to AWS X-Ray - Here is an example using AWS Serverless Application Model (SAM) + +```yaml:title=template.yaml +Resources: + HelloWorldFunction: + Type: AWS::Serverless::Function + Properties: + ... + Runtime: java8 + + Tracing: Active + Environment: + Variables: + POWERTOOLS_SERVICE_NAME: example +``` + +The Powertools service name is used as the X-Ray namespace. This can be set using the environment variable +`POWERTOOLS_SERVICE_NAME` + +To enable Powertools tracing to your function add the @PowertoolsTracing annotation to your handleRequest method. + +```java +public class App implements RequestHandler { + + @PowertoolsTracing + public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) { + ... + } +``` + +By default this annotation will automatically record method responses and exceptions. To disable these features set the +parameter to false in the annotation. + +```java +public class App implements RequestHandler { + + @PowertoolsTracing(captureError = false, captureResponse = false) + public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) { + ... + } +``` \ No newline at end of file diff --git a/docs/gatsby-config.js b/docs/gatsby-config.js index 07abebb99..c9aa9459a 100644 --- a/docs/gatsby-config.js +++ b/docs/gatsby-config.js @@ -23,8 +23,8 @@ module.exports = { 'index' ], 'Core utilities': [ - 'core/tracer', - 'core/logger' + 'core/logging', + 'core/tracing' ] }, navConfig: { diff --git a/example/HelloWorldFunction/src/main/java/helloworld/App.java b/example/HelloWorldFunction/src/main/java/helloworld/App.java index a22a3b067..8f39e4d78 100644 --- a/example/HelloWorldFunction/src/main/java/helloworld/App.java +++ b/example/HelloWorldFunction/src/main/java/helloworld/App.java @@ -10,8 +10,8 @@ import org.apache.logging.log4j.Logger; import software.amazon.lambda.powertools.logging.PowertoolsLogger; import software.amazon.lambda.powertools.logging.PowertoolsLogging; -import software.amazon.lambda.powertools.tracing.PowerToolsTracing; import software.amazon.lambda.powertools.tracing.PowerTracer; +import software.amazon.lambda.powertools.tracing.PowertoolsTracing; import java.io.BufferedReader; import java.io.IOException; @@ -32,7 +32,7 @@ public class App implements RequestHandler headers = new HashMap<>(); @@ -90,13 +90,13 @@ private void threadOption2() throws InterruptedException { anotherThread.join(); } - @PowerToolsTracing + @PowertoolsTracing private void log() { log.info("inside threaded logging for function"); } - @PowerToolsTracing(namespace = "getPageContents", captureResponse = false, captureError = false) + @PowertoolsTracing(namespace = "getPageContents", captureResponse = false, captureError = false) private String getPageContents(String address) throws IOException { URL url = new URL(address); putMetadata("getPageContents", address); diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/PowertoolsLogging.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/PowertoolsLogging.java index a60d5a4c9..0ff944d3c 100644 --- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/PowertoolsLogging.java +++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/PowertoolsLogging.java @@ -24,7 +24,7 @@ * *

{@code PowertoolsLogging} provides an opinionated logger with output structured as JSON.

* - *

{@code PowertoolsLogging} should be used with handleRequest method of a class + *

{@code PowertoolsLogging} should be used with the handleRequest method of a class * which implements either * {@code com.amazonaws.services.lambda.runtime.RequestHandler} or * {@code com.amazonaws.services.lambda.runtime.RequestStreamHandler}.

diff --git a/powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/PowerToolsTracing.java b/powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/PowerToolsTracing.java deleted file mode 100644 index c1b671e36..000000000 --- a/powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/PowerToolsTracing.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2020 Amazon.com, Inc. or its affiliates. - * Licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package software.amazon.lambda.powertools.tracing; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface PowerToolsTracing { - String namespace() default ""; - boolean captureResponse() default true; - boolean captureError() default true; -} diff --git a/powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/PowerTracer.java b/powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/PowerTracer.java index 05587a045..24f593ccc 100644 --- a/powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/PowerTracer.java +++ b/powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/PowerTracer.java @@ -13,21 +13,42 @@ */ package software.amazon.lambda.powertools.tracing; -import java.util.function.Consumer; - import com.amazonaws.xray.AWSXRay; import com.amazonaws.xray.entities.Entity; import com.amazonaws.xray.entities.Subsegment; +import java.util.function.Consumer; + import static software.amazon.lambda.powertools.core.internal.LambdaHandlerProcessor.serviceName; +/** + * A class of helper functions to add additional functionality and ease + * of use. + * + */ public final class PowerTracer { + /** + * Put an annotation to the current subsegment. + * + * @param key the key of the annotation + * @param value the value of the annotation + */ public static void putAnnotation(String key, String value) { AWSXRay.getCurrentSubsegmentOptional() .ifPresent(segment -> segment.putAnnotation(key, value)); } + /** + * Put additional metadata for the current subsegment. + * + * The namespace used will be the namespace of the current subsegment if it + * is set else it will follow the namespace process as described in + * {@link PowertoolsTracing} + * + * @param key the key of the metadata + * @param value the value of the metadata + */ public static void putMetadata(String key, Object value) { String namespace = AWSXRay.getCurrentSubsegmentOptional() .map(Subsegment::getNamespace).orElse(serviceName()); @@ -35,25 +56,74 @@ public static void putMetadata(String key, Object value) { putMetadata(namespace, key, value); } + /** + * Put additional metadata for the current subsegment. + * + * @param namespace the namespace of the metadata + * @param key the key of the metadata + * @param value the value of the metadata + */ public static void putMetadata(String namespace, String key, Object value) { AWSXRay.getCurrentSubsegmentOptional() .ifPresent(segment -> segment.putMetadata(namespace, key, value)); } + /** + * Adds a new subsegment around the passed consumer. This also provides access to + * the newly created subsegment. + * + * The namespace used follows the flow as described in {@link PowertoolsTracing} + * + * This method is intended for use with multi-threaded programming where the + * context is lost between threads. + * + * @param name the name of the subsegment + * @param entity the current x-ray context + * @param subsegment the x-ray subsegment for the wrapped consumer + */ public static void withEntitySubsegment(String name, Entity entity, Consumer subsegment) { AWSXRay.setTraceEntity(entity); withEntitySubsegment(serviceName(), name, entity, subsegment); } + /** + * Adds a new subsegment around the passed consumer. This also provides access to + * the newly created subsegment. + * + * This method is intended for use with multi-threaded programming where the + * context is lost between threads. + * + * @param namespace the namespace of the subsegment + * @param name the name of the subsegment + * @param entity the current x-ray context + * @param subsegment the x-ray subsegment for the wrapped consumer + */ public static void withEntitySubsegment(String namespace, String name, Entity entity, Consumer subsegment) { AWSXRay.setTraceEntity(entity); withSubsegment(namespace, name, subsegment); } + /** + * Adds a new subsegment around the passed consumer. This also provides access to + * the newly created subsegment. + * + * The namespace used follows the flow as described in {@link PowertoolsTracing} + * + * @param name the name of the subsegment + * @param subsegment the x-ray subsegment for the wrapped consumer + */ public static void withSubsegment(String name, Consumer subsegment) { withSubsegment(serviceName(), name, subsegment); } + /** + * Adds a new subsegment around the passed consumer. This also provides access to + * the newly created subsegment. + * + * @param namespace the namespace for the subsegment + * @param name the name of the subsegment + * @param subsegment the x-ray subsegment for the wrapped consumer + */ public static void withSubsegment(String namespace, String name, Consumer subsegment) { Subsegment segment = AWSXRay.beginSubsegment("## " + name); segment.setNamespace(namespace); diff --git a/powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/PowertoolsTracing.java b/powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/PowertoolsTracing.java new file mode 100644 index 000000000..c79ef38d6 --- /dev/null +++ b/powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/PowertoolsTracing.java @@ -0,0 +1,53 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.tracing; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * {@code PowertoolsTracing} is used to signal that the annotated method should + * be extended with the Powertools tracing functionality. + * + *

{@code PowertoolsTracing} provides functionality to reduce the overhead + * of performing common tracing tasks.

+ * + *

{@code PowertoolsTracing} should be used with the handleRequest method of a class + * which implements either + * {@code com.amazonaws.services.lambda.runtime.RequestHandler} or + * {@code com.amazonaws.services.lambda.runtime.RequestStreamHandler}.

+ * + *

By default {@code PowertoolsTracing} will capture responses and add them + * to a sub segment named after the method.

+ * + *

To disable this functionality you can specify {@code @PowertoolsTracing( captureRespones = false)}

+ * + *

By default {@code PowertoolsTracing} will capture errors and add them + * to a sub segment named after the method.

+ * + *

To disable this functionality you can specify {@code @PowertoolsTracing( captureError = false)}

+ *e + *

All traces have a namespace set. If {@code @PowertoolsTracing( namespace = "ExampleService")} is set + * this takes precedent over any value set in the environment variable {@code POWER_TOOLS_SERVICE_NAME}. + * If both are undefined then the value will default to {@code service_undefined}

+ */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface PowertoolsTracing { + String namespace() default ""; + boolean captureResponse() default true; + boolean captureError() default true; +} diff --git a/powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/internal/LambdaTracingAspect.java b/powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/internal/LambdaTracingAspect.java index 6e09f3305..e24165824 100644 --- a/powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/internal/LambdaTracingAspect.java +++ b/powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/internal/LambdaTracingAspect.java @@ -19,7 +19,7 @@ import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; -import software.amazon.lambda.powertools.tracing.PowerToolsTracing; +import software.amazon.lambda.powertools.tracing.PowertoolsTracing; import static software.amazon.lambda.powertools.core.internal.LambdaHandlerProcessor.coldStartDone; import static software.amazon.lambda.powertools.core.internal.LambdaHandlerProcessor.isColdStart; @@ -33,25 +33,21 @@ public final class LambdaTracingAspect { @SuppressWarnings({"EmptyMethod", "unused"}) @Pointcut("@annotation(powerToolsTracing)") - public void callAt(PowerToolsTracing powerToolsTracing) { + public void callAt(PowertoolsTracing powerToolsTracing) { } - @Around(value = "callAt(powerToolsTracing) && execution(@PowerToolsTracing * *.*(..))", argNames = "pjp,powerToolsTracing") + @Around(value = "callAt(powerToolsTracing) && execution(@PowertoolsTracing * *.*(..))", argNames = "pjp,powerToolsTracing") public Object around(ProceedingJoinPoint pjp, - PowerToolsTracing powerToolsTracing) throws Throwable { + PowertoolsTracing powerToolsTracing) throws Throwable { Object[] proceedArgs = pjp.getArgs(); - Subsegment segment; - segment = AWSXRay.beginSubsegment("## " + pjp.getSignature().getName()); + Subsegment segment = AWSXRay.beginSubsegment("## " + pjp.getSignature().getName()); segment.setNamespace(namespace(powerToolsTracing)); - boolean placedOnHandlerMethod = placedOnHandlerMethod(pjp); - - if (placedOnHandlerMethod) { + if (placedOnHandlerMethod(pjp)) { segment.putAnnotation("ColdStart", isColdStart() == null); } - try { Object methodReturn = pjp.proceed(proceedArgs); if (powerToolsTracing.captureResponse()) { @@ -70,7 +66,7 @@ public Object around(ProceedingJoinPoint pjp, } } - private String namespace(PowerToolsTracing powerToolsTracing) { + private String namespace(PowertoolsTracing powerToolsTracing) { return powerToolsTracing.namespace().isEmpty() ? serviceName() : powerToolsTracing.namespace(); } diff --git a/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabled.java b/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabled.java index 6c24a2c1b..3c2b58820 100644 --- a/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabled.java +++ b/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabled.java @@ -15,12 +15,12 @@ import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; -import software.amazon.lambda.powertools.tracing.PowerToolsTracing; +import software.amazon.lambda.powertools.tracing.PowertoolsTracing; public class PowerTracerToolEnabled implements RequestHandler { @Override - @PowerToolsTracing(namespace = "lambdaHandler") + @PowertoolsTracing(namespace = "lambdaHandler") public Object handleRequest(Object input, Context context) { return null; } diff --git a/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabledForStream.java b/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabledForStream.java index 0f92a0fe9..3fc12485e 100644 --- a/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabledForStream.java +++ b/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabledForStream.java @@ -13,17 +13,17 @@ */ package software.amazon.lambda.powertools.tracing.handlers; -import java.io.InputStream; -import java.io.OutputStream; - import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestStreamHandler; -import software.amazon.lambda.powertools.tracing.PowerToolsTracing; +import software.amazon.lambda.powertools.tracing.PowertoolsTracing; + +import java.io.InputStream; +import java.io.OutputStream; public class PowerTracerToolEnabledForStream implements RequestStreamHandler { @Override - @PowerToolsTracing(namespace = "streamHandler") + @PowertoolsTracing(namespace = "streamHandler") public void handleRequest(InputStream input, OutputStream output, Context context) { } diff --git a/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabledForStreamWithNoMetaData.java b/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabledForStreamWithNoMetaData.java index 30924d782..802268a35 100644 --- a/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabledForStreamWithNoMetaData.java +++ b/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabledForStreamWithNoMetaData.java @@ -13,17 +13,17 @@ */ package software.amazon.lambda.powertools.tracing.handlers; -import java.io.InputStream; -import java.io.OutputStream; - import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestStreamHandler; -import software.amazon.lambda.powertools.tracing.PowerToolsTracing; +import software.amazon.lambda.powertools.tracing.PowertoolsTracing; + +import java.io.InputStream; +import java.io.OutputStream; public class PowerTracerToolEnabledForStreamWithNoMetaData implements RequestStreamHandler { @Override - @PowerToolsTracing(captureResponse = false, captureError = false) + @PowertoolsTracing(captureResponse = false, captureError = false) public void handleRequest(InputStream input, OutputStream output, Context context) { } diff --git a/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabledWithException.java b/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabledWithException.java index ed4696dad..1b34e8bdc 100644 --- a/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabledWithException.java +++ b/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabledWithException.java @@ -15,12 +15,12 @@ import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; -import software.amazon.lambda.powertools.tracing.PowerToolsTracing; +import software.amazon.lambda.powertools.tracing.PowertoolsTracing; public class PowerTracerToolEnabledWithException implements RequestHandler { @Override - @PowerToolsTracing(namespace = "lambdaHandler") + @PowertoolsTracing(namespace = "lambdaHandler") public Object handleRequest(Object input, Context context) { throw new RuntimeException("I am failing!"); } diff --git a/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabledWithNoMetaData.java b/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabledWithNoMetaData.java index 96e193438..925fb0e30 100644 --- a/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabledWithNoMetaData.java +++ b/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/handlers/PowerTracerToolEnabledWithNoMetaData.java @@ -15,12 +15,12 @@ import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; -import software.amazon.lambda.powertools.tracing.PowerToolsTracing; +import software.amazon.lambda.powertools.tracing.PowertoolsTracing; public class PowerTracerToolEnabledWithNoMetaData implements RequestHandler { @Override - @PowerToolsTracing(captureResponse = false, captureError = false) + @PowertoolsTracing(captureResponse = false, captureError = false) public Object handleRequest(Object input, Context context) { return null; }