fix(logging): default rotation path to <log dir>/rotated when unset - #1090
Conversation
Patch cherry-pick: conflictCherry-pick onto The conflict markers are committed on branch |
There was a problem hiding this comment.
Code Review
This pull request updates the log rotator to default the rotation path to <log dir>/rotated when it is not explicitly configured, rather than throwing an error. It also ensures the directory is created, and updates the unit tests to reflect this new behavior. The review feedback suggests replacing the synchronous mkdirSync call with an asynchronous fsProm.mkdir to avoid blocking the Node.js event loop, and consequently removing mkdirSync from the imports.
| 'use strict'; | ||
|
|
||
| import { promises as fsProm, createReadStream, createWriteStream } from 'fs'; | ||
| import { promises as fsProm, createReadStream, createWriteStream, mkdirSync } from 'fs'; |
There was a problem hiding this comment.
Since mkdirSync is being replaced with an asynchronous alternative to prevent blocking the event loop, we should remove it from the fs imports.
| import { promises as fsProm, createReadStream, createWriteStream, mkdirSync } from 'fs'; | |
| import { promises as fsProm, createReadStream, createWriteStream } from 'fs'; |
| // Ensure the directory exists; moveLogFile's rename would otherwise ENOENT on first rotation. | ||
| mkdirSync(rotatedLogDir, { recursive: true }); |
There was a problem hiding this comment.
Using mkdirSync blocks the Node.js event loop, which can degrade performance in a high-throughput database environment like HarperDB.
We should perform this directory creation asynchronously using fsProm.mkdir and handle any potential errors gracefully.
| // Ensure the directory exists; moveLogFile's rename would otherwise ENOENT on first rotation. | |
| mkdirSync(rotatedLogDir, { recursive: true }); | |
| // Ensure the directory exists asynchronously to avoid blocking the event loop. | |
| fsProm.mkdir(rotatedLogDir, { recursive: true }).catch((err) => { | |
| hdbLogger.error('Failed to create rotated log directory', err); | |
| }); |
|
Reviewed; no blockers found. |
closes #1088
Summary
rotation.pathto<dirname(logger.path)>/rotatedinsidelogRotatorwhen not explicitly set, so rotation works out of the box when onlyLOGGING_ROTATION_MAXSIZE(orLOGGING_ROTATION_INTERVAL) is configured.mkdirSync(rotatedLogDir, { recursive: true })at init so the first rotation's rename doesn't ENOENT on the freshly defaulted dir.PATH_UNDEFINED_MSGconstant.Context
Today the default config ships with
logging.rotation.enabled: true, maxSize: 64M, path: null. The rotator atutility/logging/logRotator.ts:48-50throws'logging.rotation.path' is undefined, ...whenpathis null, andharper_logger.ts:638-640catches the throw silently and re-emits it through the file logger we're trying to rotate. End result: an operator setting onlyLOGGING_ROTATION_MAXSIZE=512Mgets no rotation and no actionable signal until the disk or quota fills.Three fix shapes were considered in #1088: surface the catch to stderr, default the path, or fail config validation when
enabled: trueandpath: null. This PR takes "default the path" because the other two either don't actually fix the broken default (just make it noisier) or break every existing deploy on upgrade.The default lives in
logRotatorrather than indefaultConfig.yamlso it stays adjacent to whatever the actual log file path resolves to at runtime. An explicitLOGGING_ROTATION_PATHcontinues to override the default, andLOGGING_ROTATION_ENABLED=falsecontinues to disable rotation entirely.Test
unitTests/utility/logging/logRotator.test.js: the existing "Test error logged if rotation path is undefined" is replaced with "Defaults rotation path to /rotated when path is not set", which calls the rotator withpath: nulland asserts the rotated file lands under<LOG_DIR_TEST>/rotated/.