Skip to content

Instantly share code, notes, and snippets.

@brianmriley
Last active April 27, 2016 12:02
Show Gist options
  • Save brianmriley/876abe19466192a83396 to your computer and use it in GitHub Desktop.
Save brianmriley/876abe19466192a83396 to your computer and use it in GitHub Desktop.
Attempt to wrap the `console.log()` method of the browser and successfully bind to the client object calling `logger.debug()` and not the logger itself.
// I've created a simple logger (wraps console.* methods) that provides output similar to say Log4J or other robust
// loggers out there for the enterprise, but a huge missing piece (for me) is that you can no longer see the file
// reference and line number from the client object using the logger. When you use console.log() OOTB it'll spit out
// a clickable link to the file and line number that executed the console.log making it easy to debug; when you wrap
// console.log it simply spits out the logger file reference and the line number the console.log was executed, so
// all logging shows up as from the logger wrapper (which is technically correct)...bottom line, you lose the context
// from which you actually made the logging call and I'd like to get that back.
// Aside from blackboxing, is there another way to wrap console.log() such that it binds to the client callee
// and ultimately shows the correct file reference and line number of the callee (and not the log wrapper)?
// @JohnYanarella pointed me to the blackboxing solution for Chrome Dev Tools via Paul Irish
// http://bl.ocks.org/paulirish/c307a5a585ddbcc17242, but I'm looking for a code-only solution...possible?
// `console.log.bind` is used as an attempt to force the client calling `logger.debug()` to save
// the correct line numbers and file so it shows up correctly in Chrome Dev Tools' console and not as
// those of the logger itself.
var logFactory =
{
// Correctly displays the client object filename and line number that called debug(),
// but we can't manipulate the input.
getLoggerA: function () {
return {
// I want to intercept the args being passed to debug() from the
// client object calling so I can further manipulate the actual log
// and not hardcode to say "MAGIC"...so in the example below, how do we
// capture the incoming "BMR" and change it to "BMR, TJM, AG"?
debug: console.log.bind(console, 'MAGIC')
};
},
// DOES NOT correctly display the client object filename and line number that called debug()
// and shows the logger itself, but does allow us to capture the input...
getLoggerB: function () {
return {
debug: (function () {
var logFn = console.log.bind(console);
return function (msg) {
logFn("PREFIX ", msg);
};
})()
};
},
// DOES NOT correctly display the client object filename and line number that called debug()
// and shows the logger itself, but does allow us to capture the input...
getLoggerC: function (context) {
var Logger = function(context)
{
this.context = context || "DEFAULT CONTEXT";
this.logFn = console.log.bind(console);
this.debug = function(msg) {
this.logFn(this.context, msg);
}
};
return new Logger(context);
}
};
logFactory.getLoggerA().debug("BMR"); // output >> "MAGIC BMR" with correct line numbers and file ref
logFactory.getLoggerB().debug("BMR"); // output >> "PREFIX BMR" with incorrect line numbers and file ref
logFactory.getLoggerC().debug("BMR"); // output >> "DEFAULT CONTEXT BMR" with incorrect line numbers and file ref
@ThomasBurleson
Copy link

When I run the above in Developer Tools console, the functions called directly appear to work as expected:

getLogger-debug-results

From what I understand ^^, you actually want to head hook the original console.log and console.debug alls. The above code does NOT head hook (aka head intercept); so calls to console.log( ) will work without your above interceptors.

An additional issue is the you can only effectively intercept/hook 1x; unless you do parameter recognitions. This means that your originating calls will need something like:

var $log = logFactory.getLoggerC();

$log.debug("This is an error message", "Line 37");

Am I understanding the situation correctly?

@brianmriley
Copy link
Author

brianmriley commented Apr 27, 2016

@ThomasBurleson Some context...I've created a simple logger (wraps console.* methods) that provides output similar to say Log4J or other robust loggers out there for the enterprise, but a huge missing piece (for me) is that you can no longer see the file reference and line number from the client object using the logger. When you use console.log() OOTB it'll spit out a clickable link to the file and line number that executed the console.log making it easy to debug; when you wrap console.log it simply spits out the logger file reference and the line number the console.log was executed, so all logging shows up as from the logger wrapper (which is technically correct)...bottom line, you lose the context from which you actually made the logging call and I'd like to get that back.

If you want to see exactly what I'm talking about you'll need to drop the logger code into one file, let's call it Logger.js, and then create a second file called FooBar.js that calls logFactory.getLoggerA().debug("BMR"); and run it in the console...you'll see that the file ref and line number are for Logger.js and not FooBar.js.

@Codecatalyst I see your tweet with the following updated "Issue 1859293002: [DevTools] Move Console to v8_inspector (Closed)", but haven'r had a chance to see if this fixes the issue: https://codereview.chromium.org/1859293002

@brianmriley
Copy link
Author

And sorry for the delayed response @ThomasBurleson as I didn't realize gists no longer notify you when someone comments: isaacs/github#21

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment