-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
fix(metadata precedence) - fix metadata override issues #1989
Changes from 39 commits
e2d4402
29a9ff7
23d9036
5df5786
4b0624b
d23801d
c942452
e72d96b
4495caa
f951b9a
6ba9967
fd14dfe
70fa754
e18e1bb
692de0d
dc005b7
f2ee50a
85ea8a6
b233a8b
ce2f607
96dfeda
b44d4b1
f748636
f350f2c
f89285a
b2efe8f
010e955
f393a50
3577d1d
fc39513
d9f105c
8eab107
4c544f1
4e830d6
8724f4b
a2ec0c2
c4dd5ea
b36158f
830d15b
97a87b6
ddb4dd1
0198284
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,5 +4,5 @@ reporter: | |
check-coverage: true | ||
branches: 61.51 | ||
lines: 70.85 | ||
functions: 73.21 | ||
functions: 73.08 | ||
statements: 70.54 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,7 @@ | |
|
||
const { Stream, Transform } = require('readable-stream'); | ||
const asyncForEach = require('async/forEach'); | ||
const { LEVEL, SPLAT } = require('triple-beam'); | ||
const { LEVEL, SPLAT, MESSAGE } = require('triple-beam'); | ||
const isStream = require('is-stream'); | ||
const ExceptionHandler = require('./exception-handler'); | ||
const RejectionHandler = require('./rejection-handler'); | ||
|
@@ -42,30 +42,12 @@ class Logger extends Transform { | |
this.configure(options); | ||
} | ||
|
||
child(defaultRequestMetadata) { | ||
child(childMetadata) { | ||
const logger = this; | ||
const clonedParentMetadata = JSON.parse(JSON.stringify(this.defaultMeta)) | ||
return Object.create(logger, { | ||
write: { | ||
maverick1872 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
value: function (info) { | ||
const infoClone = Object.assign( | ||
{}, | ||
defaultRequestMetadata, | ||
info | ||
); | ||
|
||
// Object.assign doesn't copy inherited Error | ||
// properties so we have to do that explicitly | ||
// | ||
// Remark (indexzero): we should remove this | ||
// since the errors format will handle this case. | ||
// | ||
if (info instanceof Error) { | ||
infoClone.stack = info.stack; | ||
infoClone.message = info.message; | ||
} | ||
|
||
logger.write(infoClone); | ||
} | ||
defaultMeta: { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I forget most of the design decisions here. Should this be called There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this is a great question. The short answer is that it's consistent with every other usage regarding configuring default metadata. I want to preface the following with it's possible that I'm way off base in my understanding of how P.S. It is possible that there's a configuration that I'm unaware of that's leveraged in the dynamic |
||
value: Object.assign({}, clonedParentMetadata, childMetadata) | ||
} | ||
}); | ||
} | ||
|
@@ -288,6 +270,10 @@ class Logger extends Transform { | |
info[LEVEL] = info.level; | ||
} | ||
|
||
if (!info[MESSAGE]) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this for? This looks unrelated to child loggers / metadata -- is this fixing some other issue, or is it indeed related? If it's related, a comment might be helpful explaining why? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe this to have been an issue with the SPLAT implementation and associated hotpath optimizations. If I am remembering correctly this stemmed from this comment on my previous PR. Additional discussion was had in #1596 way back when. If we want to remove this addition from this addition I'm happy to (so long as all my tests that I've written are still passing. 😃 Edit: I've verified all my tests work without this implementation. Happy to remove. Alternatively I can try and find some time to add in some additional SPLAT tests to re-verify my understanding of this addition; although that may take some time. About to be fairly busy in the coming weeks. |
||
info[MESSAGE] = info.message; | ||
} | ||
|
||
// Remark: really not sure what to do here, but this has been reported as | ||
// very confusing by pre winston@2.0.0 users as quite confusing when using | ||
// custom levels. | ||
|
@@ -647,7 +633,9 @@ class Logger extends Transform { | |
|
||
_addDefaultMeta(msg) { | ||
if (this.defaultMeta) { | ||
Object.assign(msg, this.defaultMeta); | ||
// The msg must be cloned as it is being mutated, but any metadata provided with the msg takes precedence over default | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wait, so There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this is a mutating operation. The issue with this mutation is that we lost the ability to apply the metadata defined in the appropriate order of precedence. Considerations:
Due to the above, and the fact that we HAVE to mutate |
||
const msgClone = JSON.parse(JSON.stringify(msg)); | ||
Object.assign(msg, this.defaultMeta, msgClone); | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this really the fastest way to clone an object in JS in 2022? :O
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also can we do ; at ends of lines?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honestly I'm not entirely sure. Versions of node we currently support (>12) do not have a proper language native implementation for deep cloning objects. So as far as I can determine the only solutions available to us at this current juncture are the following:
I feel like none of these are good solutions. Recently there was an introduction of structuredClone but it's only bundled with Node v17.x.x. We could alternatively pull a pollyfill for the functionality but I'm not sure if that's something we want to do or not.
Alternatively if anyone knows of a better way to clone to deeply clone objects I'd love to learn as this has been a reoccurring pain point for myself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe we're using a safe-stringify function in this library in general to avoid issues with circular references etc.; that might be a good idea here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was unaware of this and typically I personally like to see when a resultant object has a circular reference myself so I default to letting it throw the TypeError. But in the context of a library such as Winston it probably is better to handle them gracefully. Will update.
Since I forgot to address this directly; Sounds like we should make an addition to the linter config 😆