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

211 lines
5.3 KiB
JavaScript
Raw Normal View History

🎨 configurable logging with bunyan (#7431) - 🛠 add bunyan and prettyjson, remove morgan - ✨ add logging module - GhostLogger class that handles setup of bunyan - PrettyStream for stdout - ✨ config for logging - @TODO: testing level fatal? - ✨ log each request via GhostLogger (express middleware) - @TODO: add errors to output - 🔥 remove errors.updateActiveTheme - we can read the value from config - 🔥 remove 15 helper functions in core/server/errors/index.js - all these functions get replaced by modules: 1. logging 2. error middleware handling for html/json 3. error creation (which will be part of PR #7477) - ✨ add express error handler for html/json - one true error handler for express responses - contains still some TODO's, but they are not high priority for first implementation/integration - this middleware only takes responsibility of either rendering html responses or return json error responses - 🎨 use new express error handler in middleware/index - 404 and 500 handling - 🎨 return error instead of error message in permissions/index.js - the rule for error handling should be: if you call a unit, this unit should return a custom Ghost error - 🎨 wrap serve static module - rule: if you call a module/unit, you should always wrap this error - it's always the same rule - so the caller never has to worry about what comes back - it's always a clear error instance - in this case: we return our notfounderror if serve static does not find the resource - this avoid having checks everywhere - 🎨 replace usages of errors/index.js functions and adapt tests - use logging.error, logging.warn - make tests green - remove some usages of logging and throwing api errors -> because when a request is involved, logging happens automatically - 🐛 return errorDetails to Ghost-Admin - errorDetails is used for Theme error handling - 🎨 use 500er error for theme is missing error in theme-handler - 🎨 extend file rotation to 1w
2016-10-04 17:33:43 +02:00
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});
🎨 configurable logging with bunyan (#7431) - 🛠 add bunyan and prettyjson, remove morgan - ✨ add logging module - GhostLogger class that handles setup of bunyan - PrettyStream for stdout - ✨ config for logging - @TODO: testing level fatal? - ✨ log each request via GhostLogger (express middleware) - @TODO: add errors to output - 🔥 remove errors.updateActiveTheme - we can read the value from config - 🔥 remove 15 helper functions in core/server/errors/index.js - all these functions get replaced by modules: 1. logging 2. error middleware handling for html/json 3. error creation (which will be part of PR #7477) - ✨ add express error handler for html/json - one true error handler for express responses - contains still some TODO's, but they are not high priority for first implementation/integration - this middleware only takes responsibility of either rendering html responses or return json error responses - 🎨 use new express error handler in middleware/index - 404 and 500 handling - 🎨 return error instead of error message in permissions/index.js - the rule for error handling should be: if you call a unit, this unit should return a custom Ghost error - 🎨 wrap serve static module - rule: if you call a module/unit, you should always wrap this error - it's always the same rule - so the caller never has to worry about what comes back - it's always a clear error instance - in this case: we return our notfounderror if serve static does not find the resource - this avoid having checks everywhere - 🎨 replace usages of errors/index.js functions and adapt tests - use logging.error, logging.warn - make tests green - remove some usages of logging and throwing api errors -> because when a request is involved, logging happens automatically - 🐛 return errorDetails to Ghost-Admin - errorDetails is used for Theme error handling - 🎨 use 500er error for theme is missing error in theme-handler - 🎨 extend file rotation to 1w
2016-10-04 17:33:43 +02:00
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;