Skip to content

lib: added logger api in node core#60468

Open
mertcanaltin wants to merge 66 commits intonodejs:mainfrom
mertcanaltin:mert/create-logger-api/node-core
Open

lib: added logger api in node core#60468
mertcanaltin wants to merge 66 commits intonodejs:mainfrom
mertcanaltin:mert/create-logger-api/node-core

Conversation

@mertcanaltin
Copy link
Member

@mertcanaltin mertcanaltin commented Oct 28, 2025

for: #49296 (comment)

I try a draft development for new logger api, and i try create some benchmark for pino and node:logger package

@nodejs-github-bot
Copy link
Collaborator

Review requested:

  • @nodejs/performance

@nodejs-github-bot nodejs-github-bot added the needs-ci PRs that need a full CI run. label Oct 28, 2025
@mertcanaltin mertcanaltin changed the title lib: added logger package in node core lib: added logger api in node core Oct 28, 2025
@mertcanaltin mertcanaltin changed the title lib: added logger api in node core [WIP] lib: added logger api in node core Oct 28, 2025
@mertcanaltin mertcanaltin requested a review from Qard October 29, 2025 14:16
@mertcanaltin
Copy link
Member Author

mertcanaltin commented Oct 29, 2025

thats my first performance results:

I think need improvement for child logger area, but ı'm so happy because other results it looks nice.
cc @mcollina @Qard @trentm @jsumners

node:logger vs pino

➜ node git:(mert/create-logger-api/node-core) ✗ ./node benchmark/logger/vs-pino.js n=100000
logger/vs-pino.js scenario="simple" logger="node-logger" n=100000: 5,240,540.823813018
logger/vs-pino.js scenario="child" logger="node-logger" n=100000: 2,635,847.7027229806
logger/vs-pino.js scenario="disabled" logger="node-logger" n=100000: 159,436,487.67795104
logger/vs-pino.js scenario="fields" logger="node-logger" n=100000: 3,619,336.304205216
logger/vs-pino.js scenario="simple" logger="pino" n=100000: 3,398,489.9761368227
logger/vs-pino.js scenario="child" logger="pino" n=100000: 4,489,799.803418606
logger/vs-pino.js scenario="disabled" logger="pino" n=100000: 119,772,384.56038144
logger/vs-pino.js scenario="fields" logger="pino" n=100000: 1,257,930.8609750536

@mertcanaltin
Copy link
Member Author

mertcanaltin commented Oct 29, 2025

I now learn this feat in Pino

pinojs/pino#2281

I will try add in node:logger

@mcollina
Copy link
Member

This will require support for serializers

@mertcanaltin
Copy link
Member Author

mertcanaltin commented Oct 30, 2025

This will require support for serializers

I wonder, should we name them like Pino does (built-in serializers), or go with something like standardSerializers ?

@mcollina
Copy link
Member

mcollina commented Nov 8, 2025

This will require support for serializers

I wonder, should we name them like Pino does (built-in serializers), or go with something like standardSerializers ?

Follow pino and we’ll change it

@mertcanaltin
Copy link
Member Author

mertcanaltin commented Nov 10, 2025

This will require support for serializers

I wonder, should we name them like Pino does (built-in serializers), or go with something like standardSerializers ?

Follow pino and we’ll change it

I tryed serializer implement for logger, and some bench result repaired

and fields and simple are experiencing a decline; I will try to resolve these

fields: 3.62M → 2.16M (-40%)
simple: 5.24M → 4.87M (-7%)

previously, the results for the child logger were quite slow at around 70%, but the new results have dropped to 18% and have actually improved significantly.

I continue to try new methods.

➜  node git:(mert/create-logger-api/node-core) ✗ ./node benchmark/logger/vs-pino.js n=100000
logger/vs-pino.js scenario="simple" logger="node-logger" n=100000: 4,868,164.032787085
logger/vs-pino.js scenario="child" logger="node-logger" n=100000: 3,894,327.425314102
logger/vs-pino.js scenario="disabled" logger="node-logger" n=100000: 160,503,080.85663706
logger/vs-pino.js scenario="fields" logger="node-logger" n=100000: 2,157,462.3927336666
logger/vs-pino.js scenario="simple" logger="pino" n=100000: 3,424,706.4418693925
logger/vs-pino.js scenario="child" logger="pino" n=100000: 4,753,595.477010947
logger/vs-pino.js scenario="disabled" logger="pino" n=100000: 122,100,122.10012211
logger/vs-pino.js scenario="fields" logger="pino" n=100000: 1,411,215.99189962
➜  node git:(mert/create-logger-api/node-core) ✗ 

