Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Never serialize .cause Errors, rely on message + stack summary instead #110

Merged
merged 5 commits into from
Jun 13, 2022

Conversation

voxpelli
Copy link
Contributor

This is an alternative fix to #94, replacing #105 and #108 and in the process make #109 not needed

Builds on my comment here #105 (comment)

In short:

Doing both a summary of the errors cause chain + serializing all the errors in the cause chain is doing the same thing twice basically.

And when on top of that doing summaries for each cause along the chain as well, then that's triple work.

In https://github.com/pinojs/pino-std-serializers/pull/78/files#diff-71c187d84f435004e68161a25e470d823f4de310a1d39b531cc02a90f3730149R56 I specifically opted out causes from recursion:

if (val instanceof Error && key !== 'cause') {
  /* eslint-disable no-prototype-builtins */
  if (!val.hasOwnProperty(seen)) {

I think #94 simply reflects that it didn't do what it intended do do, which should have been this:

if (val instanceof Error) {
  /* eslint-disable no-prototype-builtins */
  if (key !== 'cause' && !val.hasOwnProperty(seen)) {

That way it will exclude all Error causes from serialization, as intended, but keeping other causes for increased backwards compatibility.

This PR reverts #105 and #108, then applies the above fix.

voxpelli added 3 commits June 13, 2022 15:39
Instead rely on its content being appended to the message and the stack.

This is an alternative fix to pinojs#94, replacing pinojs#105 and pinojs#108 + makes pinojs#109 not needed
@hypesystem
Copy link
Contributor

hypesystem commented Jun 13, 2022

Oh, just saw this PR, so I'll ask here as well/instead: could you elaborate on explicitly opting out of serializing Error causes? What does that mean and what will the effect be?

Specifically, my original reason for making #105 and #108 was that serializing just the error messages was often not very useful, I needed a nested set of stack traces to get to the bottom of an error.

@hypesystem
Copy link
Contributor

Maybe I have just overlooked stack traces with "caused by" in them? I think I'm starting to see what your point is with your implementation.

It seems like an issue to me that it was not clear in the output I saw, and that it didn't seem to cover the use case I had -- but with the understanding I'm now getting, I see what I must have missed, and how it works.

@KoltesDigital
Copy link

KoltesDigital commented Jun 13, 2022

I'm taking the opportunity to present you with a problem I'm having. Here is my scenario:

class CustomErrorWithInfo extends VError {
	constructor(cause) {
		super(
			{
				cause,
				info: {
					foo: 'bar',
				},
			},
			'Custom error with info'
		);
	}
}

class CustomErrorWithNoStackTrack extends VError {
	constructor(cause) {
		super(
			{
				cause,
			},
			'Custom error with no stack trace'
		);
		this.stack = undefined;
	}
}

try {
	try {
		try {
			throw new Error('first error');
		} catch (err) {
			throw new CustomErrorWithInfo(err);
		}
	} catch (err) {
		throw new CustomErrorWithNoStackTrack(err);
	}
} catch (err) {
	logger.error({
		err,
	});
}

I wrote a custom prettifier (supposedly to be open sourced soon) that made that output:

[#] ERROR: Custom error with no stack trace: Custom error with info: first error
    err: CustomErrorWithNoStackTrack: Custom error with no stack trace
    ---
    caused by: CustomErrorWithInfo: Custom error with info
# stacktrace
    info: {
      "foo": "bar"
    }
    ---
    caused by: Error: first error
# stacktrace

I've just upgraded the project dependencies, and discovered that your lib now appends the error chain in the message. That's cool in most cases, however, it doesn't show the special info property of VError. And it's somewhat good, because you can't possibly know about other libs' stuffs, and don't have to anyway.

As a summary: I don't think it's a good idea to loose the original cause object.

Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add a unit test?

@voxpelli
Copy link
Contributor Author

I think that for 90% of the use cases a summary of the cause chain is good enough.

For the remainder it is always possible to provide a custom error serializer to Pino and that serializer could then skip the message and stack summary in favor of recursively serializing the error chain.

I think this serializer should cater to the 90% use case and ensure that the output strikes a good balance between size between and usefulness.

Maybe I have just overlooked stack traces with "caused by" in them? I think I'm starting to see what your point is with your implementation.

@hypesystem Yes, both stacks and messages are summarized, so you should get the full context, just not any extra data of the cause errors. I think this strikes a good balance between the size of the output and the usefulness of the data.

_err.message = messageWithCauses(err)
_err.stack = stackWithCauses(err)

@voxpelli
Copy link
Contributor Author

Can you please add a unit test?

@mcollina Yes, sorry, should of course have added that, done ✔️

@voxpelli voxpelli requested a review from mcollina June 13, 2022 14:36
@KoltesDigital
Copy link

That's what I indeed up doing. FTR the stack from the object passed as argument of the custom serializer already embeds all error stacks, therefore the first stack is extracted with stack.indexOf('\ncaused by: ') and then I iterate on causes. A bit sad to have to do these extra computations.

With this PR's title I was afraid you'd drop access to the original cause, nevermind.

@voxpelli
Copy link
Contributor Author

voxpelli commented Jun 13, 2022

@KoltesDigital Maybe one could add an option for toggling between the behaviors, not sure what @mcollina, @jsumners and such feels about that, as currently no such options are part of this module.

Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@mcollina
Copy link
Member

@KoltesDigital Maybe one could add an option for toggling between the behaviors, not sure what @mcollina, @jsumners and such feels about that, as currently no such options are part of this module.

I don't think that's a great idea. I would prefer to have this module as vanilla as possible. I'm happy to have a separate module catering to more advanced use cases, or export a different error serializer under a different file in this module.

@mcollina
Copy link
Member

@voxpelli is this mergeable/releasable now?

@voxpelli
Copy link
Contributor Author

voxpelli commented Jun 13, 2022

With this PR's title I was afraid you'd drop access to the original cause

@KoltesDigital That is kind of what this change does. Any .cause that is an Error will be excluded from the result of errSerializer and thus not available to wrapErrorSerializer either, unless one goes through .raw. And .raw is probably the correct way anyway. Then you can eg. use things like findCauseByReference() to find the decorated one.

@mcollina With the exception of the above possible caveat, then yes.

@mcollina
Copy link
Member

@jsumners you ok for this to ship?

@hypesystem
Copy link
Contributor

I feel like there are still some unresolved issues in the little back and forth in code we've had. If there's no rush, I'd love the time to formulate what I see (but it won't be for a few hours).

@hypesystem
Copy link
Contributor

Okay, finally had a moment after putting my kid to bed 😄

I think overall I'm a bit confused as to the design goals for these serializers, and it seems like that confusion is also what led to the back and forth here. So I'll try to talk from what I think are the design goals, but honestly I'm confused, and that confusion will probably lead to similar things in the future. I'm feeling a lack of alignment, so I'll try and at least explain how I see the problem space 😄 sorry if this is too much, I'm trying to be concise.

I understand from @mcollina that the goal is to keep this library simple/"vanilla", and let people use their own more advanced error serializers if they need them. I assume that a good "simple/vanilla" solution will have some simple rules that just about support "normal" (common?) errors. In that case, the specific support for VError is a bit weird, but not too far out of scope.

I think overall there are two approaches:

  • limited scope (sort of as suggested in err serializer should not copy every key #27 which has been sitting for a few years), where only very few fields are support (message, stack, cause, maybe code as it is common in Node.js errors)
  • serialize everything (treat Errors as objects that will be extended and where added fields probably hold relevant information), with a few custom fields

I would argue that people commonly use their own error objects that may or may not even be instanceof Error and can contain all sorts of relevant information. To support most people (90% case) I would argue for supporting as broad a set of Error(-like) things as possible.

Pino already supports err, req and res as "special" default fields that behave differently from other data when logging things. I think this pattern makes sense for errors as well: treat a few fields (message, stack, cause) as (potentially) special, but otherwise serialize everything "normally"/as an object.

From this observation I think I have the following feedback on the current implementation + this PR:

  • The behavior of concatenating message and stack strings is weird and unexpected. I wouldn't expect serialization to significantly alter the object structure, and here it does. That's the reason for my original PR: I didn't realize what it was doing because it was so unexpected.
  • Parsing messages and stack traces out of the context of error objects makes it harder to evaluate the error cause chain. Users will have to parse two chains of strings in parallel to figure out what is happening. (And woe betide you if one of the messages contains : , that's the split signifier!)
  • Advanced handling of message and stack doesn't seem like the "vanilla" version of serializing errors. It might be useful for some teams, but it seems further from normal code behavior than just keeping the nested error structure that is created in code.
  • Behavior with cause fields becomes harder to reason about because whether or not Error is in an objects prototype chain determines behavior. Nested causes will work fine for thrown objects that aren't actual Errors but breaks when it hits an error.

I'm not necessarily saying the approach in my PR is the correct solution, but I think there are problems with the summarization approach that I haven't seen discussed anywhere.

@voxpelli says the goal of the approach is to strike "a good balance between the size of the output and the usefulness of the data". If that is a design goal, I don't think that's reflected elsewhere in the code --- this would speak for more of a limited scope approach (see above and #27), and would certainly be reasonable! But it's not what I would expect from the other behavior of this library as is.

Hope you can help me see more clearly what the aim of this library is, so I can contribute most helpfully 😄 (and make my own thing if I'm going in a different direction).

@mcollina
Copy link
Member

I do not have time to "dig deep" into the ins-and-out of this change and the topic. Could you make some example? I'm a bit lost.

@kibertoad could you chime in too?

@hypesystem
Copy link
Contributor

Sorry, I know that was long.

Basically: the current error serializer is confusing and unpredictable.

Do you want

  • simple but exhaustive serialization (currently every enumerable field on an Error is serialized except a few special ones); or
  • optimizing for usefulness per size (message and stack are concatenated but causes are not serialized in full)

These two design goals run counter to each other and that makes it hard to know what to expect from this library, and how to contribute.

@mcollina
Copy link
Member

The expected behavior is

optimizing for usefulness per size (message and stack are concatenated but causes are not serialized in full)

@jsumners
Copy link
Member

@KoltesDigital Maybe one could add an option for toggling between the behaviors, not sure what @mcollina, @jsumners and such feels about that, as currently no such options are part of this module.

I don't think that's a great idea. I would prefer to have this module as vanilla as possible. I'm happy to have a separate module catering to more advanced use cases, or export a different error serializer under a different file in this module.

I concur. This module exports a function for wrapping the error serializer specifically so that the functionality can be extended without constant patches to this module -- https://github.com/pinojs/pino-std-serializers#exportswraperrorserializercustomserializer. We added the .cause serialization because it (thankfully) got adopted as a standard Error property.

lib/err.js Outdated Show resolved Hide resolved
@hypesystem
Copy link
Contributor

Cool, it seems there is consenaus among y'all, this PR definitely fits that consensus 😁

Do you also agree that removing serialization of every field is a good idea then? c.f. #27 — or has something in the observations regarding that changed? (I don't wanna do another PR that's instantly reverted 😅)

@jsumners
Copy link
Member

Cool, it seems there is consenaus among y'all, this PR definitely fits that consensus 😁

Do you also agree that removing serialization of every field is a good idea then? c.f. #27 — or has something in the observations regarding that changed? (I don't wanna do another PR that's instantly reverted 😅)

#27 (comment)

That wrapper is what I linked above. Let's keep this simple and make the "standard serializer" only serialize standard Error properties.

@mcollina mcollina merged commit a476999 into pinojs:master Jun 13, 2022
@voxpelli voxpelli deleted the voxpelli/cause-improvements branch June 14, 2022 04:04
@rektide
Copy link
Contributor

rektide commented Jul 22, 2022

This change has been quite detrimental to us. We use Restify & follow a restify-like pattern in many places, where we often see things like:

try{ /* something bad */ } catch (err) {
  throw new BadRequestError(err)
}

Before this PR, our resultant error-handler logs would get useful information from the properties on the err object, that would tell us what was going wrong.

These logs were also of well structured data that could be easily read: err.cause.type is RequestError? Great, that's easy to work with.

Now we have: a) no properties/fields that we had before, b) unstructured stack traces that we cannot parse/walk/use.

Doing both a summary of the errors cause chain + serializing all the errors in the cause chain is doing the same thing twice basically.

This is a reasonable problem statement. But. I feel like we took the wrong path here, in deciding not to serialize errors. We should have gone down the other path available to us & started reducing the quantity of (not-so-machine-readable/not-so-structured) summary information we present. There are some legit improvements we could have made, that my example disuses.

I'd far have preferred we serialize errors, & have each error print only it's piece of the stack next to it (not the whole stack). The original premise was we don't need to do both, and that's fine, but we chose the low density, lower information, less machine-usable pick. I'd like us to do better.

I also think this PR sets us on the wrong path/precedent with another complex error, AggregateError.

Full Example

before this pr

(+) fields usable
(+) structured data that log engines can use
(-) data in stack fields repeat

{
  "type": "BadRequestError",
  "message": "Failed to oscillate: Service request failed: Alien now on vehicle",
  "stack": "Error: Failed to oscillate\n    at Object.<anonymous> (/Users/mfowle/archive/pino-std-serializers/ex.js:28:12)\n    at Module._compile (node:internal/modules/cjs/loader:1103:14)\n    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)\n    at Module.load (node:internal/modules/cjs/loader:981:32)\n    at Function.Module._load (node:internal/modules/cjs/loader:822:12)\n    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)\n    at node:internal/main/run_main_module:17:47\ncaused by: Error: Service request failed\n    at Object.<anonymous> (/Users/mfowle/archive/pino-std-serializers/ex.js:27:13)\n    at Module._compile (node:internal/modules/cjs/loader:1103:14)\n    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)\n    at Module.load (node:internal/modules/cjs/loader:981:32)\n    at Function.Module._load (node:internal/modules/cjs/loader:822:12)\n    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)\n    at node:internal/main/run_main_module:17:47\ncaused by: Error: Alien now on vehicle\n    at Object.<anonymous> (/Users/mfowle/archive/pino-std-serializers/ex.js:26:15)\n    at Module._compile (node:internal/modules/cjs/loader:1103:14)\n    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)\n    at Module.load (node:internal/modules/cjs/loader:981:32)\n    at Function.Module._load (node:internal/modules/cjs/loader:822:12)\n    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)\n    at node:internal/main/run_main_module:17:47",
  "cause": {
    "type": "ServiceRequestError",
    "message": "Service request failed: Alien now on vehicle",
    "stack": "Error: Service request failed\n    at Object.<anonymous> (/Users/mfowle/archive/pino-std-serializers/ex.js:27:13)\n    at Module._compile (node:internal/modules/cjs/loader:1103:14)\n    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)\n    at Module.load (node:internal/modules/cjs/loader:981:32)\n    at Function.Module._load (node:internal/modules/cjs/loader:822:12)\n    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)\n    at node:internal/main/run_main_module:17:47\ncaused by: Error: Alien now on vehicle\n    at Object.<anonymous> (/Users/mfowle/archive/pino-std-serializers/ex.js:26:15)\n    at Module._compile (node:internal/modules/cjs/loader:1103:14)\n    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)\n    at Module.load (node:internal/modules/cjs/loader:981:32)\n    at Function.Module._load (node:internal/modules/cjs/loader:822:12)\n    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)\n    at node:internal/main/run_main_module:17:47",
    "cause": {
      "type": "AlienOnVehicle",
      "message": "Alien now on vehicle",
      "stack": "Error: Alien now on vehicle\n    at Object.<anonymous> (/Users/mfowle/archive/pino-std-serializers/ex.js:26:15)\n    at Module._compile (node:internal/modules/cjs/loader:1103:14)\n    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)\n    at Module.load (node:internal/modules/cjs/loader:981:32)\n    at Function.Module._load (node:internal/modules/cjs/loader:822:12)\n    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)\n    at node:internal/main/run_main_module:17:47",
      "addition": "alien"
    },
    "url": "http://yoyodyne.example/overthruster/oscillate",
    "status": 2000
  },
  "dimensions": 8
}

after this pr

(+) no repeated stacks
(-) all nested fields are missing
(-) unstructured/not-so-machine-readable stack data only

{
  "type": "BadRequestError",
  "message": "Failed to oscillate: Service request failed: Alien now on vehicle",
  "stack": "Error: Failed to oscillate\n    at finishDrive (/Users/mfowle/archive/pino-std-serializers/ex.js:30:14)\n    at testDrive (/Users/mfowle/archive/pino-std-serializers/ex.js:33:9)\n    at Object.<anonymous> (/Users/mfowle/archive/pino-std-serializers/ex.js:37:35)\n    at Module._compile (node:internal/modules/cjs/loader:1103:14)\n    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)\n    at Module.load (node:internal/modules/cjs/loader:981:32)\n    at Function.Module._load (node:internal/modules/cjs/loader:822:12)\n    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)\n    at node:internal/main/run_main_module:17:47\ncaused by: Error: Service request failed\n    at finishDrive (/Users/mfowle/archive/pino-std-serializers/ex.js:29:15)\n    at testDrive (/Users/mfowle/archive/pino-std-serializers/ex.js:33:9)\n    at Object.<anonymous> (/Users/mfowle/archive/pino-std-serializers/ex.js:37:35)\n    at Module._compile (node:internal/modules/cjs/loader:1103:14)\n    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)\n    at Module.load (node:internal/modules/cjs/loader:981:32)\n    at Function.Module._load (node:internal/modules/cjs/loader:822:12)\n    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)\n    at node:internal/main/run_main_module:17:47\ncaused by: Error: Alien now on vehicle\n    at finishDrive (/Users/mfowle/archive/pino-std-serializers/ex.js:28:17)\n    at testDrive (/Users/mfowle/archive/pino-std-serializers/ex.js:33:9)\n    at Object.<anonymous> (/Users/mfowle/archive/pino-std-serializers/ex.js:37:35)\n    at Module._compile (node:internal/modules/cjs/loader:1103:14)\n    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)\n    at Module.load (node:internal/modules/cjs/loader:981:32)\n    at Function.Module._load (node:internal/modules/cjs/loader:822:12)\n    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)\n    at node:internal/main/run_main_module:17:47",
  "dimensions": 8
}

code

#!/usr/bin/env node
var pss = require("pino-std-serializers")
class AlienOnVehicle extends Error{
	constructor(){
		super("Alien now on vehicle")
		this.addition = "alien"
	}
}
class ServiceRequestError extends Error{
	constructor(cause){
		super("Service request failed", {cause})
		this.url = "http://yoyodyne.example/overthruster/oscillate"
		this.status = 2000
	}
}
class BadRequestError extends Error{
	constructor(cause) {
		super("Failed to oscillate", {cause});
		this.dimensions = 8;
	}
}

function testDrive(){
	function finishDrive(){
		const alien = new AlienOnVehicle() // the problem
		const svc = new ServiceRequestError(alien) // the service call that hit the problem
		const br = new BadRequestError(svc) // the error we send to the error-handler/user
		return br;
	}
	return finishDrive();
}

console.log(JSON.stringify(pss.err(testDrive())), null, '\t')
//console.log(JSON.stringify(testDrive().stack))

Alternative Analysis

Alternatives

I think some of the authors original objection was to criticize this original-behavior output specifically (unfolded from inline display). This is the top stack from before this pr, human formatted:

  stack: 'Error: Failed to oscillate\n' +
    '    at finishDrive (/Users/mfowle/archive/pino-std-serializers/ex.js:30:14)\n' +
    '    at testDrive (/Users/mfowle/archive/pino-std-serializers/ex.js:33:9)\n' +
    '    at Object.<anonymous> (/Users/mfowle/archive/pino-std-serializers/ex.js:36:46)\n' +
    '    at Module._compile (node:internal/modules/cjs/loader:1103:14)\n' +
    '    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)\n' +
    '    at Module.load (node:internal/modules/cjs/loader:981:32)\n' +
    '    at Function.Module._load (node:internal/modules/cjs/loader:822:12)\n' +
    '    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)\n' +
    '    at node:internal/main/run_main_module:17:47\n' +
    'caused by: Error: Service request failed\n' +
    '    at finishDrive (/Users/mfowle/archive/pino-std-serializers/ex.js:29:15)\n' +
    '    at testDrive (/Users/mfowle/archive/pino-std-serializers/ex.js:33:9)\n' +
    '    at Object.<anonymous> (/Users/mfowle/archive/pino-std-serializers/ex.js:36:46)\n' +
    '    at Module._compile (node:internal/modules/cjs/loader:1103:14)\n' +
    '    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)\n' +
    '    at Module.load (node:internal/modules/cjs/loader:981:32)\n' +
    '    at Function.Module._load (node:internal/modules/cjs/loader:822:12)\n' +
    '    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)\n' +
    '    at node:internal/main/run_main_module:17:47\n' +
    'caused by: Error: Alien now on vehicle\n' +
    '    at finishDrive (/Users/mfowle/archive/pino-std-serializers/ex.js:28:17)\n' +
    '    at testDrive (/Users/mfowle/archive/pino-std-serializers/ex.js:33:9)\n' +
    '    at Object.<anonymous> (/Users/mfowle/archive/pino-std-serializers/ex.js:36:46)\n' +
    '    at Module._compile (node:internal/modules/cjs/loader:1103:14)\n' +
    '    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)\n' +
    '    at Module.load (node:internal/modules/cjs/loader:981:32)\n' +
    '    at Function.Module._load (node:internal/modules/cjs/loader:822:12)\n' +
    '    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)\n' +
    '    at node:internal/main/run_main_module:17:47',

But note that we're going to repeat the Error: Alien now on vehicle two more times, in each of these cause's separate stacks. This was a sensible & logical thing to want to address. But we bludgeoned a lot of useful / helpful / great information by making such a sharp reduction in unwinding.

I think pino-std-serializers may even have went extra distance to do the caused by, to glump the stacks together, to create the expanded stacks? If I just print testDrive().stack I get no duplication, none of the causes stacks, only:

Error: Failed to oscillate
    at finishDrive (/Users/mfowle/archive/pino-std-serializers/ex.js:30:14)
    at testDrive (/Users/mfowle/archive/pino-std-serializers/ex.js:33:9)
    at Object.<anonymous> (/Users/mfowle/archive/pino-std-serializers/ex.js:39:13)
    at Module._compile (node:internal/modules/cjs/loader:1103:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    at node:internal/main/run_main_module:17:47

The caused by does not appear. I think we should go back to where we were, but remove the caused by data. There is still some duplicate information, but overall it is fairly minimal. Message and Type repeat, but everything else is unique.

@voxpelli
Copy link
Contributor Author

@rektide You bring up similar criticism as @hypesystem did and which was discussed earlier in this thread with pointers on how one can cater to your needs but why it also makes sense for it to not be the default.

Have you looked at eg #110 (comment) ?

@rektide
Copy link
Contributor

rektide commented Jul 23, 2022

@rektide You bring up similar criticism as @hypesystem did and which was discussed earlier in this thread with pointers on how one can cater to your needs but why it also makes sense for it to not be the default.

I've seen opinions but not justifications for what has been done here. Pino has, so far, been a great tool that gives users the data. A useless, text only, stack only log message with zero details (as my simple example shows) seems to be the new pivot, and it feels like a frigging joke. There's nothing that makes sense about any of this. This is such a harsh & radical u-turn on what pino has been, & I don't see any arguments made anywhere here to argue with: there's a seeming vast concensus that basically doing nothing for the user & concealing all relevant information is good, & the one dude who said, wait no please dont, got steamrolled already. There's literally no argumentation to disagree with about why doing absolutely nothing good for the user is beneficial, so there's no chance to make a concerted disagreement, no chance we ever make any other decisions, no chance for any other views to have a chance. Doing nothing but unreadable textual spamming inside JSON needs justification, and it hasn't.

I've tried to show some very basic impact. But getting told "how one can cater to your needs" when my needs are- I want my logs to show some basic minimal information in a machine readable way/json-y way- is deeply cutting & a joke. I've gone to great lengths to show that this PR is a complete destruction of useful information at all levels, completely contrary to any modern logging practice in it's utter savaging of structured information. My needs are to show some basic sensible error messages. Your needs are to show nothing but text blobs??? You should do your own thing if you have those "particular" needs. I see other authors agree, but again, I just see zero justification. I can't argue with points of view that have never been justified AT ALL.

In short: Doing both a summary of the errors cause chain + serializing all the errors in the cause chain is doing the same thing twice basically.

Again.... why did we not take the other path? Why show only a worthless text-only summary, instead of reducing the summary & cleanly nicely doing a very similar but structured & informative output? Many opinions, few arguments. In my honest opinion: much harm (with no rationalization for why).

@mcollina
Copy link
Member

Configuring a different serializer is easy, if you have a different need you can configure your own. I do not understand why you are so upset.

I'm not sure we need any justification to do a breaking change in a semver-major release.

@hypesystem
Copy link
Contributor

Hey, I made an alternate (exhaustive) error serializer that I'd love input on, that sounds like it fits your needs @rektide - pretty early stage for now: https://www.npmjs.com/package/serialize-every-error

@rektide
Copy link
Contributor

rektide commented Aug 2, 2022

I do not understand why you are so upset.

It makes me upset to see useful, helpful, structured information replaced by a massive stack trace that holds much of the same information in a unusable unstructured form. I don't see what could justify turning the good, usable information we had into bad, unusable information like this. Of the two paths we picked, we chose to keep the obviously worse path we had, rather than work with the good one:

*Doing both a summary of the errors cause chain + serializing all the errors in the cause chain is doing the same thing twice basically.

@pinojs pinojs locked and limited conversation to collaborators Aug 3, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants