summary refs log tree commit diff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/util/Sentry.ts102
-rw-r--r--src/util/util/index.ts1
2 files changed, 103 insertions, 0 deletions
diff --git a/src/util/util/Sentry.ts b/src/util/util/Sentry.ts
new file mode 100644

index 00000000..3e7bb97b --- /dev/null +++ b/src/util/util/Sentry.ts
@@ -0,0 +1,102 @@ +import { Config } from "./Config"; +import { yellow } from "picocolors"; + +import express from "express"; +import * as SentryNode from "@sentry/node"; +import * as Tracing from "@sentry/tracing"; +import * as Integrations from "@sentry/integrations"; + +// Work around for when bundle calls api/etc +let errorHandlersUsed = false; + +export const Sentry = { + /** Call BEFORE registering your routes */ + init: async (app?: express.Application) => { + const { enabled, endpoint, traceSampleRate, environment } = + Config.get().sentry; + if (!enabled) return; + + if (!!SentryNode.getCurrentHub().getClient()) return; // we've already initialised sentry + + console.log("[Sentry] Enabling sentry..."); + + if (traceSampleRate >= 0.8) { + console.log( + `[Sentry] ${yellow( + "Your sentry trace sampling rate is >= 80%. For large loads, this may degrade performance.", + )}`, + ); + } + + SentryNode.init({ + dsn: endpoint, + integrations: [ + new SentryNode.Integrations.Http({ tracing: true }), + new Tracing.Integrations.Express({ app }), + new Tracing.Integrations.Mysql(), + new Integrations.RewriteFrames({ + root: __dirname, + }), + ], + tracesSampleRate: traceSampleRate, // naming? + environment, + }); + + SentryNode.addGlobalEventProcessor((event, hint) => { + if (event.transaction) { + // Rewrite things that look like IDs to `:id` for sentry + event.transaction = event.transaction + .split("/") + .map((x) => (!parseInt(x) ? x : ":id")) + .join("/"); + } + + // TODO: does this even do anything? + delete event.request?.cookies; + if (event.request?.headers) { + delete event.request.headers["X-Real-Ip"]; + delete event.request.headers["X-Forwarded-For"]; + delete event.request.headers["X-Forwarded-Host"]; + delete event.request.headers["X-Super-Properties"]; + } + + if (event.breadcrumbs) { + event.breadcrumbs = event.breadcrumbs.filter((x) => { + // Filter breadcrumbs that we don't care about + if (x.message?.includes("identified as")) return false; + if (x.message?.includes("[WebSocket] closed")) return false; + if ( + x.message?.includes( + "Got Resume -> cancel not implemented", + ) + ) + return false; + if (x.message?.includes("[Gateway] New connection from")) + return false; + + return true; + }); + } + + return event; + }); + + if (app) { + app.use(SentryNode.Handlers.requestHandler()); + app.use(SentryNode.Handlers.tracingHandler()); + } + }, + + /** Call AFTER registering your routes */ + errorHandler: (app: express.Application) => { + if (!Config.get().sentry.enabled) return; + if (errorHandlersUsed) return; + errorHandlersUsed = true; + + app.use(SentryNode.Handlers.errorHandler()); + app.use(function onError(err: any, req: any, res: any, next: any) { + res.statusCode = 500; + res.end(res.sentry + "\n"); + }); + }, +}; diff --git a/src/util/util/index.ts b/src/util/util/index.ts
index 01ef4eae..0012579f 100644 --- a/src/util/util/index.ts +++ b/src/util/util/index.ts
@@ -20,3 +20,4 @@ export * from "./String"; export * from "./Array"; export * from "./TraverseDirectory"; export * from "./InvisibleCharacters"; +export * from "./Sentry";