@mertcanaltin
Copy link
Member Author

mertcanaltin commented Nov 10, 2025

This will require support for serializers

I wonder, should we name them like Pino does (built-in serializers), or go with something like standardSerializers ?

Follow pino and we’ll change it

I tryed serializer implement for logger, and some bench result repaired

and fields and simple are experiencing a decline; I will try to resolve these

fields: 3.62M → 2.16M (-40%) simple: 5.24M → 4.87M (-7%)

previously, the results for the child logger were quite slow at around 70%, but the new results have dropped to 18% and have actually improved significantly.

I continue to try new methods.

➜  node git:(mert/create-logger-api/node-core) ✗ ./node benchmark/logger/vs-pino.js n=100000
logger/vs-pino.js scenario="simple" logger="node-logger" n=100000: 4,868,164.032787085
logger/vs-pino.js scenario="child" logger="node-logger" n=100000: 3,894,327.425314102
logger/vs-pino.js scenario="disabled" logger="node-logger" n=100000: 160,503,080.85663706
logger/vs-pino.js scenario="fields" logger="node-logger" n=100000: 2,157,462.3927336666
logger/vs-pino.js scenario="simple" logger="pino" n=100000: 3,424,706.4418693925
logger/vs-pino.js scenario="child" logger="pino" n=100000: 4,753,595.477010947
logger/vs-pino.js scenario="disabled" logger="pino" n=100000: 122,100,122.10012211
logger/vs-pino.js scenario="fields" logger="pino" n=100000: 1,411,215.99189962
➜  node git:(mert/create-logger-api/node-core) ✗ 

I inspected pino and I learn some patterns, than I applied this commit and new results! 1ededc7

I used this patterns

removed the cost of serializing bindings in each log for the child logger,
skipped unnecessary serializer checks,
used direct string concatenation instead of object merging,
sped up type checking

simple: 6.06M vs 3.48M ops/s (+74% faster)
child: 5.76M vs 4.41M ops/s (+31% faster)
disabled: 174M vs 146M ops/s (+19% faster)
fields: 2.13M vs 1.36M ops/s (+56% faster)

➜  node git:(mert/create-logger-api/node-core) ✗ ./node benchmark/logger/vs-pino.js n=100000
logger/vs-pino.js scenario="simple" logger="node-logger" n=100000: 6,062,182.962986493
logger/vs-pino.js scenario="child" logger="node-logger" n=100000: 5,758,903.394222795
logger/vs-pino.js scenario="disabled" logger="node-logger" n=100000: 174,026,539.04720467
logger/vs-pino.js scenario="fields" logger="node-logger" n=100000: 2,126,059.37552321
logger/vs-pino.js scenario="simple" logger="pino" n=100000: 3,477,918.037575009
logger/vs-pino.js scenario="child" logger="pino" n=100000: 4,407,389.658686015
logger/vs-pino.js scenario="disabled" logger="pino" n=100000: 145,551,509.22359914
logger/vs-pino.js scenario="fields" logger="pino" n=100000: 1,363,125.197883181
➜  node git:(mert/create-logger-api/node-core) ✗ 

@mertcanaltin
Copy link
Member Author

mertcanaltin commented Nov 20, 2025

hello @mcollina do you any comments or suggestions for this end commits, I'm curious 🙏 .

@mertcanaltin mertcanaltin marked this pull request as ready for review November 29, 2025 14:16
@codecov
Copy link

codecov bot commented Nov 29, 2025

Codecov Report

❌ Patch coverage is 88.79056% with 76 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.70%. Comparing base (e7d6728) to head (e2b603f).
⚠️ Report is 142 commits behind head on main.

Files with missing lines Patch % Lines
lib/logger.js 87.90% 71 Missing ⚠️
lib/internal/logger/serializers.js 93.50% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #60468      +/-   ##
==========================================
- Coverage   89.74%   89.70%   -0.04%     
==========================================
  Files         674      678       +4     
  Lines      204395   206665    +2270     
  Branches    39274    39565     +291     
