Hacker News new | past | comments | ask | show | jobs | submit login
Console.log with style (adamschwartz.co)
236 points by adamschwartz on Apr 12, 2013 | hide | past | web | favorite | 56 comments

The problem with wrapping console.log is that you lose the ability to know what line number initiated the log entry. The line number Chrome gives for the log line will always be where you call console.log inside the wrapper, not the line where you call the wrapper. Since there's no way to grab the line number of a caller in JS (Chrome's dev console uses browser hooks unavailable in JS), you can't even emulate the line number reporting yourself as a suffix to the log entry.

Here is a way to fix this: https://gist.github.com/bgrins/5108712. When you call `log` it will preserve the line number.

Here is a demo: http://jsfiddle.net/bgrins/MZWtG/.

Beautiful solution -- line number links work and everything. You've just made my day.

This is brilliant!

Using straight console.log statements seems to be non-negotiable for effective debugging, at least until a good workaround for the above is found.

For using Chrome's logging styles, we define a few short helper functions — l1(), l2(), l3(), etc. — that return predefined CSS strings, then doing our logging like

    console.log("%cThis is a heading", l1())
    console.log("%cLess important stuff", l2())
This means you're only adding 6 or so characters to get nice styled console messages that also maintain the nice line numbers and links to the source. Plus, it's similar enough to h1, h2, etc. that it's easy to remember.

We found that varying the font color (black vs. gray) and margin-left (2em, 4em) were most helpful in differentiating more and less important log messages.

I recommend simply using console.debug, console.log, console.warn, and console.error, which differentiate for you.

What about `console.info()`? Or is it a bit too adventurous?

info and log are indistinguishable, at least in Chrome.

Yes. So much about differentiation.

Maybe add console.assert to that list:

    console.assert(str.length === 10, "String is not 10 characters long!");
and console.group/groupEnd

    console.log(1 + 1);
    console.log(2 - 3);

You actually can get the line number of a caller in JS: https://github.com/eriwen/javascript-stacktrace

You can just parse (new Error).stack:

    var __LINE__ = (new Error).stack.split("\n")[1].match(/:([0-9]+):/)[1];

I do something similar for logging my node apps... in .Net I use reflection for essentially the same.

`(new Error()).stack` is non-standard. But that’s a nice hack, nevertheless.

The underlying construct (console.log processing "%c" and styles) is nonstandard to begin with.

Yes. It will not break, though.

Unless you’re running it on an old IE that doesn’t host the `window.console` object.

Note: that uses arguments.callee, which is disallowed in ES5 strict-mode.

After looking at the code in more depth, I feel I should point out that it looks like `arguments.callee` is only the last-ditch fallback for generating a trace. I see baked-in support for Chrome, IE, FF, Safari, and Opera, and so unless your preferred browser is something else (or you want to target every possible browser) then you could change just a few lines to make it strict mode compliant.

Thanks for these suggestions. You can track progress on this here: https://github.com/adamschwartz/log/issues/1

This will severely degrade performance in almost every scenario. I don't recommend doing it by default, though it is a nice feature to have. Sometimes you want to be able to call console.log a few times per frame in a game without your framerate dropping into the single digits.

Calling `console.log()` in “production mode” is a bad idea, anyway.

Ideally, you’ll want those calls stripped at some point, in your build script.

