Skip to content

Commit a701d19

Browse files
committed
fix: dont warn on error cleaning individual log files
Closes: #4128 This also refactors the logic for cleaning log files to use the `ignore` option from `glob` to not clean current log files instead of relying on updating the `logs-max` count. I also discovered a bug where we weren't cleaning log files written with the old naming convention, so this fixes that as well.
1 parent 4dbeb00 commit a701d19

File tree

2 files changed

+40
-28
lines changed

2 files changed

+40
-28
lines changed

lib/utils/log-file.js

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ const fsMiniPass = require('fs-minipass')
88
const log = require('./log-shim')
99
const withChownSync = require('./with-chown-sync')
1010

11+
const padZero = (n, length) => n.toString().padStart(length.toString().length, '0')
12+
1113
const _logHandler = Symbol('logHandler')
1214
const _formatLogItem = Symbol('formatLogItem')
1315
const _getLogFilePath = Symbol('getLogFilePath')
@@ -34,7 +36,7 @@ class LogFiles {
3436
// here for infinite loops that still log. This is also partially handled
3537
// by the config.get('max-files') option, but this is a failsafe to
3638
// prevent runaway log file creation
37-
#MAX_LOG_FILES_PER_PROCESS = null
39+
#MAX_FILES_PER_PROCESS = null
3840

3941
#fileLogCount = 0
4042
#totalLogCount = 0
@@ -48,18 +50,14 @@ class LogFiles {
4850
} = {}) {
4951
this.#logId = LogFiles.logId(new Date())
5052
this.#MAX_LOGS_PER_FILE = maxLogsPerFile
51-
this.#MAX_LOG_FILES_PER_PROCESS = maxFilesPerProcess
53+
this.#MAX_FILES_PER_PROCESS = maxFilesPerProcess
5254
this.on()
5355
}
5456

5557
static logId (d) {
5658
return d.toISOString().replace(/[.:]/g, '_')
5759
}
5860

59-
static fileName (prefix, suffix) {
60-
return `${prefix}-debug-${suffix}.log`
61-
}
62-
6361
static format (count, level, title, ...args) {
6462
let prefix = `${count} ${level}`
6563
if (title) {
@@ -149,7 +147,7 @@ class LogFiles {
149147
if (this.#fileLogCount >= this.#MAX_LOGS_PER_FILE) {
150148
// Write last chunk to the file and close it
151149
this[_endStream](logOutput)
152-
if (this.#files.length >= this.#MAX_LOG_FILES_PER_PROCESS) {
150+
if (this.#files.length >= this.#MAX_FILES_PER_PROCESS) {
153151
// but if its way too many then we just stop listening
154152
this.off()
155153
} else {
@@ -166,23 +164,21 @@ class LogFiles {
166164
return LogFiles.format(this.#totalLogCount++, ...args)
167165
}
168166

169-
[_getLogFilePath] (prefix, suffix) {
170-
return path.resolve(this.#dir, LogFiles.fileName(prefix, suffix))
167+
[_getLogFilePath] (prefix, suffix, sep = '-') {
168+
return path.resolve(this.#dir, prefix + sep + 'debug' + sep + suffix + '.log')
171169
}
172170

173171
[_openLogFile] () {
174172
// Count in filename will be 0 indexed
175173
const count = this.#files.length
176174

177-
// Pad with zeros so that our log files are always sorted properly
178-
// We never want to write files ending in `-9.log` and `-10.log` because
179-
// log file cleaning is done by deleting the oldest so in this example
180-
// `-10.log` would be deleted next
181-
const countDigits = this.#MAX_LOG_FILES_PER_PROCESS.toString().length
182-
183175
try {
184176
const logStream = withChownSync(
185-
this[_getLogFilePath](this.#logId, count.toString().padStart(countDigits, '0')),
177+
// Pad with zeros so that our log files are always sorted properly
178+
// We never want to write files ending in `-9.log` and `-10.log` because
179+
// log file cleaning is done by deleting the oldest so in this example
180+
// `-10.log` would be deleted next
181+
this[_getLogFilePath](this.#logId, padZero(count, this.#MAX_FILES_PER_PROCESS)),
186182
// Some effort was made to make the async, but we need to write logs
187183
// during process.on('exit') which has to be synchronous. So in order
188184
// to never drop log messages, it is easiest to make it sync all the time
@@ -214,14 +210,13 @@ class LogFiles {
214210
return
215211
}
216212

217-
// Add 1 to account for the current log file and make
218-
// minimum config 0 so current log file is never deleted
219-
// XXX: we should make a separate documented option to
220-
// disable log file writing
221-
const max = Math.max(this.#logsMax, 0) + 1
222213
try {
223-
const files = await glob(this[_getLogFilePath]('*', '*'))
224-
const toDelete = files.length - max
214+
// Handle the old (prior to 8.2.0) log file names which did not have an counter suffix
215+
// so match by anything after `-debug` and before `.log` (including nothing)
216+
const logGlob = this[_getLogFilePath]('*-', '*', '')
217+
// Always ignore the currently written files
218+
const files = await glob(logGlob, { ignore: this.#files })
219+
const toDelete = files.length - this.#logsMax
225220

226221
if (toDelete <= 0) {
227222
return
@@ -233,7 +228,7 @@ class LogFiles {
233228
try {
234229
await rimraf(file)
235230
} catch (e) {
236-
log.warn('logfile', 'error removing log file', file, e)
231+
log.silly('logfile', 'error removing log file', file, e)
237232
}
238233
}
239234
} catch (e) {

test/lib/utils/log-file.js

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,20 @@ t.cleanSnapshot = (path) => cleanCwd(path)
1212

1313
const last = arr => arr[arr.length - 1]
1414
const range = (n) => Array.from(Array(n).keys())
15-
const makeOldLogs = (count) => {
15+
const makeOldLogs = (count, oldStyle) => {
1616
const d = new Date()
1717
d.setHours(-1)
1818
d.setSeconds(0)
19-
return range(count / 2).reduce((acc, i) => {
19+
return range(count / (oldStyle ? 1 : 2)).reduce((acc, i) => {
2020
const cloneDate = new Date(d.getTime())
2121
cloneDate.setSeconds(i)
22-
acc[LogFile.fileName(LogFile.logId(cloneDate), 0)] = 'hello'
23-
acc[LogFile.fileName(LogFile.logId(cloneDate), 1)] = 'hello'
22+
const dateId = LogFile.logId(cloneDate)
23+
if (oldStyle) {
24+
acc[`${dateId}-debug.log`] = 'hello'
25+
} else {
26+
acc[`${dateId}-debug-0.log`] = 'hello'
27+
acc[`${dateId}-debug-1.log`] = 'hello'
28+
}
2429
return acc
2530
}, {})
2631
}
@@ -247,6 +252,18 @@ t.test('glob error', async t => {
247252
t.match(last(logs).content, /error cleaning log files .* bad glob/)
248253
})
249254

255+
t.test('cleans old style logs too', async t => {
256+
const logsMax = 5
257+
const oldLogs = 10
258+
const { readLogs } = await loadLogFile(t, {
259+
logsMax,
260+
testdir: makeOldLogs(oldLogs, false),
261+
})
262+
263+
const logs = await readLogs()
264+
t.equal(logs.length, logsMax + 1)
265+
})
266+
250267
t.test('rimraf error', async t => {
251268
const logsMax = 5
252269
const oldLogs = 10

0 commit comments

Comments
 (0)