Skip to content

Commit c07dfcf

Browse files
committed
Improved logging
- `options.logLevel` can be a string, where its value must be 'debug', 'verbose', 'info', 'warn', or 'error' - `options.log` can be an object with {debug, verbose, info, warn, error} methods - When `options.log` is a function, its second argument will be the log level of the given message - When `options.log` is undefined, the `console` methods are used by default - When `options.log` is falsy (or `options.silent` is truthy), log messages are silenced - Some log messages have been tweaked, and log levels attached - The pool master now emits an 'error' event with the associated `Error` object
1 parent 7421553 commit c07dfcf

File tree

3 files changed

+84
-43
lines changed

3 files changed

+84
-43
lines changed

lib/helper.js

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,56 @@ var termTypes = protodef.Term.TermType;
33
var datumTypes = protodef.Datum.DatumType;
44
var net = require('net');
55

6+
var logLevels = {
7+
error: 0,
8+
warn: 1,
9+
info: 2,
10+
verbose: 3,
11+
debug: 4,
12+
};
613

7-
function createLogger(poolMaster, silent) {
8-
return function(message) {
9-
if (silent !== true) {
10-
console.error(message);
14+
function createLogger(poolMaster, logLevel, logger) {
15+
var maxLevel = logLevels[logLevel];
16+
if (maxLevel === undefined) {
17+
throw new Error('Unsupported log level: ' + logLevel);
18+
}
19+
20+
var log = Function.prototype;
21+
if (logger === undefined) {
22+
log = function(level, message) {
23+
if (level === 'error') {
24+
console.error(message);
25+
} else if (level === 'warn') {
26+
console.warn(message);
27+
} else {
28+
console.log(message);
29+
}
30+
};
31+
} else if (logger) {
32+
if (typeof logger === 'function') {
33+
log = logger;
34+
} else if (typeof logger === 'object') {
35+
log = function(level, message) {
36+
logger[level](message);
37+
};
38+
} else {
39+
throw new TypeError('`options.log` must be an object or function');
1140
}
12-
poolMaster.emit('log', message);
1341
}
42+
43+
return {
44+
log: function(level, message) {
45+
if (logLevels[level] <= maxLevel) {
46+
log(level, message);
47+
poolMaster.emit('log', message, level);
48+
}
49+
},
50+
error: function(error) {
51+
log(error.stack, 'error');
52+
poolMaster.emit('log', error.stack, 'error');
53+
poolMaster.emit('error', error);
54+
}
55+
};
1456
}
1557
module.exports.createLogger = createLogger;
1658

lib/pool.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ function Pool(r, options) {
6161
}
6262
}, 0);
6363
this.id = Math.floor(Math.random()*100000);
64-
this._log('Creating a pool connected to '+this.getAddress());
64+
this._log('info', 'Creating a pool connected to: ' + this.getAddress());
6565
}
6666

