1 | import npmlog from 'npmlog';
|
2 | import { createLogger, format, transports } from 'winston';
|
3 | import { fs, logger } from 'appium-support';
|
4 | import dateformat from 'dateformat';
|
5 | import _ from 'lodash';
|
6 |
|
7 |
|
8 |
|
9 | logger.patchLogger(npmlog);
|
10 | global._global_npmlog = npmlog;
|
11 |
|
12 |
|
13 | npmlog.level = 'silent';
|
14 | const levels = {
|
15 | debug: 4,
|
16 | info: 3,
|
17 | warn: 2,
|
18 | error: 1,
|
19 | };
|
20 |
|
21 | const colors = {
|
22 | info: 'cyan',
|
23 | debug: 'grey',
|
24 | warn: 'yellow',
|
25 | error: 'red',
|
26 | };
|
27 |
|
28 | const npmToWinstonLevels = {
|
29 | silly: 'debug',
|
30 | verbose: 'debug',
|
31 | debug: 'debug',
|
32 | info: 'info',
|
33 | http: 'info',
|
34 | warn: 'warn',
|
35 | error: 'error',
|
36 | };
|
37 |
|
38 | let log = null;
|
39 | let timeZone = null;
|
40 |
|
41 |
|
42 | const timestampFormat = format.timestamp({
|
43 | format () {
|
44 | let date = new Date();
|
45 | if (!timeZone) {
|
46 | date = new Date(date.valueOf() + date.getTimezoneOffset() * 60000);
|
47 | }
|
48 | return dateformat(date, 'yyyy-mm-dd HH:MM:ss:l');
|
49 | },
|
50 | });
|
51 |
|
52 |
|
53 | const colorizeFormat = format.colorize({
|
54 | colors,
|
55 | });
|
56 |
|
57 |
|
58 | const stripColorFormat = format(function stripColor (info) {
|
59 | const code = /\u001b\[(\d+(;\d+)*)?m/g;
|
60 | info.message = info.message.replace(code, '');
|
61 | return info;
|
62 | })();
|
63 |
|
64 | function createConsoleTransport (args, logLvl) {
|
65 | return new (transports.Console)({
|
66 | name: 'console',
|
67 | handleExceptions: true,
|
68 | exitOnError: false,
|
69 | json: false,
|
70 | level: logLvl,
|
71 | stderrLevels: ['error'],
|
72 | format: format.combine(
|
73 | format(function adjustDebug (info) {
|
74 |
|
75 | if (info.level === 'debug') {
|
76 | info.level = 'info';
|
77 | info.message = `[debug] ${info.message}`;
|
78 | }
|
79 | return info;
|
80 | })(),
|
81 | timestampFormat,
|
82 | args.logNoColors ? stripColorFormat : colorizeFormat,
|
83 | format.printf(function printInfo (info) {
|
84 | return `${args.logTimestamp ? `${info.timestamp} - ` : ''}${info.message}`;
|
85 | })
|
86 | ),
|
87 | });
|
88 | }
|
89 |
|
90 | function createFileTransport (args, logLvl) {
|
91 | return new (transports.File)({
|
92 | name: 'file',
|
93 | filename: args.logFile,
|
94 | maxFiles: 1,
|
95 | handleExceptions: true,
|
96 | exitOnError: false,
|
97 | json: false,
|
98 | level: logLvl,
|
99 | format: format.combine(
|
100 | stripColorFormat,
|
101 | timestampFormat,
|
102 | format.printf(function printInfo (info) {
|
103 | return `${info.timestamp} ${info.message}`;
|
104 | })
|
105 | )
|
106 | });
|
107 | }
|
108 |
|
109 | function createHttpTransport (args, logLvl) {
|
110 | let host = '127.0.0.1';
|
111 | let port = 9003;
|
112 |
|
113 | if (args.webhook.match(':')) {
|
114 | const hostAndPort = args.webhook.split(':');
|
115 | host = hostAndPort[0];
|
116 | port = parseInt(hostAndPort[1], 10);
|
117 | }
|
118 |
|
119 | return new (transports.Http)({
|
120 | name: 'http',
|
121 | host,
|
122 | port,
|
123 | path: '/',
|
124 | handleExceptions: true,
|
125 | exitOnError: false,
|
126 | json: false,
|
127 | level: logLvl,
|
128 | format: format.combine(
|
129 | stripColorFormat,
|
130 | format.printf(function printInfo (info) {
|
131 | return `${info.timestamp} ${info.message}`;
|
132 | })
|
133 | ),
|
134 | });
|
135 | }
|
136 |
|
137 | async function createTransports (args) {
|
138 | let transports = [];
|
139 | let consoleLogLevel = null;
|
140 | let fileLogLevel = null;
|
141 |
|
142 | if (args.loglevel && args.loglevel.match(':')) {
|
143 |
|
144 | const lvlPair = args.loglevel.split(':');
|
145 | consoleLogLevel = lvlPair[0] || consoleLogLevel;
|
146 | fileLogLevel = lvlPair[1] || fileLogLevel;
|
147 | } else {
|
148 | consoleLogLevel = fileLogLevel = args.loglevel;
|
149 | }
|
150 |
|
151 | transports.push(createConsoleTransport(args, consoleLogLevel));
|
152 |
|
153 | if (args.logFile) {
|
154 | try {
|
155 |
|
156 |
|
157 |
|
158 | if (await fs.exists(args.logFile)) {
|
159 | await fs.unlink(args.logFile);
|
160 | }
|
161 |
|
162 | transports.push(createFileTransport(args, fileLogLevel));
|
163 | } catch (e) {
|
164 |
|
165 | console.log(`Tried to attach logging to file '${args.logFile}' but an error ` +
|
166 | `occurred: ${e.message}`);
|
167 | }
|
168 | }
|
169 |
|
170 | if (args.webhook) {
|
171 | try {
|
172 | transports.push(createHttpTransport(args, fileLogLevel));
|
173 | } catch (e) {
|
174 |
|
175 | console.log(`Tried to attach logging to Http at ${args.webhook} but ` +
|
176 | `an error occurred: ${e.message}`);
|
177 | }
|
178 | }
|
179 |
|
180 | return transports;
|
181 | }
|
182 |
|
183 | async function init (args) {
|
184 |
|
185 | timeZone = args.localTimezone;
|
186 |
|
187 |
|
188 | clear();
|
189 |
|
190 | log = createLogger({
|
191 | transports: await createTransports(args),
|
192 | levels,
|
193 | });
|
194 |
|
195 |
|
196 | npmlog.on('log', (logObj) => {
|
197 | const winstonLevel = npmToWinstonLevels[logObj.level] || 'info';
|
198 | let msg = logObj.message;
|
199 | if (logObj.prefix) {
|
200 | const prefix = `[${logObj.prefix}]`;
|
201 | msg = `${args.logNoColors ? prefix : prefix.magenta} ${msg}`;
|
202 | }
|
203 | log[winstonLevel](msg);
|
204 | if (args.logHandler && _.isFunction(args.logHandler)) {
|
205 | args.logHandler(logObj.level, msg);
|
206 | }
|
207 |
|
208 | });
|
209 | }
|
210 |
|
211 | function clear () {
|
212 | if (log) {
|
213 | for (let transport of _.keys(log.transports)) {
|
214 | log.remove(transport);
|
215 | }
|
216 | }
|
217 | npmlog.removeAllListeners('log');
|
218 | }
|
219 |
|
220 |
|
221 | export { init, clear };
|
222 | export default init;
|