MOM.SOFT

MOMSOFT  /  기술 블로그

Architecture

로그와 추적을 나중에 붙이면 늦는 이유

장애가 터진 뒤에 로그를 붙이면, 그 장애는 이미 못 봅니다. 관측 장치를 코드와 같이 짜야 하는 이유와, 최소 비용으로 넣는 순서를 정리했습니다.

프로젝트 문의하기 →

결론부터: 관측 장치는 기능이 아니라 코드의 일부입니다

로그와 추적은 "나중에 여유 생기면 붙이는 것"이 아닙니다. 붙이는 시점에 이미 그 장애를 못 보기 때문입니다. 장애가 터지고 나서 로그를 추가하면 우리가 얻는 것은 다음 번 같은 장애에 대한 정보뿐입니다. 지금 눈앞의 장애는 여전히 캄캄합니다. 그런데 같은 장애가 같은 모양으로 다시 나는 경우는 생각보다 드뭅니다.

그래서 저는 신규 서비스를 시작할 때 인증, 설정, 배포 파이프라인과 같은 급으로 관측 장치를 취급합니다. 화려한 대시보드를 만들라는 뜻이 아닙니다. 요청 하나를 끝까지 따라갈 수 있는 상관관계 ID, 기계가 읽을 수 있는 구조화 로그, 그리고 사용자 체감을 대변하는 지표 서너 개. 이 셋이면 초기에는 충분하고, 셋 다 나중에 붙이는 비용이 지금 붙이는 비용보다 훨씬 큽니다. 아래에서 그 비용 차이가 어디서 생기는지, 무엇부터 넣어야 하는지, 그리고 어디까지만 해야 하는지를 순서대로 정리하겠습니다.

평소 남기는 정보와 장애 때 필요한 정보는 다릅니다

대부분의 서비스에는 로그가 이미 있습니다. 문제는 그 로그가 개발자가 개발 중에 보려고 남긴 로그라는 점입니다. 개발 중에는 내가 방금 무엇을 실행했는지 알고 있으니, 로그는 "여기까지 왔다"만 알려주면 충분합니다. 장애 상황은 정반대입니다. 무슨 일이 있었는지 모르는 상태에서, 남의 요청 수만 건 사이에 섞인 특정 요청 하나를 찾아내야 합니다.

이 간극을 표로 보면 명확합니다.

질문평소 로그가 답하는 것장애 때 실제로 필요한 것
누가 겪었나"결제 처리 시작"어떤 사용자·테넌트·주문의 요청인지 식별자
어디서 깨졌나스택 트레이스 한 덩어리요청이 지나간 서비스 구간별 소요 시간
얼마나 번졌나에러 로그 몇 줄같은 원인의 실패 건수와 영향 사용자 비율
언제 시작됐나알람이 울린 시각지표가 정상 범위를 벗어나기 시작한 시각
배포 탓인가없음버전·인스턴스 단위로 쪼갠 에러율
재현되나없음실패 요청의 입력 형태(개인정보 제외)와 분포

오른쪽 열은 하나같이 맥락(context)입니다. 그리고 맥락은 로그 문장이 아니라 로그에 딸린 필드에서 나옵니다. "결제 처리 시작"이라는 문장을 아무리 예쁘게 다듬어도, 그 줄에 주문 식별자와 추적 ID가 없으면 장애 때 쓸모가 없습니다. 반대로 문장이 투박해도 필드가 붙어 있으면 검색으로 실마리를 잡을 수 있습니다.

로그·지표·추적은 대체재가 아닙니다

세 신호는 각각 다른 질문에 답합니다. 하나로 나머지를 대신하려 들면 비용만 커집니다.

신호답하는 질문비용 성격
지표(metric)지금 이상한가, 언제부터인가시계열 개수(카디널리티)에 비례
추적(trace)느린 요청이 어디서 시간을 썼나요청 수에 비례, 샘플링으로 조절
로그그 순간 정확히 무슨 값이었나줄 수와 보존 기간에 비례, 대체로 가장 비쌈

