본문으로 건너뛰기

클라이언트 앱 모니터링 가이드

작성일: 2026-04-06 Last Updated: 2026-04-06 대상: Browser Extension, Tauri Desktop, Flutter Mobile


목차​

  1. 크래시 리포트
  2. 에러 트래킹
  3. 사용 분석 (Analytics)
  4. 성능 모니터링
  5. 사용자 피드백 수집
  6. 프라이버시 준수
  7. 대시보드 구성
  8. 알림 설정

1. 크래시 리포트​

1.1 Sentry 기반 통합 구성​

플랫폼SDK패키지
Browser Extension@sentry/browsernpm install @sentry/browser
Tauri (Rust)sentry cratecargo add sentry
Tauri (Frontend)@sentry/browsernpm install @sentry/browser
Fluttersentry_flutterflutter pub add sentry_flutter

1.2 초기화 코드​

Browser Extension​

import * as Sentry from '@sentry/browser';

Sentry.init({
dsn: CONFIG.SENTRY_DSN,
environment: CONFIG.ENV, // dev, staging, prod
release: `browser-ext@${CONFIG.VERSION}`,
integrations: [
Sentry.breadcrumbsIntegration({
console: true,
dom: true,
fetch: true,
xhr: true,
}),
],
// 프로덕션에서만 100% 샘플링, 개발 중에는 비활성화
sampleRate: CONFIG.ENV === 'prod' ? 1.0 : 0,
// PII 전송 방지
beforeSend(event) {
// 이메일, IP 등 개인정보 제거
if (event.user) {
delete event.user.email;
delete event.user.ip_address;
}
return event;
},
});

Tauri (Rust 백엔드)​

fn main() {
let _guard = sentry::init((
env!("SENTRY_DSN"),
sentry::ClientOptions {
release: sentry::release_name!(),
environment: Some(env!("APP_ENV").into()),
sample_rate: 1.0,
..Default::default()
},
));

tauri::Builder::default()
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

Flutter​

Future<void> main() async {
await SentryFlutter.init(
(options) {
options.dsn = Config.sentryDsn;
options.environment = Config.env;
options.release = 'flutter@${Config.version}';
options.tracesSampleRate = 0.2;
options.attachScreenshot = true;
options.attachViewHierarchy = true;
// PII 제거
options.beforeSend = (event, hint) {
event = event.copyWith(
user: event.user?.copyWith(email: null, ipAddress: null),
);
return event;
};
},
appRunner: () => runApp(const MyApp()),
);
}

1.3 소스맵/디버그 심볼 업로드​

플랫폼도구CI 명령
Browser Extension@sentry/clisentry-cli sourcemaps upload --release=X.Y.Z dist/
Tauri (Rust)sentry-clisentry-cli debug-files upload target/release/
Flutter (Android)Sentry Gradle plugin자동 (build.gradle 설정)
Flutter (iOS)sentry-clisentry-cli debug-files upload build/ios/
# GitHub Actions - 소스맵 업로드
- name: Upload source maps to Sentry
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ vars.SENTRY_ORG }}
SENTRY_PROJECT: ${{ vars.SENTRY_PROJECT }}
run: |
npx sentry-cli releases new "$VERSION"
npx sentry-cli sourcemaps upload --release="$VERSION" dist/
npx sentry-cli releases finalize "$VERSION"

2. 에러 트래킹​

2.1 에러 분류 체계​

레벨설명예시알림
Fatal앱 크래시, 복구 불가미처리 예외, OOM즉시
Error기능 실패, 사용자 영향API 실패, 결제 오류5분
Warning잠재적 문제재시도 성공, 느린 응답1시간
Info참고 정보기능 사용 패턴일간

2.2 구조화된 에러 컨텍스트​

// 에러에 컨텍스트 추가
Sentry.withScope((scope) => {
scope.setTag('feature', 'sync');
scope.setTag('client_type', 'browser_ext');
scope.setContext('sync_state', {
lastSyncAt: state.lastSyncAt,
pendingItems: state.pendingQueue.length,
retryCount: state.retryCount,
});
Sentry.captureException(error);
});

2.3 플랫폼별 에러 수집 범위​

