added unit testing, and started implementing unit tests...phew

This commit is contained in:
Josh Burman
2019-03-12 22:28:02 -04:00
parent 74aad4a957
commit e8c2539f1b
3489 changed files with 464813 additions and 88 deletions

181
node_modules/winston/lib/winston.js generated vendored Normal file
View File

@ -0,0 +1,181 @@
/**
* winston.js: Top-level include defining Winston.
*
* (C) 2010 Charlie Robbins
* MIT LICENCE
*/
'use strict';
const logform = require('logform');
const { warn } = require('./winston/common');
/**
* Setup to expose.
* @type {Object}
*/
const winston = exports;
/**
* Expose version. Use `require` method for `webpack` support.
* @type {string}
*/
winston.version = require('../package.json').version;
/**
* Include transports defined by default by winston
* @type {Array}
*/
winston.transports = require('./winston/transports');
/**
* Expose utility methods
* @type {Object}
*/
winston.config = require('./winston/config');
/**
* Hoist format-related functionality from logform.
* @type {Object}
*/
winston.addColors = logform.levels;
/**
* Hoist format-related functionality from logform.
* @type {Object}
*/
winston.format = logform.format;
/**
* Expose core Logging-related prototypes.
* @type {function}
*/
winston.createLogger = require('./winston/create-logger');
/**
* Expose core Logging-related prototypes.
* @type {Object}
*/
winston.ExceptionHandler = require('./winston/exception-handler');
/**
* Expose core Logging-related prototypes.
* @type {Object}
*/
winston.RejectionHandler = require('./winston/rejection-handler');
/**
* Expose core Logging-related prototypes.
* @type {Container}
*/
winston.Container = require('./winston/container');
/**
* Expose core Logging-related prototypes.
* @type {Object}
*/
winston.Transport = require('winston-transport');
/**
* We create and expose a default `Container` to `winston.loggers` so that the
* programmer may manage multiple `winston.Logger` instances without any
* additional overhead.
* @example
* // some-file1.js
* const logger = require('winston').loggers.get('something');
*
* // some-file2.js
* const logger = require('winston').loggers.get('something');
*/
winston.loggers = new winston.Container();
/**
* We create and expose a 'defaultLogger' so that the programmer may do the
* following without the need to create an instance of winston.Logger directly:
* @example
* const winston = require('winston');
* winston.log('info', 'some message');
* winston.error('some error');
*/
const defaultLogger = winston.createLogger();
// Pass through the target methods onto `winston.
Object.keys(winston.config.npm.levels)
.concat([
'log',
'query',
'stream',
'add',
'remove',
'clear',
'profile',
'startTimer',
'handleExceptions',
'unhandleExceptions',
'handleRejections',
'unhandleRejections',
'configure'
])
.forEach(
method => (winston[method] = (...args) => defaultLogger[method](...args))
);
/**
* Define getter / setter for the default logger level which need to be exposed
* by winston.
* @type {string}
*/
Object.defineProperty(winston, 'level', {
get() {
return defaultLogger.level;
},
set(val) {
defaultLogger.level = val;
}
});
/**
* Define getter for `exceptions` which replaces `handleExceptions` and
* `unhandleExceptions`.
* @type {Object}
*/
Object.defineProperty(winston, 'exceptions', {
get() {
return defaultLogger.exceptions;
}
});
/**
* Define getters / setters for appropriate properties of the default logger
* which need to be exposed by winston.
* @type {Logger}
*/
['exitOnError'].forEach(prop => {
Object.defineProperty(winston, prop, {
get() {
return defaultLogger[prop];
},
set(val) {
defaultLogger[prop] = val;
}
});
});
/**
* The default transports and exceptionHandlers for the default winston logger.
* @type {Object}
*/
Object.defineProperty(winston, 'default', {
get() {
return {
exceptionHandlers: defaultLogger.exceptionHandlers,
rejectionHandlers: defaultLogger.rejectionHandlers,
transports: defaultLogger.transports
};
}
});
// Have friendlier breakage notices for properties that were exposed by default
// on winston < 3.0.
warn.deprecated(winston, 'setLevels');
warn.forFunctions(winston, 'useFormat', ['cli']);
warn.forProperties(winston, 'useFormat', ['padLevels', 'stripColors']);
warn.forFunctions(winston, 'deprecated', [
'addRewriter',
'addFilter',
'clone',
'extend'
]);
warn.forProperties(winston, 'deprecated', ['emitErrs', 'levelLength']);
// Throw a useful error when users attempt to run `new winston.Logger`.
warn.moved(winston, 'createLogger', 'Logger');

61
node_modules/winston/lib/winston/common.js generated vendored Normal file
View File

@ -0,0 +1,61 @@
/**
* common.js: Internal helper and utility functions for winston.
*
* (C) 2010 Charlie Robbins
* MIT LICENCE
*/
'use strict';
const { format } = require('util');
/**
* Set of simple deprecation notices and a way to expose them for a set of
* properties.
* @type {Object}
* @private
*/
exports.warn = {
deprecated(prop) {
return () => {
throw new Error(format('{ %s } was removed in winston@3.0.0.', prop));
};
},
useFormat(prop) {
return () => {
throw new Error([
format('{ %s } was removed in winston@3.0.0.', prop),
'Use a custom winston.format = winston.format(function) instead.'
].join('\n'));
};
},
forFunctions(obj, type, props) {
props.forEach(prop => {
obj[prop] = exports.warn[type](prop);
});
},
moved(obj, movedTo, prop) {
function movedNotice() {
return () => {
throw new Error([
format('winston.%s was moved in winston@3.0.0.', prop),
format('Use a winston.%s instead.', movedTo)
].join('\n'));
};
}
Object.defineProperty(obj, prop, {
get: movedNotice,
set: movedNotice
});
},
forProperties(obj, type, props) {
props.forEach(prop => {
const notice = exports.warn[type](prop);
Object.defineProperty(obj, prop, {
get: notice,
set: notice
});
});
}
};

98
node_modules/winston/lib/winston/config/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,98 @@
// Type definitions for winston 3.0
// Project: https://github.com/winstonjs/winston
/// <reference types="node" />
declare namespace winston {
interface AbstractConfigSetLevels {
[key: string]: number;
}
interface AbstractConfigSetColors {
[key: string]: string | string[];
}
interface AbstractConfigSet {
levels: AbstractConfigSetLevels;
colors: AbstractConfigSetColors;
}
interface CliConfigSetLevels extends AbstractConfigSetLevels {
error: number;
warn: number;
help: number;
data: number;
info: number;
debug: number;
prompt: number;
verbose: number;
input: number;
silly: number;
}
interface CliConfigSetColors extends AbstractConfigSetColors {
error: string | string[];
warn: string | string[];
help: string | string[];
data: string | string[];
info: string | string[];
debug: string | string[];
prompt: string | string[];
verbose: string | string[];
input: string | string[];
silly: string | string[];
}
interface NpmConfigSetLevels extends AbstractConfigSetLevels {
error: number;
warn: number;
info: number;
http: number;
verbose: number;
debug: number;
silly: number;
}
interface NpmConfigSetColors extends AbstractConfigSetColors {
error: string | string[];
warn: string | string[];
info: string | string[];
verbose: string | string[];
debug: string | string[];
silly: string | string[];
}
interface SyslogConfigSetLevels extends AbstractConfigSetLevels {
emerg: number;
alert: number;
crit: number;
error: number;
warning: number;
notice: number;
info: number;
debug: number;
}
interface SyslogConfigSetColors extends AbstractConfigSetColors {
emerg: string | string[];
alert: string | string[];
crit: string | string[];
error: string | string[];
warning: string | string[];
notice: string | string[];
info: string | string[];
debug: string | string[];
}
interface Config {
allColors: AbstractConfigSetColors;
cli: { levels: CliConfigSetLevels, colors: CliConfigSetColors };
npm: { levels: NpmConfigSetLevels, colors: NpmConfigSetColors };
syslog: { levels: SyslogConfigSetLevels, colors: SyslogConfigSetColors };
addColors(colors: AbstractConfigSetColors): void;
}
}
declare const winston: winston.Config;
export = winston;

35
node_modules/winston/lib/winston/config/index.js generated vendored Normal file
View File

@ -0,0 +1,35 @@
/**
* index.js: Default settings for all levels that winston knows about.
*
* (C) 2010 Charlie Robbins
* MIT LICENCE
*/
'use strict';
const logform = require('logform');
const { configs } = require('triple-beam');
/**
* Export config set for the CLI.
* @type {Object}
*/
exports.cli = logform.levels(configs.cli);
/**
* Export config set for npm.
* @type {Object}
*/
exports.npm = logform.levels(configs.npm);
/**
* Export config set for the syslog.
* @type {Object}
*/
exports.syslog = logform.levels(configs.syslog);
/**
* Hoist addColors from logform where it was refactored into in winston@3.
* @type {Object}
*/
exports.addColors = logform.levels;

114
node_modules/winston/lib/winston/container.js generated vendored Normal file
View File

