diff --git a/examples/grafana/dashboard.json b/examples/grafana/dashboard.json new file mode 100644 index 0000000..9af6a16 --- /dev/null +++ b/examples/grafana/dashboard.json @@ -0,0 +1,902 @@ +{ + "annotations": { + "list": [ + { + "name": "429 Rate Limits", + "datasource": { + "type": "loki", + "uid": "loki" + }, + "enable": true, + "iconColor": "red", + "expr": "{service_name=\"anthropic-proxy\"} |= \"upstream error\" | json | status = \"429\"", + "titleFormat": "429 Rate Limited", + "textFormat": "{{error_message}}" + } + ] + }, + "editable": true, + "graphTooltip": 1, + "links": [], + "templating": { + "list": [ + { + "name": "window_age_5h", + "type": "query", + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "query": "query_result(time() - proxy_usage_resets_at{window=\"5h\"} + 18000)", + "regex": "/.* (\\d+\\.?\\d*) .*/", + "refresh": 2, + "hide": 2 + }, + { + "name": "window_age_7d", + "type": "query", + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "query": "query_result(time() - proxy_usage_resets_at{window=\"7d\"} + 604800)", + "regex": "/.* (\\d+\\.?\\d*) .*/", + "refresh": 2, + "hide": 2 + } + ] + }, + "panels": [ + { + "title": "5h Utilization", + "type": "gauge", + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 0 + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "thresholds": { + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 60 + }, + { + "color": "orange", + "value": 80 + }, + { + "color": "red", + "value": 95 + } + ] + } + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "showThresholdLabels": false + }, + "targets": [ + { + "expr": "proxy_usage_utilization{window=\"5h\"}", + "legendFormat": "5h", + "refId": "A" + } + ] + }, + { + "title": "7d Utilization", + "type": "gauge", + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 0 + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "thresholds": { + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 60 + }, + { + "color": "orange", + "value": 80 + }, + { + "color": "red", + "value": 95 + } + ] + } + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "showThresholdLabels": false + }, + "targets": [ + { + "expr": "proxy_usage_utilization{window=\"7d\"}", + "legendFormat": "7d", + "refId": "A" + } + ] + }, + { + "title": "Window Tokens In", + "description": "Input tokens in current Anthropic rate limit windows. Resets when window rolls over.", + "type": "stat", + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 0 + }, + "datasource": { + "type": "loki", + "uid": "loki" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "color": { + "mode": "fixed", + "fixedColor": "blue" + } + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "colorMode": "background", + "graphMode": "area", + "textMode": "auto" + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "loki" + }, + "expr": "sum(sum_over_time({service_name=\"anthropic-proxy\"} |= \"completed\" | unwrap input_tokens | __error__=\"\" [${window_age_5h}s]))", + "legendFormat": "5h window", + "refId": "A" + }, + { + "datasource": { + "type": "loki", + "uid": "loki" + }, + "expr": "sum(sum_over_time({service_name=\"anthropic-proxy\"} |= \"completed\" | unwrap input_tokens | __error__=\"\" [${window_age_7d}s]))", + "legendFormat": "7d window", + "refId": "B" + } + ] + }, + { + "title": "Window Tokens Out", + "description": "Output tokens in current Anthropic rate limit windows. Resets when window rolls over.", + "type": "stat", + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 0 + }, + "datasource": { + "type": "loki", + "uid": "loki" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "color": { + "mode": "fixed", + "fixedColor": "green" + } + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "colorMode": "background", + "graphMode": "area", + "textMode": "auto" + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "loki" + }, + "expr": "sum(sum_over_time({service_name=\"anthropic-proxy\"} |= \"completed\" | unwrap output_tokens | __error__=\"\" [${window_age_5h}s]))", + "legendFormat": "5h window", + "refId": "A" + }, + { + "datasource": { + "type": "loki", + "uid": "loki" + }, + "expr": "sum(sum_over_time({service_name=\"anthropic-proxy\"} |= \"completed\" | unwrap output_tokens | __error__=\"\" [${window_age_7d}s]))", + "legendFormat": "7d window", + "refId": "B" + } + ] + }, + { + "title": "Utilization Over Time", + "type": "timeseries", + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 6 + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "fillOpacity": 15, + "lineWidth": 2, + "thresholdsStyle": { + "mode": "line" + } + }, + "unit": "percent", + "min": 0, + "max": 100, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 60 + }, + { + "color": "orange", + "value": 80 + }, + { + "color": "red", + "value": 95 + } + ] + } + }, + "overrides": [] + }, + "targets": [ + { + "expr": "proxy_usage_utilization{window=\"5h\"}", + "legendFormat": "5h utilization", + "refId": "A" + }, + { + "expr": "proxy_usage_utilization{window=\"7d\"}", + "legendFormat": "7d utilization", + "refId": "B" + } + ] + }, + { + "type": "timeseries", + "title": "5h Window Tokens", + "datasource": { + "type": "loki", + "uid": "loki" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 100, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "loki" + }, + "expr": "sum(sum_over_time({service_name=\"anthropic-proxy\"} |= \"completed\" | unwrap output_tokens | __error__=\"\" [$__interval]))", + "legendFormat": "output", + "refId": "A" + } + ], + "timeFrom": "${window_age_5h}s", + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "fillOpacity": 20, + "lineWidth": 2, + "stacking": { + "mode": "none" + }, + "pointSize": 1, + "spanNulls": true + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "input" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "output" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "transformations": [ + { + "id": "calculateField", + "options": { + "mode": "cumulativeFunctions", + "cumulative": { + "field": "Value", + "reducer": "sum" + }, + "alias": "output total", + "replaceFields": true + } + } + ], + "options": { + "tooltip": { + "mode": "multi" + } + }, + "hideTimeOverride": true + }, + { + "type": "timeseries", + "title": "7d Window Tokens", + "datasource": { + "type": "loki", + "uid": "loki" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 101, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "loki" + }, + "expr": "sum(sum_over_time({service_name=\"anthropic-proxy\"} |= \"completed\" | unwrap output_tokens | __error__=\"\" [$__interval]))", + "legendFormat": "output", + "refId": "A" + } + ], + "timeFrom": "${window_age_7d}s", + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "fillOpacity": 20, + "lineWidth": 2, + "stacking": { + "mode": "none" + }, + "pointSize": 1, + "spanNulls": true + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "input" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "output" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + } + ] + }, + "transformations": [ + { + "id": "calculateField", + "options": { + "mode": "cumulativeFunctions", + "cumulative": { + "field": "Value", + "reducer": "sum" + }, + "alias": "output total", + "replaceFields": true + } + } + ], + "options": { + "tooltip": { + "mode": "multi" + } + }, + "hideTimeOverride": true + }, + { + "title": "Request Rate", + "type": "timeseries", + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 14 + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "fillOpacity": 15, + "lineWidth": 2 + }, + "unit": "reqps" + }, + "overrides": [] + }, + "targets": [ + { + "expr": "sum(rate(proxy_request_count_total[5m])) by (stream)", + "legendFormat": "stream={{stream}}", + "refId": "A" + }, + { + "expr": "sum(rate(proxy_request_count_total[5m]))", + "legendFormat": "total", + "refId": "B" + } + ] + }, + { + "title": "Error Rate", + "type": "timeseries", + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 22 + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "fillOpacity": 15, + "lineWidth": 2 + }, + "unit": "reqps" + }, + "overrides": [] + }, + "targets": [ + { + "expr": "sum(rate(proxy_upstream_errors_total[5m])) by (error_type)", + "legendFormat": "{{error_type}}", + "refId": "A" + }, + { + "expr": "sum(rate(proxy_request_count_total{status_code=~\"4..|5..\"}[5m])) by (status_code)", + "legendFormat": "HTTP {{status_code}}", + "refId": "B" + } + ] + }, + { + "title": "Request Latency (p50/p95/p99)", + "type": "timeseries", + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 30 + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "fillOpacity": 10, + "lineWidth": 2 + }, + "unit": "ms" + }, + "overrides": [] + }, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(rate(proxy_request_duration_ms_milliseconds_bucket[5m])) by (le))", + "legendFormat": "p50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(proxy_request_duration_ms_milliseconds_bucket[5m])) by (le))", + "legendFormat": "p95", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(proxy_request_duration_ms_milliseconds_bucket[5m])) by (le))", + "legendFormat": "p99", + "refId": "C" + } + ] + }, + { + "title": "Requests by Status Code", + "type": "timeseries", + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 30 + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "bars", + "fillOpacity": 50, + "lineWidth": 1, + "stacking": { + "mode": "normal" + } + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "2.." + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "4.." + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "5.." + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "targets": [ + { + "expr": "sum(rate(proxy_request_count_total[5m])) by (status_code) * 60", + "legendFormat": "{{status_code}}", + "refId": "A" + } + ] + }, + { + "title": "Total Requests", + "type": "stat", + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 43 + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "unit": "short" + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "colorMode": "background", + "graphMode": "area" + }, + "targets": [ + { + "expr": "sum(proxy_request_count_total)", + "legendFormat": "requests", + "refId": "A" + } + ] + }, + { + "title": "Credential Cooldowns", + "type": "stat", + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 43 + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "thresholds": { + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "red", + "value": 5 + } + ] + } + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "colorMode": "background", + "graphMode": "none" + }, + "targets": [ + { + "expr": "sum(proxy_credential_cooldowns_total) or vector(0)", + "legendFormat": "cooldowns", + "refId": "A" + } + ] + }, + { + "title": "Tokens by Model", + "type": "timeseries", + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 47 + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "bars", + "fillOpacity": 50, + "lineWidth": 1, + "stacking": { + "mode": "normal" + } + }, + "unit": "short" + }, + "overrides": [] + }, + "targets": [ + { + "expr": "sum(rate(proxy_tokens_input_total[5m])) by (model) * 60", + "legendFormat": "in: {{model}}", + "refId": "A" + }, + { + "expr": "sum(rate(proxy_tokens_output_total[5m])) by (model) * 60", + "legendFormat": "out: {{model}}", + "refId": "B" + } + ] + }, + { + "title": "Request Body Size (p50/p95)", + "type": "timeseries", + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 47 + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "fillOpacity": 10, + "lineWidth": 2 + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(rate(proxy_request_body_size_bytes_bucket[5m])) by (le))", + "legendFormat": "p50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(proxy_request_body_size_bytes_bucket[5m])) by (le))", + "legendFormat": "p95", + "refId": "B" + } + ] + } + ], + "refresh": "30s", + "schemaVersion": 39, + "tags": [ + "anthropic-proxy", + "otel" + ], + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Anthropic Proxy", + "uid": "anthropic-proxy" +}