Configuring the X-Ray SDK for Java
The X-Ray SDK for Java includes a class named AWSXRay
that provides
the global recorder. This is a TracingHandler
that you can use to instrument your code. You can
configure the global recorder to customize the AWSXRayServletFilter
that creates segments for incoming
HTTP calls.
Service plugins
Use plugins
to record information about the service hosting
your application.
Plugins
Amazon EC2 –
EC2Plugin
adds the instance ID, Availability Zone, and the CloudWatch Logs Group.Elastic Beanstalk –
ElasticBeanstalkPlugin
adds the environment name, version label, and deployment ID.Amazon ECS –
ECSPlugin
adds the container ID.Amazon EKS –
EKSPlugin
adds the container ID, cluster name, pod ID, and the CloudWatch Logs Group.
To use a plugin, call withPlugin
on your AWSXRayRecorderBuilder
.
Example src/main/java/scorekeep/WebConfig.java - recorder
import com.amazonaws.xray.AWSXRay;
import com.amazonaws.xray.AWSXRayRecorderBuilder;
import com.amazonaws.xray.plugins.EC2Plugin;
import com.amazonaws.xray.plugins.ElasticBeanstalkPlugin;
import com.amazonaws.xray.strategy.sampling.LocalizedSamplingStrategy;
@Configuration
public class WebConfig {
...
static {
AWSXRayRecorderBuilder builder = AWSXRayRecorderBuilder.standard().withPlugin(new EC2Plugin()).withPlugin(new ElasticBeanstalkPlugin());
URL ruleFile = WebConfig.class.getResource("/sampling-rules.json");
builder.withSamplingStrategy(new LocalizedSamplingStrategy(ruleFile));
AWSXRay.setGlobalRecorder(builder.build());
}
}
The SDK also uses plugin settings to set the origin
field on the segment. This indicates the type of AWS resource that runs your application.
When you use multiple plugins, the SDK uses the following resolution order to determine the origin: ElasticBeanstalk > EKS > ECS > EC2.
Sampling rules
The SDK uses the sampling rules you define in the X-Ray console to determine which requests to record. The default rule traces the first request each second, and five percent of any additional requests across all services sending traces to X-Ray. Create additional rules in the X-Ray console to customize the amount of data recorded for each of your applications.
The SDK applies custom rules in the order in which they are defined. If a request matches multiple custom rules, the SDK applies only the first rule.
Note
If the SDK can't reach X-Ray to get sampling rules, it reverts to a default local rule of the first request each second, and five percent of any additional requests per host. This can occur if the host doesn't have permission to call sampling APIs, or can't connect to the X-Ray daemon, which acts as a TCP proxy for API calls made by the SDK.
You can also configure the SDK to load sampling rules from a JSON document. The SDK can use local rules as a backup for cases where X-Ray sampling is unavailable, or use local rules exclusively.
Example sampling-rules.json
{
"version": 2,
"rules": [
{
"description": "Player moves.",
"host": "*",
"http_method": "*",
"url_path": "/api/move/*",
"fixed_target": 0,
"rate": 0.05
}
],
"default": {
"fixed_target": 1,
"rate": 0.1
}
}
This example defines one custom rule and a default rule. The custom rule applies a five-percent
sampling rate with no minimum number of requests to trace for paths under /api/move/
.
The default rule traces the first request each second and 10 percent of additional requests.
The disadvantage of defining rules locally is that the fixed target is applied by each instance of the recorder independently, instead of being managed by the X-Ray service. As you deploy more hosts, the fixed rate is multiplied, making it harder to control the amount of data recorded.
On AWS Lambda, you cannot modify the sampling rate. If your function is called by an instrumented service, calls that generated requests that were sampled by that service will be recorded by Lambda. If active tracing is enabled and no tracing header is present, Lambda makes the sampling decision.
To provide backup rules in Spring, configure the global recorder with a
CentralizedSamplingStrategy
in a configuration class.
Example src/main/java/myapp/WebConfig.java - recorder configuration
import com.amazonaws.xray.AWSXRay;
import com.amazonaws.xray.AWSXRayRecorderBuilder;
import com.amazonaws.xray.javax.servlet.AWSXRayServletFilter;
import com.amazonaws.xray.plugins.EC2Plugin;
import com.amazonaws.xray.strategy.sampling.LocalizedSamplingStrategy;
@Configuration
public class WebConfig {
static {
AWSXRayRecorderBuilder builder = AWSXRayRecorderBuilder.standard().withPlugin(new EC2Plugin());
URL ruleFile = WebConfig.class.getResource("/sampling-rules.json");
builder.withSamplingStrategy(new CentralizedSamplingStrategy(ruleFile));
AWSXRay.setGlobalRecorder(builder.build());
}
For Tomcat, add a listener that extends ServletContextListener
and register the listener in the
deployment descriptor.
Example src/com/myapp/web/Startup.java
import com.amazonaws.xray.AWSXRay;
import com.amazonaws.xray.AWSXRayRecorderBuilder;
import com.amazonaws.xray.plugins.EC2Plugin;
import com.amazonaws.xray.strategy.sampling.LocalizedSamplingStrategy;
import java.net.URL;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class Startup implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent event) {
AWSXRayRecorderBuilder builder = AWSXRayRecorderBuilder.standard().withPlugin(new EC2Plugin());
URL ruleFile = Startup.class.getResource("/sampling-rules.json");
builder.withSamplingStrategy(new CentralizedSamplingStrategy(ruleFile));
AWSXRay.setGlobalRecorder(builder.build());
}
@Override
public void contextDestroyed(ServletContextEvent event) { }
}
Example WEB-INF/web.xml
...
<listener>
<listener-class>com.myapp.web.Startup</listener-class>
</listener>
To use local rules only, replace the CentralizedSamplingStrategy
with a
LocalizedSamplingStrategy
.
builder.withSamplingStrategy(new
LocalizedSamplingStrategy
(ruleFile));
Logging
By default, the SDK outputs ERROR
-level messages to your application logs. You can enable debug-level logging on the SDK to
output more detailed logs to your application log file. Valid log levels are DEBUG
, INFO
, WARN
, ERROR
, and FATAL
.
FATAL
log level silences all log messages because the SDK does not log at fatal level.
Example application.properties
Set the logging level with the logging.level.com.amazonaws.xray
property.
logging.level.com.amazonaws.xray = DEBUG
Use debug logs to identify issues, such as unclosed subsegments, when you generate subsegments manually.
Trace ID injection into logs
To expose the current fully qualified trace ID to your log statements, you can inject the ID into the mapped diagnostic
context (MDC). Using the SegmentListener
interface, methods are called from the X-Ray recorder
during segment lifecycle events. When a segment or subsegment begins, the qualified trace ID is injected into the MDC with the key
AWS-XRAY-TRACE-ID
. When that segment ends, the key is removed from the MDC. This exposes the
trace ID to the logging library in use. When a subsegment ends, its parent ID is injected into the MDC.
Example fully qualified trace ID
The fully qualified ID is represented as TraceID@EntityID
1-5df42873-011e96598b447dfca814c156@541b3365be3dafc3
This feature works with Java applications instrumented with the AWS X-Ray SDK for Java, and supports the following logging configurations:
-
SLF4J front-end API with Logback backend
-
SLF4J front-end API with Log4J2 backend
-
Log4J2 front-end API with Log4J2 backend
See the following tabs for the needs of each front end and each backend.
Trace ID Injection Example
The following shows a PatternLayout
string modified to include the trace ID. The trace ID is
printed after the thread name (%t
) and before the log level (%-5p
).
Example PatternLayout
With ID injection
%d{HH:mm:ss.SSS} [%t]
%X{AWS-XRAY-TRACE-ID}
%-5p %m%n
AWS X-Ray automatically prints the key and the trace ID in the log statement for easy parsing. The
following shows a log statement using the modified PatternLayout
.
Example Log statement with ID injection
2019-09-10 18:58:30.844 [nio-5000-exec-4]
AWS-XRAY-TRACE-ID
: 1-5d77f256-19f12e4eaa02e3f76c78f46a@1ce7df03252d99e1 WARN 1 -Your logging message here
The logging message itself is housed in the pattern %m
and is set when calling the
logger.
Segment listeners
Segment listeners are an interface to intercept lifecycle events such as the beginning
and ending of segments produced by the AWSXRayRecorder
. Implementation of a
segment listener event function might be to add the same annotation to all subsegments when
they are created with onBeginSubsegment
, log a message after each segment is sent to the
daemon using afterEndSegment
, or to record queries sent by the SQL interceptors
using beforeEndSubsegment
to verify if the subsegment represents an SQL
query, adding additional metadata if so.
To see the full list of SegmentListener
functions, visit the documentation
for the AWS X-Ray Recorder SDK for Java API.
The following example shows how to add a consistent annotation to all subsegments on
creation with onBeginSubsegment
and to print a log message at the end of each
segment with afterEndSegment
.
Example MySegmentListener.java
import com.amazonaws.xray.entities.Segment;
import com.amazonaws.xray.entities.Subsegment;
import com.amazonaws.xray.listeners.SegmentListener;
public class MySegmentListener implements SegmentListener {
.....
@Override
public void onBeginSubsegment(Subsegment subsegment) {
subsegment.putAnnotation("annotationKey
", "annotationValue
");
}
@Override
public void afterEndSegment(Segment segment) {
// Be mindful not to mutate the segment
logger.info("Segment with ID " + segment.getId()
);
}
}
This custom segment listener is then referenced when building the
AWSXRayRecorder
.
Example AWSXRayRecorderBuilder statement
AWSXRayRecorderBuilder builder = AWSXRayRecorderBuilder
.standard().withSegmentListener(new MySegmentListener()
);
Environment variables
You can use environment variables to configure the X-Ray SDK for Java. The SDK supports the following variables.
AWS_XRAY_CONTEXT_MISSING
– Set toRUNTIME_ERROR
to throw exceptions when your instrumented code attempts to record data when no segment is open.Valid Values
-
RUNTIME_ERROR
– Throw a runtime exception. -
LOG_ERROR
– Log an error and continue (default). -
IGNORE_ERROR
– Ignore error and continue.
Errors related to missing segments or subsegments can occur when you attempt to use an instrumented client in startup code that runs when no request is open, or in code that spawns a new thread.
-
AWS_XRAY_DAEMON_ADDRESS
– Set the host and port of the X-Ray daemon listener. By default, the SDK uses127.0.0.1:2000
for both trace data (UDP) and sampling (TCP). Use this variable if you have configured the daemon to listen on a different port or if it is running on a different host.Format
-
Same port –
address
:port
-
Different ports –
tcp:
address
:port
udp:address
:port
-
-
AWS_LOG_GROUP
– Set the name of a log group to log group associated with your application. If your log group uses the same AWS account and region as your application, X-Ray will automatically search for your application's segment data using this specified log group. For more information about log groups, see Working with log groups and streams. -
AWS_XRAY_TRACING_NAME
– Set a service name that the SDK uses for segments. Overrides the service name that you set on the servlet filter's segment naming strategy.
Environment variables override equivalent system properties and values set in code.
System properties
You can use system properties as a JVM-specific alternative to environment variables. The SDK supports the following properties:
-
com.amazonaws.xray.strategy.tracingName
– Equivalent toAWS_XRAY_TRACING_NAME
. -
com.amazonaws.xray.emitters.daemonAddress
– Equivalent toAWS_XRAY_DAEMON_ADDRESS
. -
com.amazonaws.xray.strategy.contextMissingStrategy
– Equivalent toAWS_XRAY_CONTEXT_MISSING
.
If both a system property and the equivalent environment variable are set, the environment variable value is used. Either method overrides values set in code.