@ -0,0 +1,114 @@
/**
* container.js: Inversion of control container for winston logger instances.
*
* (C) 2010 Charlie Robbins
* MIT LICENCE
*/
'use strict';
const createLogger = require('./create-logger');
/**
* Inversion of control container for winston logger instances.
* @type {Container}
*/
module.exports = class Container {
/**
* Constructor function for the Container object responsible for managing a
* set of `winston.Logger` instances based on string ids.
* @param {!Object} [options={}] - Default pass-thru options for Loggers.
*/
constructor(options = {}) {
this.loggers = new Map();
this.options = options;
}
/**
* Retreives a `winston.Logger` instance for the specified `id`. If an
* instance does not exist, one is created.
* @param {!string} id - The id of the Logger to get.
* @param {?Object} [options] - Options for the Logger instance.
* @returns {Logger} - A configured Logger instance with a specified id.
*/
add(id, options) {
if (!this.loggers.has(id)) {
// Remark: Simple shallow clone for configuration options in case we pass
// in instantiated protoypal objects
options = Object.assign({}, options || this.options);
const existing = options.transports || this.options.transports;
// Remark: Make sure if we have an array of transports we slice it to
// make copies of those references.
options.transports = existing ? existing.slice() : [];
const logger = createLogger(options);
logger.on('close', () => this._delete(id));
this.loggers.set(id, logger);
}
return this.loggers.get(id);
}
/**
* Retreives a `winston.Logger` instance for the specified `id`. If
* an instance does not exist, one is created.
* @param {!string} id - The id of the Logger to get.
* @param {?Object} [options] - Options for the Logger instance.
* @returns {Logger} - A configured Logger instance with a specified id.
*/
get(id, options) {
return this.add(id, options);
}
/**
* Check if the container has a logger with the id.
* @param {?string} id - The id of the Logger instance to find.
* @returns {boolean} - Boolean value indicating if this instance has a
* logger with the specified `id`.
*/
has(id) {
return !!this.loggers.has(id);
}
/**
* Closes a `Logger` instance with the specified `id` if it exists.
* If no `id` is supplied then all Loggers are closed.
* @param {?string} id - The id of the Logger instance to close.
* @returns {undefined}
*/
close(id) {
if (id) {
return this._removeLogger(id);
}
this.loggers.forEach((val, key) => this._removeLogger(key));
}
/**
* Remove a logger based on the id.
* @param {!string} id - The id of the logger to remove.
* @returns {undefined}
* @private
*/
_removeLogger(id) {
if (!this.loggers.has(id)) {
return;
}
const logger = this.loggers.get(id);
logger.close();
this._delete(id);
}
/**
* Deletes a `Logger` instance with the specified `id`.
* @param {!string} id - The id of the Logger instance to delete from
* container.
* @returns {undefined}
* @private
*/
_delete(id) {
this.loggers.delete(id);
}
};

104
node_modules/winston/lib/winston/create-logger.js generated vendored Normal file
View File

@ -0,0 +1,104 @@
/**
* create-logger.js: Logger factory for winston logger instances.
*
* (C) 2010 Charlie Robbins
* MIT LICENCE
*/
'use strict';
const { LEVEL } = require('triple-beam');
const config = require('./config');
const Logger = require('./logger');
const debug = require('diagnostics')('winston:create-logger');
function isLevelEnabledFunctionName(level) {
return 'is' + level.charAt(0).toUpperCase() + level.slice(1) + 'Enabled';
}
/**
* Create a new instance of a winston Logger. Creates a new
* prototype for each instance.
* @param {!Object} opts - Options for the created logger.
* @returns {Logger} - A newly created logger instance.
*/
module.exports = function (opts = {}) {
//
// Default levels: npm
//
opts.levels = opts.levels || config.npm.levels;
/**
* DerivedLogger to attach the logs level methods.
* @type {DerivedLogger}
* @extends {Logger}
*/
class DerivedLogger extends Logger {
/**
* Create a new class derived logger for which the levels can be attached to
* the prototype of. This is a V8 optimization that is well know to increase
* performance of prototype functions.
* @param {!Object} options - Options for the created logger.
*/
constructor(options) {
super(options);
}
}
const logger = new DerivedLogger(opts);
//
// Create the log level methods for the derived logger.
//
Object.keys(opts.levels).forEach(function (level) {
debug('Define prototype method for "%s"', level);
if (level === 'log') {
// eslint-disable-next-line no-console
console.warn('Level "log" not defined: conflicts with the method "log". Use a different level name.');
return;
}
//
// Define prototype methods for each log level e.g.:
// logger.log('info', msg) implies these methods are defined:
// - logger.info(msg)
// - logger.isInfoEnabled()
//
// Remark: to support logger.child this **MUST** be a function
// so it'll always be called on the instance instead of a fixed
// place in the prototype chain.
//
DerivedLogger.prototype[level] = function (...args) {
// Prefer any instance scope, but default to "root" logger
const self = this || logger;
// Optimize the hot-path which is the single object.
if (args.length === 1) {
const [msg] = args;
const info = msg && msg.message && msg || { message: msg };
info.level = info[LEVEL] = level;
self._addDefaultMeta(info);
self.write(info);
return (this || logger);
}
// When provided nothing assume the empty string
if (args.length === 0) {
self.log(level, '');
return self;
}
// Otherwise build argument list which could potentially conform to
// either:
// . v3 API: log(obj)
// 2. v1/v2 API: log(level, msg, ... [string interpolate], [{metadata}], [callback])
return self.log(level, ...args);
};
DerivedLogger.prototype[isLevelEnabledFunctionName(level)] = function () {
return (this || logger).isLevelEnabled(level);
};
});
return logger;
};

245
node_modules/winston/lib/winston/exception-handler.js generated vendored Normal file
View File

@ -0,0 +1,245 @@
/**
* exception-handler.js: Object for handling uncaughtException events.
*
* (C) 2010 Charlie Robbins
* MIT LICENCE
*/
'use strict';
const os = require('os');
const asyncForEach = require('async/forEach');
const debug = require('diagnostics')('winston:exception');
const once = require('one-time');
const stackTrace = require('stack-trace');
const ExceptionStream = require('./exception-stream');
/**
* Object for handling uncaughtException events.
* @type {ExceptionHandler}
*/
module.exports = class ExceptionHandler {
/**
* TODO: add contructor description
* @param {!Logger} logger - TODO: add param description
*/
constructor(logger) {
if (!logger) {
throw new Error('Logger is required to handle exceptions');
}
this.logger = logger;
this.handlers = new Map();
}
/**
* Handles `uncaughtException` events for the current process by adding any
* handlers passed in.
* @returns {undefined}
*/
handle(...args) {
args.forEach(arg => {
if (Array.isArray(arg)) {
return arg.forEach(handler => this._addHandler(handler));
}
this._addHandler(arg);
});
if (!this.catcher) {
this.catcher = this._uncaughtException.bind(this);
process.on('uncaughtException', this.catcher);
}
}
/**
* Removes any handlers to `uncaughtException` events for the current
* process. This does not modify the state of the `this.handlers` set.
* @returns {undefined}
*/
unhandle() {
if (this.catcher) {
process.removeListener('uncaughtException', this.catcher);
this.catcher = false;
Array.from(this.handlers.values())
.forEach(wrapper => this.logger.unpipe(wrapper));
}
}
/**
* TODO: add method description
* @param {Error} err - Error to get information about.
* @returns {mixed} - TODO: add return description.
*/
getAllInfo(err) {
let { message } = err;
if (!message && typeof err === 'string') {
message = err;
}
return {
error: err,
// TODO (indexzero): how do we configure this?
level: 'error',
message: [
`uncaughtException: ${(message || '(no error message)')}`,
err.stack || ' No stack trace'
].join('\n'),
stack: err.stack,
exception: true,
date: new Date().toString(),
process: this.getProcessInfo(),
os: this.getOsInfo(),
trace: this.getTrace(err)
};
}
/**
* Gets all relevant process information for the currently running process.
* @returns {mixed} - TODO: add return description.
*/
getProcessInfo() {
return {
pid: process.pid,
uid: process.getuid ? process.getuid() : null,
gid: process.getgid ? process.getgid() : null,
cwd: process.cwd(),
execPath: process.execPath,
version: process.version,
argv: process.argv,
memoryUsage: process.memoryUsage()
};
}
/**
* Gets all relevant OS information for the currently running process.
* @returns {mixed} - TODO: add return description.
*/
getOsInfo() {
return {
loadavg: os.loadavg(),
uptime: os.uptime()
};
}
/**
* Gets a stack trace for the specified error.
* @param {mixed} err - TODO: add param description.
* @returns {mixed} - TODO: add return description.
*/
getTrace(err) {
const trace = err ? stackTrace.parse(err) : stackTrace.get();
return trace.map(site => {
return {
column: site.getColumnNumber(),
file: site.getFileName(),
function: site.getFunctionName(),
line: site.getLineNumber(),
method: site.getMethodName(),
native: site.isNative()
};
});
}
/**
* Helper method to add a transport as an exception handler.
* @param {Transport} handler - The transport to add as an exception handler.
* @returns {void}
*/
_addHandler(handler) {
if (!this.handlers.has(handler)) {
handler.handleExceptions = true;
const wrapper = new ExceptionStream(handler);
this.handlers.set(handler, wrapper);
this.logger.pipe(wrapper);
}
}
/**
* Logs all relevant information around the `err` and exits the current
* process.
* @param {Error} err - Error to handle
* @returns {mixed} - TODO: add return description.
* @private
*/
_uncaughtException(err) {
const info = this.getAllInfo(err);
const handlers = this._getExceptionHandlers();
// Calculate if we should exit on this error
let doExit = typeof this.logger.exitOnError === 'function'
? this.logger.exitOnError(err)
: this.logger.exitOnError;
let timeout;
if (!handlers.length && doExit) {
// eslint-disable-next-line no-console
console.warn('winston: exitOnError cannot be true with no exception handlers.');
// eslint-disable-next-line no-console
console.warn('winston: not exiting process.');
doExit = false;
}
function gracefulExit() {
debug('doExit', doExit);
debug('process._exiting', process._exiting);
if (doExit && !process._exiting) {
// Remark: Currently ignoring any exceptions from transports when
// catching uncaught exceptions.
if (timeout) {
clearTimeout(timeout);
}
// eslint-disable-next-line no-process-exit
process.exit(1);
}
}
if (!handlers || handlers.length === 0) {
return process.nextTick(gracefulExit);
}
// Log to all transports attempting to listen for when they are completed.
asyncForEach(handlers, (handler, next) => {
const done = once(next);
const transport = handler.transport || handler;
// Debug wrapping so that we can inspect what's going on under the covers.
function onDone(event) {
return () => {
debug(event);
done();
};
}
transport._ending = true;
transport.once('finish', onDone('finished'));
transport.once('error', onDone('error'));
}, () => doExit && gracefulExit());
this.logger.log(info);
// If exitOnError is true, then only allow the logging of exceptions to
// take up to `3000ms`.
if (doExit) {
timeout = setTimeout(gracefulExit, 3000);
}
}
/**
* Returns the list of transports and exceptionHandlers for this instance.
* @returns {Array} - List of transports and exceptionHandlers for this
* instance.
* @private
*/
_getExceptionHandlers() {
// Remark (indexzero): since `logger.transports` returns all of the pipes
// from the _readableState of the stream we actually get the join of the
// explicit handlers and the implicit transports with
// `handleExceptions: true`
return this.logger.transports.filter(wrap => {
const transport = wrap.transport || wrap;
return transport.handleExceptions;
});
}
};

