Showing Posts From

Debug로

로그 레벨을 DEBUG로 두고 배포한 죄책감

로그 레벨을 DEBUG로 두고 배포한 죄책감

로그 레벨을 DEBUG로 두고 배포한 죄책감 새벽 3시의 슬랙 메시지 금요일 저녁 7시. 배포 완료. "수고하셨습니다~" 단톡에 올리고 퇴근. 치킨 시켜놓고 맥주 땄다. 새벽 3시 20분. 슬랙 알림. "서버 응답 속도 왜 이래요?" 인프라팀 최대리다. 심장이 멎었다. 노트북 켰다. 손이 떨렸다.로그 파일 30GB VPN 접속. 서버 들어갔다. 로그 파일 확인했다. -rw-r--r-- 1 app app 30G Jan 17 03:15 application.log30기가. 배포 전엔 200메가였다. 4시간 만에 150배. tail 명령어 쳤다. 화면이 미친 듯이 흘렀다. 2025-01-17 03:15:23.441 DEBUG [http-nio-8080-exec-234] - Request received: GET /api/users 2025-01-17 03:15:23.442 DEBUG [http-nio-8080-exec-234] - Parsing request parameters... 2025-01-17 03:15:23.443 DEBUG [http-nio-8080-exec-234] - DB connection pool size: 15 2025-01-17 03:15:23.444 DEBUG [http-nio-8080-exec-234] - Executing query: SELECT * FROM users WHERE...1초에 수백 줄. 모든 API 호출마다. 모든 DB 쿼리마다. 모든 Redis 접근마다. 다 찍히고 있었다. application.yml 열었다. logging: level: root: DEBUG com.company: DEBUG내가 그제 고친 거다. 로컬에서 버그 잡으려고. 그리고 까먹었다.디스크 사용률 97% 더 큰 문제가 있었다. 그라파나 대시보드 확인. 디스크 사용률: 97%. 1시간 전만 해도 65%였다. 로그 때문에 디스크가 차고 있었다. 100% 되면 서버가 죽는다. 쓰기 작업 전부 실패한다. 오전 9시까지 4시간. 이 속도면 2시간 안에 100%. 손가락 떨면서 타이핑. sudo rm -rf /var/log/app/application.log.* sudo truncate -s 0 /var/log/app/application.log구형 로그 지웠다. 현재 로그도 비웠다. 5분 뒤. 다시 1.2GB. yml 수정했다. logging: level: root: INFO com.company: WARN긴급 배포. Jenkins 띄우고 빌드. 12분 걸렸다. 평소엔 8분인데. 배포 완료. 서버 재시작. 로그 속도 정상화. 디스크 사용률 72%에서 멈췄다. 새벽 4시 10분. 50분 걸렸다.월요일 아침 회의 주말 내내 불안했다. 로그 모니터링만 10번 확인. 다행히 문제 없었다. 월요일 9시. 주간 회의. 팀장이 물었다. "금요일 배포 후 이슈 있었나요?" 나: "아... 로그 레벨 설정 실수가 있었습니다." 인프라팀 최대리가 옆에 있었다. 눈빛이 날카로웠다. 팀장: "어떤 실수?" 나: "DEBUG로 남겨서 로그가 폭발했습니다. 디스크 97%까지 갔었고요." 회의실이 조용해졌다. 팀장: "언제 알았어요?" 나: "토요일 새벽 3시요." 팀장: "고객 영향은?" 나: "없었습니다. 응답 속도 약간 느렸지만." 거짓말이었다. Latency가 평소 200ms에서 800ms까지 튀었다. 다만 timeout은 안 났다. 팀장: "재발 방지는?" 나: "배포 체크리스트에 추가하겠습니다." 인프라팀 최대리: "로그 볼륨 알림도 설정해야죠." 나: "예, 그것도 하겠습니다." 회의 끝나고. 팀장이 따로 불렀다. "다음부턴 미리 말해." 그게 다였다. 혼은 안 났다. 더 무서웠다. 체크리스트 추가 그날 오후. 배포 문서를 수정했다. 배포 전 필수 체크리스트:application.yml 로그 레벨 확인 (INFO/WARN) 프로파일 설정 확인 (prod) DB 커넥션 URL 확인 Redis 엔드포인트 확인 외부 API 키 확인빨간색으로 강조했다. "로그 레벨 반드시 INFO 이하" Jenkins에 훅도 추가했다. 빌드 전에 yml 파싱해서. DEBUG 있으면 빌드 실패. stage('Check Log Level') { steps { script { def config = readYaml file: 'src/main/resources/application.yml' if (config.logging.level.root == 'DEBUG') { error('로그 레벨이 DEBUG입니다. INFO로 변경하세요.') } } } }후배 김주니어가 물었다. "형, 이거 너무 빡빡한 거 아니에요?" 나: "실수 한 번 하면 알게 돼." 김주니어는 이해 못 하는 표정. 2년 차는 아직 모른다. 프로덕션 장애의 공포를. 로그의 무게 개발할 땐 로그가 친구다. println 박고. System.out 찍고. log.debug() 남기고. "여기 들어왔나?" "이 값이 뭐지?" "쿼리 제대로 나가나?" 로그 없으면 디버깅 못 한다. IntelliJ 디버거 써도. 결국 로그를 본다. 그런데 프로덕션은 다르다. 로그 한 줄이 디스크를 먹는다. 초당 천 건 API면. DEBUG로 10줄씩 찍으면. 초당 만 줄. 분당 60만 줄. 시간당 3600만 줄. 하루면 8억 줄이 넘는다. 그게 전부 디스크에 쌓인다. 파일 시스템이 버틴다. 로그 수집기가 버틴다. 엘라스틱서치가 버틴다. 근데 비용이 나간다. S3 저장 비용. 클라우드워치 비용. 엘라스틱서치 인덱싱 비용. 회사 돈이다. 그리고 성능이 떨어진다. 파일 I/O는 느리다. 로그 찍는 동안 스레드가 멈춘다. async logger 써도. 버퍼가 차면 대기한다. 사용자는 기다린다. 로그 한 줄의 무게. 신입 때는 몰랐다. 7년 차가 되니 안다. 그래도 실수는 반복된다 이번이 처음은 아니다. 3년 전에는. 하드코딩한 테스트 계정. 프로덕션에 그대로 배포. 2년 전에는. Redis 키 prefix 빼먹어서. dev 데이터랑 prod 데이터 섞임. 1년 전에는. SQL 쿼리에 limit 빠뜨려서. 10만 건 full scan. 매번 다짐한다. "다시는 안 그러겠다." 근데 또 한다. 사람이라서. 피곤해서. 급해서. 시스템으로 막는다. 체크리스트. 자동화. 코드 리뷰. 그래도 빠져나간다. 완벽한 시스템은 없다. 결국 새벽에 슬랙 온다. 심장 떨린다. 노트북 켠다. 7년 차도 이런데. 15년 차는 어떨까. 익숙해질까. 아니면 더 조심해질까. 금요일 배포의 저주 왜 하필 금요일이었을까. 금요일 배포는 저주다. 업계 불문율. "금요일엔 배포하지 마라." 근데 우리 회사는 한다. 스프린트가 2주. 매주 금요일이 배포일. 그래서 매주 금요일. 6시 퇴근이 9시가 된다. 배포하고. 모니터링하고. 괜찮으면 퇴근. 근데 이번엔 방심했다. 배포 후 30분만 보고. "괜찮네" 하고 나왔다. 문제는 4시간 뒤에 터졌다. 로그가 쌓이는 건 느리다. 처음엔 티가 안 난다. 새벽에 터진다. 트래픽 적을 때. 다들 자고 있을 때. 월요일 배포였으면. 당일에 발견했을 거다. 사람 많을 때. 금요일 배포의 저주. 맞는 말이었다. 인프라팀의 차가운 시선 월요일 점심. 구내식당에서 최대리 만났다. 나: "저번에 죄송했습니다." 최대리: "괜찮아요. 빨리 조치했잖아요." 말투는 괜찮은데. 표정이 안 괜찮았다. 인프라팀 입장에선. 개발팀이 원수다. 우리가 코드 잘못 짜면. 서버가 죽는다. 그럼 인프라팀이 깬다. 메모리 릭. CPU 100%. 디스크 풀. 네트워크 타임아웃. 전부 개발자 실수다. 인프라팀이 수습한다. 그래서 우리를 못 믿는다. 배포할 때마다 긴장한다. "또 뭐 터질까." 이번 건으로. 신뢰가 더 깎였다. 다음 배포 때. 더 까다롭게 체크할 거다. "로그 레벨 확인했어요?" "진짜 확인했어요?" "yml 파일 보여주세요." 귀찮아진다. 근데 내 잘못이다. 신뢰는 쌓기 어렵고. 무너지긴 쉽다. 로그 레벨의 철학 INFO는 뭐고. WARN은 뭐고. ERROR는 뭔가. 신입 때는 몰랐다. 그냥 아무거나 썼다. log.info("유저 정보 조회"); log.warn("유저가 없음"); log.error("DB 연결 실패");다 틀렸다. INFO는 비즈니스 이벤트다. "주문 생성됨" "결제 완료" "회원가입 성공" 운영에 필요한 정보. 흐름 파악용. WARN은 비정상인데 처리 가능. "재시도 했음" "캐시 미스" "외부 API 느림" 신경 쓸 건데 급하진 않음. ERROR는 장애다. "DB 죽음" "필수 API 실패" "데이터 정합성 깨짐" 당장 처리해야 함. 슬랙 알림 가는 레벨. DEBUG는 개발용이다. 프로덕션엔 절대 안 씀. TRACE는 더 심하다. 라이브러리 내부 로직. 쓸 일 없다. 이걸 7년 만에 깨달았다. 늦었다. 다른 사람들의 실수 우리 팀만 그런 게 아니다. 작년에 A사. 환경변수 잘못 설정. 개발 DB를 프로덕션으로 착각. 실서비스가 테스트 데이터로 돌아감. B사는. 배포 스크립트 오타. 서버 전체 재시작 대신. 서버 전체 삭제. 백업으로 복구하는데 4시간. C사는. 캐시 TTL 설정 실수. 1시간이 1초로. Redis 트래픽 폭발. AWS 비용 하루에 300만원. 다들 실수한다. 베테랑도. 대기업도. 카카오 불 났을 때. 데이터센터 하나 죽었다. 백업 센터 자동 전환 실패. 카톡 5시간 먹통. 페이스북은. 잘못된 설정 배포로. 글로벌 서비스 6시간 다운. 아마존은. 오타 하나로. S3 전체 다운. 인터넷 절반이 멈췄다. 우리가 약한 게 아니다. 모두가 약하다. 다만 시스템을 개선해. 같은 실수 반복을 막는다. 지금의 대책 일주일 지났다. 추가한 것들.Jenkins 빌드 훅 - 로그 레벨 자동 체크 Grafana 알림 - 디스크 80% 넘으면 슬랙 로그 볼륨 모니터링 - 시간당 1GB 넘으면 경고 PR 템플릿 수정 - 로그 레벨 확인 항목 추가 배포 문서 업데이트 - 로그 관련 섹션 강화김주니어한테 교육했다. "로그는 비용이다." "프로덕션은 전쟁터다." "금요일 배포는 조심해라." 주니어는 고개 끄덕였다. 근데 이해 못 한 것 같았다. 결국 직접 겪어야 안다. 언젠가 김주니어도. 새벽 3시에 깰 거다. 심장 떨리며 노트북 켤 거다. 그게 성장이다. 아프지만. 로그가 가르쳐준 것 7년 동안 배운 것. 코드는 혼자 안 돌아간다. 서버 위에서 돈다. 네트워크 타고 간다. 데이터베이스랑 얘기한다. 그 모든 게 비용이다. CPU. 메모리. 디스크. 네트워크. 로그도 비용이다. 공짜가 아니다. "일단 찍어보자"가 습관이었다. 이제는 "꼭 필요한가"를 묻는다. DEBUG 로그 남길 때. "프로덕션에서 보겠어?" 아니면 지운다. INFO 로그 남길 때. "운영에 필요한가?" 아니면 DEBUG로. WARN 로그 남길 때. "조치 필요한가?" 아니면 INFO로. ERROR 로그 남길 때. "당장 처리해야 하나?" 그럼 슬랙 알림도. 로그 한 줄을 신중하게. 프로덕션을 존중하게. 여전히 불안한 금요일 오늘도 금요일. 배포일이다. 어제 PR 3개 머지했다. 오늘 오후 6시 배포 예정. 벌써 불안하다. 점심도 안 넘어간다. 체크리스트 10번 확인. 로그 레벨 INFO 맞음. 환경변수 prod 맞음. DB URL 맞음. 그래도 불안하다. 뭐 빠뜨린 것 같다. 김주니어가 물었다. "형, 왜 이렇게 예민해요?" 나: "작년에 사고 쳐봐서." 김주니어: "큰 사고였어요?" 나: "새벽 3시에 깼어." 김주니어: "아..." 이제 알 것 같다는 표정. 커피 세 번째. 손 떨린다. 카페인 때문인지. 긴장 때문인지. 6시간 남았다.금요일 배포는 여전히 무섭다. 7년 차도 그렇다.