AriaMinaei / pretty-error

See node.js errors with less clutter
MIT License
1.52k stars 48 forks source link

Question: Associate with console.log out of the box #21

Closed Kikobeats closed 9 years ago

Kikobeats commented 9 years ago

I want to integrate the library with my error library Errorifier. Basically in my library I create a Error Object, I add a little logic and return the logic. Something like:

constructor: ->
  err = new Error()
  # adding logic
  err

Externally is used like:

err = new Errorifier()
console.log err # normal output

The point is: I want to integrate with the library to, when you use console.log, see the outputted generate by the method .render, like:

err = new Errorifier()
console.log err # pretty output!

I didn't find a way to do it and still return the err object in my library constructor.

Do you think that this is possible? If is necessary, I can extends PrettyError.

AriaMinaei commented 9 years ago

Would this help?

var PrettyError = require('pretty-error');
var pe = new PrettyError();
var err = new Errorifier();
var renderedError = pe.render(err);

console.log(renderedError);
Kikobeats commented 9 years ago

No, because I want associate console.log with renderedError out of the box, I mean, I want to return the error, and later, when the user need to show the error using console.log render it as prettyError. renderedError

AriaMinaei commented 9 years ago

I tried a few things but couldn't find a perfect solution. My less than ideal suggestion is to implement an Errorifier::render() method (which uses pretty-error), and then console.log(err.render()).

Here is why:

First of all, we obviously don't want to override console.log(), so that's out the window.

Ideally, we want our Error object to be pretty printed when fed to console.log(). The problem with that is that console.log() doesn't care if the value fed to it is an Error object. It won't try to render its stack tract and it won't call its ::toString() method. It just renders something like a plain object: image

Node only renders an error's stack trace if its uncaught. Which means that if you want to console.log() an error's stack trace without leaving it uncaught, then you need to do something like this: console.log((new Error "message").stack)

So, I don't know if there is any way to achieve what you're looking for. So, I would either implement a render() method for the error object, or just override its stack tract, like this:

err = new Error "Some message"
err.stack = pe.render err # we could also implement err.stack as a getter method

# and then
console.log err.stack
reggi commented 9 years ago

Not sure if this answers / helps this particular question, but as @Kikobeats expressed too, I'd like to still maintain the error object when rendering out an error with pe, so below are several options on how to do that.

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

function NiceError (message) {
  this.name = e.name
  this.message = e.message
  this.stack = pe.render(e)
}
NiceError.prototype = Error.prototype

function renderToError (e) {
  e.stack = pe.render(e)
  return e
}

var e = new Error('Some error message')

// showing that what `pe.render` returns is not an actual error
var renderedError = pe.render(e)
console.log(typeof renderedError) // => string ????
console.log(renderedError instanceof Error) // => false ????

// using a function to convert error to a pretty error
var actualError = renderToError(e)
console.log(typeof actualError) // => object
console.log(actualError instanceof Error) // => true

var e = new NiceError('Some error message')

// NiceError is Error with pretty stack
console.log(typeof e) // => object
console.log(e instanceof Error) // => true

var NativeError = Error
function RelaceError(message) {
  var e = new NativeError(message)
  this.name = e.name
  this.message = e.message
  this.stack = pe.render(e)
}
RelaceError.prototype = Error.prototype;
Error = RelaceError

// call Error with pretty stack
var e = new Error('Some error message')
console.log(typeof actualError) // => object
console.log(actualError instanceof Error) // => true
AriaMinaei commented 9 years ago

either implement a render() method for the error object

I should retract my suggestion. Implementing a custom error object for the sole purpose of having it rendered nicely isn't really a good separation of concerns. An error object's only purpose is to give information about the error itself. Rendering it should be left to a separate module. If you pre-render an error's stack tract with pretty-error, you would limit users` ability to view the stack trace in environments where pretty-printing (especially with line wrapping and colors) isn't possible (e.g. error logs).

So, my suggestion is to return meaningful error objects (e.g. Error, ParseError, etc.) and leave the rendering to the user of the library.

Kikobeats commented 9 years ago

The solution based in a .render method is ok. We can reduce the client behavior to handle other type of errors and Errors that implemente PrettyError in the same method in:

console.log(err.render?() or err)

Actually I would like avoid this and have a standard behavior across whatever application, but I understand that the current native Error object is not possible.

AriaMinaei commented 9 years ago

Okay then. Feel free to close the issue if you think it is resolved.