54
node_modules/winston/lib/winston/exception-stream.js generated vendored Normal file
View File

@ -0,0 +1,54 @@
/**
* exception-stream.js: TODO: add file header handler.
*
* (C) 2010 Charlie Robbins
* MIT LICENCE
*/
'use strict';
const { Writable } = require('readable-stream');
/**
* TODO: add class description.
* @type {ExceptionStream}
* @extends {Writable}
*/
module.exports = class ExceptionStream extends Writable {
/**
* Constructor function for the ExceptionStream responsible for wrapping a
* TransportStream; only allowing writes of `info` objects with
* `info.exception` set to true.
* @param {!TransportStream} transport - Stream to filter to exceptions
*/
constructor(transport) {
super({ objectMode: true });
if (!transport) {
throw new Error('ExceptionStream requires a TransportStream instance.');
}
// Remark (indexzero): we set `handleExceptions` here because it's the
// predicate checked in ExceptionHandler.prototype.__getExceptionHandlers
this.handleExceptions = true;
this.transport = transport;
}
/**
* Writes the info object to our transport instance if (and only if) the
* `exception` property is set on the info.
* @param {mixed} info - TODO: add param description.
* @param {mixed} enc - TODO: add param description.
* @param {mixed} callback - TODO: add param description.
* @returns {mixed} - TODO: add return description.
* @private
*/
_write(info, enc, callback) {
if (info.exception) {
return this.transport.log(info, callback);
}
callback();
return true;
}
};

662
node_modules/winston/lib/winston/logger.js generated vendored Normal file
View File

