macOS 통합 로그로 클라우드 Mac 빌드와 서명 장애 진단하기
새벽에 자동 빌드가 갑자기 실패했지만 터미널에는 Command PhaseScriptExecution failed만 남고, 다시 실행하면 정상적으로 완료되는 경우가 있습니다. 이때 마지막 한 줄만 계속 들여다봐도 원인을 찾기 어렵습니다. 클라우드 Mac에서는 빌드 도구, 서명 서비스, 네트워크 프로세스, 시스템 권한 관련 구성 요소가 각각 macOS 통합 로그에 이벤트를 기록합니다. 이 기록을 하나의 시간축에 맞춰 보면 문제가 프로젝트 스크립트에서 발생했는지, 시스템 서비스에서 비롯됐는지, 원격 연결이 끊긴 탓인지 대체로 구분할 수 있습니다.
먼저 장애 시간대와 재현 범위를 확정하기
우선 노드의 현재 시각, 명령 시작 시각, 실패 시각, 종료 코드를 기록합니다. 원격 클라이언트에 표시되는 로컬 시각은 노드의 시간대와 다를 수 있으므로, 진단할 때는 노드 시각을 기준으로 통일합니다.
date -u '+%Y-%m-%dT%H:%M:%SZ'
set -o pipefail
xcodebuild \
-workspace Demo.xcworkspace \
-scheme Demo \
-configuration Release \
build 2>&1 | tee "$HOME/build-output.log"
printf 'exit=%s
' "${PIPESTATUS[0]}"
DerivedData를 바로 삭제하거나 프로세스를 재시작하거나 기존 로그를 덮어쓰지 마세요. 먼저 빌드 출력을 복사한 뒤 장애가 안정적으로 재현되는지 확인해야 합니다. 간헐적인 문제라면 최소 두 번의 실행 결과를 기록하고, 두 실행에서 사용한 커밋, Xcode 경로, Shell 환경, 작업 디렉터리가 동일했는지도 함께 명시합니다.
통합 로그는 터미널 출력을 대신하지 않습니다. 통합 로그는 시스템과 서비스에서 어떤 일이 있었는지를 설명하고, 터미널 출력은 빌드 명령이 어느 단계까지 실행됐는지를 보여 줍니다. 두 기록은 반드시 같은 시간 범위를 기준으로 수집해야 합니다.
조건식으로 통합 로그 범위 좁히기
log show는 이미 발생한 이벤트를 되짚어 볼 때 적합합니다. 처음부터 몇 시간 분량의 전체 로그를 내보내면 잡음이 크게 늘고 민감 정보 제거 작업도 복잡해집니다. 실패 전후 10분을 경계로 삼아 먼저 프로세스 이름으로 필터링합니다.
log show \
--last 20m \
--style compact \
--info \
--debug \
--predicate 'process == "xcodebuild" OR process == "codesign"'
터미널에 서명 실패만 표시된다면 보안 서비스가 반환한 거부 메시지를 추가로 검색합니다. 원격 세션이 빌드 과정에 영향을 줬을 가능성이 있다면 sshd와 실제로 스크립트를 실행한 프로세스를 확인합니다. 조건식에는 전체 텍스트를 광범위하게 검색하기보다 process, subsystem, category, eventMessage 필드를 우선 사용하는 것이 좋습니다.
log show --last 15m --style compact \
--predicate '(process == "sshd") OR (eventMessage CONTAINS[c] "denied")'
자주 나타나는 신호는 아래 표처럼 해석할 수 있지만, 최종 판단은 반드시 종료 코드와 재현 절차를 함께 고려해야 합니다.
| 로그 신호 | 우선 확인할 항목 | 바로 내려서는 안 되는 결론 |
|---|---|---|
permission denied |
파일 권한, 키체인 접근, 실행 계정 | 노드 하드웨어 장애 |
| 프로세스 종료 | 메모리 압박, 부모 프로세스, 스크립트 시간 제한 규칙 | Xcode 자체 손상 |
| SSH 세션 연결 끊김 | 클라이언트 네트워크, 연결 유지 설정, 작업 실행 방식 | 빌드가 반드시 실패함 |
| 서명 서비스에서 일치 항목 없음 | 키체인, 인증서 이름, 프로비저닝 프로파일 매핑 | 전체 도구 체인을 다시 설치해야 함 |
재현 중 핵심 이벤트를 실시간으로 관찰하기
문제를 안정적으로 재현할 수 있다면 별도의 SSH 세션을 열고 log stream을 실행합니다. 실시간 스트림은 관찰 용도로만 사용해야 합니다. 필터 조건을 지나치게 넓게 설정하면 연속 출력에 핵심 이벤트가 묻힐 수 있습니다.
log stream \
--style compact \
--level info \
--predicate 'process == "xcodebuild" OR process == "codesign" OR process == "securityd"'
그런 다음 기존 세션에서 빌드를 시작하고, 첫 번째 이상 로그가 나타난 시점과 빌드 실패 시점 사이의 시간 차이를 기록합니다. 서명 오류가 먼저 발생한 뒤 빌드 도구가 이를 일반적인 실패로 요약했다면 서명 경로를 우선 해결해야 합니다. 반대로 SSH 연결이 먼저 끊겼지만 빌드 프로세스는 계속 실행 중이라면 컴파일 오류로 잘못 판단하지 말고, 작업이 대화형 터미널에 종속돼 있는지 확인해야 합니다.
스크립트에 연관 분석용 표식 추가하기
직접 관리하는 스크립트라면 시작과 종료 시점에 통합 로그를 남길 수 있습니다. 고정된 subsystem과 실행할 때마다 고유한 작업 번호를 사용하면 모호한 파일명 검색에 의존하지 않고도 관련 이벤트를 묶을 수 있습니다.
job_id="$(date -u '+%Y%m%dT%H%M%SZ')"
logger -p user.notice -t minid-build "job=$job_id phase=start"
./scripts/build.sh
status=$?
logger -p user.notice -t minid-build "job=$job_id phase=end status=$status"
exit "$status"
logger가 기록한 태그는 process 또는 메시지 내용으로 검색할 수 있습니다. 작업 번호는 한 번의 실행을 연관 짓는 용도로만 사용해야 하며, 토큰이나 저장소 자격 증명, 고객 데이터를 포함해서는 안 됩니다.
다시 검토하고 안전하게 전달할 수 있는 증거 내보내기
명령줄의 텍스트 출력은 빠른 분석에 적합하지만, 복잡한 문제는 .logarchive 형식으로 보관해야 합니다. 아카이브를 만들기 전에 시간 범위를 다시 확인해 장애와 무관한 과거 기록까지 수집하지 않도록 합니다.
mkdir -p "$HOME/diagnostics"
sudo log collect \
--last 15m \
--output "$HOME/diagnostics/build-incident.logarchive"
cp "$HOME/build-output.log" "$HOME/diagnostics/"
전체 디렉터리를 그대로 전송해서는 안 됩니다. 먼저 빌드 로그에서 확장된 환경 변수, 프로젝트의 절대 경로, 노드 주소, 저장소 주소, 인증서 이름, 스크립트 인수를 확인합니다. 민감한 값을 치환할 때는 일관된 매핑을 유지해야 합니다. 예를 들어 같은 사용자 이름은 항상 <USER>로 바꿔야 이후에도 여러 이벤트가 동일한 계정에서 발생했는지 판단할 수 있습니다.
UTC 시각, 실행 명령, 종료 코드, 예상 결과, 실제 결과, 재현 가능 여부, 장애 직전 마지막으로 성공한 실행의 커밋을 담은 일반 텍스트 설명 파일도 함께 작성하는 것이 좋습니다. 로그는 실제로 무슨 일이 있었는지를 입증하고, 설명 파일은 조사 범위를 명확히 제한합니다.
증거에 따라 다음 조치 결정하기
수집을 마치면 먼저 문제를 프로젝트, 환경, 연결, 리소스의 네 가지 유형으로 분류합니다. 프로젝트 문제는 같은 커밋을 깨끗한 작업 디렉터리에서 실행해 검증할 수 있습니다. 환경 문제는 Xcode 선택 상태, Shell 초기화, 키체인 가시성을 확인해야 합니다. 연결 문제는 세션 연결 끊김과 작업 종료를 구분해야 합니다. 리소스 문제라면 남은 디스크 공간, 메모리 압박, 동시에 실행 중인 프로세스를 점검합니다.
진단을 끝내기 전에 최소 검수 절차를 한 번 수행합니다. 동일한 커밋을 두 번 연속 빌드해 종료 코드가 0인지 확인하고, 서명된 결과물은 codesign --verify --deep --strict로 검증합니다. SSH 연결이 끊긴 뒤에도 백그라운드 작업이 예상대로 완료되는지 확인하고, 진단 디렉터리에 평문 토큰이 남아 있지 않은지도 점검합니다. 이 조건이 모두 충족돼야 장애가 실제로 종결됐다고 볼 수 있습니다.
자주 묻는 질문
xcodebuild 출력만 저장하면 부족한 이유는 무엇인가요?
빌드 출력에는 작업 단계가 주로 기록됩니다. 권한 거부, 서명 서비스, 네트워크 연결 종료와 시스템 프로세스 오류는 통합 로그에만 남을 수 있습니다.
로그를 전달하기 전에 무엇을 제거해야 하나요?
사용자 이름, 프로젝트 절대 경로, 노드 주소, 저장소 주소, 토큰, 인증서 이름과 업무 데이터를 확인하고 일관된 대체 문자열로 가려야 합니다.
MiniD 클라우드 Mac
전용 물리 Mac mini를 일·주·월 단위로 대여
모든 플랜은 전용 물리 Mac mini에서 실행되며 원격 데스크톱과 SSH로 접속할 수 있습니다. 최신 모델·리전·기간은 주문 페이지에서 확인하세요.