이상 감지는 지표로, 범위 좁히기는 추적으로, 마지막 확인 사살은 로그로. 이 순서를 전제로 설계하면 로그를 무한정 늘릴 이유가 사라집니다. 반대로 이 순서가 없으면 "혹시 모르니 다 남기자"가 유일한 전략이 되고, 그 결과가 아무도 읽지 않는 거대한 저장소입니다.

왜 사후에 붙이기가 유독 어려운가

"코드 몇 줄 넣으면 되는 것 아닌가"라고 생각하기 쉽습니다. 실제로 어려운 이유는 코드량이 아니라 다음 네 가지 구조적 제약 때문입니다.

1. 과거는 복구되지 않습니다

가장 단순하고 가장 치명적인 이유입니다. 어제 남기지 않은 로그는 오늘 어떤 도구로도 만들어낼 수 없습니다. 데이터베이스 스키마는 마이그레이션으로 과거 데이터를 채울 수라도 있지만, 관측 데이터는 그 순간에만 존재합니다. 간헐적으로 하루에 몇 건 나는 종류의 장애라면, 관측 장치를 붙이고 다시 잡기까지 몇 주가 그냥 흘러갑니다. 그 사이에 원인 후보를 추측으로 좁히다가 엉뚱한 곳을 고치는 일도 흔합니다.

2. 맥락은 호출 경계를 넘으면서 사라집니다

사후에 로그를 붙일 때 사람들은 보통 에러가 난 지점에 로그를 추가합니다. 그런데 그 지점은 대개 NullPointerException이 터진 최말단이고, 정작 알고 싶은 것은 "이 값이 왜 null이 되어 여기까지 왔는가"입니다. 그 답은 서너 계층 위, 어쩌면 다른 서비스에 있습니다. 요청 시작 시점에 식별자를 심어 두지 않았다면, 최말단 로그와 진입점 로그를 이어 붙일 방법이 없습니다.

비동기가 끼면 더 나빠집니다. 스레드 풀에 작업을 던지는 순간, 메시지 큐로 넘기는 순간 스레드 로컬 기반 맥락은 끊어집니다. 이 전파 코드를 나중에 넣으려면 이미 곳곳에 퍼져 있는 @Async, 이벤트 리스너, 큐 컨슈머를 전부 손봐야 합니다. 처음에 실행기(executor)와 메시지 어댑터를 한 번 감싸 두면 끝날 일이, 나중에는 수십 군데 수정이 됩니다.

3. 로그 형식이 굳으면 되돌리기 어렵습니다

평문 로그가 쌓이고, 그 위에 알람 규칙과 정규식 파서와 운영 문서가 얹히면, 구조화 로그로 전환하는 일은 코드 변경이 아니라 합의의 문제가 됩니다. "기존 파서 깨진다", "운영 매뉴얼 다시 써야 한다"는 반대에 부딪히고, 결국 두 형식을 병행하다가 둘 다 반쯤 신뢰하게 됩니다.

4. 관측 없는 코드는 관측하기 어려운 모양으로 자랍니다

이게 가장 조용하고 가장 비싼 이유입니다. 처음부터 추적을 켜 두면 개발자는 자기 코드의 호출 그래프를 눈으로 봅니다. 반복 호출(N+1), 불필요한 동기 대기, 얽힌 순환 호출이 그림으로 드러나니 자연스럽게 정리됩니다. 관측이 없으면 아무도 그 그림을 못 보므로, 아키텍처는 아무도 모르는 채로 복잡해집니다. 그렇게 몇 년을 자란 시스템에 추적을 붙이면, 첫 화면에서 마주하는 것은 통찰이 아니라 수백 개 스팬으로 뒤엉킨 폭포수입니다.

상관관계 ID: 가장 먼저, 가장 싸게

