Skip to content

Commit f309c1c

Browse files
committed
fix(refactor): move timer and error logfile messages to lib/npm
1 parent 43e6194 commit f309c1c

File tree

5 files changed

+39
-168
lines changed

5 files changed

+39
-168
lines changed

lib/cli/exit-handler.js

+4-66
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { log, output, time, META } = require('proc-log')
1+
const { log, output, META } = require('proc-log')
22
const errorMessage = require('../utils/error-message.js')
33
const { redactLog: replaceInfo } = require('@npmcli/redact')
44

@@ -7,19 +7,8 @@ let exitHandlerCalled = false
77
let showLogFileError = false
88

99
process.on('exit', code => {
10-
// process.emit is synchronous, so the timeEnd handler will run before the
11-
// unfinished timer check below
12-
time.end('npm')
13-
1410
const hasLoadedNpm = npm?.config.loaded
1511

16-
// Unfinished timers can be read before config load
17-
if (npm) {
18-
for (const [name, timer] of npm.unfinishedTimers) {
19-
log.silly('unfinished npm timer', name, timer)
20-
}
21-
}
22-
2312
if (!code) {
2413
log.info('ok')
2514
} else {
@@ -31,65 +20,14 @@ process.on('exit', code => {
3120
log.error('', 'Exit handler never called!')
3221
log.error('', 'This is an error with npm itself. Please report this error at:')
3322
log.error('', ' <https://github.com/npm/cli/issues>')
34-
35-
if (!npm || !npm.silent) {
36-
// eslint-disable-next-line no-console
37-
console.error('')
38-
}
39-
23+
// eslint-disable-next-line no-console
24+
console.error('')
4025
showLogFileError = true
4126
}
4227

4328
// npm must be loaded to know where the log file was written
4429
if (hasLoadedNpm) {
45-
// write the timing file now, this might do nothing based on the configs set.
46-
// we need to call it here in case it errors so we dont tell the user
47-
// about a timing file that doesn't exist
48-
npm.finish()
49-
50-
const logsDir = npm.logsDir
51-
const logFiles = npm.logFiles
52-
53-
const timingDir = npm.timingDir
54-
const timingFile = npm.timingFile
55-
56-
const timing = npm.config.get('timing')
57-
const logsMax = npm.config.get('logs-max')
58-
59-
// Determine whether to show log file message and why it is
60-
// being shown since in timing mode we always show the log file message
61-
const logMethod = showLogFileError ? 'error' : timing ? 'info' : null
62-
63-
if (logMethod) {
64-
// just a line break, will be ignored in silent mode
65-
output.error('')
66-
67-
const message = []
68-
69-
if (timingFile) {
70-
message.push(`Timing info written to: ${timingFile}`)
71-
} else if (timing) {
72-
message.push(
73-
`The timing file was not written due to an error writing to the directory: ${timingDir}`
74-
)
75-
}
76-
77-
if (logFiles.length) {
78-
message.push(`A complete log of this run can be found in: ${logFiles}`)
79-
} else if (logsMax <= 0) {
80-
// user specified no log file
81-
message.push(`Log files were not written due to the config logs-max=${logsMax}`)
82-
} else {
83-
// could be an error writing to the directory
84-
message.push(
85-
`Log files were not written due to an error writing to the directory: ${logsDir}`,
86-
'You can rerun the command with `--loglevel=verbose` to see the logs in your terminal'
87-
)
88-
}
89-
90-
log[logMethod]('', message.join('\n'))
91-
}
92-
30+
npm.finish({ showLogFileError })
9331
// This removes any listeners npm setup, mostly for tests to avoid max listener warnings
9432
npm.unload()
9533
}

lib/npm.js

+27-17
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,35 @@ class Npm {
117117
this.#logFile.off()
118118
}
119119

120-
finish () {
120+
finish ({ showLogFileError } = {}) {
121121
this.#timers.finish({
122122
id: this.#runId,
123123
command: this.#argvClean,
124124
logfiles: this.logFiles,
125125
version: this.version,
126126
})
127+
128+
if (showLogFileError) {
129+
if (!this.silent) {
130+
// just a line break if not in silent mode
131+
output.error('')
132+
}
133+
134+
const logsMax = this.config.get('logs-max')
135+
136+
if (this.logFiles.length) {
137+
log.error('', `A complete log of this run can be found in: ${this.logFiles}`)
138+
} else if (logsMax <= 0) {
139+
// user specified no log file
140+
log.error('', `Log files were not written due to the config logs-max=${logsMax}`)
141+
} else {
142+
// could be an error writing to the directory
143+
log.error('',
144+
`Log files were not written due to an error writing to the directory: ${this.#logsDir}` +
145+
'\nYou can rerun the command with `--loglevel=verbose` to see the logs in your terminal'
146+
)
147+
}
148+
}
127149
}
128150

129151
get title () {
@@ -179,7 +201,7 @@ class Npm {
179201
// which we will tell them about at the end
180202
if (this.config.get('logs-max') > 0) {
181203
await time.start('npm:load:mkdirplogs', () =>
182-
fs.mkdir(this.logsDir, { recursive: true })
204+
fs.mkdir(this.#logsDir, { recursive: true })
183205
.catch((e) => log.verbose('logfile', `could not create logs-dir: ${e}`)))
184206
}
185207

@@ -208,7 +230,7 @@ class Npm {
208230
})
209231

210232
this.#timers.load({
211-
path: this.config.get('timing') ? this.logPath : null,
233+
path: this.logPath,
212234
timing: this.config.get('timing'),
213235
})
214236

@@ -281,14 +303,6 @@ class Npm {
281303
return 2
282304
}
283305

284-
get unfinishedTimers () {
285-
return this.#timers.unfinished
286-
}
287-
288-
get finishedTimers () {
289-
return this.#timers.finished
290-
}
291-
292306
get started () {
293307
return this.#timers.started
294308
}
@@ -297,16 +311,12 @@ class Npm {
297311
return this.#logFile.files
298312
}
299313

300-
get logsDir () {
314+
get #logsDir () {
301315
return this.config.get('logs-dir') || join(this.cache, '_logs')
302316
}
303317

304318
get logPath () {
305-
return resolve(this.logsDir, `${this.#runId}-`)
306-
}
307-
308-
get timingFile () {
309-
return this.#timers.file
319+
return resolve(this.#logsDir, `${this.#runId}-`)
310320
}
311321

312322
get npmRoot () {

tap-snapshots/test/lib/cli/exit-handler.js.test.cjs

+4-4
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ XX error code ECODE
2929
XX error ERR SUMMARY Unknown error
3030
XX error ERR DETAIL Unknown error
3131
XX verbose exit 1
32-
XX timing npm Completed in {TIME}ms
3332
XX verbose code 1
34-
XX error Timing info written to: {CWD}/cache/_logs/{DATE}-timing.json
33+
XX timing npm Completed in {TIME}ms
34+
XX info timing Timing info written to: {CWD}/cache/_logs/{DATE}-timing.json
3535
XX error A complete log of this run can be found in: {CWD}/cache/_logs/{DATE}-debug-0.log
3636
`
3737

@@ -59,8 +59,8 @@ error code ECODE
5959
error ERR SUMMARY Unknown error
6060
error ERR DETAIL Unknown error
6161
verbose exit 1
62-
timing npm Completed in {TIME}ms
6362
verbose code 1
64-
error Timing info written to: {CWD}/cache/_logs/{DATE}-timing.json
63+
timing npm Completed in {TIME}ms
64+
info timing Timing info written to: {CWD}/cache/_logs/{DATE}-timing.json
6565
error A complete log of this run can be found in: {CWD}/cache/_logs/{DATE}-debug-0.log
6666
`

tap-snapshots/test/lib/utils/exit-handler.js.test.cjs

-68
This file was deleted.

test/lib/cli/exit-handler.js

+4-13
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ t.test('timers fail to write', async (t) => {
382382

383383
await exitHandler(new Error())
384384

385-
t.match(logs.error[2], `error writing to the directory`)
385+
t.match(logs.warn[0], `timing could not write timing file: Error: err`)
386386
})
387387

388388
t.test('log files fail to write', async (t) => {
@@ -455,33 +455,25 @@ t.test('files from error message with error', async (t) => {
455455

456456
t.test('timing with no error', async (t) => {
457457
const { exitHandler, timingFile, npm, logs } = await mockExitHandler(t, {
458-
config: { timing: true, loglevel: 'info' },
458+
config: { timing: true, loglevel: 'silly' },
459459
})
460460

461461
await exitHandler()
462462
const timingFileData = await timingFile()
463463

464464
t.equal(process.exitCode, 0)
465465

466-
const msg = logs.info[1]
467-
t.match(msg, /A complete log of this run can be found in:/)
466+
const msg = logs.info.byTitle('timing')[0]
468467
t.match(msg, /Timing info written to:/)
469468

470-
t.match(
471-
timingFileData.timers,
472-
Object.keys(npm.finishedTimers).reduce((acc, k) => {
473-
acc[k] = Number
474-
return acc
475-
}, {})
476-
)
477-
t.strictSame(npm.unfinishedTimers, new Map())
478469
t.match(timingFileData, {
479470
metadata: {
480471
command: [],
481472
version: npm.version,
482473
logfiles: [String],
483474
},
484475
timers: {
476+
'npm:load': Number,
485477
npm: Number,
486478
},
487479
})
@@ -511,7 +503,6 @@ t.test('unfinished timers', async (t) => {
511503
const timingFileData = await timingFile()
512504

513505
t.equal(process.exitCode, 0)
514-
t.match(npm.unfinishedTimers, new Map([['foo', Number], ['bar', Number]]))
515506
t.match(timingFileData, {
516507
metadata: {
517508
command: [],

0 commit comments

Comments
 (0)