diff --git a/README.md b/README.md index 323de99..1c1137d 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ The environment variable `CRON_ROTATE` is used to schedule the rotation of the f If any files are rotated then, optionally, `LOGROTATE_POSTROTATE_COMMAND` is called. It can be necessary to signal the application that the rotation occurred so it can open a new file. +Files are normally just renamed. You can set `LOGROTATE_COPYTRUNCATE_SUFFIXES` to instead copy and then truncate the file. Some files, like redirected output, can't be renamed and then deleted. + Rotated files are appended with the file's change date and the current UTC timestamp. See: https://nodejs.org/api/fs.html#stat-time-values ### Stage 2 - Compress log file diff --git a/src/constants.ts b/src/constants.ts index 8ae8a58..f843063 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -15,6 +15,8 @@ export const LOGROTATE_AGE_MAX = process.env.LOGROTATE_AGE_MAX : 0; export const LOGROTATE_SUFFIX = process.env.LOGROTATE_SUFFIX ?? 'log'; +export const LOGROTATE_COPYTRUNCATE_SUFFIXES = + process.env.LOGROTATE_COPYTRUNCATE_SUFFIXES?.split(',') ?? []; export const LOGROTATE_POSTROTATE_COMMAND = process.env.LOGROTATE_POSTROTATE_COMMAND ?? ''; export const JANITOR_COPIES = Number.parseInt( diff --git a/src/cron/rotate.ts b/src/cron/rotate.ts index d8b5cc6..a5b1cd3 100644 --- a/src/cron/rotate.ts +++ b/src/cron/rotate.ts @@ -7,6 +7,7 @@ import { LOGROTATE_POSTROTATE_COMMAND, LOGROTATE_DIRECTORY, LOGROTATE_SUFFIX, + LOGROTATE_COPYTRUNCATE_SUFFIXES, LOGROTATE_FILESIZE_MIN, LOGROTATE_AGE_MAX, } from '../constants'; @@ -64,9 +65,16 @@ export async function rotateLogs(db: DatabaseService) { async function rotateLog(db: DatabaseService, file: string) { const oldPath = path.join(LOGROTATE_DIRECTORY, file); const newPath = path.join(LOGROTATE_DIRECTORY, newLogName(file)); + const strategy = computeRotateStrategy(file); - console.log(`rotate: ${oldPath} -> ${newPath}`); - fs.renameSync(oldPath, newPath); + console.log(`rotate: [${strategy}] ${oldPath} -> ${newPath}`); + + if (strategy === 'rename') { + fs.renameSync(oldPath, newPath); + } else if (strategy === 'copytruncate') { + fs.copyFileSync(oldPath, newPath); + fs.truncateSync(oldPath); + } // Add log to database await db.addLog(file, newPath); @@ -85,3 +93,12 @@ function changeDate(filePath: string) { const { ctime } = fs.statSync(filePath); return ctime; } + +function computeRotateStrategy(file: string) { + for (const suffix of LOGROTATE_COPYTRUNCATE_SUFFIXES) { + if (file.endsWith(suffix)) { + return 'copytruncate'; + } + } + return 'rename'; +}