관측 장치 중 투자 대비 회수가 압도적으로 좋은 것이 상관관계 ID입니다. 요청이 시스템에 들어오는 첫 지점에서 ID를 하나 만들고, 그 요청이 만드는 모든 로그와 모든 하위 호출에 같은 ID를 달아 보냅니다. 그것뿐입니다.

규칙은 세 가지입니다.

자체 헤더를 만들기 전에 표준부터 보세요

여기서 순서를 자주 뒤집습니다. 나중에라도 분산 추적을 쓸 생각이라면, 자체 헤더를 새로 정의하기보다 W3C Trace Context의 traceparent 헤더를 먼저 검토하는 편이 낫습니다. 이 헤더 안에 trace-id가 들어 있고, 대부분의 추적 도구가 이 형식을 공통으로 이해하기 때문입니다. 추적 도구를 붙이면 그 trace-id를 그대로 로그의 상관관계 필드로 쓰면 되고, 헤더를 두 벌 관리할 이유가 없어집니다.

추적 도구를 아직 안 쓰는 단계라면 자체 헤더로 시작해도 됩니다. 다만 그 경우에도 "언젠가 trace-id로 갈아탄다"를 전제로, ID를 읽고 쓰는 지점을 한 군데로 모아 두세요. 아래는 그 최소 형태입니다.

// 진입 필터: 승계하거나 새로 만들고, 끝나면 반드시 정리합니다
String cid = req.getHeader("X-Correlation-Id");
if (cid == null || cid.isBlank()) cid = UUID.randomUUID().toString();
MDC.put("correlationId", cid);
try {
    res.setHeader("X-Correlation-Id", cid); // 응답에도 실어 고객 문의 때 바로 추적
    chain.doFilter(req, res);
} finally {
    MDC.remove("correlationId"); // 스레드 재사용 환경에서 필수
}

여기서 흔히 놓치는 것들이 있습니다.

// 비동기 경계: 스냅샷을 떠서 실어 보냅니다
Map<String, String> ctx = MDC.getCopyOfContextMap();
executor.execute(() -> {
    if (ctx != null) MDC.setContextMap(ctx);
    try {
        doWork();
    } finally {
        MDC.clear();
    }
});

주의할 점은 이 코드를 호출부마다 반복해서 쓰면 안 된다는 것입니다. 반드시 실행기를 감싸는 한 지점(스프링이라면 태스크 데코레이터 같은 확장점)에 넣어 두고, 애플리케이션 코드는 아무것도 모르게 만들어야 합니다. 이 규칙이 무너지면 "어떤 비동기 작업은 ID가 붙고 어떤 건 안 붙는" 상태가 되는데, 이 상태가 ID가 아예 없는 것보다 더 위험합니다. 로그가 비어 있으면 사람은 의심하지만, 절반만 채워져 있으면 그 절반을 전부라고 믿기 때문입니다.

응답 헤더나 에러 화면에 이 ID를 노출하는 것도 권합니다. 고객이 "화면에 뜬 코드가 이겁니다"라고 말해 주는 순간, 로그 검색은 몇 초 만에 끝납니다. 노출하는 값은 내부 구조를 드러내지 않는 무의미한 식별자여야 합니다.

ID 하나에서 추적으로 넘어가는 지점

상관관계 ID는 "이 요청의 로그 모아 보기"까지만 해 줍니다. "이 요청이 어느 구간에서 시간을 썼나"는 답하지 못합니다. 서비스가 둘 이상으로 나뉘거나 외부 API 의존이 여럿이 되면 그때 분산 추적으로 넘어갑니다. 다행히 이 전환 비용은 예전보다 낮습니다. OpenTelemetry 계열의 자동 계측을 쓰면 HTTP 서버·클라이언트, JDBC, 메시징처럼 흔한 구간은 애플리케이션 코드 수정 없이 스팬이 생깁니다. 코드에는 도메인적으로 의미 있는 구간만 수동으로 추가하면 됩니다. 스프링 부트 3 계열에서는 마이크로미터 기반 추적 연동이 표준 경로인데, 의존성 이름과 설정 키는 버전에 따라 달라지므로 쓰는 버전의 문서를 확인하는 편이 안전합니다.

