/** @module */
'use strict';
var coreutil = require('util');
var JSUtils = require('../utils/jsutils.js').JSUtils;
var Logger = require('./Logger.js').Logger;
var LogData = require('./LogData.js').LogData;
var Promise = require('../utils/promise.js');
/**
* @class
*/
function LocationData(wiki, title, meta, reqId, userAgent) {
this.wiki = wiki;
this.title = title;
this.oldId = (meta && meta.revision && meta.revision.revid) ?
meta.revision.revid : null;
this.reqId = reqId || null;
this.userAgent = userAgent || null;
}
LocationData.prototype.toString = function() {
const query = this.oldId ? "?oldid=" + this.oldId : "";
return `[${this.wiki}/${this.title}${query}]`;
};
/**
* @class
* @extends module:logger/LogData~LogData
*/
function ParsoidLogData(logType, logObject, locationData) {
this.locationData = locationData;
LogData.call(this, logType, logObject);
}
coreutil.inherits(ParsoidLogData, LogData);
/**
* @class
* @extends module:logger/Logger~Logger
* @param {MWParserEnvironment} env
*/
function ParsoidLogger(env) {
this.env = env;
Logger.apply(this, {});
}
coreutil.inherits(ParsoidLogger, Logger);
ParsoidLogger.prototype.getDefaultBackend = function() {
return logData => this._defaultBackend(logData);
};
ParsoidLogger.prototype.getDefaultTracerBackend = function() {
return logData => this._defaultTracerBackend(logData);
};
ParsoidLogger.prototype.registerLoggingBackends = function(defaultLogLevels, parsoidConfig, lintLogger) {
// Register a default backend based on default logTypes.
// DEFAULT: Combine all regexp-escaped default logTypes into a single regexp.
var fixLogType = function(logType) { return JSUtils.escapeRegExp(logType) + "(\\/|$)"; };
var defaultRE = new RegExp((defaultLogLevels || []).map(fixLogType).join("|"));
var loggerBackend;
if (typeof (parsoidConfig.loggerBackend) === 'function') {
loggerBackend = parsoidConfig.loggerBackend;
} else if (parsoidConfig.loggerBackend && parsoidConfig.loggerBackend.name) {
var parts = parsoidConfig.loggerBackend.name.split('/');
// use a leading colon to indicate a parsoid-local logger.
var ClassObj = require(parts.shift().replace(/^:/, './'));
parts.forEach(function(k) {
ClassObj = ClassObj[k];
});
loggerBackend = new ClassObj(parsoidConfig.loggerBackend.options)
.getLogger();
} else {
loggerBackend = this.getDefaultBackend();
}
this.registerBackend(defaultRE, loggerBackend);
// Register sampling
if (Array.isArray(parsoidConfig.loggerSampling)) {
parsoidConfig.loggerSampling.forEach(function(s) {
this.registerSampling(s[0], s[1]);
}, this);
}
// TRACE / DEBUG: Make trace / debug regexp with appropriate postfixes,
// depending on the command-line options passed in.
function buildTraceOrDebugFlag(parsoidFlags, logType) {
var escapedFlags = Array.from(parsoidFlags).map(JSUtils.escapeRegExp);
var combinedFlag = logType + "\/(" + escapedFlags.join("|") + ")(\\/|$)";
return new RegExp(combinedFlag);
}
// Register separate backend for tracing / debugging events.
// Tracing and debugging use the same backend for now.
var tracerBackend = (typeof (parsoidConfig.tracerBackend) === 'function') ?
parsoidConfig.tracerBackend : this.getDefaultTracerBackend();
if (parsoidConfig.traceFlags) {
this.registerBackend(buildTraceOrDebugFlag(parsoidConfig.traceFlags, "trace"),
tracerBackend);
}
if (parsoidConfig.debug) {
this.registerBackend(/^debug(\/.*)?/, tracerBackend);
} else if (parsoidConfig.debugFlags) {
this.registerBackend(buildTraceOrDebugFlag(parsoidConfig.debugFlags, "debug"),
tracerBackend);
}
if (lintLogger && parsoidConfig.linting) {
this.registerBackend(/^lint(\/.*)?/, logData => lintLogger.linterBackend(logData));
this.registerBackend(/^end(\/.*)/, logData => lintLogger.logLintOutput(logData));
}
};
ParsoidLogger.prototype._createLogData = function(logType, logObject) {
return new ParsoidLogData(logType, logObject, this.locationData());
};
// Set up a location message function in Logdata
// so all logging backends can output location message
ParsoidLogger.prototype.locationData = function() {
return new LocationData(
this.env.conf.wiki.iwp,
this.env.page.name,
this.env.page.meta,
this.env.reqId,
this.env.userAgent
);
};
ParsoidLogger.prototype._defaultBackend = Promise.async(function *(logData) { // eslint-disable-line require-yield
// The default logging backend provided by Logger.js is not useful to us.
// Parsoid needs to be able to emit page location to logs.
try {
console.warn("[%s]%s %s", logData.logType, logData.locationData.toString(), logData.fullMsg());
} catch (e) {
console.error("Error in ParsoidLogger._defaultBackend: %s", e);
}
});
var prettyLogTypeMap = {
"debug": "[DEBUG]",
"trace/pre-peg": "[pre-peg]",
"trace/peg": "[peg]",
"trace/pre": "[PRE]",
"debug/pre": "[PRE-DBG]",
"trace/p-wrap": "[P]",
"trace/html": "[HTML]",
"debug/html": "[HTML-DBG]",
"trace/sanitizer": "[SANITY]",
"trace/tsp": "[TSP]",
"trace/dsr": "[DSR]",
"trace/list": "[LIST]",
"trace/quote": "[QUOTE]",
"trace/sync:1": "[S1]",
"trace/async:2": "[A2]",
"trace/sync:3": "[S3]",
"trace/wts": "[WTS]",
"debug/wts/sep": "[SEP]",
"trace/selser": "[SELSER]",
"trace/domdiff": "[DOM-DIFF]",
"trace/wt-escape": "[wt-esc]",
"trace/batcher": "[batcher]",
"trace/apirequest": "[ApiRequest]",
};
ParsoidLogger.prototype._defaultTracerBackend = Promise.async(function *(logData) { // eslint-disable-line require-yield
try {
var msg = '';
var typeColumnWidth = 15;
var logType = logData.logType;
var firstArg = Array.isArray(logData.logObject) ? logData.logObject[0] : null;
// Assume first numeric arg is always the pipeline id
if (typeof firstArg === 'number') {
msg = firstArg + "-";
logData.logObject.shift();
}
// indent by number of slashes
var match = logType.match(/\//g);
var level = match ? match.length - 1 : 0;
var indent = ' '.repeat(level);
msg += indent;
var prettyLogType = prettyLogTypeMap[logType];
if (prettyLogType) {
msg += prettyLogType;
} else {
// XXX: could shorten or strip trace/ logType prefix in a pure
// trace logger
msg += logType;
// More space for these log types
typeColumnWidth = 30;
}
// Fixed-width type column so that the messages align
msg = msg.substr(0, typeColumnWidth);
msg += ' '.repeat(typeColumnWidth - msg.length);
msg += '| ' + indent + logData.msg();
if (msg) {
console.warn(msg);
}
} catch (e) {
console.error("Error in ParsoidLogger._defaultTracerBackend: " + e);
}
});
if (typeof module === "object") {
module.exports.ParsoidLogger = ParsoidLogger;
module.exports.ParsoidLogData = ParsoidLogData;
}