UNPKG

rusty-replay

Version:

Lightweight error tracking and replay system for React apps using rrweb and Rust-powered backend integration.

166 lines (126 loc) β€’ 3.92 kB
# πŸ¦€ rusty-replay μ›Ή ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ λ°œμƒν•œ 였λ₯˜λ₯Ό μˆ˜μ§‘ν•˜κ³ , 직전 μ‚¬μš©μž ν™œλ™μ„ λ¦¬ν”Œλ ˆμ΄ ν˜•νƒœλ‘œ ν•¨κ»˜ μ „μ†‘ν•˜λŠ” κ²½λŸ‰ 였λ₯˜ 좔적 λ„κ΅¬μž…λ‹ˆλ‹€. `rrweb` 기반의 μ‚¬μš©μž 행동 λ¦¬ν”Œλ ˆμ΄ κΈ°λŠ₯κ³Ό `axios` μ—λŸ¬ μžλ™ μ „μ†‘κΉŒμ§€ μ§€μ›ν•©λ‹ˆλ‹€. ## πŸ“¦ μ„€μΉ˜ ```bash npm install rusty-replay ``` --- ## βš™οΈ μ΄ˆκΈ°ν™” Next.jsμ—μ„œ `rusty-replay`λŠ” 일반적으둜 `app/providers.tsx` λ˜λŠ” `layout.tsx`μ—μ„œ μ΄ˆκΈ°ν™”ν•©λ‹ˆλ‹€. ```ts import { init } from 'rusty-replay'; init({ endpoint: 'https://your-api.com/batch-events', apiKey: 'YOUR_PUBLIC_API_KEY', flushIntervalMs: 10000, // 버퍼가 μ°° λ•ŒκΉŒμ§€ μ΅œλŒ€ λŒ€κΈ° μ‹œκ°„ (ms) maxBufferSize: 2000000, // 전솑 μ „ μ΅œλŒ€ 버퍼 μ‚¬μ΄μ¦ˆ (bytes) beforeErrorSec: 10, // μ—λŸ¬ λ°œμƒ μ „ λͺ‡ μ΄ˆκ°„μ˜ 이벀트λ₯Ό λ¦¬ν”Œλ ˆμ΄λ‘œ 남길지 }); ``` --- ## 🧠 κΈ€λ‘œλ²Œ μ—λŸ¬ μžλ™ 캑처 ```ts import { setupGlobalErrorHandler } from 'rusty-replay'; setupGlobalErrorHandler(); ``` - `window.onerror` - `window.onunhandledrejection` 을 μžλ™ κ°μ§€ν•˜μ—¬ 였λ₯˜λ₯Ό μ„œλ²„λ‘œ μ „μ†‘ν•©λ‹ˆλ‹€. --- ## πŸ”§ Axios μ—λŸ¬ μžλ™ 전솑 ```ts import axios from 'axios'; import { captureException, AdditionalInfo } from 'rusty-replay'; axios.interceptors.response.use( (res) => res, (error) => { if (axios.isAxiosError(error)) { const additionalInfo: Partial<AdditionalInfo> = { pageUrl: window.location.href, request: { url: error.config?.url ?? '', method: error.config?.method ?? '', headers: error.config?.headers ?? {}, }, response: { status: error.response?.status ?? 0, statusText: error.response?.statusText ?? '', data: { message: error.response?.data?.message ?? '', errorCode: error.response?.data?.errorCode ?? '', }, }, }; captureException( error instanceof Error ? error : new Error('API μš”μ²­ μ‹€νŒ¨'), additionalInfo ); } return Promise.reject(error); } ); ``` --- ## πŸ–₯️ React Error Boundary 톡합 ```tsx import { ErrorBoundary } from 'react-error-boundary'; import { captureException } from 'rusty-replay'; <ErrorBoundaryFallbackComponent={() => <div>였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.</div>} onError={(error, info) => { captureException(error); }} > <App /> </ErrorBoundary> ``` --- ## πŸ” λ¦¬ν”Œλ ˆμ΄ μž¬μƒ (rrweb-player) ```tsx import { decompressFromBase64 } from 'rusty-replay'; import 'rrweb-player/dist/style.css'; const events = decompressFromBase64(error.replay); new Player({ target: document.getElementById('player')!, props: { events, width: 1000, height: 600, autoPlay: false, showController: true, skipInactive: true, }, }); ``` --- ## πŸ“‹ μ„œλ²„λ‘œ μ „μ†‘λ˜λŠ” 데이터 Payload ```ts { message: 'Uncaught TypeError: ...', stacktrace: 'TypeError: ...', replay: 'compressedBase64Data', environment: 'production', browser: 'Chrome 123.0', os: 'macOS 14', userAgent: '...', appVersion: '1.0.0', apiKey: 'YOUR_API_KEY', additionalInfo: { request: {...}, response: {...}, pageUrl: 'https://your.site/path' }, userId: 123 } ``` --- ## πŸ“Ž API μ°Έκ³  ### `init(options: InitOptions)` μ˜΅μ…˜ μ„€λͺ…: | μ˜΅μ…˜ | νƒ€μž… | μ„€λͺ… | | ----------------- | ------ | -------------------------------------- | | `endpoint` | string | μ—λŸ¬ μˆ˜μ§‘ μ„œλ²„μ˜ μ—”λ“œν¬μΈνŠΈ | | `apiKey` | string | ν”„λ‘œμ νŠΈ μ‹λ³„μš© API Key | | `flushIntervalMs` | number | μ—λŸ¬ 전솑 간격 (κΈ°λ³Έ: 10초) | | `maxBufferSize` | number | μ΅œλŒ€ 전솑 버퍼 크기 | | `beforeErrorSec` | number | λ¦¬ν”Œλ ˆμ΄ μˆ˜μ§‘ ꡬ간 (κΈ°λ³Έ: 10초 μ „κΉŒμ§€) |