log
log copied to clipboard
Make the stack trace and/or line number available
Possibly do something like this: https://github.com/eriwen/javascript-stacktrace
Or like this:
__LINE__ = (new Error).stack.split("\n")[1].match(/:([0-9]+):/)[1]
https://news.ycombinator.com/item?id=5540763
See https://news.ycombinator.com/item?id=5540716 for more information.
We definitely want to add line numbers. However, unfortunately, the nature of wrapping console.log
means we'll lose the ability to display the line number on the right.
There are a number of possible solutions we are considering to address this. For example, if we change the exports at the bottom of the script to something like the following:
window.log = console.log.bind(console)
window.log.format = stringToArgs
Then you could call the following and still get line numbers:
log(log.format('this is _bold_'))
If you didn't want the text to be formatted, you could still call:
log('this is _just some text with two underscores around it_')
Of course, having to wrap your string in a log.format
is certainly less sexy than we'd like. So we're considering other possible solutions as well.
On a related note, there may be some potential changes coming to console.log
. We're actively following and participating in the discussions here:
https://code.google.com/p/chromium/issues/detail?id=167911 https://bugs.webkit.org/show_bug.cgi?id=20141
Hi Adam,
I came up with a simple hack to enable logging line numbers. I have only tested it in Chrome though. Here's how it works:
- The
log.js:19
was useless information. I got rid of it by callingtoString()
onlog
and assigning towindow.log
usingeval
. - Used
console.groupCollapsed
instead ofconsole.log
. Clicking it opens a log statement with a link to actual file and line number, clicking which takes you to that file in the Sources tab. It only works if such a statement is logged directly usingconsole.log
without any other parameters or styles, which is whyconsole.group
was needed. -
console.group
makes all your text bold, so I had to use hacks to addfont-weight: normal
everywhere. - To make
log.l
log actual line numbers, I changed it to_log = console.log.bind(console)
.
I could've also added two console.log
statements: one for logging, the other for the file name and line number, but I thought that would be obtrusive and figured using console.group
would be a much elegant solution.
Limitations:
- Links in your log statements will no longer work, since clicking the log statement now expands / collapses the file and line number. (You can get around that by right clicking and selecting: Open in a new tab.)
- Clicking the source link sometimes takes you to the actual javascript code in a new tab. (Not sure why that happens. It works fine with inline js, prettified js and source maps.)
See source here: https://github.com/fleon/log/blob/master/log.coffee jsFiddle: http://jsfiddle.net/fleon/b6etu/1/
This is fantastic work. Very clever.
However, before merging I'd like to take the following steps.
- First, let's make sure we test in every one of the currently supported browsers. We may be able to feature test for
console.groupCollapsed
. If all else fails we can use anotheruserAgent
test. - Next, let's run some benchmarks on jsperf comparing this to the current version of log. If the performance is dramatically slower, we may release this as an alternative in the repo without wholesale replacing the original. Or we may want to refactor such that there's a way to call either version (
log
,log.l
, andlog.e
perhaps). - Finally, I'd like to spend a few more days brainstorming on possible ways to avoid the groups altogether. Your use of
eval
to remove the line number was very clever. I'm not so sure there aren't other clever tricks like that out there waiting to be found.
Thanks for your contribution!
I managed to get it working in Firefox+Firebug as well, but the hack is very ugly. It works without console.group
though.
Each log statement now shows up the filename and actual line number overlayed on top of the log.js line number (thanks to Firebug allowing position:absolute
in log styles). It's not clickable though, so I logged arguments.callee.caller
to its left, clicking which will take you to the function definition (close enough). To make sure it is positioned correctly with correct padding, I did some DOM insertion hacks (which would sorta make it slower, but we can get around that). Two console.log
s added an additional hr, which I managed to hide by overlaying with a white 1px high, 100% wide absolute box.
Nevertheless, this was a lot of fun!
Source: https://github.com/fleon/log/commit/0713275eae0f2ccfcd7f963016c4febd0e659cb7 (warning: ugly code) jsFiddle: http://jsfiddle.net/fleon/b6etu/1/
Another option, although not as independent, is to combine log.js with stacktrace.js. Here's the modified _log
function from log.js source (this is also only tested in Chrome and only with one simple test case, but we could test further if you want to go down this road):
_log = function() {
if (typeof window.printStackTrace === 'function') {
var trace = printStackTrace();
var callerLine = trace[trace.length-1];
var index = callerLine.indexOf("at ");
var clean = callerLine.slice(index+2, callerLine.length);
}
var array = makeArray(arguments);
if (clean) { array.push(clean); }
return console.log.apply(console, array);
};
Assuming you have included stacktrace.js
in your page and you call log('hello')
from line 4 of script.js
, the output will be: hello path/to/script.js:4:1
. If you don't have stacktrace.js
, everything still works fine -- just without the correct line number displayed.
See my fork at https://github.com/6twenty/log/commit/249864da2a39d80f7abd4774a11d8858a40af37c for a working example (coffeescript version updated too, but with a typo which is fixed in https://github.com/6twenty/log/commit/5f0f16820eb35c060e42dbf41a6ef8db4a5266d6).
you could do something like
if (Function.prototype.bind) {
//Preserves line numbers
window.log = Function.prototype.bind.call(console.log, console);
} else {
//Fallback
}
window.md = function(){
var args = Array.prototype.slice.call(arguments);
//style markdown in args
return args;
}
log(md("This is *italic*"));
or this:
function log(){
var args = Array.prototype.slice.call(arguments);
//style markdown in args
return Function.prototype.apply.bind(window.console.log,window.console, args)
}
log("This is *italic*")();
which would output nothing if you missed of the trailing ()
but is very concise otherwise.
@SamHasler Thanks! Those are both very interesting options.
The log(md("This is *italic*"));
is great as it's very clear what it's doing (assuming md
is understood). However, I'm not excited about adding another global to the scope. There's already a log.l
which attempts to serve this purpose, so perhaps the syntax would be log.l(log.md("This is *italic*));
. Not as good as yours but may be a good compromise. Then the library would say "If you care about line numbers, use log.l log.md
, and if you don't, just use log
".
The other approach is very tempting, but I think it's a little too tricky for our average user. I would worry too many people would miss the subtlety of the extra ()
and be frustrated with the library. Ironically, this could be mitigated with a console.log
message if the user tried log("This is *italic*")
but unfortunately we A) can't know what happens later in the call chain and B) wouldn't want to log anything additional in a log library ;). Nevertheless a similar option as above could be taken of making a log.something
which does this.
One of these will likely get us there though, so thanks again!
The user can turn on Chrome Dev Tools Settings > General > Sources > Skip stepping through sources with particular names
, and set pattern
to match log.min.js. It's worth documenting in the Readme.
However it doesn't help if they concatenate log.min.js into thier own code. See also: jsbin/jsbin#1833
Thanks @SamHasler. Didn’t know about that setting. :+1:
@SamHasler thanks for the tips with md()
I have question
When i code
log(md('[c="color: #32c5d2"] Mytexte in color : [c]'));
The console write a line in a array like this
how we can remove the bracket and first " ?