구조화 로그: 문장이 아니라 필드로 남깁니다

구조화 로그는 로그 한 줄을 사람이 읽는 문장이 아니라 기계가 읽는 레코드로 남기는 방식입니다. 대개 JSON 한 줄입니다.

{"ts":"...","level":"WARN","logger":"PaymentService",
 "msg":"payment declined","traceId":"...","tenantId":"t-19",
 "orderId":"o-8821","pgCode":"51","elapsedMs":812,"attempt":2}

같은 정보를 "결제 실패: 주문 o-8821, 코드 51, 812ms"로 남겨도 사람은 읽습니다. 차이는 그 다음입니다. 구조화되어 있으면 "지난 한 시간 동안 pgCode 51인 실패를 테넌트별로 집계"가 질의 한 줄이지만, 평문이면 정규식을 새로 짜야 하고 그 정규식은 누군가 메시지 문구를 다듬는 순간 조용히 깨집니다.

어떤 필드를 넣을 것인가

시각은 UTC로, 정밀도는 밀리초 이상으로

여러 서비스의 로그를 한 화면에 시간순으로 놓고 보는 순간, 타임존이 섞여 있거나 초 단위 정밀도만 있으면 인과관계를 거꾸로 읽게 됩니다. "A가 실패해서 B가 실패했다"와 "B가 먼저 죽었다"를 구분하려면 밀리초 단위가 필요합니다. 저장은 UTC로 하고 화면에서만 지역 시간으로 바꾸는 편이 안전하며, 호스트 시계 동기화가 깨져 있지 않은지도 한 번은 확인해야 합니다. 이건 나중에 고쳐도 과거 로그의 시각은 여전히 못 믿습니다.

지키면 좋은 규칙 몇 가지

무엇을 지표로 볼 것인가

대시보드를 채우려 들면 끝이 없습니다. 시작은 사용자 체감에 직결되는 것으로 좁히는 편이 낫습니다. 요청을 처리하는 서비스라면 세 가지로 충분합니다. 요청량, 에러율, 지연 시간 분포입니다. 여기에 자원 쪽에서 포화도(스레드 풀·커넥션 풀·큐 적체) 하나를 더하면 초기 운영은 거의 커버됩니다.

평균 지연 시간은 보지 마세요

지연 시간에서 평균은 거의 항상 거짓말을 합니다. 대다수 요청이 빠르면 소수의 치명적으로 느린 요청은 평균에 묻힙니다. 그런데 장애를 인지하고 이탈하는 사람은 정확히 그 소수입니다. 처음부터 분위수(p95, p99)로 볼 수 있도록 히스토그램 형태로 수집하세요. 이것도 사후 전환이 번거로운 항목입니다. 평균만 저장해 온 시계열에서는 과거 구간의 분위수를 되살릴 수 없습니다. 버킷 경계는 나중에 바꾸면 과거와 비교가 어려워지므로, 서비스의 목표 응답 시간 주변을 촘촘하게 잡아 두는 편이 좋습니다.

알람은 원인이 아니라 증상에 겁니다

"CPU 80% 초과"류의 알람은 사용자가 아무 불편이 없을 때도 울리고, 사용자가 죽어 갈 때도 조용합니다. 알람은 "사용자가 겪는 실패율", "사용자가 겪는 지연"에 걸고, CPU나 큐 길이는 원인 규명용 대시보드에 둡니다. 임계값을 정하기 어렵다면 "이 값이 이 정도로 나빠지면 우리가 새벽에 일어날 것인가"를 기준으로 잡으면 대체로 맞습니다. 일어나지 않을 값이면 그건 알람이 아니라 리포트입니다. 그리고 순간 스파이크마다 울리지 않도록 일정 시간 지속될 때만 울리게 하는 조건은 처음부터 넣으세요.

지표에 고카디널리티 라벨을 붙이지 마세요