==========================================
+ Hits       183427   185399    +1972     
- Misses      13275    13420     +145     
- Partials     7693     7846     +153     
Files with missing lines Coverage Δ
lib/internal/bootstrap/realm.js 96.21% <100.00%> (+0.21%) ⬆️
lib/internal/process/pre_execution.js 97.34% <100.00%> (+1.37%) ⬆️
src/node_options.cc 76.32% <100.00%> (-0.06%) ⬇️
src/node_options.h 97.95% <100.00%> (+0.06%) ⬆️
lib/internal/logger/serializers.js 93.50% <93.50%> (ø)
lib/logger.js 87.90% <87.90%> (ø)

... and 188 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mertcanaltin mertcanaltin requested a review from a team as a code owner November 30, 2025 17:53
@mertcanaltin mertcanaltin force-pushed the mert/create-logger-api/node-core branch 2 times, most recently from f5b0108 to 429359b Compare November 30, 2025 18:01
Copy link
Member

@AugustinMauroy AugustinMauroy left a comment

Choose a reason for hiding this comment

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

LGTM !

@mertcanaltin
Copy link
Member Author

@AugustinMauroy @RafaelGSS Thanks for the review, edited your comments

@mertcanaltin mertcanaltin changed the title [WIP] lib: added logger api in node core lib: added logger api in node core Feb 25, 2026
@anonrig
Copy link
Member

anonrig commented Feb 25, 2026

@RafaelGSS please take a look. 7 days passed since your review has been requested.

Copy link
Member

@RafaelGSS RafaelGSS left a comment

Choose a reason for hiding this comment

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

It's missing tests for a significant part of the exposed API. Apart from my comments, why are we copying pino internals instead of vendoring pino (which is more robust and well tested) into core?

I'd love to hear @mcollina and @jsumners thoughts on this PR too.

@@ -0,0 +1,819 @@
# Logger

<!--introduced_in=v26.0.0-->
Copy link
Member

Choose a reason for hiding this comment

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

Unless we flag this as semver-major, this is wrong.

<!-- source_link=lib/logger.js -->

The `node:logger` module provides high-performance structured logging
Copy link
Member

Choose a reason for hiding this comment

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

We should clarify this is only enabled via --experimental-logger

Comment on lines +104 to +106
* `obj` {Object} Object containing `msg` property and additional fields.
* `error` {Error} Error object to log.
* `fields` {Object} Additional fields to include in the log record.
Copy link
Member

Choose a reason for hiding this comment

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

It's not clear its impact on the call

Comment on lines +148 to +151
* `msg` {string} Log message.
* `obj` {Object} Object containing `msg` property and additional fields.
* `error` {Error} Error object to log.
* `fields` {Object} Additional fields to include in the log record.
Copy link
Member

Choose a reason for hiding this comment

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

Ditto

logger.fatal(new Error('Unrecoverable error'));
```

### `logger.child(bindings[, options])`
Copy link
Member

Choose a reason for hiding this comment

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

Considering child logger instances are a bit complex, I'd also include it as > stability 1.1

*/
function serializeErr(error) {
if (!isNativeError(error)) {
return error;
Copy link
Member

Choose a reason for hiding this comment

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

It's not clear to me why we return if it's not a native error; shouldn't we log/fail instead?

// Handle error cause recursively
if (error.cause !== undefined) {
obj.cause = typeof error.cause === 'object' && error.cause !== null ?
serializeErr(error.cause) :
Copy link
Member

Choose a reason for hiding this comment

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

Couldn't it cause a crash if it recurses indefinitely?

// Create channels for each log level
const channels = {
__proto__: null,
trace: diagnosticsChannel.channel('log:trace'),
Copy link
Member

Choose a reason for hiding this comment

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

we should document the channel names used somewhere.

@RafaelGSS
Copy link
Member

@RafaelGSS please take a look. 7 days passed since your review has been requested.

It's a 2.5k lines PR, it's hard to concilate time to review it properly.

mertcanaltin and others added 2 commits February 26, 2026 12:42
Co-authored-by: Rafael Gonzaga <rafael.nunu@hotmail.com>
Co-authored-by: Rafael Gonzaga <rafael.nunu@hotmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.