tscpp
tscpp

Reputation: 1576

JavaScript Change console call stack

Correct Behavior

When I call console.log() directly from a function, the stack (function and file) from which i called is correct in dev-tools console, as expected.

main.js:

function main() {
    // Works correctly
    console.log('Hello from main()!');
}

Console:

Hello from main()!    ...    main.js:3                       

What I want

Now, when I add a second file called debug.js and call console.log from there, the file from where i called is debug.js, which is correct... but I need debug() to log as if it was called in main.js. Somehow I need to modify the caller, stack or trace to fool console.log() it was called from main.js, when it actually was from deubg.js.

Code

debug.js:

function debug(msg) {
   console.log(msg)
}

main.js

function main() {
   debug('Hello world!') // debug() in debug.js
}

Behavior

The current behavior:

Hello world!    ...    debug.js:2

The behavior I want:

Hello world!    ...    main.js:3

Upvotes: 13

Views: 2471

Answers (4)

Brandon McConnell
Brandon McConnell

Reputation: 6129

The originally recommended solution below no longer appears to work:


I believe the issue here is that console log is typically executed from wherever it runs. However, if you were to pass back a function that performs the console log, this might work as you'd like it to. Can you try the below code?

Attempt #1

debug.js:

function debug(msg) {
   return (function(msg) { console.log(msg) })(msg)
}

main.js:

function main() {
   debug('Hello world!')
}

If that doesn't work, could you try this:

Attempt #2

debug.js:

function debug() {
   return function(msg) { console.log(msg) }
}

main.js:

function main() {
   debug()('Hello world!')
}

UPDATE

As the above solutions no longer work, these are some viable alternatives:

2 methods:

1. console.trace()

One workaround to this problem is to simply console.trace() rather than console.log(), which will log the entire call stack along with the logged data, so debug() would look like this:

function debug(msg) {
  console.trace(msg);
}

2. Error().stack

Alternatively, if you only want the very first item from the call stack, you can extract the entire call stack from a new Error() and then log that with your data, which might look something like this:

function debug(msg) {
  const stackTrace = Error().stack.split('\n    at ').slice(1);
  console.log(msg, `\n\ntriggered by ${stackTrace.at(-1)}`);
}

In either of these cases, main.js can simply use debug('Hello world!');.

Upvotes: 8

Yash Shah
Yash Shah

Reputation: 141

What you could do is:

const log = console.log // for future use, preserve the default function
console.log = (...args) => {
    console.trace(...args)
}

On Node:

console.log = (...args) => {
    console.trace(...args, path.basename(__filename))
}

To get something like this:

const path = require("path");
console.log = (...args) => {
  console.trace(...args, path.basename(__filename))
}

function f() {
  return function g() {
    console.log("test")
  }
}

f()()

Upvotes: 0

Ravikumar
Ravikumar

Reputation: 2205

This can be done by creating Error instance new Error() which will hold the traces in string form like below.

function debug(...args) {
    const error = new Error();
    console.log(...args, error.stack.replace(/.+\n.+\n/, ''))
}

Though the MDN Error stack document says it's a non standard property but seems all browser has support for that Browser compatibility

Upvotes: 1

Guerric P
Guerric P

Reputation: 31825

As the WHATWG specification says, the output of the console for every function (error, warn, log, etc...) is implementation-specific:

The printer operation is implementation-defined

As it happens, chromium based browsers display the current frame of the callstack (not the full callstack) when printing the result of a console.log, and you won't be able to change this behavior, because this is related to the JavaScript engine (V8 for chromium based browsers), and not customizable through JavaScript code.

The only JavaScript standard that allows you to display the full callstack is console.trace whose specification is here: https://console.spec.whatwg.org/#trace

It will display something like this for your example code:

console.trace in a chromium based browser

Upvotes: 4

Related Questions