Configuring the X-Ray SDK for Java (original) (raw)

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.

Sections

Service plugins

Use plugins to record information about the service hosting your application.

Plugins

Segment resource data with Amazon EC2 and Elastic Beanstalk plugins.

To use a plugin, call withPlugin on your AWSXRayRecorderBuilder.

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 aCentralizedSamplingStrategy in a configuration class.

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 aLocalizedSamplingStrategy.

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 keyAWS-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:

See the following tabs for the needs of each front end and each backend.

SLF4J Frontend

  1. Add the following Maven dependency to your project.
<dependency>  
    <groupId>com.amazonaws</groupId>  
    <artifactId>aws-xray-recorder-sdk-slf4j</artifactId>  
    <version>2.11.0</version>  
</dependency>  
  1. Include the withSegmentListener method when building theAWSXRayRecorder. This adds a SegmentListener class, which automatically injects new trace IDs into the SLF4J MDC.
    The SegmentListener takes an optional string as a parameter to configure the log statement prefix. The prefix can be configured in the following ways:
    • None – Uses the default AWS-XRAY-TRACE-ID prefix.
    • Empty – Uses an empty string (e.g. "").
    • Custom – Uses a custom prefix as defined in the string.
Example AWSXRayRecorderBuilder statement
AWSXRayRecorderBuilder builder = AWSXRayRecorderBuilder  
        .standard().withSegmentListener(new SLF4JSegmentListener("CUSTOM-PREFIX"));  

Log4J2 front end

  1. Add the following Maven dependency to your project.
<dependency>  
    <groupId>com.amazonaws</groupId>  
    <artifactId>aws-xray-recorder-sdk-log4j</artifactId>  
    <version>2.11.0</version>  
</dependency>  
  1. Include the withSegmentListener method when building theAWSXRayRecorder. This will add a SegmentListener class, which automatically injects new fully qualified trace IDs into the SLF4J MDC.
    The SegmentListener takes an optional string as a parameter to configure the log statement prefix. The prefix can be configured in the following ways:
    • None – Uses the default AWS-XRAY-TRACE-ID prefix.
    • Empty – Uses an empty string (e.g. "") and removes the prefix.
    • Custom – Uses the custom prefix defined in the string.
Example AWSXRayRecorderBuilder statement
AWSXRayRecorderBuilder builder = AWSXRayRecorderBuilder  
        .standard().withSegmentListener(new Log4JSegmentListener("CUSTOM-PREFIX"));  

Logback backend

To insert the trace ID into your log events, you must modify the logger's PatternLayout, which formats each logging statement.

  1. Find where the patternLayout is configured. You can do this programmatically, or through an XML configuration file. To learn more, see Logback configuration.
  2. Insert %X{AWS-XRAY-TRACE-ID} anywhere in the patternLayout to insert the trace ID in future logging statements. %X{} indicates that you are retrieving a value with the provided key from the MDC. To learn more about PatternLayouts in Logback, see PatternLayout.

Log4J2 backend

  1. Find where the patternLayout is configured. You can do this programmatically, or through a configuration file written in XML, JSON, YAML, or properties format.
    To learn more about configuring Log4J2 through a configuration file, see Configuration.
    To learn more about configuring Log4J2 programmatically, see Programmatic Configuration.
  2. Insert %X{AWS-XRAY-TRACE-ID} anywhere in the PatternLayout to insert the trace ID in future logging statements. %X{} indicates that you are retrieving a value with the provided key from the MDC. To learn more about PatternLayouts in Log4J2, see Pattern Layout.
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 theAWSXRayRecorder.

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.

Valid Values
Format

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:

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.