From 5061735da79cb8bf10b4c78fb536eea3e9ba3f04 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Wed, 24 Jul 2024 18:10:29 +0200 Subject: [PATCH] feat: :sparkles: Add Sentry support --- README.md | 1 + app.ts | 2 ++ bun.lockb | Bin 254548 -> 278820 bytes config/config.example.toml | 12 ++++++++++++ index.ts | 2 ++ package.json | 1 + packages/config-manager/config.type.ts | 21 +++++++++++++++++++++ utils/sentry.ts | 18 ++++++++++++++++++ 8 files changed, 57 insertions(+) create mode 100644 utils/sentry.ts diff --git a/README.md b/README.md index 2bbb3744..13146f91 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ - [x] Advanced Roles and Permissions API. - [x] HTTP proxy support - [x] Tor hidden service support +- [x] Sentry logging support - [x] Ability to change the domain name in a single config change, without any database edits ## Screenshots diff --git a/app.ts b/app.ts index 94cfdd23..7954b841 100644 --- a/app.ts +++ b/app.ts @@ -1,4 +1,5 @@ import { errorResponse, jsonResponse, response } from "@/response"; +import { sentry } from "@/sentry"; import { Hono } from "@hono/hono"; import { getLogger } from "@logtape/logtape"; import { config } from "config-manager"; @@ -96,6 +97,7 @@ export const appFactory = async () => { app.onError((error) => { const serverLogger = getLogger("server"); serverLogger.error`${error}`; + sentry?.captureException(error); return jsonResponse( { error: "A server error occured", diff --git a/bun.lockb b/bun.lockb index 810ed68d4806ad6c6679efca3b5c62361d4724df..dcf00f4a53ba761f9f6363a598002edd74d36a91 100755 GIT binary patch delta 60540 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 L-9>0k=l%Z&mtr~x diff --git a/config/config.example.toml b/config/config.example.toml index 7360d170..628bd9cc 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -389,6 +389,18 @@ log_ip = false # Log all filtered objects log_filters = true +[logging.sentry] +# Whether to enable https://sentry.io error logging +enabled = false +# Sentry DSN for error logging +dsn = "" +debug = false + +sample_rate = 1.0 +traces_sample_rate = 1.0 +max_breadcrumbs = 100 +# environment = "production" + [logging.storage] # Path to logfile for requests requests = "logs/requests.log" diff --git a/index.ts b/index.ts index dfd8c83b..2490b018 100644 --- a/index.ts +++ b/index.ts @@ -1,4 +1,5 @@ import { configureLoggers } from "@/loggers"; +import { sentry } from "@/sentry"; import { createServer } from "@/server"; import { config } from "config-manager"; import { appFactory } from "~/app"; @@ -6,6 +7,7 @@ import { setupDatabase } from "./drizzle/db"; if (import.meta.main) { await import("./setup"); + sentry?.captureMessage("Server started"); } await setupDatabase(); diff --git a/package.json b/package.json index 40c7f129..50519171 100644 --- a/package.json +++ b/package.json @@ -106,6 +106,7 @@ "@lysand-org/client": "^0.2.5", "@lysand-org/federation": "2.1.8", "@oclif/core": "^4.0.14", + "@sentry/bun": "^8.19.0", "@tufjs/canonical-json": "^2.0.0", "altcha-lib": "^0.4.1", "blurhash": "^2.0.5", diff --git a/packages/config-manager/config.type.ts b/packages/config-manager/config.type.ts index 1f9b6bcf..8487da0d 100644 --- a/packages/config-manager/config.type.ts +++ b/packages/config-manager/config.type.ts @@ -568,6 +568,20 @@ export const configValidator = z.object({ .default("info"), log_ip: z.boolean().default(false), log_filters: z.boolean().default(true), + sentry: z + .object({ + enabled: z.boolean().default(false), + dsn: z.string().url().or(z.literal("")).optional(), + debug: z.boolean().default(false), + sample_rate: z.number().min(0).max(1.0).default(1.0), + traces_sample_rate: z.number().min(0).max(1.0).default(1.0), + max_breadcrumbs: z.number().default(100), + environment: z.string().optional(), + }) + .refine( + (arg) => (arg.enabled ? !!arg.dsn : true), + "When sentry is enabled, DSN must be set", + ), storage: z .object({ requests: z.string().default("logs/requests.log"), @@ -582,6 +596,13 @@ export const configValidator = z.object({ log_level: "info", log_ip: false, log_filters: true, + sentry: { + enabled: false, + debug: false, + sample_rate: 1.0, + traces_sample_rate: 1.0, + max_breadcrumbs: 100, + }, storage: { requests: "logs/requests.log", }, diff --git a/utils/sentry.ts b/utils/sentry.ts new file mode 100644 index 00000000..33a56af3 --- /dev/null +++ b/utils/sentry.ts @@ -0,0 +1,18 @@ +import * as Sentry from "@sentry/bun"; +import { config } from "config-manager"; +import pkg from "~/package.json"; + +const sentryInstance = + config.logging.sentry.enabled && + Sentry.init({ + dsn: config.logging.sentry.dsn, + debug: config.logging.sentry.debug, + sampleRate: config.logging.sentry.sample_rate, + maxBreadcrumbs: config.logging.sentry.max_breadcrumbs, + tracesSampleRate: config.logging.sentry.traces_sample_rate, + environment: config.logging.sentry.environment, + tracePropagationTargets: [config.http.bind], + release: pkg.version, + }); + +export const sentry = sentryInstance || undefined;