터미널·서버 실무 · Part 8

스택트레이스와 디버깅

에러를 붙여넣지 않고 스스로 원인을 좁혀 가기

작성 기준2026년 7월

이 파트에서 다루는 내용

스택트레이스 읽기원인 예외 찾기이분 탐색가설과 검증
01

스택트레이스는 위가 아니라 아래를 봅니다

스택트레이스는 오류가 난 순간의 호출 경로를 보여 줍니다. 길고 복잡해 보이지만 읽는 법은 정해져 있습니다.

맨 위는 오류가 최종적으로 드러난 지점이고, 아래로 갈수록 그 오류를 부른 원래 호출입니다. 그리고 여러 예외가 겹쳐 있을 때는 진짜 원인이 아래쪽에 숨어 있습니다.

첫 줄: 무엇이
예외 종류

맨 윗줄은 어떤 오류인지(예외 이름)와 메시지입니다. NullPointer 인지, 파일을 못 찾았는지, 연결이 끊겼는지를 먼저 봅니다.

내 코드부터 찾기
위치

스택트레이스 대부분은 라이브러리 내부입니다. 그 사이에서 내 프로젝트 패키지가 나오는 줄이 실제로 손댈 지점입니다. 거기서부터 봅니다.

Caused by 가 진짜 원인
핵심

Caused by 로 이어지는 아래쪽 예외가 근본 원인인 경우가 많습니다. 맨 위 예외는 그 결과일 뿐입니다. 가장 아래 Caused by 부터 확인합니다.

스택트레이스 읽는 순서text
java.lang.RuntimeException: 주문 처리 실패     ← 겉으로 드러난 오류
    at com.example.order.OrderService.create(OrderService.java:42)  ← 내 코드
    at com.example.order.OrderController.post(OrderController.java:28)
    ...
Caused by: java.sql.SQLException: connection refused   ← 진짜 원인
    at com.example.db.Pool.getConnection(Pool.java:80)
    ...

# 읽는 순서
# 1. 맨 위: 무슨 예외인가 (RuntimeException)
# 2. Caused by: 진짜 원인은 무엇인가 (SQLException: connection refused)
# 3. 내 코드 줄: 어디를 봐야 하나 (OrderService.java:42)
# 4. 원인 판단: DB 연결 문제 -> 네트워크 진단(Part 5)으로

이 예시에서 겉보기 오류는 주문 처리 실패지만 진짜 원인은 DB 연결 거부입니다. Caused by 를 놓치면 엉뚱한 곳을 고치게 됩니다.

02

오류 메시지를 문자 그대로 읽습니다

많은 문제가 오류 메시지에 답이 그대로 적혀 있습니다. 그런데 메시지를 대충 보고 지나쳐 시간을 낭비하는 경우가 많습니다.

AI나 검색 없이 스스로 해결할 때는, 메시지를 한 단어씩 정확히 읽는 것이 첫 단계입니다.

메시지를 분해
정확히 읽기

connection refused 는 연결이 거부됨, no such file 은 파일이 없음, permission denied 는 권한 없음입니다. 각 단어가 어느 트랙에서 다룬 문제인지 가리킵니다.

숫자와 경로 확인
단서

메시지에 포함된 포트 번호, 파일 경로, 값이 단서입니다. 8080 이라면 포트 문제(Part 5), 경로라면 권한이나 위치 문제(Part 6)로 이어집니다.

메시지가 원인은 아님
주의

메시지는 증상이지 항상 원인은 아닙니다. connection refused 의 원인은 서버 미기동일 수도, 포트 오류일 수도, 방화벽일 수도 있습니다. 메시지에서 출발해 원인을 좁혀 갑니다.

03

이분 탐색으로 원인 범위를 반씩 줄입니다

원인이 어디인지 막막할 때 가장 강력한 방법입니다. 전체를 반으로 나눠 어느 쪽에 문제가 있는지 확인하고, 다시 그 절반을 반으로 나눕니다. 몇 번이면 범위가 한 곳으로 좁혀집니다.

