First, you’ll need to install aws-xray-sdk-core module by running one of the following commands:

yarn add aws-xray-sdk-core npm i --save aws-xray-sdk-core

Let’s start with a simple Lambda with one segment:

import AWSXRay from 'aws-xray-sdk-core'



AWSXRay.enableManualMode()



const fetchData = () => {

return {

message: 'hello'

}

}



export const hello = (event, context, callback) => {

const segment = new AWSXRay.Segment('hello')



try {

const data = fetchData()



callback(null, {

statusCode: 200,

body: data,

})



} catch(err) {

segment.addError(err)

} finally {

segment.close()

}

}

Running this code you will see something like that in the AWS X-Ray console:

It shows the percentage of errors, average execution time and number of requests per minute. But let’s do something more complex. Let’s say you have an endpoint that has several parts of code which you want to analyze separately:

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')

}

}

That’s where sub-segments or additional segments come into play:

import AWSXRay from 'aws-xray-sdk-core'



import { slowFunction, fasterFunction, unreliableFunction } from './functions'



AWSXRay.enableManualMode()



const fetchData = async (segment) => {

const slowSubsegment = segment.addNewSubsegment('Slow Function')



try {

await slowFunction()

} finally {

slowSubsegment.close()

}



const fasterSubsegment = segment.addNewSubsegment('Faster Function')



try {

await fasterFunction()

} finally {

fasterSubsegment.close()

}



const unreliableSubsegment = segment.addNewSubsegment('Unreliable Function')



try {

await unreliableFunction()

} catch (err) {

unreliableSubsegment.addError(err)

throw err

} finally {

unreliableSubsegment.close()

}



return {

message: 'hello'

}

}



export const hello = async (event, context, callback) => {

const segment = new AWSXRay.Segment('hello function')



try {

const data = await fetchData(segment)



callback(null, data)

} catch(err) {

segment.addError(err)

callback(err)

} finally {

segment.close()

}

}

Successfully running that function will give following trace in X-Ray:

Now you can analyze your response time with real-time production data.

If our unreliable function throws an error the trace will have information on that as well:

Same here, you can analyze your application health and investigate errors much easier than going through megabytes of logs.

But that code is ugly. You definitely don’t want to pollute your code with all the try stuff. Let’s wrap it into a helper function:

import AWSXRay from 'aws-xray-sdk-core'



import { slowFunction, fasterFunction, unreliableFunction } from './functions'



AWSXRay.enableManualMode()



const asyncSubsegment = async (name, parent, fn) => {

const subsegment = parent.addNewSubsegment(name)

try {

return await fn()

} catch (e) {

subsegment.addError(e)

throw e

} finally {

subsegment.close()

}

}



const fetchData = async (segment) => {

await asyncSubsegment('Slow Function', segment, slowFunction)



await asyncSubsegment('Faster Function', segment, fasterFunction)



return asyncSubsegment('Unreliable Function', segment, unreliableFunction)

}



export const hello = async (event, context, callback) => {

const segment = new AWSXRay.Segment('hello function')



try {

const data = await fetchData(segment)

callback(null, data)

} catch(err) {

segment.addError(err)

callback(err)

} finally {

segment.close()

}

}

Not a perfect solution, but looks much better. You might want to do a bunch of helper functions and reuse them across your application.

Full example code