@ -0,0 +1,662 @@
/**
* logger.js: TODO: add file header description.
*
* (C) 2010 Charlie Robbins
* MIT LICENCE
*/
'use strict';
const { Stream, Transform } = require('readable-stream');
const asyncForEach = require('async/forEach');
const { LEVEL, SPLAT } = require('triple-beam');
const isStream = require('is-stream');
const ExceptionHandler = require('./exception-handler');
const RejectionHandler = require('./rejection-handler');
const LegacyTransportStream = require('winston-transport/legacy');
const Profiler = require('./profiler');
const { warn } = require('./common');
const config = require('./config');
/**
* Captures the number of format (i.e. %s strings) in a given string.
* Based on `util.format`, see Node.js source:
* https://github.com/nodejs/node/blob/b1c8f15c5f169e021f7c46eb7b219de95fe97603/lib/util.js#L201-L230
* @type {RegExp}
*/
const formatRegExp = /%[scdjifoO%]/g;
/**
* TODO: add class description.
* @type {Logger}
* @extends {Transform}
*/
class Logger extends Transform {
/**
* Constructor function for the Logger object responsible for persisting log
* messages and metadata to one or more transports.
* @param {!Object} options - foo
*/
constructor(options) {
super({ objectMode: true });
this.configure(options);
}
child(defaultRequestMetadata) {
const logger = this;
return Object.create(logger, {
write: {
value: function (info) {
const infoClone = Object.assign(
{},
defaultRequestMetadata,
info
);
// Object.assign doesn't copy inherited Error
// properties so we have to do that explicitly
//
// Remark (indexzero): we should remove this
// since the errors format will handle this case.
//
if (info instanceof Error) {
infoClone.stack = info.stack;
infoClone.message = info.message;
}
logger.write(infoClone);
}
}
});
}
/**
* This will wholesale reconfigure this instance by:
* 1. Resetting all transports. Older transports will be removed implicitly.
* 2. Set all other options including levels, colors, rewriters, filters,
* exceptionHandlers, etc.
* @param {!Object} options - TODO: add param description.
* @returns {undefined}
*/
configure({
silent,
format,
defaultMeta,
levels,
level = 'info',
exitOnError = true,
transports,
colors,
emitErrs,
formatters,
padLevels,
rewriters,
stripColors,
exceptionHandlers,
rejectionHandlers
} = {}) {
// Reset transports if we already have them
if (this.transports.length) {
this.clear();
}
this.silent = silent;
this.format = format || this.format || require('logform/json')();
this.defaultMeta = defaultMeta || null;
// Hoist other options onto this instance.
this.levels = levels || this.levels || config.npm.levels;
this.level = level;
this.exceptions = new ExceptionHandler(this);
this.rejections = new RejectionHandler(this);
this.profilers = {};
this.exitOnError = exitOnError;
// Add all transports we have been provided.
if (transports) {
transports = Array.isArray(transports) ? transports : [transports];
transports.forEach(transport => this.add(transport));
}
if (
colors ||
emitErrs ||
formatters ||
padLevels ||
rewriters ||
stripColors
) {
throw new Error(
[
'{ colors, emitErrs, formatters, padLevels, rewriters, stripColors } were removed in winston@3.0.0.',
'Use a custom winston.format(function) instead.',
'See: https://github.com/winstonjs/winston/tree/master/UPGRADE-3.0.md'
].join('\n')
);
}
if (exceptionHandlers) {
this.exceptions.handle(exceptionHandlers);
}
if (rejectionHandlers) {
this.rejections.handle(rejectionHandlers);
}
}
isLevelEnabled(level) {
const givenLevelValue = getLevelValue(this.levels, level);
if (givenLevelValue === null) {
return false;
}
const configuredLevelValue = getLevelValue(this.levels, this.level);
if (configuredLevelValue === null) {
return false;
}
if (!this.transports || this.transports.length === 0) {
return configuredLevelValue >= givenLevelValue;
}
const index = this.transports.findIndex(transport => {
let transportLevelValue = getLevelValue(this.levels, transport.level);
if (transportLevelValue === null) {
transportLevelValue = configuredLevelValue;
}
return transportLevelValue >= givenLevelValue;
});
return index !== -1;
}
/* eslint-disable valid-jsdoc */
/**
* Ensure backwards compatibility with a `log` method
* @param {mixed} level - Level the log message is written at.
* @param {mixed} msg - TODO: add param description.
* @param {mixed} meta - TODO: add param description.
* @returns {Logger} - TODO: add return description.
*
* @example
* // Supports the existing API:
* logger.log('info', 'Hello world', { custom: true });
* logger.log('info', new Error('Yo, it\'s on fire'));
*
* // Requires winston.format.splat()
* logger.log('info', '%s %d%%', 'A string', 50, { thisIsMeta: true });
*
* // And the new API with a single JSON literal:
* logger.log({ level: 'info', message: 'Hello world', custom: true });
* logger.log({ level: 'info', message: new Error('Yo, it\'s on fire') });
*
* // Also requires winston.format.splat()
* logger.log({
* level: 'info',
* message: '%s %d%%',
* [SPLAT]: ['A string', 50],
* meta: { thisIsMeta: true }
* });
*
*/
/* eslint-enable valid-jsdoc */
log(level, msg, ...splat) {
// eslint-disable-line max-params
// Optimize for the hotpath of logging JSON literals
if (arguments.length === 1) {
// Yo dawg, I heard you like levels ... seriously ...
// In this context the LHS `level` here is actually the `info` so read
// this as: info[LEVEL] = info.level;
level[LEVEL] = level.level;
this._addDefaultMeta(level);
this.write(level);
return this;
}
// Slightly less hotpath, but worth optimizing for.
if (arguments.length === 2) {
if (msg && typeof msg === 'object') {
msg[LEVEL] = msg.level = level;
this._addDefaultMeta(msg);
this.write(msg);
return this;
}
this.write({ [LEVEL]: level, level, message: msg });
return this;
}
const [meta] = splat;
if (typeof meta === 'object' && meta !== null) {
// Extract tokens, if none available default to empty array to
// ensure consistancy in expected results
const tokens = msg && msg.match && msg.match(formatRegExp);
if (!tokens) {
const info = Object.assign({}, this.defaultMeta, meta, {
[LEVEL]: level,
[SPLAT]: splat,
level,
message: msg
});
if (meta.message) info.message += `${meta.message}`;
if (meta.stack) info.stack = meta.stack;
this.write(info);
return this;
}
}
this.write(Object.assign({}, this.defaultMeta, {
[LEVEL]: level,
[SPLAT]: splat,
level,
message: msg
}));
return this;
}
/**
* Pushes data so that it can be picked up by all of our pipe targets.
* @param {mixed} info - TODO: add param description.
* @param {mixed} enc - TODO: add param description.
* @param {mixed} callback - Continues stream processing.
* @returns {undefined}
* @private
*/
_transform(info, enc, callback) {
if (this.silent) {
return callback();
}
// [LEVEL] is only soft guaranteed to be set here since we are a proper
// stream. It is likely that `info` came in through `.log(info)` or
// `.info(info)`. If it is not defined, however, define it.
// This LEVEL symbol is provided by `triple-beam` and also used in:
// - logform
// - winston-transport
// - abstract-winston-transport
if (!info[LEVEL]) {
info[LEVEL] = info.level;
}
// Remark: really not sure what to do here, but this has been reported as
// very confusing by pre winston@2.0.0 users as quite confusing when using
// custom levels.
if (!this.levels[info[LEVEL]] && this.levels[info[LEVEL]] !== 0) {
// eslint-disable-next-line no-console
console.error('[winston] Unknown logger level: %s', info[LEVEL]);
}
// Remark: not sure if we should simply error here.
if (!this._readableState.pipes) {
// eslint-disable-next-line no-console
console.error(
'[winston] Attempt to write logs with no transports %j',
info
);
}
// Here we write to the `format` pipe-chain, which on `readable` above will
// push the formatted `info` Object onto the buffer for this instance. We trap
// (and re-throw) any errors generated by the user-provided format, but also
// guarantee that the streams callback is invoked so that we can continue flowing.
try {
this.push(this.format.transform(info, this.format.options));
} catch (ex) {
throw ex;
} finally {
// eslint-disable-next-line callback-return
callback();
}
}
/**
* Delays the 'finish' event until all transport pipe targets have
* also emitted 'finish' or are already finished.
* @param {mixed} callback - Continues stream processing.
*/
_final(callback) {
const transports = this.transports.slice();
asyncForEach(
transports,
(transport, next) => {
if (!transport || transport.finished) return setImmediate(next);
transport.once('finish', next);
transport.end();
},
callback
);
}
/**
* Adds the transport to this logger instance by piping to it.
* @param {mixed} transport - TODO: add param description.
* @returns {Logger} - TODO: add return description.
*/
add(transport) {
// Support backwards compatibility with all existing `winston < 3.x.x`
// transports which meet one of two criteria:
// 1. They inherit from winston.Transport in < 3.x.x which is NOT a stream.
// 2. They expose a log method which has a length greater than 2 (i.e. more then
// just `log(info, callback)`.
const target =
!isStream(transport) || transport.log.length > 2
? new LegacyTransportStream({ transport })
: transport;
if (!target._writableState || !target._writableState.objectMode) {
throw new Error(
'Transports must WritableStreams in objectMode. Set { objectMode: true }.'
);
}
// Listen for the `error` event and the `warn` event on the new Transport.
this._onEvent('error', target);
this._onEvent('warn', target);
this.pipe(target);
if (transport.handleExceptions) {
this.exceptions.handle();
}
if (transport.handleRejections) {
this.rejections.handle();
}
return this;
}
/**
* Removes the transport from this logger instance by unpiping from it.
* @param {mixed} transport - TODO: add param description.
* @returns {Logger} - TODO: add return description.
*/
remove(transport) {
let target = transport;
if (!isStream(transport) || transport.log.length > 2) {
target = this.transports.filter(
match => match.transport === transport
)[0];
}
if (target) {
this.unpipe(target);
}
return this;
}
/**
* Removes all transports from this logger instance.
* @returns {Logger} - TODO: add return description.
*/
clear() {
this.unpipe();
return this;
}
/**
* Cleans up resources (streams, event listeners) for all transports
* associated with this instance (if necessary).
* @returns {Logger} - TODO: add return description.
*/
close() {
this.clear();
this.emit('close');
return this;
}
/**
* Sets the `target` levels specified on this instance.
* @param {Object} Target levels to use on this instance.
*/
setLevels() {
warn.deprecated('setLevels');
}
/**
* Queries the all transports for this instance with the specified `options`.
* This will aggregate each transport's results into one object containing
* a property per transport.
* @param {Object} options - Query options for this instance.
* @param {function} callback - Continuation to respond to when complete.
*/
query(options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
options = options || {};
const results = {};
const queryObject = Object.assign({}, options.query || {});
// Helper function to query a single transport
function queryTransport(transport, next) {
if (options.query && typeof transport.formatQuery === 'function') {
options.query = transport.formatQuery(queryObject);
}
transport.query(options, (err, res) => {
if (err) {
return next(err);
}
if (typeof transport.formatResults === 'function') {
res = transport.formatResults(res, options.format);
}
next(null, res);
});
}
// Helper function to accumulate the results from `queryTransport` into
// the `results`.
function addResults(transport, next) {
queryTransport(transport, (err, result) => {
// queryTransport could potentially invoke the callback multiple times
// since Transport code can be unpredictable.
if (next) {
result = err || result;
if (result) {
results[transport.name] = result;
}
// eslint-disable-next-line callback-return
next();
}
next = null;
});
}
// Iterate over the transports in parallel setting the appropriate key in
// the `results`.
asyncForEach(
this.transports.filter(transport => !!transport.query),
addResults,
() => callback(null, results)
);
}
/**
* Returns a log stream for all transports. Options object is optional.
* @param{Object} options={} - Stream options for this instance.
* @returns {Stream} - TODO: add return description.
*/
stream(options = {}) {
const out = new Stream();
const streams = [];
out._streams = streams;
out.destroy = () => {
let i = streams.length;
while (i--) {
streams[i].destroy();
}
};
// Create a list of all transports for this instance.
this.transports
.filter(transport => !!transport.stream)
.forEach(transport => {
const str = transport.stream(options);
if (!str) {
return;
}
streams.push(str);
str.on('log', log => {
log.transport = log.transport || [];
log.transport.push(transport.name);
out.emit('log', log);
});
str.on('error', err => {
err.transport = err.transport || [];
err.transport.push(transport.name);
out.emit('error', err);
});
});
return out;
}
/**
* Returns an object corresponding to a specific timing. When done is called
* the timer will finish and log the duration. e.g.:
* @returns {Profile} - TODO: add return description.
* @example
* const timer = winston.startTimer()
* setTimeout(() => {
* timer.done({
* message: 'Logging message'
* });
* }, 1000);
*/
startTimer() {
return new Profiler(this);
}
/**
* Tracks the time inbetween subsequent calls to this method with the same
* `id` parameter. The second call to this method will log the difference in
* milliseconds along with the message.
* @param {string} id Unique id of the profiler
* @returns {Logger} - TODO: add return description.
*/
profile(id, ...args) {
const time = Date.now();
if (this.profilers[id]) {
const timeEnd = this.profilers[id];
delete this.profilers[id];
// Attempt to be kind to users if they are still using older APIs.
if (typeof args[args.length - 2] === 'function') {
// eslint-disable-next-line no-console
console.warn(
'Callback function no longer supported as of winston@3.0.0'
);
args.pop();
}
// Set the duration property of the metadata
const info = typeof args[args.length - 1] === 'object' ? args.pop() : {};
info.level = info.level || 'info';
info.durationMs = time - timeEnd;
info.message = info.message || id;
return this.write(info);
}
this.profilers[id] = time;
return this;
}
/**
* Backwards compatibility to `exceptions.handle` in winston < 3.0.0.
* @returns {undefined}
* @deprecated
*/
handleExceptions(...args) {
// eslint-disable-next-line no-console
console.warn(
'Deprecated: .handleExceptions() will be removed in winston@4. Use .exceptions.handle()'
);
this.exceptions.handle(...args);
}
/**
* Backwards compatibility to `exceptions.handle` in winston < 3.0.0.
* @returns {undefined}
* @deprecated
*/
unhandleExceptions(...args) {
// eslint-disable-next-line no-console
console.warn(
'Deprecated: .unhandleExceptions() will be removed in winston@4. Use .exceptions.unhandle()'
);
this.exceptions.unhandle(...args);
}
/**
* Throw a more meaningful deprecation notice
* @throws {Error} - TODO: add throws description.
*/
cli() {
throw new Error(
[
'Logger.cli() was removed in winston@3.0.0',
'Use a custom winston.formats.cli() instead.',
'See: https://github.com/winstonjs/winston/tree/master/UPGRADE-3.0.md'
].join('\n')
);
}
/**
* Bubbles the `event` that occured on the specified `transport` up
* from this instance.
* @param {string} event - The event that occured
* @param {Object} transport - Transport on which the event occured
* @private
*/
_onEvent(event, transport) {
function transportEvent(err) {
this.emit(event, err, transport);
}
if (!transport['__winston' + event]) {
transport['__winston' + event] = transportEvent.bind(this);
transport.on(event, transport['__winston' + event]);
}
}
_addDefaultMeta(msg) {
if (this.defaultMeta) {
Object.assign(msg, this.defaultMeta);
}
}
}
function getLevelValue(levels, level) {
const value = levels[level];
if (!value && value !== 0) {
return null;
}
return value;
}
/**
* Represents the current readableState pipe targets for this Logger instance.
* @type {Array|Object}
*/
Object.defineProperty(Logger.prototype, 'transports', {
configurable: false,
enumerable: true,
get() {
const { pipes } = this._readableState;
return !Array.isArray(pipes) ? [pipes].filter(Boolean) : pipes;
}
});
module.exports = Logger;

51
node_modules/winston/lib/winston/profiler.js generated vendored Normal file
View File