에러 유형ExtensionTauriFlutter
미처리 JS 예외OO (WebView)-
Rust panic-O-
Dart 미처리 예외--O
네트워크 오류OOO
WebView 렌더 오류-O-
ANR (Application Not Responding)--O (Android)
네이티브 크래시-OO

2.4 에러 그룹핑 규칙​

그룹 기준설명
에러 타입 + 스택트레이스기본 그룹핑
fingerprint 커스텀특정 에러의 그룹핑 오버라이드
릴리즈별 분리버전별 에러 추적
환경별 분리staging vs production

3. 사용 분석 (Analytics)​

3.1 분석 도구 선택​

도구장점단점적합
PostHog (자체호스팅)데이터 소유권, GDPR 친화운영 부담프라이버시 중시
Mixpanel강력한 퍼널/리텐션비용B2C
Amplitude프로덕트 분석비용B2B SaaS
Google Analytics무료, 익숙함프라이버시 우려가벼운 분석
자체 구축완전한 통제개발 비용최소 수집만 필요 시

3.2 추적 이벤트 설계​

공통 이벤트​

이벤트속성비고
app_launchedversion, platform, os_version앱 시작
feature_usedfeature_name, duration_ms기능 사용
error_occurrederror_type, feature에러 발생
subscription_changedplan, action (upgrade/downgrade/cancel)구독 변경
settings_changedsetting_key, new_value설정 변경

플랫폼별 이벤트​

이벤트ExtensionTauriFlutter
extension_installedO--
extension_updatedO--
window_resized-O-
system_tray_clicked-O-
push_notification_received--O
deep_link_opened-OO

3.3 이벤트 구현 패턴​

// 분석 추상화 레이어
interface AnalyticsProvider {
track(event: string, properties?: Record<string, unknown>): void;
identify(userId: string, traits?: Record<string, unknown>): void;
reset(): void;
}

class Analytics {
private providers: AnalyticsProvider[] = [];
private enabled = false;

init(providers: AnalyticsProvider[]) {
this.providers = providers;
// 사용자 옵트인 확인 후 활성화
this.enabled = UserPreferences.analyticsOptedIn();
}

track(event: string, properties?: Record<string, unknown>) {
if (!this.enabled) return;
const enriched = {
...properties,
app_version: APP_VERSION,
platform: PLATFORM,
timestamp: Date.now(),
};
this.providers.forEach((p) => p.track(event, enriched));
}
}

4. 성능 모니터링​

4.1 핵심 메트릭​

메트릭측정 방법임계값
앱 시작 시간 (Cold Start)프로세스 시작 ~ 첫 렌더< 2초
화면 전환 시간네비게이션 시작 ~ 렌더 완료< 300ms
API 응답 시간 (P95)요청 시작 ~ 응답 수신< 1초
메모리 사용량 (피크)주기적 측정< 150MB (모바일), < 300MB (데스크톱)
프레임 드롭16ms 이상 걸린 프레임 수< 1%
번들/바이너리 크기빌드 출력증가 추세 모니터링

4.2 Sentry Performance (트랜잭션)​

// 화면 전환 성능 측정
const transaction = Sentry.startTransaction({
name: 'screen.settings',
op: 'navigation',
});

// 하위 작업 측정
const span = transaction.startChild({
op: 'db.query',
description: 'Load user preferences',
});
await loadPreferences();
span.finish();

transaction.finish();
// Flutter 성능 모니터링
final transaction = Sentry.startTransaction('loadDashboard', 'ui.load');
try {
final span = transaction.startChild('http.client', description: 'Fetch data');
await api.fetchDashboardData();
span.finish(status: const SpanStatus.ok());
} finally {
await transaction.finish();
}

4.3 플랫폼별 성능 도구​

플랫폼내장 도구외부 도구
Browser ExtensionChrome DevTools PerformanceLighthouse CI
TauriChrome DevTools (WebView) + perf (Linux)Instruments (macOS)
FlutterFlutter DevToolsFirebase Performance

4.4 성능 알림 규칙​

조건알림 레벨채널
Cold Start P95 > 3초WarningSlack
API P95 > 2초WarningSlack
크래시율 > 1%CriticalPagerDuty + Slack
메모리 사용 > 500MBWarningSlack
프레임 드롭 > 5%Warning대시보드

