Flutter 튜토리얼 75편: 디버거와 로깅 - DevTools로 앱 디버깅하기

요약#

핵심 요지#

  • 문제 정의: Flutter 앱에서 버그가 발생했을 때 원인을 빠르게 파악하기 어렵다.
  • 핵심 주장: DevTools의 디버깅 도구들을 활용하면 코드 실행 흐름을 추적하고 문제를 효율적으로 해결할 수 있다.
  • 주요 근거: DevTools는 브레이크포인트, 로그 뷰, 네트워크 모니터링 등 종합적인 디버깅 기능을 제공한다.

문서가 설명하는 범위#

  • Debugger로 브레이크포인트 설정 및 코드 스테핑
  • Console에서 출력 확인 및 표현식 평가
  • Network 뷰로 HTTP 트래픽 모니터링
  • Logging 뷰로 앱 이벤트 추적

읽는 시간: 20분 | 난이도: 초급


참고 자료#


문제 상황#

앱에서 예상치 못한 동작이 발생했을 때, print 문만으로는 원인을 파악하기 어렵습니다. 코드 실행 흐름을 따라가면서 변수 값을 확인하고 싶지만 방법을 모릅니다.

기존 방식의 한계#

// print 문으로만 디버깅하는 방식
Future<void> loadUserData(String userId) async {
print('loadUserData 시작: $userId'); // 어디서 호출됐는지 모름
final response = await api.getUser(userId);
print('응답: $response'); // 응답 전체 구조 파악 어려움
if (response.data != null) {
print('데이터 있음');
user = response.data;
} else {
print('데이터 없음'); // 왜 없는지 알 수 없음
}
print('loadUserData 끝');
}

문제는 다음과 같습니다.

  • 코드 실행을 중간에 멈출 수 없다
  • 변수 값을 실시간으로 확인하기 어렵다
  • 호출 스택을 추적하기 어렵다
  • print 문을 계속 추가/삭제해야 한다

해결 방법#

챕터 1: DevTools Debugger 시작하기#

Why#

NOTE

Debugger1는 코드 실행을 원하는 지점에서 멈추고, 변수 값을 확인하며, 한 줄씩 실행할 수 있게 해줍니다. print 문 없이도 코드의 동작을 상세히 분석할 수 있습니다.

What#

NOTE

DevTools Debugger의 주요 기능입니다.

flowchart TD subgraph Debugger["Debugger 기능"] BP[Breakpoints] ST[Stepping] VAR[Variables] CS[Call Stack] end subgraph Actions["동작"] BP --> P[일시 정지] ST --> N[한 줄씩 실행] VAR --> I[값 검사] CS --> T[호출 추적] end
기능설명단축키
Continue다음 브레이크포인트까지 실행F5
Step Over현재 줄 실행 후 다음 줄로F10
Step Into함수 내부로 진입F11
Step Out현재 함수 빠져나가기Shift+F11

How#

TIP

Debugger를 시작하는 방법입니다.

Terminal window
# 1. 디버그 모드로 앱 실행
flutter run
# 2. DevTools 열기
# VS Code: Ctrl+Shift+P → "Dart: Open DevTools"
# 또는 터미널에 표시된 DevTools URL 클릭
// DevTools Debugger 탭에서:
// 1. 소스 파일 탐색 (Libraries 버튼 또는 Ctrl+P)
// 2. 줄 번호 클릭하여 브레이크포인트 설정
// 3. 앱에서 해당 코드 실행되면 자동 일시 정지

소스 파일 탐색 방법입니다.

파일 찾기: 1. Debugger 탭 열기
2. 우측 상단 "Libraries" 클릭 (또는 Ctrl+P)
3. 파일명 검색
4. 원하는 파일 선택

Watch out#

WARNING

VS Code를 사용하면 DevTools의 Debugger 탭이 숨겨집니다. VS Code에 내장 디버거가 있기 때문입니다.

VS Code 사용 시:
- DevTools Debugger 탭 숨김
- VS Code 내장 디버거 사용 권장
- 동일한 기능 제공
Android Studio/IntelliJ 사용 시:
- DevTools Debugger 탭 표시
- DevTools 또는 IDE 디버거 선택 가능

결론: Debugger를 사용하면 코드 실행을 멈추고 변수 값을 확인하며 단계별로 실행할 수 있다.


챕터 2: 브레이크포인트 설정과 활용#

Why#

NOTE

브레이크포인트2는 코드의 특정 지점에서 실행을 멈추게 하는 표시입니다. 문제가 의심되는 코드에 브레이크포인트를 설정하면 해당 시점의 상태를 확인할 수 있습니다.

