mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-12-16 21:56:25 -05:00
feat: exposed rotating-file log for json logging (#948)
This both allows for logger type 'rotating-file' and passing of other options from the config "option" example: {type: rotating-file, format: json, path: /path/to/log.jsonl, level: http, options: {period: 1d}}
This commit is contained in:
parent
d0798c491f
commit
5ca0ca5228
5 changed files with 84 additions and 45 deletions
|
@ -126,7 +126,8 @@ packages:
|
|||
#
|
||||
# parameters for file: name is filename
|
||||
# {type: 'file', path: 'verdaccio.log', level: 'debug'},
|
||||
#
|
||||
# Rotating log stream. Options are passed directly to bunyan. See: https://github.com/trentm/node-bunyan#stream-type-rotating-file
|
||||
# {type: rotating-file, format: json, path: /path/to/log.jsonl, level: http, options: {period: 1d}}
|
||||
# parameters for stdout and stderr: format: json | pretty | pretty-timestamped
|
||||
# {type: 'stdout', format: 'pretty', level: 'debug'},
|
||||
logs:
|
||||
|
|
|
@ -11,9 +11,12 @@ logs:
|
|||
- {type: stdout, format: pretty, level: http}
|
||||
# file output
|
||||
- {type: file, path: verdaccio.log, level: info}
|
||||
# Rotating log stream. Options are passed directly to bunyan. See: https://github.com/trentm/node-bunyan#stream-type-rotating-file
|
||||
- {type: rotating-file, format: json, path: /path/to/log.jsonl, level: http, options: {period: 1d}}
|
||||
```
|
||||
|
||||
Use `SIGUSR2` to notify the application, the log-file was rotated and it needs to reopen it.
|
||||
Note: Rotating log stream is not supported in cluster mode. [See here](https://github.com/trentm/node-bunyan#stream-type-rotating-file)
|
||||
|
||||
### Configuration
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
"mime": "2.3.1",
|
||||
"minimatch": "3.0.4",
|
||||
"mkdirp": "0.5.1",
|
||||
"mv": "2.1.1",
|
||||
"pkginfo": "0.4.1",
|
||||
"request": "2.87.0",
|
||||
"semver": "5.5.0",
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
const cluster = require('cluster');
|
||||
const Logger = require('bunyan');
|
||||
const Error = require('http-errors');
|
||||
const Stream = require('stream');
|
||||
const chalk = require('chalk');
|
||||
const Utils = require('./utils');
|
||||
const pkgJSON = require('../../package.json');
|
||||
const _ = require('lodash');
|
||||
|
||||
/**
|
||||
* Match the level based on buyan severity scale
|
||||
|
@ -22,6 +24,16 @@ function getlvl(x) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A RotatingFileStream that modifes the message first
|
||||
*/
|
||||
class VerdaccioRotatingFileStream extends Logger.RotatingFileStream { // We depend on mv so that this is there
|
||||
write(obj) {
|
||||
const msg = fillInMsgTemplate(obj.msg, obj, false);
|
||||
super.write(JSON.stringify({...obj, msg}, Logger.safeCycles()) + '\n');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the Buyan logger
|
||||
* @param {*} logs list of log configuration
|
||||
|
@ -33,55 +45,77 @@ function setup(logs) {
|
|||
}
|
||||
|
||||
logs.forEach(function(target) {
|
||||
let level = target.level || 35;
|
||||
if (level === 'http') {
|
||||
level = 35;
|
||||
}
|
||||
|
||||
// create a stream for each log configuration
|
||||
const stream = new Stream();
|
||||
stream.writable = true;
|
||||
if (target.type === 'rotating-file') {
|
||||
if (target.format !== 'json') {
|
||||
throw new Error('Rotating file streams only work with JSON!');
|
||||
}
|
||||
if (cluster.isWorker) {
|
||||
// https://github.com/trentm/node-bunyan#stream-type-rotating-file
|
||||
throw new Error('Cluster mode is not supported for rotating-file!');
|
||||
}
|
||||
|
||||
let dest;
|
||||
let destIsTTY = false;
|
||||
const prettyPrint = (obj) => print(obj.level, obj.msg, obj, destIsTTY) + '\n';
|
||||
const prettyTimestampedPrint = (obj) => obj.time.toISOString() + print(obj.level, obj.msg, obj, destIsTTY) + '\n';
|
||||
const jsonPrint = (obj) => {
|
||||
const msg = fillInMsgTemplate(obj.msg, obj, destIsTTY);
|
||||
return JSON.stringify({...obj, msg}, Logger.safeCycles()) + '\n';
|
||||
};
|
||||
const stream = new VerdaccioRotatingFileStream(
|
||||
_.merge({},
|
||||
// Defaults can be found here: https://github.com/trentm/node-bunyan#stream-type-rotating-file
|
||||
target.options || {},
|
||||
{path: target.path, level})
|
||||
);
|
||||
|
||||
if (target.type === 'file') {
|
||||
// destination stream
|
||||
dest = require('fs').createWriteStream(target.path, {flags: 'a', encoding: 'utf8'});
|
||||
dest.on('error', function(err) {
|
||||
Logger.emit('error', err);
|
||||
streams.push(
|
||||
{
|
||||
type: 'raw',
|
||||
level,
|
||||
stream,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
const stream = new Stream();
|
||||
stream.writable = true;
|
||||
|
||||
let destination;
|
||||
let destinationIsTTY = false;
|
||||
if (target.type === 'file') {
|
||||
// destination stream
|
||||
destination = require('fs').createWriteStream(target.path, {flags: 'a', encoding: 'utf8'});
|
||||
destination.on('error', function(err) {
|
||||
stream.emit('error', err);
|
||||
});
|
||||
} else if (target.type === 'stdout' || target.type === 'stderr') {
|
||||
destination = target.type === 'stdout' ? process.stdout : process.stderr;
|
||||
destinationIsTTY = destination.isTTY;
|
||||
} else {
|
||||
throw Error('wrong target type for a log');
|
||||
}
|
||||
|
||||
if (target.format === 'pretty') {
|
||||
// making fake stream for prettypritting
|
||||
stream.write = (obj) => {
|
||||
destination.write(`${print(obj.level, obj.msg, obj, destinationIsTTY)}\n`);
|
||||
};
|
||||
} else if (target.format === 'pretty-timestamped') {
|
||||
// making fake stream for pretty pritting
|
||||
stream.write = (obj) => {
|
||||
destination.write(`${obj.time.toISOString()}${print(obj.level, obj.msg, obj, destinationIsTTY)}\n`);
|
||||
};
|
||||
} else {
|
||||
stream.write = (obj) => {
|
||||
const msg = fillInMsgTemplate(obj.msg, obj, destinationIsTTY);
|
||||
destination.write(`${JSON.stringify({...obj, msg}, Logger.safeCycles())}\n`);
|
||||
};
|
||||
}
|
||||
|
||||
streams.push({
|
||||
type: 'raw',
|
||||
level,
|
||||
stream: stream,
|
||||
});
|
||||
} else if (target.type === 'stdout' || target.type === 'stderr') {
|
||||
dest = target.type === 'stdout' ? process.stdout : process.stderr;
|
||||
destIsTTY = dest.isTTY;
|
||||
} else {
|
||||
throw Error('wrong target type for a log');
|
||||
}
|
||||
|
||||
if (target.format === 'pretty') {
|
||||
// making fake stream for prettypritting
|
||||
stream.write = (obj) => {
|
||||
dest.write(prettyPrint(obj));
|
||||
};
|
||||
} else if (target.format === 'pretty-timestamped') {
|
||||
// making fake stream for prettypritting
|
||||
stream.write = (obj) => {
|
||||
dest.write(prettyTimestampedPrint(obj));
|
||||
};
|
||||
} else {
|
||||
stream.write = (obj) => {
|
||||
dest.write(jsonPrint(obj));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
if (target.level === 'http') target.level = 35;
|
||||
streams.push({
|
||||
type: 'raw',
|
||||
level: target.level || 35,
|
||||
stream: stream,
|
||||
});
|
||||
});
|
||||
|
||||
// buyan default configuration
|
||||
|
|
BIN
yarn.lock
BIN
yarn.lock
Binary file not shown.
Loading…
Reference in a new issue