@ -0,0 +1,51 @@
/**
* profiler.js: TODO: add file header description.
*
* (C) 2010 Charlie Robbins
* MIT LICENCE
*/
'use strict';
/**
* TODO: add class description.
* @type {Profiler}
* @private
*/
module.exports = class Profiler {
/**
* Constructor function for the Profiler instance used by
* `Logger.prototype.startTimer`. When done is called the timer will finish
* and log the duration.
* @param {!Logger} logger - TODO: add param description.
* @private
*/
constructor(logger) {
if (!logger) {
throw new Error('Logger is required for profiling.');
}
this.logger = logger;
this.start = Date.now();
}
/**
* Ends the current timer (i.e. Profiler) instance and logs the `msg` along
* with the duration since creation.
* @returns {mixed} - TODO: add return description.
* @private
*/
done(...args) {
if (typeof args[args.length - 1] === 'function') {
// eslint-disable-next-line no-console
console.warn('Callback function no longer supported as of winston@3.0.0');
args.pop();
}
const info = typeof args[args.length - 1] === 'object' ? args.pop() : {};
info.level = info.level || 'info';
info.durationMs = (Date.now()) - this.start;
return this.logger.write(info);
}
};

251
node_modules/winston/lib/winston/rejection-handler.js generated vendored Normal file
View File

@ -0,0 +1,251 @@
/**
* exception-handler.js: Object for handling uncaughtException events.
*
* (C) 2010 Charlie Robbins
* MIT LICENCE
*/
'use strict';
const os = require('os');
const asyncForEach = require('async/forEach');
const debug = require('diagnostics')('winston:rejection');
const once = require('one-time');
const stackTrace = require('stack-trace');
const ExceptionStream = require('./exception-stream');
/**
* Object for handling unhandledRejection events.
* @type {RejectionHandler}
*/
module.exports = class RejectionHandler {
/**
* TODO: add contructor description
* @param {!Logger} logger - TODO: add param description
*/
constructor(logger) {
if (!logger) {
throw new Error('Logger is required to handle rejections');
}
this.logger = logger;
this.handlers = new Map();
}
/**
* Handles `unhandledRejection` events for the current process by adding any
* handlers passed in.
* @returns {undefined}
*/
handle(...args) {
args.forEach(arg => {
if (Array.isArray(arg)) {
return arg.forEach(handler => this._addHandler(handler));
}
this._addHandler(arg);
});
if (!this.catcher) {
this.catcher = this._unhandledRejection.bind(this);
process.on('unhandledRejection', this.catcher);
}
}
/**
* Removes any handlers to `unhandledRejection` events for the current
* process. This does not modify the state of the `this.handlers` set.
* @returns {undefined}
*/
unhandle() {
if (this.catcher) {
process.removeListener('unhandledRejection', this.catcher);
this.catcher = false;
Array.from(this.handlers.values()).forEach(wrapper =>
this.logger.unpipe(wrapper)
);
}
}
/**
* TODO: add method description
* @param {Error} err - Error to get information about.
* @returns {mixed} - TODO: add return description.
*/
getAllInfo(err) {
let { message } = err;
if (!message && typeof err === 'string') {
message = err;
}
return {
error: err,
// TODO (indexzero): how do we configure this?
level: 'error',
message: [
`unhandledRejection: ${message || '(no error message)'}`,
err.stack || ' No stack trace'
].join('\n'),
stack: err.stack,
exception: true,
date: new Date().toString(),
process: this.getProcessInfo(),
os: this.getOsInfo(),
trace: this.getTrace(err)
};
}
/**
* Gets all relevant process information for the currently running process.
* @returns {mixed} - TODO: add return description.
*/
getProcessInfo() {
return {
pid: process.pid,
uid: process.getuid ? process.getuid() : null,
gid: process.getgid ? process.getgid() : null,
cwd: process.cwd(),
execPath: process.execPath,
version: process.version,
argv: process.argv,
memoryUsage: process.memoryUsage()
};
}
/**
* Gets all relevant OS information for the currently running process.
* @returns {mixed} - TODO: add return description.
*/
getOsInfo() {
return {
loadavg: os.loadavg(),
uptime: os.uptime()
};
}
/**
* Gets a stack trace for the specified error.
* @param {mixed} err - TODO: add param description.
* @returns {mixed} - TODO: add return description.
*/
getTrace(err) {
const trace = err ? stackTrace.parse(err) : stackTrace.get();
return trace.map(site => {
return {
column: site.getColumnNumber(),
file: site.getFileName(),
function: site.getFunctionName(),
line: site.getLineNumber(),
method: site.getMethodName(),
native: site.isNative()
};
});
}
/**
* Helper method to add a transport as an exception handler.
* @param {Transport} handler - The transport to add as an exception handler.
* @returns {void}
*/
_addHandler(handler) {
if (!this.handlers.has(handler)) {
handler.handleExceptions = true;
const wrapper = new ExceptionStream(handler);
this.handlers.set(handler, wrapper);
this.logger.pipe(wrapper);
}
}
/**
* Logs all relevant information around the `err` and exits the current
* process.
* @param {Error} err - Error to handle
* @returns {mixed} - TODO: add return description.
* @private
*/
_unhandledRejection(err) {
const info = this.getAllInfo(err);
const handlers = this._getRejectionHandlers();
// Calculate if we should exit on this error
let doExit =
typeof this.logger.exitOnError === 'function'
? this.logger.exitOnError(err)
: this.logger.exitOnError;
let timeout;
if (!handlers.length && doExit) {
// eslint-disable-next-line no-console
console.warn('winston: exitOnError cannot be true with no rejection handlers.');
// eslint-disable-next-line no-console
console.warn('winston: not exiting process.');
doExit = false;
}
function gracefulExit() {
debug('doExit', doExit);
debug('process._exiting', process._exiting);
if (doExit && !process._exiting) {
// Remark: Currently ignoring any rejections from transports when
// catching unhandled rejections.
if (timeout) {
clearTimeout(timeout);
}
// eslint-disable-next-line no-process-exit
process.exit(1);
}
}
if (!handlers || handlers.length === 0) {
return process.nextTick(gracefulExit);
}
// Log to all transports attempting to listen for when they are completed.
asyncForEach(
handlers,
(handler, next) => {
const done = once(next);
const transport = handler.transport || handler;
// Debug wrapping so that we can inspect what's going on under the covers.
function onDone(event) {
return () => {
debug(event);
done();
};
}
transport._ending = true;
transport.once('finish', onDone('finished'));
transport.once('error', onDone('error'));
},
() => doExit && gracefulExit()
);
this.logger.log(info);
// If exitOnError is true, then only allow the logging of exceptions to
// take up to `3000ms`.
if (doExit) {
timeout = setTimeout(gracefulExit, 3000);
}
}
/**
* Returns the list of transports and exceptionHandlers for this instance.
* @returns {Array} - List of transports and exceptionHandlers for this
* instance.
* @private
*/
_getRejectionHandlers() {
// Remark (indexzero): since `logger.transports` returns all of the pipes
// from the _readableState of the stream we actually get the join of the
// explicit handlers and the implicit transports with
// `handleRejections: true`
return this.logger.transports.filter(wrap => {
const transport = wrap.transport || wrap;
return transport.handleRejections;
});
}
};

124
node_modules/winston/lib/winston/tail-file.js generated vendored Normal file
View File

@ -0,0 +1,124 @@
/**
* tail-file.js: TODO: add file header description.
*
* (C) 2010 Charlie Robbins
* MIT LICENCE
*/
'use strict';
const fs = require('fs');
const { StringDecoder } = require('string_decoder');
const { Stream } = require('readable-stream');
/**
* Simple no-op function.
* @returns {undefined}
*/
function noop() {}
/**
* TODO: add function description.
* @param {Object} options - Options for tail.
* @param {function} iter - Iterator function to execute on every line.
* `tail -f` a file. Options must include file.
* @returns {mixed} - TODO: add return description.
*/
module.exports = (options, iter) => {
const buffer = Buffer.alloc(64 * 1024);
const decode = new StringDecoder('utf8');
const stream = new Stream();
let buff = '';
let pos = 0;
let row = 0;
if (options.start === -1) {
delete options.start;
}
stream.readable = true;
stream.destroy = () => {
stream.destroyed = true;
stream.emit('end');
stream.emit('close');
};
fs.open(options.file, 'a+', '0644', (err, fd) => {
if (err) {
if (!iter) {
stream.emit('error', err);
} else {
iter(err);
}
stream.destroy();
return;
}
(function read() {
if (stream.destroyed) {
fs.close(fd, noop);
return;
}
return fs.read(fd, buffer, 0, buffer.length, pos, (err, bytes) => {
if (err) {
if (!iter) {
stream.emit('error', err);
} else {
iter(err);
}
stream.destroy();
return;
}
if (!bytes) {
if (buff) {
// eslint-disable-next-line eqeqeq
if (options.start == null || row > options.start) {
if (!iter) {
stream.emit('line', buff);
} else {
iter(null, buff);
}
}
row++;
buff = '';
}
return setTimeout(read, 1000);
}
let data = decode.write(buffer.slice(0, bytes));
if (!iter) {
stream.emit('data', data);
}
data = (buff + data).split(/\n+/);
const l = data.length - 1;
let i = 0;
for (; i < l; i++) {
// eslint-disable-next-line eqeqeq
if (options.start == null || row > options.start) {
if (!iter) {
stream.emit('line', data[i]);
} else {
iter(null, data[i]);
}
}
row++;
}
buff = data[l];
pos += bytes;
return read();
});
}());
});
if (!iter) {
return stream;
}
return stream.destroy;
};