What#

NOTE

브레이크포인트의 종류와 사용법입니다.

flowchart LR subgraph Types["브레이크포인트 유형"] L[Line Breakpoint] E[Exception Breakpoint] end subgraph States["상태"] A[활성화] D[비활성화] H[조건부] end Types --> States
유형설명사용 시점
Line특정 줄에서 멈춤일반적인 디버깅
Exception예외 발생 시 멈춤에러 추적
Conditional조건 충족 시만 멈춤특정 조건 디버깅

How#

TIP

브레이크포인트 설정 방법입니다.

// 브레이크포인트 설정 예시
class UserRepository {
Future<User> getUser(String id) async {
// 여기에 브레이크포인트 설정 (줄 번호 클릭)
final response = await _api.fetchUser(id);
// 응답 처리 로직에도 설정
if (response.statusCode == 200) {
return User.fromJson(response.body);
} else {
throw ApiException(response.statusCode);
}
}
}

브레이크포인트 관리 방법입니다.

Breakpoints 패널 사용: 1. 좌측 하단 Breakpoints 영역 확인
2. 체크박스로 개별 활성화/비활성화
3. X 버튼으로 제거
4. 더블클릭으로 해당 위치로 이동

예외에서 멈추기 설정입니다.

// Debugger 상단의 드롭다운에서 예외 처리 설정
//
// Ignore: 예외 발생해도 멈추지 않음
// Stop on Unhandled: 처리되지 않은 예외에서만 멈춤
// Stop on All: 모든 예외에서 멈춤 (try-catch 포함)
try {
await riskyOperation();
} catch (e) {
// "Stop on All" 설정 시 여기서도 멈춤
handleError(e);
}

Watch out#

WARNING

Hot Restart3를 하면 모든 브레이크포인트가 초기화됩니다. 중요한 브레이크포인트 위치를 기억해두세요.

Hot Restart 영향:
- 브레이크포인트 초기화됨
- 변수 값 초기화됨
- 앱 상태 초기화됨
Hot Reload:
- 브레이크포인트 유지됨
- 변수 값 유지됨 (가능한 경우)

결론: 브레이크포인트를 설정하면 원하는 지점에서 코드 실행을 멈추고 상태를 확인할 수 있다.


챕터 3: 변수 검사와 스테핑#

Why#

NOTE

브레이크포인트에서 멈췄을 때, 현재 상태의 변수 값을 확인하고 코드를 한 줄씩 실행하며 변화를 추적할 수 있습니다. 이를 통해 버그의 정확한 원인을 찾을 수 있습니다.

What#

NOTE

Variables 패널과 스테핑 기능입니다.

flowchart TD subgraph Inspection["변수 검사"] V[Variables 패널] H[Hover 검사] W[Watch 표현식] end subgraph Stepping["스테핑"] SI[Step Into] SO[Step Over] SOU[Step Out] C[Continue] end
스테핑 명령동작사용 시점
Step Into함수 내부로 진입함수 내부 확인 필요
Step Over함수 건너뛰고 다음 줄함수 내부 불필요
Step Out현재 함수 완료까지 실행함수 빠져나가기
Continue다음 브레이크포인트까지특정 지점까지 건너뛰기

How#

TIP

Variables 패널 사용법입니다.

// 브레이크포인트에서 멈췄을 때
void processOrder(Order order) {
// 여기서 멈춤 - Variables 패널에서 확인 가능:
// - order: Order 객체
// - order.items: List<Item>
// - order.totalPrice: double
final discount = calculateDiscount(order);
// Step Over 후: discount 값 확인 가능
final finalPrice = order.totalPrice - discount;
// Step Over 후: finalPrice 값 확인 가능
if (finalPrice < 0) {
// 이 조건이 왜 true인지 확인 가능
throw InvalidPriceException();
}
}

객체 내부 탐색입니다.

Variables 패널에서:
1. 객체 옆의 화살표 클릭하여 펼치기
2. 중첩된 객체도 계속 펼치기 가능
3. 객체 위에 마우스 올리면 toString() 결과 표시
예시:
order (Order)
├── id: "123"
├── items (List<Item>)
│ ├── [0]: Item
│ │ ├── name: "Product A"
│ │ └── price: 10000
│ └── [1]: Item
└── totalPrice: 25000

Call Stack 활용입니다.

// Call Stack 패널에서 호출 경로 확인
//
// processOrder (order_service.dart:42)
// handleCheckout (checkout_page.dart:128)
// onPressed (checkout_page.dart:85)
// ...
//
// → 각 스택 프레임 클릭 시 해당 위치로 이동
// → 해당 스코프의 변수 확인 가능

