---
title: "Claude Code 세션 옵저버빌리티를 직접 만들어봤음 – Langfuse 셀프호스팅으로"
published: 2026-01-31T22:07:10.000Z
canonical: https://jeff.news/article/762
---
# Claude Code 세션 옵저버빌리티를 직접 만들어봤음 – Langfuse 셀프호스팅으로

Principal AI Architect가 Claude Code 세션 데이터가 날아가는 문제를 해결하기 위해 Langfuse 셀프호스팅 옵저버빌리티 시스템을 구축한 과정. 마크다운 로그의 7가지 한계를 겪고, Docker 6개 서비스 + Stop 훅 + 오프라인 큐로 완전한 트레이싱 파이프라인을 만들었음.

## 왜 필요했나

- Principal AI Architect가 Claude Code를 메인 개발 도구로 쓰면서, 하루 20~50턴의 대화를 여러 프로젝트에서 돌리고 있었음
- 문제는 터미널을 닫는 순간 디버깅 세션, 아키텍처 논의, 프롬프트 노하우 등 모든 맥락이 사라진다는 것
- "어떤 프롬프트가 좋은 결과를 내는지", "Claude가 도구를 어떻게 활용하는지", "생산적인 세션의 구조는 뭔지" 같은 질문에 답할 수 없었음
- 기업 AI 시스템에 옵저버빌리티 구축해주는 게 본업인데, 정작 본인 도구에는 없다는 아이러니를 깨달음

## 첫 시도: 마크다운 로그의 한계

- 처음엔 `log-prompt.py` 훅으로 프롬프트를 마크다운 파일에 append하는 방식을 썼음
- 2주 만에 7가지 문제가 드러남:
  1. 파일이 무한 성장 (수천 줄)
  2. 긴 프롬프트가 500자로 잘림 — 정작 중요한 상세 프롬프트가 손실됨
  3. Claude의 응답은 아예 기록 안 됨 (대화의 절반만 저장)
  4. 마크다운이라 쿼리 불가
  5. 세션 컨텍스트 없음 — 9턴짜리 디버깅이 9개의 단절된 항목으로 보임
  6. "[outcome pending]"이 영원히 pending으로 남음
  7. 프로젝트 간 패턴 분석 불가

## "이건 그냥 LLM 옵저버빌리티잖아"

- 필요한 게 결국 트레이스, 스팬, 세션 그룹핑, 쿼리 가능한 저장소, 크로스 프로젝트 집계라는 걸 깨달음
- Langfuse를 선택한 이유: 셀프호스팅 가능(데이터가 내 머신에 유지), 트레이스/스팬/세션/제너레이션 데이터 모델 내장, 웹 UI 제공, API 쿼리 가능, 오픈소스
- 마침 Langfuse가 ClickHouse와 합류한 타이밍이기도 했음

## 아키텍처와 셋업

- Docker Compose로 6개 서비스 구동: Langfuse, PostgreSQL, ClickHouse, Redis, MinIO, 웹 UI(localhost:3050)
- 메모리 사용량 약 4~6GB, 디스크 이미지 2~5GB + 데이터
- 셋업은 딱 5개 명령어: `git clone` → `generate-env.sh` → `docker compose up -d` → health check → `install-hook.sh`
- `generate-env.sh`가 PostgreSQL, ClickHouse, Redis, MinIO, Langfuse 암호화 키 등 모든 크레덴셜을 자동 생성해줌
- 템플릿 레포 공개됨: `github.com/doneyli/claude-code-langfuse-template`

> [!TIP]
> 코딩 안 할 때는 `docker compose down`으로 내려도 Docker 볼륨에 데이터 유지됨. 리소스 아끼려면 필요할 때만 올리면 됨.

## 훅 동작 원리