117
node_modules/winston/lib/winston/transports/console.js generated vendored Normal file
View File

@ -0,0 +1,117 @@
/* eslint-disable no-console */
/*
* console.js: Transport for outputting to the console.
*
* (C) 2010 Charlie Robbins
* MIT LICENCE
*/
'use strict';
const os = require('os');
const { LEVEL, MESSAGE } = require('triple-beam');
const TransportStream = require('winston-transport');
/**
* Transport for outputting to the console.
* @type {Console}
* @extends {TransportStream}
*/
module.exports = class Console extends TransportStream {
/**
* Constructor function for the Console transport object responsible for
* persisting log messages and metadata to a terminal or TTY.
* @param {!Object} [options={}] - Options for this instance.
*/
constructor(options = {}) {
super(options);
// Expose the name of this Transport on the prototype
this.name = options.name || 'console';
this.stderrLevels = this._stringArrayToSet(options.stderrLevels);
this.consoleWarnLevels = this._stringArrayToSet(options.consoleWarnLevels);
this.eol = options.eol || os.EOL;
this.setMaxListeners(30);
}
/**
* Core logging method exposed to Winston.
* @param {Object} info - TODO: add param description.
* @param {Function} callback - TODO: add param description.
* @returns {undefined}
*/
log(info, callback) {
setImmediate(() => this.emit('logged', info));
// Remark: what if there is no raw...?
if (this.stderrLevels[info[LEVEL]]) {
if (console._stderr) {
// Node.js maps `process.stderr` to `console._stderr`.
console._stderr.write(`${info[MESSAGE]}${this.eol}`);
} else {
// console.error adds a newline
console.error(info[MESSAGE]);
}
if (callback) {
callback(); // eslint-disable-line callback-return
}
return;
} else if (this.consoleWarnLevels[info[LEVEL]]) {
if (console._stderr) {
// Node.js maps `process.stderr` to `console._stderr`.
// in Node.js console.warn is an alias for console.error
console._stderr.write(`${info[MESSAGE]}${this.eol}`);
} else {
// console.warn adds a newline
console.warn(info[MESSAGE]);
}
if (callback) {
callback(); // eslint-disable-line callback-return
}
return;
}
if (console._stdout) {
// Node.js maps `process.stdout` to `console._stdout`.
console._stdout.write(`${info[MESSAGE]}${this.eol}`);
} else {
// console.log adds a newline.
console.log(info[MESSAGE]);
}
if (callback) {
callback(); // eslint-disable-line callback-return
}
}
/**
* Returns a Set-like object with strArray's elements as keys (each with the
* value true).
* @param {Array} strArray - Array of Set-elements as strings.
* @param {?string} [errMsg] - Custom error message thrown on invalid input.
* @returns {Object} - TODO: add return description.
* @private
*/
_stringArrayToSet(strArray, errMsg) {
if (!strArray)
return {};
errMsg = errMsg || 'Cannot make set from type other than Array of string elements';
if (!Array.isArray(strArray)) {
throw new Error(errMsg);
}
return strArray.reduce((set, el) => {
if (typeof el !== 'string') {
throw new Error(errMsg);
}
set[el] = true;
return set;
}, {});
}
};

698
node_modules/winston/lib/winston/transports/file.js generated vendored Normal file
View File

