Files
NodeBB/src/logger.js

227 lines
5.2 KiB
JavaScript
Raw Normal View History

2014-03-15 16:08:31 -04:00
'use strict';
2013-10-04 01:46:50 -04:00
/*
* Logger module: ability to dynamically turn on/off logging for http requests & socket.io events
*/
2017-02-17 20:20:42 -07:00
var fs = require('fs');
var path = require('path');
var winston = require('winston');
var util = require('util');
var file = require('./file');
var meta = require('./meta');
var morgan = require('morgan');
2013-10-04 01:46:50 -04:00
var opts = {
/*
* state used by Logger
*/
2017-02-18 01:27:46 -07:00
express: {
app: {},
set: 0,
ofn: null,
2013-10-04 01:46:50 -04:00
},
2017-02-18 01:27:46 -07:00
streams: {
log: { f: process.stdout },
2017-02-17 19:31:21 -07:00
},
2013-10-04 01:46:50 -04:00
};
2013-10-04 01:54:23 -04:00
/* -- Logger -- */
(function (Logger) {
2013-10-04 01:46:50 -04:00
Logger.init = function (app) {
2013-10-04 01:46:50 -04:00
opts.express.app = app;
/* Open log file stream & initialize express logging if meta.config.logger* variables are set */
Logger.setup();
2014-03-15 16:08:31 -04:00
};
2013-10-04 01:46:50 -04:00
Logger.setup = function () {
2013-10-04 01:46:50 -04:00
Logger.setup_one('loggerPath', meta.config.loggerPath);
2014-03-15 16:08:31 -04:00
};
2013-10-04 01:46:50 -04:00
Logger.setup_one = function (key, value) {
2013-10-04 01:46:50 -04:00
/*
* 1. Open the logger stream: stdout or file
* 2. Re-initialize the express logger hijack
*/
2014-03-15 16:08:31 -04:00
if (key === 'loggerPath') {
Logger.setup_one_log(value);
Logger.express_open();
2013-10-04 01:46:50 -04:00
}
2014-03-15 16:08:31 -04:00
};
2013-10-04 01:46:50 -04:00
Logger.setup_one_log = function (value) {
2013-10-04 01:54:23 -04:00
/*
* If logging is currently enabled, create a stream.
* Otherwise, close the current stream
*/
if (meta.config.loggerStatus > 0 || meta.config.loggerIOStatus) {
2013-10-04 01:46:50 -04:00
var stream = Logger.open(value);
if (stream) {
2014-03-15 16:08:31 -04:00
opts.streams.log.f = stream;
} else {
opts.streams.log.f = process.stdout;
}
2017-02-17 22:11:35 -07:00
} else {
2013-10-04 01:46:50 -04:00
Logger.close(opts.streams.log);
}
2014-03-15 16:08:31 -04:00
};
2013-10-04 01:46:50 -04:00
Logger.open = function (value) {
2013-10-04 01:46:50 -04:00
/* Open the streams to log to: either a path or stdout */
var stream;
if (value) {
if (file.existsSync(value)) {
2014-03-15 16:08:31 -04:00
var stats = fs.statSync(value);
if (stats) {
if (stats.isDirectory()) {
2014-01-02 15:59:25 -05:00
stream = fs.createWriteStream(path.join(value, 'nodebb.log'), {flags: 'a'});
} else {
stream = fs.createWriteStream(value, {flags: 'a'});
}
2014-01-02 14:53:27 -05:00
}
2014-01-02 15:59:25 -05:00
} else {
stream = fs.createWriteStream(value, {flags: 'a'});
}
if (stream) {
stream.on('error', function (err) {
2014-01-02 14:53:27 -05:00
winston.error(err.message);
});
2014-01-02 15:59:25 -05:00
}
2014-01-02 14:53:27 -05:00
} else {
2013-10-04 01:46:50 -04:00
stream = process.stdout;
2014-01-02 14:53:27 -05:00
}
2013-10-04 01:46:50 -04:00
return stream;
2014-03-15 16:08:31 -04:00
};
2013-10-04 01:46:50 -04:00
Logger.close = function (stream) {
if (stream.f !== process.stdout && stream.f) {
2014-03-15 16:08:31 -04:00
stream.end();
}
2013-10-04 01:46:50 -04:00
stream.f = null;
2014-03-15 16:08:31 -04:00
};
2013-10-04 01:46:50 -04:00
Logger.monitorConfig = function (socket, data) {
2013-10-04 01:46:50 -04:00
/*
* This monitor's when a user clicks "save" in the Logger section of the admin panel
*/
2017-02-18 01:31:47 -07:00
Logger.setup_one(data.key, data.value);
2013-10-04 01:46:50 -04:00
Logger.io_close(socket);
Logger.io(socket);
2014-03-15 16:08:31 -04:00
};
2013-10-04 01:46:50 -04:00
Logger.express_open = function () {
if (opts.express.set !== 1) {
2013-10-04 01:46:50 -04:00
opts.express.set = 1;
opts.express.app.use(Logger.expressLogger);
}
/*
* Always initialize "ofn" (original function) with the original logger function
*/
2017-02-18 01:27:46 -07:00
opts.express.ofn = morgan('combined', {stream: opts.streams.log.f});
2014-03-15 16:08:31 -04:00
};
2013-10-04 01:46:50 -04:00
2017-02-18 01:31:47 -07:00
Logger.expressLogger = function (req, res, next) {
2013-10-04 01:46:50 -04:00
/*
* The new express.logger
*
* This hijack allows us to turn logger on/off dynamically within express
*/
if (meta.config.loggerStatus > 0) {
2017-02-18 01:31:47 -07:00
return opts.express.ofn(req, res, next);
2014-01-02 14:53:27 -05:00
} else {
return next();
2013-10-04 01:46:50 -04:00
}
2014-03-15 16:08:31 -04:00
};
2013-10-04 01:46:50 -04:00
Logger.prepare_io_string = function (_type, _uid, _args) {
2013-10-04 01:46:50 -04:00
/*
* This prepares the output string for intercepted socket.io events
*
* The format is: io: <uid> <event> <args>
*/
try {
2016-10-13 11:42:29 +02:00
return 'io: ' + _uid + ' ' + _type + ' ' + util.inspect(Array.prototype.slice.call(_args)) + '\n';
} catch (err) {
2014-03-15 16:08:31 -04:00
winston.info("Logger.prepare_io_string: Failed", err);
2013-10-04 01:46:50 -04:00
return "error";
}
2014-03-15 16:08:31 -04:00
};
2013-10-04 01:46:50 -04:00
Logger.io_close = function (socket) {
2013-10-04 01:46:50 -04:00
/*
* Restore all hijacked sockets to their original emit/on functions
*/
2016-01-07 18:07:43 +02:00
if (!socket || !socket.io || !socket.io.sockets || !socket.io.sockets.sockets) {
return;
}
var clients = socket.io.sockets.sockets;
for (var sid in clients) {
if (clients.hasOwnProperty(sid)) {
var client = clients[sid];
if (client.oEmit && client.oEmit !== client.emit) {
2016-01-07 18:07:43 +02:00
client.emit = client.oEmit;
}
2013-10-04 01:46:50 -04:00
if (client.$oEmit && client.$oEmit !== client.$emit) {
2016-01-07 18:07:43 +02:00
client.$emit = client.$oEmit;
}
2014-01-02 14:53:27 -05:00
}
2016-01-07 18:07:43 +02:00
}
2014-03-15 16:08:31 -04:00
};
2013-10-04 01:46:50 -04:00
Logger.io = function (socket) {
2013-10-04 01:54:23 -04:00
/*
* Go through all of the currently established sockets & hook their .emit/.on
*/
2015-09-25 16:16:07 -04:00
2016-01-07 18:07:43 +02:00
if (!socket || !socket.io || !socket.io.sockets || !socket.io.sockets.sockets) {
2013-10-04 01:46:50 -04:00
return;
}
2015-09-25 16:16:07 -04:00
var clients = socket.io.sockets.sockets;
for (var sid in clients) {
2016-01-07 18:07:43 +02:00
if (clients.hasOwnProperty(sid)) {
Logger.io_one(clients[sid], clients[sid].uid);
}
}
2014-03-15 16:08:31 -04:00
};
Logger.io_one = function (socket, uid) {
2013-10-04 01:46:50 -04:00
/*
* This function replaces a socket's .emit/.on functions in order to intercept events
*/
2015-09-25 16:16:07 -04:00
function override(method, name, errorMsg) {
return function () {
if (opts.streams.log.f) {
2015-09-25 16:16:07 -04:00
opts.streams.log.f.write(Logger.prepare_io_string(name, uid, arguments));
2014-03-15 16:08:31 -04:00
}
2015-09-25 16:16:07 -04:00
try {
method.apply(socket, arguments);
} catch (err) {
2015-09-25 16:16:07 -04:00
winston.info(errorMsg, err);
}
};
}
2014-01-02 15:59:25 -05:00
2015-09-25 16:16:07 -04:00
if (socket && meta.config.loggerIOStatus > 0) {
// courtesy of: http://stackoverflow.com/a/9674248
socket.oEmit = socket.emit;
var emit = socket.emit;
socket.emit = override(emit, 'emit', 'Logger.io_one: emit.apply: Failed');
2013-10-04 01:46:50 -04:00
2015-09-25 16:16:07 -04:00
socket.$oEmit = socket.$emit;
var $emit = socket.$emit;
socket.$emit = override($emit, 'on', 'Logger.io_one: $emit.apply: Failed');
2013-10-04 01:46:50 -04:00
}
2014-03-15 16:08:31 -04:00
};
2013-10-04 01:46:50 -04:00
}(exports));