Skip to content

refactor: consistent naming of powertools tracing and initial docs. #48

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Logger
title: Logging
description: Core utility
---

Expand Down
12 changes: 0 additions & 12 deletions docs/content/core/tracer.mdx

This file was deleted.

58 changes: 58 additions & 0 deletions docs/content/core/tracing.mdx
Original file line number Diff line number Diff line change
@@ -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<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

@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<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

@PowertoolsTracing(captureError = false, captureResponse = false)
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
...
}
```
4 changes: 2 additions & 2 deletions docs/gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ module.exports = {
'index'
],
'Core utilities': [
'core/tracer',
'core/logger'
'core/logging',
'core/tracing'
]
},
navConfig: {
Expand Down
8 changes: 4 additions & 4 deletions example/HelloWorldFunction/src/main/java/helloworld/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -32,7 +32,7 @@ public class App implements RequestHandler<APIGatewayProxyRequestEvent, APIGatew
Logger log = LogManager.getLogger();

@PowertoolsLogging(logEvent = true)
@PowerToolsTracing
@PowertoolsTracing(captureError = false, captureResponse = false)
public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
Map<String, String> headers = new HashMap<>();

Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
*
* <p>{@code PowertoolsLogging} provides an opinionated logger with output structured as JSON.</p>
*
* <p>{@code PowertoolsLogging} should be used with handleRequest method of a class
* <p>{@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}.</p>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,47 +13,117 @@
*/
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());

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> 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> 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> 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) {
Subsegment segment = AWSXRay.beginSubsegment("## " + name);
segment.setNamespace(namespace);
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
*
* <p>{@code PowertoolsTracing} provides functionality to reduce the overhead
* of performing common tracing tasks.</p>
*
* <p>{@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}.</p>
*
* <p>By default {@code PowertoolsTracing} will capture responses and add them
* to a sub segment named after the method.</p>
*
* <p>To disable this functionality you can specify {@code @PowertoolsTracing( captureRespones = false)}</p>
*
* <p>By default {@code PowertoolsTracing} will capture errors and add them
* to a sub segment named after the method.</p>
*
* <p>To disable this functionality you can specify {@code @PowertoolsTracing( captureError = false)}</p>
*e
* <p>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}</p>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PowertoolsTracing {
String namespace() default "";
boolean captureResponse() default true;
boolean captureError() default true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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()) {
Expand All @@ -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();
}

Expand Down
Loading