사용자 ID, 주문 번호, 원본 URL 경로 같은 값을 지표 라벨로 넣으면 시계열이 폭발합니다. 이건 비용 문제이기도 하지만 그전에 저장소를 죽이는 문제입니다. 경로는 /orders/8821이 아니라 /orders/{id}로 정규화해서 넣습니다. 개별 식별자는 로그와 추적의 몫입니다. 반대로 카디널리티가 낮으면서 판단에 결정적인 라벨은 반드시 넣으세요. 배포 버전, 인스턴스, 엔드포인트, 응답 코드 계열 정도가 그렇습니다.

로그 비용은 설계 문제입니다

관측을 미루는 진짜 이유가 비용인 경우가 많습니다. 실제로 관리형 로그 수집 도구 비용은 트래픽이 늘면 가파르게 커집니다. 다만 그 비용은 대부분 이 아니라 무분별함에서 옵니다. 로그 한 줄의 비용은 생성만이 아니라 전송·색인·보관까지 합친 값이라는 점을 기억하면 판단이 쉬워집니다. 처음부터 다음 장치를 넣어 두면 통제 가능한 범위에 머무릅니다.

수단내용주의점
보존 기간 계층화최근 며칠은 즉시 검색, 그 이후는 저비용 저장소로 이동규제상 보존 의무가 있는 감사 로그는 별도 경로로 분리
추적 샘플링정상 요청은 낮은 비율로, 에러·초과 지연 요청은 되도록 전량 보관아래 설명 참조. 방식에 따라 가능 여부가 갈림
레벨 동적 조정기본 INFO, 조사 중일 때만 특정 패키지를 DEBUG로재배포 없이 바꿀 수 있어야 의미가 있음
반복 로그 억제같은 사건이 초당 수천 건이면 요약해서 한 줄억제됐다는 사실과 억제된 건수는 남겨야 함
집계로 대체"건마다 한 줄" 대신 카운터 지표로개별 사건을 되짚어야 하는 로그는 대체 불가

샘플링에서 자주 틀리는 지점

"에러 난 요청은 전부 저장한다"는 말은 생각보다 단순하지 않습니다. 요청 시작 시점에 샘플링 여부를 정하는 방식(헤드 샘플링)에서는 그 요청이 나중에 실패할지 알 수 없기 때문입니다. 이 방식은 결정을 요청 단위로 한 번 내리고 전파해야 트레이스가 조각나지 않는다는 장점이 있지만, "실패한 것만 남기기"는 원리적으로 불가능합니다. 트레이스가 끝난 뒤에 판단하려면 수집기 단에서 스팬을 일정 시간 모아 두었다가 결정하는 방식이 필요하고, 그만큼 수집기의 메모리와 운영 부담이 생깁니다. 초기에는 낮은 비율의 헤드 샘플링 + 에러는 로그와 지표로 전량 확보가 현실적인 절충이고, 트레이스가 진짜 부족해질 때 다음 단계를 검토하는 편이 낫습니다.

가장 효과가 큰 것은 의외로 단순합니다. 루프 안의 로그와 정상 경로의 DEBUG 로그를 걷어내는 것. 대부분의 서비스에서 로그 물량의 큰 부분은 아무도 읽지 않는 정상 흐름 기록입니다. 정상 흐름은 지표로 세고, 로그는 "예외적인 일"에 집중시키면 양이 눈에 띄게 줄어듭니다.

그리고 비용을 감시 대상으로 만드세요. 서비스별·환경별 로그 발생량을 지표로 보면, 어느 날 누군가 넣은 로그 한 줄이 물량을 몇 배로 늘렸을 때 청구서가 아니라 그래프로 먼저 알게 됩니다.

실제 도입 순서

