Tracing Function Calls in JavaScript or Node.js or Dialogflow

For debugging our code we often need to track the function call hierarchy. There we need to understand and visualise which function is being called by which function and their sequence of calls. If you search for this in JavaScript then you will either find the deprecated features like Function.caller or not very flexible or useful features like console.trace(). So I found no better way than my custom developed one (as follows) to trace function calls in JavaScript while building my Google Dialogflow Chatbot.

Here is the main function which can be called from anywhere in your code with a new Error() parameter to locate the function call and its path/hierarchy of calls. Please note that the output of the trace depends on where you create the Error() object.
function trace(e) {
    if (!e) e = new Error()
    let result
    const errStack = e.stack
    if (errStack) {
        const stackArr = errStack.split('\n')
        const fDetailsArr = []
        let fDetails // function details
        stackArr.forEach(line => {
            fDetails = extract(line)
            if (fDetails)
                if (fDetails.fn)
                    if (fDetails.fn.indexOf('.') <= 0) // system/framework objects generally have '.'
                        fDetailsArr.push(fDetails.fp)
        })

        if (fDetailsArr.length > 0) {
            fDetailsArr.reverse()
            result = fDetailsArr.join(' ==> ')
        }
    }
    return result
}
This function takes the help of the following helper function to extract the function details from each line of the trace.
function extract(line) {
    let fp, fn, fl // function path (name+location), function name, function location
    let pathArr, pathLocIndex = -1, fnPart, fnParts, flPart
    if (line) {
        const parts = line.split('(')
        if (parts.length > 1) {
            fnPart = parts[0] // file name part
            flPart = parts[1] // file location part
            if (fnPart && flPart) {
                fnParts = fnPart.split('at ')
                if (fnParts.length > 1) fn = fnParts[1] // function name
                if (flPart.indexOf('\\') >= 0)
                    pathArr = flPart.split('\\')
                else if (flPart.indexOf('/') >= 0)
                    pathArr = flPart.split('/') // cloud function run file path has this
                if (pathArr) pathLocIndex = pathArr.length - 1
                if (pathLocIndex > 0) {
                    fl = '(' + pathArr[pathLocIndex] // function file path and location of the code
                    fp = fn + fl
                    if (fn) fn = fn.trim() // file name has a trailing space
                }
            }
        }
    }
    if (fp)
        return { fp, fn, fl }
    else return null
}

This is was as per my exact requirement so it may not fit 100% with your need. So you may need to modify the logic of the code if your requirement differs from mine. However, the overall code will hopefully be similar to this.

I have also used this custom function call tracer to enhance my custom logger function which you can read at Handling Complex Logs better for Google Cloud Functions

Thank you.

Post a Comment