This repository has been archived by the owner on Mar 15, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
41fe450
commit b1fb7e6
Showing
6 changed files
with
194 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ uuid | |
self | ||
version | ||
error | ||
crash-reporter | ||
log-inner | ||
log | ||
glob | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import { request } from "node:https"; | ||
|
||
const { | ||
Boolean, | ||
Buffer, | ||
Date, | ||
JSON: { stringify: stringifyJSON }, | ||
Number, | ||
process: { | ||
env: { APPMAP_TELEMETRY_DISABLED }, | ||
}, | ||
Promise, | ||
} = globalThis; | ||
|
||
// This key is meant to be publically shared. However, I'm adding a simple | ||
// obfuscation to mitigate key scraping bots on GitHub. The key is split on | ||
// hypens and base64 encoded without padding. | ||
// key.split('-').map((x) => x.toString('base64').replace(/=*/, '')) | ||
const INSTRUMENTATION_KEY = [ | ||
"NTBjMWE1YzI", | ||
"NDliNA", | ||
"NDkxMw", | ||
"YjdjYw", | ||
"ODZhNzhkNDA3NDVm", | ||
] | ||
.map((x) => Buffer.from(x, "base64").toString("utf8")) | ||
.join("-"); | ||
|
||
const METHOD_REGEX = /at\s(?!\w+:\/\/)(.*?)[\s:]/u; | ||
const INGESTION_ENDPOINT = "centralus-2.in.applicationinsights.azure.com"; | ||
const LOCATION_REGEX = /at\s+(\w+:\/\/|.*\()?(?:\w+:\/\/)?(.*):(\d+):\d+/u; | ||
|
||
export const parseExceptionStack = (exception) => | ||
exception.stack | ||
?.split("\n") | ||
.filter((line) => line.match(/^\s+at\s/u)) | ||
.map((line, index) => { | ||
const method = line.match(METHOD_REGEX)?.[1] ?? ""; | ||
const [, , fileName, lineNumber] = line.match(LOCATION_REGEX) ?? []; | ||
if (!fileName || !lineNumber) { | ||
return null; | ||
} | ||
|
||
return { | ||
level: index, | ||
method, | ||
fileName, | ||
line: Number(lineNumber), | ||
}; | ||
}) | ||
.filter(Boolean) ?? []; | ||
|
||
/* c8 ignore start */ | ||
export const reportException = (exception) => { | ||
if (APPMAP_TELEMETRY_DISABLED) { | ||
return null; | ||
} | ||
|
||
const data = { | ||
name: "Microsoft.ApplicationInsights.Exception", | ||
time: new Date().toISOString(), | ||
iKey: INSTRUMENTATION_KEY, | ||
tags: { | ||
"ai.cloud.roleInstance": "@appland/appmap-agent-js", | ||
}, | ||
data: { | ||
baseType: "ExceptionData", | ||
baseData: { | ||
ver: 2, | ||
handledAt: "UserCode", | ||
exceptions: [ | ||
{ | ||
id: 1, | ||
typeName: exception.name, | ||
message: exception.message, | ||
hasFullStack: Boolean(exception.stack), | ||
parsedStack: parseExceptionStack(exception), | ||
}, | ||
], | ||
}, | ||
}, | ||
}; | ||
|
||
const options = { | ||
hostname: INGESTION_ENDPOINT, | ||
path: "/v2/track", | ||
method: "POST", | ||
headers: { | ||
"Content-Type": "application/json", | ||
}, | ||
}; | ||
|
||
return new Promise((resolve) => { | ||
const req = request(options, resolve); | ||
|
||
// Don't throw if the request fails - we don't want to crash the app | ||
req.on("error", resolve); | ||
|
||
req.write(stringifyJSON(data)); | ||
req.end(); | ||
}); | ||
}; | ||
/* c8 ignore stop */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { assertDeepEqual } from "../../__fixture__.mjs"; | ||
import { parseExceptionStack } from "./index.mjs"; | ||
|
||
{ | ||
const error = { | ||
stack: `InternalAppmapError: expected at least two argv | ||
at assert (file:///Users/user/dev/appland/appmap-agent-js/dist/bundles/recorder-process.mjs:191:11) | ||
at extendConfigurationNode (file:///Users/user/dev/appland/appmap-agent-js/dist/bundles/recorder-process.mjs:5588:3) | ||
at record (file:///Users/user/dev/appland/appmap-agent-js/dist/bundles/recorder-process.mjs:5609:19) | ||
at file:///Users/user/dev/appland/appmap-agent-js/lib/node/recorder.mjs:11:1 | ||
at ModuleJob.run (node:internal/modules/esm/module_job:183:25) | ||
at <anonymous>:1:1`, | ||
message: "expected at least two argv", | ||
name: "InternalAppmapError", | ||
}; | ||
|
||
const stack = parseExceptionStack(error); | ||
assertDeepEqual(stack, [ | ||
{ | ||
level: 0, | ||
method: "assert", | ||
fileName: | ||
"/Users/user/dev/appland/appmap-agent-js/dist/bundles/recorder-process.mjs", | ||
line: 191, | ||
}, | ||
{ | ||
level: 1, | ||
method: "extendConfigurationNode", | ||
fileName: | ||
"/Users/user/dev/appland/appmap-agent-js/dist/bundles/recorder-process.mjs", | ||
line: 5588, | ||
}, | ||
{ | ||
level: 2, | ||
method: "record", | ||
fileName: | ||
"/Users/user/dev/appland/appmap-agent-js/dist/bundles/recorder-process.mjs", | ||
line: 5609, | ||
}, | ||
{ | ||
level: 3, | ||
method: "", | ||
fileName: "/Users/user/dev/appland/appmap-agent-js/lib/node/recorder.mjs", | ||
line: 11, | ||
}, | ||
{ | ||
level: 4, | ||
method: "ModuleJob.run", | ||
fileName: "node:internal/modules/esm/module_job", | ||
line: 183, | ||
}, | ||
{ | ||
level: 5, | ||
method: "<anonymous>", | ||
fileName: "<anonymous>", | ||
line: 1, | ||
}, | ||
]); | ||
} | ||
|
||
{ | ||
// Unknown stack trace formats are ignored | ||
const error = { | ||
stack: `Error: something went wrong | ||
at Class.method ()`, | ||
message: "something went wrong", | ||
name: "Error", | ||
}; | ||
|
||
const stack = parseExceptionStack(error); | ||
assertDeepEqual(stack, []); | ||
} | ||
|
||
{ | ||
// Empty stacks return an empty array | ||
const error = { | ||
stack: null, | ||
message: "something went wrong", | ||
name: "Error", | ||
}; | ||
|
||
const stack = parseExceptionStack(error); | ||
assertDeepEqual(stack, []); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters