Skip to content

Commit d856068

Browse files
author
Pankaj Agrawal
committed
Initial implementation of tracing support
1 parent 7efdbc0 commit d856068

File tree

7 files changed

+157
-2
lines changed

7 files changed

+157
-2
lines changed

example/HelloWorldFunction/src/main/java/helloworld/App.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
import org.apache.logging.log4j.Logger;
1717
import software.aws.lambda.logging.PowerLogger;
1818
import software.aws.lambda.logging.PowerToolsLogging;
19+
import software.aws.lambda.tracing.PowerToolTracing;
20+
import software.aws.lambda.tracing.PowerTracer;
21+
22+
import static software.aws.lambda.tracing.PowerTracer.putMetadata;
1923

2024
/**
2125
* Handler for requests to Lambda function.
@@ -25,6 +29,7 @@ public class App implements RequestHandler<APIGatewayProxyRequestEvent, APIGatew
2529
Logger log = LogManager.getLogger();
2630

2731
@PowerToolsLogging(logEvent = true)
32+
@PowerToolTracing
2833
public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
2934
Map<String, String> headers = new HashMap<>();
3035
headers.put("Content-Type", "application/json");
@@ -37,8 +42,15 @@ public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEv
3742
try {
3843
final String pageContents = this.getPageContents("https://checkip.amazonaws.com");
3944
log.info(pageContents);
45+
PowerTracer.putAnnotation("Test", "New");
4046
String output = String.format("{ \"message\": \"hello world\", \"location\": \"%s\" }", pageContents);
4147

48+
PowerTracer.withSubsegment("loggingResponse", subsegment -> {
49+
String sampled = "log something out";
50+
log.info(sampled);
51+
log.info(output);
52+
});
53+
4254
log.info("After output");
4355
return response
4456
.withStatusCode(200)
@@ -50,8 +62,10 @@ public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEv
5062
}
5163
}
5264

65+
@PowerToolTracing(namespace = "getPageContents", captureResponse = false, captureError = false)
5366
private String getPageContents(String address) throws IOException {
5467
URL url = new URL(address);
68+
putMetadata("getPageContents", address);
5569
try (BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()))) {
5670
return br.lines().collect(Collectors.joining(System.lineSeparator()));
5771
}

example/template.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ Resources:
2020
MemorySize: 512
2121
Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object
2222
Variables:
23-
PARAM1: VALUE
23+
POWERTOOLS_SERVICE_NAME: SAILING
24+
Tracing: Active
2425
Events:
2526
HelloWorld:
2627
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
@@ -35,6 +36,7 @@ Resources:
3536
Handler: helloworld.AppStream::handleRequest
3637
Runtime: java8
3738
MemorySize: 512
39+
Tracing: Active
3840
Environment:
3941
Variables:
4042
PARAM1: VALUE

pom.xml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,32 @@
8383
<artifactId>aspectjrt</artifactId>
8484
<version>${aspectj.version}</version>
8585
</dependency>
86+
<dependency>
87+
<groupId>com.amazonaws</groupId>
88+
<artifactId>aws-xray-recorder-sdk-core</artifactId>
89+
<version>2.4.0</version>
90+
</dependency>
91+
<dependency>
92+
<groupId>com.amazonaws</groupId>
93+
<artifactId>aws-xray-recorder-sdk-aws-sdk</artifactId>
94+
<version>2.4.0</version>
95+
</dependency>
96+
<dependency>
97+
<groupId>com.amazonaws</groupId>
98+
<artifactId>aws-xray-recorder-sdk-aws-sdk-instrumentor</artifactId>
99+
<version>2.4.0</version>
100+
</dependency>
101+
<dependency>
102+
<groupId>com.amazonaws</groupId>
103+
<artifactId>aws-xray-recorder-sdk-aws-sdk-v2</artifactId>
104+
<version>2.4.0</version>
105+
</dependency>
106+
<dependency>
107+
<groupId>com.amazonaws</groupId>
108+
<artifactId>aws-xray-recorder-sdk-aws-sdk-v2-instrumentor</artifactId>
109+
<version>2.4.0</version>
110+
</dependency>
111+
86112

87113
<!-- Test dependencies -->
88114
<dependency>

src/main/java/software/aws/lambda/logging/internal/LambdaAspect.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public final class LambdaAspect {
3535
public void callAt(PowerToolsLogging powerToolsLogging) {
3636
}
3737

38-
@Around(value = "callAt(powerToolsLogging)", argNames = "pjp,powerToolsLogging")
38+
@Around(value = "callAt(powerToolsLogging) && execution(@PowerToolsLogging * *.*(..))", argNames = "pjp,powerToolsLogging")
3939
public Object around(ProceedingJoinPoint pjp,
4040
PowerToolsLogging powerToolsLogging) throws Throwable {
4141
Object[] proceedArgs = pjp.getArgs();
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package software.aws.lambda.tracing;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Retention(RetentionPolicy.RUNTIME)
9+
@Target(ElementType.METHOD)
10+
public @interface PowerToolTracing {
11+
String namespace() default "";
12+
boolean captureResponse() default true;
13+
boolean captureError() default true;
14+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package software.aws.lambda.tracing;
2+
3+
import java.util.function.Consumer;
4+
5+
import com.amazonaws.xray.AWSXRay;
6+
import com.amazonaws.xray.entities.Subsegment;
7+
8+
public final class PowerTracer {
9+
public static final String SERVICE_NAME = null != System.getenv("POWERTOOLS_SERVICE_NAME")
10+
? System.getenv("POWERTOOLS_SERVICE_NAME") : "default";
11+
12+
public static void putAnnotation(String key, String value) {
13+
AWSXRay.getCurrentSubsegmentOptional()
14+
.ifPresent(segment -> segment.putAnnotation(key, value));
15+
}
16+
17+
public static void putMetadata(String key, Object value) {
18+
String namespace = AWSXRay.getCurrentSubsegmentOptional()
19+
.map(Subsegment::getNamespace).orElse(SERVICE_NAME);
20+
21+
putMetadata(namespace, key, value);
22+
}
23+
24+
public static void putMetadata(String namespace, String key, Object value) {
25+
AWSXRay.getCurrentSubsegmentOptional()
26+
.ifPresent(segment -> segment.putMetadata(namespace, key, value));
27+
}
28+
29+
public static void withSubsegment(String name, Consumer<Subsegment> subsegment) {
30+
Subsegment segment = AWSXRay.beginSubsegment("## " + name);
31+
try {
32+
subsegment.accept(segment);
33+
}finally {
34+
AWSXRay.endSubsegment();
35+
}
36+
}
37+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package software.aws.lambda.tracing.internal;
2+
3+
import com.amazonaws.xray.AWSXRay;
4+
import com.amazonaws.xray.entities.Subsegment;
5+
import com.fasterxml.jackson.databind.ObjectMapper;
6+
import org.aspectj.lang.ProceedingJoinPoint;
7+
import org.aspectj.lang.annotation.Around;
8+
import org.aspectj.lang.annotation.Aspect;
9+
import org.aspectj.lang.annotation.Pointcut;
10+
import software.aws.lambda.tracing.PowerToolTracing;
11+
12+
import static software.aws.lambda.tracing.PowerTracer.SERVICE_NAME;
13+
14+
@Aspect
15+
public final class LambdaTracingAspect {
16+
static Boolean IS_COLD_START = null;
17+
private static final ObjectMapper mapper = new ObjectMapper();
18+
19+
@Pointcut("@annotation(powerToolsTracing)")
20+
public void callAt(PowerToolTracing powerToolsTracing) {
21+
}
22+
23+
@Around(value = "callAt(powerToolsTracing) && execution(@PowerToolTracing * *.*(..))", argNames = "pjp,powerToolsTracing")
24+
public Object around(ProceedingJoinPoint pjp,
25+
PowerToolTracing powerToolsTracing) throws Throwable {
26+
Object[] proceedArgs = pjp.getArgs();
27+
Subsegment segment;
28+
29+
segment = AWSXRay.beginSubsegment("## " + pjp.getSignature().getName());
30+
segment.setNamespace(namespace(powerToolsTracing));
31+
32+
if (placedOnHandlerMethod(pjp)) {
33+
segment.putAnnotation("ColdStart", IS_COLD_START == null);
34+
}
35+
36+
IS_COLD_START = false;
37+
38+
try {
39+
Object proceed = pjp.proceed(proceedArgs);
40+
if (powerToolsTracing.captureResponse()) {
41+
segment.putMetadata(namespace(powerToolsTracing), pjp.getSignature().getName() + " response", proceed);
42+
}
43+
return proceed;
44+
} catch (Exception e) {
45+
if (powerToolsTracing.captureError()) {
46+
segment.putMetadata(namespace(powerToolsTracing), pjp.getSignature().getName() + " error", e);
47+
}
48+
throw e;
49+
} finally {
50+
AWSXRay.endSubsegment();
51+
}
52+
}
53+
54+
private String namespace(PowerToolTracing powerToolsTracing) {
55+
return powerToolsTracing.namespace().isEmpty() ? SERVICE_NAME : powerToolsTracing.namespace();
56+
}
57+
58+
// TODO enrich to check more like inherited class
59+
private boolean placedOnHandlerMethod(ProceedingJoinPoint pjp) {
60+
return "handleRequest".equals(pjp.getSignature().getName());
61+
}
62+
}

0 commit comments

Comments
 (0)