diff --git a/default.json b/default.json index cb48c1b0..248a4c7c 100644 --- a/default.json +++ b/default.json @@ -6,6 +6,13 @@ "enabled": false, "collectDefaultMetrics": true, "requestDurationBuckets": [1, 5, 7, 9, 11, 13, 15, 20, 30] + }, + "logging": { + "level": "info", + "console": { + "json": true, + "colorize": false + } } }, "rendering": { @@ -17,6 +24,7 @@ "clustering": { "mode": "browser", "maxConcurrency": 5 - } + }, + "verboseLogging": false } } \ No newline at end of file diff --git a/dev.json b/dev.json index 41e7f7a8..269adbe1 100644 --- a/dev.json +++ b/dev.json @@ -6,6 +6,13 @@ "enabled": true, "collectDefaultMetrics": true, "requestDurationBuckets": [1, 5, 7, 9, 11, 13, 15, 20, 30] + }, + "logging": { + "level": "debug", + "console": { + "json": false, + "colorize": true + } } }, "rendering": { @@ -17,6 +24,7 @@ "clustering": { "mode": "browser", "maxConcurrency": 5 - } + }, + "verboseLogging": false } } \ No newline at end of file diff --git a/docs/remote_rendering_using_docker.md b/docs/remote_rendering_using_docker.md index bdf6565a..5978f9d6 100644 --- a/docs/remote_rendering_using_docker.md +++ b/docs/remote_rendering_using_docker.md @@ -49,6 +49,15 @@ You can enable [Prometheus](https://prometheus.io/) metrics endpoint `/metrics` export ENABLE_METRICS=true ``` +**Log level:** + +Change the log level. Default is `info` and will include log messages with level `error`, `warning` and info. + + +```bash +export LOG_LEVEL=info +``` + ## Configuration file You can override certain settings by using a configuration file, see [default.json](https://github.com/grafana/grafana-image-renderer/tree/master/default.json) for defaults. Note that any configured environment variable takes precedence over configuration file settings. diff --git a/package.json b/package.json index b0476c10..d39f429e 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,8 @@ "prom-client": "^11.5.3", "puppeteer": "^2.0.0", "puppeteer-cluster": "^0.18.0", - "unique-filename": "^1.1.0" + "unique-filename": "^1.1.0", + "winston": "^3.2.1" }, "devDependencies": { "@types/express": "^4.11.1", diff --git a/src/app.ts b/src/app.ts index e995925f..ed55c6a1 100644 --- a/src/app.ts +++ b/src/app.ts @@ -34,14 +34,13 @@ async function main() { plugin.start(); } else if (command === 'server') { let config: ServiceConfig = defaultServiceConfig; - const logger = new ConsoleLogger(); if (argv.config) { try { const fileConfig = readJSONFileSync(argv.config); config = _.merge(config, fileConfig); } catch (e) { - logger.error('failed to read config from path', argv.config, 'error', e); + console.error('failed to read config from path', argv.config, 'error', e); return; } } @@ -52,6 +51,7 @@ async function main() { timings = new MetricsBrowserTimings(); } + const logger = new ConsoleLogger(config.service.logging); const browser = createBrowser(config.rendering, logger, timings); const server = new HttpServer(config, logger, browser); @@ -101,6 +101,10 @@ function populateServiceConfigFromEnv(config: ServiceConfig, env: NodeJS.Process config.service.port = parseInt(env['HTTP_PORT'] as string, 10); } + if (env['LOG_LEVEL']) { + config.service.logging.level = env['LOG_LEVEL'] as string; + } + if (env['IGNORE_HTTPS_ERRORS']) { config.rendering.ignoresHttpsErrors = env['IGNORE_HTTPS_ERRORS'] === 'true'; } diff --git a/src/browser/browser.ts b/src/browser/browser.ts index 62a174a4..bb99fcee 100644 --- a/src/browser/browser.ts +++ b/src/browser/browser.ts @@ -113,9 +113,12 @@ export class Browser { await browser.newPage() ); + this.addPageListeners(page); + return await this.takeScreenshot(page, options); } finally { if (page) { + this.removePageListeners(page); await page.close(); } if (browser) { @@ -164,4 +167,69 @@ export class Browser { return { filePath: options.filePath }; } + + addPageListeners(page: any) { + page.on('error', this.logError.bind); + page.on('pageerror', this.logPageError); + page.on('requestfailed', this.logRequestFailed); + page.on('console', this.logConsoleMessage); + + if (this.config.verboseLogging) { + page.on('request', this.logRequest); + page.on('requestfinished', this.logRequestFinished); + page.on('close', this.logPageClosed); + } + } + + removePageListeners(page: any) { + page.removeListener('error', this.logError); + page.removeListener('pageerror', this.logPageError); + page.removeListener('requestfailed', this.logRequestFailed); + page.removeListener('console', this.logConsoleMessage); + + if (this.config.verboseLogging) { + page.removeListener('request', this.logRequest); + page.removeListener('requestfinished', this.logRequestFinished); + page.removeListener('close', this.logPageClosed); + } + } + + logError = (err: Error) => { + this.log.error('Browser page crashed', 'error', err.toString()); + }; + + logPageError = (err: Error) => { + this.log.error('Browser uncaught exception', 'error', err.toString()); + }; + + logConsoleMessage = (msg: any) => { + const msgType = msg.type(); + if (!this.config.verboseLogging && msgType !== 'error') { + return; + } + + const loc = msg.location(); + if (msgType === 'error') { + this.log.error('Browser console error', 'msg', msg.text(), 'url', loc.url, 'line', loc.lineNumber, 'column', loc.columnNumber); + return; + } + + this.log.debug(`Browser console ${msgType}`, 'msg', msg.text(), 'url', loc.url, 'line', loc.lineNumber, 'column', loc.columnNumber); + }; + + logRequest = (req: any) => { + this.log.debug('Browser request', 'url', req._url, 'method', req._url); + }; + + logRequestFailed = (req: any) => { + this.log.error('Browser request failed', 'url', req._url, 'method', req._method); + }; + + logRequestFinished = (req: any) => { + this.log.debug('Browser request finished', 'url', req._url, 'method', req._method); + }; + + logPageClosed = () => { + this.log.debug('Browser page closed'); + }; } diff --git a/src/browser/clustered.ts b/src/browser/clustered.ts index 8d011044..e2a1f628 100644 --- a/src/browser/clustered.ts +++ b/src/browser/clustered.ts @@ -31,7 +31,12 @@ export class ClusteredBrowser extends Browser { // set timezone await page.emulateTimezone(data.timezone); } - return await this.takeScreenshot(page, data); + + try { + return await this.takeScreenshot(page, data); + } finally { + this.removePageListeners(page); + } }); } diff --git a/src/browser/reusable.ts b/src/browser/reusable.ts index 665128bd..2126bc2d 100644 --- a/src/browser/reusable.ts +++ b/src/browser/reusable.ts @@ -39,9 +39,12 @@ export class ReusableBrowser extends Browser { await page.emulateTimezone(options.timezone); } + this.addPageListeners(page); + return await this.takeScreenshot(page, options); } finally { if (page) { + this.removePageListeners(page); await page.close(); } if (context) { diff --git a/src/config.ts b/src/config.ts index c7c0f0c2..3b4853af 100644 --- a/src/config.ts +++ b/src/config.ts @@ -12,6 +12,7 @@ export interface RenderingConfig { timingMetrics: boolean; mode: string; clustering: ClusteringConfig; + verboseLogging: boolean; } export interface MetricsConfig { @@ -20,11 +21,23 @@ export interface MetricsConfig { requestDurationBuckets: number[]; } +export interface ConsoleLoggerConfig { + level?: string; + json: boolean; + colorize: boolean; +} + +export interface LoggingConfig { + level: string; + console?: ConsoleLoggerConfig; +} + export interface ServiceConfig { service: { host?: string; port: number; metrics: MetricsConfig; + logging: LoggingConfig; }; rendering: RenderingConfig; } @@ -49,6 +62,7 @@ const defaultRenderingConfig: RenderingConfig = { mode: 'browser', maxConcurrency: 5, }, + verboseLogging: false, }; export const defaultServiceConfig: ServiceConfig = { @@ -60,6 +74,13 @@ export const defaultServiceConfig: ServiceConfig = { collectDefaultMetrics: true, requestDurationBuckets: [0.5, 1, 3, 5, 7, 10, 20, 30, 60], }, + logging: { + level: 'info', + console: { + json: true, + colorize: false, + }, + }, }, rendering: defaultRenderingConfig, }; diff --git a/src/logger.ts b/src/logger.ts index b1d6625a..87b0fa6c 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,29 +1,89 @@ +import winston = require('winston'); +import { LoggingConfig } from './config'; + +export interface LogWriter { + write(message, encoding); +} + export interface Logger { + writer: LogWriter; debug(message?: string, ...optionalParams: any[]); info(message?: string, ...optionalParams: any[]); warn(message?: string, ...optionalParams: any[]); error(message?: string, ...optionalParams: any[]); } -export class ConsoleLogger { - debug(message?: string, ...optionalParams: any[]) { - console.debug(message, ...optionalParams); +export class ConsoleLogger implements Logger { + writer: LogWriter; + logger: winston.Logger; + + constructor(config: LoggingConfig) { + const options2 = { + console: { + level: 'debug', + handleExceptions: true, + colorize: true, + }, + }; + + const transports: any[] = []; + + if (config.console) { + const options: any = { + exitOnError: false, + }; + if (config.console.level) { + options.level = config.console.level; + } + const formatters: any[] = []; + if (config.console.colorize) { + formatters.push(winston.format.colorize()); + } + + if (config.console.json) { + formatters.push(winston.format.json()); + } else { + formatters.push(winston.format.align()); + formatters.push(winston.format.simple()); + } + + options.format = winston.format.combine(...(formatters as any)); + transports.push(new winston.transports.Console(options)); + } + + this.logger = winston.createLogger({ + level: config.level, + exitOnError: false, + transports: transports, + }); + + this.writer = { + write: message => { + this.logger.info(message); + }, + }; } - info(message?: string, ...optionalParams: any[]) { - console.info(message, ...optionalParams); + debug(message: string, ...optionalParams: any[]) { + this.logger.debug(message, optionalParams); } - warn(message?: string, ...optionalParams: any[]) { - console.warn(message, ...optionalParams); + info(message: string, ...optionalParams: any[]) { + this.logger.info(message, optionalParams); } - error(message?: string, ...optionalParams: any[]) { - console.error(message, ...optionalParams); + warn(message: string, ...optionalParams: any[]) { + this.logger.warn(message, optionalParams); + } + + error(message: string, ...optionalParams: any[]) { + this.logger.error(message, optionalParams); } } -export class PluginLogger { +export class PluginLogger implements Logger { + writer: LogWriter; + private logEntry(level: string, message?: string, ...optionalParams: any[]) { const logEntry = { '@level': level, diff --git a/src/plugin/grpc-plugin.ts b/src/plugin/grpc-plugin.ts index 68134807..8dc545da 100644 --- a/src/plugin/grpc-plugin.ts +++ b/src/plugin/grpc-plugin.ts @@ -92,7 +92,7 @@ export class GrpcPlugin { const result = await this.browser.render(options); callback(null, { error: '' }); } catch (err) { - this.log.error('Render request failed', 'url', options.url, 'error', err); + this.log.error('Render request failed', 'url', options.url, 'error', err.toString()); callback(null, { error: err.toString() }); } } diff --git a/src/service/http-server.ts b/src/service/http-server.ts index 30043f29..c5b2f8c1 100644 --- a/src/service/http-server.ts +++ b/src/service/http-server.ts @@ -1,4 +1,3 @@ -import * as http from 'http'; import * as net from 'net'; import express = require('express'); import { Logger } from '../logger'; @@ -17,7 +16,7 @@ export class HttpServer { async start() { this.app = express(); - this.app.use(morgan('combined')); + this.app.use(morgan('combined', { stream: this.log.writer })); this.app.use(metricsMiddleware(this.config.service.metrics, this.log)); this.app.get('/', (req: express.Request, res: express.Response) => { res.send('Grafana Image Renderer'); @@ -81,9 +80,13 @@ export class HttpServer { timezone: req.query.timezone, encoding: req.query.encoding, }; - this.log.info(`render request received for ${options.url}`); - const result = await this.browser.render(options); - res.sendFile(result.filePath); + try { + this.log.info(`Render request received', 'url', ${options.url}`); + const result = await this.browser.render(options); + res.sendFile(result.filePath); + } catch (err) { + this.log.error('Render request failed', 'url', options.url, 'error', err); + } }; } diff --git a/yarn.lock b/yarn.lock index 3003e2a6..5660eecb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -371,6 +371,13 @@ async-limiter@~1.0.0: resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== +async@^2.6.1: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + dependencies: + lodash "^4.17.14" + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -569,7 +576,7 @@ code-point-at@^1.0.0: resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= -color-convert@^1.9.0: +color-convert@^1.9.0, color-convert@^1.9.1: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== @@ -588,11 +595,45 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= -color-name@~1.1.4: +color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-string@^1.5.2: + version "1.5.3" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc" + integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@3.0.x: + version "3.0.0" + resolved "https://registry.yarnpkg.com/color/-/color-3.0.0.tgz#d920b4328d534a3ac8295d68f7bd4ba6c427be9a" + integrity sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w== + dependencies: + color-convert "^1.9.1" + color-string "^1.5.2" + +colornames@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/colornames/-/colornames-1.1.1.tgz#f8889030685c7c4ff9e2a559f5077eb76a816f96" + integrity sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y= + +colors@^1.2.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + +colorspace@1.1.x: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.2.tgz#e0128950d082b86a2168580796a0aa5d6c68d8c5" + integrity sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ== + dependencies: + color "3.0.x" + text-hex "1.0.x" + colour@~0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/colour/-/colour-0.7.1.tgz#9cb169917ec5d12c0736d3e8685746df1cadf778" @@ -788,6 +829,15 @@ detect-libc@^1.0.2: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= +diagnostics@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.1.tgz#cab6ac33df70c9d9a727490ae43ac995a769b22a" + integrity sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ== + dependencies: + colorspace "1.1.x" + enabled "1.0.x" + kuler "1.0.x" + diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -823,6 +873,13 @@ elegant-spinner@^1.0.1: resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" integrity sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4= +enabled@1.0.x: + version "1.0.2" + resolved "https://registry.yarnpkg.com/enabled/-/enabled-1.0.2.tgz#965f6513d2c2d1c5f4652b64a2e3396467fc2f93" + integrity sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M= + dependencies: + env-variable "0.0.x" + encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -835,6 +892,11 @@ end-of-stream@^1.1.0: dependencies: once "^1.4.0" +env-variable@0.0.x: + version "0.0.5" + resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.5.tgz#913dd830bef11e96a039c038d4130604eba37f88" + integrity sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA== + error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -1037,6 +1099,11 @@ fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fast-safe-stringify@^2.0.4: + version "2.0.7" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" + integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA== + fastq@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.6.0.tgz#4ec8a38f4ac25f21492673adb7eae9cfef47d1c2" @@ -1051,6 +1118,11 @@ fd-slicer@~1.0.1: dependencies: pend "~1.2.0" +fecha@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd" + integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg== + figures@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" @@ -1436,6 +1508,11 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + is-directory@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" @@ -1587,6 +1664,13 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" +kuler@1.0.x: + version "1.0.1" + resolved "https://registry.yarnpkg.com/kuler/-/kuler-1.0.1.tgz#ef7c784f36c9fb6e16dd3150d152677b2b0228a6" + integrity sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ== + dependencies: + colornames "^1.1.1" + lcid@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" @@ -1688,7 +1772,7 @@ lodash.clone@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6" integrity sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y= -lodash@^4.17.15: +lodash@^4.17.14, lodash@^4.17.15: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -1716,6 +1800,17 @@ log-update@^2.3.0: cli-cursor "^2.0.0" wrap-ansi "^3.0.1" +logform@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.1.2.tgz#957155ebeb67a13164069825ce67ddb5bb2dd360" + integrity sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ== + dependencies: + colors "^1.2.1" + fast-safe-stringify "^2.0.4" + fecha "^2.3.3" + ms "^2.1.1" + triple-beam "^1.3.0" + long@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" @@ -2032,6 +2127,11 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" +one-time@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/one-time/-/one-time-0.0.4.tgz#f8cdf77884826fe4dff93e3a9cc37b1e4480742e" + integrity sha1-+M33eISCb+Tf+T46nMN7HkSAdC4= + onetime@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" @@ -2439,7 +2539,7 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2: +readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@^2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -2452,6 +2552,15 @@ readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.0.6, readable string_decoder "~1.1.1" util-deprecate "~1.0.1" +readable-stream@^3.1.1: + version "3.5.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.5.0.tgz#465d70e6d1087f6162d079cd0b5db7fbebfd1606" + integrity sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + regenerator-runtime@^0.13.2: version "0.13.3" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" @@ -2551,7 +2660,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@^5.0.1, safe-buffer@^5.1.2: +safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== @@ -2649,6 +2758,13 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -2717,6 +2833,11 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= + "statuses@>= 1.5.0 < 2", statuses@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" @@ -2763,6 +2884,13 @@ string-width@^1.0.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -2852,6 +2980,11 @@ tdigest@^0.1.1: dependencies: bintrees "1.0.1" +text-hex@1.0.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + thenify-all@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" @@ -2896,6 +3029,11 @@ tough-cookie@~2.4.3: psl "^1.1.24" punycode "^1.4.1" +triple-beam@^1.2.0, triple-beam@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" + integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== + tsc-watch@^1.0.21: version "1.1.39" resolved "https://registry.yarnpkg.com/tsc-watch/-/tsc-watch-1.1.39.tgz#2575401009e6ddfe53e553e0152ec8d7e7a7c77a" @@ -3030,7 +3168,7 @@ url-value-parser@^2.0.0: resolved "https://registry.yarnpkg.com/url-value-parser/-/url-value-parser-2.0.1.tgz#c8179a095ab9ec1f5aa17ca36af5af396b4e95ed" integrity sha512-bexECeREBIueboLGM3Y1WaAzQkIn+Tca/Xjmjmfd0S/hFHSCEoFkNh0/D0l9G4K74MkEP/lLFRlYnxX3d68Qgw== -util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= @@ -3093,6 +3231,29 @@ window-size@^0.1.4: resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" integrity sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY= +winston-transport@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.3.0.tgz#df68c0c202482c448d9b47313c07304c2d7c2c66" + integrity sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A== + dependencies: + readable-stream "^2.3.6" + triple-beam "^1.2.0" + +winston@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.2.1.tgz#63061377976c73584028be2490a1846055f77f07" + integrity sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw== + dependencies: + async "^2.6.1" + diagnostics "^1.1.1" + is-stream "^1.1.0" + logform "^2.1.1" + one-time "0.0.4" + readable-stream "^3.1.1" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.3.0" + word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"