0

I am trying to use AWS X-Ray in my SailsJS application. I noticed missing subsegments - I added custom traces via AWSXRay.captureAsyncFunc but noticed they are missing. After some closer inspection, I think they actually ended up in a different trace. Lets say I call login API then another API later. I notice my login API trace is weird

Notice theres calls quite abit after the request should have ended.

Those requests should actually be in another segment:

enter image description here

I'd think they should appear after find device subsegment. Why are segments scrambled like that?


My setup: in http.js,

const AWSXRay = require('aws-xray-sdk');
const xrayEnabled = process.env.AWS_XRAY === 'yes'

module.exports.http = {
  middleware: {
    order: [
        'startRequestTimer',
        'cookieParser',
        'session',
        'myRequestLogger',
        'bodyParser',
        'handleBodyParserError',
        'compress',
        'methodOverride',
        'poweredBy',
        'awsXrayStart',
        'router',
        'awsXrayEnd',
        'www',
        'favicon',
        '404',
        '500',
    ],

    awsXrayStart: xrayEnabled ? AWSXRay.express.openSegment(`cast-${process.env.NODE_ENV || 'noenv'}`) : (req, res, next) => next(),
    awsXrayEnd: xrayEnabled ? AWSXRay.express.closeSegment() : (req, res, next) => next(),

Then I wrapped my promises like:

instrumentPromise(promise, name, metadata = {}) {
    if (this.isXrayEnabled()) {
        return new Promise((resolve, reject) => {
            AWSXRay.captureAsyncFunc(name, (subsegment) => {
                if (!subsegment) console.warn(`[XRAY] Failed to instrument ${name}`)
                Object.keys(metadata).forEach(k => {
                    if (subsegment) subsegment.addMetadata(k, metadata[k])
                })
                console.time(`[XRAY TIME] ${name}`)
                promise
                    .then((data) => {
                        if (subsegment) subsegment.close()
                        console.timeEnd(`[XRAY TIME] ${name}`)
                        resolve(data)
                    })
                    .catch(err => {
                        if (subsegment) subsegment.close()
                        console.timeEnd(`[XRAY TIME] ${name}`)
                        reject(err)
                    })
            })
        })
    }
    return promise
}

Is there any information I am missing here? What am I doing wrong?


I tried manual mode and its alot more reliable but I have to manually pass segment around. Whats wrong with automatic mode? I am kind of guessing it does not work well with async nature nodejs? Like the SDK is not able to differenciate between the various async requests? And may close or track segments in the wrong places? That said ... its supposed to work with express, why isit not working as expected ...

Another thing is how will a shared mysql connection pool be tracked correctly by X-Ray? Different segments will be using the same mysql pool. I assume this will not work work well at all?

Jiew Meng
  • 84,767
  • 185
  • 495
  • 805

1 Answers1

0

The issue you encounter seems to be related to how CLS handle context binding with Promise. There is a opt-in promise patch introduced in this PR https://github.com/aws/aws-xray-sdk-node/pull/11. It has full discussion around the repros and fixes. That should resolve the issue with subsegments being attached to the wrong trace.

The SDK does support capturing pool.query. You can see examples here https://www.npmjs.com/package/aws-xray-sdk-mysql.

haotian465
  • 679
  • 3
  • 4