electron-log
Version:
Just a simple logging module for your Electron application
215 lines (182 loc) • 5.47 kB
JavaScript
'use strict';
const scopeFactory = require('./scope');
const Buffering = require('./Buffering');
/**
* @property {Function} error
* @property {Function} warn
* @property {Function} info
* @property {Function} verbose
* @property {Function} debug
* @property {Function} silly
*/
class Logger {
static instances = {};
dependencies = {};
errorHandler = null;
eventLogger = null;
functions = {};
hooks = [];
isDev = false;
levels = null;
logId = null;
scope = null;
transports = {};
variables = {};
constructor({
allowUnknownLevel = false,
dependencies = {},
errorHandler,
eventLogger,
initializeFn,
isDev = false,
levels = ['error', 'warn', 'info', 'verbose', 'debug', 'silly'],
logId,
transportFactories = {},
variables,
} = {}) {
this.addLevel = this.addLevel.bind(this);
this.create = this.create.bind(this);
this.initialize = this.initialize.bind(this);
this.logData = this.logData.bind(this);
this.processMessage = this.processMessage.bind(this);
this.allowUnknownLevel = allowUnknownLevel;
this.buffering = new Buffering(this);
this.dependencies = dependencies;
this.initializeFn = initializeFn;
this.isDev = isDev;
this.levels = levels;
this.logId = logId;
this.scope = scopeFactory(this);
this.transportFactories = transportFactories;
this.variables = variables || {};
for (const name of this.levels) {
this.addLevel(name, false);
}
this.log = this.info;
this.functions.log = this.log;
this.errorHandler = errorHandler;
errorHandler?.setOptions({ ...dependencies, logFn: this.error });
this.eventLogger = eventLogger;
eventLogger?.setOptions({ ...dependencies, logger: this });
for (const [name, factory] of Object.entries(transportFactories)) {
this.transports[name] = factory(this, dependencies);
}
Logger.instances[logId] = this;
}
static getInstance({ logId }) {
return this.instances[logId] || this.instances.default;
}
addLevel(level, index = this.levels.length) {
if (index !== false) {
this.levels.splice(index, 0, level);
}
this[level] = (...args) => this.logData(args, { level });
this.functions[level] = this[level];
}
catchErrors(options) {
this.processMessage(
{
data: ['log.catchErrors is deprecated. Use log.errorHandler instead'],
level: 'warn',
},
{ transports: ['console'] },
);
return this.errorHandler.startCatching(options);
}
create(options) {
if (typeof options === 'string') {
options = { logId: options };
}
return new Logger({
dependencies: this.dependencies,
errorHandler: this.errorHandler,
initializeFn: this.initializeFn,
isDev: this.isDev,
transportFactories: this.transportFactories,
variables: { ...this.variables },
...options,
});
}
compareLevels(passLevel, checkLevel, levels = this.levels) {
const pass = levels.indexOf(passLevel);
const check = levels.indexOf(checkLevel);
if (check === -1 || pass === -1) {
return true;
}
return check <= pass;
}
initialize(options = {}) {
this.initializeFn({ logger: this, ...this.dependencies, ...options });
}
logData(data, options = {}) {
if (this.buffering.enabled) {
this.buffering.addMessage({ data, date: new Date(), ...options });
} else {
this.processMessage({ data, ...options });
}
}
processMessage(message, { transports = this.transports } = {}) {
if (message.cmd === 'errorHandler') {
this.errorHandler.handle(message.error, {
errorName: message.errorName,
processType: 'renderer',
showDialog: Boolean(message.showDialog),
});
return;
}
let level = message.level;
if (!this.allowUnknownLevel) {
level = this.levels.includes(message.level) ? message.level : 'info';
}
const normalizedMessage = {
date: new Date(),
logId: this.logId,
...message,
level,
variables: {
...this.variables,
...message.variables,
},
};
for (const [transName, transFn] of this.transportEntries(transports)) {
if (typeof transFn !== 'function' || transFn.level === false) {
continue;
}
if (!this.compareLevels(transFn.level, message.level)) {
continue;
}
try {
// eslint-disable-next-line arrow-body-style
const transformedMsg = this.hooks.reduce((msg, hook) => {
return msg ? hook(msg, transFn, transName) : msg;
}, normalizedMessage);
if (transformedMsg) {
transFn({ ...transformedMsg, data: [...transformedMsg.data] });
}
} catch (e) {
this.processInternalErrorFn(e);
}
}
}
processInternalErrorFn(_e) {
// Do nothing by default
}
transportEntries(transports = this.transports) {
const transportArray = Array.isArray(transports)
? transports
: Object.entries(transports);
return transportArray
.map((item) => {
switch (typeof item) {
case 'string':
return this.transports[item] ? [item, this.transports[item]] : null;
case 'function':
return [item.name, item];
default:
return Array.isArray(item) ? item : null;
}
})
.filter(Boolean);
}
}
module.exports = Logger;