|
1 | 1 | import { Trace } from "../transport/trace"; |
2 | 2 | import { promises, existsSync } from "fs"; |
3 | 3 | import { KlepperError } from "../transport/base"; |
4 | | -import { CatchExceptionsOptions, KlepperOptions } from "../transport/options"; |
| 4 | +import { CatchExceptionsOptions } from "../transport/options"; |
5 | 5 | import { KlepperEvent } from "../transport/events"; |
6 | 6 | import { KlepperIncomingMessage } from "../transport/http"; |
7 | | -import { mapRequestData } from "./helpers"; |
| 7 | +import { getOsPlatform, mapRequestData } from "./helpers"; |
| 8 | +import * as os from "os"; |
8 | 9 |
|
9 | 10 | const FULL_MATCH = |
10 | | - /at (?:async )?(?:(.+?)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/; |
| 11 | + /at (?:async )?(?:(.+?)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/; |
11 | 12 |
|
12 | 13 | export const parseStackTraces = async (stack: string): Promise<Trace[]> => { |
13 | | - const frames: Trace[] = []; |
| 14 | + const frames: Trace[] = []; |
14 | 15 |
|
15 | | - if (!stack.length) { |
16 | | - return []; |
17 | | - } |
| 16 | + if (!stack.length) { |
| 17 | + return []; |
| 18 | + } |
18 | 19 |
|
19 | | - for (const line of stack.split("\n").slice(1)) { |
20 | | - const frame = await createTrace(line); |
21 | | - if (frame) { |
22 | | - frames.push(frame); |
23 | | - } |
| 20 | + for (const line of stack.split("\n").slice(1)) { |
| 21 | + const frame = await createTrace(line); |
| 22 | + if (frame) { |
| 23 | + frames.push(frame); |
24 | 24 | } |
| 25 | + } |
25 | 26 |
|
26 | | - return ( |
27 | | - frames.slice(0, 25).map((frame) => ({ |
28 | | - ...frame, |
29 | | - })) || [] |
30 | | - ); |
| 27 | + return ( |
| 28 | + frames.slice(0, 25).map((frame) => ({ |
| 29 | + ...frame, |
| 30 | + })) || [] |
| 31 | + ); |
31 | 32 | }; |
32 | 33 |
|
33 | 34 | export const createTrace = async (line: string): Promise<Trace | undefined> => { |
34 | | - const lineMatch = line.match(FULL_MATCH); |
35 | | - if (!lineMatch || lineMatch[0].includes("<anonymous>")) { |
36 | | - return undefined; |
37 | | - } |
38 | | - |
39 | | - let functionName: string | undefined; |
40 | | - let typeName: string | undefined; |
41 | | - let methodName: string | undefined; |
42 | | - let splitedPath: string[] | undefined; |
43 | | - |
44 | | - if (lineMatch[1]) { |
45 | | - functionName = lineMatch[1]; |
46 | | - } |
47 | | - |
48 | | - if (functionName === undefined) { |
49 | | - functionName = typeName ? `${typeName}.${methodName}` : "<anonymous>"; |
50 | | - } |
51 | | - |
52 | | - const path = lineMatch[2]?.startsWith("file://") |
53 | | - ? lineMatch[2].substr(7) |
54 | | - : lineMatch[2]; |
55 | | - const internal = |
56 | | - path !== undefined && |
57 | | - !path.includes("node_modules/") && |
58 | | - !path.includes("node_modules\\") && |
59 | | - !path.includes("internal/"); |
60 | | - |
61 | | - const isNodeProcess = path?.includes("internal") || path?.includes("process"); |
62 | | - isNodeProcess |
63 | | - ? (splitedPath = path?.split("/")) |
64 | | - : (splitedPath = path?.split("\\")); |
65 | | - |
66 | | - const fileName = splitedPath[splitedPath?.length - 1]; |
67 | | - |
68 | | - const splitedFilename = fileName.split("."); |
69 | | - const extension = splitedFilename[splitedFilename.length - 1]; |
70 | | - const lineNo = parseInt(lineMatch[3], 10); |
71 | | - |
72 | | - const { code, preCode, postCode } = await getCodeFromFs(path, lineNo); |
73 | | - |
74 | | - return { |
75 | | - filename: fileName, |
76 | | - function: functionName, |
77 | | - absPath: path, |
78 | | - lineNo, |
79 | | - columnNo: parseInt(lineMatch[4], 10) || undefined, |
80 | | - internal, |
81 | | - extension, |
82 | | - code, |
83 | | - postCode, |
84 | | - preCode, |
85 | | - }; |
| 35 | + const lineMatch = line.match(FULL_MATCH); |
| 36 | + if (!lineMatch || lineMatch[0].includes("<anonymous>")) { |
| 37 | + return undefined; |
| 38 | + } |
| 39 | + |
| 40 | + let functionName: string | undefined; |
| 41 | + let typeName: string | undefined; |
| 42 | + let methodName: string | undefined; |
| 43 | + let splitedPath: string[] | undefined; |
| 44 | + |
| 45 | + if (lineMatch[1]) { |
| 46 | + functionName = lineMatch[1]; |
| 47 | + } |
| 48 | + |
| 49 | + if (functionName === undefined) { |
| 50 | + functionName = typeName ? `${typeName}.${methodName}` : "<anonymous>"; |
| 51 | + } |
| 52 | + |
| 53 | + const path = lineMatch[2]?.startsWith("file://") |
| 54 | + ? lineMatch[2].substr(7) |
| 55 | + : lineMatch[2]; |
| 56 | + const internal = |
| 57 | + path !== undefined && |
| 58 | + !path.includes("node_modules/") && |
| 59 | + !path.includes("node_modules\\") && |
| 60 | + !path.includes("internal/"); |
| 61 | + |
| 62 | + const isNodeProcess = path?.includes("internal") || path?.includes("process"); |
| 63 | + isNodeProcess |
| 64 | + ? (splitedPath = path?.split("/")) |
| 65 | + : (splitedPath = path?.split("\\")); |
| 66 | + |
| 67 | + const fileName = splitedPath[splitedPath?.length - 1]; |
| 68 | + |
| 69 | + const splitedFilename = fileName.split("."); |
| 70 | + const extension = splitedFilename[splitedFilename.length - 1]; |
| 71 | + const lineNo = parseInt(lineMatch[3], 10); |
| 72 | + |
| 73 | + const { code, preCode, postCode } = await getCodeFromFs(path, lineNo); |
| 74 | + |
| 75 | + return { |
| 76 | + filename: fileName, |
| 77 | + function: functionName, |
| 78 | + absPath: path, |
| 79 | + lineNo, |
| 80 | + columnNo: parseInt(lineMatch[4], 10) || undefined, |
| 81 | + internal, |
| 82 | + extension, |
| 83 | + code, |
| 84 | + postCode, |
| 85 | + preCode, |
| 86 | + }; |
86 | 87 | }; |
87 | 88 |
|
88 | 89 | const getCodeFromFs = async ( |
89 | | - path: string, |
90 | | - codeLine: number |
| 90 | + path: string, |
| 91 | + codeLine: number |
91 | 92 | ): Promise<{ code: string; preCode: string[]; postCode: string[] }> => { |
92 | | - let code: string = ""; |
93 | | - let preCode: string[] = []; |
94 | | - let postCode: string[] = []; |
95 | | - let linesOfCode: string[] = []; |
96 | | - |
97 | | - const context = await readFileAsync(path); |
98 | | - |
99 | | - if (context) { |
100 | | - linesOfCode = context?.split("\n"); |
101 | | - |
102 | | - code = linesOfCode[codeLine - 1]; |
103 | | - preCode = linesOfCode.slice(codeLine - 6, codeLine - 1); |
104 | | - postCode = linesOfCode.slice(codeLine + 1, codeLine + 6); |
105 | | - } |
106 | | - |
107 | | - return { |
108 | | - code, |
109 | | - preCode, |
110 | | - postCode, |
111 | | - }; |
| 93 | + let code: string = ""; |
| 94 | + let preCode: string[] = []; |
| 95 | + let postCode: string[] = []; |
| 96 | + let linesOfCode: string[] = []; |
| 97 | + |
| 98 | + const context = await readFileAsync(path); |
| 99 | + |
| 100 | + if (context) { |
| 101 | + linesOfCode = context?.split("\n"); |
| 102 | + |
| 103 | + code = linesOfCode[codeLine - 1]; |
| 104 | + preCode = linesOfCode.slice(codeLine - 6, codeLine - 1); |
| 105 | + postCode = linesOfCode.slice(codeLine + 1, codeLine + 6); |
| 106 | + } |
| 107 | + |
| 108 | + return { |
| 109 | + code, |
| 110 | + preCode, |
| 111 | + postCode, |
| 112 | + }; |
112 | 113 | }; |
113 | 114 |
|
114 | 115 | const readFileAsync = async (path: string): Promise<string> => { |
115 | | - let context = ""; |
| 116 | + let context = ""; |
116 | 117 |
|
117 | | - //check if file with this path exist |
118 | | - const isFileExists = existsSync(path); |
119 | | - if (isFileExists) { |
120 | | - context = await promises.readFile(path, "utf8"); |
121 | | - } |
| 118 | + //check if file with this path exist |
| 119 | + const isFileExists = existsSync(path); |
| 120 | + if (isFileExists) { |
| 121 | + context = await promises.readFile(path, "utf8"); |
| 122 | + } |
122 | 123 |
|
123 | | - return context; |
| 124 | + return context; |
124 | 125 | }; |
125 | 126 |
|
126 | | -export const prepareException = async (error: KlepperError, options?: CatchExceptionsOptions, req?: KlepperIncomingMessage): Promise<KlepperEvent> => { |
127 | | - const { message, name } = error; |
128 | | - |
129 | | - const traces = await parseStackTraces(String(error?.stack)); |
130 | | - const event: KlepperEvent = { |
131 | | - type: name, |
132 | | - message, |
133 | | - traces, |
134 | | - stack: String(error.stack), |
135 | | - options |
136 | | - }; |
137 | | - |
138 | | - if (req !== undefined) { |
139 | | - event.requestData = mapRequestData(req); |
140 | | - } |
141 | | - |
142 | | - return event; |
143 | | -} |
| 127 | +export const prepareException = async ( |
| 128 | + error: KlepperError, |
| 129 | + options?: CatchExceptionsOptions, |
| 130 | + req?: KlepperIncomingMessage |
| 131 | +): Promise<KlepperEvent> => { |
| 132 | + const { message, name } = error; |
| 133 | + |
| 134 | + const platform = getOsPlatform(); |
| 135 | + |
| 136 | + const traces = await parseStackTraces(String(error?.stack)); |
| 137 | + const event: KlepperEvent = { |
| 138 | + type: name, |
| 139 | + message, |
| 140 | + traces, |
| 141 | + stack: String(error.stack), |
| 142 | + options, |
| 143 | + platform |
| 144 | + }; |
| 145 | + |
| 146 | + if (req !== undefined) { |
| 147 | + event.requestData = mapRequestData(req); |
| 148 | + } |
| 149 | + |
| 150 | + return event; |
| 151 | +}; |
0 commit comments