|
1 | 1 | const sourcemap = require("source-map"); |
2 | 2 | import * as path from "path"; |
3 | 3 | import { cache } from "../common/decorators"; |
4 | | -import * as iOSLogFilterBase from "../common/mobile/ios/ios-log-filter"; |
5 | 4 |
|
6 | | -export class IOSLogFilter extends iOSLogFilterBase.IOSLogFilter implements Mobile.IPlatformLogFilter { |
7 | | - protected infoFilterRegex = /^.*?((?:<Notice>:)?.*?(((?:CONSOLE|JS) (?:LOG|ERROR)).*?))$/im; |
| 5 | +export class IOSLogFilter implements Mobile.IPlatformLogFilter { |
| 6 | + // Used to recognize output related to the current project |
| 7 | + // This looks for artifacts like: AppName[22432] or AppName(SomeTextHere)[23123] |
| 8 | + private appOutputRegex: RegExp = /([^\s\(\)]+)(?:\([^\s]+\))?\[[0-9]+\]/; |
| 9 | + |
| 10 | + // Used to trim the passed messages to a simpler output |
| 11 | + // Example: |
| 12 | + // This: "May 24 15:54:52 Dragons-iPhone NativeScript250(NativeScript)[356] <Notice>: CONSOLE ERROR file:///app/tns_modules/@angular/core/bundles/core.umd.js:3477:36: ORIGINAL STACKTRACE:" |
| 13 | + // Becomes: CONSOLE ERROR file:///app/tns_modules/@angular/core/bundles/core.umd.js:3477:36: ORIGINAL STACKTRACE: |
| 14 | + protected infoFilterRegex = new RegExp(`^.*(?:<Notice>:|<Error>:|<Warning>:|\\(NativeScript\\)|${this.appOutputRegex.source}:){1}`); |
| 15 | + |
| 16 | + private filterActive: boolean = true; |
8 | 17 |
|
9 | 18 | private partialLine: string = null; |
10 | 19 |
|
11 | | - constructor($loggingLevels: Mobile.ILoggingLevels, |
| 20 | + constructor(private $logger: ILogger, |
| 21 | + private $loggingLevels: Mobile.ILoggingLevels, |
12 | 22 | private $fs: IFileSystem, |
13 | 23 | private $projectData: IProjectData) { |
14 | | - super($loggingLevels); |
15 | 24 | } |
16 | 25 |
|
17 | | - public filterData(data: string, logLevel: string, pid?: string): string { |
18 | | - data = super.filterData(data, logLevel, pid); |
19 | | - if (pid && data && data.indexOf(`[${pid}]`) === -1) { |
20 | | - return null; |
| 26 | + public filterData(data: string, loggingOptions: Mobile.IDeviceLogOptions = <any>{}): string { |
| 27 | + const specifiedLogLevel = (loggingOptions.logLevel || '').toUpperCase(); |
| 28 | + this.$logger.trace("Logging options", loggingOptions); |
| 29 | + |
| 30 | + if (specifiedLogLevel !== this.$loggingLevels.info || !data) { |
| 31 | + return data; |
21 | 32 | } |
22 | 33 |
|
23 | | - if (data) { |
24 | | - const skipLastLine = data[data.length - 1] !== "\n"; |
25 | | - const lines = data.split("\n"); |
26 | | - let result = ""; |
27 | | - for (let i = 0; i < lines.length; i++) { |
28 | | - let line = lines[i]; |
29 | | - if (i === 0 && this.partialLine) { |
30 | | - line = this.partialLine + line; |
31 | | - this.partialLine = null; |
32 | | - } |
33 | | - if (line.length < 1 || |
34 | | - line.indexOf("SecTaskCopyDebugDescription") !== -1 || |
35 | | - line.indexOf("NativeScript loaded bundle") !== -1 || |
36 | | - (line.indexOf("assertion failed:") !== -1 && data.indexOf("libxpc.dylib") !== -1)) { |
37 | | - continue; |
38 | | - } |
39 | | - // CONSOLE LOG messages comme in the following form: |
40 | | - // <date> <domain> <app>[pid] CONSOLE LOG file:///location:row:column: <actual message goes here> |
41 | | - // This code removes unnecessary information from log messages. The output looks like: |
42 | | - // CONSOLE LOG file:///location:row:column: <actual message goes here> |
43 | | - if (pid) { |
44 | | - if (line.indexOf(`[${pid}]: `) !== -1) { |
45 | | - const pidRegex = new RegExp(`^.*\\[${pid}\\]:\\s(?:\\(NativeScript\\)\\s)?`); |
46 | | - line = line.replace(pidRegex, "").trim(); |
47 | | - this.getOriginalFileLocation(line); |
48 | | - result += this.getOriginalFileLocation(line) + "\n"; |
49 | | - } |
| 34 | + const chunkLines = data.split('\n'); |
| 35 | + const skipLastLine = chunkLines.length > 0 ? data[data.length - 1] !== "\n" : false; |
| 36 | + let output = ""; |
| 37 | + for (let i = 0; i < chunkLines.length; i++) { |
| 38 | + let currentLine = chunkLines[i]; |
50 | 39 |
|
51 | | - continue; |
52 | | - } |
53 | | - if (skipLastLine && i === lines.length - 1 && lines.length > 1) { |
54 | | - this.partialLine = line; |
55 | | - } else { |
56 | | - result += this.getOriginalFileLocation(line) + "\n"; |
57 | | - } |
| 40 | + if (this.partialLine) { |
| 41 | + currentLine = this.partialLine + currentLine; |
| 42 | + this.partialLine = undefined; |
| 43 | + } |
| 44 | + |
| 45 | + if (i === chunkLines.length - 1 && skipLastLine) { |
| 46 | + this.partialLine = currentLine; |
| 47 | + break; |
| 48 | + } |
| 49 | + |
| 50 | + // Legacy filter moved to preFilter |
| 51 | + if (this.preFilter(data, currentLine)) { |
| 52 | + continue; |
| 53 | + } |
| 54 | + |
| 55 | + const matchResult = this.appOutputRegex.exec(currentLine); |
| 56 | + |
| 57 | + if (matchResult && matchResult.length > 1) { |
| 58 | + // Check if the name of the app equals the name of the CLI project and turn on the filter if not. |
| 59 | + // We call initializeProjectData in order to obtain the current project name as the instance |
| 60 | + // of this filter may be used accross multiple projects. |
| 61 | + const projectName = loggingOptions && loggingOptions.projectName; |
| 62 | + this.filterActive = matchResult[1] !== projectName; |
| 63 | + } |
| 64 | + |
| 65 | + if (this.filterActive) { |
| 66 | + continue; |
58 | 67 | } |
59 | | - return result; |
| 68 | + |
| 69 | + const filteredLineInfo = currentLine.match(this.infoFilterRegex); |
| 70 | + if (filteredLineInfo && filteredLineInfo.length > 0) { |
| 71 | + currentLine = currentLine.replace(filteredLineInfo[0], ""); |
| 72 | + } |
| 73 | + |
| 74 | + currentLine = currentLine.trim(); |
| 75 | + output += this.getOriginalFileLocation(currentLine) + '\n'; |
60 | 76 | } |
61 | 77 |
|
62 | | - return data; |
| 78 | + return output.length === 0 ? null : output; |
| 79 | + } |
| 80 | + |
| 81 | + private preFilter(data: string, currentLine: string): boolean { |
| 82 | + return currentLine.length < 1 || |
| 83 | + currentLine.indexOf("SecTaskCopyDebugDescription") !== -1 || |
| 84 | + currentLine.indexOf("NativeScript loaded bundle") !== -1 || |
| 85 | + (currentLine.indexOf("assertion failed:") !== -1 && data.indexOf("libxpc.dylib") !== -1); |
63 | 86 | } |
64 | 87 |
|
65 | 88 | private getOriginalFileLocation(data: string): string { |
|
0 commit comments