README.md 9.14 KB
Newer Older
liang ce committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
# pretty-error

[![Dependency status](https://david-dm.org/AriaMinaei/pretty-error.svg)](https://david-dm.org/AriaMinaei/pretty-error)
[![Build Status](https://secure.travis-ci.org/AriaMinaei/pretty-error.svg?branch=master)](https://travis-ci.org/AriaMinaei/pretty-error) [![npm](https://img.shields.io/npm/dm/pretty-error.svg)](https://npmjs.org/package/pretty-error)

A small tool to see node.js errors with less clutter:

![screenshot of pretty-error](https://github.com/AriaMinaei/pretty-error/raw/master/docs/images/pretty-error-screenshot.png)

... which is more readable compared to node's unformatted errors:

![screenshot of normal errors](https://github.com/AriaMinaei/pretty-error/raw/master/docs/images/normal-error-screenshot.png)

## Installation

Install with npm:

	$ npm install pretty-error

## Usage and Examples

To see an error rendered with colors, you can do this:

```javascript
var PrettyError = require('pretty-error');
var pe = new PrettyError();

var renderedError = pe.render(new Error('Some error message'));
console.log(renderedError);
```

Of course, you can render caught exceptions too:

```javascript
try {
   doSomethingThatThrowsAnError();
} catch (error) {
   console.log(pe.render(error));
}
```

But if you want pretty-error to render all errors, there is a shortcut for it:

```javascript
require('pretty-error').start();
```

... which is essentially equal to:

```javascript
var PrettyError = require('pretty-error');

// instantiate PrettyError, which can then be used to render error objects
var pe = new PrettyError();
pe.start();
```

You can also preload pretty-error into your code using node's [`--require`](https://nodejs.org/api/cli.html#cli_r_require_module) argument:

```
$ node --require pretty-error/start your-module.js
```

## How it Works

PrettyError turns error objects into something similar to an html document, and then uses [RenderKid](https://github.com/AriaMinaei/renderkid) to render the document using simple html/css-like commands. This allows PrettyError to be themed using simple css-like declarations.

## Theming

PrettyError's default theme is a bunch of simple css-like rules. [Here](https://github.com/AriaMinaei/pretty-error/blob/master/src/defaultStyle.coffee) is the source of the default theme.

Since the default theme is all css, you can customize it to fit your taste. Let's do a minimal one:

```javascript
// the start() shortcut returns an instance of PrettyError ...
pe = require('pretty-error').start();

// ... which we can then use to customize like this:
pe.appendStyle({
   // this is a simple selector to the element that says 'Error'
   'pretty-error > header > title > kind': {
      // which we can hide:
      display: 'none'
   },

   // the 'colon' after 'Error':
   'pretty-error > header > colon': {
      // we hide that too:
      display: 'none'
   },

   // our error message
   'pretty-error > header > message': {
      // let's change its color:
      color: 'bright-white',

      // we can use black, red, green, yellow, blue, magenta, cyan, white,
      // grey, bright-red, bright-green, bright-yellow, bright-blue,
      // bright-magenta, bright-cyan, and bright-white

      // we can also change the background color:
      background: 'cyan',

      // it understands paddings too!
      padding: '0 1' // top/bottom left/right
   },

   // each trace item ...
   'pretty-error > trace > item': {
      // ... can have a margin ...
      marginLeft: 2,

      // ... and a bullet character!
      bullet: '"<grey>o</grey>"'

      // Notes on bullets:
      //
      // The string inside the quotation mark gets used as the character
      // to show for the bullet point.
      //
      // You can set its color/background color using tags.
      //
      // This example sets the background color to white, and the text color
      // to cyan, the character will be a hyphen with a space character
      // on each side:
      // example: '"<bg-white><cyan> - </cyan></bg-white>"'
      //
      // Note that we should use a margin of 3, since the bullet will be
      // 3 characters long.
   },

   'pretty-error > trace > item > header > pointer > file': {
      color: 'bright-cyan'
   },

   'pretty-error > trace > item > header > pointer > colon': {
      color: 'cyan'
   },

   'pretty-error > trace > item > header > pointer > line': {
      color: 'bright-cyan'
   },

   'pretty-error > trace > item > header > what': {
      color: 'bright-white'
   },

   'pretty-error > trace > item > footer > addr': {
      display: 'none'
   }
});
```

This is how our minimal theme will look like: ![screenshot of our custom theme](https://github.com/AriaMinaei/pretty-error/raw/master/docs/images/custom-theme-screenshot.png)

Read [RenderKid](https://github.com/AriaMinaei/renderkid)'s docs to learn about all the css rules that are supported.

## Customization

There are a few methods to help you customize the contents of your error logs.

Let's instantiate first:

```javascript
PrettyError = require('pretty-error');
pe = new PrettyError();

// or:
pe = require('pretty-error').start();
```

#### Shortening paths

You might want to substitute long paths with shorter, more readable aliases:

```javascript
pe.alias('E:/open-source/theatrejs/lib', '(Theare.js)');
```

#### Skipping packages

You might want to skip trace lines that belong to specific packages (chai, when, socket.io):

```javascript
pe.skipPackage('chai', 'when', 'socket.io');
```

#### Skipping node files

```javascript
// this will skip node.js, path.js, event.js, etc.
pe.skipNodeFiles();
```

#### Skipping paths

```javascript
pe.skipPath('/home/dir/someFile.js');
```

#### Skipping by callback

You can customize which trace lines get logged and which won't:
```javascript
pe.skip(function(traceLine, lineNumber){
   // if we know which package this trace line comes from, and it isn't
   // our 'demo' package ...
   if (typeof traceLine.packageName !== 'undefined' && traceLine.packageName !== 'demo') {
      // then skip this line
      return true;
   }

   // You can console.log(traceLine) to see all of it's properties.
   // Don't expect all these properties to be present, and don't assume
   // that our traceLine is always an object.
});
```

#### Modifying each trace line's contents

```javascript
pe.filter(function(traceLine, lineNumber){
   // the 'what' clause is something like:
   // 'DynamicTimeline.module.exports.DynamicTimeline._verifyProp'
   if (typeof traceLine.what !== 'undefined'){

      // we can shorten it with a regex:
      traceLine.what = traceLine.what.replace(
         /(.*\.module\.exports\.)(.*)/, '$2'
      );
   }
});
```

## Disabling colors
```javascript
pe.withoutColors(); // Errors will be rendered without coloring
```

## Integrating with frameworks

PrettyError is very simple to set up, so it should be easy to use within other frameworks.

### Integrating with [express](https://github.com/visionmedia/express)

Most frameworks such as express, catch errors automatically and provide a mechanism to handle those errors. Here is an example of how you can use PrettyError to log unhandled errors in express:

```javascript
// this is app.js

var express = require('express');
var PrettyError = require('pretty-error');

var app = express();

app.get('/', function(req, res) {
   // this will throw an error:
   var a = b;
});

var server = app.listen(3000, function(){
   console.log('Server started \n');
});


// we can now instantiaite Prettyerror:
pe = new PrettyError();

// and use it for our app's error handler:
app.use(function(err, req, res, next){
   console.log(pe.render(err));
   next();
});

// we can optionally configure prettyError to simplify the stack trace:

pe.skipNodeFiles(); // this will skip events.js and http.js and similar core node files
pe.skipPackage('express'); // this will skip all the trace lines about express` core and sub-modules
```

## Troubleshooting

`PrettyError.start()` modifies the stack traces of all errors thrown anywhere in your code, so it could potentially break packages that rely on node's original stack traces. I've only encountered this problem once, and it was with BlueBird when `Promise.longStackTraces()` was on.

In order to avoid this problem, it's better to not use `PrettyError.start()` and instead, manually catch errors and render them with PrettyError:

```javascript
var PrettyError = require('pretty-error');
var pe = new PrettyError();

// To render exceptions thrown in non-promies code:
process.on('uncaughtException', function(error){
   console.log(pe.render(error));
});

// To render unhandled rejections created in BlueBird:
process.on('unhandledRejection', function(reason){
   console.log("Unhandled rejection");
   console.log(pe.render(reason));
});

// While PrettyError.start() works out of the box with when.js` unhandled rejections,
// now that wer'e manually rendering errors, we have to instead use npmjs.org/packages/pretty-monitor
// to handle when.js rejections.

```

The only drawback with this approach is that exceptions thrown in the first tick are not prettified. To fix that, you can delay your application's startup for one tick:

```javascript
// (continued form above)

throw new Error(); // not prettified
process.nextTick(function(){
   throw new Error(); // prettified
});

```

## License

MIT