Watch out#

WARNING

Variables 패널에서 객체를 펼치면 toString()이 호출됩니다. toString() 내에 부수효과가 있으면 주의가 필요합니다.

// 주의: toString()에 부수효과가 있는 경우
class Counter {
int value = 0;
@override
String toString() {
value++; // 부수효과 - 디버깅 시 값이 변함!
return 'Counter: $value';
}
}
// 권장: toString()은 순수 함수로 작성
class Counter {
int value = 0;
@override
String toString() {
return 'Counter: $value'; // 부수효과 없음
}
}

결론: Variables 패널과 스테핑 기능으로 코드 실행 흐름을 따라가며 변수 값의 변화를 추적할 수 있다.


챕터 4: Debug Console 활용#

Why#

NOTE

Debug Console4은 앱의 출력을 확인하고, 실시간으로 코드를 실행할 수 있는 도구입니다. 브레이크포인트 없이도 앱 상태를 확인할 수 있습니다.

What#

NOTE

Debug Console의 주요 기능입니다.

flowchart LR subgraph Console["Debug Console"] O[stdout/stderr 출력] E[표현식 평가] H[힙 스냅샷] end subgraph Usage["활용"] O --> L[로그 확인] E --> T[실시간 테스트] H --> M[메모리 분석] end
기능설명예시
stdout 표시print 출력 확인print('debug')
표현식 평가코드 실시간 실행user.name 입력
힙 브라우징객체 탐색스냅샷 열기

How#

TIP

Console에서 출력 확인하기입니다.

// 앱 코드에서 출력
void main() {
print('앱 시작');
debugPrint('디버그 메시지'); // 긴 출력도 잘림 없이 표시
runApp(MyApp());
}
// Console에서 확인:
// 앱 시작
// 디버그 메시지

표현식 평가 기능입니다.

브레이크포인트에서 멈춘 상태에서:
1. Console 하단 입력창에 표현식 입력
2. Enter로 실행
3. 결과 확인
예시:
> user.name
"John Doe"
> user.orders.length
5
> user.orders.where((o) => o.status == 'pending').length
2
> calculateTotal(user.orders)
150000

힙 스냅샷 브라우징입니다.

힙 스냅샷 열기:
1. Memory 뷰에서 스냅샷 캡처
2. 스냅샷에서 특정 인스턴스 우클릭
3. "Browse in Console" 선택
4. Console에서 해당 객체 탐색 가능
Console에서:
> instance.field1
> instance.method()

Watch out#

WARNING

Console에서 실행한 코드는 앱 상태를 변경할 수 있습니다. 테스트 목적으로만 사용하고, 의도치 않은 변경에 주의하세요.

// Console에서 실행 시 주의
> user.name = "Modified" // 실제로 변경됨!
> list.add(item) // 실제로 추가됨!
> api.deleteUser(id) // 실제로 삭제됨!
// 안전한 사용
> user.name // 읽기만
> list.length // 읽기만
> user.toJson() // 메서드 호출 (부수효과 없는 것만)

결론: Debug Console에서 앱 출력을 확인하고 표현식을 실시간으로 평가할 수 있다.


챕터 5: Network 뷰로 HTTP 트래픽 분석#

Why#

NOTE

API 호출이 제대로 동작하는지 확인하려면 실제 HTTP 요청과 응답을 봐야 합니다. Network 뷰5에서 앱의 모든 네트워크 트래픽을 모니터링할 수 있습니다.

What#

NOTE

Network 뷰가 기록하는 정보입니다.

flowchart LR subgraph Request["요청 정보"] M[Method] U[URL] H1[Headers] B1[Body] end subgraph Response["응답 정보"] S[Status] H2[Headers] B2[Body] T[Timing] end Request --> Response
컬럼설명
MethodHTTP 메서드 (GET, POST 등)
URL요청 URL
Status응답 상태 코드
Type컨텐츠 타입 (json, html 등)
Duration요청 소요 시간

How#

TIP

Network 뷰 사용법입니다.

기본 사용: 1. DevTools > Network 탭 선택
2. 앱에서 네트워크 요청 발생시키기
3. 요청 목록에서 항목 확인
4. 요청 선택하여 상세 정보 보기
상세 정보 탭:
- General: URL, 메서드, 상태 코드
- Request Headers: 요청 헤더
- Request Body: 요청 본문 (POST 등)
- Response Headers: 응답 헤더
- Response Body: 응답 본문
- Timing: 타이밍 정보

필터링으로 원하는 요청만 보기입니다.