6767
util.inherits(Pool, events.EventEmitter);
@@ -152,7 +152,8 @@ Pool.prototype.putConnection = function(connection) {
152152
else if (self._extraConnections > 0) {
153153
self._extraConnections--;
154154
connection.close().error(function(error) {
155-
self._log('Fail to properly close a connection. Error:'+JSON.stringify(error));
155+
self._log('debug', 'Failed to close a connection properly');
156+
self._log.error(error);
156157
});
157158
clearTimeout(connection.timeout);
158159
}
@@ -162,7 +163,8 @@ Pool.prototype.putConnection = function(connection) {
162163
// Note that because we have available connections here, the pool master has no pending
163164
// queries.
164165
connection.close().error(function(error) {
165-
self._log('Fail to properly close a connection. Error:'+JSON.stringify(error));
166+
self._log('debug', 'Failed to close a connection properly');
167+
self._log.error(error);
166168
});
167169
clearTimeout(connection.timeout);
168170
}
@@ -219,7 +221,7 @@ Pool.prototype.createConnection = function() {
219221
}
220222
// Need another flag
221223
else if ((self._slowlyGrowing === true) && (self._slowGrowth === true) && (self._consecutiveFails > 0)) {
222-
self._log('Exiting slow growth mode');
224+
self._log('info', 'Exiting slow growth mode');
223225
self._consecutiveFails = 0;
224226
self._slowGrowth = false;
225227
self._slowlyGrowing = false;
@@ -231,7 +233,8 @@ Pool.prototype.createConnection = function() {
231233
connection.on('error', function(error) {
232234
// We are going to close connection, but we don't want another process to use it before
233235
// So we remove it from the pool now (if it's inside)
234-
self._log('Error emitted by a connection: '+JSON.stringify(error));
236+
self._log('debug', 'Error emitted by a connection');
237+
self._log.error(error);
235238
for(var i=0; i<self.getAvailableLength(); i++) {
236239
if (self._pool.get(i) === this) {
237240
self._pool.delete(i);
@@ -292,12 +295,13 @@ Pool.prototype.createConnection = function() {
292295

293296
self._slowGrowth = true;
294297
if (self._slowlyGrowing === false) {
295-
self._log('Entering slow growth mode');
298+
self._log('warn', 'Entering slow growth mode');
296299
}
297300
self._slowlyGrowing = true;
298301

299302
// Log an error
300-
self._log('Fail to create a new connection for the connection pool. Error:'+JSON.stringify(error));
303+
self._log('debug', 'Failed to create a new connection');
304+
self._log.error(error);
301305

302306
if (self._openingConnections === 0) {
303307
self._consecutiveFails++;
@@ -371,7 +375,7 @@ Pool.prototype.drainLocalhost = function() {
371375
Pool.prototype.drain = function() {
372376
var self = this;
373377
self._draining = true;
374-
self._log('Draining the pool connected to '+this.getAddress());
378+
self._log('verbose', 'Draining the pool connected to: ' + this.getAddress());
375379
self.emit('draining');
376380
var p = new Promise(function(resolve, reject) {
377381
var connection = self._pool.pop();

lib/pool_master.js

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ function PoolMaster(r, options) {
2626
self._options = options;
2727
self._options.buffer = options.buffer || 50;
2828
self._options.max = options.max || 1000;
29-
self._log = helper.createLogger(self, options.silent || false);
30-
if (typeof options.log == 'function') {
31-
self.on('log', options.log);
32-
}
3329
self._draining = false;
3430
self._numConnections = 0;
3531
self._numAvailableConnections = 0;
@@ -39,6 +35,10 @@ function PoolMaster(r, options) {
3935
self._timeoutError = options.timeoutError || 1000; // How long should we wait before recreating a connection that failed?
4036
self._maxExponent = options.maxExponent || 6; // Maximum timeout is 2^maxExponent*timeoutError
4137

38+
var logger = helper.createLogger(self, options.logLevel || 'debug', options.silent ? null : options.log);
39+
self._log = logger.log;
40+
self._log.error = logger.error;
41+
4242
//TODO
4343
//self._usingPool = true; // If we have used the pool
4444
self._seed = 0;
@@ -211,13 +211,12 @@ PoolMaster.prototype.handleAllServersResponse = function(servers) {
211211
for(var i=0;i<self._pools[UNKNOWN_POOLS].length; i++) {
212212
// These pools does not match any server returned by RethinkDB.
213213
var pool = self._pools[UNKNOWN_POOLS].splice(i, 1)[0];
214-
self._log('Removing pool connected to: '+pool.getAddress())
214+
self._log('verbose', 'Removing pool connected to: ' + pool.getAddress());
215215
pool.drain().then(function() {
216216
pool.removeAllListeners();
217217
}).error(function(error) {
218-
self._log('Pool connected to: '+self._pools[UNKNOWN_POOLS][i].getAddress()+' could not be properly drained.')
219-
self._log(error.message);
220-
self._log(error.stack);
218+
self._log('debug', 'Pool failed to drain properly: ' + pool.getAddress());
219+
self._log.error(error);
221220
});
222221
}
223222
}
@@ -264,13 +263,12 @@ PoolMaster.prototype.createPool = function(server) {
264263
PoolMaster.prototype.deletePool = function(key) {
265264
var self = this;
266265
var pool = self._pools[key];
267-
self._log('Removing pool connected to: '+pool.getAddress())
266+
self._log('verbose', 'Removing pool connected to: ' + pool.getAddress());
268267
pool.drain().then(function() {
269268
pool.removeAllListeners();
270269
}).error(function(error) {
271-
self._log('Pool connected to: '+self._pools[key].getAddress()+' could not be properly drained.')
272-
self._log(error.message);
273-
self._log(error.stack);
270+
self._log('debug', 'Pool failed to drain properly: ' + pool.getAddress());
271+
self._log.error(error);
274272
});
275273
delete self._pools[key];
276274
self.resetBufferParameters();
@@ -307,9 +305,10 @@ PoolMaster.prototype.fetchServers = function(useSeeds) {
307305
self._feed = feed;
308306
var initializing = true;
309307
var servers = [];
310-
feed.each(function(err, change) {
311-
if (err) {
312-
self._log('The changefeed on server_status returned an error: '+err.toString());
308+
feed.each(function(error, change) {
309+
if (error) {
310+
self._log('debug', 'The changefeed on `server_status` returned an error');
311+
self._log.error(error);
313312
// We have to refetch everything as the server that was serving the feed may
314313
// have died.
315314
if (!self._draining) {
@@ -329,7 +328,8 @@ PoolMaster.prototype.fetchServers = function(useSeeds) {
329328
self._r.db('rethinkdb').table('server_status').run({cursor: false}).then(function(servers) {
330329
self.handleAllServersResponse(servers);
331330
}).error(function(error) {
332-
self._log('Fail to retrieve a second copy of server_status');
331+
self._log('debug', 'Failed to fetch another copy of `server_status`');
332+
self._log.error(error);
333333
//TODO Retry
334334
});
335335
}, 1000);
@@ -359,24 +359,21 @@ PoolMaster.prototype.fetchServers = function(useSeeds) {
359359
found = true;
360360

361361
(function (pool) {
362-
self._log('Removing pool connected to: '+pool.getAddress())
362+
self._log('verbose', 'Removing pool connected to: ' + pool.getAddress());
363363
var pool = self._pools[UNKNOWN_POOLS].splice(i, 1)[0];
364364
pool.drain().then(function() {
365365
pool.removeAllListeners();
366366
}).error(function(error) {
367-
if (self._options.silent !== true) {
368-
self._log('Pool connected to: '+pool.getAddress()+' could not be properly drained.')
369-
self._log(error.message);
370-
self._log(error.stack);
371-
}
367+
self._log('debug', 'Pool failed to drain properly: ' + pool.getAddress());
368+
self._log.error(error);
372369
});
373370
})(self._pools[UNKNOWN_POOLS][i]);
374371
break;
375372
}
376373
}
377374
}
378375
if (found === false) {
379-
self._log('A server was removed but no pool for this server exists...')
376+
self._log('verbose', 'Removed server has no associated pool');
380377
}
381378
}
382379
// We ignore this change since this it doesn't affect whether the server
@@ -385,8 +382,9 @@ PoolMaster.prototype.fetchServers = function(useSeeds) {
385382
});
386383
return null;
387384
}).error(function(error) {
388-
self._log('Could not retrieve the data from server_status: '+JSON.stringify(error));
389-
385+
self._log('debug', 'Failed to get data from `server_status` feed');
386+
self._log.error(error);
387+
390388
var timeout;
391389
if (self._consecutiveFails === -1) {
392390
timeout = 0;
@@ -526,11 +524,8 @@ PoolMaster.prototype.drain = function() {
526524
pools[i].removeAllListeners();
527525
}
528526
}).error(function(error) {
529-
if (self._options.silent !== true) {
530-
self._log('Failed to drain all the pools:');
531-
self._log(error.message);
532-
self._log(error.stack);
533-
}
527+
self._log('debug', 'Failed to drain all the pools');
528+
self._log.error(error);
534529
});
535530
}
536531

0 commit comments

Comments
 (0)