@ -0,0 +1,698 @@
/* eslint-disable complexity,max-statements */
/**
* file.js: Transport for outputting to a local log file.
*
* (C) 2010 Charlie Robbins
* MIT LICENCE
*/
'use strict';
const fs = require('fs');
const path = require('path');
const asyncSeries = require('async/series');
const zlib = require('zlib');
const { MESSAGE } = require('triple-beam');
const { Stream, PassThrough } = require('readable-stream');
const TransportStream = require('winston-transport');
const debug = require('diagnostics')('winston:file');
const os = require('os');
const tailFile = require('../tail-file');
/**
* Transport for outputting to a local log file.
* @type {File}
* @extends {TransportStream}
*/
module.exports = class File extends TransportStream {
/**
* Constructor function for the File transport object responsible for
* persisting log messages and metadata to one or more files.
* @param {Object} options - Options for this instance.
*/
constructor(options = {}) {
super(options);
// Expose the name of this Transport on the prototype.
this.name = options.name || 'file';
// Helper function which throws an `Error` in the event that any of the
// rest of the arguments is present in `options`.
function throwIf(target, ...args) {
args.slice(1).forEach(name => {
if (options[name]) {
throw new Error(`Cannot set ${name} and ${target} together`);
}
});
}
// Setup the base stream that always gets piped to to handle buffering.
this._stream = new PassThrough();
this._stream.setMaxListeners(30);
// Bind this context for listener methods.
this._onError = this._onError.bind(this);
if (options.filename || options.dirname) {
throwIf('filename or dirname', 'stream');
this._basename = this.filename = options.filename
? path.basename(options.filename)
: 'winston.log';
this.dirname = options.dirname || path.dirname(options.filename);
this.options = options.options || { flags: 'a' };
} else if (options.stream) {
// eslint-disable-next-line no-console
console.warn('options.stream will be removed in winston@4. Use winston.transports.Stream');
throwIf('stream', 'filename', 'maxsize');
this._dest = this._stream.pipe(this._setupStream(options.stream));
this.dirname = path.dirname(this._dest.path);
// We need to listen for drain events when write() returns false. This
// can make node mad at times.
} else {
throw new Error('Cannot log to file without filename or stream.');
}
this.maxsize = options.maxsize || null;
this.rotationFormat = options.rotationFormat || false;
this.zippedArchive = options.zippedArchive || false;
this.maxFiles = options.maxFiles || null;
this.eol = options.eol || os.EOL;
this.tailable = options.tailable || false;
// Internal state variables representing the number of files this instance
// has created and the current size (in bytes) of the current logfile.
this._size = 0;
this._pendingSize = 0;
this._created = 0;
this._drain = false;
this._opening = false;
this._ending = false;
if (this.dirname) this._createLogDirIfNotExist(this.dirname);
this.open();
}
finishIfEnding() {
if (this._ending) {
if (this._opening) {
this.once('open', () => {
this._stream.once('finish', () => this.emit('finish'));
setImmediate(() => this._stream.end());
});
} else {
this._stream.once('finish', () => this.emit('finish'));
setImmediate(() => this._stream.end());
}
}
}
/**
* Core logging method exposed to Winston. Metadata is optional.
* @param {Object} info - TODO: add param description.
* @param {Function} callback - TODO: add param description.
* @returns {undefined}
*/
log(info, callback = () => {}) {
// Remark: (jcrugzz) What is necessary about this callback(null, true) now
// when thinking about 3.x? Should silent be handled in the base
// TransportStream _write method?
if (this.silent) {
callback();
return true;
}
// Output stream buffer is full and has asked us to wait for the drain event
if (this._drain) {
this._stream.once('drain', () => {
this._drain = false;
this.log(info, callback);
});
return;
}
if (this._rotate) {
this._stream.once('rotate', () => {
this._rotate = false;
this.log(info, callback);
});
return;
}
// Grab the raw string and append the expected EOL.
const output = `${info[MESSAGE]}${this.eol}`;
const bytes = Buffer.byteLength(output);
// After we have written to the PassThrough check to see if we need
// to rotate to the next file.
//
// Remark: This gets called too early and does not depict when data
// has been actually flushed to disk.
function logged() {
this._size += bytes;
this._pendingSize -= bytes;
debug('logged %s %s', this._size, output);
this.emit('logged', info);
// Do not attempt to rotate files while opening
if (this._opening) {
return;
}
// Check to see if we need to end the stream and create a new one.
if (!this._needsNewFile()) {
return;
}
// End the current stream, ensure it flushes and create a new one.
// This could potentially be optimized to not run a stat call but its
// the safest way since we are supporting `maxFiles`.
this._rotate = true;
this._endStream(() => this._rotateFile());
}
// Keep track of the pending bytes being written while files are opening
// in order to properly rotate the PassThrough this._stream when the file
// eventually does open.
this._pendingSize += bytes;
if (this._opening
&& !this.rotatedWhileOpening
&& this._needsNewFile(this._size + this._pendingSize)) {
this.rotatedWhileOpening = true;
}
const written = this._stream.write(output, logged.bind(this));
if (!written) {
this._drain = true;
this._stream.once('drain', () => {
this._drain = false;
callback();
});
} else {
callback(); // eslint-disable-line callback-return
}
debug('written', written, this._drain);
this.finishIfEnding();
return written;
}
/**
* Query the transport. Options object is optional.
* @param {Object} options - Loggly-like query options for this instance.
* @param {function} callback - Continuation to respond to when complete.
* TODO: Refactor me.
*/
query(options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
options = normalizeQuery(options);
const file = path.join(this.dirname, this.filename);
let buff = '';
let results = [];
let row = 0;
const stream = fs.createReadStream(file, {
encoding: 'utf8'
});
stream.on('error', err => {
if (stream.readable) {
stream.destroy();
}
if (!callback) {
return;
}
return err.code !== 'ENOENT' ? callback(err) : callback(null, results);
});
stream.on('data', data => {
data = (buff + data).split(/\n+/);
const l = data.length - 1;
let i = 0;
for (; i < l; i++) {
if (!options.start || row >= options.start) {
add(data[i]);
}
row++;
}
buff = data[l];
});
stream.on('close', () => {
if (buff) {
add(buff, true);
}
if (options.order === 'desc') {
results = results.reverse();
}
// eslint-disable-next-line callback-return
if (callback) callback(null, results);
});
function add(buff, attempt) {
try {
const log = JSON.parse(buff);
if (check(log)) {
push(log);
}
} catch (e) {
if (!attempt) {
stream.emit('error', e);
}
}
}
function push(log) {
if (
options.rows &&
results.length >= options.rows &&
options.order !== 'desc'
) {
if (stream.readable) {
stream.destroy();
}
return;
}
if (options.fields) {
log = options.fields.reduce((obj, key) => {
obj[key] = log[key];
return obj;
}, {});
}
if (options.order === 'desc') {
if (results.length >= options.rows) {
results.shift();
}
}
results.push(log);
}
function check(log) {
if (!log) {
return;
}
if (typeof log !== 'object') {
return;
}
const time = new Date(log.timestamp);
if (
(options.from && time < options.from) ||
(options.until && time > options.until) ||
(options.level && options.level !== log.level)
) {
return;
}
return true;
}
function normalizeQuery(options) {
options = options || {};
// limit
options.rows = options.rows || options.limit || 10;
// starting row offset
options.start = options.start || 0;
// now
options.until = options.until || new Date();
if (typeof options.until !== 'object') {
options.until = new Date(options.until);
}
// now - 24
options.from = options.from || (options.until - (24 * 60 * 60 * 1000));
if (typeof options.from !== 'object') {
options.from = new Date(options.from);
}
// 'asc' or 'desc'
options.order = options.order || 'desc';
// which fields to select
options.fields = options.fields;
return options;
}
}
/**
* Returns a log stream for this transport. Options object is optional.
* @param {Object} options - Stream options for this instance.
* @returns {Stream} - TODO: add return description.
* TODO: Refactor me.
*/
stream(options = {}) {
const file = path.join(this.dirname, this.filename);
const stream = new Stream();
const tail = {
file,
start: options.start
};
stream.destroy = tailFile(tail, (err, line) => {
if (err) {
return stream.emit('error', err);
}
try {
stream.emit('data', line);
line = JSON.parse(line);
stream.emit('log', line);
} catch (e) {
stream.emit('error', e);
}
});
return stream;
}
/**
* Checks to see the filesize of.
* @returns {undefined}
*/
open() {
// If we do not have a filename then we were passed a stream and
// don't need to keep track of size.
if (!this.filename) return;
if (this._opening) return;
this._opening = true;
// Stat the target file to get the size and create the stream.
this.stat((err, size) => {
if (err) {
return this.emit('error', err);
}
debug('stat done: %s { size: %s }', this.filename, size);
this._size = size;
this._dest = this._createStream(this._stream);
this._opening = false;
this.once('open', () => {
if (this._stream.eventNames().includes('rotate')) {
this._stream.emit('rotate');
} else {
this._rotate = false;
}
});
});
}
/**
* Stat the file and assess information in order to create the proper stream.
* @param {function} callback - TODO: add param description.
* @returns {undefined}
*/
stat(callback) {
const target = this._getFile();
const fullpath = path.join(this.dirname, target);
fs.stat(fullpath, (err, stat) => {
if (err && err.code === 'ENOENT') {
debug('ENOENT ok', fullpath);
// Update internally tracked filename with the new target name.
this.filename = target;
return callback(null, 0);
}
if (err) {
debug(`err ${err.code} ${fullpath}`);
return callback(err);
}
if (!stat || this._needsNewFile(stat.size)) {
// If `stats.size` is greater than the `maxsize` for this
// instance then try again.
return this._incFile(() => this.stat(callback));
}
// Once we have figured out what the filename is, set it
// and return the size.
this.filename = target;
callback(null, stat.size);
});
}
/**
* Closes the stream associated with this instance.
* @param {function} cb - TODO: add param description.
* @returns {undefined}
*/
close(cb) {
if (!this._stream) {
return;
}
this._stream.end(() => {
if (cb) {
cb(); // eslint-disable-line callback-return
}
this.emit('flush');
this.emit('closed');
});
}
/**
* TODO: add method description.
* @param {number} size - TODO: add param description.
* @returns {undefined}
*/
_needsNewFile(size) {
size = size || this._size;
return this.maxsize && size >= this.maxsize;
}
/**
* TODO: add method description.
* @param {Error} err - TODO: add param description.
* @returns {undefined}
*/
_onError(err) {
this.emit('error', err);
}
/**
* TODO: add method description.
* @param {Stream} stream - TODO: add param description.
* @returns {mixed} - TODO: add return description.
*/
_setupStream(stream) {
stream.on('error', this._onError);
return stream;
}
/**
* TODO: add method description.
* @param {Stream} stream - TODO: add param description.
* @returns {mixed} - TODO: add return description.
*/
_cleanupStream(stream) {
stream.removeListener('error', this._onError);
return stream;
}
/**
* TODO: add method description.
*/
_rotateFile() {
this._incFile(() => this.open());
}
/**
* Unpipe from the stream that has been marked as full and end it so it
* flushes to disk.
*
* @param {function} callback - Callback for when the current file has closed.
* @private
*/
_endStream(callback = () => {}) {
if (this._dest) {
this._stream.unpipe(this._dest);
this._dest.end(() => {
this._cleanupStream(this._dest);
callback();
});
} else {
callback(); // eslint-disable-line callback-return
}
}
/**
* Returns the WritableStream for the active file on this instance. If we
* should gzip the file then a zlib stream is returned.
*
* @param {ReadableStream} source  PassThrough to pipe to the file when open.
* @returns {WritableStream} Stream that writes to disk for the active file.
*/
_createStream(source) {
const fullpath = path.join(this.dirname, this.filename);
debug('create stream start', fullpath, this.options);
const dest = fs.createWriteStream(fullpath, this.options)
// TODO: What should we do with errors here?
.on('error', err => debug(err))
.on('close', () => debug('close', dest.path, dest.bytesWritten))
.on('open', () => {
debug('file open ok', fullpath);
this.emit('open', fullpath);
source.pipe(dest);
// If rotation occured during the open operation then we immediately
// start writing to a new PassThrough, begin opening the next file
// and cleanup the previous source and dest once the source has drained.
if (this.rotatedWhileOpening) {
this._stream = new PassThrough();
this._stream.setMaxListeners(30);
this._rotateFile();
this.rotatedWhileOpening = false;
this._cleanupStream(dest);
source.end();
}
});
debug('create stream ok', fullpath);
if (this.zippedArchive) {
const gzip = zlib.createGzip();
gzip.pipe(dest);
return gzip;
}
return dest;
}
/**
* TODO: add method description.
* @param {function} callback - TODO: add param description.
* @returns {undefined}
*/
_incFile(callback) {
debug('_incFile', this.filename);
const ext = path.extname(this._basename);
const basename = path.basename(this._basename, ext);
if (!this.tailable) {
this._created += 1;
this._checkMaxFilesIncrementing(ext, basename, callback);
} else {
this._checkMaxFilesTailable(ext, basename, callback);
}
}
/**
* Gets the next filename to use for this instance in the case that log
* filesizes are being capped.
* @returns {string} - TODO: add return description.
* @private
*/
_getFile() {
const ext = path.extname(this._basename);
const basename = path.basename(this._basename, ext);
const isRotation = this.rotationFormat
? this.rotationFormat()
: this._created;
// Caveat emptor (indexzero): rotationFormat() was broken by design When
// combined with max files because the set of files to unlink is never
// stored.
const target = !this.tailable && this._created
? `${basename}${isRotation}${ext}`
: `${basename}${ext}`;
return this.zippedArchive && !this.tailable
? `${target}.gz`
: target;
}
/**
* Increment the number of files created or checked by this instance.
* @param {mixed} ext - TODO: add param description.
* @param {mixed} basename - TODO: add param description.
* @param {mixed} callback - TODO: add param description.
* @returns {undefined}
* @private
*/
_checkMaxFilesIncrementing(ext, basename, callback) {
// Check for maxFiles option and delete file.
if (!this.maxFiles || this._created < this.maxFiles) {
return setImmediate(callback);
}
const oldest = this._created - this.maxFiles;
const isOldest = oldest !== 0 ? oldest : '';
const isZipped = this.zippedArchive ? '.gz' : '';
const filePath = `${basename}${isOldest}${ext}${isZipped}`;
const target = path.join(this.dirname, filePath);
fs.unlink(target, callback);
}
/**
* Roll files forward based on integer, up to maxFiles. e.g. if base if
* file.log and it becomes oversized, roll to file1.log, and allow file.log
* to be re-used. If file is oversized again, roll file1.log to file2.log,
* roll file.log to file1.log, and so on.
* @param {mixed} ext - TODO: add param description.
* @param {mixed} basename - TODO: add param description.
* @param {mixed} callback - TODO: add param description.
* @returns {undefined}
* @private
*/
_checkMaxFilesTailable(ext, basename, callback) {
const tasks = [];
if (!this.maxFiles) {
return;
}
// const isZipped = this.zippedArchive ? '.gz' : '';
const isZipped = this.zippedArchive ? '.gz' : '';
for (let x = this.maxFiles - 1; x > 1; x--) {
tasks.push(function (i, cb) {
let fileName = `${basename}${(i - 1)}${ext}${isZipped}`;
const tmppath = path.join(this.dirname, fileName);
fs.exists(tmppath, exists => {
if (!exists) {
return cb(null);
}
fileName = `${basename}${i}${ext}${isZipped}`;
fs.rename(tmppath, path.join(this.dirname, fileName), cb);
});
}.bind(this, x));
}
asyncSeries(tasks, () => {
fs.rename(
path.join(this.dirname, `${basename}${ext}`),
path.join(this.dirname, `${basename}1${ext}${isZipped}`),
callback
);
});
}
_createLogDirIfNotExist(dirPath) {
/* eslint-disable no-sync */
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
/* eslint-enable no-sync */
}
};

