Skip to content

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
lib/logger.js Outdated
constructor(options = {}) {
validateObject(options, 'options');
const {
handler = new JSONHandler(),
Copy link
Member

Choose a reason for hiding this comment

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

Rather than passing the handler directly in like this, it would be worth considering a design more like swift-log where there is a separate interface for indirectly attaching a consumer. That way it doesn't need to be the responsibility of each place a logger is constructed to decide where the logs are being shipped. I had planned on working on structured logging myself at some point, using diagnostics_channel to manage dispatching log events to consumers, and even support multiple consumers. In a lot of apps you might want console output but also to be writing logs to other places like log search services.

My original plan was to have separate channels for each log level, that way events of log levels not being listened to could be ignored entirely, but also it would enable each consumer to decide their own log level independently--a console logger might want to only listen to info+ levels while an attached diagnostics tool might want to see everything.

Copy link
Member Author

Choose a reason for hiding this comment

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

+1 sound good, thanks for detail, I will apply this plan.

@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.41463% with 76 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.56%. Comparing base (6274eb7) to head (429359b).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
lib/logger.js 87.84% 71 Missing ⚠️
lib/internal/logger/serializers.js 93.05% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #60468      +/-   ##
==========================================
+ Coverage   88.55%   88.56%   +0.01%     
==========================================
  Files         703      705       +2     
  Lines      208291   208947     +656     
  Branches    40170    40268      +98     
==========================================
+ Hits       184443   185055     +612     
- Misses      15874    15904      +30     
- Partials     7974     7988      +14     
Files with missing lines Coverage Δ
lib/internal/logger/serializers.js 93.05% <93.05%> (ø)
lib/logger.js 87.84% <87.84%> (ø)

... and 43 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 from 259652e to f5b0108 Compare November 30, 2025 17:57
@mertcanaltin mertcanaltin force-pushed the mert/create-logger-api/node-core branch from f5b0108 to 429359b Compare November 30, 2025 18:01
* @returns {boolean}
*/
enabled(level) {
return LEVELS[level] >= this.#levelValue;
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this throw an explicit validation error if the provided level is unknown? (e.g., typo, wrong case, accidental leading/trailing space, etc.)

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.

10 participants