한 번에 전부 하려 들면 시작을 못 합니다. 아래 순서는 앞 단계가 뒤 단계 없이도 단독으로 값어치를 한다는 점에서 안전합니다.

  1. 상관관계 ID 전파. 진입 필터, MDC 주입, 로그 패턴 반영, 아웃바운드 헤더 전파, 비동기 경계 래핑. 응답 헤더에도 노출합니다.
  2. 로그를 JSON으로. 서비스명·인스턴스·배포 버전·추적 ID를 공통 필드로 자동 부착합니다. 로컬 개발용으로는 사람이 읽기 좋은 포맷을 유지해도 됩니다.
  3. 핵심 지표 네 개. 요청량, 에러율, 지연 분위수, 포화도. 이 단계에서 알람은 두세 개만 겁니다.
  4. 헬스체크와 준비 상태 분리. "프로세스가 살아 있음"과 "트래픽을 받을 준비가 됨"은 다른 개념이고, 이걸 하나로 합치면 배포·재기동 중에 오히려 장애의 원인이 됩니다.
  5. 분산 추적. 서비스 경계가 둘 이상이 되는 시점에 자동 계측부터 켭니다. 수동 스팬은 도메인 구간에만 최소로 넣습니다.
  6. 업무 사건 로그 정리. 주문 생성, 결제 승인, 정산 확정처럼 "나중에 반드시 되짚어야 하는" 사건에 표준 필드를 부여합니다. 이 부류는 디버그 로그가 아니라 사실상 기록이므로 보존 정책도 따로 잡습니다.
  7. 비용 통제. 보존 정책, 샘플링 비율, 로그량 지표와 임계 알람.

새 코드에 적용할 최소 체크리스트

장애를 겪은 뒤 반드시 할 한 가지

회고에서 "왜 발생했나"만 묻고 끝내면 관측은 영원히 제자리입니다. 한 항목을 더 넣으세요. "원인을 찾는 데 걸린 시간 중, 데이터가 없어서 지연된 부분은 어디였나." 그 답이 곧 다음에 추가할 필드나 지표의 목록입니다. 이 방식이 좋은 이유는 추측으로 계측을 늘리지 않기 때문입니다. 실제로 아쉬웠던 것만 붙으니 대시보드도 알람도 비대해지지 않습니다.

언제는 하지 말아야 하는가

여기까지 읽고 "그럼 전부 다 깔자"로 가면 곤란합니다. 관측 장치도 유지보수 대상이고, 과하면 시스템보다 관측이 더 복잡해집니다. 다음 경우에는 미루거나 아예 하지 않는 편이 낫습니다.

단일 프로세스, 단일 인스턴스에 분산 추적

서비스가 하나이고 인스턴스도 하나라면 추적의 가치는 크지 않습니다. 스택 트레이스와 프로파일러로 대부분 해결됩니다. 상관관계 ID와 구조화 로그, 지연 분위수 정도만 챙기고 추적은 서비스가 쪼개지거나 외부 의존이 여러 개로 늘어날 때 도입하세요.

수명이 정해진 것

내부용 일회성 배치, 마이그레이션 스크립트, 검증용 프로토타입은 대상이 아닙니다. 다만 "프로토타입이라 관측을 뺐는데 그대로 운영에 올라간" 사례가 흔하다는 점은 기억해야 합니다. 운영에 올리기로 결정하는 순간이 관측을 붙이는 시점입니다.

안 볼 대시보드 만들기

패널 수십 개짜리 대시보드는 만들 때만 뿌듯합니다. 아무도 기준선을 모르면 어떤 그래프가 이상한지도 판단할 수 없습니다. 화면 하나에 들어오는 개수로 시작해서, 실제 장애를 겪으며 "그때 이게 있었으면 좋았겠다" 싶은 것만 추가하세요.

알람의 무한 증식

사람이 대응할 수 없는 알람은 알람이 아니라 소음입니다. 소음이 쌓이면 진짜 알람도 무시하게 됩니다. 새 알람을 만들 때 "이게 울리면 무엇을 할 것인가"에 답하지 못하면 만들지 마세요. 답이 "일단 본다"라면 그건 대시보드 항목입니다. 그리고 한 달에 한 번은 울린 알람 목록을 보고, 아무 조치도 하지 않은 알람은 지우거나 조건을 고치세요.

