mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat: add Sentry error tracking with PII scrubbing
This commit is contained in:
@@ -73,6 +73,12 @@ app.setErrorHandler((error: Error & { statusCode?: number }, request, reply) =>
|
|||||||
{ err: error, url: request.url, method: request.method },
|
{ err: error, url: request.url, method: request.method },
|
||||||
"Unhandled request error",
|
"Unhandled request error",
|
||||||
);
|
);
|
||||||
|
try {
|
||||||
|
const Sentry = require("@sentry/node") as typeof import("@sentry/node");
|
||||||
|
Sentry.captureException(error);
|
||||||
|
} catch {
|
||||||
|
// Sentry not available
|
||||||
|
}
|
||||||
const isProduction = process.env.NODE_ENV === "production";
|
const isProduction = process.env.NODE_ENV === "production";
|
||||||
reply.status(statusCode).send({
|
reply.status(statusCode).send({
|
||||||
error: statusCode >= 500 ? "Internal server error" : error.message,
|
error: statusCode >= 500 ? "Internal server error" : error.message,
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import { env } from "../config.js";
|
|||||||
import { db, schema } from "../db/index.js";
|
import { db, schema } from "../db/index.js";
|
||||||
import { getAuthUser } from "../plugins/auth.js";
|
import { getAuthUser } from "../plugins/auth.js";
|
||||||
|
|
||||||
|
const FILE_EXT_PATTERN =
|
||||||
|
/\.(jpe?g|png|pdf|webp|gif|tiff?|bmp|svg|he[ic]f?|avif|raw|cr2|nef|arw|dng|psd|tga|exr|hdr)\b/gi;
|
||||||
|
const FILE_PATH_PATTERN = /\/(tmp\/workspace|data\/files|data\/ai)\//g;
|
||||||
|
|
||||||
let posthogClient: import("posthog-node").PostHog | null = null;
|
let posthogClient: import("posthog-node").PostHog | null = null;
|
||||||
|
|
||||||
export function initAnalytics(): void {
|
export function initAnalytics(): void {
|
||||||
@@ -19,6 +23,51 @@ export function initAnalytics(): void {
|
|||||||
} catch {
|
} catch {
|
||||||
// posthog-node not available — analytics disabled
|
// posthog-node not available — analytics disabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (env.SENTRY_DSN) {
|
||||||
|
try {
|
||||||
|
const Sentry = require("@sentry/node") as typeof import("@sentry/node");
|
||||||
|
Sentry.init({
|
||||||
|
dsn: env.SENTRY_DSN,
|
||||||
|
sendDefaultPii: false,
|
||||||
|
beforeSend(event) {
|
||||||
|
if (event.user) {
|
||||||
|
delete event.user.email;
|
||||||
|
delete event.user.username;
|
||||||
|
}
|
||||||
|
if (event.exception?.values) {
|
||||||
|
for (const ex of event.exception.values) {
|
||||||
|
if (ex.value) {
|
||||||
|
ex.value = ex.value
|
||||||
|
.replace(FILE_EXT_PATTERN, ".[REDACTED]")
|
||||||
|
.replace(FILE_PATH_PATTERN, "/[REDACTED]/");
|
||||||
|
}
|
||||||
|
if (ex.stacktrace?.frames) {
|
||||||
|
for (const frame of ex.stacktrace.frames) {
|
||||||
|
if (frame.filename) {
|
||||||
|
frame.filename = frame.filename
|
||||||
|
.replace(FILE_EXT_PATTERN, ".[REDACTED]")
|
||||||
|
.replace(FILE_PATH_PATTERN, "/[REDACTED]/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return event;
|
||||||
|
},
|
||||||
|
beforeBreadcrumb(breadcrumb) {
|
||||||
|
if (breadcrumb.message) {
|
||||||
|
breadcrumb.message = breadcrumb.message
|
||||||
|
.replace(FILE_EXT_PATTERN, ".[REDACTED]")
|
||||||
|
.replace(FILE_PATH_PATTERN, "/[REDACTED]/");
|
||||||
|
}
|
||||||
|
return breadcrumb;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// @sentry/node not available
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function shutdownAnalytics(): Promise<void> {
|
export async function shutdownAnalytics(): Promise<void> {
|
||||||
@@ -26,6 +75,13 @@ export async function shutdownAnalytics(): Promise<void> {
|
|||||||
await posthogClient.shutdown();
|
await posthogClient.shutdown();
|
||||||
posthogClient = null;
|
posthogClient = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const Sentry = require("@sentry/node") as typeof import("@sentry/node");
|
||||||
|
await Sentry.close(2000);
|
||||||
|
} catch {
|
||||||
|
// @sentry/node not available
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInstanceId(): string {
|
function getInstanceId(): string {
|
||||||
|
|||||||
Reference in New Issue
Block a user