Skip to content

Commit

Permalink
feat(configure): add ability to configure formatter and output
Browse files Browse the repository at this point in the history
  • Loading branch information
esysuser committed Nov 29, 2017
1 parent feb7083 commit baf8e42
Show file tree
Hide file tree
Showing 11 changed files with 3,532 additions and 2,707 deletions.
5 changes: 5 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const Logger = require('./src/logger/logger');
const isNamespaceEnabled = require('./src/enabled/enabled');
const contextMiddlewareFactory = require('./src/context-middleware-factory/context-middleware-factory');
const formatter = require('./src/formatter');

/**
* @param namespace
Expand All @@ -23,5 +24,9 @@ logFactory.getKoaMiddleware = contextMiddlewareFactory.getKoaMiddleware.bind(con
logFactory.getExpressMiddleware = contextMiddlewareFactory.getExpressMiddleware.bind(contextMiddlewareFactory);
logFactory.getMiddleware = logFactory.getKoaMiddleware;
logFactory.setOnContext = contextMiddlewareFactory.setOnContext.bind(contextMiddlewareFactory);
logFactory.configure = function(options) {
Logger.configure(options);
};
logFactory.formatter = formatter;

module.exports = logFactory;
6,030 changes: 3,359 additions & 2,671 deletions package-lock.json

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions src/formatter/debug.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use strict';

const ColorName = require('../output/color-name/color-name');
const stringifyLevel = require('../output/stringify-level/stringify-level');
const formatTime = require('../output/format-time/format-time');
const formatBody = require('../output/format-body/format-body');

module.exports = function(log) {
return [
ColorName.addColor(log.name),
stringifyLevel(log.level),
formatTime.elapsedTime(log.time),
formatBody(log)
].join(' ');
};
16 changes: 16 additions & 0 deletions src/formatter/debug.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use strict';

const debug = require('./debug');
const ColorName = require('../output/color-name/color-name');

describe('debug formatter', function() {
afterEach(function () {
ColorName.reset();
});

it('should format line', function() {
const logLine = { level: 10, time: new Date().toISOString(), name: 'redis', random: 15 };

expect(debug(logLine)).to.eql('\u001b[36mredis\u001b[39m TRACE +0ms random=15');
});
});
9 changes: 9 additions & 0 deletions src/formatter/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict';

const jsonFormatter = require('./json');
const debugFormatter = require('./debug');

module.exports = {
json: jsonFormatter,
debug: debugFormatter
};
5 changes: 5 additions & 0 deletions src/formatter/json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict';

module.exports = function(log) {
return JSON.stringify(log);
};
64 changes: 44 additions & 20 deletions src/logger/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ const config = require('../config');
const continuationLocalStorage = require('cls-hooked');
const STACK_TRACE_LIMIT = 4000;
const Timer = require('../timer/timer');
const jsonFormatter = require('../formatter/json');
const consoleOutput = require('../output/console');
const allowedKeys = ['output', 'formatter'];

const getContextStorage = function() {
const contextNamespace = continuationLocalStorage.getNamespace('session');

if (contextNamespace && contextNamespace.active) {
const { id, _ns_name, ...contextData } = contextNamespace.active;
return contextData;
Expand All @@ -16,31 +18,25 @@ const getContextStorage = function() {
return {};
};

const logMethodFactory = function(level) {
return function(action, data) {
if (!this._enabled) {
return;
}

console.log(JSON.stringify(Object.assign(
{
name: this._namespace,
action: action,
level: config.levels[level].number,
time: new Date().toISOString()
},
getContextStorage(),
data
)));
}
};

class Logger {
constructor(namespace, enabled) {
this._namespace = namespace;
this._enabled = enabled;
}

static configure(options = {}) {
this._validate(options);
Object.assign(Logger.config, options);
}

static _validate(options) {
Object.keys(options).forEach(key => {
if (!allowedKeys.includes(key)) {
throw new Error('Only the following keys are allowed: formatter, output')
}
});
}

isEnabled() {
return this._enabled;
}
Expand All @@ -64,6 +60,34 @@ class Logger {
}
}

Logger.config = {
formatter: jsonFormatter,
output: consoleOutput
};

const logMethodFactory = function(level) {
return function(action, data) {
if (!this._enabled) {
return;
}

const dataToLog = Object.assign(
{
name: this._namespace,
action: action,
level: config.levels[level].number,
time: new Date().toISOString()
},
getContextStorage(),
data
);

Logger.config.output(
Logger.config.formatter(dataToLog)
);
}
};

Logger.prototype.trace = logMethodFactory('trace');
Logger.prototype.debug = logMethodFactory('debug');
Logger.prototype.info = logMethodFactory('info');
Expand Down
46 changes: 46 additions & 0 deletions src/logger/logger.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

const Logger = require('./logger');
const continuationLocalStorage = require('cls-hooked');
const jsonFormatter = require('../formatter/json');
const consoleOutput = require('../output/console');

describe('Logger', function() {
let logger;
Expand All @@ -11,6 +13,13 @@ describe('Logger', function() {
this.sandbox.stub(console, 'log');
});

afterEach(function() {
Logger.configure({
formatter: jsonFormatter,
output: consoleOutput
});
});

it('should call log info method when enabled', function() {
logger.info('wedidit', { details: 'forever' });

Expand Down Expand Up @@ -67,4 +76,41 @@ describe('Logger', function() {
expect(logArguments.error_stack).to.eql(error.stack);
expect(logArguments.error_message).to.eql(error.message);
});

describe('#configure', function() {
it('should change format method', function() {
const formattedOutput = '{"my":"method"}';
const formatterStub = this.sandbox.stub();
formatterStub.returns(formattedOutput);

Logger.configure({
formatter: formatterStub
});
logger.info('hi');

expect(formatterStub).to.have.been.called;
expect(console.log).to.have.been.calledWith(formattedOutput);
});

it('should change output method', function() {
const outputStub = this.sandbox.stub();
Logger.configure({
output: outputStub
});
logger.info('hi');

expect(outputStub).to.have.been.called;
});

it('should throw error on invalid config', function() {
try {
Logger.configure({
invalid: true
});
throw new Error('should throw');
} catch(e) {
expect(e.message).to.eql('Only the following keys are allowed: formatter, output');
}
});
});
});
30 changes: 19 additions & 11 deletions src/output/color-name/color-name.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
'use strict';

const chalk = require('chalk');

const colors = ['cyan', 'magenta', 'grey', 'blue', 'green', 'yellow', 'white', 'red'];
const names = {};
let colorCounter = 0;

module.exports = function colorName(name) {
if (!names[name]) {
names[name] = { color: colorCounter % colors.length };
colorCounter++;
class ColorName {
static addColor(name) {
if (!this.names[name]) {
this.names[name] = { color: this.counter % colors.length };
this.counter++;
}

const color = colors[this.names[name].color];
return chalk[color](name);
}

static reset() {
this.counter = 0;
this.names = {};
}
}

const color = colors[names[name].color];
return chalk[color](name);
};
ColorName.counter = 0;
ColorName.names = {};
ColorName.colors = colors;

module.exports.colors = colors;
module.exports = ColorName;
14 changes: 9 additions & 5 deletions src/output/color-name/color-name.spec.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
'use strict';

const colorName = require('./color-name');
const ColorName = require('./color-name');

describe('colorName', function() {
afterEach(function () {
ColorName.reset();
});

it('should pick the first color for the name', function() {
expect(colorName('mongo')).to.eql('\u001b[36mmongo\u001b[39m');
expect(ColorName.addColor('mongo')).to.eql('\u001b[36mmongo\u001b[39m');
});

it('should pick the same color for same name', function() {
expect(colorName('mongo')).to.eql(colorName('mongo'));
expect(ColorName.addColor('mongo')).to.eql(ColorName.addColor('mongo'));
});

it('should add different colors for different names', function() {
const firstName = colorName('mongo');
const secondName = colorName('redis');
const firstName = ColorName.addColor('mongo');
const secondName = ColorName.addColor('redis');

expect(secondName.replace('redis', 'mongo')).not.to.eql(firstName);
});
Expand Down
5 changes: 5 additions & 0 deletions src/output/console.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict';

module.exports = function(formattedLog) {
console.log(formattedLog);
};

0 comments on commit baf8e42

Please sign in to comment.