필터 문법:
- method, m: HTTP 메서드
- status, s: 상태 코드
- type, t: 컨텐츠 타입
예시:
- "m:get t:json" → GET 요청 중 JSON만
- "s:404" → 404 에러만
- "api/users" → URL에 api/users 포함
검색:
- 입력창에 텍스트 입력
- URL, 메서드, 상태 등 전체 검색

앱 시작 시점부터 네트워크 기록하기입니다.

Terminal window
# 앱 시작 시점의 네트워크도 기록하려면:
# 1. 앱을 일시 정지 상태로 시작
flutter run --start-paused
# 2. DevTools Network 탭 열기 (Recording 확인)
# 3. 앱 재개
# DevTools에서 Resume 버튼 클릭 또는
# 터미널에서 'r' 입력

Watch out#

WARNING

Network 뷰는 dart:io 기반 HTTP 클라이언트만 지원합니다. 웹 앱은 브라우저 개발자 도구를 사용하세요.

// 지원되는 HTTP 클라이언트
import 'dart:io';
final client = HttpClient(); // 지원
// dio 패키지 - 지원
// http 패키지 - 지원
// 웹 앱에서는
// Chrome DevTools > Network 탭 사용

결론: Network 뷰에서 앱의 HTTP 요청과 응답을 모니터링하여 API 통신 문제를 디버깅할 수 있다.


챕터 6: Logging 뷰 활용#

Why#

NOTE

Logging 뷰6는 앱에서 발생하는 다양한 이벤트를 시간순으로 보여줍니다. Dart 런타임, Flutter 프레임워크, 앱 로그를 한 곳에서 확인할 수 있습니다.

What#

NOTE

Logging 뷰가 표시하는 이벤트 유형입니다.

flowchart TD subgraph Sources["로그 소스"] D[Dart Runtime] F[Flutter Framework] A[Application] end subgraph Events["이벤트 유형"] D --> GC[GC 이벤트] F --> FR[프레임 이벤트] A --> ST[stdout/stderr] A --> CL[Custom Logs] end
소스이벤트설명
DartGC가비지 컬렉션 발생
FlutterFrame프레임 생성
Appstdoutprint() 출력
AppCustomdeveloper.log()

How#

TIP

Logging 뷰 기본 사용법입니다.

// 다양한 로깅 방법
// 1. print - 기본 출력
print('Simple log message');
// 2. debugPrint - 긴 메시지도 잘림 없이
debugPrint('Very long message that would normally be truncated...');
// 3. developer.log - 구조화된 로깅
import 'dart:developer' as developer;
developer.log(
'User logged in',
name: 'AuthService',
error: jsonEncode({'userId': '123'}),
);

커스텀 로깅 구현입니다.

// 앱 전용 로거 클래스
import 'dart:developer' as developer;
class AppLogger {
static void debug(String message, {String? tag}) {
developer.log(
message,
name: tag ?? 'DEBUG',
level: 500,
);
}
static void info(String message, {String? tag}) {
developer.log(
message,
name: tag ?? 'INFO',
level: 800,
);
}
static void error(String message, {Object? error, StackTrace? stackTrace}) {
developer.log(
message,
name: 'ERROR',
level: 1000,
error: error,
stackTrace: stackTrace,
);
}
}
// 사용 예시
AppLogger.debug('Loading user data', tag: 'UserRepository');
AppLogger.info('User loaded successfully');
AppLogger.error('Failed to load user', error: e, stackTrace: stack);

로그 필터링입니다.

Logging 뷰 필터:
- 검색창에 텍스트 입력하여 필터링
- 특정 소스만 보기 가능
유용한 필터:
- "ERROR" - 에러 로그만
- "AuthService" - 특정 태그만
- "gc" - GC 이벤트만

Watch out#

WARNING

릴리스 빌드에서는 로그가 제거되거나 무시될 수 있습니다. 프로덕션 로깅이 필요하면 별도 로깅 서비스를 사용하세요.

// 릴리스 빌드에서 로그 제어
import 'package:flutter/foundation.dart';
void log(String message) {
if (kDebugMode) {
print(message); // 디버그 빌드에서만 출력
}
}
// 프로덕션 로깅 - 외부 서비스 사용
// Firebase Crashlytics, Sentry 등

결론: Logging 뷰에서 앱의 모든 로그와 이벤트를 시간순으로 확인하고 필터링할 수 있다.


챕터 7: 효과적인 디버깅 전략#

Why#

NOTE

도구를 아는 것과 효과적으로 사용하는 것은 다릅니다. 체계적인 디버깅 전략을 적용하면 버그를 더 빨리 찾을 수 있습니다.

