Skip to main content

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

작성일: 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 에스컬레이션 정책[ ]
주간 리포트 스케줄[ ]
알림 담당자/온콜 로테이션[ ]