From a266391f1b71c52ca1a952cf4dc210d53d863216 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Mon, 13 Mar 2017 18:36:55 -0700 Subject: [PATCH] logger: truncate log files. --- lib/mining/cpuminer.js | 2 + lib/mining/miner.js | 12 +-- lib/net/pool.js | 16 +-- lib/node/logger.js | 223 +++++++++++++++++++++++++++++++++++------ lib/node/node.js | 16 +-- lib/utils/util.js | 6 +- 6 files changed, 216 insertions(+), 59 deletions(-) diff --git a/lib/mining/cpuminer.js b/lib/mining/cpuminer.js index fe47b123..07e9aedb 100644 --- a/lib/mining/cpuminer.js +++ b/lib/mining/cpuminer.js @@ -528,6 +528,7 @@ CPUJob.prototype.destroy = function destroy() { /** * Calculate number of hashes. + * @param {Number} nonce * @returns {Number} */ @@ -537,6 +538,7 @@ CPUJob.prototype.getHashes = function getHashes(nonce) { /** * Calculate hashrate. + * @param {Number} nonce * @returns {Number} */ diff --git a/lib/mining/miner.js b/lib/mining/miner.js index 1a3876b3..fd581984 100644 --- a/lib/mining/miner.js +++ b/lib/mining/miner.js @@ -210,9 +210,9 @@ Miner.prototype.updateTime = function updateTime(attempt) { * @returns {Promise} Returns {@link CPUJob}. */ -Miner.prototype.createJob = co(function* createJob(tip, address) { - return yield this.cpu.createJob(tip, address); -}); +Miner.prototype.createJob = function createJob(tip, address) { + return this.cpu.createJob(tip, address); +}; /** * Mine a single block. @@ -222,9 +222,9 @@ Miner.prototype.createJob = co(function* createJob(tip, address) { * @returns {Promise} Returns {@link Block}. */ -Miner.prototype.mineBlock = co(function* mineBlock(tip, address) { - return yield this.cpu.mineBlock(tip, address); -}); +Miner.prototype.mineBlock = function mineBlock(tip, address) { + return this.cpu.mineBlock(tip, address); +}; /** * Add an address to the address list. diff --git a/lib/net/pool.js b/lib/net/pool.js index bc2cf102..ddf0d767 100644 --- a/lib/net/pool.js +++ b/lib/net/pool.js @@ -477,16 +477,16 @@ Pool.prototype.discoverGateway = co(function* discoverGateway() { this.logger.debug('Discovering internet gateway (upnp).'); wan = yield UPNP.discover(); } catch (e) { - this.logger.debug('UPNP error:'); - this.logger.error(e); + this.logger.debug('Could not discover internet gateway (upnp).'); + this.logger.debug(e); return false; } try { host = yield wan.getExternalIP(); } catch (e) { - this.logger.debug('Could not find external IP.'); - this.logger.error(e); + this.logger.debug('Could not find external IP (upnp).'); + this.logger.debug(e); return false; } @@ -500,8 +500,8 @@ Pool.prototype.discoverGateway = co(function* discoverGateway() { try { yield wan.addPortMapping(host, src, dest); } catch (e) { - this.logger.debug('Could not add port mapping.'); - this.logger.error(e); + this.logger.debug('Could not add port mapping (upnp).'); + this.logger.debug(e); return false; } @@ -572,8 +572,8 @@ Pool.prototype.discoverExternal = co(function* discoverExternal() { try { host = yield this.getIP(); } catch (e) { - this.logger.debug('Could not find external IP.'); - this.logger.error(e); + this.logger.debug('Could not find external IP (http).'); + this.logger.debug(e); return; } diff --git a/lib/node/logger.js b/lib/node/logger.js index 4bf1a8ad..e4569315 100644 --- a/lib/node/logger.js +++ b/lib/node/logger.js @@ -10,6 +10,7 @@ var assert = require('assert'); var fs = require('../utils/fs'); var util = require('../utils/util'); var co = require('../utils/co'); +var Lock = require('../utils/lock'); /** * Basic stdout and file logger. @@ -27,9 +28,13 @@ function Logger(options) { this.level = Logger.levels.NONE; this.colors = Logger.HAS_TTY; this.console = true; + this.shrink = true; + this.closed = true; + this.closing = false; this.filename = null; this.stream = null; this.contexts = {}; + this.locker = new Lock(); this.init(options); } @@ -41,6 +46,14 @@ function Logger(options) { Logger.HAS_TTY = !!(process.stdout && process.stdout.isTTY); +/** + * Maximum file size. + * @const {Number} + * @default + */ + +Logger.MAX_FILE_SIZE = 20 << 20; + /** * Available log levels. * @enum {Number} @@ -91,7 +104,7 @@ Logger.prefixByVal = [ * @default */ -Logger.colors = [ +Logger.styles = [ '0', '1;31', '1;33', @@ -100,6 +113,23 @@ Logger.colors = [ '90' ]; +/** + * Default CSI colors for modules. + * @const {String[]} + * @default + */ + +Logger.colors = [ + '32', + '92', + '34', + '94', + '35', + '95', + '36', + '96' +]; + /** * Initialize the logger. * @private @@ -130,6 +160,11 @@ Logger.prototype.init = function init(options) { this.console = options.console; } + if (options.shrink != null) { + assert(typeof options.shrink === 'boolean'); + this.shrink = options.shrink; + } + if (options.filename != null) { assert(typeof options.filename === 'string', 'Bad file.'); this.filename = options.filename; @@ -138,35 +173,122 @@ Logger.prototype.init = function init(options) { /** * Open the logger. + * @method * @returns {Promise} */ Logger.prototype.open = co(function* open() { + var unlock = yield this.locker.lock(); + try { + return yield this._open(); + } finally { + unlock(); + } +}); + +/** + * Open the logger (no lock). + * @method + * @returns {Promise} + */ + +Logger.prototype._open = co(function* open() { if (fs.unsupported) return; if (!this.filename) return; + if (this.stream) + return; + + if (this.shrink) + yield this.truncate(); + this.stream = yield openStream(this.filename); this.stream.once('error', this.handleError.bind(this)); + this.closed = false; }); /** * Destroy the write stream. + * @method * @returns {Promise} */ Logger.prototype.close = co(function* close() { + var unlock = yield this.locker.lock(); + try { + return yield this._close(); + } finally { + unlock(); + } +}); + +/** + * Destroy the write stream (no lock). + * @method + * @returns {Promise} + */ + +Logger.prototype._close = co(function* close() { if (this.timer != null) { co.clearTimeout(this.timer); this.timer = null; } if (this.stream) { - yield closeStream(this.stream); + try { + this.closing = true; + yield closeStream(this.stream); + } finally { + this.closing = false; + } this.stream = null; } + + this.closed = true; +}); + +/** + * Truncate the log file to the last 20mb. + * @method + * @private + * @returns {Promise} + */ + +Logger.prototype.truncate = co(function* truncate() { + var maxSize = Logger.MAX_FILE_SIZE; + var stat, data, fd; + + if (!this.filename) + return; + + if (fs.unsupported) + return; + + assert(!this.stream); + + try { + stat = yield fs.stat(this.filename); + } catch (e) { + if (e.code === 'ENOENT') + return; + throw e; + } + + if (stat.size <= maxSize + (maxSize / 10)) + return; + + this.debug('Truncating log file to %d bytes.', maxSize); + + fd = yield fs.open(this.filename, 'r+'); + + data = new Buffer(maxSize); + yield fs.read(fd, data, 0, maxSize, stat.size - maxSize); + yield fs.ftruncate(fd, maxSize); + yield fs.write(fd, data, 0, maxSize, 0); + yield fs.close(fd); }); /** @@ -193,12 +315,35 @@ Logger.prototype.handleError = function handleError(err) { */ Logger.prototype.reopen = co(function* reopen() { + var unlock = yield this.locker.lock(); + try { + return yield this._reopen(); + } finally { + unlock(); + } +}); + +/** + * Try to reopen the logger (no lock). + * @method + * @private + * @returns {Promise} + */ + +Logger.prototype._reopen = co(function* reopen() { + if (this.stream) + return; + + if (this.closed) + return; + try { this.stream = yield openStream(this.filename); } catch (e) { this.retry(); return; } + this.stream.once('error', this.handleError.bind(this)); }); @@ -210,6 +355,7 @@ Logger.prototype.reopen = co(function* reopen() { */ Logger.prototype.retry = function* retry() { + assert(this.timer == null); this.timer = co.setTimeout(function() { this.timer = null; this.reopen(); @@ -399,7 +545,7 @@ Logger.prototype.context = function context(module) { Logger.prototype.writeConsole = function writeConsole(level, module, args) { var name = Logger.prefixByVal[level]; var msg = ''; - var fmt, color; + var fmt, color, ch; assert(name, 'Invalid log level.'); @@ -407,16 +553,18 @@ Logger.prototype.writeConsole = function writeConsole(level, module, args) { return; if (util.isBrowser) { - fmt = args[0]; msg += '[' + name + '] '; if (module) msg += '(' + module + ') '; - if (typeof args[0] !== 'object') - fmt = util.format(args, false); + if (typeof args[0] === 'object') { + return level === Logger.levels.ERROR + ? console.error(msg, args[0]) + : console.log(msg, args[0]); + } - msg += fmt; + msg += util.format(args, false); return level === Logger.levels.ERROR ? console.error(msg) @@ -424,20 +572,33 @@ Logger.prototype.writeConsole = function writeConsole(level, module, args) { } if (this.colors) { - color = Logger.colors[level]; + color = Logger.styles[level]; + assert(color); + msg += '\x1b[' + color + 'm'; msg += '[' + name + '] '; msg += '\x1b[m'; + + if (module) { + ch = module.charCodeAt(0) + module.length; + color = Logger.colors[ch % Logger.colors.length]; + msg += '\x1b[' + color + 'm'; + msg += '(' + module + ') '; + msg += '\x1b[m'; + } + } else { + msg += '[' + name + '] '; + + if (module) + msg += '(' + module + ') '; } - if (module) - msg += '(' + module + ') '; - msg += util.format(args, this.colors); + msg += '\n'; return level === Logger.levels.ERROR - ? process.stderr.write(msg + '\n') - : process.stdout.write(msg + '\n'); + ? process.stderr.write(msg) + : process.stdout.write(msg); }; /** @@ -449,12 +610,14 @@ Logger.prototype.writeConsole = function writeConsole(level, module, args) { Logger.prototype.writeStream = function writeStream(level, module, args) { var name = Logger.prefixByVal[level]; - var stream = this.stream; var msg = ''; assert(name, 'Invalid log level.'); - if (!stream) + if (!this.stream) + return; + + if (this.closing) return; msg += '['; @@ -468,7 +631,7 @@ Logger.prototype.writeStream = function writeStream(level, module, args) { msg += util.format(args, false); msg += '\n'; - stream.write(msg); + this.stream.write(msg); }; /** @@ -486,14 +649,16 @@ Logger.prototype.logError = function logError(level, module, err) { if (this.closed) return; - if (util.isBrowser && this.console && level >= Logger.levels.DEBUG) - console.error(err); + if (util.isBrowser && this.console) { + if (level <= Logger.levels.WARNING) + console.error(err); + } msg = (err.message + '').replace(/^ *Error: */, ''); this.log(level, module, [msg]); - if (this.level >= Logger.levels.DEBUG) { + if (level <= Logger.levels.WARNING) { if (this.stream) this.stream.write(err.stack + '\n'); } @@ -505,19 +670,15 @@ Logger.prototype.logError = function logError(level, module, err) { */ Logger.prototype.memory = function memory(module) { - var mem; + var mem = util.memoryUsage(); - if (!process.memoryUsage) - return; - - mem = process.memoryUsage(); - - this.log(Logger.levels.DEBUG, module, - ['Memory: rss=%dmb, js-heap=%d/%dmb native-heap=%dmb', - util.mb(mem.rss), - util.mb(mem.heapUsed), - util.mb(mem.heapTotal), - util.mb(mem.rss - mem.heapTotal)]); + this.log(Logger.levels.DEBUG, module, [ + 'Memory: rss=%dmb, js-heap=%d/%dmb native-heap=%dmb', + mem.total, + mem.jsHeap, + mem.jsHeapTotal, + mem.nativeHeap + ]); }; /** diff --git a/lib/node/node.js b/lib/node/node.js index 76d06465..74f00a43 100644 --- a/lib/node/node.js +++ b/lib/node/node.js @@ -74,7 +74,7 @@ Node.prototype.initOptions = function initOptions() { this.logger = config.obj('logger'); if (config.bool('log-file')) - this.logger.setFile(this.location('debug.log')); + this.logger.setFile(config.location('debug.log')); if (config.has('log-level')) this.logger.setLevel(config.str('log-level')); @@ -82,6 +82,9 @@ Node.prototype.initOptions = function initOptions() { if (config.has('log-console')) this.logger.console = config.bool('log-console'); + if (config.bool('debug')) + this.logger.shrink = false; + this.logger = this.logger.context('node'); }; @@ -251,17 +254,6 @@ Node.prototype.error = function error(err) { this.emit('error', err); }; -/** - * Create a file path from a name - * as well as the node's prefix. - * @param {String} name - * @returns {String} - */ - -Node.prototype.location = function location(name) { - return this.config.prefix + '/' + name; -}; - /** * Get node uptime in seconds. * @returns {Number} diff --git a/lib/utils/util.js b/lib/utils/util.js index 16607dc5..b5f8bed9 100644 --- a/lib/utils/util.js +++ b/lib/utils/util.js @@ -1051,7 +1051,8 @@ util.memoryUsage = function memoryUsage() { total: 0, jsHeap: 0, jsHeapTotal: 0, - nativeHeap: 0 + nativeHeap: 0, + external: 0 }; } @@ -1061,6 +1062,7 @@ util.memoryUsage = function memoryUsage() { total: util.mb(mem.rss), jsHeap: util.mb(mem.heapUsed), jsHeapTotal: util.mb(mem.heapTotal), - nativeHeap: util.mb(mem.rss - mem.heapTotal) + nativeHeap: util.mb(mem.rss - mem.heapTotal), + external: util.mb(mem.external) }; };