5. 사용자 피드백 수집​

5.1 인앱 피드백 채널​

채널구현용도
피드백 폼앱 내 모달/시트일반 피드백
크래시 후 보고Sentry User Feedback크래시 재현 정보
평점 요청인앱 리뷰 프롬프트스토어 평점 유도
기능 요청외부 보드 링크 (Canny, Nolt)로드맵 반영

5.2 크래시 후 사용자 피드백​

// Sentry User Feedback
Sentry.showReportDialog({
eventId: Sentry.lastEventId(),
title: '문제가 발생했습니다',
subtitle: '어떤 작업을 하고 있었는지 알려주세요.',
labelSubmit: '보내기',
labelClose: '닫기',
labelName: '이름',
labelEmail: '이메일',
labelComments: '무슨 일이 있었나요?',
});

5.3 인앱 리뷰 요청 타이밍​

조건설명
최소 사용 횟수앱 실행 10회 이상
최소 사용 기간설치 후 7일 이상
성공적 작업 완료 후핵심 기능 성공 시
최근 요청 이력마지막 요청 후 90일 이상
부정 경험 배제에러 발생 세션에서는 요청 금지

플랫폼별 인앱 리뷰 API​

플랫폼API비고
Androidcom.google.android.play:review연간 요청 횟수 제한
iOSSKStoreReviewController.requestReview()연 3회 표시
Chrome Extension스토어 페이지 링크네이티브 API 없음
Tauri해당 없음GitHub Star 또는 자체 시스템

6. 프라이버시 준수​

6.1 GDPR / 개인정보보호법 체크리스트​

항목요구사항구현
사전 동의데이터 수집 전 명시적 동의옵트인 UI (첫 실행 시)
동의 철회언제든 수집 중단 가능설정 > 개인정보 > 분석 끄기
데이터 접근권사용자 데이터 내보내기API 엔드포인트 제공
삭제권사용자 데이터 완전 삭제계정 삭제 + Sentry 데이터 삭제
최소 수집필요한 최소한의 데이터만PII 자동 제거 필터
투명성수집 항목 공개개인정보처리방침 + 앱 내 설명

6.2 옵트인/옵트아웃 구현​

// 데이터 수집 동의 관리
interface ConsentState {
analytics: boolean; // 사용 분석
crashReports: boolean; // 크래시 리포트
performance: boolean; // 성능 모니터링
consentVersion: string; // 동의 버전 (약관 변경 시 재동의)
consentDate: string; // 동의 일시
}

class ConsentManager {
async updateConsent(consent: Partial<ConsentState>) {
const state = { ...await this.getConsent(), ...consent };
await storage.set('consent', state);

// 동의 상태에 따라 SDK 활성화/비활성화
if (!state.crashReports) {
Sentry.close();
}
if (!state.analytics) {
analytics.disable();
}
}

isConsentValid(): boolean {
const state = this.getConsent();
return state.consentVersion === CURRENT_CONSENT_VERSION;
}
}

6.3 수집 데이터 분류​

카테고리수집 항목동의 필요비고
필수 (기능용)인증 토큰, 설정서비스 약관수집 중단 불가
크래시 리포트스택트레이스, OS 정보, 앱 버전옵트인PII 제거
사용 분석이벤트, 화면 조회, 기능 사용옵트인익명화
성능 데이터로딩 시간, 메모리, 프레임옵트인집계만

6.4 Apple App Privacy (iOS 필수)​

Privacy Nutrition Label해당 여부 확인
Data Used to Track You사용 시 ATT 필수
Data Linked to You사용자 ID 연결 데이터
Data Not Linked to You익명 분석 데이터
Data Not Collected해당 카테고리 없음

6.5 Google Play 데이터 안전 섹션​

항목선언 필요
수집하는 데이터 유형O
데이터 공유 여부O
보안 관행 (암호화, 삭제 요청)O
독립 보안 검토 여부선택

7. 대시보드 구성​

7.1 Sentry 대시보드 레이아웃​

Overview 대시보드​

