OpenClaw 게이트웨이가 여러 모델과 도구 엔드포인트로 동시에 트래픽을 펼치면 “느리다”는 문의만 쌓이고 어디에 증거를 붙여야 할지 합의가 안 납니다. 이 글에서는 요청 범위 식별자 발급, W3C traceparent 전파, 도구 호출마다 한 줄짜리 JSON, 그리고 이미 정리한 OpenClaw용 Prometheus 스크랩 설계와 메트릭 파이프라인을 맞추는 방법을 한데 묶습니다. 읽기 정체 해석은 읽기 타임아웃·교착 진단 과 같은 운영 선상에서 같이 봐야 pager에서 JSON 라인까지 한 줄로 이어집니다.
목표는 간단합니다. 운영자가 request_id 하나만 검색창에 넣어도 도구 체인·상류 상태·큐 깊이 스냅샷·스팬 순서가 복구되어 사용자가 본 지연을 워크로드를 다시 돌리지 않고도 설명할 수 있게 하는 것입니다. 숫자 가드레일로는 UUIDv4 엔트로피, 지연은 90~95 백분위에 두는 SLO 사고방식, 리허설 예산은 하루 약 16.9달러 전후의 Apple 실리콘 Mac mini 대여가 현실적입니다.
request_id, trace_id, span_id 역할
층이 섞이면 장애 대응이 무너집니다. request_id는 사용자에게 보이는 티켓 번호처럼 인바운드 HTTP·WebSocket 세션당 하나입니다. 에지에서 UUIDv4(무작위 122비트)를 만들거나 신뢰 가능한 경로의 X-Request-ID를 채택합니다. 클라이언트가 보낸 식별자는 길이를 검증하고 ASCII 128자 초과는 거부해 로그 인젝션을 막습니다.
W3C 트레이스 컨텍스트는 서비스 간 이음새입니다. trace-id는 워크플로 전체에서 불변이고 자식 스팬은 새 span-id를 만들며 trace-id를 복사합니다. 게이트웨이 프로세스 안에서는 MCP 호출마다 가벼운 tool_span_id를 두면 비동기 완료 시에도 표준 출력이 뒤섞여도 정렬 가능한 순서가 남습니다.
| 식별자 | 범위 | 카디널리티 주의 |
|---|---|---|
request_id | 단일 인바운드 대화 | 높음. 원시 UUID를 Prometheus 라벨로 쓰지 않음 |
trace_id | 분산 그래프 전체 | 로그에는 중간. 라벨 남용 금지 |
tool.name + 결과 | 집계 | 낮음. RED 메트릭에 적합 |
헤더, 프록시, 충돌 규칙
TLS 종료는 리버스 프록시에서 하고 없으면 X-Request-ID를 주입합니다. traceparent는 OpenTelemetry를 이해하는 상류 LLM 게이트웨이로 그대로 넘기고 클라이언트가 중복 헤더를 보내면 하나를 제거해 충돌을 피합니다. CDN 뒤에 둘 때는 스트리밍 응답에 에지 최소 유휴 120초 같은 여유를 주되 게이트웨이 유휴는 더 짧게 두면 CDN이 멈췄는지 공급자가 멈췄는지 로그로 갈립니다.
WebSocket은 첫 서버 프레임에 request_id를 에코해 재연결 폭주 때 스팬이 고아가 되지 않게 합니다.
게이트웨이와 도구용 구조화 JSON
줄 바꿈 구분 JSON만 사용하고 이벤트는 한 줄에 하나, 예쁘게 출력하지 않으며 UTF-8 BOM 없음. 최소 열은 ts(UTC ISO8601), level, service=openclaw-gateway, host, request_id, trace_id, span_id, event(tool.start/tool.end 등), tool, latency_ms, upstream_status, retry_count입니다.
{
"ts": "2026-04-28T01:17:41.332Z",
"level": "info",
"service": "openclaw-gateway",
"request_id": "f6c2...9aa1",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"span_id": "00f067aa0ba902b7",
"event": "tool.end",
"tool": "filesystem.read",
"latency_ms": 184,
"upstream_status": 200,
"arg_fingerprint": "sha256:7c2a...",
"retry_count": 0
}
도구 인자는 SHA-256 지문으로만 남기고 비밀은 기본 인덱스에서 빼낸 봉투 필드로 보냅니다. schema_rev 정수를 같이 두면 리플레이 작업이 조용한 스키마 드리프트를 잡기 쉽습니다.
로그와 Prometheus 히스토그램 결합
히스토그램은 분위수를 요약합니다. 라벨은 tool, model_class, region처럼 저카디널리티로 유지합니다. 원시 request_id를 라벨에 넣으면 시계열이 폭발하므로 스택이 exemplar를 지원하면 거기에 깊은 링크를 달고 아니면 로그 배송 메타데이터에 해시를 붙여 Loki류에서 histogram_quantile(0.95,...) 스파이크에서 JSON 줄로 내려갑니다.
스크랩 15초·로그 플러시 50ms 같은 리듬을 맞추면 짧은 사건도 세 번의 스크랩 안에 카운터가 드러나고 exemplar가 한 테이블 늦어도 조사선이 끊기지 않습니다.
느린 도구 호출의 종단 간 추적
벽시계 2500ms를 넘는데 CPU가 놀면 스팬에 시스템콜 경계 훅에서 모은 wait_reason(tcp_connect, tls_handshake, provider_queue, disk_io 등)을 붙입니다. 서킷 브레이커 상태와 대조하면 백오프가 방어 로직인지 실제 포화인지 갈립니다.
스트리밍 완성에는 부분 토큰에 단조 증가 chunk_seq를 찍어 중단 뒤에도 사후 재생이 결정적으로 정렬됩니다.
LaunchAgent, 플러시, 회전과 순서
macOS launchd는 Linux journald와 표준 출력 처리가 다릅니다. 중요 이벤트는 명시적으로 플러시하거나 배치가 안전한 구조화 시퍼에 맡깁니다. newsyslog나 Vector 계열은 야간 회전 뒤에도 request_id가 끊기지 않게 오프셋을 확인한 뒤 압축합니다. 클라우드 Apple Silicon Mac mini에서 순서 어긋남을 먼저 찾는 편이 Linux 컨테이너만 쓰는 CI보다 현실적입니다.
프로덕션 전 체크리스트
- 잘못된 트레이스 헤더는 실행 가능한 JSON 오류와 함께
400으로 거절합니다. - 프로세스 시작 이벤트에
gateway.version과git_sha를 한 번만 기록합니다. - 핫 쿼리를 늦추지 않으려면 14일 뒤 구조화 로그는 콜드 계층으로 넘깁니다.
- 샘플된 트레이스의 최소 99%가 히스토그램 버킷과 맞물리는지 대시보드로 감사합니다.
- OpenClaw 워크스페이스 정책 옆에 마스킹 목록을 문서화합니다.
샘플링, 저장 예산, 사건 재생
수다스러운 부하는 도구 호출마다 풀 트레이스를 켜면 분당 25MB를 넘길 수 있습니다. 게이트웨이에서 헤드 기반 샘플링을 쓰고 오류 경로는 100%, 평시 성공은 5~10%, 최근 5분 오류 예산이 0.5%를 넘으면 자동으로 50%까지 올리는 계단이 현실적입니다. 샘플링 결정에도 같은 request_id를 실어야 하류 수집기가 반쪽 트레이스를 안 남깁니다.
콜드 스토리지는 규제 고객을 위해 400일을 기준으로 잡되 본문은 지우고 지문과 지연만 남기는 민감도별 계층을 둡니다. 재생 시 ts와 chunk_seq로 정렬하고 서킷 브레이커 전환·큐 깊이를 겹치면 완화가 한 스크랩 주기 안에 먹혔는지 읽을 수 있습니다. 주간으로 샌드박스 도구에 250ms 인공 지연을 넣어 같은 상관 키로 알림에서 JSON 줄까지 3분 안에 내려오는지 훈련하세요. 공유 게이트웨이에서는 테넌트 라벨과 워크스페이스 ID 매핑을 문서화해 트레이스 형식이 같아도 권한 경계를 넘는 조회가 없게 합니다.
JSONL·UTC·request_id 삼각대는 두 엔지니어가 정렬된 트레이스를 나란히 비교할 수 있는 재현성을 주고 벤더 바이너리 캡처에 덜 묶입니다. Apple Silicon Mac mini는 JSON 직렬화 부하가 있는 미들웨어를 조용히 받쳐 주고 MacHTML 클라우드는 launchd 의미까지 포함해 리허설할 수 있으며 하루 약 16.9달러 탄력 요금으로 피크 검증과 상시 관측을 바꿔 끼우기 좋습니다.
다음 장애 훈련 전에 상관 추적을 끝까지 연결하세요
Apple Silicon Mac mini를 빌려 LaunchAgent 로그·게이트웨이 업그레이드·트레이스 대시보드를 프로덕션에 가까운 신호로 연습합니다. 요금은 하루 약 $16.9부터.