Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding log level methods when using Logger class #2351

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 1 addition & 58 deletions lib/winston/create-logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,8 @@

'use strict';

const { LEVEL } = require('triple-beam');
const config = require('./config');
const Logger = require('./logger');
const debug = require('@dabh/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
Expand Down Expand Up @@ -47,58 +41,7 @@ module.exports = function (opts = {}) {

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);
};
});
logger.createLogLevelMethods(logger, opts.levels);

return logger;
};
52 changes: 52 additions & 0 deletions lib/winston/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const LegacyTransportStream = require('winston-transport/legacy');
const Profiler = require('./profiler');
const { warn } = require('./common');
const config = require('./config');
const debug = require('@dabh/diagnostics')('winston:create-logger');

/**
* Captures the number of format (i.e. %s strings) in a given string.
Expand Down Expand Up @@ -149,6 +150,57 @@ class Logger extends Transform {
}
}

//
// Create the log level methods for the derived logger.
//
createLogLevelMethods(logger, levels) {
Object.keys(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.
//
Logger.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);
};
const isLevelEnabledFunctionName = 'is' + level.charAt(0).toUpperCase() + level.slice(1) + 'Enabled';
Logger.prototype[isLevelEnabledFunctionName] = function () {
return (this || logger).isLevelEnabled(level);
};
});
}

isLevelEnabled(level) {
const givenLevelValue = getLevelValue(this.levels, level);
if (givenLevelValue === null) {
Expand Down
26 changes: 26 additions & 0 deletions test/unit/winston/logger.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,32 @@ describe('Logger Instance', function () {
});

describe('Log Levels', function () {
it('create log level methods using Logger class', function (done) {
stdMocks.use();
const logger = new winston.Logger({
level: 'info',
transports: [new winston.transports.Console()],
format: winston.format.combine(winston.format.splat(), winston.format.colorize({ all: true }), winston.format.simple())
})
logger.error('test');
logger.warn('test');
logger.info('test');
logger.verbose('test');
logger.debug('test');
logger.silly('test');

stdMocks.restore();

assume(logger.error).is.a('function');
assume(logger.warn).is.a('function');
assume(logger.info).is.a('function');
assume(logger.verbose).is.a('function');
assume(logger.debug).is.a('function');
assume(logger.silly).is.a('function');

done();
});

it('report unknown levels', function (done) {
stdMocks.use();
let logger = helpers.createLogger(function (info) {
Expand Down