iop/docs/openai-usage-grafana.md

233 lines
No EOL
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# OpenAI-compatible Usage Grafana Query Guide
> **Purpose**: 이 문서는 운영자가 Prometheus metric을 Grafana 패널로 조회해 사용자별 OpenAI-compatible token 사용량을 볼 수 있도록 한다. Control Plane/Client dashboard, request-level ledger, 사용자별 제한 enforcement는 만들지 않는다.
---
## Metric 목록
### 1. `iop_openai_usage_tokens_total` (Counter)
Provider-reported OpenAI-compatible token usage by token type.
| Label | Value 예시 | 설명 |
|-------|-----------|------|
| `edge_id` | `edge-1` | Edge instance identity |
| `principal_ref` | `usr-abc123` | Principal foreign-key-like reference |
| `principal_alias` | `john@acme` | Human-readable alias |
| `token_ref` | `tok-xyz789` | Token identity (not a raw secret) |
| `model_group` | `gpt-4o` | Model group identifier |
| `endpoint` | `chat.completions`, `responses` | OpenAI-compatible route |
| `response_mode` | `blocking`, `streaming` | Response mode |
| `token_type` | `input`, `output`, `reasoning`, `cached_input` | Token type |
### 2. `iop_openai_requests_total` (Counter)
OpenAI-compatible requests processed by terminal status and usage source.
| Label | Value 예시 | 설명 |
|-------|-----------|------|
| `edge_id` | `edge-1` | Edge instance identity |
| `principal_ref` | `usr-abc123` | Principal reference |
| `principal_alias` | `john@acme` | Human-readable alias |
| `token_ref` | `tok-xyz789` | Token identity |
| `model_group` | `gpt-4o` | Model group identifier |
| `endpoint` | `chat.completions`, `responses` | OpenAI-compatible route |
| `response_mode` | `blocking`, `streaming` | Response mode |
| `status` | `success`, `error`, `cancel` | Terminal request status |
| `usage_source` | `provider_reported`, `unavailable` | Whether at least one token type was reported |
### 3. `iop_openai_reasoning_observed_total` (Counter)
Requests where reasoning text was observed but the provider did not report reasoning token usage.
Same labels as `iop_openai_requests_total` excluding `status` and `usage_source`: `edge_id`, `principal_ref`, `principal_alias`, `token_ref`, `model_group`, `endpoint`, `response_mode`.
### 4. `iop_openai_reasoning_chars_total` (Counter)
Observed reasoning text characters for requests without provider-reported reasoning tokens. Never converted to a token estimate.
---
## Label Allowlist & Forbidden Labels
### 허용 label
```
edge_id, principal_ref, principal_alias, token_ref,
model_group, endpoint, response_mode, status,
token_type, usage_source
```
### 금지 label
- `request_id`, `session_id` — request-level 상세는 후속 ledger/Loki 축에서 다룬다.
- Bearer token, provider API key, raw payload, raw prompt/response text — secret 누출 방지 (SDD S08).
- 그 외 임의 label — cardinality 폭발을 막는다.
---
## PromQL Examples
### 기본: 사용자별 사용량 (principal_alias 기준)
```promql
# 입력 토큰 합계
sum by (principal_alias) (iop_openai_usage_tokens_total{token_type="input"})
# 출력 토큰 합계
sum by (principal_alias) (iop_openai_usage_tokens_total{token_type="output"})
```
### principal_ref별 usage breakdown
```promql
# principal_ref, token_type별 aggregation
sum by (principal_ref, token_type) (iop_openai_usage_tokens_total)
```
### token_ref별 사용량
```promql
# token_ref별 input/output 합계
sum by (token_ref, token_type) (iop_openai_usage_tokens_total)
```
### model_group별 usage
```promql
# model_group, token_type별 aggregation
sum by (model_group, token_type) (iop_openai_usage_tokens_total)
```
### endpoint별 요청 수
```promql
# endpoint, status별 요청 수
sum by (endpoint, status) (iop_openai_requests_total)
```
### response_mode별 분석
```promql
# response_mode별 성공 요청 수
sum by (response_mode, status) (iop_openai_requests_total{status="success"})
```
### token_type별 사용량 전체
```promql
# 모든 token_type별 합계 (time range 그래프용)
sum by (token_type) (irate(iop_openai_usage_tokens_total[5m]))
```
### usage_source별 요청 coverage
```promql
# provider_reported vs unavailable 비율
sum by (usage_source) (iop_openai_requests_total)
```
### reasoning 보조 metric
provider가 reasoning token을 보고하지 않는 경우:
```promql
# reasoning text가 관찰된 요청 수 (provider token 미보고)
sum by (principal_alias) (iop_openai_reasoning_observed_total)
# reasoning text character 합계
sum by (principal_alias) (iop_openai_reasoning_chars_total)
```
> **주의**: `iop_openai_reasoning_observed_total` / `iop_openai_reasoning_chars_total`는 provider-reported reasoning token이 있을 경우 emit되지 않는다. 즉, 이 metric은 "reasoning text는 있으나 token count 보고를 안 하는 provider"만 커버한다. token 추정을 위해 chars를 사용할 수 있으나 이 문서는 추정 권유를 하지 않는다.
---
## Dashboard Panel 후보
| 패널 | query | visualization |
|------|-------|---------------|
| 사용자별 token 사용량 (line) | `sum by (principal_alias, token_type) (irate(iop_openai_usage_tokens_total[5m]))` | Time series, legend=`{{principal_alias}} {{token_type}}` |
| model_group별 token 비율 (pie) | `sum by (model_group, token_type) (iop_openai_usage_tokens_total)` | Stat or bar chart |
| 요청 상태 분포 (table) | `sum by (endpoint, status, usage_source) (iop_openai_requests_total)` | Table |
| reasoning 보조 지표 (singlestat) | `sum(iop_openai_reasoning_observed_total)` | Singlestat |
> Grafana JSON dashboard import file은 본 scope에 포함되지 않는다. 위 PromQL을 바탕으로 패널을 수동 구성한다.
---
## daily / monthly Rollup
### 일일 토큰 합계
```promql
# 일일 입력/출력 토큰 합계 (principal_alias별)
sum by (principal_alias, token_type) (
increase(iop_openai_usage_tokens_total[1d])
)
```
> Grafana dashboard에서 `by time` aggregation으로 대체 가능:
> ```promql
> # Grafana 범용 aggregation (PromQL 함수 아님)
> # time range를 1일로 설정 후 sum by (principal_alias, token_type)
> iop_openai_usage_tokens_total
> ```
### 월간 토큰 합계
```promql
# 월간 입력/출력 토큰 합계 (principal_alias별)
sum by (principal_alias, token_type) (
increase(iop_openai_usage_tokens_total[30d])
)
```
> Grafana dashboard에서 범용 aggregation으로 대체 가능:
> ```promql
> # Grafana 범용 aggregation (PromQL 함수 아님)
> # time range를 30일로 설정 후 sum by (principal_alias, token_type)
> iop_openai_usage_tokens_total
> ```
### 일일/월간 rollup 활용 시나리오
- `principal_alias` 또는 `principal_ref``by` clause에 추가해 사용자별 일일/월간 토큰 사용량을 산출한다.
- `token_type`을 함께 group by하면 input/output/reasoning/cached_input을 구분한다.
- `model_group`을 추가하면 모델별 비용 기반 추정 가능하다 (billing 산출은 이 문서 범위를 벗남).
---
## Limit Follow-up: 경계 명시
### 후속 Milestone으로 남기는 항목
- 사용자별 daily/monthly token **warn** 또는 **reject** enforcement는 이 Milestone의 범위가 아니며 후속 Milestone으로 Planned된다.
- billing, price, ROI amount 산출은 별도 ledger/cost model 범위다.
- request-level ledger / audit log는 Loki/queriable log축 후속 작업의 대상이다.
### 현재 문서가 제공하는 것
- `principal_ref`, `token_ref`, `model_group`, `token_type` 라벨 기반 daily/monthly rollup PromQL
- 사용자별 사용량 조회를 통한 운영 판단 기준
- provider reasoning report 누락 시 `reasoning_observed_total` / `reasoning_chars_total`로 보조 확인
이 rollup 기준은 후속 enforce Milestone에서 Prometheus query를 그대로 재사용할 수 있도록 설계되었다.
---
## Quick Reference: Label Values
| Label | 허용 값 |
|-------|---------|
| `endpoint` | `chat.completions`, `responses` |
| `status` | `success`, `error`, `cancel` |
| `usage_source` | `provider_reported`, `unavailable` |
| `token_type` | `input`, `output`, `reasoning`, `cached_input` |
| `response_mode` | `blocking`, `streaming` |
---
## Appendix: Grafana Scrape Target
Edge metrics는 보통 `localhost:19092` (local) 또는 해당 Edge metrics port에서 Prometheus scrape된다. Grafana data source에 Prometheus를 추가하고 위 PromQL을 테스트 패널에서 검증한다.