I found a way... well, sort of:

    var log = function(){
        args = [].slice.call(arguments);
        return console.log.bind.apply(console.log, args) 
But you have to add extra parenthesis at the end, hopefully is not too much overhead for most devs.


> there's no way to grab the line number of a caller in JS

But this is easily fixed by converting the function call to a macro, right?

Oh wait - this isn't a ClojureScript library... so nevermind.

It's missing "This site is best viewed in IE5"... Err, I mean Chrome, but it's the same.

It's not supposed to be used everywhere.

It's a developer tool for browsers that have the requisite developer tools support.

Works also in Firefox with Firebug (but not yet in native Firefox console). See [1] for a blog entry from Jan Odvarko.

[1] http://www.softwareishard.com/blog/firebug/firebug-tip-style...

This "console"... IE5 didn't even have console... and event the current one IE haves is a joke compared to firefox or chrome.

I think parent is referring to the bad old days of browser specific sites.

The features of the console is not really a usability issue.

I'm on OS X with an external keyboard, and I gave up after trying 3 or 4 keyboard combinations. I literally don't know for sure what key any of the three symbols is referring to.

This is command + option + J

If you're using a windows keyboard, this should be the windows key + alt + J

ctrl + shift + j in chrome for windows (or simply F12)

Just updated the instructions: https://github.com/adamschwartz/log/commit/919f8ffac919f0183...

Basically just open the javascript console.

I think OP wanted ⌘ and ⌥ spelled out (command and option respectively)

right-click -> inspect element should work everywhere

On FreeBSD 9x it was Ctrl + Shift + i, so I inferred that what I initially thought was a lower case "L" was actually an upper case "I." (the Shift)

That was the first thing I tried, but apparently that opens Mail for some reason.

Try this: console.log('%cHello world', 'font-size:100px;color:#fff;text-shadow:0 1px 0 #ccc,0 2px 0 #c9c9c9,0 3px 0 #bbb,0 4px 0 #b9b9b9,0 5px 0 #aaa,0 6px 1px rgba(0,0,0,.1),0 0 5px rgba(0,0,0,.1),0 1px 3px rgba(0,0,0,.3),0 3px 5px rgba(0,0,0,.2),0 5px 10px rgba(0,0,0,.25),0 10px 10px rgba(0,0,0,.2),0 20px 20px rgba(0,0,0,.15);');

btw orignal Creator is Sindre Sorhus -- try this var _log = console.log; console.log = function() { _log.call(console, '%c' + [].slice.call(arguments).join(' '), 'color:transparent;text-shadow:0 0 2px rgba(0,0,0,.5);'); };

Then run some console.log("Hello Console") or other statements after executing the function above and see the prank ;)

That's awesome!

Didn't know it's possible, I need to read Addy Osmani's posts more often (https://plus.google.com/+AddyOsmani/posts/TanDFKEN9Kn)

These are the CSS attr's they accept

  ["background", "border", "color", "font", "line", "margin", "padding", "text", "-webkit-background", "-webkit-border", "-webkit-font", "-webkit-margin", "-webkit-padding", "-webkit-text"]
Try this:

  console.log("%c ", 'background: url("http://placekitten.com/200/200"); padding: 5000px')
edit: put my code snippets in code blocks

Um, great, how am I supposed to trust the console if even logging in that one can be screwed up?

YUI has a pretty nice console.log wrapper with tons of extra functionality. I don't use all of its functionality, but it does have the nice feature of not breaking IE when calling console.log without first having the Developer Tools window open.



Really cool!

I don't want to sound nitpicky buuuuuut in text based emails folks have been using bold, /italics/, _underlining_, and {{{ preformatted }}} text for a long time with slightly different syntax. How attached are you to the one you chose? Would you be open to accepting a patch to use the older syntax?

I once tried to write a markup parser with slashes for italics, then I understood why no parser seems to use them. It interferes with URLs, dates, slashes as "or", etc.

AFAIR thunderbird used it

For this first pass I went with a markdown-like syntax. However, I'm not tied to it.

Submit a PR here https://github.com/adamschwartz/log/pulls and we'll consider it if there is wide support.

Cool find aside, it must degrade gracefully on a non-Chrome console.

Edit: also, try log('this is code: `a =* `= b* == c`');

If anybody else is wondering how this is possible:


Is there anything I need to get this to work? It doesn't work for me in OS X on Chrome 23

Update to Chrome 26 (latest stable)

That's kinda surprising; WebKit's has had support for this for 6 months now: https://trac.webkit.org/browser/trunk/Source/WebCore/inspect... (I thought chromium was pretty quick to bump webkit revs)

This seems like a terrible idea. Another potential failure point for no good reason.

Holy crap that's beautiful. Thanks for showing this off.

firefox 20.0 on mac osx 10.8.2, not working for me :(

Registration is open for Startup School 2019. Classes start July 22nd.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact