Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract call stack's information thanks latest v8 features #1342

Open
Mumeii opened this issue Nov 11, 2022 · 0 comments
Open

Extract call stack's information thanks latest v8 features #1342

Mumeii opened this issue Nov 11, 2022 · 0 comments

Comments

@Mumeii
Copy link
Contributor

Mumeii commented Nov 11, 2022

Hi

I've noticed that callstack information extraction is based on the use of a regular expression

It seems to work fine, but I wonder if the process could gain some speed-up by avoiding going thru all the burden of extracting it from call stack layers formatted as strings.

Indeed those strings themself got those informations from a NodeJS internal data structure !

And, fortunately, in the latest versions of the V8 engine, it's possible to skip the whole string & regexp management part using this feature

Here is a code sample I've already successfully used on a project :

const NOT_AVAILABLE_STRING = "N/A"

function getStackInfo() {
    // see following links for further informations about how to get the informations back :
    // - https://v8.dev/docs/stack-trace-api
    // - https://stackoverflow.com/questions/11386492/accessing-line-number-in-v8-javascript-chrome-node-js
    // - https://stackoverflow.com/a/59706213

    const oldStackTrace = Error.prepareStackTrace;

    try {
        // eslint-disable-next-line handle-callback-err
        Error.prepareStackTrace = ( _, structuredStackTrace ) => structuredStackTrace;

        const stackInfoAccessObject = new Error();

        Error.captureStackTrace( stackInfoAccessObject );

        // we have to peel the first callstack layers in order to get to the actual caller of the logger function
        // otherwise we'll always get the same callsite, pointing constantly to this logger.js file ... which would be useless :)
        // 
        // To do so, let's skip layers up to the current file reference (included)
        // And because there could be several layers pointing to this file, let's perform a bottom up search :
        const reversedStackShallowCopy = [ ...stackInfoAccessObject.stack ].reverse()

        // now we're reverted the callstack, we can look for the first occurence of current file name :
        const preCallsiteIdx = reversedStackShallowCopy
            .findIndex( stackLayer => stackLayer.getFileName() === __filename )
        
        // once found, what we're looking for is the callee of this layer, so the previous one :
        const callSite = reversedStackShallowCopy[ preCallsiteIdx - 1 ]

        // and to simplify the filename path, only keep the part relative to the project base directory :
        const relativeFileName = path.relative( PROJECT_BASE_DIRECTORY, callSite.getFileName() )

        // now we can return the requested informations :
        return {
            column: callSite.getColumnNumber(),
            line: callSite.getLineNumber(),
            func: callSite.getFunctionName(),
            method: callSite.getMethodName(),
            file: relativeFileName,
        };
    } catch( err ) {
        return { // in case of errors, return a placeholder structure ...
            column: -1,
            line: -1,
            func: NOT_AVAILABLE_STRING,
            method: NOT_AVAILABLE_STRING,
            file: NOT_AVAILABLE_STRING,
        }
    } finally {
        Error.prepareStackTrace = oldStackTrace;
    }
}

Of course, this sample is missing some features of already working version of defaultParseCallStack but it should be difficult to add them I guess

Please, notice that I can't certify that it will run faster, because I didn't performed tests myself.

But I doubt it could run slower, and the whole point here is to produce a code that should be stable.

Using an extraction process based on the v8 data structure prevent the code from having to change along potential futur changes of the call stack's string formatting process

@Mumeii Mumeii changed the title Extract callstack informations thanks modern feature Extract call stack's information thanks latest v8 features Nov 11, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant