Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite #77

Merged
merged 6 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 32 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,47 +1,56 @@
# proc-log

Emits 'log' events on the process object which a log output listener can
consume and print to the terminal.
Emits events on the process object which a listener can consume and print to the terminal or log file.

This is used by various modules within the npm CLI stack in order to send
log events that can be consumed by a listener on the process object.
This is used by various modules within the npm CLI stack in order to send log events that can be consumed by a listener on the process object.

Currently emits `log` and `output` events.

## API

```js
const { log, output } = require('proc-log')
```

#### output
* `output.standard(...args)` calls `process.emit('output', 'standard', ...args)`
This is for general standard output. Consumers will typically show this on stdout (after optionally formatting or filtering it).
* `output.error(...args)` calls `process.emit('output', 'error', ...args)`
This is for general error output. Consumers will typically show this on stderr (after optionally formatting or filtering it).
* `output.buffer(...args)` calls `process.emit('output', 'buffer', ...args)`
This is for buffered output. Consumers will typically buffer this until they are ready to display.
* `output.LEVELS` an array of strings of all output method names

#### log
* `log.error(...args)` calls `process.emit('log', 'error', ...args)`
The highest log level. For printing extremely serious errors that
indicate something went wrong.
The highest log level. For printing extremely serious errors that indicate something went wrong.
* `log.warn(...args)` calls `process.emit('log', 'warn', ...args)`
A fairly high log level. Things that the user needs to be aware of, but
which won't necessarily cause improper functioning of the system.
A fairly high log level. Things that the user needs to be aware of, but which won't necessarily cause improper functioning of the system.
* `log.notice(...args)` calls `process.emit('log', 'notice', ...args)`
Notices which are important, but not necessarily dangerous or a cause for
excess concern.
Notices which are important, but not necessarily dangerous or a cause for excess concern.
* `log.info(...args)` calls `process.emit('log', 'info', ...args)`
Informative messages that may benefit the user, but aren't particularly
important.
Informative messages that may benefit the user, but aren't particularly important.
* `log.verbose(...args)` calls `process.emit('log', 'verbose', ...args)`
Noisy output that is more detail that most users will care about.
* `log.silly(...args)` calls `process.emit('log', 'silly', ...args)`
Extremely noisy excessive logging messages that are typically only useful
for debugging.
Extremely noisy excessive logging messages that are typically only useful for debugging.
* `log.http(...args)` calls `process.emit('log', 'http', ...args)`
Information about HTTP requests made and/or completed.
* `log.pause()` calls `process.emit('log', 'pause')` Used to tell
the consumer to stop printing messages.
* `log.timing(...args)` calls `process.emit('log', 'timing', ...args)`
Timing information.
* `log.pause()` calls `process.emit('log', 'pause')`
Used to tell the consumer to stop printing messages.
* `log.resume()` calls `process.emit('log', 'resume')`
Used to tell the consumer that it is ok to print messages again.
* `log.LEVELS` an array of strings of all log method names

## Examples

Every method calls `process.emit('log', level, ...otherArgs)` internally.
So in order to consume those events you need to do `process.on('log', fn)`.
Every `log` method calls `process.emit('log', level, ...otherArgs)` internally. So in order to consume those events you need to do `process.on('log', fn)`.

### Colorize based on level

Here's an example of how to consume `proc-log` events and colorize them
based on level:
Here's an example of how to consume `proc-log` log events and colorize them based on level:

```js
const chalk = require('chalk')
Expand All @@ -57,18 +66,13 @@ process.on('log', (level, ...args) => {

### Pause and resume

`pause` and `resume` are included so you have the ability to tell your consumer
that you want to pause or resume your display of logs. In the npm CLI we use
this to buffer all logs on init until we know the correct loglevel to display.
But we also setup a second handler that writes everything to a file even if
paused.
`log.pause` and `log.resume` are included so you have the ability to tell your consumer that you want to pause or resume your display of logs. In the npm CLI we use this to buffer all logs on init until we know the correct loglevel to display. But we also setup a second handler that writes everything to a file even if paused.

```js
let paused = true
const buffer = []

