Proxy Monitor: 요청 로그, 필터링, 상세 복원 및 내보내기
이미 로컬 리버스 프록시를 실행했지만, 401/429/500, 스트리밍 중단, 또는 "갑자기 계정/모델이 바뀜"이 발생하면, 문제 해결이 쉽게 맹목 추측이 됩니다.
이 수업에서는 한 가지만 설명합니다: Proxy Monitor를 사용하여 각 호출을 "복습 가능한 증거"로 복원하여, 요청이 어디서 왔는지, 어떤 엔드포인트에 닿았는지, 어떤 계정을 사용했는지, 모델이 매핑되었는지, 그리고 토큰 소비가 대략 얼마인지 알게 됩니다.
이 수업을 마치면 할 수 있는 것
/monitor페이지에서 녹화를 열기/일시 중지하고, Token Stats에 영향을 주는지 이해할 수 있습니다- 검색 상자, 빠른 필터, 계정 필터를 사용하여 빠르게 한 요청 기록을 찾을 수 있습니다
- 상세 팝업에서 요청/응답 패킷을 보고 복사하여, 실패 원인을 복습할 수 있습니다
- Proxy Monitor의 데이터 저장 위치(
proxy_logs.db)와 정리 동작을 알 수 있습니다 - 현재 버전의 "로그 내보내기" 실제 능력 경계를 이해할 수 있습니다(GUI vs 백엔드 명령)
현재의 문제점
- "호출 실패/시간 초과"만 보이지만, 실패가 업스트림, 프록시, 또는 클라이언트 구성에서 발생했는지 모릅니다
- 모델 매핑 또는 계정 로테이션이 트리거되었다고 의심하지만, 증거 체인이 없습니다
- 한 요청의 완전한 payload(특히 스트리밍/Thinking)를 복습하고 싶지만, 로그에서 볼 수 없습니다
언제 이 방법을 사용해야 할까요?
- 문제 해결하려고 할 때: 401 인증 실패, 429 속도 제한, 5xx 업스트림 오류, 스트리밍 중단
- 확인하려고 할 때: 어떤 요청이 어떤 계정을 사용했는지(
X-Account-Email) - 모델 라우팅 전략을 만들 때, "클라이언트 모델 이름 → 실제 매핑 모델 이름"을 확인하려고 할 때
🎒 시작 전 준비
전제 조건
Proxy Monitor는 "리버스 프록시 서비스가 받은 요청"을 기록합니다. 따라서 최소한 먼저 실행해야 합니다:
- 리버스 프록시 서비스가 시작되었고,
/healthz에 접근할 수 있습니다 - 현재 리버스 프록시의 Base URL과 포트를 알고 있습니다
아직 실행하지 않았다면, 먼저 **로컬 리버스 프록시 시작 및 첫 번째 클라이언트 연결**를 보세요.
Proxy Monitor란 무엇인가요?
Proxy Monitor는 Antigravity Tools 내장의 "요청 로그 대시보드"입니다. 각 요청이 로컬 리버스 프록시로 들어온 후, 시간, 경로, 상태 코드, 소요 시간, 모델 및 프로토콜을 기록하고, 응답에서 가능한 토큰 사용량을 추출합니다. 또한 단일 기록을 클릭하여 요청과 응답 패킷을 볼 수 있으며, 이를 사용하여 실패 원인과 라우팅/계정 선택 결과를 복습할 수 있습니다.
데이터 저장 위치
Proxy Monitor의 로그는 데이터 디렉터리 아래의 SQLite에 기록됩니다: proxy_logs.db. 데이터 디렉터리를 찾는 방법과 백업 방법은 먼저 **최초 실행 필독: 데이터 디렉터리, 로그, 트레이 및 자동 시작**을 복습하는 것이 좋습니다.
핵심 아이디어: 주시해야 할 6개 필드
Proxy Monitor의 한 기록(백엔드 구조체 ProxyRequestLog)에서 가장 실용적인 것은 다음 필드들입니다:
| 필드 | 사용하여 무엇을 답할 수 있는지 |
|---|---|
status | 이 요청이 성공했는지 실패했는지(200-399 vs 기타) |
url / method | 실제로 어떤 엔드포인트에 도달했는지(예: /v1/messages, /v1/chat/completions) |
protocol | 이것이 OpenAI / Claude(Anthropic) / Gemini 어느 프로토콜인지 |
account_email | 이 요청이 최종적으로 어떤 계정을 사용했는지(응답 헤더 X-Account-Email에서) |
model / mapped_model | 클라이언트 요청 모델 이름이 "라우팅/매핑"을 통해 다른 모델이 되었는지 |
input_tokens / output_tokens | 이 요청의 토큰 사용량(추출 가능한 경우에만) |
먼저 "요약"을 사용하고, 필요할 때 "상세"를 클릭하세요
목록 페이지는 요약만 표시합니다(request/response body 없음). 단일 기록을 클릭하면 백엔드에서 완전한 상세를 로드하여, 목록이 한 번에 너무 많은 대용량 필드를 가져오는 것을 방지합니다.
따라해 보세요: 한 번의 호출로 "모니터링 폐루프" 완성
1단계: 먼저 "확실히 나타날" 요청 하나 만들기
왜 필요한가요? Proxy Monitor는 리버스 프록시 서비스가 받은 요청만 기록합니다. 가장 간단한 요청으로 "기록이 있는지"를 먼저 검증하고, 다음 필터링과 상세를 논의합니다.
## 1) 헬스 체크(반드시 존재하는 엔드포인트)
curl "http://127.0.0.1:PORT/healthz"
## 2) 다시 models 요청(인증을 켰다면 header 추가하는 것을 기억하세요)
curl "http://127.0.0.1:PORT/v1/models"## 1) 헬스 체크(반드시 존재하는 엔드포인트)
curl "http://127.0.0.1:PORT/healthz"
## 2) 다시 models 요청(인증을 켰다면 header 추가하는 것을 기억하세요)
curl "http://127.0.0.1:PORT/v1/models"보아야 할 것: 터미널이 {"status":"ok"}(또는 유사한 JSON)을 반환하고, /v1/models의 응답(성공 또는 401 모두 됨)을 봅니다.
2단계: Monitor 페이지 열기 및 "녹화 상태" 확인
왜 필요한가요? Proxy Monitor에 "녹화/일시 중지" 스위치가 있습니다. 현재 상태를 먼저 확인해야, 계속 요청하지만 목록이 항상 비어 있는 것을 피할 수 있습니다.
Antigravity Tools에서 사이드바의 API 모니터링 대시보드(라우트 /monitor)를 엽니다.
페이지 상단에 점이 있는 버튼이 있습니다:
┌───────────────────────────────────────────┐
│ ● 녹화 중 [검색 상자] [새로고침] [지우기] │
└───────────────────────────────────────────┘"일시 중지"를 보면, 한 번 클릭하여 "녹화 중"으로 전환합니다.
보아야 할 것: 버튼 상태가 "녹화 중"이 됩니다. 목록에 방금의 요청 기록이 나타나기 시작합니다.
3단계: "검색 + 빠른 필터"로 한 기록 찾기
왜 필요한가요? 실제 문제 해결할 때, 보통 한 조각만 기억합니다: 경로에 messages가 있거나, 상태 코드가 401이거나, 모델 이름에 gemini가 있습니다. 검색 상자는 이런 기억을 위해 설계되었습니다.
Proxy Monitor의 검색은 입력을 "퍼지 키워드"로 처리하고, 백엔드에서 SQL LIKE로 다음 필드를 일치시킵니다:
urlmethodmodelstatusaccount_email
몇 가지 전형적인 키워드를 시도해 볼 수 있습니다:
healthzmodels401(방금 401을 만들었다면)
"빠른 필터" 버튼을 클릭할 수도 있습니다: 오류만 / Chat / Gemini / Claude / 그림.
보아야 할 것: 목록에 예상하는 한 종류의 요청만 남습니다.
4단계: 상세를 클릭하여, "요청 패킷 + 응답 패킷" 복원
왜 필요한가요? 목록은 "무엇이 발생했는지"만 답할 수 있습니다. "왜"를 답하려면, 보통 완전한 요청/응답 payload를 봐야 합니다.
임의의 기록을 클릭하면, 상세 창이 팝업됩니다. 중점적으로 확인할 수 있습니다:
프로토콜(OpenAI/Claude/Gemini)사용 모델과매핑 모델사용 계정토큰 소비 (입력/출력)
그 다음 버튼으로 복사:
요청 패킷 (Request)응답 패킷 (Response)
보아야 할 것: 상세에 두 블록의 JSON(또는 텍스트) 미리보기가 있습니다. 복사한 후 티켓/노트에 붙여넣어 복습할 수 있습니다.
5단계: "처음부터 재현"이 필요할 때, 로그 비우기
왜 필요한가요? 문제 해결할 때 가장 두려운 것은 "이전 데이터가 판단을 방해하는" 것입니다. 비운 후 한 번 재현하면, 성공/실패가 매우 명확합니다.
상단의 "지우기" 버튼을 클릭하면, 확인창이 팝업됩니다.
이것은 되돌릴 수 없는 동작입니다
지우기는 proxy_logs.db의 모든 기록을 삭제합니다.
보아야 할 것: 확인 후 목록이 비어 있고, 통계 숫자가 0으로 돌아갑니다.
체크포인트 ✅
- [ ]
/monitor에서 방금 보낸/healthz또는/v1/models기록을 볼 수 있습니다 - [ ] 검색 상자로 한 기록을 필터링할 수 있습니다(예:
healthz입력) - [ ] 한 기록을 클릭하여 요청/응답 패킷을 보고 복사할 수 있습니다
- [ ] 로그를 비우면 모든 역사 기록이 직접 삭제되는 것을 알고 있습니다
일반적인 실수
| 시나리오 | 이해할 수 있는 것(❌) | 실제 동작(✓) |
|---|---|---|
| "일시 중지"= 모니터링 오버헤드 완전 없음 | 일시 중지 후 요청이 파싱되지 않을 것으로 생각함 | 일시 중지는 "Proxy Monitor 로그에 쓸지"에만 영향을 줍니다. 하지만 요청/응답 파싱(스트리밍 데이터의 SSE 파싱 포함)은 여전히 발생하며, 파싱된 데이터는 저장되지 않습니다. Token Stats도 여전히 기록합니다(모니터링 활성 여부와 상관없음). |
| 바이너리/대용량 패킷 로그가 비어 있음 | 모니터링이 망가졌다고 생각함 | 바이너리 요청/응답은 [Binary Request Data] / [Binary Response Data]로 표시됩니다. 응답 바디가 100MB를 초과하면 [Response too large (>100MB)]로 표시됩니다. 요청 바디가 제한을 초과하면 기록하지 않습니다. |
| Monitor를 사용하여 "누가 요청을 보냈는지" 찾으려고 함 | 호출 프로세스까지 추적할 수 있다고 생각함 | Monitor는 HTTP 레이어 정보(메소드/경로/모델/계정)를 기록하며, "호출자 프로세스 이름"을 포함하지 않습니다. 클라이언트 자체 로그 또는 시스템 네트워크 패킷 캡처를 결합하여 출처를 찾아야 합니다. |
| 모니터링 활성화 시 Token Stats 데이터 비정상 | 통계 오류라고 생각함 | 모니터링 활성화 시, Token Stats가 두 번 기록될 수 있습니다(모니터링 함수 시작 시 한 번, 비동기 DB 쓰기 때 한 번). 이것은 현재 버전의 소스 코드 동작입니다. |
내보내기 및 장기 보존: 먼저 능력 경계를 명확히 하세요
1) GUI에서 현재 할 수 있는 것
현재 버전의 Monitor UI(ProxyMonitor.tsx)에서, 다음을 할 수 있습니다:
- 검색/필터링/페이지 매김
- 상세를 클릭하여 payload 보기 및 복사
- 모든 로그 지우기
하지만 "내보내기 버튼"을 발견하지 못했습니다(소스 코드에 관련 UI가 보이지 않음).
2) 백엔드가 이미 가진 내보내기 능력(2차 개발에 적합)
백엔드 Tauri 명령은 두 가지 내보내기 방식을 제공합니다:
export_proxy_logs(file_path): 데이터베이스에서 "모든 로그"를 JSON 파일로 내보냅니다export_proxy_logs_json(file_path, json_data): 전달한 JSON 배열을 포맷하여 파일에 씁니다(입력은 반드시 배열 형식이어야 함)
GUI의 2차 개발 또는 자신만의 호출 스크립트를 작성하려면, 이러한 명령을 직접 재사용할 수 있습니다.
3) 가장 간단한 "내보내기": proxy_logs.db를 직접 백업
Proxy Monitor는 본질적으로 SQLite이므로, proxy_logs.db를 "문제 해결 증거 패키지"로 함께 백업할 수 있습니다(예: token_stats.db와 함께). 데이터 디렉터리 위치는 **최초 실행 필독**를 참조하세요.
계속 읽기를 추천합니다
- 모델 매핑을 명확히 하려면: 모델 라우팅: 커스텀 매핑, 와일드카드 우선순위 및 프리셋 전략
- 인증 문제를 해결하려면: 401/인증 실패: auth_mode, Header 호환 및 클라이언트 구성 목록
- Monitor와 비용 통계를 결합하려면: 다음 절에서 Token Stats를 설명합니다(
token_stats.db)
이 수업 요약
- Proxy Monitor의 가치는 "복습 가능": 상태 코드/경로/프로토콜/계정/모델 매핑/토큰 사용량을 기록하고, 요청 상세를 제공합니다
- 검색과 빠른 필터는 문제 해결 진입점입니다: 먼저 범위를 좁히고, 다음 상세를 클릭하여 payload를 봅니다
- 로그 지우기는 되돌릴 수 없는 동작입니다. 현재 내보내기는 더 2차 개발 능력과 "데이터베이스 파일 백업"으로 치우칩니다
다음 수업 예고
다음 수업에서는 **Token Stats: 비용 관점의 통계 지표 및 차트 해석**을 학습하여, "비싸다"는 느낌을 정량화 가능한 최적화로 만듭니다.
부록: 소스 코드 참조
클릭하여 소스 코드 위치 확인
업데이트 시간: 2026-01-23
| 기능 | 파일 경로 | 라인 |
|---|---|---|
| Monitor 페이지 진입(ProxyMonitor 마운트) | src/pages/Monitor.tsx | 1-12 |
| Monitor UI: 테이블/필터/상세 팝업 | src/components/proxy/ProxyMonitor.tsx | 13-713 |
| UI: 구성 읽기 및 enable_logging 동기화 | src/components/proxy/ProxyMonitor.tsx | 174-243 |
| UI: 녹화 전환(config 쓰기 + set_proxy_monitor_enabled) | src/components/proxy/ProxyMonitor.tsx | 254-267 |
| UI: 실시간 이벤트 리스닝(proxy://request) 및 중복 제거 | src/components/proxy/ProxyMonitor.tsx | 273-355 |
| UI: 로그 지우기(clear_proxy_logs) | src/components/proxy/ProxyMonitor.tsx | 389-403 |
| UI: 단일 상세 로드(get_proxy_log_detail) | src/components/proxy/ProxyMonitor.tsx | 505-519 |
| 모니터링 미들웨어: 요청/응답 캡처, 토큰 파싱, monitor에 쓰기 | src-tauri/src/proxy/middleware/monitor.rs | 13-337 |
| ProxyMonitor: enabled 스위치, DB 쓰기, 이벤트 전송 | src-tauri/src/proxy/monitor.rs | 33-194 |
| 서버 측 모니터링 미들웨어 마운트(layer) | src-tauri/src/proxy/server.rs | 183-194 |
| Tauri 명령: get/count/filter/detail/clear/export | src-tauri/src/commands/proxy.rs | 180-314 |
| SQLite: proxy_logs.db 경로, 테이블 구조 및 필터링 SQL | src-tauri/src/modules/proxy_db.rs | 1-416 |
| 모니터링 설명(구현과 차이가 있을 수 있으므로 소스 코드를 기준으로 함) | docs/proxy-monitor-technical.md | 1-53 |
핵심 상수:
MAX_REQUEST_LOG_SIZE = 100 * 1024 * 1024: 모니터링 미들웨어가 읽을 수 있는 최대 요청 바디(초과하면 읽기 실패)MAX_RESPONSE_LOG_SIZE = 100 * 1024 * 1024: 모니터링 미들웨어가 읽을 수 있는 최대 응답 바디(이미지 등 대용량 응답에 사용)
핵심 함수/명령:
monitor_middleware(...): HTTP 레이어에서 요청과 응답을 캡처하고,monitor.log_request(...)를 호출합니다ProxyMonitor::log_request(...): 메모리 + SQLite에 쓰고,proxy://request이벤트를 통해 요약을 푸시합니다get_proxy_logs_count_filtered(filter, errors_only)/get_proxy_logs_filtered(...): 목록 페이지 필터링 및 페이지 매김get_proxy_log_detail(log_id): 단일 로그의 완전한 request/response body 로드export_proxy_logs(file_path): 모든 로그를 JSON 파일로 내보냄(현재 UI에 버튼이 노출되지 않음)