에러 관측 (Sentry)
운영 에러는 Sentry 로 수집한다 (org j6nops). 서비스마다 별도 Sentry project. 자작 텔레그램 알림은 폐기하고 Sentry 로 일원화했다 (2026-05-24).
이 문서는 dartbrief 의 Sentry 연동을 다룬다. project: dartbrief-backend(Go), dartbrief-frontend(Next.js).
백엔드 (dartbrief-backend, Go)
sentry-go 로 연동. DSN 비면 no-op (로컬 dev 안전). Issue 와 Logs 두 갈래 (Sentry 표준 — log→issue 자동변환은 deprecated. 예외는 capture, 로그는 Logs 로).
Issues (알림·triage 대상)
| 포착 | 방식 |
|---|---|
| HTTP 5xx 응답 | capture5xx 미들웨어 (cmd/server/sentry_http.go) — status≥500 전부 CaptureMessage |
| HTTP panic | capture5xx 복구 → 500 응답 보장 → CaptureException (재던지지 않음). sentryhttp 가 바깥에서 요청별 hub 제공 |
| AI 스케줄러 워커 panic | scheduler.runJob recover → sentry.CurrentHub().Recover |
capture5xx는 항상 적용 — Sentry 비활성이어도 panic→500 보장(HTTP 의미론).
Logs (검색용 로그 스트림 — "다 넣기")
- 공식
sentry-go/slog핸들러 +sentry.Init(EnableLogs:true).SENTRY_LOG_LEVEL(기본 Info) 이상 모든 slog 로그가 Sentry Logs 로 전송. fanoutHandler로 stdout JSON(Railway 로그)과 동시에 보냄(이중 sink).- 로그는 Logs, 에러는 Issues → 이슈 중복 없음.
환경변수 (Railway)
| env | 비고 |
|---|---|
SENTRY_DSN | dartbrief-backend project DSN. 비면 Sentry 비활성(no-op) |
SENTRY_ENVIRONMENT | 기본 APP_ENV → 없으면 production |
SENTRY_LOG_LEVEL | Logs 전송 최소 레벨 (debug/info/warn/error). 기본 info |
RAILWAY_GIT_COMMIT_SHA | Sentry Release. Railway 자동 주입 |
- DSN 은 시크릿 아님(config). auth token(소스맵/릴리즈)은
~/.config/cloud-tokens/sentry.env(시크릿, git 금지). - 로컬:
.env.local에SENTRY_DSN미설정 → 캡처 안 함. 정상.
프론트 (dartbrief-frontend, Next.js)
@sentry/nextjs 로 연동 (CF Workers + @opennextjs/cloudflare). opennextjs 는 Node 런타임 (nodejs_compat)이라 표준 @sentry/nextjs 셋업 그대로 됨 (@sentry/cloudflare 불필요). 요건: wrangler.toml 의 nodejs_compat + compatibility_date ≥ 2025-08-16 (현재 2026-05-09 충족).
| 포착 | 파일 |
|---|---|
| 클라이언트(브라우저) 에러 | src/instrumentation-client.ts (Sentry.init, 에러 시 리플레이) |
| 서버(RSC/route/server action) | src/instrumentation.ts register + onRequestError = Sentry.captureRequestError, src/sentry.server.config.ts |
| 엣지 | src/sentry.edge.config.ts |
| 클라 렌더 에러 경계 | src/app/global-error.tsx → Sentry.captureException |
| 빌드 인스트루먼테이션 + 소스맵 | next.config.ts withSentryConfig (org j6nops, project dartbrief-frontend) |
- DSN 은 config 파일에 공개값으로 박음(클라 번들에 포함되는 게 정상). 런타임 env 불필요.
- 소스맵: 빌드 시
SENTRY_AUTH_TOKEN(시크릿,~/.config/cloud-tokens/sentry.env) 있으면 업로드 → 원본 라인. 없으면 스킵(에러 캡처는 됨, minified 스택). CF git-integration 배포면 CF build env 에SENTRY_AUTH_TOKEN설정. - 쿼터 절약: 상시 세션 리플레이 off(
replaysSessionSampleRate:0), 에러 시에만 리플레이. traces 0.1.
앱 (dartbrief-mobile, Flutter)
sentry_flutter 로 연동. project dartbrief-mobile (org j6nops).
- 포착: Dart/Flutter 미처리 에러(FlutterError/PlatformDispatcher 자동 후킹) + 네이티브 크래시(iOS/Android) + Release Health(crash-free 세션/유저).
- 위치:
mobile/lib/app/bootstrap.dart—SentryFlutter.init(...)의appRunner로 전체 init+runApp을 가드 존에서 실행. - DSN: 공개값.
--dart-define=SENTRY_DSN=override + 하드코딩 fallback → prod 항상 동작. 빈 값이면 비활성. - environment: flavor 기준(prod/development). traces 0.1.
- 심볼 업로드(네이티브 스택 가독):
sentry_dart_plugin. pubspecsentry:블록(org/project,upload_debug_symbols) +make build-ios-prod가 ipa 빌드 후flutter pub run sentry_dart_plugin실행 → iOS dSYM/Android 네이티브 심볼 업로드.SENTRY_AUTH_TOKEN은 Makefile 이~/.config/cloud-tokens/sentry.env에서 주입.- 빌드 바이너리는 안 바꿈(난독화/
--split-debug-info미적용). Dart 스택은 릴리즈에서 이미 가독, 네이티브 크래시만 심볼로 해독. Dart 난독화/source-context 까지 원하면 추후--split-debug-info+--save-obfuscation-map추가.
- 빌드 바이너리는 안 바꿈(난독화/
oncall 자동수정 연계 (후속)
기존 oncall(에러→버튼→Claude Remote Control 수정) 파이프라인은 Sentry 와 연결 가능: Sentry alert rule → webhook → 텔레그램(oncall 봇) → 버튼 → Claude 세션. 관측은 Sentry, 자동수정 트리거는 oncall 로 역할 분리. (현재 미구현 — 후속 작업)