From 15e677e9f1a2ba46fac0cf6d052233d8a0c3a486 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 28 Jun 2017 18:30:37 +0200 Subject: [PATCH] Refactor stream logger to keep streams as state --- build/actions/build.js | 6 ++-- build/actions/deploy.js | 32 ++++++++++----------- build/utils/docker.js | 21 +++++++------- build/utils/logger.js | 60 +++++++++++++++++++++++++++++++++++++++ lib/actions/build.coffee | 4 +-- lib/actions/deploy.coffee | 31 +++++++++----------- lib/utils/docker.coffee | 20 ++++++------- lib/utils/logger.coffee | 44 ++++++++++++++++++++++++++++ lib/utils/logging.coffee | 45 ----------------------------- 9 files changed, 157 insertions(+), 106 deletions(-) create mode 100644 build/utils/logger.js create mode 100644 lib/utils/logger.coffee delete mode 100644 lib/utils/logging.coffee diff --git a/build/actions/build.js b/build/actions/build.js index e2ea7d98..6ea4bbbd 100644 --- a/build/actions/build.js +++ b/build/actions/build.js @@ -43,8 +43,8 @@ module.exports = { } ]), action: function(params, options, done) { - var logging; - logging = require('../utils/logging'); - return dockerUtils.runBuild(params, options, getBundleInfo, logging.getLogStreams()).asCallback(done); + var Logger; + Logger = require('../utils/logger'); + return dockerUtils.runBuild(params, options, getBundleInfo, new Logger()).asCallback(done); } }; diff --git a/build/actions/deploy.js b/build/actions/deploy.js index ed091caa..0efaccab 100644 --- a/build/actions/deploy.js +++ b/build/actions/deploy.js @@ -79,7 +79,7 @@ getBundleInfo = function(options) { }); }; -performUpload = function(imageStream, token, username, url, appName, logStreams) { +performUpload = function(imageStream, token, username, url, appName, logger) { var progressBar, progressStream, request, streamWithProgress, uploadRequest, zlib; request = require('request'); progressStream = require('progress-stream'); @@ -108,7 +108,7 @@ performUpload = function(imageStream, token, username, url, appName, logStreams) level: 6 })) }); - return uploadToPromise(uploadRequest, logStreams); + return uploadToPromise(uploadRequest, logger); }; uploadLogs = function(logs, token, url, buildId, username, appName) { @@ -124,20 +124,18 @@ uploadLogs = function(logs, token, url, buildId, username, appName) { }); }; -uploadToPromise = function(uploadRequest, logStreams) { - var logging; - logging = require('../utils/logging'); +uploadToPromise = function(uploadRequest, logger) { return new Promise(function(resolve, reject) { var handleMessage; handleMessage = function(data) { var e, obj; data = data.toString(); - logging.logDebug(logStreams, "Received data: " + data); + logger.logDebug("Received data: " + data); try { obj = JSON.parse(data); } catch (error) { e = error; - logging.logError(logStreams, 'Error parsing reply from remote side'); + logger.logError('Error parsing reply from remote side'); reject(e); return; } @@ -148,7 +146,7 @@ uploadToPromise = function(uploadRequest, logStreams) { case 'success': return resolve(obj); case 'status': - return logging.logInfo(logStreams, "Remote: " + obj.message); + return logger.logInfo("Remote: " + obj.message); default: return reject(new Error("Received unexpected reply from remote: " + data)); } @@ -183,13 +181,13 @@ module.exports = { } ]), action: function(params, options, done) { - var _, logStreams, logging, logs, resin, tmp, tmpNameAsync, upload; + var Logger, _, logger, logs, resin, tmp, tmpNameAsync, upload; _ = require('lodash'); tmp = require('tmp'); tmpNameAsync = Promise.promisify(tmp.tmpName); resin = require('resin-sdk-preconfigured'); - logging = require('../utils/logging'); - logStreams = logging.getLogStreams(); + Logger = require('../utils/logger'); + logger = new Logger(); tmp.setGracefulCleanup(); logs = ''; upload = function(token, username, url) { @@ -206,7 +204,7 @@ module.exports = { }); return Promise["try"](function() { if (build) { - return dockerUtils.runBuild(params, options, getBundleInfo, logStreams); + return dockerUtils.runBuild(params, options, getBundleInfo, logger); } else { return { image: imageName, @@ -216,9 +214,9 @@ module.exports = { }).then(function(arg1) { var buildLogs, imageName; imageName = arg1.image, buildLogs = arg1.log; - logging.logInfo(logStreams, 'Initializing deploy...'); + logger.logInfo('Initializing deploy...'); logs = buildLogs; - return Promise.all([dockerUtils.bufferImage(docker, imageName, bufferFile), token, username, url, params.appName, logStreams]).spread(performUpload); + return Promise.all([dockerUtils.bufferImage(docker, imageName, bufferFile), token, username, url, params.appName, logger]).spread(performUpload); })["finally"](function() { return Promise["try"](function() { return require('mz/fs').unlink(bufferFile); @@ -228,7 +226,7 @@ module.exports = { }).tap(function(arg) { var buildId, imageName; imageName = arg.image, buildId = arg.buildId; - logging.logSuccess(logStreams, "Successfully deployed image: " + (formatImageName(imageName))); + logger.logSuccess("Successfully deployed image: " + (formatImageName(imageName))); return buildId; }).then(function(arg) { var buildId, imageName; @@ -236,11 +234,11 @@ module.exports = { if (logs === '' || (options.nologupload != null)) { return ''; } - logging.logInfo(logStreams, 'Uploading logs to dashboard...'); + logger.logInfo('Uploading logs to dashboard...'); return Promise.join(logs, token, url, buildId, username, params.appName, uploadLogs)["return"]('Successfully uploaded logs'); }).then(function(msg) { if (msg !== '') { - return logging.logSuccess(logStreams, msg); + return logger.logSuccess(msg); } }).asCallback(done); }); diff --git a/build/utils/docker.js b/build/utils/docker.js index beef09de..ba9c0b4f 100644 --- a/build/utils/docker.js +++ b/build/utils/docker.js @@ -171,8 +171,8 @@ parseBuildArgs = function(args, onError) { return buildArgs; }; -exports.runBuild = function(params, options, getBundleInfo, logStreams) { - var Promise, dockerBuild, doodles, es, logging, logs, path, qemuPath, resolver, transpose; +exports.runBuild = function(params, options, getBundleInfo, logger) { + var Promise, dockerBuild, doodles, es, logs, path, qemuPath, resolver, transpose; Promise = require('bluebird'); dockerBuild = require('resin-docker-build'); resolver = require('resin-bundle-resolve'); @@ -180,7 +180,6 @@ exports.runBuild = function(params, options, getBundleInfo, logStreams) { doodles = require('resin-doodles'); transpose = require('docker-qemu-transpose'); path = require('path'); - logging = require('../utils/logging'); if (params.source == null) { params.source = '.'; } @@ -192,7 +191,7 @@ exports.runBuild = function(params, options, getBundleInfo, logStreams) { } return hasQemu().then(function(present) { if (!present) { - logging.logInfo(logStreams, 'Installing qemu for ARM emulation...'); + logger.logInfo('Installing qemu for ARM emulation...'); return installQemu(); } }).then(function() { @@ -224,18 +223,18 @@ exports.runBuild = function(params, options, getBundleInfo, logStreams) { buildStream: function(stream) { var buildThroughStream, logThroughStream, newStream; if (options.emulated) { - logging.logInfo(logStreams, 'Running emulated build'); + logger.logInfo('Running emulated build'); } getBundleInfo(options).then(function(info) { var arch, bundle, deviceType; if (info == null) { - logging.logWarn(logStreams, 'Warning: No architecture/device type or application information provided.\n Dockerfile/project pre-processing will not be performed.'); + logger.logWarn('Warning: No architecture/device type or application information provided.\n Dockerfile/project pre-processing will not be performed.'); return tarStream; } else { arch = info[0], deviceType = info[1]; bundle = new resolver.Bundle(tarStream, deviceType, arch); return resolver.resolveBundle(bundle, resolver.getDefaultResolvers()).then(function(resolved) { - logging.logInfo(logStreams, "Building " + resolved.projectType + " project"); + logger.logInfo("Building " + resolved.projectType + " project"); return resolved.tarStream; }); } @@ -264,13 +263,13 @@ exports.runBuild = function(params, options, getBundleInfo, logStreams) { } else { newStream = stream; } - return newStream.pipe(logThroughStream).pipe(cacheHighlightStream()).pipe(logStreams.build); + return newStream.pipe(logThroughStream).pipe(cacheHighlightStream()).pipe(logger.streams.build); } }; return generateConnectOpts(options).then(function(connectOpts) { var builder, opts; - logging.logDebug(logStreams, 'Connecting with the following options:'); - logging.logDebug(logStreams, JSON.stringify(connectOpts, null, ' ')); + logger.logDebug('Connecting with the following options:'); + logger.logDebug(JSON.stringify(connectOpts, null, ' ')); builder = new dockerBuild.Builder(connectOpts); opts = {}; if (options.tag != null) { @@ -281,7 +280,7 @@ exports.runBuild = function(params, options, getBundleInfo, logStreams) { } if (options.buildArg != null) { opts['buildargs'] = parseBuildArgs(options.buildArg, function(arg) { - return logging.logWarn(logStreams, "Could not parse variable: '" + arg + "'"); + return logger.logWarn("Could not parse variable: '" + arg + "'"); }); } if (options.squash != null) { diff --git a/build/utils/logger.js b/build/utils/logger.js new file mode 100644 index 00000000..31a76d21 --- /dev/null +++ b/build/utils/logger.js @@ -0,0 +1,60 @@ +// Generated by CoffeeScript 1.12.6 +var Logger, eol; + +eol = require('os').EOL; + +module.exports = Logger = (function() { + function Logger() { + var StreamLogger, _, colors, logger; + StreamLogger = require('resin-stream-logger').StreamLogger; + colors = require('colors'); + _ = require('lodash'); + logger = new StreamLogger(); + logger.addPrefix('build', colors.blue('[Build]')); + logger.addPrefix('info', colors.cyan('[Info]')); + logger.addPrefix('debug', colors.magenta('[Debug]')); + logger.addPrefix('success', colors.green('[Success]')); + logger.addPrefix('warn', colors.yellow('[Warn]')); + logger.addPrefix('error', colors.red('[Error]')); + this.streams = { + build: logger.createLogStream('build'), + info: logger.createLogStream('info'), + debug: logger.createLogStream('debug'), + success: logger.createLogStream('success'), + warn: logger.createLogStream('warn'), + error: logger.createLogStream('error') + }; + _.mapKeys(this.streams, function(stream, key) { + if (key !== 'debug') { + return stream.pipe(process.stdout); + } else { + if (process.env.DEBUG != null) { + return stream.pipe(process.stdout); + } + } + }); + } + + Logger.prototype.logInfo = function(msg) { + return this.streams.info.write(msg + eol); + }; + + Logger.prototype.logDebug = function(msg) { + return this.streams.debug.write(msg + eol); + }; + + Logger.prototype.logSuccess = function(msg) { + return this.streams.success.write(msg + eol); + }; + + Logger.prototype.logWarn = function(msg) { + return this.streams.warn.write(msg + eol); + }; + + Logger.prototype.logError = function(msg) { + return this.streams.error.write(msg + eol); + }; + + return Logger; + +})(); diff --git a/lib/actions/build.coffee b/lib/actions/build.coffee index c0a355fe..4bc6bba6 100644 --- a/lib/actions/build.coffee +++ b/lib/actions/build.coffee @@ -58,7 +58,7 @@ module.exports = }, ] action: (params, options, done) -> - logging = require('../utils/logging') - dockerUtils.runBuild(params, options, getBundleInfo, logging.getLogStreams()) + Logger = require('../utils/logger') + dockerUtils.runBuild(params, options, getBundleInfo, new Logger()) .asCallback(done) diff --git a/lib/actions/deploy.coffee b/lib/actions/deploy.coffee index 7f8a90d5..d4d7c747 100644 --- a/lib/actions/deploy.coffee +++ b/lib/actions/deploy.coffee @@ -50,7 +50,7 @@ getBundleInfo = (options) -> .then (app) -> [app.arch, app.device_type] -performUpload = (imageStream, token, username, url, appName, logStreams) -> +performUpload = (imageStream, token, username, url, appName, logger) -> request = require('request') progressStream = require('progress-stream') zlib = require('zlib') @@ -74,7 +74,7 @@ performUpload = (imageStream, token, username, url, appName, logStreams) -> level: 6 })) - uploadToPromise(uploadRequest, logStreams) + uploadToPromise(uploadRequest, logger) uploadLogs = (logs, token, url, buildId, username, appName) -> request = require('request') @@ -85,19 +85,17 @@ uploadLogs = (logs, token, url, buildId, username, appName) -> bearer: token body: Buffer.from(logs) -uploadToPromise = (uploadRequest, logStreams) -> - logging = require('../utils/logging') - +uploadToPromise = (uploadRequest, logger) -> new Promise (resolve, reject) -> handleMessage = (data) -> data = data.toString() - logging.logDebug(logStreams, "Received data: #{data}") + logger.logDebug("Received data: #{data}") try obj = JSON.parse(data) catch e - logging.logError(logStreams, 'Error parsing reply from remote side') + logger.logError('Error parsing reply from remote side') reject(e) return @@ -105,7 +103,7 @@ uploadToPromise = (uploadRequest, logStreams) -> switch obj.type when 'error' then reject(new Error("Remote error: #{obj.error}")) when 'success' then resolve(obj) - when 'status' then logging.logInfo(logStreams, "Remote: #{obj.message}") + when 'status' then logger.logInfo("Remote: #{obj.message}") else reject(new Error("Received unexpected reply from remote: #{data}")) else reject(new Error("Received unexpected reply from remote: #{data}")) @@ -155,9 +153,8 @@ module.exports = tmpNameAsync = Promise.promisify(tmp.tmpName) resin = require('resin-sdk-preconfigured') - logging = require('../utils/logging') - - logStreams = logging.getLogStreams() + Logger = require('../utils/logger') + logger = new Logger() # Ensure the tmp files gets deleted tmp.setGracefulCleanup() @@ -179,11 +176,11 @@ module.exports = Promise.try -> if build - dockerUtils.runBuild(params, options, getBundleInfo, logStreams) + dockerUtils.runBuild(params, options, getBundleInfo, logger) else { image: imageName, log: '' } .then ({ image: imageName, log: buildLogs }) -> - logging.logInfo(logStreams, 'Initializing deploy...') + logger.logInfo('Initializing deploy...') logs = buildLogs Promise.all [ @@ -192,7 +189,7 @@ module.exports = username url params.appName - logStreams + logger ] .spread(performUpload) .finally -> @@ -203,13 +200,13 @@ module.exports = require('mz/fs').unlink(bufferFile) .catch(_.noop) .tap ({ image: imageName, buildId }) -> - logging.logSuccess(logStreams, "Successfully deployed image: #{formatImageName(imageName)}") + logger.logSuccess("Successfully deployed image: #{formatImageName(imageName)}") return buildId .then ({ image: imageName, buildId }) -> if logs is '' or options.nologupload? return '' - logging.logInfo(logStreams, 'Uploading logs to dashboard...') + logger.logInfo('Uploading logs to dashboard...') Promise.join( logs @@ -222,7 +219,7 @@ module.exports = ) .return('Successfully uploaded logs') .then (msg) -> - logging.logSuccess(logStreams, msg) if msg isnt '' + logger.logSuccess(msg) if msg isnt '' .asCallback(done) Promise.join( diff --git a/lib/utils/docker.coffee b/lib/utils/docker.coffee index 8f246f0e..2f8c8391 100644 --- a/lib/utils/docker.coffee +++ b/lib/utils/docker.coffee @@ -174,7 +174,7 @@ parseBuildArgs = (args, onError) -> # Pass in the command line parameters and options and also # a function which will return the information about the bundle -exports.runBuild = (params, options, getBundleInfo, logStreams) -> +exports.runBuild = (params, options, getBundleInfo, logger) -> Promise = require('bluebird') dockerBuild = require('resin-docker-build') @@ -184,8 +184,6 @@ exports.runBuild = (params, options, getBundleInfo, logStreams) -> transpose = require('docker-qemu-transpose') path = require('path') - logging = require('../utils/logging') - # The default build context is the current directory params.source ?= '.' logs = '' @@ -198,7 +196,7 @@ exports.runBuild = (params, options, getBundleInfo, logStreams) -> hasQemu() .then (present) -> if !present - logging.logInfo(logStreams, 'Installing qemu for ARM emulation...') + logger.logInfo('Installing qemu for ARM emulation...') installQemu() .then -> # Copy the qemu binary into the build context @@ -226,12 +224,12 @@ exports.runBuild = (params, options, getBundleInfo, logStreams) -> buildFailure: reject buildStream: (stream) -> if options.emulated - logging.logInfo(logStreams, 'Running emulated build') + logger.logInfo('Running emulated build') getBundleInfo(options) .then (info) -> if !info? - logging.logWarn logStreams, ''' + logger.logWarn ''' Warning: No architecture/device type or application information provided. Dockerfile/project pre-processing will not be performed. ''' @@ -242,7 +240,7 @@ exports.runBuild = (params, options, getBundleInfo, logStreams) -> bundle = new resolver.Bundle(tarStream, deviceType, arch) resolver.resolveBundle(bundle, resolver.getDefaultResolvers()) .then (resolved) -> - logging.logInfo(logStreams, "Building #{resolved.projectType} project") + logger.logInfo("Building #{resolved.projectType} project") return resolved.tarStream .then (buildStream) -> @@ -275,15 +273,15 @@ exports.runBuild = (params, options, getBundleInfo, logStreams) -> newStream .pipe(logThroughStream) .pipe(cacheHighlightStream()) - .pipe(logStreams.build) + .pipe(logger.streams.build) # Create a builder generateConnectOpts(options) .then (connectOpts) -> # Allow degugging output, hidden behind an env var - logging.logDebug(logStreams, 'Connecting with the following options:') - logging.logDebug(logStreams, JSON.stringify(connectOpts, null, ' ')) + logger.logDebug('Connecting with the following options:') + logger.logDebug(JSON.stringify(connectOpts, null, ' ')) builder = new dockerBuild.Builder(connectOpts) opts = {} @@ -294,7 +292,7 @@ exports.runBuild = (params, options, getBundleInfo, logStreams) -> opts['nocache'] = true if options.buildArg? opts['buildargs'] = parseBuildArgs options.buildArg, (arg) -> - logging.logWarn(logStreams, "Could not parse variable: '#{arg}'") + logger.logWarn("Could not parse variable: '#{arg}'") if options.squash? opts['squash'] = true diff --git a/lib/utils/logger.coffee b/lib/utils/logger.coffee new file mode 100644 index 00000000..1ff104a0 --- /dev/null +++ b/lib/utils/logger.coffee @@ -0,0 +1,44 @@ +eol = require('os').EOL + +module.exports = class Logger + constructor: -> + { StreamLogger } = require('resin-stream-logger') + colors = require('colors') + _ = require('lodash') + + logger = new StreamLogger() + logger.addPrefix('build', colors.blue('[Build]')) + logger.addPrefix('info', colors.cyan('[Info]')) + logger.addPrefix('debug', colors.magenta('[Debug]')) + logger.addPrefix('success', colors.green('[Success]')) + logger.addPrefix('warn', colors.yellow('[Warn]')) + logger.addPrefix('error', colors.red('[Error]')) + + @streams = + build: logger.createLogStream('build'), + info: logger.createLogStream('info'), + debug: logger.createLogStream('debug'), + success: logger.createLogStream('success'), + warn: logger.createLogStream('warn'), + error: logger.createLogStream('error') + + _.mapKeys @streams, (stream, key) -> + if key isnt 'debug' + stream.pipe(process.stdout) + else + stream.pipe(process.stdout) if process.env.DEBUG? + + logInfo: (msg) -> + @streams.info.write(msg + eol) + + logDebug: (msg) -> + @streams.debug.write(msg + eol) + + logSuccess: (msg) -> + @streams.success.write(msg + eol) + + logWarn: (msg) -> + @streams.warn.write(msg + eol) + + logError: (msg) -> + @streams.error.write(msg + eol) diff --git a/lib/utils/logging.coffee b/lib/utils/logging.coffee deleted file mode 100644 index 271e8e22..00000000 --- a/lib/utils/logging.coffee +++ /dev/null @@ -1,45 +0,0 @@ -eol = require('os').EOL - -exports.getLogStreams = -> - { StreamLogger } = require('resin-stream-logger') - colors = require('colors') - _ = require('lodash') - - logger = new StreamLogger() - logger.addPrefix('build', colors.blue('[Build]')) - logger.addPrefix('info', colors.cyan('[Info]')) - logger.addPrefix('debug', colors.magenta('[Debug]')) - logger.addPrefix('success', colors.green('[Success]')) - logger.addPrefix('warn', colors.yellow('[Warn]')) - logger.addPrefix('error', colors.red('[Error]')) - - streams = - build: logger.createLogStream('build'), - info: logger.createLogStream('info'), - debug: logger.createLogStream('debug'), - success: logger.createLogStream('success'), - warn: logger.createLogStream('warn'), - error: logger.createLogStream('error') - - _.mapKeys streams, (stream, key) -> - if key isnt 'debug' - stream.pipe(process.stdout) - else - stream.pipe(process.stdout) if process.env.DEBUG? - - streams - -exports.logInfo = (logStreams, msg) -> - logStreams.info.write(msg + eol) - -exports.logDebug = (logStreams, msg) -> - logStreams.debug.write(msg + eol) - -exports.logSuccess = (logStreams, msg) -> - logStreams.success.write(msg + eol) - -exports.logWarn = (logStreams, msg) -> - logStreams.warn.write(msg + eol) - -exports.logError = (logStreams, msg) -> - logStreams.error.write(msg + eol)