-
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
Implement child loggers #1471
Implement child loggers #1471
Conversation
@DABH Any chance for a review?.. |
Not today but hopefully soon. Seems cool at first glance though! 😎 |
@DABH Any ETA for when you could possible have time to take a look? |
Ok, I'm looking at this now in combination with #1482 . Can you help me understand why it isn't enough to just use a dynamic formatter? Something like
...hmmm... which I guess you could use like
(code not tested!). Maybe a better idea since that got a bit inelegant is to add a function to logger called like
Anyway, something like this could be more efficient than creating a bunch of different logger objects. Let me know what you think! |
If you required an isomorphic interface, you could make some kind of wrapper so that a |
@kibertoad would you consider making it so that the only argument a child logger could take is the default metadata? you could change it to use this more efficient instantiation pattern referenced here #1482 and enabled by #1483 our use case is a logger per request and it has to be as light as possible. I'm not a member of the project so this is just a friendly suggestion =) i have no idea if it will make it more or less likely to merge. It's easier to add api later than take it away later. |
Thanks for all the feedback and ideas! I'll definitely meditate over this during weekend and see what happens :) |
@DABH Any chance for a rereview?.. |
@kibertoad Sure I'll take a look now |
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.
This looks good to me now but I'd like @indexzero to be the one to hit Merge in case there is anything he spots that I don't. Thanks for your effort and patience with this!
Also, did you do anything to verify that performance of the "hotpaths" in log() aren't affected for regular loggers without defaultMeta? I think this is a useful feature but want to be sure it doesn't slow down the core code paths if people don't use the feature. |
@DABH How do you recommend to verify that? |
@kibertoad So it looks like the path that's modified is
and run it on your branch and on master. Does that make sense? I doubt the extra |
@DABH I've used master: branch: I don't see any meaningful difference in two results. |
Here is exact code so that anyone could reproduce it or point out flaws in the way it was tested:
|
Nice! Thanks so much. You have my +1 -- as long as @indexzero is ok with this design, this is ready to merge. |
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.
This is definitely moving in the right direction & this feature has been requested many times by the community. Will give this a deeper look over in the next week or so and then it will likely land. Tests look solid.
If you have the benchmark script you ran that would be very helpful!
@indexzero Please check previous comments for a benchmark script; the only thing it was missing were import statements, added them now. |
@indexzero Is there enough information or do I need provide anything additionally? |
@kibertoad We just ran out of time reviewing this in our last meeting so we didn't complete a final review -- but I am pretty sure there is enough info here. Assuming @indexzero +1's the design, the plan is to merge this and cut a new winston release to npm on 12/23. Apologies for the delay and thanks again for your patience! |
lib/winston/logger.js
Outdated
return Object.create(logger, { | ||
write: { | ||
value: function (info) { | ||
logger.write(Object.assign( |
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.
if info is a Error type value,this will lost some values,such as stack.
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.
@little-yao Thank you for noticing this! I've fixed the case when error is passed as the only param; it doesn't look like Winston itself supports cases when you pass error message as string followed by Error message, but please correct me if I'm wrong or if there are additional cases that need handling. Also would appreciate if you could check latest commit for correctness.
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.
thank you for replying and editing!I looked for winston carefully, and also can't find somthing about surpporting Error.
I think how about use "info instanceof Error" to judging,Object.assign can't cover "stack" is because enumerable is false, but user can also set "stack" prop.
and how about set info prototype to result, here is my code
if (info instanceof Error) { infoClone.stack = info.stack; infoClone.message = info.message; } infoClone.__proto__ = info.__proto__;
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.
Changed, thanks!
Note: I see same AppVeyor test failing in master, so probably it doesn't matter. |
I've been looking through the source code and unlike creating multiple loggers, creating a child logger simply returns a new logger instance but does not actually add it to winston.loggers map. If this is correct then one would manually have to handle passing the created instance to the places it needs to be used as well as potentially removing it when done. Should the child loggers be maintained in an internal map to the logger container or the overall winston loggers map and in turn provide access and utility methods such as get, remove etc? What is the use case for using child logger instead of just creating a new logger? Are the child loggers that much more performant than base logger creation? I'm asking because I'm looking to dynamically create child loggers to include dynamic request meta in express app and want to avoid doing something like attaching the child instance to the req object and having to reference it that way. Would ideally like to import the base logger and perform a get based on a unique id attached to the child meta on creation. |
* Implement child loggers * Fix lint warning * More tests * Replace child logger implementation with a more high-performance version * Adjust implementation to be compatible with Node 6. Switch priority of meta override * Add support for passing error directly to logger * Improve test cross-OS compatibility * Minor improvements based on code review * Remove proto override since linting settings enforce not using it
Note that this is a naive implementation that reinitializes each child logger completely which may be undesireable for performance reasons (didn't benchmark it, though, at a glance it doesn't look like any expensive operations are happening, but we may still squeeze some additional performance out of it). If this implementation is reviewed and accepted I am going to work on a follow-up optimization that will reuse original logger in hot-path cases.
Update for historical purposes: it was reworked for performance before being merged.