Update winston logger
MODIFY
lib/logsink.js
lib/logsink.js
import npmlog from 'npmlog';
-import winston from 'winston';
+import { createLogger, format, transports } from 'winston';
import { fs, logger } from 'appium-support';
import dateformat from 'dateformat';
import _ from 'lodash';
+
// set up distributed logging before everything else
logger.patchLogger(npmlog);
global._global_npmlog = npmlog;
@@ -37,127 +38,138 @@ const npmToWinstonLevels = {
let log = null;
let timeZone = null;
-function timestamp () {
+// add the timestamp in the correct format to the log info object
+const timestampFormat = format.timestamp({
+ format () {
let date = new Date();
if (!timeZone) {
date = new Date(date.valueOf() + date.getTimezoneOffset() * 60000);
}
- return dateformat(date, "yyyy-mm-dd HH:MM:ss:l");
-}
+ return dateformat(date, 'yyyy-mm-dd HH:MM:ss:l');
+ },
+});
+
+// set the custom colors
+const colorizeFormat = format.colorize({
+ colors,
+});
-// Strip the color marking within messages.
-// We need to patch the transports, because the stripColor functionality in
-// Winston is wrongly implemented at the logger level, and we want to avoid
-// having to create 2 loggers.
-function applyStripColorPatch (transport) {
- let _log = transport.log.bind(transport);
- transport.log = function (level, msg, meta, callback) { // eslint-disable-line promise/prefer-await-to-callbacks
+// Strip the color marking within messages
+const stripColorFormat = format(function (info) {
const code = /\u001b\[(\d+(;\d+)*)?m/g; // eslint-disable-line no-control-regex
- msg = ('' + msg).replace(code, '');
- _log(level, msg, meta, callback);
- };
-}
+ info.message = info.message.replace(code, '');
+ return info;
+})();
-function _createConsoleTransport (args, logLvl) {
- let transport = new (winston.transports.Console)({
- name: "console",
- timestamp: args.logTimestamp ? timestamp : undefined,
- colorize: !args.logNoColors,
+function createConsoleTransport (args, logLvl) {
+ return new (transports.Console)({
+ name: 'console',
handleExceptions: true,
exitOnError: false,
json: false,
level: logLvl,
- formatter (options) {
- let meta = options.meta && Object.keys(options.meta).length ? `\n\t${JSON.stringify(options.meta)}` : '';
- let timestampPrefix = '';
- if (options.timestamp) {
- timestampPrefix = `${options.timestamp()} - `;
- }
- return `${timestampPrefix}${options.message || ''}${meta}`;
- }
+ stderrLevels: ['error'],
+ format: format.combine(
+ format(function (info) {
+ // prepend debug marker, and shift to `info` log level
+ if (info.level === 'debug') {
+ info.level = 'info';
+ info.message = `[debug] ${info.message}`;
+ }
+ return info;
+ })(),
+ timestampFormat,
+ colorizeFormat,
+ format.printf(function (info) {
+ return `${args.logTimestamp ? `${info.timestamp} - ` : ''}${info.message}`;
+ })
+ ),
});
- if (args.logNoColors) {
- applyStripColorPatch(transport);
}
- return transport;
-}
-
-function _createFileTransport (args, logLvl) {
- let transport = new (winston.transports.File)({
- name: "file",
- timestamp,
- filename: args.log,
+function createFileTransport (args, logLvl) {
+ return new (transports.File)({
+ name: 'file',
+ filename: args.logFile,
maxFiles: 1,
handleExceptions: true,
exitOnError: false,
json: false,
level: logLvl,
+ format: format.combine(
+ stripColorFormat,
+ timestampFormat,
+ format.printf(function (info) {
+ return `${info.timestamp} ${info.message}`;
+ })
+ )
});
- applyStripColorPatch(transport);
- return transport;
}
-function _createHttpTransport (args, logLvl) {
- let host = null,
- port = null;
+function createHttpTransport (args, logLvl) {
+ let host = '127.0.0.1';
+ let port = 9003;
if (args.webhook.match(':')) {
- let hostAndPort = args.webhook.split(':');
+ const hostAndPort = args.webhook.split(':');
host = hostAndPort[0];
port = parseInt(hostAndPort[1], 10);
}
- let transport = new (winston.transports.Http)({
- name: "http",
- host: host || '127.0.0.1',
- port: port || 9003,
+ return new (transports.Http)({
+ name: 'http',
+ host,
+ port,
path: '/',
handleExceptions: true,
exitOnError: false,
json: false,
level: logLvl,
+ format: format.combine(
+ stripColorFormat,
+ format.printf(function (info) {
+ return `${info.timestamp} ${info.message}`;
+ })
+ ),
});
- applyStripColorPatch(transport);
- return transport;
}
-async function _createTransports (args) {
+async function createTransports (args) {
let transports = [];
let consoleLogLevel = null;
let fileLogLevel = null;
- if (args.loglevel && args.loglevel.match(":")) {
+ if (args.loglevel && args.loglevel.match(':')) {
// --log-level arg can optionally provide diff logging levels for console and file, separated by a colon
- let lvlPair = args.loglevel.split(':');
+ const lvlPair = args.loglevel.split(':');
consoleLogLevel = lvlPair[0] || consoleLogLevel;
fileLogLevel = lvlPair[1] || fileLogLevel;
} else {
consoleLogLevel = fileLogLevel = args.loglevel;
}
- transports.push(_createConsoleTransport(args, consoleLogLevel));
+ transports.push(createConsoleTransport(args, consoleLogLevel));
- if (args.log) {
+ if (args.logFile) {
try {
// if we don't delete the log file, winston will always append and it will grow infinitely large;
// winston allows for limiting log file size, but as of 9.2.14 there's a serious bug when using
// maxFiles and maxSize together. https://github.com/flatiron/winston/issues/397
- if (await fs.exists(args.log)) {
- await fs.unlink(args.log);
+ if (await fs.exists(args.logFile)) {
+ await fs.unlink(args.logFile);
}
- transports.push(_createFileTransport(args, fileLogLevel));
+ transports.push(createFileTransport(args, fileLogLevel));
} catch (e) {
// eslint-disable-next-line no-console
- console.log(`Tried to attach logging to file ${args.log} but an error ` +
+ console.log(`Tried to attach logging to file '${args.logFile}' but an error ` +
`occurred: ${e.message}`);
}
}
if (args.webhook) {
try {
- transports.push(_createHttpTransport(args, fileLogLevel));
+ transports.push(createHttpTransport(args, fileLogLevel));
} catch (e) {
// eslint-disable-next-line no-console
console.log(`Tried to attach logging to Http at ${args.webhook} but ` +
@@ -172,27 +184,21 @@ async function init (args) {
// set de facto param passed to timestamp function
timeZone = args.localTimezone;
- // by not adding colors here and not setting 'colorize' in transports
- // when logNoColors === true, console output is fully stripped of color.
- if (!args.logNoColors) {
- winston.addColors(colors);
- }
-
- // clean up in case we have initted before since npmlog is a global
- // object
+ // clean up in case we have initted before since npmlog is a global object
clear();
- log = new (winston.Logger)({
- transports: await _createTransports(args)
+ log = createLogger({
+ transports: await createTransports(args),
+ levels,
});
// Capture logs emitted via npmlog and pass them through winston
npmlog.on('log', (logObj) => {
- let winstonLevel = npmToWinstonLevels[logObj.level] || 'info';
+ const winstonLevel = npmToWinstonLevels[logObj.level] || 'info';
let msg = logObj.message;
if (logObj.prefix) {
- let prefix = `[${logObj.prefix}]`;
- msg = `${prefix.magenta} ${msg}`;
+ const prefix = `[${logObj.prefix}]`;
+ msg = `${args.logNoColors ? prefix : prefix.magenta} ${msg}`;
}
log[winstonLevel](msg);
if (args.logHandler && _.isFunction(args.logHandler)) {
@@ -200,17 +206,6 @@ async function init (args) {
}
});
-
-
- log.setLevels(levels);
-
- // 8/19/14 this is a hack to force Winston to print debug messages to stdout rather than stderr.
- // TODO: remove this if winston provides an API for directing streams.
- if (levels[log.transports.console.level] === levels.debug) {
- log.debug = function (msg) {
- log.info(`[debug] ${msg}`);
- };
- }
}
function clear () {

MODIFY
lib/parser.js
lib/parser.js
@@ -104,7 +104,7 @@ const args = [
[['-g', '--log'], {
defaultValue: null,
- dest: 'log',
+ dest: 'logFile',
required: false,
example: '/path/to/appium.log',
help: 'Also send log output to this file',

MODIFY
package.json
package.json
"semver": "^5.5.0",
"source-map-support": "0.x",
"teen_process": "1.x",
- "winston": "2.x"
+ "winston": "3.x"
},
"scripts": {
"prepare": "gulp prepublish",
"heapdump": "0.x"
},
"greenkeeper": {
- "ignore": [
- "winston"
- ]
+ "ignore": []
}
}

MODIFY
test/logger-specs.js
test/logger-specs.js
@@ -6,9 +6,9 @@ import { logger } from 'appium-support';
// temporarily turn on logging to stdio, so we can catch and query
-let forceLogs = process.env._FORCE_LOGS;
+const forceLogs = process.env._FORCE_LOGS;
process.env._FORCE_LOGS = 1;
-let log = logger.getLogger('Appium');
+const log = logger.getLogger('Appium');
describe('logging', function () {
let stderrSpy;

Update winston logger (#11583)