시작하기 전에: 왜 AI API 모니터링이 중요한가?
저는 3개월 전 이커머스 스타트업에서 AI 고객 서비스 봇을 개발했습니다. 블랙프라이데이 시즌을 앞두고 트래픽이 평소의 50배로 급증할 것으로 예상되던 시점이었죠.深夜 모니터링 대시보드를 지켜보며 불안하게 coffee를 마시던 중, API 응답 시간이 평소 200ms에서 8초까지 치솟는 현상을 발견했습니다.
문제는 단순한 지연이 아니었습니다. API 제공자의 rate limit에 도달해 요청이 실패하기 시작했고, 사용자들은 "죄송합니다, 일시적인 오류가 발생했습니다"라는 메시지만 받게 됐죠. 결국 2시간 만에 15%의 주문 전환율 손실이라는 비용을 치뤘습니다.
이 경험 이후, 저는 HolySheep AI 게이트웨이를 통해 AI API를 호출하는 모든 프로젝트에 Prometheus + Alertmanager 모니터링 시스템을 구축하고 있습니다. 이 튜토리얼에서는 그 구체적인 구현 방법을 상세히 설명드리겠습니다.
1. 전체 아키텍처 개요
┌─────────────────────────────────────────────────────────────────────┐
│ 모니터링 아키텍처 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │HolySheep │ │ Prometheus│ │Grafana │ │ Alertmanager │ │
│ │ AI API │───▶│ Collector │───▶│Dashboard │───▶│ Slack/Pager│ │
│ │ │ │ │ │ │ │ Duty Email │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌──────────┐ │
│ │ │ node_ │ │
│ │ │ exporter │ │
│ │ └──────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ Your AI Application Service │ │
│ │ - Flask/FastAPI/Django │ │
│ │ - prometheus_client 라이브러리 │ │
│ └──────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
2. HolySheep AI API 통합: 메트릭 수집 시작
먼저 HolySheep AI 게이트웨이에 연결하고, 모든 API 호출에 대한 메트릭을 자동으로 수집하는 구조를 만들겠습니다. HolySheep AI는 지금 가입하면 무료 크레딧을 제공하며, GPT-4.1 ($8/MTok), Claude Sonnet 4.5 ($15/MTok), Gemini 2.5 Flash ($2.50/MTok), DeepSeek V3.2 ($0.42/MTok) 등 모든 주요 모델을 단일 API 키로 통합 관리할 수 있습니다.
# requirements.txt
AI & 웹 프레임워크
openai==1.12.0
fastapi==0.109.2
uvicorn==0.27.1
모니터링 & 메트릭
prometheus-client==0.19.0
prometheus-fastapi-instrumentator==6.1.0
유틸리티
python-dotenv==1.0.1
httpx==0.26.0
# config.py
import os
from dotenv import load_dotenv
load_dotenv()
HolySheep AI 설정
⚠️ 실제 API 키는 환경변수로 관리하세요
HOLYSHEEP_API_KEY = os.getenv("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY")
HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1" # 반드시 이 URL 사용
모델별 가격 설정 (Dollar per 1M tokens)
MODEL_PRICING = {
"gpt-4.1": {"input": 8.0, "output": 32.0},
"gpt-4.1-mini": {"input": 1.5, "output": 6.0},
"claude-sonnet-4-20250514": {"input": 15.0, "output": 75.0},
"gemini-2.5-flash": {"input": 2.50, "output": 10.0},
"deepseek-v3.2": {"input": 0.42, "output": 1.68},
}
Prometheus 설정
PROMETHEUS_PORT = 9090
ALERTMANAGER_URL = "http://localhost:9093"
# holy_sheep_monitor.py
"""
HolySheep AI API 호출 모니터링 및 메트릭 수집 모듈
모든 API 호출을 감싸서 Prometheus 메트릭으로 자동 수집
"""
from prometheus_client import Counter, Histogram, Gauge, Info
from functools import wraps
import time
from typing import Callable, Any
from config import HOLYSHEEP_BASE_URL, MODEL_PRICING
from openai import OpenAI
import httpx
─────────────────────────────────────────────────────────────
Prometheus 메트릭 정의
─────────────────────────────────────────────────────────────
요청 카운터: 모델별, 상태코드별, 엔드포인트별
REQUEST_COUNTER = Counter(
"ai_api_requests_total",
"Total AI API requests",
["model", "status_code", "endpoint", "error_type"]
)
응답 시간 히스토그램: P50, P90, P99 측정
RESPONSE_TIME = Histogram(
"ai_api_response_seconds",
"AI API response time in seconds",
["model", "endpoint"],
buckets=[0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0]
)
토큰 사용량 게이지: 입력/출력 토큰 카운트
TOKEN_USAGE = Counter(
"ai_api_tokens_total",
"Total tokens used",
["model", "token_type"] # token_type: "input" or "output"
)
비용 추적 카운터
API_COST = Counter(
"ai_api_cost_dollars",
"API cost in dollars",
["model"]
)
활성 요청 수 게이지: 동시 요청 모니터링
ACTIVE_REQUESTS = Gauge(
"ai_api_active_requests",
"Number of active requests",
["model"]
)
Rate Limit 상태 게이지
RATE_LIMIT_REMAINING = Gauge(
"ai_api_rate_limit_remaining",
"Remaining API calls in rate limit window",
["model"]
)
─────────────────────────────────────────────────────────────
HolySheep AI 클라이언트 래퍼
─────────────────────────────────────────────────────────────
class MonitoredHolySheepClient:
"""
HolySheep AI API 호출을 모니터링하는 래퍼 클라이언트
모든 요청에 대해 자동 메트릭 수집
"""
def __init__(self, api_key: str):
self.client = OpenAI(
api_key=api_key,
base_url=HOLYSHEEP_BASE_URL # HolySheep 게이트웨이 사용
)
self._error_counts = {}
def _extract_error_type(self, error: Exception) -> str:
"""오류 유형 분류"""
error_str = str(error).lower()
if "rate limit" in error_str or "429" in error_str:
return "rate_limit"
elif "timeout" in error_str or "timed out" in error_str:
return "timeout"
elif "401" in error_str or "unauthorized" in error_str:
return "auth_error"
elif "500" in error_str or "502" in error_str or "503" in error_str:
return "server_error"
elif "context_length" in error_str or "max_tokens" in error_str:
return "context_limit"
else:
return "unknown"
def chat_completions_create(
self,
model: str,
messages: list,
temperature: float = 0.7,
max_tokens: int = 2048,
**kwargs
) -> dict:
"""
HolySheep AI 채팅 완성 API 호출 (메트릭 자동 수집)
실제 지연 시간 예시:
- Gemini 2.5 Flash: 평균 150ms (Cold start 포함 800ms)
- DeepSeek V3.2: 평균 200ms
- GPT-4.1: 평균 400ms
"""
endpoint = "/chat/completions"
ACTIVE_REQUESTS.labels(model=model).inc()
start_time = time.perf_counter()
try:
response = self.client.chat.completions.create(
model=model,
messages=messages,
temperature=temperature,
max_tokens=max_tokens,
**kwargs
)
# 성공 메트릭 수집
elapsed = time.perf_counter() - start_time
RESPONSE_TIME.labels(model=model, endpoint=endpoint).observe(elapsed)
REQUEST_COUNTER.labels(
model=model,
status_code="200",
endpoint=endpoint,
error_type="none"
).inc()
# 토큰 사용량 및 비용 계산
if hasattr(response, 'usage') and response.usage:
input_tokens = response.usage.prompt_tokens or 0
output_tokens = response.usage.completion_tokens or 0
TOKEN_USAGE.labels(model=model, token_type="input").inc(input_tokens)
TOKEN_USAGE.labels(model=model, token_type="output").inc(output_tokens)
# 비용 계산 (Dollar)
if model in MODEL_PRICING:
cost = (
(input_tokens / 1_000_000) * MODEL_PRICING[model]["input"] +
(output_tokens / 1_000_000) * MODEL_PRICING[model]["output"]
)
API_COST.labels(model=model).inc(cost)
return response
except Exception as e:
elapsed = time.perf_counter() - start_time
error_type = self._extract_error_type(e)
# 실패 메트릭 수집
RESPONSE_TIME.labels(model=model, endpoint=endpoint).observe(elapsed)
REQUEST_COUNTER.labels(
model=model,
status_code="error",
endpoint=endpoint,
error_type=error_type
).inc()
# 오류 카운터 업데이트 (연속 실패 감지용)
self._error_counts[model] = self._error_counts.get(model, 0) + 1
raise
finally:
ACTIVE_REQUESTS.labels(model=model).dec()
글로벌 클라이언트 인스턴스
_client_instance = None
def get_monitored_client(api_key: str) -> MonitoredHolySheepClient:
global _client_instance
if _client_instance is None:
_client_instance = MonitoredHolySheepClient(api_key)
return _client_instance
3. FastAPI 애플리케이션과 Prometheus 엔드포인트
# app.py
"""
FastAPI + Prometheus 모니터링 통합 애플리케이션
HolySheep AI 기반 AI 서비스 예시
"""
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from contextlib import asynccontextmanager
import logging
from holy_sheep_monitor import get_monitored_client
from config import HOLYSHEEP_API_KEY
from prometheus_client import make_asgi_app, REGISTRY, generate_latest
로깅 설정
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
─────────────────────────────────────────────────────────────
FastAPI 앱 설정
─────────────────────────────────────────────────────────────
@asynccontextmanager
async def lifespan(app: FastAPI):
"""애플리케이션 시작/종료 시 실행"""
logger.info("🚀 AI API 모니터링 시스템 시작")
logger.info(f"📊 HolySheep API 엔드포인트: {HOLYSHEEP_API_KEY[:8]}...")
# HolySheep AI 클라이언트 초기화
client = get_monitored_client(HOLYSHEEP_API_KEY)
app.state.client = client
yield
logger.info("🔴 모니터링 시스템 종료")
app = FastAPI(
title="AI Customer Service API",
version="1.0.0",
lifespan=lifespan
)
Prometheus 메트릭 엔드포인트 마운트
metrics_app = make_asgi_app()
app.mount("/metrics", metrics_app)
─────────────────────────────────────────────────────────────
요청/응답 모델
─────────────────────────────────────────────────────────────
class ChatRequest(BaseModel):
model: str = "deepseek-v3.2" # 기본값: 가장 저렴한 모델
message: str
system_prompt: str = "당신은 친절한 고객 서비스 담당자입니다."
temperature: float = 0.7
max_tokens: int = 1024
class ChatResponse(BaseModel):
model: str
response: str
input_tokens: int
output_tokens: int
cost_usd: float
latency_ms: float
─────────────────────────────────────────────────────────────
API 엔드포인트
─────────────────────────────────────────────────────────────
@app.post("/api/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
"""AI 고객 서비스 채팅 엔드포인트"""
import time
from config import MODEL_PRICING
start = time.perf_counter()
try:
client = app.state.client
messages = [
{"role": "system", "content": request.system_prompt},
{"role": "user", "content": request.message}
]
response = client.chat_completions_create(
model=request.model,
messages=messages,
temperature=request.temperature,
max_tokens=request.max_tokens
)
elapsed_ms = (time.perf_counter() - start) * 1000
# 토큰 및 비용 계산
usage = response.usage
input_tokens = usage.prompt_tokens
output_tokens = usage.completion_tokens
pricing = MODEL_PRICING.get(request.model, {"input": 1.0, "output": 1.0})
cost_usd = (
(input_tokens / 1_000_000) * pricing["input"] +
(output_tokens / 1_000_000) * pricing["output"]
)
logger.info(
f"✅ [{request.model}] 응답 완료: "
f"latency={elapsed_ms:.0f}ms, tokens={input_tokens}+{output_tokens}, "
f"cost=${cost_usd:.4f}"
)
return ChatResponse(
model=request.model,
response=response.choices[0].message.content,
input_tokens=input_tokens,
output_tokens=output_tokens,
cost_usd=cost_usd,
latency_ms=round(elapsed_ms, 2)
)
except Exception as e:
logger.error(f"❌ 채팅 요청 실패: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
@app.get("/health")
async def health_check():
"""헬스체크 엔드포인트"""
return {"status": "healthy", "service": "ai-customer-service"}
@app.get("/metrics")
async def custom_metrics():
"""커스텀 메트릭 엔드포인트"""
return Response(
content=generate_latest(REGISTRY),
media_type="text/plain"
)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
4. Prometheus 설정 및 Alertmanager 연동
# prometheus.yml
docker-compose.yml과 함께 사용하는 Prometheus 설정
global:
scrape_interval: 15s
evaluation_interval: 15s
external_labels:
cluster: 'ai-api-production'
environment: 'production'
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
rule_files:
- /etc/prometheus/rules/*.yml
scrape_configs:
# 자체 애플리케이션 메트릭
- job_name: 'ai-service'
static_configs:
- targets: ['ai-service:8000']
metrics_path: '/metrics'
scrape_interval: 10s
scrape_timeout: 5s
# Prometheus 자체 메트릭
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
# node_exporter (서버 리소스 모니터링)
- job_name: 'node'
static_configs:
- targets: ['node-exporter:9100']
# rules/ai-alerts.yml
AI API 모니터링 알림 규칙
groups:
- name: ai_api_alerts
interval: 30s
rules:
# ─────────────────────────────────────────────────────
# 1. 고가용성 알림: 서비스 장애
# ─────────────────────────────────────────────────────
- alert: AIAPIServiceDown
expr: up{job="ai-service"} == 0
for: 1m
labels:
severity: critical
team: platform
annotations:
summary: "AI API 서비스 연결 불가"
description: "{{ $labels.instance }} 서비스가 1분 이상 응답하지 않습니다."
- alert: AIAPIMultiRegionFailure
expr: |
(
sum(rate(ai_api_requests_total{status_code="error"}[5m])) by (model)
/
sum(rate(ai_api_requests_total[5m])) by (model)
) > 0.1
for: 3m
labels:
severity: critical
annotations:
summary: "AI API {{ $labels.model }} 모델 10% 이상 실패"
description: "{{ $labels.model }} 실패율이 10%를 초과합니다. 현재: {{ $value | humanizePercentage }}"
# ─────────────────────────────────────────────────────
# 2. 성능 알림: 지연 시간 이상
# ─────────────────────────────────────────────────────
- alert: AIAPILatencyHigh
expr: |
histogram_quantile(0.95,
sum(rate(ai_api_response_seconds_bucket[5m])) by (le, model)
) > 5
for: 5m
labels:
severity: warning
annotations:
summary: "AI API {{ $labels.model }} 응답 지연 증가"
description: "P95 응답 시간이 5초를 초과합니다. 현재: {{ $value | humanizeDuration }}"
- alert: AIAPILatencyCritical
expr: |
histogram_quantile(0.99,
sum(rate(ai_api_response_seconds_bucket[5m])) by (le, model)
) > 10
for: 2m
labels:
severity: critical
annotations:
summary: "AI API {{ $labels.model }} 심각한 지연"
description: "P99 응답 시간이 10초를 초과합니다. 즉시 조치가 필요합니다."
# ─────────────────────────────────────────────────────
# 3. Rate Limit 알림:Quota 소진 경고
# ─────────────────────────────────────────────────────
- alert: AIAPIRateLimitWarning
expr: |
increase(ai_api_requests_total{error_type="rate_limit"}[5m]) > 10
for: 1m
labels:
severity: warning
annotations:
summary: "AI API Rate Limit 접근"
description: "{{ $labels.model }} 모델의 Rate Limit 오류가 5분간 10회 이상 발생했습니다."
- alert: AIAPIErrorRateThreshold
expr: |
(
sum(rate(ai_api_requests_total{error_type=~"timeout|server_error"}[10m])) by (model)
/
sum(rate(ai_api_requests_total[10m])) by (model)
) > 0.05
for: 5m
labels:
severity: warning
annotations:
summary: "AI API {{ $labels.model }} 오류율 5% 초과"
# ─────────────────────────────────────────────────────
# 4. 비용 알림: Budget 관리
# ─────────────────────────────────────────────────────
- alert: AIAPICostDailyBudgetWarning
expr: |
sum(increase(ai_api_cost_dollars[24h])) > 100
for: 1m
labels:
severity: warning
budget: "daily"
annotations:
summary: "AI API 일일 비용 경고"
description: "24시간 비용이 $100을 초과했습니다. 현재: ${{ $value | humanize }}"
- alert: AIAPICostBurst
expr: |
sum(increase(ai_api_cost_dollars[1h])) > 20
for: 5m
labels:
severity: warning
annotations:
summary: "AI API 비용 급증 감지"
description: "1시간 비용이 $20를 초과했습니다. 이상 트래픽 패턴을 확인하세요."
# ─────────────────────────────────────────────────────
# 5. 동시성 알림: 시스템 과부하
# ─────────────────────────────────────────────────────
- alert: AIAPIActiveRequestsHigh
expr: |
sum(ai_api_active_requests) by (model) > 50
for: 5m
labels:
severity: warning
annotations:
summary: "AI API {{ $labels.model }} 동시 요청过多"
description: "활성 요청 수가 50개를 초과합니다. 스케일링을 고려하세요."
# ─────────────────────────────────────────────────────
# 6. 토큰 사용량 알림
# ─────────────────────────────────────────────────────
- alert: AIAPITokenUsageSpike
expr: |
sum(rate(ai_api_tokens_total[1h])) by (model, token_type)
> 1000000 # 시간당 100만 토큰 이상
for: 10m
labels:
severity: info
annotations:
summary: "AI API {{ $labels.model }} 토큰 사용량 급증"
description: "{{ $labels.token_type }} 토큰 사용량이 시간당 100만개를 초과합니다."
# alertmanager.yml
Alertmanager 설정: Slack, Email, PagerDuty 연동
global:
resolve_timeout: 5m
smtp_smarthost: 'smtp.gmail.com:587'
smtp_from: '[email protected]'
smtp_auth_username: '[email protected]'
smtp_auth_password: 'YOUR_APP_PASSWORD'
templates:
- '/etc/alertmanager/template/*.tmpl'
route:
group_by: ['alertname', 'severity']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'default'
routes:
# 심각한(critical) 알림은 즉시通知
- match:
severity: critical
receiver: 'critical-alerts'
group_wait: 10s
repeat_interval: 1h
# 비용 알림은 별도 채널로
- match:
budget: daily
receiver: 'cost-alerts'
continue: true
# 팀별 라우팅
- match:
team: platform
receiver: 'platform-team'
receivers:
# 기본 수신자 (Slack)
- name: 'default'
slack_configs:
- api_url: 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL'
channel: '#ai-alerts'
send_resolved: true
title: |
{{ if eq .Status "firing" }}🚨{{ else }}✅{{ end }}
{{ .GroupLabels.alertname }}
text: |
{{ range .Alerts }}
*Severity:* {{ .Labels.severity }}
*Summary:* {{ .Annotations.summary }}
*Description:* {{ .Annotations.description }}
*Instance:* {{ .Labels.instance }}
*Value:* {{ .Value }}
*Time:* {{ .StartsAt.Format "2006-01-02 15:04:05" }}
{{ end }}
# 심각한 알림 수신자 (SMS + Slack)
- name: 'critical-alerts'
slack_configs:
- api_url: 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL'
channel: '#ai-critical'
send_resolved: true
title: "🚨 CRITICAL: AI API 장애 발생"
text: |
*🚨 심각한 AI API 장애 감지*
*알림:* {{ .CommonLabels.alertname }}
*설명:* {{ .CommonAnnotations.summary }}
*시간:* {{ .CommonStartsAt }}
⚡ 즉시 확인 필요!
pagerduty_configs:
- service_key: 'YOUR_PAGERDUTY_SERVICE_KEY'
severity: critical
# 비용 알림 수신자
- name: 'cost-alerts'
slack_configs:
- api_url: 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL'
channel: '#ai-cost'
send_resolved: true
title: "💰 AI API 비용 알림"
text: |
*💰 비용 알림*
*알림:* {{ .CommonLabels.alertname }}
*현재 비용:* ${{ .CommonAnnotations.description }}
📊 비용 대시보드: http://grafana.example.com/d/costs
# 플랫폼 팀
- name: 'platform-team'
email_configs:
- to: '[email protected]'
send_resolved: true
headers:
subject: '[P1] {{ .CommonLabels.alertname }}'
inhibit_rules:
# 같은 인스턴스의 알림 억제
- source_match:
severity: 'critical'
target_match:
severity: 'warning'
equal: ['alertname', 'instance']
5. Docker Compose로 한 번에 실행
# docker-compose.yml
version: '3.8'
services:
# FastAPI AI 서비스
ai-service:
build:
context: .
dockerfile: Dockerfile
container_name: ai-service
ports:
- "8000:8000"
environment:
- HOLYSHEEP_API_KEY=${HOLYSHEEP_API_KEY}
volumes:
- ./config.py:/app/config.py
- ./holy_sheep_monitor.py:/app/holy_sheep_monitor.py
networks:
- monitoring
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
# Prometheus
prometheus:
image: prom/prometheus:v2.48.1
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- ./rules:/etc/prometheus/rules:ro
- prometheus-data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.enable-lifecycle'
networks:
- monitoring
restart: unless-stopped
# Alertmanager
alertmanager:
image: prom/alertmanager:v0.27.0
container_name: alertmanager
ports:
- "9093:9093"
volumes:
- ./alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
- alertmanager-data:/alertmanager
command:
- '--config.file=/etc/alertmanager/alertmanager.yml'
- '--storage.path=/alertmanager'
networks:
- monitoring
restart: unless-stopped
# Grafana (시각화)
grafana:
image: grafana/grafana:10.2.3
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD:-admin}
- GF_USERS_ALLOW_SIGN_UP=false
volumes:
- grafana-data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning:ro
networks:
- monitoring
depends_on:
- prometheus
restart: unless-stopped
# Node Exporter (서버 메트릭)
node-exporter:
image: prom/node-exporter:v1.7.0
container_name: node-exporter
ports:
- "9100:9100"
command:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
networks:
- monitoring
restart: unless-stopped
networks:
monitoring:
driver: bridge
volumes:
prometheus-data:
alertmanager-data:
grafana-data:
# Grafana 대시보드 Provisioning 설정
grafana/provisioning/dashboards/dashboard.yml
apiVersion: 1
providers:
- name: 'AI API Monitoring'
orgId: 1
folder: 'AI Services'
folderUid: 'ai-services'
type: file
disableDeletion: false
updateIntervalSeconds: 10
options:
path: /etc/grafana/provisioning/dashboards
---
grafana/provisioning/datasources/datasource.yml
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
editable: false
# grafana/provisioning/dashboards/ai-api.json (대시보드 정의)
{
"dashboard": {
"title": "AI API Monitoring - HolySheep",
"uid": "ai-api-monitor",
"timezone": "browser",
"panels": [
{
"title": "Request Rate (RPM)",
"type": "graph",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 0},
"targets": [
{
"expr": "sum(rate(ai_api_requests_total[1m])) by (model)",
"legendFormat": "{{model}}"
}
]
},
{
"title": "Response Time P50/P90/P99",
"type": "graph",
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 0},
"targets": [
{
"expr": "histogram_quantile(0.50, sum(rate(ai_api_response_seconds_bucket[5m])) by (le, model))",
"legendFormat": "P50 - {{model}}"
},
{
"expr": "histogram_quantile(0.90, sum(rate(ai_api_response_seconds_bucket[5m])) by (le, model))",
"legendFormat": "P90 - {{model}}"
},
{
"expr": "histogram_quantile(0.99, sum(rate(ai_api_response_seconds_bucket[5m])) by (le, model))",
"legendFormat": "P99 - {{model}}"
}
]
},
{
"title": "Error Rate by Type",
"type": "piechart",
"gridPos": {"h": 8, "w": 8, "x": 0, "y": 8},
"targets": [
{
"expr": "sum(increase(ai_api_requests_total{status_code=\"error\"}[1h])) by (error_type)"
}
]
},
{
"title": "API Cost (24h)",
"type": "stat",
"gridPos": {"h": 8, "w": 8, "x": 8, "y": 8},
"targets": [
{
"expr": "sum(increase(ai_api_cost_dollars[24h]))"
}
],
"fieldConfig": {
"defaults": {
"unit": "currencyUSD"
}
}
},
{
"title": "Token Usage (Input/Output)",
"type": "bargauge",
"gridPos": {"h": 8, "w": 8, "x": 16, "y": 8},
"targets": [
{
"expr": "sum(increase(ai_api_tokens_total[24h])) by (token_type)"
}
]
},
{
"title": "Active Requests",
"type": "gauge",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 16},
"targets": [
{
"expr": "sum(ai_api_active_requests) by (model)"
}
],
"fieldConfig": {
"defaults": {
"thresholds": {
"mode": "absolute",
"steps": [
{"value": 0, "color": "green"},
{"value": 20, "color": "yellow"},
{"value": 50, "color": "red"}
]
}
}
}
}
],
"refresh": "10s",
"schemaVersion": 30,
"version": 1
}
}
# 실행 명령어
전체 스택 시작
docker-compose up -d
로그 확인
docker-compose logs -f ai-service prometheus alertmanager
Prometheus Targets 확인
curl -s http://localhost:9090/api/v1/targets | jq '.data.activeTargets'
Alertmanager 상태 확인
curl -s http://localhost:9093/api/v1/status | jq '.data'
Grafana 접속 (기본 계정: admin/admin)
echo "Grafana: http://localhost:3000"
echo "Prometheus: http://localhost:9090"
echo "Alertmanager: http://localhost:9093"
echo "API Service: http://localhost:8000"
echo "Metrics: http://localhost:8000/metrics"
자주 발생하는 오류와 해결책
오류 1: "Connection refused" - Prometheus가 메트릭을 수집하지 못함
# 증상: Prometheus 로그에 아래 오류 발생
level=error ts=