Newer
Older
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* The metrics module is designed to report interesting events to a file.
* Metrics files from different production servers can then be aggregated
* and post processed to get an idea of the degree and ways that browserid is
* being used by the world, to facilitate capacity planning and changes
* to the software.
*
* NOTE: This is *not* a generic logging mechanism for low level events
* interesting only to debug or assess the health of a server.
*
* DOUBLE NOTE: Sensitive information shouldn't be
* reported through this mechanism, and it isn't necesary to do so given
* we're after general trends, not specifics.
*/
const
winston = require("winston"),
configuration = require("./configuration"),
Lloyd Hilaiel
committed
path = require('path'),
Lloyd Hilaiel
committed
fs = require('fs'),
urlparse = require('urlparse');
// existsSync moved from path in 0.6.x to fs in 0.8.x
if (typeof fs.existsSync === 'function') {
var existsSync = fs.existsSync;
} else {
var existsSync = path.existsSync;
}
// go through the configuration and determine log location
// for now we only log to one place
// FIXME: separate logs depending on purpose?
Lloyd Hilaiel
committed
var log_path = path.join(configuration.get('var_path'), 'log');
Lloyd Hilaiel
committed
var LOGGER;
Lloyd Hilaiel
committed
// simple inline function for creation of dirs
function mkdir_p(p) {
if (!existsSync(p)) {
Lloyd Hilaiel
committed
mkdir_p(path.dirname(p));
fs.mkdirSync(p, "0755");
}
}
Lloyd Hilaiel
committed
function setupLogger() {
// don't create the logger if it already exists
if (LOGGER) return;
if (!log_path)
return console.log("no log path! Not logging!");
Lloyd Hilaiel
committed
else
mkdir_p(log_path);
var filename = path.join(log_path, configuration.get('process_type') + "-metrics.json");
Zachary Carter
committed
if (process.env.METRICS_LOG_FILE) {
filename = process.env.METRICS_LOG_FILE;
}
Lloyd Hilaiel
committed
LOGGER = new (winston.Logger)({
Austin King
committed
transports: [new (winston.transports.File)({filename: filename})],
timestamp: function () { return new Date().toISOString() },
});
}
// entry is an object that will get JSON'ified
Lloyd Hilaiel
committed
exports.report = function(type, entry) {
Lloyd Hilaiel
committed
setupLogger();
Lloyd Hilaiel
committed
// allow convenient reporting of atoms by converting
// atoms into objects
if (entry === null || typeof entry !== 'object') entry = { msg: entry };
if (entry.type) throw "reported metrics may not have a `type` property, that's reserved";
entry.type = type;
Lloyd Hilaiel
committed
if (entry.at) throw "reported metrics may not have an `at` property, that's reserved";
// if no logger, go to console (FIXME: do we really want to log to console?)
Lloyd Hilaiel
committed
LOGGER.info(JSON.stringify(entry));
// utility function to log a bunch of stuff at user entry point
Lloyd Hilaiel
committed
exports.userEntry = function(req) {
Lloyd Hilaiel
committed
var ipAddress = req.connection.remoteAddress;
if (req.headers['x-real-ip']) ipAddress = req.headers['x-real-ip'];
Lloyd Hilaiel
committed
var referer = null;
try {
// don't log more than we need
referer = urlparse(req.headers['referer']).originOnly().toString();
} catch(e) {
// ignore malformed referrers. just log null
}
Lloyd Hilaiel
committed
exports.report('signin', {
Lloyd Hilaiel
committed
browser: req.headers['user-agent'],
Lloyd Hilaiel
committed
rp: referer,
Lloyd Hilaiel
committed
// IP address (this probably needs to be replaced with the X-forwarded-for value
Lloyd Hilaiel
committed
ip: ipAddress