OpenClaw 에이전트 실행 이력, 세 레이어로 분리해 인시던트마다 어느 로그부터 열지 판단하기
에이전트 파이프라인을 프로덕션에 올리고 나서 가장 먼저 맞닥뜨리는 문제가 있습니다. 뭔가 잘못 돌아갔는데, 정확히 어떤 추론 경로에서 어떤 툴을 왜 호출했는지 알 수가 없습니다. 로그를 뒤지면 인프라 이벤트는 넘쳐나는데 에이전트 내부는 블랙박스처럼 느껴지죠.
OpenClaw는 에이전트 실행 이력을 서로 성격이 다른 세 개의 레이어로 기록합니다. 추론 체인 전체를 직렬화하는 JSONL 세션 트랜스크립트, 모든 툴 콜을 해시 체인으로 연결하는 ShieldEvent 감사 로그, 그리고 개인정보 없이 메타데이터만 담는 Gateway 감사 원장입니다. 이 세 레이어를 각각 어떤 상황에서 열어야 하는지 이해하면 인시던트 사후 분석, 재현 시도, 규정 준수 감사까지 하나의 관찰성 체계 안에서 정리됩니다.
2026년 기준으로는 여기에 내장 OpenTelemetry 지원까지 더해져서 기존 Prometheus·Grafana 인프라에 에이전트 트레이스를 그대로 편입시키는 것도 가능해졌습니다. 이 글에서는 세 레이어의 구조를 파악하고, 실제 시나리오별로 어떻게 조합해 쓰는지, 그리고 놓치기 쉬운 함정까지 같이 살펴보겠습니다.
세 레이어의 역할 분리
1차 레이어: JSONL 세션 트랜스크립트
세션 트랜스크립트는 ~/.openclaw/workspace/[job-name]/logs/ 경로에 저장되는 JSONL 파일입니다. 각 라인이 독립적인 JSON 객체라서 jq나 표준 파서로 라인 단위 스트리밍 처리가 가능합니다.
한 라인의 구조를 보면 이렇습니다.
{
"timestamp": "2026-09-13T04:21:07.312Z",
"role": "assistant",
"content": "파일 목록을 확인한 뒤 빌드 스크립트를 실행하겠습니다.",
"tool_call_name": "bash",
"tool_call_arguments": { "command": "ls -la ./dist" },
"tool_result": "total 48\ndrwxr-xr-x ...",
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
"spanId": "00f067aa0ba902b7",
"parentSpanId": "00f067aa0ba902b6",
"traceFlags": "01"
}2026년 기준 릴리스부터는 진단 트레이스 컨텍스트가 유효한 라인에 traceId, spanId, parentSpanId, traceFlags가 최상위 키로 붙습니다. 이 덕분에 로컬 파일 로그와 OTEL 스팬을 traceId 하나로 조인할 수 있어서 분산 추적과 로컬 디버깅을 같은 맥락에서 볼 수 있습니다. 단, 트레이스 컨텍스트가 생성된 라인에만 키가 붙는다는 점은 조인 쿼리를 짤 때 염두에 두어야 합니다.
디버그 레벨은 error → warn → info(기본) → debug → trace 순으로 제어할 수 있습니다. 프로덕션에서는 info로 두고, 문제가 터졌을 때만 debug나 trace로 올려서 상세 추론 경로를 캡처하는 패턴이 일반적입니다.
2차 레이어: ShieldEvent 해시 체인
ShieldEvent는 모든 툴 콜을 툴 이름, 세션 ID, 정책 결정(allow/deny), 그리고 이전 레코드와의 해시 체인 링크와 함께 버전이 붙은 레코드로 기록합니다. before_tool_call, tool_result_persist, before_model_resolve, before_prompt_build 등 여러 라이프사이클 훅이 자동으로 등록되며, 전체 목록은 공식 문서의 훅 레퍼런스에서 확인하는 게 정확합니다.
해시 체인 구조 덕분에 중간 레코드가 변조됐는지 탐지가 가능합니다. 규정 준수 감사에서 "이 시점에 정말 이 정책 결정이 있었는가"를 증명해야 할 때 이 tamper-evident 체인이 핵심 근거가 됩니다.
세션 트랜스크립트 기록과 ShieldEvent 해시 체인 링크는 툴 실행 이후 순차적으로 발화되며, 두 경로가 병렬로 갈라지는 것이 아니라 하나의 라이프사이클 안에서 순서대로 이어진다는 점이 다이어그램의 핵심입니다.
3차 레이어: Gateway 감사 원장
Gateway 레벨에는 세 번째 레이어가 있습니다. 공유 상태 DB에 에이전트 실행 메타데이터(identity, timing, tool name, normalized outcome)만 기록하는 원장으로, ShieldEvent가 세션별로 남긴 흔적을 조직 단위로 집계해서 보는 업스트림 뷰에 가깝습니다. 프롬프트 본문이나 툴 인수 원문은 저장하지 않습니다.
이 설계가 처음엔 제약처럼 느껴졌는데, 오히려 실무에서 장점이 됩니다. 개인정보 규제를 준수하면서도 집계 감사는 가능한 구조이기 때문입니다. 다만 원장 레코드의 보존 기간과 행 상한은 환경 설정에 따라 달라지므로, 장기 감사가 필요한 조직은 배포 시점의 Gateway config-observability 문서에서 기본값을 확인하고 외부 스토리지로 주기적으로 내보내는 파이프라인을 별도로 구성하는 편이 안전합니다.
⚠️ 시크릿 마스킹은 best-effort입니다. 세 레이어 모두 디스크 기록 전에 자동 마스킹이 적용되지만, 이는 알려진 패턴에 기반한 best-effort 처리입니다. 바이너리 페이로드, 커스텀 인코딩, 비표준 식별자 형식은 마스킹이 보장되지 않습니다. 로그를 외부 시스템으로 내보내거나 티켓에 붙일 때는 반드시 별도 스크러빙 파이프라인을 한 겹 더 두는 것을 권장합니다.
시나리오별 활용법
시나리오 1: 프로덕션 인시던트 사후 분석
에이전트가 예상치 못한 툴을 호출했다는 알림이 올 때, ShieldEvent 로그에서 session_id로 해당 세션의 정책 결정 순서를 재구성하고, 같은 session_id로 세션 트랜스크립트를 조인해서 모델의 추론 경로까지 추적합니다.
# ShieldEvent 로그에서 특정 세션의 deny 이벤트 추출
jq 'select(.session_id == "sess_abc123" and .policy_decision == "deny")' \
~/.openclaw/workspace/my-agent/logs/shield_events.jsonl
# 세션 트랜스크립트에서 해당 시점의 추론 체인 확인
jq 'select(.timestamp >= "2026-09-13T04:00:00Z" and .role == "assistant")' \
~/.openclaw/agents/main/sessions/sess_abc123.jsonl# traceId로 분산 트레이스와 로컬 로그를 한 번에 조회
TRACE_ID="4bf92f3577b34da6a3ce929d0e0e4736"
jq --arg tid "$TRACE_ID" 'select(.traceId == $tid)' \
~/.openclaw/agents/main/sessions/sess_abc123.jsonl시나리오 2: 문제 직전 상태로 되돌리는 재현 워크플로우
먼저 짚어둘 게 있습니다. 커뮤니티에서 오래 요청받고 있는 /session save|load 명령어(공식 이슈 #13700)는 아직 공식 기능이 아닙니다. 컨텍스트 토큰 수·모델·컴팩션 상태를 함께 체크포인트로 잡는 완전한 스냅샷 기능은 로드맵에 있고, 정식으로 들어오면 다른 모델로 A/B 테스트를 붙이는 것도 매끄러워질 예정입니다.
그럼 지금 당장은 뭘 할 수 있느냐. 세션 트랜스크립트 JSONL 파일 자체를 이용하는 우회 경로가 있습니다. ~/.openclaw/agents/main/sessions/<sessionId>.jsonl 파일을 그대로 로드해서 문제 발생 직전 상태부터 대화를 재시작하는 방식입니다. 컨텍스트 완전 복원이 아니라 "메시지 이력 기반 재시작"에 가까워서, 컴팩션 시점이 끼어 있는 세션은 100% 재현이 안 될 수 있다는 한계가 있습니다.
세션이 손상됐거나 불일치 상태에 빠진 경우에는 openclaw doctor 계열 진단 서브커맨드로 상태를 점검하고 복구할 수 있습니다(구체적인 서브커맨드는 배포 버전의 CLI --help 출력에서 확인하는 것을 권장합니다 — 개념적 예시).
시나리오 3: OpenTelemetry로 Grafana 대시보드 연결
2026년 기준 릴리스부터 내장된 OpenTelemetry 지원을 활성화하려면 diagnostics.otel 설정을 추가하면 됩니다. OpenTelemetry GenAI Semantic Conventions를 준수하며, gen_ai.input.messages, gen_ai.output.messages 같은 이벤트 키를 지원합니다(그 외 콘텐츠 키의 안정성 여부는 스펙 페이지의 stability 표기를 그대로 참고하는 편이 안전합니다).
// openclaw.json (개념적 구성 예시)
{
"diagnostics": {
"otel": {
"enabled": true,
"endpoint": "http://localhost:4318",
"protocol": "http/protobuf",
"content_keys": ["gen_ai.input.messages", "gen_ai.output.messages"]
}
}
}diagnostics-otel 플러그인으로 내보낸 데이터는 Grafana Labs 공개 대시보드(ID: 25067)에서 바로 시각화할 수 있습니다. 토큰 수, 레이턴시 히스토그램, 활성 대화 게이지, 에러 카운터를 실시간으로 확인할 수 있습니다.
주의: 고볼륨 파이프라인에서 전체 콘텐츠 키를 활성화하면 토큰·페이로드 크기로 인해 트레이스 스토리지 비용이 급증할 수 있습니다. 처음엔 메타데이터 키만 켜고, 실제로 필요한 콘텐츠 키를 선택적으로 추가하는 방식이 현실적입니다.
시나리오 4: 규정 준수 감사 스트림 구성
Gateway 감사 원장을 외부 SIEM이나 별도 스트림으로 내보내면 툴 실행 패턴을 집계할 수 있습니다. 메시지 본문 없이 메타데이터만 저장하는 설계가 GDPR 같은 개인정보 규제를 준수하면서 감사 요건을 동시에 충족하는 구조입니다.
# Gateway 감사 원장 내보내기 (개념적 예시 — 실제 CLI는 배포 버전에서 확인)
openclaw audit export \
--format jsonl \
--since 2026-08-01 \
--output ./audit_export_2026_08.jsonl
# jq로 툴 실행 패턴 집계
jq -r '.tool_name' audit_export_2026_08.jsonl | sort | uniq -c | sort -rn트레이드오프와 흔히 빠지는 함정
| 항목 | 장점 | 주의사항 |
|---|---|---|
| JSONL 세션 트랜스크립트 | jq로 즉시 분석 가능, 추론 체인 전체 보존 |
~/.openclaw/agents/main/sessions/에 무기한 누적 (이슈 #25373) |
| ShieldEvent 해시 체인 | 변조 탐지 가능한 증거 체인 형성 | 심층 디버깅엔 세션 트랜스크립트 병행 필수 |
| Gateway 감사 원장 | 개인정보 규제 준수, 메타데이터 집계 | 보존 기간·행 상한은 환경 설정 의존, 외부 적재 파이프라인 필요 |
| OTEL 통합 | 기존 관찰성 인프라에 별도 에이전트 없이 편입 | 전체 콘텐츠 키 활성화 시 스토리지 비용 급증 위험 |
| traceId 조인 | 분산 추적·로컬 로그 동일 컨텍스트 분석 | 진단 트레이스가 활성화된 라인에만 키가 붙음 |
놓치기 쉬운 버그가 하나 있습니다. openclaw.json이 재작성될 때 agent:main:main 포인터가 뒤집히면서 세션 히스토리가 소실되는 케이스(이슈 #74640)가 알려져 있습니다. 설정 파일을 수정할 때는 세션 트랜스크립트를 미리 백업해두는 습관이 필요합니다.
훅 API 변경도 체크할 필요가 있습니다. 2026년 중반 릴리스 사이클에서 before_model_resolve, before_prompt_build 훅이 추가됐고 before_agent_start가 deprecated 처리됐습니다(정확한 릴리스 번호는 공식 changelog에서 확인). 관찰성 플러그인 최신 라인은 새 훅을 타겟으로 하므로, 기존 플러그인을 업그레이드하거나 마이그레이션이 필요할 수 있습니다.
인시던트가 터졌을 때 어느 레이어부터 열어야 할까
세 레이어의 정보 범위가 다르다는 걸 이해했다면, 실제 상황에서는 "무엇을 알고 싶은가"에 따라 순서를 잡는 게 가장 빠릅니다. 정리하면 이런 식의 판단 흐름이 됩니다.
세션 트랜스크립트가 무기한 누적되는 이슈, 시크릿 마스킹의 best-effort 한계, openclaw.json 재작성 시 히스토리 소실 버그는 실제 인시던트 대응 과정에서 발이 걸리기 쉬운 지점이므로 파이프라인 설계 단계에 미리 반영해두면 좋습니다. /session save|load가 정식 기능으로 들어오기 전까지는 트랜스크립트 파일을 백업·로드하는 우회 경로로 재현 워크플로우를 유지하고, OTEL은 콘텐츠 키를 선택적으로 열어가면서 비용 곡선을 관찰하는 것이 현실적인 출발점이 됩니다.
참고 자료
- Logging · OpenClaw 공식 문서
- Gateway Logging · OpenClaw 공식 문서
- Audit Records · OpenClaw 공식 문서
- Session Management Deep Dive · OpenClaw 공식 문서
- Agent Harness Sessions and Results · OpenClaw 공식 문서
- Session State Awareness · OpenClaw 공식 문서
- Configuration — audit, logging, diagnostics, and telemetry · OpenClaw
- OpenTelemetry GenAI Semantic Conventions
- OpenClaw Tool Call Audit Log: How to Capture Every Agent Action – Zedly AI Blog
- OpenClaw Immutable Audit Log: Build a Tamper-Evident Event Chain – Zedly AI Blog
- OpenClaw Logging and Debugging: Troubleshoot Agent Behavior | SFAI Labs
- Openclaw Audit Logging: Compliance and Monitoring Configuration | SFAI Labs
- OpenClaw Logging Best Practices: Keep It Clear – ClawGo
- Instrument Your OpenClaw Agent with OpenTelemetry – LangWatch
- Tracing OpenClaw with OpenTelemetry and Orq.ai
- OpenClaw OTel Observability Dashboard – Grafana Labs
- OpenClaw Observability Plugin (henrikrexed) – GitHub
- GitHub Issue #25373: orphan transcript .jsonl files accumulate
- GitHub PR #84708: fix(agents): recover message-tool mirror replay poison
- GitHub Issue #13700: Session snapshots — save and load context checkpoints