수집 도구부터 고르는 것

관측 도입을 "어떤 제품을 살 것인가"로 시작하면 대개 실패합니다. 도구는 데이터가 있어야 값어치가 있습니다. 상관관계 ID와 구조화 로그는 어떤 도구를 쓰든 필요하고, 표준 계측을 쓰면 나중에 도구를 바꿀 때 애플리케이션 코드를 거의 건드리지 않아도 됩니다. 순서는 계측이 먼저, 저장소 선택이 나중입니다.

수동 스팬과 로그로 도메인 코드를 덮는 것

모든 메서드에 스팬을 열고 진입·이탈 로그를 찍는 코드는 관측이 아니라 잡음입니다. 자동 계측이 이미 잡아 주는 구간(HTTP, DB, 메시징)을 수동으로 다시 감싸면 스팬만 늘고 화면은 읽을 수 없게 됩니다. 수동 계측은 "자동 계측이 못 보는 도메인 단위 작업"에만 넣으세요. 판단 기준은 간단합니다. 그 구간이 느릴 때 우리가 할 조치가 따로 있는가. 없으면 넣지 않습니다.

규제·개인정보 영역의 페이로드 전량 로깅

디버깅에 편하다는 이유로 요청·응답 본문을 통째로 남기는 설정은, 개인정보나 인증 정보를 다루는 경로에서는 켜지 마세요. 로그 저장소는 복제와 백업이 일어나고 접근 권한도 넓은 경우가 많아, 애플리케이션에서 아무리 잘 통제해도 그 통제가 로그까지 이어지지 않습니다. 이런 경로에서는 본문 대신 구조와 크기와 검증 실패 사유만 남기는 편이 낫습니다. 한 번 남긴 민감 데이터는 사후에 지우기가 매우 어렵습니다.

기존 시스템 전체를 한 번에 개조하는 것

이미 몇 년 굴러간 시스템이라면 전면 개조는 대개 중간에 멈춥니다. 대신 가장 자주 장애가 나는 흐름 하나를 골라 그 경로만 끝까지 계측하세요. 진입점부터 외부 호출까지 한 줄기가 완성되면 효과가 즉시 체감되고, 그 패턴을 옆 흐름으로 복제하는 편이 훨씬 안전합니다. 전면 전환은 그렇게 몇 줄기가 쌓인 뒤에 판단해도 늦지 않습니다.

정리

관측 장치를 나중에 붙이기 어려운 이유는 기술적으로 복잡해서가 아닙니다. 지나간 시간은 되돌릴 수 없고, 맥락은 경계를 넘으며 사라지고, 형식은 굳으면 바꾸기 어렵고, 안 보이는 시스템은 안 보이는 모양으로 자라기 때문입니다. 네 가지 모두 시간이 갈수록 비용이 커지는 종류의 문제입니다.

반대로 초기 비용은 놀랄 만큼 쌉니다. 상관관계 ID 전파와 JSON 로그 설정은 프로젝트 초기라면 설정 파일 몇 개와 필터 하나, 실행기 래퍼 하나로 끝나는 작업이고, 그 뒤로는 개발자가 의식하지 않아도 계속 작동합니다. 다음 프로젝트를 시작한다면, 첫 커밋에 로깅 설정과 상관관계 필터를 함께 넣어 두시길 권합니다. 그 판단의 값어치는 첫 장애가 났을 때 한 번에 회수됩니다.

같은 주제의 다른 글

맘소프트는 19년 넘게 금융 · 엔터프라이즈 · 모바일 시스템을 만들어 왔습니다. 여기 적는 글은 그 과정에서 실제로 부딪히고 해결한 것들입니다.

기술 판단이 필요하신가요

맘소프트는 소프트웨어 개발과 CTO 대행 · 기술 자문을 제공합니다. 편하게 문의해 주세요.

[email protected]