What#

NOTE

효과적인 디버깅 프로세스입니다.

flowchart TD subgraph Process["디버깅 프로세스"] R[재현] I[격리] A[분석] F[수정] V[검증] end R -->|"버그 재현"| I I -->|"범위 좁히기"| A A -->|"원인 분석"| F F -->|"코드 수정"| V V -->|"재테스트"| R

How#

TIP

단계별 디버깅 전략입니다.

// 1. 재현 (Reproduce)
// - 버그가 발생하는 정확한 조건 파악
// - 재현 단계 기록
// 2. 격리 (Isolate)
// - 문제 범위를 좁혀나감
// - 브레이크포인트를 넓은 범위에서 좁은 범위로
// 3. 분석 (Analyze)
// - 변수 값 확인
// - 호출 스택 추적
// - 예상값 vs 실제값 비교
// 4. 수정 (Fix)
// - 근본 원인 해결
// - 임시 방편 피하기
// 5. 검증 (Verify)
// - 수정 후 재테스트
// - 다른 부분에 영향 없는지 확인

자주 발생하는 버그 패턴입니다.

// 1. Null 참조 에러
// 브레이크포인트: null 발생 직전
// 확인: 어디서 null이 되는지 역추적
// 2. 상태 불일치
// 브레이크포인트: setState 호출 지점
// 확인: 상태 변경 타이밍과 순서
// 3. 비동기 문제
// 브레이크포인트: await 전후
// 확인: 실행 순서, 콜백 호출 여부
// 4. UI 업데이트 안 됨
// 브레이크포인트: build 메서드
// 확인: 위젯 재빌드 여부, 상태 값
// 5. API 에러
// Network 뷰: 요청/응답 확인
// 확인: 상태 코드, 응답 본문

디버깅 체크리스트입니다.

버그 발견 시:
[ ] 버그 재현 가능?
[ ] 어떤 조건에서 발생?
[ ] 에러 메시지나 스택 트레이스 있음?
[ ] 최근 변경한 코드와 관련?
브레이크포인트 설정:
[ ] 에러 발생 지점
[ ] 의심되는 로직 시작점
[ ] 데이터 흐름 중간 지점
변수 확인:
[ ] 예상값과 실제값 비교
[ ] null 여부 확인
[ ] 타입 확인
수정 후:
[ ] 버그 재현 시도
[ ] 관련 기능 테스트
[ ] 다른 부분 영향 확인

Watch out#

WARNING

디버깅에 너무 많은 시간을 쓰고 있다면, 접근 방식을 바꿔보세요.

디버깅이 오래 걸릴 때:
- 잠시 휴식 후 새로운 관점으로
- 동료에게 설명해보기 (러버덕 디버깅)
- 문제를 더 작은 단위로 분리
- 가정을 의심하기
피해야 할 것:
- 같은 접근법 반복
- 추측만으로 코드 수정
- print 문 무한 추가

결론: 체계적인 디버깅 프로세스를 따르면 버그를 더 효율적으로 찾고 해결할 수 있다.


한계#

  • VS Code 제한: VS Code 사용 시 DevTools Debugger 탭이 숨겨지며 VS Code 내장 디버거를 사용해야 한다
  • 웹 앱 제한: Network 뷰는 웹 앱에서 동작하지 않으며, 브라우저 개발자 도구를 사용해야 한다
  • 릴리스 빌드: 릴리스 빌드에서는 DevTools 연결이 불가능하다

Footnotes#

  1. Debugger(디버거): 코드 실행을 제어하고 상태를 검사할 수 있게 해주는 도구이다.

  2. Breakpoint(브레이크포인트): 코드 실행을 일시 중지시키는 지점 표시이다.

  3. Hot Restart(핫 리스타트): 앱 상태를 초기화하고 전체 앱을 다시 시작하는 기능이다.

  4. Debug Console(디버그 콘솔): 앱 출력을 확인하고 표현식을 실행할 수 있는 인터페이스이다.

  5. Network View(네트워크 뷰): HTTP 요청과 응답을 모니터링하는 DevTools 기능이다.

  6. Logging View(로깅 뷰): 앱의 로그 이벤트를 시간순으로 표시하는 DevTools 기능이다.

공유

이 글이 도움이 되었다면 다른 사람과 공유해주세요!

Flutter 튜토리얼 75편: 디버거와 로깅 - DevTools로 앱 디버깅하기
https://moodturnpost.net/posts/flutter/flutter-debugger-and-logging/
작성자
Moodturn
게시일
2026-01-08
Moodturn

목차