edgerender
Version:
Render at the edge
121 lines • 4.03 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Sentry = exports.setupSentry = void 0;
function setupSentry(dsn, environment, release) {
const m = dsn.match(/^https:\/\/(.+?)@(.+?)\.ingest\.sentry\.io\/(.+)/);
if (m) {
const [, key, server, app] = m;
return new Sentry(key, server, app, environment, release);
}
else {
console.warn('invalid sentry DSN', dsn);
}
}
exports.setupSentry = setupSentry;
class Sentry {
key;
server;
app;
release;
environment;
constructor(key, server, app, environment, release) {
this.key = key;
this.server = server;
this.app = app;
this.environment = environment || 'production';
this.release = release;
}
captureMessage(event, message, { level = 'info', extra = {} } = {}) {
event.waitUntil(this.capture(event.request, { message, level, extra }));
}
captureException(event, exc, { level = 'error', extra = {} } = {}) {
const message = exc.toString() || exc.message || 'Unknown error';
event.waitUntil(this.capture(event.request, {
exception: {
mechanism: { handled: true, type: 'generic' },
values: [
{
type: 'Error',
value: message,
stacktrace: { frames: get_frames(exc.stack) },
},
],
},
message,
level,
extra,
}));
}
async capture(request, data) {
const sentry_data = Object.assign({
platform: 'javascript',
logger: 'cloudflare',
environment: this.environment,
fingerprint: [`${request.method}-${request.url}-${data.message || 'null'}`],
user: {
ip_address: request.headers.get('CF-Connecting-IP'),
},
request: {
url: request.url,
method: request.method,
headers: Object.fromEntries(request.headers),
},
extra: {},
}, data);
sentry_data.extra.cloudflare = request.cf;
// console.log('sentry data:', sentry_data)
// if (this.release) {
// defaults.release = this.release
// }
const params = {
sentry_key: this.key,
sentry_version: 7,
sentry_client: 'edgerender; https://github.com/samuelcolvin/edgerender',
};
const args = Object.entries(params)
.map(([k, v]) => `${k}=${encodeURIComponent(v)}`)
.join('&');
const sentry_url = `https://sentry.io/api/${this.app}/store/?${args}`;
return await fetch(sentry_url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(sentry_data),
});
}
}
exports.Sentry = Sentry;
function get_frames(stack) {
if (!stack) {
return [];
}
const lines = stack.split('\n');
lines.splice(0, 1);
return lines
.reverse()
.filter(line => line.match(/^ {4}at /))
.map(extract_frame);
}
const frame_regexes = [
/^ +at (?<func>.+?) \((?<filename>.+?):(?<lineno>\d+):(?<colno>\d+)\)/,
/^ +at (?<func>.+?):(?<lineno>\d+):(?<colno>\d+)/,
/^ +at (?<func>.+?) \(/,
];
function extract_frame(line) {
for (const regex of frame_regexes) {
const m = line.match(regex);
if (m) {
const { func, filename, lineno, colno } = m.groups;
const f = {
in_app: true,
filename: `~/${filename || '__unknown__.js'}`,
function: func,
};
if (lineno) {
Object.assign(f, { lineno: parseInt(lineno), colno: parseInt(colno) });
}
return f;
}
}
throw Error(`no frame found in stack line: "${line}"`);
}
//# sourceMappingURL=sentry.js.map