0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-24 23:48:13 -05:00
ghost/core/server/logging/GhostLogger.js
Hannah Wolfe d979bd442e 🎨 Add support for short one-line log format (#7523)
refs #7116

- The long format logs were making it hard to see the debug statements
- Seeing headers for every asset is a bit much
- "short" format doesn't output bodyPretty
- This needs love as there's no reason to calculate bodyPretty if we aren't using it
- The default output should be discussed
- req.url doesn't include the full path when apps are mounted
- Use mode instead of format & pass config correctly
2016-10-10 16:17:16 +02:00

210 lines
5.3 KiB
JavaScript

var bunyan = require('bunyan'),
_ = require('lodash'),
GhostPrettyStream = require('./PrettyStream');
function GhostLogger(options) {
this.env = options.env;
this.transports = options.transports || ['stdout'];
this.level = options.level || 'info';
this.mode = options.mode || 'short';
this.path = options.path || 'ghost.log';
this.rotation = options.rotation || false;
this.loggers = {};
this.setSerializers();
this.setLoggers();
this.setStreams();
}
// @TODO: add correlation identifier
// @TODO: res.on('finish') has no access to the response body
GhostLogger.prototype.setSerializers = function setSerializers() {
var self = this;
this.serializers = {
req: function (req) {
return {
url: req.url,
method: req.method,
originalUrl: req.originalUrl,
params: req.params,
headers: self.removeSensitiveData(req.headers),
body: self.removeSensitiveData(req.body),
query: self.removeSensitiveData(req.query)
};
},
res: function (res) {
return {
_headers: self.removeSensitiveData(res._headers),
statusCode: res.statusCode
};
},
err: function (err) {
return {
name: err.errorType,
statusCode: err.statusCode,
level: err.level,
message: err.message,
context: err.context,
help: err.help,
stack: err.stack,
hideStack: err.hideStack
};
}
};
};
GhostLogger.prototype.setLoggers = function setLoggers() {
var self = this;
this.log = {
info: function (options) {
var req = options.req,
res = options.res;
_.each(self.loggers, function (logger) {
logger.log.info({
req: req,
res: res
});
});
},
debug: function (options) {
var req = options.req,
res = options.res;
_.each(self.loggers, function (logger) {
logger.log.debug({
req: req,
res: res
});
});
},
error: function (options) {
var req = options.req,
res = options.res,
err = options.err;
_.each(self.loggers, function (logger) {
logger.log.error({
req: req,
res: res,
err: err
});
});
}
};
};
GhostLogger.prototype.setStreams = function setStreams() {
var self = this,
streams = [],
prettyStdOut;
_.each(self.transports, function (transport) {
if (transport === 'file') {
streams.push({
name: 'file',
stream: {
path: self.path,
level: self.level
}
});
}
if (transport === 'stdout') {
prettyStdOut = new GhostPrettyStream({mode: self.mode});
prettyStdOut.pipe(process.stdout);
streams.push({
name: 'stdout',
stream: {
type: 'raw',
stream: prettyStdOut,
level: self.level
}
});
}
});
if (self.rotation) {
streams.push({
name: 'rotation',
stream: {
type: 'rotating-file',
path: self.path,
period: '1w',
count: 3,
level: self.level
}
});
}
// the env defines which streams are available
_.each(streams, function (stream) {
self.loggers[stream.name] = {
name: stream.name,
log: bunyan.createLogger({
name: 'Log',
streams: [stream.stream],
serializers: self.serializers
})
};
});
};
GhostLogger.prototype.removeSensitiveData = function removeSensitiveData(obj) {
var newObj = {};
_.each(obj, function (value, key) {
if (!key.match(/pin|password|authorization|cookie/gi)) {
newObj[key] = value;
}
});
return newObj;
};
GhostLogger.prototype.info = function info() {
var print = '';
_.each(arguments, function (value) {
print += value;
print += ' ';
});
this.loggers.stdout.log.info(print);
};
GhostLogger.prototype.warn = function warn() {
var print = '';
_.each(arguments, function (value) {
print += value;
print += ' ';
});
this.loggers.stdout.log.warn(print);
};
GhostLogger.prototype.debug = function debug(options) {
this.loggers.stdout.log.debug(options);
};
GhostLogger.prototype.error = function error(err) {
this.log.error({err: err});
};
GhostLogger.prototype.request = function request(options) {
var req = options.req,
res = options.res,
err = options.err;
if (err) {
this.log.error({req: req, res: res, err: err});
} else {
this.log.info({req: req, res: res});
}
};
module.exports = GhostLogger;