Skip to content

Commit ba2ab12

Browse files
committed
feat(timer): add timer to logger, same api as logger
1 parent 41413cf commit ba2ab12

File tree

7 files changed

+93
-17
lines changed

7 files changed

+93
-17
lines changed

index.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use strict';
22

33
const Logger = require('./src/logger/logger');
4-
const Timer = require('./src/timer/timer');
54
const isNamespaceEnabled = require('./src/enabled/enabled');
65
const contextMiddlewareFactory = require('./src/context-middleware-factory/context-middleware-factory');
76

@@ -17,7 +16,6 @@ function logFactory(namespace, options) {
1716
}
1817

1918
logFactory.Logger = Logger;
20-
logFactory.Timer = Timer;
2119
logFactory.getNamespaces = function() {
2220
return process.env.DEBUG || '';
2321
};

src/index.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ describe('LogFactory', function() {
1616
const logger = logFactory('mongo');
1717

1818
expect(logger).to.be.an.instanceOf(Logger);
19-
expect(logger.enabled).to.be.true;
19+
expect(logger.isEnabled()).to.be.true;
2020
});
2121

2222
it('should return a disabled log instance when different', function() {
2323
const logger = logFactory('redis');
2424

2525
expect(logger).to.be.an.instanceOf(Logger);
26-
expect(logger.enabled).to.be.false;
26+
expect(logger.isEnabled()).to.be.false;
2727
});
2828

2929
it('should be mockable through public interface', function() {

src/logger/logger.js

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,51 @@ const config = require('../config');
44
const continuationLocalStorage = require('cls-hooked');
55
const _ = require('lodash');
66
const STACK_TRACE_LIMIT = 4000;
7+
const Timer = require('../timer/timer');
78

89
const logMethodFactory = function(level) {
910
return function(action, data) {
10-
if (!this.enabled) {
11+
if (!this._enabled) {
1112
return;
1213
}
1314

14-
const namespace = continuationLocalStorage.getNamespace('session');
15-
const storage = (namespace && namespace.active) ? _.omit(namespace.active, 'id', '_ns_name') : {};
15+
const contextNamespace = continuationLocalStorage.getNamespace('session');
16+
const contextStorage = (contextNamespace && contextNamespace.active) ?
17+
_.omit(contextNamespace.active, 'id', '_ns_name') : {};
1618

1719
console.log(JSON.stringify(Object.assign(
1820
{
19-
name: this.namespace,
21+
name: this._namespace,
2022
action: action,
2123
level: config.levels[level].number,
2224
time: new Date().toISOString()
2325
},
24-
storage,
26+
contextStorage,
2527
data
2628
)));
2729
}
2830
};
2931

3032
class Logger {
3133
constructor(namespace, enabled) {
32-
this.namespace = namespace;
33-
this.enabled = enabled;
34+
this._namespace = namespace;
35+
this._enabled = enabled;
3436
}
3537

36-
fromError(action, error, options = {}) {
38+
isEnabled() {
39+
return this._enabled;
40+
}
41+
42+
fromError(action, error, data = {}) {
3743
this.error(action, Object.assign({
3844
error_name: error.name,
3945
error_stack: this._shortenStackTrace(error),
4046
error_message: error.message
41-
}, options));
47+
}, data));
48+
}
49+
50+
timer() {
51+
return new Timer(this);
4252
}
4353

4454
_shortenStackTrace(error) {

src/logger/logger.spec.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ describe('Logger', function() {
4141
expect(console.log).not.to.have.been.called;
4242
});
4343

44+
it('should not call log info method when disabled', function() {
45+
logger = new Logger('mongo', false);
46+
const timer = logger.timer();
47+
const infoStub = this.sandbox.stub(logger, 'info');
48+
49+
this.clock.tick(100);
50+
timer.info('hi');
51+
52+
expect(infoStub).to.have.been.calledWith('hi', { duration: 100 });
53+
});
54+
4455
it('should log error with action', function() {
4556
const error = new Error('failed');
4657

src/setup.spec.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ global.expect = chai.expect;
1010

1111
beforeEach(function () {
1212
this.sandbox = sinon.sandbox.create();
13+
this.clock = sinon.useFakeTimers();
1314
});
1415

1516
afterEach(function () {
1617
this.sandbox.restore();
1718
this.sandbox = undefined;
19+
this.clock.restore();
20+
this.clock = undefined;
1821
});

src/timer/timer.js

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,40 @@
11
'use strict';
22

3+
const logMethodFactory = function(level) {
4+
return function(action, data) {
5+
this._logger[level](
6+
action,
7+
Object.assign({ duration: this._duration() }, data)
8+
);
9+
}
10+
};
11+
312
class Timer {
4-
constructor() {
5-
this.start = new Date().getTime();
13+
constructor(logger) {
14+
this._logger = logger;
15+
this._start = new Date().getTime();
616
}
717

8-
elapsedTime() {
18+
fromError(action, error, data = {}) {
19+
this._logger.fromError(
20+
action,
21+
error,
22+
Object.assign({ duration: this._duration() }, data)
23+
);
24+
}
25+
26+
_duration() {
927
const end = new Date().getTime();
1028

11-
return end - this.start;
29+
return end - this._start;
1230
}
1331
}
1432

33+
Timer.prototype.trace = logMethodFactory('trace');
34+
Timer.prototype.debug = logMethodFactory('debug');
35+
Timer.prototype.info = logMethodFactory('info');
36+
Timer.prototype.warn = logMethodFactory('warn');
37+
Timer.prototype.error = logMethodFactory('error');
38+
Timer.prototype.fatal = logMethodFactory('fatal');
39+
1540
module.exports = Timer;

src/timer/timer.spec.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
'use strict';
2+
3+
const Logger = require('../logger/logger');
4+
const Timer = require('./timer');
5+
6+
describe('Timer', function() {
7+
it('should log elapsed time', function() {
8+
const logger = new Logger('test', false);
9+
const infoStub = this.sandbox.stub(logger, 'info');
10+
const timer = new Timer(logger);
11+
12+
this.clock.tick(100);
13+
timer.info('time', { customer_id: 10 });
14+
15+
expect(infoStub).to.have.been. calledWith('time', { customer_id: 10, duration: 100 });
16+
});
17+
18+
it('should log elapsed time with error', function() {
19+
const logger = new Logger('test', false);
20+
const errorStub = this.sandbox.stub(logger, 'fromError');
21+
const timer = new Timer(logger);
22+
const error = new Error('intended');
23+
24+
this.clock.tick(100);
25+
timer.fromError('time', error, { customer_id: 10 });
26+
27+
expect(errorStub).to.have.been. calledWith('time', error, { customer_id: 10, duration: 100 });
28+
});
29+
});

0 commit comments

Comments
 (0)