위젯표시 내용기간
크래시율 추이일별 크래시 비율 (크래시 세션/전체 세션)30일
미해결 이슈 Top 10가장 빈번한 에러7일
릴리즈 안정성버전별 크래시율 비교최근 3개 릴리즈
영향받은 사용자 수유니크 유저 기준24시간
플랫폼별 에러 분포Extension / Tauri / Flutter 비율7일

Performance 대시보드​

위젯표시 내용
P50 / P75 / P95 / P99 응답 시간API 엔드포인트별
앱 시작 시간 추이버전별 비교
가장 느린 트랜잭션 Top 5개선 대상 식별
Web Vitals (Tauri/Extension)LCP, FID, CLS

7.2 Analytics 대시보드​

카테고리주요 지표
활성 사용자DAU, WAU, MAU, DAU/MAU 비율
리텐션D1, D7, D30 리텐션율
기능 사용기능별 사용 빈도, 활성 사용자 비율
전환 퍼널설치 > 가입 > 활성화 > 구독
이탈 분석이탈 시점, 마지막 사용 기능

7.3 운영 대시보드​

카테고리모니터링 항목
배포 현황최신 버전 도달률, 롤아웃 진행률
스토어 리뷰평점 추이, 부정 리뷰 알림
라이선스활성 구독 수, 만료 임박
인프라업데이트 서버 상태, API 헬스체크

8. 알림 설정​

8.1 알림 채널 구성​

채널용도도구
Slack #app-alerts실시간 운영 알림Sentry → Slack 연동
Slack #app-metrics일간/주간 리포트스케줄 봇
Email주간 요약 리포트Sentry Digest
PagerDuty긴급 에스컬레이션 (P0)Sentry → PagerDuty

8.2 알림 규칙​

조건심각도알림 방법대응 시간
크래시율 > 2% (1시간 내)P0PagerDuty + Slack15분
새 Fatal 에러 (10건 이상)P0Slack 즉시30분
크래시율 > 0.5% (24시간)P1Slack4시간
새 Error (50건 이상)P1Slack4시간
API P95 > 3초 (30분간)P2Slack24시간
스토어 평점 1점 리뷰P2Slack24시간
주간 크래시율 0.1% 초과P3Email다음 스프린트

8.3 Sentry 알림 규칙 설정 예시​

# sentry alert rules (웹 UI 또는 API로 설정)
rules:
- name: "High crash rate"
conditions:
- type: event_frequency
value: 100
interval: 1h
actions:
- type: slack
channel: "#app-alerts"
- type: pagerduty
severity: critical

- name: "New issue in production"
conditions:
- type: first_seen_event
environment: production
filters:
- type: level
value: [fatal, error]
actions:
- type: slack
channel: "#app-alerts"

8.4 알림 피로 방지​

전략설명
디바운싱동일 이슈 알림은 최소 1시간 간격
에스컬레이션미처리 시 30분 후 재알림 + 상위 에스컬레이션
근무 시간P2 이하는 근무 시간에만 알림
묶음 알림Warning은 1시간 단위 묶음 발송
자동 해결14일간 재발하지 않으면 자동 Resolved

부록: 모니터링 설정 체크리스트​

초기 설정​

항목상태
Sentry 프로젝트 생성 (플랫폼별)[ ]
Sentry DSN 환경 변수 등록[ ]
소스맵/디버그 심볼 업로드 CI 설정[ ]
릴리즈 추적 설정 (version tagging)[ ]
환경 분리 (staging, production)[ ]
옵트인 동의 UI 구현[ ]
개인정보처리방침 업데이트[ ]

Analytics 설정​

항목상태
Analytics 도구 선택 및 프로젝트 생성[ ]
추적 이벤트 목록 정의[ ]
이벤트 추상화 레이어 구현[ ]
옵트인/옵트아웃 연동[ ]
핵심 대시보드 구성[ ]
전환 퍼널 정의[ ]

알림 설정​

항목상태
Slack 연동 설정[ ]
P0 ~ P3 알림 규칙 생성[ ]
PagerDuty 에스컬레이션 정책[ ]
주간 리포트 스케줄[ ]
알림 담당자/온콜 로테이션[ ]