fix: prevent infinite loop on logging
resolves #298
Codecov Report
:x: Patch coverage is 83.33333% with 3 lines in your changes missing coverage. Please review.
:white_check_mark: Project coverage is 30.86%. Comparing base (24c98ce) to head (a8a2384).
:warning: Report is 58 commits behind head on main.
| Files with missing lines | Patch % | Lines |
|---|---|---|
| src/consola.ts | 83.33% | 3 Missing :warning: |
Additional details and impacted files
@@ Coverage Diff @@
## main #370 +/- ##
===========================================
- Coverage 61.08% 30.86% -30.23%
===========================================
Files 13 43 +30
Lines 1380 1740 +360
Branches 58 100 +42
===========================================
- Hits 843 537 -306
- Misses 537 1176 +639
- Partials 0 27 +27
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
:rocket: New features to boost your workflow:
- :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
- :package: JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
Nice solution however as discussed in #298 it is an issue with Browser reporter without util.format support. Unless we can reproduce it in node, we might better apply this fix to browser reporter.
It can be reproduced in node, see https://github.com/unjs/consola/issues/298#issuecomment-2125827332
And it's caused by this JSON.strinfify
https://github.com/unjs/consola/blob/5ac9ed76b021c9ffc768f0727355238056aabeb1/src/consola.ts#L425-L430
JSON.stringify invokes the getter, which logs the same obj again, resulting in a recursive call to JSON.stringify, and this process continues indefinitely.
Wondering if we could make it safer (and faster) by using ohash for comparing log objects instead of full serialization.
No, I've tried (ohash or other methods), but they don't help.
Anythings that works like serialize (which triggers getter) will result in infinite loop.
It's not just the getter; Proxy can also trigger this behavior.
For example:
const p = new Proxy({}, {
get(target, prop, receiver) {
console.warn('proxy getter', p)
return Reflect.get(target, prop, receiver)
}
})
consola.wrapConsole();
consola.warn(p);
consola.restoreConsole();
This would also result in infinite loop. (And there could be more edge cases 🫠)