Skip to content

Commit 5330207

Browse files
authored
feat: cleaner log output (#5680)
* feat: cleaner log output * feat: break logs wider than the terminal width into new lines * fix: reduce ios log predicate scope * chore: add todo notes * feat: allow using classicLogs with a temporary --env.classicLogs flag
1 parent e958766 commit 5330207

File tree

2 files changed

+133
-7
lines changed

2 files changed

+133
-7
lines changed

lib/common/constants.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@ export class EmulatorDiscoveryNames {
6262
}
6363

6464
export const DEVICE_LOG_EVENT_NAME = "deviceLogData";
65-
export const IOS_LOG_PREDICATE =
66-
'senderImagePath contains "NativeScript" || eventMessage contains[c] "NativeScript"';
65+
export const IOS_LOG_PREDICATE = 'senderImagePath contains "NativeScript"';
6766
export const IOS_APP_CRASH_LOG_REG_EXP = /Fatal JavaScript exception \- application has been terminated/;
6867
export const FAIL_LIVESYNC_LOG_REGEX = /Failed to refresh the application with RefreshRequest./;
6968

+132-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
import { DeviceLogProviderBase } from "./device-log-provider-base";
22
import { DEVICE_LOG_EVENT_NAME } from "../constants";
3-
import { LoggerConfigData } from "../../constants";
43
import { injector } from "../yok";
54

5+
import * as chalk from "chalk";
6+
import { LoggerConfigData } from "../../constants";
7+
import { IOptions } from "../../declarations";
8+
69
export class DeviceLogProvider extends DeviceLogProviderBase {
710
constructor(
811
protected $logFilter: Mobile.ILogFilter,
912
protected $logger: ILogger,
10-
protected $logSourceMapService: Mobile.ILogSourceMapService
13+
protected $logSourceMapService: Mobile.ILogSourceMapService,
14+
protected $options: IOptions
1115
) {
1216
super($logFilter, $logger, $logSourceMapService);
1317
}
@@ -17,6 +21,7 @@ export class DeviceLogProvider extends DeviceLogProviderBase {
1721
platform: string,
1822
deviceIdentifier: string
1923
): void {
24+
// console.log(lineText)
2025
const loggingOptions = this.getDeviceLogOptionsForDevice(deviceIdentifier);
2126
let data = this.$logFilter.filterData(platform, lineText, loggingOptions);
2227
data = this.$logSourceMapService.replaceWithOriginalFileLocations(
@@ -25,7 +30,7 @@ export class DeviceLogProvider extends DeviceLogProviderBase {
2530
loggingOptions
2631
);
2732
if (data) {
28-
this.logDataCore(data);
33+
this.logDataCore(data, deviceIdentifier);
2934
this.emit(DEVICE_LOG_EVENT_NAME, lineText, deviceIdentifier, platform);
3035
}
3136
}
@@ -34,8 +39,130 @@ export class DeviceLogProvider extends DeviceLogProviderBase {
3439
this.$logFilter.loggingLevel = logLevel.toUpperCase();
3540
}
3641

37-
private logDataCore(data: string): void {
38-
this.$logger.info(data, { [LoggerConfigData.skipNewLine]: true });
42+
private consoleLogLevelRegex: RegExp = /^CONSOLE (LOG|INFO|WARN|ERROR|TRACE|INFO( .+)):\s/;
43+
private consoleLevelColor: Record<string, (line: string) => string> = {
44+
log: (line) => line,
45+
info: chalk.cyanBright,
46+
warn: chalk.yellowBright,
47+
error: chalk.redBright,
48+
trace: chalk.grey,
49+
time: chalk.greenBright,
50+
};
51+
52+
private deviceColorMap = new Map<string, typeof chalk.BackgroundColor>();
53+
54+
private colorPool: typeof chalk.BackgroundColor[] = [
55+
"bgGray",
56+
"bgMagentaBright",
57+
"bgBlueBright",
58+
"bgWhiteBright",
59+
"bgCyanBright",
60+
"bgYellowBright",
61+
"bgGreenBright",
62+
];
63+
private colorPoolIndex = 0;
64+
65+
private getDeviceColor(deviceIdentifier: string) {
66+
if (this.deviceColorMap.has(deviceIdentifier)) {
67+
return this.deviceColorMap.get(deviceIdentifier);
68+
}
69+
70+
const color = this.colorPool[this.colorPoolIndex];
71+
// wrap around if we have no more colors in the pool
72+
this.colorPoolIndex =
73+
this.colorPoolIndex === this.colorPool.length - 1
74+
? 0
75+
: this.colorPoolIndex + 1;
76+
77+
this.deviceColorMap.set(deviceIdentifier, color);
78+
79+
return color;
80+
}
81+
82+
private logDataCore(data: string, deviceIdentifier: string): void {
83+
// todo: use config to set logger - --env.classicLogs is temporary!
84+
if ("classicLogs" in this.$options.env) {
85+
// legacy logging
86+
this.$logger.info(data, { [LoggerConfigData.skipNewLine]: true });
87+
return;
88+
}
89+
90+
// todo: extract into an injectable printer/logger service
91+
let shouldPrepend = false;
92+
let splitIndexes: number[] = [];
93+
const lines = data
94+
.split(/\n(CONSOLE)/)
95+
.map((line, index, lines) => {
96+
if (line === "CONSOLE") {
97+
shouldPrepend = true;
98+
99+
if (lines[index - 1]) {
100+
splitIndexes.push(index - 1);
101+
}
102+
103+
return null;
104+
}
105+
106+
if (shouldPrepend) {
107+
shouldPrepend = false;
108+
return `CONSOLE${line}`;
109+
}
110+
111+
const suffix = line.endsWith("\n") ? "" : "\n";
112+
return line + suffix;
113+
})
114+
.map((line, index) => {
115+
if (splitIndexes.includes(index)) {
116+
return line + "\n";
117+
}
118+
return line;
119+
})
120+
.filter((line) => {
121+
return line !== null;
122+
});
123+
124+
if (!lines.length && data.length) {
125+
lines.push(data);
126+
}
127+
128+
for (const line of lines) {
129+
let [match, level, timeLabel] =
130+
this.consoleLogLevelRegex.exec(line) ?? [];
131+
132+
if (timeLabel) {
133+
level = "time";
134+
timeLabel = timeLabel.replace("INFO ", "").trim() + ": ";
135+
} else {
136+
level = level?.toLowerCase() ?? "log";
137+
}
138+
139+
const toLog = [timeLabel ?? "", match ? line.replace(match, "") : line]
140+
.join("")
141+
.trim();
142+
143+
toLog.split("\n").forEach((actualLine) => {
144+
this.printLine(
145+
chalk[this.getDeviceColor(deviceIdentifier)](" "),
146+
this.consoleLevelColor[level](actualLine)
147+
);
148+
});
149+
}
150+
}
151+
152+
private printLine(prefix: string, ...parts: string[]) {
153+
const maxWidth = process.stdout.columns - 2;
154+
const fullLine = parts.join(" ");
155+
156+
// console.log(prefix, fullLine);
157+
// return;
158+
if (fullLine.length < maxWidth) {
159+
console.log(prefix, fullLine);
160+
} else {
161+
for (let i = 0; i < fullLine.length; i += maxWidth) {
162+
const part = fullLine.substring(i, i + maxWidth);
163+
console.log(prefix, part);
164+
}
165+
}
39166
}
40167
}
41168
injector.register("deviceLogProvider", DeviceLogProvider);

0 commit comments

Comments
 (0)