// this handler will buffer and replay logs only
// after `procLog.resume()` is called
// this handler will buffer and replay logs only after `procLog.resume()` is called
process.on('log', (level, ...args) => {
if (level === 'resume') {
buffer.forEach((item) => console.log(...item))
Expand All @@ -87,4 +91,4 @@ process.on('log', (level, ...args) => {
process.on('log', (...args) => {
fs.appendFileSync('debug.log', args.join(' '))
})
```
```
83 changes: 61 additions & 22 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,62 @@
// emits 'log' events on the process
const LEVELS = [
'notice',
'error',
'warn',
'info',
'verbose',
'http',
'silly',
'pause',
'resume',
]

const log = level => (...args) => process.emit('log', level, ...args)

const logger = {}
for (const level of LEVELS) {
logger[level] = log(level)
module.exports = {
output: {
LEVELS: [
'standard',
'error',
'buffer',
],
standard: function (...args) {
return process.emit('output', 'standard', ...args)
},
error: function (...args) {
return process.emit('output', 'error', ...args)
},
buffer: function (...args) {
return process.emit('output', 'buffer', ...args)
},
},
log: {
LEVELS: [
'notice',
'error',
'warn',
'info',
'verbose',
'http',
'silly',
'timing',
'pause',
'resume',
],
error: function (...args) {
return process.emit('log', 'error', ...args)
},
notice: function (...args) {
return process.emit('log', 'notice', ...args)
},
warn: function (...args) {
return process.emit('log', 'warn', ...args)
},
info: function (...args) {
return process.emit('log', 'info', ...args)
},
verbose: function (...args) {
return process.emit('log', 'verbose', ...args)
},
http: function (...args) {
return process.emit('log', 'http', ...args)
},
silly: function (...args) {
return process.emit('log', 'silly', ...args)
},
timing: function (...args) {
return process.emit('log', 'timing', ...args)
},
pause: function (...args) {
return process.emit('log', 'pause', ...args)
},
resume: function (...args) {
return process.emit('log', 'resume', ...args)
},
},
}

logger.LEVELS = LEVELS

module.exports = logger
11 changes: 10 additions & 1 deletion tap-snapshots/test/index.js.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Make sure to inspect the output below. Do not ignore changes!
*/
'use strict'
exports[`test/index.js TAP > log levels 1`] = `
exports[`test/index.js TAP log > log levels 1`] = `
Array [
"notice",
"error",
Expand All @@ -14,7 +14,16 @@ Array [
"verbose",
"http",
"silly",
"timing",
"pause",
"resume",
]
`

exports[`test/index.js TAP output > output levels 1`] = `
Array [
"standard",
"error",
"buffer",
]
`
38 changes: 27 additions & 11 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,32 @@
const t = require('tap')
const log = require('../')
const { LEVELS } = log

t.matchSnapshot(LEVELS, 'log levels')
for (const level of LEVELS) {
t.test(level, t => {
t.match(log[level], Function)
process.once('log', (actual, ...args) => {
t.equal(actual, level, 'emitted log with expected level')
t.same(args, [1, 2, 3], 'got expected args')
const procLog = require('../')
for (const method in procLog) {
t.test(method, t => {
const log = procLog[method]
const { LEVELS } = log
wraithgar marked this conversation as resolved.
Show resolved Hide resolved
t.matchSnapshot(LEVELS, `${method} levels`)
t.test(`all ${method}.LEVELS have a function in ${method}`, t => {
for (const level of LEVELS) {
t.test(level, t => {
t.match(log[level], Function)
process.once(method, (actual, ...args) => {
t.equal(actual, level, `emitted ${method} with expected level`)
t.same(args, [1, 'two', [3], { 4: 4 }], 'got expected args')
t.end()
})
log[level](1, 'two', [3], { 4: 4 })
})
}
t.end()
})
log[level](1, 2, 3)
t.test(`all ${method} functions are in ${method}.LEVELS`, t => {
t.plan(LEVELS.length)
for (const fn in log) {
if (fn !== 'LEVELS') {
t.ok(LEVELS.includes(fn), `${method}.${fn} is in ${method}.LEVELS`)
}
}
})
t.end()
})
}
Loading