이것은 코드뿐 아니라 모든 문제 진단에 쓰는 사고법입니다. 검색이 막힌 환경에서 스스로 원인을 찾는 핵심 도구입니다.

동작하던 시점과 비교
언제부터

언제까지 됐고 언제부터 안 되는지를 나눕니다. 그 사이에 바뀐 것이 원인입니다. 배포, 설정 변경, 데이터 변화 중 무엇이 그 구간에 있었는지 봅니다.

경로를 반으로
어디서 끊기나

요청이 여러 단계를 거친다면 중간 지점에서 값을 확인합니다. 거기까지 정상이면 뒤쪽, 아니면 앞쪽입니다. Part 5의 계층별 진단과 같은 원리입니다.

코드를 반으로
어느 줄이

의심 구간에 로그를 찍어 어디까지 실행되는지 확인합니다. 로그가 찍힌 지점까지는 정상이므로 범위가 절반으로 줄어듭니다.

형상관리 활용
Git 연계

언제부터 깨졌는지 모를 때, 정상이던 커밋과 현재 사이를 반씩 좁혀 원인 커밋을 찾습니다. Git 이 이 이분 탐색을 도와주는 기능을 제공합니다.

로그로 이분 탐색하기text
# 어느 지점에서 실패하는지 모를 때
# 의심 구간의 중간에 표시를 남기고 어디까지 가는지 본다

처리 시작            ← 여기는 찍힘
  ...
"== 1단계 완료 =="   ← 여기도 찍힘  (문제는 이 아래)
  ...
"== 2단계 완료 =="   ← 안 찍힘      (문제는 1단계와 2단계 사이)
  ...
처리 끝

# 범위가 절반으로 줄었다. 그 사이를 다시 반으로 나눈다.

정교한 디버거가 없어도 이 방법으로 원인 위치를 좁힐 수 있습니다. 폐쇄망 서버에서 특히 유용합니다.

04

가설을 세우고 하나씩 검증합니다

막연히 이것저것 바꿔 보는 것은 시간이 오래 걸리고, 우연히 고쳐도 원인을 모릅니다. 대신 가설을 세우고 검증하는 방식으로 접근합니다.

  • 1. 증상을 정확히 관찰합니다. 언제, 무엇을 할 때, 어떤 메시지가 나오는지.
  • 2. 가설을 세웁니다. 'DB 연결이 안 되는 것 같다' 처럼 확인 가능한 문장으로.
  • 3. 가장 빨리 확인할 수 있는 가설부터 검증합니다.
  • 4. 한 번에 하나만 바꿉니다. 여러 개를 동시에 바꾸면 무엇이 원인인지 모릅니다.
  • 5. 틀렸으면 되돌리고 다음 가설로 넘어갑니다.
한 번에 하나만
핵심 원칙

여러 설정을 동시에 바꿔서 고쳐지면 무엇이 원인이었는지 영영 모릅니다. 재발하면 또 헤맵니다. 하나씩 바꾸고 확인합니다.

되돌릴 수 있게
안전

검증하려고 바꾼 것은 기록하고, 아니면 원래대로 되돌립니다. 트랙 A의 백업 습관이 여기서 쓰입니다. 진단하다 새 문제를 만들지 않습니다.

확인된 것을 기록
누적

무엇이 정상이고 무엇이 원인 후보인지 적어 둡니다. 폐쇄망에서는 물어볼 곳이 없으므로, 확인한 사실을 쌓는 것이 유일한 진전입니다. Part 9로 이어집니다.

핵심

AI에게 에러를 붙여넣는 대신, 스택트레이스에서 진짜 원인을 찾고, 이분 탐색으로 범위를 좁히고, 가설을 하나씩 검증합니다. 이 사고법은 도구가 없어도, 검색이 막혀도 작동합니다. 오히려 그런 환경에서 진짜 실력이 됩니다.

체크

이 파트 완료 기준