Crocon 🐊

Crocon makes developer console great again.

Crocon is a Javascript wrapper for browser's developer console. Its goal is to make debugging painless, convenient and beautiful.

This is a Rails gem version of the library. For source files and an npm package, go here.

Installation

Add this to your Gemfile:

gem 'crocon'

Add this to your application.js:

//= require crocon

Add this to your application.css:

*= require crocon

Why?

The builtin developer console in modern browsers suffers from a number of problems. Here are some of the big ones:

There's no good way to turn logging on/off.

Most of the time you don't want your clients to see debugging output in their console on your production website. But, console.log does not care if it runs in development or production, it's going to log anyway. This leads to developers seldom using the console or writing console.log over and over again just to erase it afterwards (...just to write it back again afterwards, and so on). Disabling the console is still possible (e.x. if (!debug) console.log = function () {}), but it's not a good solution if you use other console methods (which you should!). Also, imagine you want to be able to see debugging output in production while normal website users don't see anything. What do you do?

Crocon solves this problem by introducing a flexible enable/disable mechanism. First of all, you can enable or disable it during initialization: crocon = new Crocon({ enabled: debug }) (assuming that debug is true in development and false in production). But also, you can enable or disable Crocon in your browser (crocon.enable() or crocon.disable()), which will override the global enabled option. Thus, you can easily switch Crocon on/off in any environment, and it will only affect your console.

See initialization options.

console.group is a great idea, but it's not implemented well

With console.group you can split your output in foldable groups, which is a very good thing to be able to do. However, a lot of JS these days is asynchronous, which is something you have to constantly think about if you want to group your output.

Consider this simple scenario:

async function f1() {
    console.group('group 1');
    console.log('function 1 start');
    await sleep(1000);
    console.log('function 1 end');
    console.groupEnd();
}

async function f2() {
    console.group('group 2');
    console.log('function 2 start');
    await sleep(500);
    console.log('function 2 end');
    console.groupEnd();
}

f1(); f2()

Result:

Async and groups

Crocon solves this by creating a different implementation of groups. With Crocon, you can use groups like this:

crocon.group('my namespace').log('hello from my namespace')
/* or */
crocon.group('my namespace', function () {
  crocon.log('hello from my namespace')
  /* ... */
})

See grouping

console.log supports formatting with CSS, but it's not convenient

console supports formatting with CSS rules:

console.log('roses are %cred%c, violets are %cblue', 'color: red;', 'color: black;', 'color: blue;')

Result:

Console formatting

This is awesome, but really not convenient.

Crocon makes formatting much easier by introducing a markdown-like syntax. See formatting.

Browser support

TBD

Usage

Methods that work exactly like their console's counterparts:

Also:

crocon.profile('profile1')
myVar = myFunction()
crocon.profileEnd()

/* is the same as */

myVar = crocon.profile('profile1', myFunction)

Initialization options

crocon = new Crocon({
  enabled: true,
  enableFormatting: true,
  collapseGroups: false,
  modifyConsole: true
})
  • enabledByDefault: Defines whether to enable or disable Crocon. When Crocon is disabled, it will not produce any output. However, lambda versions of profile, time and group will still execute given functions. Default: true.
  • enableFormatting: Defines whether formatting should be enabled. Default: true.
  • collapseGroups: Defines whether groups should be collapsed or not. Default: false (expanded).
  • modifyConsole: Defines whether Crocon needs to modify console upon initialization. Generally, modifying global objects is a bad thing to do, but this is required if you want Crocon to handle console output correctly. Crocon is modifying console functions very carefully (it just needs to hook to those methods). You can safely disable this options, but regular console output will occasionally get stuck inside groups it does not belong to. see known issues. Default: true.

Grouping

Groups in Crocon work a little different from console's groups. There are two ways to group the output.

/* method 1 */
crocon.group('group one').log('inside group 1')

/* method 2 */
crocon.group('group one', function () {
  crocon.log('inside group 1')
})

You can easily mix methods together and nest groups however you want:

crocon.group('user login', function () {
  crocon.info('user login started')
  crocon.group('credentials').log('credentials are [correct].green')
  /* code */
  crocon.info('[success].badge.green')
})

crocon.group('group 1').log('some more output')
crocon.group('group 1', 'another group!').log('still nested correctly')

Output:

Group output

When document is not in focus (e.g. your console is in focus), the output becomes:

Inline group output

This behaviour is explained in known issues.

Formatting

Crocon supports Markdown-like string formatting. Here's the options:

  • **bold**
  • *italic*
  • ~strikethrough~
  • _underline_
  • [custom text].classOne.classTwo.... This syntax allows you to apply CSS classes to text in square brackets. Available classes are: badge, bold, italic, strikethrough, underline and color classes.

At the moment, you cannot nest formatting options into each other. Objects and functions are not formattable, but they likely will be in the future.

Color classes

Crocon supports following color classes (both for badges and normal text):

  • .blue
  • .orange
  • .red
  • .green
  • .cyan
  • .purple

Adding custom / overriding existing styles

All styles are declared in a stylesheet and thus are easily extensible. See index.scss. At the moment, only these attributes are supported: margin, color, background-color, border-radius, padding, font-weight, font-style, text-decoration.

Known issues

  • There's no way to detect when console output happens. Development tools are separate from window and document, and there is no way to know if the output is happening. We can detect things like console.log by modifying those functions (hence the modifyConsole init parameter), but we cannot know when, say, an error thrown with throw is going to appear in console. Groups are implemented in such a way that they don't get closed until it's necessary, so that leads to console output being stuck inside groups it doesn't belong to. Part of the problem is solved by modifying console, but another part is not solvable without a browser extension. The best we can do is to detect whether or not document is in focus (with document.hasFocus()). This enables us to change how groups work if document is not in focus (say, console is in focus). However, some things (like throw or click on the "clear console" button) are simply not catchable. So, some output will inevitably get stuck in a group it doesn't belong. Beware of this, especially when using collapseGroups = true.

  • Stack traces from crocon.error and crocon.trace contain unneeded information. Since crocon.error and crocon.trace call some functions under the hood, the stack trace produced by those functions will contain several unneeded calls.

All of this is according to the author's research. If you know a solution to this problem, you're highly encouraged to open an issue and/or a pull request at akxcv/crocon.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/akxcv/crocon.

License

The package is available as open source under the terms of the MIT License.

TODO

  • Support nested styles
  • Log history
  • Replace stylesheet with in-memory CSS?
  • Focus mode (see only the logs you need right now)
  • Custom styles in formatting (e.x. [my text]{color: #434433;})
  • Browser support
  • Object and function formatting