From 06fd3f4dc88c7b4338370b2b4093405a8c16f9dd Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 22 Jul 2022 22:39:51 +0200 Subject: [PATCH 1/5] feat: cleaner log output WIP --- lib/common/mobile/device-log-provider.ts | 108 ++++++++++++++++++++++- 1 file changed, 104 insertions(+), 4 deletions(-) diff --git a/lib/common/mobile/device-log-provider.ts b/lib/common/mobile/device-log-provider.ts index 72c9124d96..e575c9d220 100644 --- a/lib/common/mobile/device-log-provider.ts +++ b/lib/common/mobile/device-log-provider.ts @@ -1,8 +1,9 @@ import { DeviceLogProviderBase } from "./device-log-provider-base"; import { DEVICE_LOG_EVENT_NAME } from "../constants"; -import { LoggerConfigData } from "../../constants"; import { injector } from "../yok"; +import * as chalk from "chalk"; + export class DeviceLogProvider extends DeviceLogProviderBase { constructor( protected $logFilter: Mobile.ILogFilter, @@ -17,6 +18,7 @@ export class DeviceLogProvider extends DeviceLogProviderBase { platform: string, deviceIdentifier: string ): void { + // console.log(lineText) const loggingOptions = this.getDeviceLogOptionsForDevice(deviceIdentifier); let data = this.$logFilter.filterData(platform, lineText, loggingOptions); data = this.$logSourceMapService.replaceWithOriginalFileLocations( @@ -25,7 +27,7 @@ export class DeviceLogProvider extends DeviceLogProviderBase { loggingOptions ); if (data) { - this.logDataCore(data); + this.logDataCore(data, deviceIdentifier); this.emit(DEVICE_LOG_EVENT_NAME, lineText, deviceIdentifier, platform); } } @@ -34,8 +36,106 @@ export class DeviceLogProvider extends DeviceLogProviderBase { this.$logFilter.loggingLevel = logLevel.toUpperCase(); } - private logDataCore(data: string): void { - this.$logger.info(data, { [LoggerConfigData.skipNewLine]: true }); + private consoleLogLevelRegex: RegExp = /^CONSOLE (LOG|INFO|WARN|ERROR|TRACE|INFO( .+)):\s/; + private consoleLevelColor: Record string> = { + log: (line) => line, + info: chalk.cyanBright, + warn: chalk.yellowBright, + error: chalk.redBright, + trace: chalk.grey, + time: chalk.greenBright, + }; + + private deviceColorMap = new Map(); + + private colorPool: typeof chalk.BackgroundColor[] = [ + "bgGray", + "bgMagentaBright", + "bgBlueBright", + "bgWhiteBright", + "bgCyanBright", + "bgYellowBright", + "bgGreenBright", + ]; + private colorPoolIndex = 0; + + private getDeviceColor(deviceIdentifier: string) { + if (this.deviceColorMap.has(deviceIdentifier)) { + return this.deviceColorMap.get(deviceIdentifier); + } + + const color = this.colorPool[this.colorPoolIndex]; + // wrap around if we have no more colors in the pool + this.colorPoolIndex = + this.colorPoolIndex === this.colorPool.length - 1 + ? 0 + : this.colorPoolIndex + 1; + + this.deviceColorMap.set(deviceIdentifier, color); + + return color; + } + + private logDataCore(data: string, deviceIdentifier: string): void { + let shouldPrepend = false; + let splitIndexes: number[] = []; + const lines = data + .split(/\n(CONSOLE)/) + .map((line, index, lines) => { + if (line === "CONSOLE") { + shouldPrepend = true; + + if (lines[index - 1]) { + splitIndexes.push(index - 1); + } + + return null; + } + + if (shouldPrepend) { + shouldPrepend = false; + return `CONSOLE${line}`; + } + + const suffix = line.endsWith("\n") ? "" : "\n"; + return line + suffix; + }) + .map((line, index) => { + if (splitIndexes.includes(index)) { + return line + "\n"; + } + return line; + }) + .filter((line) => { + return line !== null; + }); + + if (!lines.length && data.length) { + lines.push(data); + } + + for (const line of lines) { + let [match, level, timeLabel] = + this.consoleLogLevelRegex.exec(line) ?? []; + + if (timeLabel) { + level = "time"; + timeLabel = timeLabel.replace("INFO ", "").trim() + ": "; + } else { + level = level?.toLowerCase() ?? "log"; + } + + const toLog = [timeLabel ?? "", match ? line.replace(match, "") : line] + .join("") + .trim(); + + toLog.split("\n").forEach((actualLine) => { + console.log( + chalk[this.getDeviceColor(deviceIdentifier)](" "), + this.consoleLevelColor[level](actualLine) + ); + }); + } } } injector.register("deviceLogProvider", DeviceLogProvider); From 1c84520e5a5eb0fa022cdfc6e47f95a37b39db62 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 25 Jul 2022 19:14:26 +0200 Subject: [PATCH 2/5] feat: break logs wider than the terminal width into new lines --- lib/common/mobile/device-log-provider.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/common/mobile/device-log-provider.ts b/lib/common/mobile/device-log-provider.ts index e575c9d220..784a9a8456 100644 --- a/lib/common/mobile/device-log-provider.ts +++ b/lib/common/mobile/device-log-provider.ts @@ -130,12 +130,28 @@ export class DeviceLogProvider extends DeviceLogProviderBase { .trim(); toLog.split("\n").forEach((actualLine) => { - console.log( + this.printLine( chalk[this.getDeviceColor(deviceIdentifier)](" "), this.consoleLevelColor[level](actualLine) ); }); } } + + private printLine(prefix: string, ...parts: string[]) { + const maxWidth = process.stdout.columns - 2; + const fullLine = parts.join(" "); + + // console.log(prefix, fullLine); + // return; + if (fullLine.length < maxWidth) { + console.log(prefix, fullLine); + } else { + for (let i = 0; i < fullLine.length; i += maxWidth) { + const part = fullLine.substring(i, i + maxWidth); + console.log(prefix, part); + } + } + } } injector.register("deviceLogProvider", DeviceLogProvider); From 830fde126ba536cdce6d721cc34c05485323231e Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 25 Jul 2022 19:14:53 +0200 Subject: [PATCH 3/5] fix: reduce ios log predicate scope --- lib/common/constants.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/common/constants.ts b/lib/common/constants.ts index 8586bfcb8a..447efc7ca0 100644 --- a/lib/common/constants.ts +++ b/lib/common/constants.ts @@ -62,8 +62,7 @@ export class EmulatorDiscoveryNames { } export const DEVICE_LOG_EVENT_NAME = "deviceLogData"; -export const IOS_LOG_PREDICATE = - 'senderImagePath contains "NativeScript" || eventMessage contains[c] "NativeScript"'; +export const IOS_LOG_PREDICATE = 'senderImagePath contains "NativeScript"'; export const IOS_APP_CRASH_LOG_REG_EXP = /Fatal JavaScript exception \- application has been terminated/; export const FAIL_LIVESYNC_LOG_REGEX = /Failed to refresh the application with RefreshRequest./; From 4d75859359d3fa6f916e020400492db1d1680eac Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 25 Jul 2022 19:53:52 +0200 Subject: [PATCH 4/5] chore: add todo notes --- lib/common/mobile/device-log-provider.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/common/mobile/device-log-provider.ts b/lib/common/mobile/device-log-provider.ts index 784a9a8456..5ffdd2c6d2 100644 --- a/lib/common/mobile/device-log-provider.ts +++ b/lib/common/mobile/device-log-provider.ts @@ -3,6 +3,7 @@ import { DEVICE_LOG_EVENT_NAME } from "../constants"; import { injector } from "../yok"; import * as chalk from "chalk"; +import { LoggerConfigData } from "../../constants"; export class DeviceLogProvider extends DeviceLogProviderBase { constructor( @@ -77,6 +78,14 @@ export class DeviceLogProvider extends DeviceLogProviderBase { } private logDataCore(data: string, deviceIdentifier: string): void { + // todo: allow toggling "legacy/classic" printer/logger + if (false) { + // legacy logging + this.$logger.info(data, { [LoggerConfigData.skipNewLine]: true }); + return; + } + + // todo: extract into an injectable printer/logger service let shouldPrepend = false; let splitIndexes: number[] = []; const lines = data From ed8f751fde19019162861cd9ce936c18284795bf Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 25 Jul 2022 19:58:24 +0200 Subject: [PATCH 5/5] feat: allow using classicLogs with a temporary --env.classicLogs flag --- lib/common/mobile/device-log-provider.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/common/mobile/device-log-provider.ts b/lib/common/mobile/device-log-provider.ts index 5ffdd2c6d2..0eafdbb842 100644 --- a/lib/common/mobile/device-log-provider.ts +++ b/lib/common/mobile/device-log-provider.ts @@ -4,12 +4,14 @@ import { injector } from "../yok"; import * as chalk from "chalk"; import { LoggerConfigData } from "../../constants"; +import { IOptions } from "../../declarations"; export class DeviceLogProvider extends DeviceLogProviderBase { constructor( protected $logFilter: Mobile.ILogFilter, protected $logger: ILogger, - protected $logSourceMapService: Mobile.ILogSourceMapService + protected $logSourceMapService: Mobile.ILogSourceMapService, + protected $options: IOptions ) { super($logFilter, $logger, $logSourceMapService); } @@ -78,8 +80,8 @@ export class DeviceLogProvider extends DeviceLogProviderBase { } private logDataCore(data: string, deviceIdentifier: string): void { - // todo: allow toggling "legacy/classic" printer/logger - if (false) { + // todo: use config to set logger - --env.classicLogs is temporary! + if ("classicLogs" in this.$options.env) { // legacy logging this.$logger.info(data, { [LoggerConfigData.skipNewLine]: true }); return;