Skip to content

feat: child loggers, structured meta, Error serialization, timers, TTY-aware color#55

Merged
LMaxence merged 2 commits into
LMaxence:mainfrom
hexablob:feat/child-loggers-dx
Jun 27, 2026
Merged

feat: child loggers, structured meta, Error serialization, timers, TTY-aware color#55
LMaxence merged 2 commits into
LMaxence:mainfrom
hexablob:feat/child-loggers-dx

Conversation

@hexablob

@hexablob hexablob commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Hello @LMaxence à dispo pour en parler (je t'ai contacté sur LinkedIN)

Summary

  • logger.child(meta) — create child loggers that inherit level + plugins and merge parent meta. Supports static and dynamic meta, nests arbitrarily.
  • Structured meta — widen meta from Record<string,string> to Record<string,unknown> so numbers, booleans, and objects pass through to JSON/logfmt sinks without pre-stringifying.
  • First-class Error serialization — automatically extracts { name, message, stack } from any Error argument and attaches it to HellogMessage.error for structured sinks.
  • Duration timerslogger.time(label) / logger.timeEnd(label) using process.hrtime.bigint() (monotonic, sub-ms). Logs elapsed time and includes durationMs in meta.
  • isLevelEnabled(level) — guard expensive argument construction without duplicating the level-filter logic.
  • TTY-aware colorizeHellogColorizeDefaultPlugin now auto-detects process.stdout.isTTY, NO_COLOR, and FORCE_COLOR. Accepts an explicit { enabled?: boolean } override.
  • DefaultPlugins → factory — converts the shared static plugin array to a per-instance factory to prevent cross-logger state bleed.

Backward compatibility

All changes are additive. Record<string,string> meta is a subtype of Record<string,unknown> so existing callers compile unchanged. Default plugin stack and output formats are unaffected. Zero new runtime dependencies.

Test plan

  • npm run build — TypeScript compiles clean under @tsconfig/strictest
  • npm test — 32/32 tests pass (up from 17), coverage 97%
  • npm run lint — oxlint clean
  • npm run format:check — oxfmt clean

…Y-aware color

- Add logger.child(meta) for context-binding child loggers; merges static
  and dynamic meta from parent, supports arbitrary nesting
- Widen meta type from Record<string,string> to Record<string,unknown> so
  numbers, booleans, and objects pass through to JSON/logfmt sinks
- Serialize Error arguments to { name, message, stack } on HellogMessage.error
  for structured sinks; human content unchanged via util.format
- Add time(label)/timeEnd(label) duration timers using process.hrtime.bigint()
  with durationMs in meta; no memory leak on unknown labels
- Add isLevelEnabled(level) guard for expensive argument construction
- Make HellogColorizeDefaultPlugin TTY-aware: auto-detects process.stdout.isTTY,
  NO_COLOR, FORCE_COLOR; accepts { enabled? } override
- Convert DefaultPlugins static array to per-instance factory to prevent
  cross-logger state bleed as plugins gain state
- New lib/errors.ts with SerializedError interface and serializeError() util
- 32 tests, 97% coverage (up from 17 tests, 88% coverage)
- Zero new runtime dependencies; full backward compatibility

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@LMaxence LMaxence left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thanks for the contribution !

The Hellog class is getting a big bigger than what I'd like it to be, but it's still fine for now.

Note for myself later, I'd like to move the timers and metas into isolated classes handling their logic and serde layers

Comment thread lib/plugins.ts Outdated
if (process.env['FORCE_COLOR'] === '0') return false;
if (process.env['NO_COLOR'] !== undefined) return false;
return process.stdout.isTTY === true;
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I'd prefer this to be a getter in the plugin please :)

Address review feedback: fold the standalone _colorEnabled function into a
private getter on HellogColorizeDefaultPlugin.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@LMaxence LMaxence force-pushed the feat/child-loggers-dx branch from 81f2641 to 9518991 Compare June 27, 2026 22:56
@LMaxence LMaxence merged commit 68da855 into LMaxence:main Jun 27, 2026
2 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 3.6.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@hexablob

Copy link
Copy Markdown
Contributor Author

Thanks for the contribution !

The Hellog class is getting a big bigger than what I'd like it to be, but it's still fine for now.

Note for myself later, I'd like to move the timers and metas into isolated classes handling their logic and serde layers

I agree, it would allow for better separation of concerns and make the code easier to test. Would you like me to do it @LMaxence?

@LMaxence

Copy link
Copy Markdown
Owner

I already made a commit for that in the weekend: #57

We're all good here :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants