Notes On AWS X-Ray - A Distributed Tracing Mechanism

Overview

  • AWS X-Ray works with following services:

    • Amazon EC2, Amazon EC2 Container Service (Amazon ECS),
    • AWS Lambda, and
    • AWS Elastic Beanstalk.
  • With X-Ray, you can trace requests made to applications that span multiple AWS accounts, AWS Regions, and Availability Zones.

  • First, enable "active tracing" configuration on the Lambda functions console.

  • You need atleast following privileges:

    {
    

    "Effect":"Allow", "Action": [ "xray:PutTraceSegments", "xray:PutTelemetryRecords" ], "Resource":[ "*" ] }

  • You need serverless-plugin-tracing as dev dependency so that you can have tracing:true inside provider section in serverless.yml file.

  • You need aws-xray-sdk as runtime dependency package. (It is not available by default in lambda container!)

Synopsis

# If you plan to use only manual mode ...
yarn add aws-xray-sdk-core    # If you just need minimal functions.

AWSXRay.enableManualMode()
const segment = new AWSXRay.Segment('hello')
...
if (err) segment.addError(err)
..
segment.close()

// ################### Using Subsegments ######################


AWSXRay.enableManualMode();
const segment = new AWSXRay.Segment('hello function')
...
slowSubsegment = segment.addNewSubsegment('Slow Function')
...
if (err) slowSubsegment.addError(err)
...
slowSubsegment.close()


// ######## Using Top level Segments instead of Subsegments ####

new AWSXRay.Segment('Segment Name', parentSegment.trace_id, parentSegment.id);

// This will show the new segments in console trace graph.

//
// To get current global segment :  AWSXRay.getSegment()
//     


// ############################################################
// Full functionality ...

var XRay = require('aws-xray-sdk');
var AWS = XRay.captureAWS(require('aws-sdk'));
var http = XRay.captureHTTPs(require('http'));

...
 AWS.config.region = process.env.REGION

#
# Use plugins that you want to trace for.
#
XRay.config([XRay.plugins.EC2Plugin, XRay.plugins.ElasticBeanstalkPlugin]);

# What is middleware ?
XRay.middleware.setSamplingRules('sampling-rules.json');
XRay.middleware.enableDynamicNaming();

var app = express();
var sns = new AWS.SNS();
var ddb = new AWS.DynamoDB();

// Create new segment for use with express app as middleware
app.use(XRay.express.openSegment('myfrontend'));
....

Util Example Functions to Trace

export const slowFunction = async () => {
  await new Promise(resolve => setTimeout(resolve, 2000))
}

export const fasterFunction = async () => {
  await new Promise(resolve => setTimeout(resolve, 150))
}

export const unreliableFunction = async () => {
  if(Math.random() < 0.2) {
    throw new Error('Something went wrong')
  }
}

Configuration

  • In serverless.yml, you just say tracing:true in Provider section with the help of serverless-plugin-tracing. This is the shortcut for doing the following for each function :

    resources:
      Resources:
        #add aws xray config to our functions
        CreateLambdaFunction:
          Type: AWS::Lambda::Function
          Properties:
            TracingConfig:
              Mode:
                Active
    

Using Xray to generate Least privilege role

Highlights

const AWSXRay = require('aws-xray-sdk-core');
AWSXRay.captureHTTPsGlobal(require('http'));
AWSXRay.captureAWS(require('aws-sdk'));
AWSXRay.capturePromise();
AWSXRay.setLogger(logger.child({'xray': true}));


aws xray get-trace-summaries --start-time   ... --end-time ...

AWSXRay.captureAsyncFunc("getting restaurants", async_f,  AWSXRay.getSegment());

// use request-id header
const requestId = context.awsRequestId;

Use correlation id