4장. 한 번의 실행을 트레이스로 남긴다
로그 줄이 아니라 인과관계가 필요하다
로그는 “무슨 문장이 출력되었는가”를 보여 준다. 트레이스는 하나의 요청 안에서 입력 검증, 정책 조회, 모델 호출, 도구 호출이 어떤 부모·자식 관계와 시간 순서로 일어났는지 보여 준다. 장애 조사자는 결과 문자열보다 어디서 결정이 갈렸는지를 찾아야 한다.
ClaimOps의 트레이스는 다음 최소 식별자를 가진다.
traceId: 한 실행을 묶는 고유 값claimId: 업무 객체의 비민감 식별자workflow: 실행 흐름 이름model,promptVersion,policyVersion: 재현에 필요한 버전spans: 단계별 이름, 상태, 시간, 공개 가능한 속성usage: 토큰과 추정 비용result: 마스킹된 최종 결과
OpenTelemetry 의미 규약은 서로 다른 라이브러리가 같은 개념에 비슷한 이름을 쓰도록 돕는다. 생성형 AI 속성은 계속 발전하고 일부가 별도 저장소로 이동하고 있으므로 애플리케이션 스키마 버전을 함께 남긴다. 표준 필드가 바뀌어도 과거 데이터를 읽을 수 있어야 한다.
무엇을 스팬으로 만들 것인가
모든 함수에 스팬을 붙이면 잡음과 비용이 늘어난다. 다음 중 하나에 해당할 때 스팬 후보가 된다.
- 다른 서비스나 모델, 데이터 저장소를 호출한다.
- 업무 결과를 바꾸는 정책 분기가 있다.
- 재시도·타임아웃·승인처럼 운영자가 따로 관찰해야 한다.
- 비용 또는 개인정보 위험이 발생한다.
문자열 trim 같은 내부 함수는 대개 스팬이 필요 없다. 반면 환불 도구가 실제 실행되지 않고 준비만 되었다는 사실은 반드시 남겨야 한다.
실습: 트레이스 생성과 읽기
npm run lab:run -- CLM-1001
node lab/cli.mjs trace
출력에서 고객 이름, 이메일, 전화번호는 보이지 않아야 한다. claimops.input.validate, claimops.policy.retrieve, claimops.decision, claimops.tool.refund.prepare 네 스팬이 나타난다. UUID와 시간은 실행마다 달라진다.
높은 카디널리티를 통제한다
고객 ID, 원문 질문, 오류 전문처럼 값의 종류가 거의 무한한 속성을 메트릭 라벨로 사용하면 저장 비용과 쿼리 성능이 급격히 나빠진다. 트레이스 검색용 식별자와 메트릭 집계용 라벨을 분리한다. 메트릭에는 decision, model_family, amount_bucket처럼 제한된 집합을 사용하고, 단일 요청 조사는 traceId로 이동한다.
완료 기준
- 로그와 트레이스의 차이를 설명할 수 있다.
- 네 가지 스팬의 업무 의미를 찾았다.
- 트레이스에서 직접 식별 가능한 개인정보가 제거되었음을 확인했다.