* Attempt to hide sensitive information by default (e.g. 'password' fields) in log
* New logger configuration - change logging: level -> logging: rotatingFile: level for current functionality
This commit is contained in:
parent
a729944af7
commit
d4d64f925d
|
@ -292,7 +292,17 @@ function getDefaultConfig() {
|
||||||
},
|
},
|
||||||
|
|
||||||
logging : {
|
logging : {
|
||||||
level : 'debug'
|
level : 'debug',
|
||||||
|
|
||||||
|
rotatingFile : { // set to 'disabled' or false to disable
|
||||||
|
type : 'rotating-file',
|
||||||
|
fileName : 'enigma-bbs.log',
|
||||||
|
period : '1d',
|
||||||
|
count : 3,
|
||||||
|
level : 'debug',
|
||||||
|
}
|
||||||
|
|
||||||
|
// :TODO: syslog - https://github.com/mcavage/node-bunyan-syslog
|
||||||
},
|
},
|
||||||
|
|
||||||
debug : {
|
debug : {
|
||||||
|
|
105
core/logger.js
105
core/logger.js
|
@ -1,63 +1,74 @@
|
||||||
/* jslint node: true */
|
/* jslint node: true */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var bunyan = require('bunyan');
|
// deps
|
||||||
var paths = require('path');
|
const bunyan = require('bunyan');
|
||||||
var fs = require('fs');
|
const paths = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
const _ = require('lodash');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = class Log {
|
||||||
init : function() {
|
|
||||||
var Config = require('./config.js').config;
|
|
||||||
//var ringBufferLimit = miscUtil.valueWithDefault(config.logRingBufferLimit, 100);
|
|
||||||
var logPath = Config.paths.logs;
|
|
||||||
|
|
||||||
//
|
static init() {
|
||||||
// Create something a bit more friendly if the log directory cannot be used
|
const Config = require('./config.js').config;
|
||||||
//
|
const logPath = Config.paths.logs;
|
||||||
// :TODO: this seems cheesy...
|
|
||||||
var logPathError;
|
const err = this.checkLogPath(logPath);
|
||||||
try {
|
if(err) {
|
||||||
var pathStat = fs.statSync(logPath);
|
console.error(err.message); // eslint-disable-line no-console
|
||||||
if(!pathStat.isDirectory()) {
|
return process.exit();
|
||||||
logPathError = logPath + ' is not a directory!';
|
|
||||||
}
|
|
||||||
} catch(e) {
|
|
||||||
if('ENOENT' === e.code) {
|
|
||||||
logPathError = 'No such file or directory: ' + logPath;
|
|
||||||
} else {
|
|
||||||
logPathError = e.message;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(logPathError) {
|
const logStreams = [];
|
||||||
console.error(logPathError);
|
if(_.isObject(Config.logging.rotatingFile)) {
|
||||||
process.exit();
|
Config.logging.rotatingFile.path = paths.join(logPath, Config.logging.rotatingFile.fileName);
|
||||||
|
logStreams.push(Config.logging.rotatingFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
var logFile = paths.join(logPath, 'enigma-bbs.log');
|
const serializers = {
|
||||||
|
err : bunyan.stdSerializers.err, // handle 'err' fields with stack/etc.
|
||||||
|
};
|
||||||
|
|
||||||
// :TODO: make this configurable --
|
// try to remove sensitive info by default, e.g. 'password' fields
|
||||||
// user should be able to configure rotations, levels to file vs ringBuffer,
|
[ 'formData', 'formValue' ].forEach(keyName => {
|
||||||
// completely disable logging, etc.
|
serializers[keyName] = (fd) => Log.hideSensitive(fd);
|
||||||
|
});
|
||||||
|
|
||||||
this.log = bunyan.createLogger({
|
this.log = bunyan.createLogger({
|
||||||
name : 'ENiGMA½ BBS',
|
name : 'ENiGMA½ BBS',
|
||||||
streams : [
|
streams : logStreams,
|
||||||
{
|
serializers : serializers,
|
||||||
type : 'rotating-file',
|
|
||||||
path : logFile,
|
|
||||||
period : Config.logging.period || '1d',
|
|
||||||
count : 3,
|
|
||||||
level : Config.logging.level || 'debug',
|
|
||||||
}
|
|
||||||
/*,
|
|
||||||
{
|
|
||||||
type : 'raw',
|
|
||||||
stream : ringBuffer,
|
|
||||||
level : 'trace'
|
|
||||||
}*/
|
|
||||||
],
|
|
||||||
serializers: { err : bunyan.stdSerializers.err } // handle 'err' fields with stack/etc.
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static checkLogPath(logPath) {
|
||||||
|
try {
|
||||||
|
if(!fs.statSync(logPath).isDirectory()) {
|
||||||
|
return new Error(`${logPath} is not a directory`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} catch(e) {
|
||||||
|
if('ENOENT' === e.code) {
|
||||||
|
return new Error(`${logPath} does not exist`);
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static hideSensitive(obj) {
|
||||||
|
try {
|
||||||
|
//
|
||||||
|
// Use a regexp -- we don't know how nested fields we want to seek and destroy may be
|
||||||
|
//
|
||||||
|
return JSON.parse(
|
||||||
|
JSON.stringify(obj).replace(/"(password)"\s?:\s?"([^"]+)"/, (match, valueName) => {
|
||||||
|
return `"${valueName}":"********"`;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} catch(e) {
|
||||||
|
// be safe and return empty obj!
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue