Last active 4 days ago

135dika revised this gist 4 days ago. Go to revision

1 file changed, 185 insertions

Sentry_nestjs_integration_guide.md(file created)

@@ -0,0 +1,185 @@
1 + # Setup Error Tracking (Sentry SDK) di NestJS
2 +
3 + Dokumentasi ini buat masang error tracking (capture exception, request context,
4 + stack trace) ke instance Sentry-compatible (GlitchTip self-hosted atau Sentry Cloud)
5 + di aplikasi NestJS.
6 +
7 + ## 1. Prasyarat
8 +
9 + - Sudah punya DSN dari project di dashboard GlitchTip/Sentry
10 + (format: `https://<key>@<domain>/<project_id>`)
11 + - Project NestJS pakai `.env` buat konfigurasi
12 +
13 + ## 2. Instalasi
14 +
15 + ```bash
16 + npm install @sentry/nestjs --save
17 + ```
18 +
19 + ## 3. Environment variable
20 +
21 + Tambahin di `.env`:
22 +
23 + ```
24 + SENTRY_DSN="https://<key>@<domain>/<project_id>"
25 + ```
26 +
27 + ## 4. Buat file `src/instrument.ts`
28 +
29 + File ini **harus terpisah** dari `main.ts`, dan berisi `Sentry.init()`.
30 +
31 + ```ts
32 + import 'dotenv/config'; // wajib, load .env sebelum Sentry.init() dipanggil
33 + import * as Sentry from '@sentry/nestjs';
34 +
35 + Sentry.init({
36 + dsn: process.env.SENTRY_DSN,
37 + sendDefaultPii: true, // biar IP, headers, user info ikut kecapture
38 + environment: process.env.NODE_ENV || 'production',
39 +
40 + // Konfigurasi eksplisit biar request body & query params PASTI kecapture
41 + // (default behaviour beda-beda antar versi SDK, jadi jangan andelin default)
42 + integrations: (defaultIntegrations) => [
43 + ...defaultIntegrations.filter((i) => i.name !== 'RequestData'),
44 + Sentry.requestDataIntegration({
45 + include: {
46 + ip: true,
47 + data: true, // request body
48 + query_string: true, // query params
49 + headers: true,
50 + cookies: true,
51 + user: true,
52 + },
53 + }),
54 + ],
55 + });
56 + ```
57 +
58 + > Kenapa perlu `dotenv/config` manual: `instrument.ts` diimport paling awal,
59 + > sebelum NestJS `ConfigModule` sempat jalan dan load `.env`. Tanpa ini,
60 + > `process.env.SENTRY_DSN` masih `undefined` pas `Sentry.init()` dipanggil,
61 + > dan SDK diam-diam gak akan pernah ngirim event (cuma warning
62 + > "No DSN provided" di log kalau `debug: true`).
63 +
64 + ## 5. Import di baris paling atas `main.ts`
65 +
66 + ```ts
67 + import './instrument'; // HARUS baris pertama, sebelum import apapun lain
68 +
69 + import { NestFactory } from '@nestjs/core';
70 + // ...import lain seperti biasa
71 + ```
72 +
73 + Penting:
74 + - **Tanpa** ekstensi `.ts` di akhir (`'./instrument'`, bukan `'./instrument.ts'`)
75 + - File-nya harus ada di `src/` (folder yang sama dengan `main.ts`)
76 +
77 + ## 6. Register `SentryModule` & exception filter global di `app.module.ts`
78 +
79 + ```ts
80 + import { APP_FILTER } from '@nestjs/core';
81 + import { SentryModule, SentryGlobalFilter } from '@sentry/nestjs/setup';
82 +
83 + @Module({
84 + imports: [
85 + SentryModule.forRoot(), // HARUS import PERTAMA di array imports
86 + // ...module lain
87 + ],
88 + providers: [
89 + { provide: APP_FILTER, useClass: SentryGlobalFilter }, // HARUS provider PERTAMA
90 + // ...provider lain
91 + ],
92 + })
93 + export class AppModule {}
94 + ```
95 +
96 + ## 7. Kalau project sudah punya custom exception filter
97 +
98 + Ini kasus yang sering kelewat. `SentryGlobalFilter` cuma nangkep exception yang
99 + **gak** ketangkep filter lain duluan. Kalau ada filter spesifik seperti:
100 +
101 + ```ts
102 + @Catch(PrismaClientKnownRequestError)
103 + export class SomeCustomFilter implements ExceptionFilter { ... }
104 + ```
105 +
106 + ...exception yang match `@Catch(...)` itu **tidak akan pernah** sampai ke
107 + `SentryGlobalFilter`, walaupun `SentryModule` sudah ke-setup benar. Solusinya:
108 + tambahin `Sentry.captureException(exception)` manual di filter itu.
109 +
110 + Aturan yang dipakai: **status 5xx / error tak terduga → capture. Status 4xx yang
111 + memang disengaja (validasi, not found, unauthorized) → boleh skip**, karena itu
112 + flow normal, bukan bug.
113 +
114 + Helper biar konsisten di semua filter:
115 +
116 + ```ts
117 + // src/common/sentry-report.util.ts
118 + import * as Sentry from '@sentry/nestjs';
119 +
120 + export function reportIfUnexpected(exception: unknown, httpStatus: number) {
121 + if (httpStatus >= 500) {
122 + Sentry.captureException(exception);
123 + }
124 + }
125 + ```
126 +
127 + Panggil di ujung `catch()` tiap custom filter:
128 +
129 + ```ts
130 + reportIfUnexpected(exception, status);
131 + ```
132 +
133 + **Checklist:** cari semua custom filter di project sebelum anggap setup selesai:
134 +
135 + ```bash
136 + grep -rln "@Catch(" src/ --include="*.ts" | grep -v node_modules
137 + ```
138 +
139 + ## 8. Scrub data sensitif (opsional tapi disarankan)
140 +
141 + Karena `sendDefaultPii: true` bikin request body ikut terkirim penuh, tambahin
142 + `beforeSend` di `instrument.ts` buat mask field sensitif:
143 +
144 + ```ts
145 + Sentry.init({
146 + // ...config di atas
147 + beforeSend(event) {
148 + const sensitiveFields = ['password', 'token', 'secret'];
149 + if (event.request?.data) {
150 + for (const field of sensitiveFields) {
151 + if (event.request.data[field]) event.request.data[field] = '[FILTERED]';
152 + }
153 + }
154 + return event;
155 + },
156 + });
157 + ```
158 +
159 + ## 9. Testing
160 +
161 + Penting: `SentryGlobalFilter` **tidak** mengirim `HttpException` bawaan NestJS
162 + (`NotFoundException`, `BadRequestException`, dll) secara default — itu dianggap
163 + flow kontrol normal, bukan bug. Buat testing, trigger error yang beneran
164 + unhandled, misal lewat constraint DB (contoh Prisma `create()` dengan data yang
165 + melanggar unique constraint), bukan `throw new HttpException(...)`.
166 +
167 + Cara cepat verifikasi:
168 + 1. Trigger error via endpoint yang ada request body/query params
169 + 2. Cek dashboard → tab **Issues** → buka issue-nya
170 + 3. Pastikan section **Request** ada: Body, Query String, Headers, IP
171 +
172 + ## 10. Troubleshooting
173 +
174 + | Gejala | Kemungkinan penyebab |
175 + |---|---|
176 + | `Cannot find module './instrument.ts'` | Ada `.ts` literal di baris import `main.ts`, atau `dist/` lama ke-cache — hapus `dist` dan build ulang |
177 + | `Cannot find module './instrument'` padahal sudah tanpa `.ts` | File `instrument.ts` gak ada di `src/`, atau salah folder |
178 + | `No DSN provided, client will not send events` (pakai `debug: true`) | `.env` belum ke-load pas `Sentry.init()` jalan — tambahin `import 'dotenv/config'` di baris pertama `instrument.ts` |
179 + | Event gak muncul di dashboard padahal `Sentry Logger` bilang "Captured error event" | Cek log container GlitchTip (`docker compose logs glitchtip-web`) barengan waktu trigger — kalau gak ada request masuk sama sekali, cek konektivitas network / DSN salah domain |
180 + | Request body / query params kosong di dashboard | Konfigurasi `requestDataIntegration` secara eksplisit (lihat bagian 4), jangan andelin default SDK |
181 + | Error yang "seharusnya" muncul tapi gak ada | Kemungkinan ketangkep custom exception filter duluan — lihat bagian 7 |
182 +
183 + ## Referensi
184 +
185 + - Dokumentasi resmi Sentry untuk NestJS: https://docs.sentry.io/platforms/javascript/guides/nestjs/
Newer Older