- Claude Code의 **Stop 훅**으로 동작 — 모든 어시스턴트 응답 후 자동 실행됨
- `~/.claude/projects/<project>/` 아래 `.jsonl` 트랜스크립트에서 최신 파일을 찾아 파싱
- **증분 처리**: `langfuse_state.json`에 마지막 읽은 라인을 기록해서, 매번 새 메시지만 처리. 수백 턴 후에도 1초 이내로 실행됨
- 메시지를 턴 단위로 그룹핑: 사용자 프롬프트 → 어시스턴트 응답 → 도구 호출을 하나의 트레이스로 묶음
- 각 트레이스에 자식 스팬으로 Read, Write, Edit, Bash, Grep, Glob 등 도구 호출이 전부 기록됨
- 모든 예외는 `sys.exit(0)` 처리 — 훅이 절대로 Claude Code 세션을 블로킹하지 않음

## 오프라인 큐: 데이터 유실 방지

- Langfuse가 다운됐을 때 트레이스가 유실되는 문제를 해결하기 위해 로컬 큐 추가
- 매번 2초 타임아웃 소켓 체크로 Langfuse 상태 확인 (HTTP가 아니라 raw socket — 속도 때문)
- 다운이면 `~/.claude/state/pending_traces.jsonl`에 JSONL로 저장, 각 항목에 `queued_at` 타임스탬프 포함
- 다음에 Langfuse가 살아나면 현재 턴 처리 전에 큐를 자동으로 drain
- 보수적 접근: 큐 전송 중 하나라도 실패하면 중단하고 나머지는 보존. 데이터 손실 없음
- 별도 데몬 대신 "다음 Claude Code 사용 시 자동 drain" 방식을 택함 — 단순함이 답이라는 판단

## 설정 모델과 활용

- 기본은 글로벌 활성화 — 모든 프로젝트가 자동 트레이싱됨
- 특정 프로젝트에서 끄려면 `.claude/settings.local.json`에 `TRACE_TO_LANGFUSE: false` 추가하면 됨
- 반대로 opt-in 모델도 가능: 글로벌 env 제거 후 프로젝트별로 추가

> [!NOTE]
> 사용 포트: 3050(웹), 5433(postgres), 8124(clickhouse), 6379(redis), 9090(minio). 충돌 시 `docker-compose.yml`에서 조정 가능.

## 데이터로 할 수 있는 것들

- 프로젝트별 필터링: 모든 트레이스에 프로젝트명 태그가 붙어서 코드베이스별 분석 가능
- 도구 사용 패턴 분석: Claude가 문제 해결 시 파일 읽기, 검색, 편집을 어떤 순서로 하는지 파악
- 베스트 프롬프트 검색: 입력 텍스트로 트레이스 검색해서 좋은 결과 낸 프롬프트 패턴 재활용
- 세션 리플레이: 멀티턴 디버깅 세션을 시간순으로 전체 재생 가능
- 다음 단계로 Langfuse API를 쿼리해서 "이번 주 가장 복잡한 디버깅 세션", "최고의 아키텍처 프롬프트" 같은 패턴 분석을 자동화할 계획

## 핵심 포인트

- 마크다운 로그 방식의 7가지 한계(무한 성장, 응답 미기록, 쿼리 불가 등)를 겪고 LLM 옵저버빌리티 플랫폼으로 전환
- Langfuse를 Docker Compose 6개 서비스(4-6GB RAM)로 셀프호스팅, 5개 명령어로 셋업 완료
- Claude Code Stop 훅으로 매 응답 후 자동 실행, 증분 처리로 수백 턴 후에도 1초 이내
- Langfuse 다운 시 JSONL 오프라인 큐에 저장 후 자동 drain하여 데이터 유실 방지
- 프로젝트별 opt-out/opt-in 설정 가능, 템플릿 레포 공개

## 인사이트

Claude Code 훅 시스템의 실용적 활용 사례. 프롬프트 엔지니어링을 감이 아니라 데이터 기반으로 개선할 수 있는 인프라를 제시한 점이 핵심 가치임.
