2026-05-08 xcbeautify와 구조화 xcodebuild 로그 — 임대 Apple Silicon 클라우드 Mac의 CI 게이트 (HK / JP / KR / SG / US)
컴파일러가 “컴파일을 잊었다” 때문에 CI가 멈추는 경우는 드물고, 로그를 읽을 수 없어서 죽습니다. 홍콩·도쿄·서울·싱가포르·미국의 임대 Mac mini M4에서는 병렬 레인마다 xcodebuild 출력이 수십 MB를 넘습니다. 그대로 두면 Xcode의 긴 배너를 grep 하는 동안 대기열만 탑니다. xcbeautify는 그 홍수를 줄마다 grep하기 쉬운 레코드로 바꾸며 실패를 숨기지 않습니다. tee와 결합하면 법무 보존용 원시 전사본과 자동화용 정규화 스트림을 모두 남길 수 있습니다. 이번 2026-05-08 가이드는 설치 핀, 파이프 구성, result bundle 정렬, 실패 분류를 순서대로 다루며 병렬 xcodebuild 레인, DerivedData 격리, 셀프호스티드 runner, 커버리지 게이트, 디스크 위생 옆에서 게이트를 결정적으로 유지합니다.
2026년에도 읽을 수 있는 로그가 릴리스를 막는다
Apple 툴체인 진단은 줄바꿈을 읽기 어려울 정도로 불안정합니다. CI 벤더는 HTML 뷰어로 보완하지만 SSH 전용 임대 머신에는 감사용 일반 텍스트 증적과 diff 친화적 산출물이 여전히 필요합니다. xcbeautify는 .xcresult의 진실을 대체하지 않습니다—xcresulttool을 열기 전 사람과 정규식에 여지를 줍니다. 정리된 로그를 1층, JUnit 익스포터가 보는 구조화 번들을 2층으로 생각하세요.
원격 빌더의 노이즈와 신호
MacXCode 노드에서 만성화되는 세 가지:
- 래퍼가 스트림을 잘못 합치면 stderr 순서가 사라집니다.
- 지역화된 clang 진단의 Unicode 경계—UTF-8을 끝까지 유지하세요.
- 병렬 팬아웃으로 레인 B 경고가 집계 대시보드에서 레인 A 치명 오류를 쓸어갑니다.
꾸미기 전에 상관을 붙이세요: 각 명령 앞에 RUNNER_TRACKING_ID나 빌드 행렬 좌표를 넣고 Slack 샤드를 발생 레인으로 돌립니다.
도입 경로: Mint, Homebrew, 시맨틱 핀
조직 표준에 맞춰 재현 가능한 설치를 우선합니다:
- Mint — CI YAML 근처에 커밋한
Mintfile로 핀. - Homebrew — 골든 빌드 후
brew list --versions를 스냅샷한다면 가능. - curl | bash — 공유 서명 호스트에서는 피하고 재현성이 속도를 이깁니다.
런북에 바이너리 경로를 명시하고 launchd 잡과 대화형 셸이 같은 바이너리를 해석하도록 하세요—PATH 룰렛으로 “도쿄 로컬은 되는데 싱가포르에서 실패”가 납니다.
운영에서 살아남는 파이프와 tee
원시 로그 없이 xcbeautify로만 보내지 마세요. 뼈대 예:
set -o pipefail
xcodebuild … 2>&1 | tee "${RAW_LOG}" | xcbeautify > "${PRETTY_LOG}"
pipefail로 xcodebuild 실패 시에도 파이프라인이 비영을 물려받습니다—xcbeautify는 종종 0으로 끝납니다. 명시적 RESULT_BUNDLE_PATH를 달고 JUnit 단계가 stdout 장식과 독립적으로 .xcresult를 읽게 하세요. 집중 로그 벤더에는 원시를 상류에, GitHub Actions 요약에는 정리본을 보냅니다.
ssh -t)를 피하세요—배치 모드와 비교해 버퍼링과 행 순서가 바뀝니다.
grep 게이트: 정규식과 xcresult 진실을 쌍으로
일찍 잡아야 할 자동화 실패 기준선:
| 패턴군 | grep 예 | 후속 |
|---|---|---|
| Clang 치명 | grep -E "error: fatal error:" |
xcresulttool로 issue summary |
| 서명 | grep -Ei "codesign|Provisioning profile" |
키체인 해제 절차와 레인 격리 대조 |
| 시뮬레이터 | grep -E "SimRuntime|CoreSimulator" |
시뮬레이터 보존 정책 참조 |
정리 로그는 오류 줄을 예측 가능한 접두로 접어 grep을 안정화합니다—그래도 stderr가 거짓말하는 불안정한 UI 테스트는 .xcresult로 검증합니다.
병렬 레인: 레인마다 xcbeautify 출력 상관
한 호스트에서 여러 xcodebuild가 팬아웃되면 각 줄에 레인 식별자를 앞에 붙입니다:
… | sed "s/^/[lane-${MATRIX}] /" | xcbeautify
접두가 없으면 통합 산출물이 잘못된 팀에 책임을 넘깁니다—특히 통합 메모리 압력 아래 무관 레인이 지연될 때입니다. 병렬 잡 조정의 동시성 가이드와 맞춥니다.
보존, NVMe, 산출물 예산
각 PR이 raw와 pretty를 모두 쌓으면 로그가 급증합니다.
- DerivedData 가이드를 따라 격리 TMPDIR 아래에 잡별 디렉터리.
- 계층 보존 — raw를 객체 스토리지에 14~30일, pretty 요약을 NVMe에 7일.
- 압축 — 리전 간 업로드 전
zstdtarball.
여유 공간이 운영 임계 아래로 내려가면 컴플라이언스 티켓에 묶인 .xcresult보다 먼저 오래된 pretty를 삭제합니다.
9단계 롤아웃 체크리스트
- xcbeautify를 핀하고 체크섬 또는 패키지 버전을 기록합니다.
- CI 래퍼에 pipefail+tee 배선을 추가합니다.
- xcresult 경로를 구조화 메타데이터 JSON으로 내보냅니다.
- grep 게이트와 Slack 심각도 라우팅을 추가합니다.
- 로그를 소비하는 Windows/Linux 뷰어에서 UTF-8 디코드를 검증합니다.
- 접두가 붙은 레인으로 병렬 소크를 돌립니다.
- 예산을 위해 raw와 pretty의 gzip 크기를 비교합니다.
- 인시던트 때 xcbeautify와 raw 읽는 법을 온콜에 훈련합니다.
- 인프라 PR로 변경을 승격하고 롤백 tarball을 준비합니다.
SLO 표: 임대 빌더 로그 건전성
| 신호 | 임계값 | 조치 |
|---|---|---|
| 원시 로그 산출물 누락 | 실패 빌드에서 하나라도 | 배포 중지, tee 경로 수정 |
| grep 위음성 | 스프린트당 > 2 | 패턴 조정 + xcresult 어서션 |
| 디스크 사용률 기울기 | 주간 > 18% 기울기 | 보존 조정 및 리스 SKU 확장 |
FAQ
| 질문 | 실무 답변 (2026-05-08) |
|---|---|
| Darwin 전용 xcbeautify 빌드? | OS마다 aarch64 bottle을 핀; Rosetta와 네이티브를 레인 간에 섞지 마세요. |
| 원시 로그를 생략할 수 있나요? | 아니요—감사와 Apple DTS 에스컬레이션은 가공되지 않은 전사본을 기대합니다. |
로그 집약 CI에 Mac mini M4 베어메탈이 맞는 이유
순차 로그 쓰기는 APFS 메타데이터 업데이트와 경합하고 병렬 테스트는 IOPS를 급격히 올립니다. MacXCode 리전 임대 Mac mini M4 NVMe는 테일 지연을 예측 가능하게 유지하고 tee+xcbeautify 파이프라인이 불안정한 빨강을 증폭하지 않습니다. 용량 계획은 지역별 가격, 문자셋 문제 대화 디버깅은 SSH/VNC 액세스 가이드를 함께 쓰세요.