196
node_modules/winston/lib/winston/transports/http.js generated vendored Normal file
View File

@ -0,0 +1,196 @@
/**
* http.js: Transport for outputting to a json-rpcserver.
*
* (C) 2010 Charlie Robbins
* MIT LICENCE
*/
'use strict';
const http = require('http');
const https = require('https');
const { Stream } = require('readable-stream');
const TransportStream = require('winston-transport');
/**
* Transport for outputting to a json-rpc server.
* @type {Stream}
* @extends {TransportStream}
*/
module.exports = class Http extends TransportStream {
/**
* Constructor function for the Http transport object responsible for
* persisting log messages and metadata to a terminal or TTY.
* @param {!Object} [options={}] - Options for this instance.
*/
constructor(options = {}) {
super(options);
this.name = options.name || 'http';
this.ssl = !!options.ssl;
this.host = options.host || 'localhost';
this.port = options.port;
this.auth = options.auth;
this.path = options.path || '';
this.agent = options.agent;
this.headers = options.headers || {};
this.headers['content-type'] = 'application/json';
if (!this.port) {
this.port = this.ssl ? 443 : 80;
}
}
/**
* Core logging method exposed to Winston.
* @param {Object} info - TODO: add param description.
* @param {function} callback - TODO: add param description.
* @returns {undefined}
*/
log(info, callback) {
this._request(info, (err, res) => {
if (res && res.statusCode !== 200) {
err = new Error(`Invalid HTTP Status Code: ${res.statusCode}`);
}
if (err) {
this.emit('warn', err);
} else {
this.emit('logged', info);
}
});
// Remark: (jcrugzz) Fire and forget here so requests dont cause buffering
// and block more requests from happening?
if (callback) {
setImmediate(callback);
}
}
/**
* Query the transport. Options object is optional.
* @param {Object} options - Loggly-like query options for this instance.
* @param {function} callback - Continuation to respond to when complete.
* @returns {undefined}
*/
query(options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
options = {
method: 'query',
params: this.normalizeQuery(options)
};
if (options.params.path) {
options.path = options.params.path;
delete options.params.path;
}
if (options.params.auth) {
options.auth = options.params.auth;
delete options.params.auth;
}
this._request(options, (err, res, body) => {
if (res && res.statusCode !== 200) {
err = new Error(`Invalid HTTP Status Code: ${res.statusCode}`);
}
if (err) {
return callback(err);
}
if (typeof body === 'string') {
try {
body = JSON.parse(body);
} catch (e) {
return callback(e);
}
}
callback(null, body);
});
}
/**
* Returns a log stream for this transport. Options object is optional.
* @param {Object} options - Stream options for this instance.
* @returns {Stream} - TODO: add return description
*/
stream(options = {}) {
const stream = new Stream();
options = {
method: 'stream',
params: options
};
if (options.params.path) {
options.path = options.params.path;
delete options.params.path;
}
if (options.params.auth) {
options.auth = options.params.auth;
delete options.params.auth;
}
let buff = '';
const req = this._request(options);
stream.destroy = () => req.destroy();
req.on('data', data => {
data = (buff + data).split(/\n+/);
const l = data.length - 1;
let i = 0;
for (; i < l; i++) {
try {
stream.emit('log', JSON.parse(data[i]));
} catch (e) {
stream.emit('error', e);
}
}
buff = data[l];
});
req.on('error', err => stream.emit('error', err));
return stream;
}
/**
* Make a request to a winstond server or any http server which can
* handle json-rpc.
* @param {function} options - Options to sent the request.
* @param {function} callback - Continuation to respond to when complete.
*/
_request(options, callback) {
options = options || {};
const auth = options.auth || this.auth;
const path = options.path || this.path || '';
delete options.auth;
delete options.path;
// Prepare options for outgoing HTTP request
const req = (this.ssl ? https : http).request({
method: 'POST',
host: this.host,
port: this.port,
path: `/${path.replace(/^\//, '')}`,
headers: this.headers,
auth: auth ? (`${auth.username}:${auth.password}`) : '',
agent: this.agent
});
req.on('error', callback);
req.on('response', res => (
res.on('end', () => callback(null, res)).resume()
));
req.end(Buffer.from(JSON.stringify(options), 'utf8'));
}
};

100
node_modules/winston/lib/winston/transports/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,100 @@
// Type definitions for winston 3.0
// Project: https://github.com/winstonjs/winston
/// <reference types="node" />
import {Agent} from "http";
import * as Transport from 'winston-transport';
declare namespace winston {
interface ConsoleTransportOptions extends Transport.TransportStreamOptions {
consoleWarnLevels?: string[],
stderrLevels?: string[];
debugStdout?: boolean;
eol?: string;
}
interface ConsoleTransportInstance extends Transport {
name: string;
stderrLevels: string[];
eol: string;
new(options?: ConsoleTransportOptions): ConsoleTransportInstance;
}
interface FileTransportOptions extends Transport.TransportStreamOptions {
filename?: string;
dirname?: string;
options?: object;
maxsize?: number;
stream?: NodeJS.WritableStream;
rotationFormat?: Function;
zippedArchive?: boolean;
maxFiles?: number;
eol?: string;
tailable?: boolean;
}
interface FileTransportInstance extends Transport {
name: string;
filename: string;
dirname: string;
options: object;
maxsize: number | null;
rotationFormat: Function | boolean;
zippedArchive: boolean;
maxFiles: number | null;
eol: string;
tailable: boolean;
new(options?: FileTransportOptions): FileTransportInstance;
}
interface HttpTransportOptions extends Transport.TransportStreamOptions {
ssl?: any;
host?: string;
port?: number;
auth?: { username: string; password: string; };
path?: string;
agent?: Agent;
headers?: object;
}
interface HttpTransportInstance extends Transport {
name: string;
ssl: boolean;
host: string;
port: number;
auth?: { username: string, password: string };
path: string;
agent?: Agent | null;
new(options?: HttpTransportOptions): HttpTransportInstance;
}
interface StreamTransportOptions extends Transport.TransportStreamOptions {
stream: NodeJS.WritableStream;
eol?: string;
}
interface StreamTransportInstance extends Transport {
eol: string;
new(options?: StreamTransportOptions): StreamTransportInstance;
}
interface Transports {
FileTransportOptions: FileTransportOptions;
File: FileTransportInstance;
ConsoleTransportOptions: ConsoleTransportOptions;
Console: ConsoleTransportInstance;
HttpTransportOptions: HttpTransportOptions;
Http: HttpTransportInstance;
StreamTransportOptions: StreamTransportOptions;
Stream: StreamTransportInstance;
}
}
declare const winston: winston.Transports;
export = winston;

56
node_modules/winston/lib/winston/transports/index.js generated vendored Normal file
View File

@ -0,0 +1,56 @@
/**
* transports.js: Set of all transports Winston knows about.
*
* (C) 2010 Charlie Robbins
* MIT LICENCE
*/
'use strict';
/**
* TODO: add property description.
* @type {Console}
*/
Object.defineProperty(exports, 'Console', {
configurable: true,
enumerable: true,
get() {
return require('./console');
}
});
/**
* TODO: add property description.
* @type {File}
*/
Object.defineProperty(exports, 'File', {
configurable: true,
enumerable: true,
get() {
return require('./file');
}
});
/**
* TODO: add property description.
* @type {Http}
*/
Object.defineProperty(exports, 'Http', {
configurable: true,
enumerable: true,
get() {
return require('./http');
}
});
/**
* TODO: add property description.
* @type {Stream}
*/
Object.defineProperty(exports, 'Stream', {
configurable: true,
enumerable: true,
get() {
return require('./stream');
}
});

63
node_modules/winston/lib/winston/transports/stream.js generated vendored Normal file
View File

@ -0,0 +1,63 @@
/**
* stream.js: Transport for outputting to any arbitrary stream.
*
* (C) 2010 Charlie Robbins
* MIT LICENCE
*/
'use strict';
const isStream = require('is-stream');
const { MESSAGE } = require('triple-beam');
const os = require('os');
const TransportStream = require('winston-transport');
/**
* Transport for outputting to any arbitrary stream.
* @type {Stream}
* @extends {TransportStream}
*/
module.exports = class Stream extends TransportStream {
/**
* Constructor function for the Console transport object responsible for
* persisting log messages and metadata to a terminal or TTY.
* @param {!Object} [options={}] - Options for this instance.
*/
constructor(options = {}) {
super(options);
if (!options.stream || !isStream(options.stream)) {
throw new Error('options.stream is required.');
}
// We need to listen for drain events when write() returns false. This can
// make node mad at times.
this._stream = options.stream;
this._stream.setMaxListeners(Infinity);
this.isObjectMode = options.stream._writableState.objectMode;
this.eol = options.eol || os.EOL;
}
/**
* Core logging method exposed to Winston.
* @param {Object} info - TODO: add param description.
* @param {Function} callback - TODO: add param description.
* @returns {undefined}
*/
log(info, callback) {
setImmediate(() => this.emit('logged', info));
if (this.isObjectMode) {
this._stream.write(info);
if (callback) {
callback(); // eslint-disable-line callback-return
}
return;
}
this._stream.write(`${info[MESSAGE]}${this.eol}`);
if (callback) {
callback(); // eslint-disable-line callback-return
}
return;
}
};