
설치가 필요 없는 도구 만들기 — 파이썬 표준 라이브러리만으로
여러 장비에 배포할 모니터링 도구를 pip 설치 없이 만들었다. 의존성을 0개로 유지했을 때 실제로 얻은 것과 포기한 것을 정리했다.
AI 코딩 도구를 여러 장비에서 쓰다 보니 토큰을 얼마나 쓰는지 파악이 안 됐다. 이 노트북에서 얼마, 저 서버에서 얼마. 합쳐서 보고 싶었다.
그래서 각 장비의 로컬 세션 기록을 읽어 중앙 서버로 보내는 도구를 만들었다. 서버 한 대가 모아서 대시보드로 보여주고, 워커가 장비마다 돈다.
만들 때 정한 제약이 하나 있다. 파이썬 표준 라이브러리만 쓴다. pip 설치 없음.
왜 의존성을 0으로 뒀나
이 도구는 여러 장비에 깔아야 한다. 그게 전부의 이유다.
의존성이 있으면 장비마다 이런 일이 생긴다.
- 파이썬 버전이 다르다. 어떤 장비는 3.10, 어떤 건 3.12
- 가상환경을 만들어야 한다. 그럼 실행 스크립트가 venv 경로를 알아야 한다
- 어떤 장비는 회사 네트워크라 pip이 느리거나 막혀 있다
- 몇 달 뒤 재설치할 때 패키지 버전이 바뀌어 있다
도구 자체는 200줄짜리인데 설치 절차가 도구보다 복잡해진다. 그리고 설치가 귀찮으면 안 깐다. 안 깔면 그 장비 데이터는 안 모인다. 도구의 목적이 무너진다.
그래서 이렇게 만들었다.
unzip wg-tokenwatch.zip
cd wg-tokenwatch
./scripts/install.sh
./scripts/easy.sh server
압축 풀고 실행하면 끝이다. 파이썬만 있으면 된다.
표준 라이브러리로 충분했던 것들
의외로 필요한 게 대부분 있었다.
HTTP 서버 — http.server로 충분했다. 동시 접속이 몇 명인 내부 대시보드에 FastAPI나 Flask가 필요하지 않다.
HTTP 클라이언트 — 워커가 서버로 데이터를 보내는 건 urllib.request로 된다. requests가 편하지만 편의 함수 몇 개 차이다.
데이터베이스 — sqlite3가 표준 라이브러리에 있다. 이게 결정적이었다. 별도 DB 서버도, ORM도 필요 없다.
JSON 파싱 — 읽어야 하는 세션 파일이 JSONL이라 json으로 한 줄씩 읽으면 된다.
설정 — .env 파싱은 20줄이면 된다. python-dotenv를 쓸 이유가 없었다.
포기한 것
정직하게 적으면 포기한 것도 있다.
웹 프레임워크의 편의. 라우팅을 직접 짜야 한다. 경로가 열 개쯤 되면 if문이 길어진다. 이건 그냥 감수했다.
비동기 처리. http.server는 기본이 단일 스레드다. 워커 여러 대가 동시에 전송하면 순차 처리된다. 전송이 1분에 한 번이고 페이로드가 작아서 문제가 안 됐다. 트래픽이 늘면 여기서 막힐 것이다.
HTML 템플릿. 대시보드 HTML을 문자열로 만든다. 화면이 복잡해지면 관리가 어려워진다. 이건 실제로 조금 불편하다.
핵심은 이 제약이 이 도구에 맞았다는 것이다. 사용자가 수천 명인 서비스였다면 잘못된 선택이다. 내부 장비 몇 대의 사용량을 모으는 도구라 맞았다.
파서는 확장 가능하게 열어뒀다
의존성을 0으로 뒀다고 확장까지 막으면 안 된다. 읽어야 할 도구가 늘어날 수 있기 때문이다.
지금 읽는 건 이렇다.
| 도구 | 경로 | 방식 |
|---|---|---|
| Claude Code | ~/.claude/projects/**/*.jsonl |
usage 토큰 필드 |
| Codex CLI | ~/.codex/sessions/**/*.jsonl |
token_count / usage 필드 |
| 기타 JSONL | 환경변수로 지정한 디렉토리 | 일반 토큰 필드 탐색 |
새 도구를 추가하려면 파서 모듈에 provider를 하나 더 넣으면 된다.
안 읽기로 한 것도 있다
Cursor, Copilot, Cline 같은 도구는 SQLite나 확장 저장소에 기록을 남긴다. 이것도 읽을 수 있다. 그런데 버전마다 저장 방식이 자주 바뀐다.
한 번 붙여두면 도구가 업데이트될 때마다 깨진다. 깨진 걸 모르면 “사용량이 0으로 나오네” 하고 잘못된 결론을 낸다.
그래서 일단 JSONL 기반 도구들로 범위를 좁혔다. 형식이 단순하고 안정적이기 때문이다. 불안정한 소스를 지원 목록에 넣는 것보다, 지원 안 한다고 명시하는 편이 낫다. 사용자가 “왜 안 나오지”로 헤매지 않는다.
설정 우선순위를 정해둔 것
작은 부분인데 실제로 도움이 됐다. 설정 우선순위를 명시했다.
셸 환경변수 / CLI 인자 > 루트 .env > config/*.env
역할별 설정 파일(config/server.env, config/worker.env)이 원래 방식이었는데, 장비 한 대에서 둘 다 돌릴 때 파일을 두 개 관리하는 게 번거로웠다. 루트에 .env 하나를 두면 양쪽을 함께 설정할 수 있게 했다.
기존 방식도 계속 동작한다. 새 방식을 추가하면서 옛 방식을 깨지 않는 것이 중요했다. 이미 깔아둔 장비에 다시 들어가서 설정을 옮기고 싶지 않았다.
정리
- 여러 장비에 배포할 도구는 설치 절차가 도구보다 복잡해지면 안 깔게 된다
- 내부용 소규모 도구에는 표준 라이브러리(
http.server,urllib,sqlite3,json)로 대부분 된다 - 대신 라우팅, 동시성, 템플릿의 편의는 포기한다. 규모가 커지면 잘못된 선택이 된다
- 저장 형식이 자주 바뀌는 소스는 지원하지 않는다고 명시하는 편이 낫다. 조용히 깨지는 것보다 낫다
- 설정 방식을 새로 추가할 때 기존 방식을 깨지 않는다. 이미 배포된 장비를 다시 손대야 한다