이 레포가 무엇을 하는 물건인가.
자동차 계기판이 연료를 얼마나 썼는지 알려주듯, splitrail은 AI 코딩 도구가 토큰을 얼마나 태웠고 비용이 얼마인지 한눈에 보여준다. 다른 점은, 차가 여러 대(Claude Code, Gemini CLI, Codex…)인데 계기판 하나로 전부 합산해 준다는 것.
요즘은 코딩할 때 AI 도구를 하나만 쓰지 않는다. 어떤 작업은 Claude Code로, 어떤 건 Gemini CLI로, VS Code 안에서는 Copilot이나 Cline으로… 이렇게 쓰다 보면 각 도구가 토큰을 얼마나 먹었는지, 한 달에 돈이 얼마 나가는지 도무지 한눈에 안 들어온다. splitrail은 이 도구들이 각자 컴퓨터에 남겨 놓은 대화 로그 파일을 직접 읽어 하나의 표·그래프로 합쳐 보여준다.
핵심은 "추가 설정 없이 그냥 돈다"는 점이다. 도구에 별도 플러그인을 심을 필요 없이, 이미 디스크에 쌓여 있는 로그를 분석할 뿐이다. splitrail 한 번이면 터미널 대시보드가 뜨고, 파일이 바뀌면 실시간으로 숫자가 갱신된다.
트렌딩 이유 · 경쟁 대비 장점.
AI 코딩 도구 사용량을 보는 도구로는 ccusage(Claude Code 전용, Node.js)가 먼저 유명했다. splitrail이 끌리는 이유는 세 가지다. 첫째, 한 도구가 아니라 십수 개를 동시에 본다. 둘째, Rust로 만든 단일 실행 파일이라 런타임 설치 없이 바로 돈다. 셋째, 터미널 대시보드만이 아니라 MCP 서버·VS Code 확장·클라우드 동기화까지 한 묶음으로 준다.
| 비교 항목 | ccusage 등 기존 | splitrail |
|---|---|---|
| 지원 도구 | 주로 Claude Code 1종 | Claude Code·Gemini·Codex·Copilot·Cline·Roo·Kilo·OpenCode·Pi 등 14종 |
| 실행 방식 | Node.js 런타임 필요 | 의존성 없는 단일 바이너리 |
| 속도 | JS 파싱 | SIMD JSON + 병렬 처리로 매우 빠름 |
| 인터페이스 | 주로 표 출력 | 실시간 TUI + MCP + VS Code + 클라우드 |
Claude Code는 Claude Code대로, Gemini는 Gemini대로 사용량이 흩어져 있어 "이번 달 AI에 총 얼마 썼지?"에 답하기 어렵다. 도구마다 로그 형식·저장 위치도 제각각이라 직접 합산하기는 사실상 불가능.
도구별 로그를 각자의 분석기(Analyzer)가 읽어, 내부적으로 똑같은 메시지 구조로 변환한다. 그래서 도구가 14개든 1개든 날짜별·모델별·비용별로 한 표에 합쳐서 비교할 수 있다.
"빠른 단일 바이너리"를 떠받치는 크레이트들.
splitrail은 100% Rust 백엔드(코어)에 얇은 TypeScript VS Code 확장이 얹힌 구조다. Rust 생태계의 라이브러리(크레이트)를 성능 위주로 골라 썼다.
| 레이어 | 기술 / 크레이트 | 역할 |
|---|---|---|
| 언어·런타임 | Rust 2024 (nightly) + tokio | 코어 전체 + 비동기 런타임(MCP·업로드) |
| CLI 파싱 | clap 4 (derive) | upload·config·stats·mcp 서브명령 |
| 터미널 UI | ratatui 0.30 + crossterm | 실시간 대시보드(표·탭·정렬) |
| JSON 파싱 | simd-json | SIMD 가속 — serde_json 대신 모든 파싱에 |
| 병렬 처리 | rayon | 분석기·파일을 동시에 파싱(par_iter) |
| 동시성 자료구조 | dashmap · parking_lot | 잠금 적은 캐시 · 빠른 Mutex/RwLock |
| 메모리 최적화 | mimalloc · lasso · tinyvec | 할당자 교체 · 문자열 인터닝 · 인라인 벡터 |
| 해싱 | xxhash-rust · sha2 | 빠른 로컬 해시 · 서버 중복제거용 SHA-256 |
| MCP 서버 | rmcp 0.12 + schemars | 공식 Rust MCP SDK · 도구 입력 스키마 |
| HTTP | reqwest (rustls) | 클라우드 업로드 · 버전 확인(OpenSSL 불필요) |
| 데이터베이스 | rusqlite (bundled) | SQLite 로그 읽기(OpenCode·Piebald·Antigravity) |
| 토큰 계산 | tiktoken-rs | Copilot처럼 토큰 수를 안 주는 도구 직접 계산 |
Cargo.toml 파일에 어떤 크레이트를 쓸지 적어 둔다.로그 파일이 어디서 어떻게 화면까지 흐르는가.
splitrail의 일은 다섯 단계로 흐른다: ① 발견 → ② 파싱 → ③ 중복제거 → ④ 집계 → ⑤ 출력(TUI·업로드·MCP). 먼저 전체 그림 한 장:
여기서 핵심 설계는 Analyzer 트레이트다. 도구가 14개라고 코드가 14벌인 게 아니라, "분석기라면 이런 일을 할 줄 알아야 한다"는 인터페이스(트레이트) 하나를 정해 두고, 각 도구는 그 빈칸만 채운다.
pub trait Analyzer {
// 화면에 보일 이름 (예: "Claude Code")
fn display_name(&self) -> &str;
// 로그 파일이 어디 있는지 찾는다
fn discover_data_sources(&self) -> Vec<DataSource>;
// 파일 하나를 읽어 공통 메시지로 변환
fn parse_source(&self, src: &DataSource) -> Vec<ConversationMessage>;
// 실시간 감시할 폴더
fn get_watch_directories(&self) -> Vec<PathBuf>;
}
모든 분석기는 결국 ConversationMessage라는 똑같은 구조체로 결과를 토해 낸다. 그래서 그 뒤의 중복제거·집계·화면 코드는 도구가 뭐였는지 신경 쓸 필요가 없다.
pub struct ConversationMessage {
pub application: Application, // 어느 도구? (enum)
pub date: DateTime<Utc>,
pub model: Option<String>, // 어떤 모델
pub stats: Stats, // 토큰·비용·파일작업…
pub local_hash: Option<String>, // 도구 내 중복제거(xxh3)
pub global_hash: String, // 기기 간 중복제거(SHA-256)
}
이 레포에서 가장 똑똑한 부분은 실시간 증분 갱신이다. 보통은 파일이 하나 바뀌면 전체를 다시 읽어야 하는데, splitrail은 그러지 않는다.
① watcher.rs가 notify 크레이트로 ~/.claude/projects 폴더를 감시한다. ② 파일 하나가 바뀌면, 그 파일 하나만 다시 파싱한다. ③ 캐시에 저장해 둔 그 파일의 예전 기여분(contribution)을 현재 합계에서 빼고, 새로 파싱한 값을 더한다. ④ 전체를 다시 스캔하지 않으니 거의 즉시(O(1)) 숫자가 갱신된다.
Box<dyn Analyzer> 목록으로 분석기들을 한 바구니에 담는 패턴. 새 도구 지원을 추가하려면 트레이트를 구현한 구조체 하나만 만들어 등록하면 된다 — 나머지 코드는 손대지 않는다. "콘센트 규격(트레이트)만 맞추면 어떤 가전(분석기)이든 꽂힌다."어떤 폴더가 무슨 일을 하나.
| 파일/폴더 | 역할 |
|---|---|
src/analyzers/ | 도구마다 1파일. 로그 위치를 찾고 공통 메시지로 변환. 새 도구 지원의 출발점. |
src/models.rs | 모델별 가격표가 코드에 박혀 있음. 출처 URL 주석 포함. 비용 계산의 단일 진실원. |
src/tui.rs | ratatui 대시보드. 표·탭·정렬·검색(/)·vim 키(h/j/k/l). |
src/watcher.rs | 파일 변경 감지 → 증분 갱신. 실시간성의 심장. |
src/contribution_cache/ | 파일별 요약(32~100바이트)을 캐싱해 add/subtract로 즉시 갱신. |
vscode-splitrail/ | 파싱을 다시 짜지 않고 splitrail stats CLI를 호출해 JSON을 받아 웹뷰에 그림. |
이 레포에서 배울 만한 것 + 어디를 보면 되는지.
"공통 인터페이스(트레이트) + 구현체 N개" 패턴의 모범 사례. async-trait, 트레이트 기본 메서드(공통 로직을 트레이트에 넣어 각 분석기는 핵심만 구현), Send + Sync 경계까지 자연스럽게 배운다. src/analyzer.rs와 analyzers/pi_agent.rs(가장 단순)부터 읽으면 좋다.
터미널 앱의 정석 루프를 볼 수 있다. enable_raw_mode → 대체 화면 진입 → terminal.draw(|f| …) → event::poll로 키 입력. 표·탭·정렬·검색이 어떻게 위젯으로 조립되는지 src/tui.rs에서 확인.
공식 SDK rmcp로 도구를 노출하는 최신 예제. 매크로(#[tool])로 도구를 정의하고 schemars로 입력 스키마를 자동 생성한다. splitrail mcp를 띄우면 AI가 사용량을 직접 조회.
# MCP 서버로 실행
splitrail mcp
# 노출되는 도구 예: get_daily_stats,
# get_cost_breakdown, compare_tools …
이 레포의 진짜 보석. rayon로 분석기·파일을 2중 병렬 파싱, simd-json으로 SIMD 파싱, mimalloc 할당자 교체, lasso로 모델명을 2바이트 키로 인터닝, tinyvec로 작은 벡터를 힙 없이 저장. 빠른 로컬 해시(xxh3) vs 안정적 글로벌 해시(SHA-256)를 용도별로 나눠 쓰는 것도 배울 점.
그냥 쓰려면 / 직접 빌드하려면 무엇이 필요한가.
| 항목 | 요구사항 |
|---|---|
| 실행(권장) | 릴리스 페이지의 OS별 바이너리 다운로드 — 별도 런타임 불필요 |
| 지원 OS | Linux(gnu·musl, x86_64·aarch64) · macOS(Intel·Apple Silicon) · Windows(x86_64) |
| 빌드 도구체인 | Rust nightly(rust-toolchain.toml로 고정), Cargo |
| Windows 빌드 | lld-link.exe(LLVM) — 컴파일 속도용. winget install LLVM.LLVM |
| 분석 대상 | 이미 사용 중인 AI 코딩 도구의 로컬 로그(자동 탐색) |
| 선택 | 클라우드 동기화 시 splitrail.dev 계정·API 토큰 |
난이도별로 손에 익히는 단계.
릴리스 페이지에서 내 OS용 파일을 받아 실행만 하면 된다. 이미 Claude Code나 Gemini CLI를 써 봤다면 곧바로 사용량이 뜬다. 토큰·비용이 날짜별로 어떻게 합산되는지 관찰해 보자.
# 받은 바이너리를 그냥 실행
splitrail
# 표만 빠르게 보고 싶으면(JSON 출력)
splitrail stats
~/.splitrail.toml을 열어 숫자 표기(천 단위 콤마)·소수 자릿수·로케일을 바꿔 보고 화면이 어떻게 달라지는지 본다. 모르는 모델 가격을 직접 추가하는 [models] 섹션도 실험해 보자.
# ~/.splitrail.toml
[formatting]
number_comma = true
decimal_places = 2
locale = "ko"
splitrail mcp로 MCP 서버를 띄우고, Claude 같은 AI 비서에 연결한다. 그다음 "이번 주 도구별 비용 비교해 줘"처럼 자연어로 물으면 AI가 compare_tools 도구를 호출해 답하게 만들어 보자.
저장소를 클론해 cargo run으로 빌드하고, 가장 단순한 analyzers/pi_agent.rs를 정독해 분석기 한 채가 어떻게 생겼는지 파악한다.
git clone https://github.com/Piebald-AI/splitrail
cd splitrail
cargo run # nightly 도구체인 자동 적용
아직 지원 안 되는 도구가 있다면 Analyzer 트레이트를 구현하는 파일을 하나 만들고 main.rs의 레지스트리에 등록해 본다. "발견 → 파싱"만 채우면 중복제거·집계·화면은 공짜로 따라온다. (저장소 .claude/skills/new-analyzer 가이드 참고)
한 주씩 따라가는 계획.
| 주차 | 주제 | 학습 자료 |
|---|---|---|
| 1주차 | Rust 기본 + Cargo + clap CLI | The Rust Book · Cargo.toml·main.rs 정독 |
| 2주차 | 트레이트·트레이트 객체·제네릭 | analyzer.rs + analyzers/pi_agent.rs |
| 3주차 | ratatui·crossterm로 TUI 만들기 | ratatui 공식 튜토리얼 · tui.rs |
| 4주차 | 동시성: rayon·tokio·parking_lot | Rayon 문서 · 파싱 병렬화 코드 |
| 5주차 | 성능: simd-json·인터닝·할당자 | cache/·models.rs + 벤치 실험 |
| 6주차 | MCP 서버(rmcp)·reqwest 업로드 | mcp/server.rs · upload.rs · MCP 명세 |
본문에 나온 용어 빠른 참조.
| 용어 | 의미 |
|---|---|
| 토큰 | AI가 글을 처리하는 최소 단위. 요금 부과의 기준이라 토큰=돈. |
| Analyzer | 도구별 로그를 읽어 공통 메시지로 바꾸는 모듈. splitrail의 플러그인 단위. |
| 트레이트(trait) | "이런 일을 할 줄 알아야 한다"는 Rust의 인터페이스. 자바의 interface와 비슷. |
| TUI | 터미널 안에서 도는 화면형 앱. ratatui로 그린다. |
| MCP | AI 비서가 외부 도구를 표준 방식으로 호출하게 하는 규약. |
| JSONL | 한 줄에 JSON 한 개씩 쌓는 로그 형식. 대부분의 AI CLI가 이렇게 기록. |
| SIMD | CPU가 한 명령으로 여러 데이터를 동시에 처리하는 기술. simd-json이 이걸로 파싱 가속. |
| 할당자(allocator) | 프로그램이 메모리를 받아오는 창구. 기본 대신 mimalloc으로 바꿔 속도↑. |
| 인터닝 | 반복되는 문자열을 짧은 번호표로 대체해 메모리·비교 비용을 줄이는 기법. |
| 중복제거(dedup) | 같은 메시지가 여러 파일/기기에 중복 기록될 때 한 번만 세는 처리. 해시로 판별. |