diff --git a/pomelo/api/transactions/v1/notifications.ts b/pomelo/api/transactions/v1/notifications.ts index 2a55be1e..60d3c9af 100644 --- a/pomelo/api/transactions/v1/notifications.ts +++ b/pomelo/api/transactions/v1/notifications.ts @@ -2,6 +2,7 @@ import type { VercelRequest, VercelResponse } from "@vercel/node"; import buffer from "../../../utils/buffer.js"; import { sendPushNotification } from "../../../utils/notifications.js"; +import { captureException } from "../../../utils/sentry.js"; import { notificationRequest } from "../../../utils/types.js"; import { signResponse, verifySignature } from "../../../utils/verify.js"; @@ -40,8 +41,8 @@ export default async function notifications(request: VercelRequest, response: Ve }, }); return signResponse(request, response.status(200), JSON.stringify(true)); - } catch { - // TODO(jg): log errors.. + } catch (error: unknown) { + captureException(error, { request, message: "failed to send notification to user" }); return response.status(500).end("internal server error"); } } else { diff --git a/pomelo/utils/sentry.ts b/pomelo/utils/sentry.ts new file mode 100644 index 00000000..e9e0860b --- /dev/null +++ b/pomelo/utils/sentry.ts @@ -0,0 +1,25 @@ +import * as Sentry from "@sentry/node"; +import type { VercelRequest } from "@vercel/node"; + +Sentry.init({ + dsn: process.env.SENTRY_DSN, + environment: process.env.ENV === "development" ? "development" : "production", + tracesSampleRate: 1, + attachStacktrace: true, + autoSessionTracking: true, +}); + +type ExceptionProperties = { + request: VercelRequest; + message: string; +}; + +export function captureException(error: unknown, { request: { url }, message }: ExceptionProperties) { + try { + Sentry.captureException(error, { tags: { url, message } }); + } catch { + // ignore + } +} + +export default Sentry;