{
  "annotations": {
    "list": [
      {
        "builtIn": 1,
        "datasource": {
          "type": "grafana",
          "uid": "-- Grafana --"
        },
        "enable": true,
        "hide": true,
        "iconColor": "rgba(0, 211, 255, 1)",
        "name": "Annotations & Alerts",
        "type": "dashboard"
      }
    ]
  },
  "editable": true,
  "fiscalYearStartMonth": 0,
  "graphTooltip": 1,
  "id": null,
  "links": [],
  "liveNow": false,
  "panels": [
    {
      "id": 1,
      "type": "row",
      "title": "Overview",
      "collapsed": false,
      "gridPos": {
        "h": 1,
        "w": 24,
        "x": 0,
        "y": 0
      },
      "panels": []
    },
    {
      "id": 2,
      "type": "stat",
      "title": "Request Rate (SUCCESS/ERROR/BLOCKED)",
      "description": "Total AI request rate from the always-on gateway counter apinizer_ai_requests_total_count, split by status.",
      "datasource": {
        "type": "prometheus",
        "uid": "${prometheus_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds",
            "fixedColor": "blue"
          },
          "unit": "reqps",
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 6,
        "w": 6,
        "x": 0,
        "y": 1
      },
      "options": {
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "orientation": "auto",
        "textMode": "auto",
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto"
      },
      "targets": [
        {
          "expr": "sum(rate(apinizer_ai_requests_total_count{provider=~\"$provider\",model=~\"$model\",projectId=~\"$project\"}[5m]))",
          "legendFormat": "req/s",
          "refId": "A"
        }
      ]
    },
    {
      "id": 3,
      "type": "stat",
      "title": "Error Rate %",
      "description": "Share of AI requests with status=ERROR over the last 5m window.",
      "datasource": {
        "type": "prometheus",
        "uid": "${prometheus_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds",
            "fixedColor": "blue"
          },
          "unit": "percent",
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "orange",
                "value": 1
              },
              {
                "color": "red",
                "value": 5
              }
            ]
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 6,
        "w": 6,
        "x": 6,
        "y": 1
      },
      "options": {
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "orientation": "auto",
        "textMode": "auto",
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto"
      },
      "targets": [
        {
          "expr": "100 * sum(rate(apinizer_ai_requests_total_count{status=\"ERROR\",provider=~\"$provider\",model=~\"$model\",projectId=~\"$project\"}[5m])) / sum(rate(apinizer_ai_requests_total_count{provider=~\"$provider\",model=~\"$model\",projectId=~\"$project\"}[5m]))",
          "legendFormat": "error %",
          "refId": "A"
        }
      ]
    },
    {
      "id": 4,
      "type": "stat",
      "title": "Avg Total Latency",
      "description": "sum(rate(_sum))/sum(rate(_count)) over apinizer_ai_latency_total_time — this Timer is NOT a percentile histogram (no bucket data), so only avg/max are meaningful here. For true p50/p95/p99 use the OTLP panel below.",
      "datasource": {
        "type": "prometheus",
        "uid": "${prometheus_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds",
            "fixedColor": "blue"
          },
          "unit": "s",
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 6,
        "w": 6,
        "x": 12,
        "y": 1
      },
      "options": {
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "orientation": "auto",
        "textMode": "auto",
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto"
      },
      "targets": [
        {
          "expr": "sum(rate(apinizer_ai_latency_total_time_seconds_sum{provider=~\"$provider\",model=~\"$model\"}[5m])) / sum(rate(apinizer_ai_latency_total_time_seconds_count{provider=~\"$provider\",model=~\"$model\"}[5m]))",
          "legendFormat": "avg",
          "refId": "A"
        }
      ]
    },
    {
      "id": 5,
      "type": "stat",
      "title": "Max Total Latency (worst-case)",
      "description": "max(apinizer_ai_latency_total_time_seconds_max) — worst single request in the window, per Timer's own max tracking.",
      "datasource": {
        "type": "prometheus",
        "uid": "${prometheus_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds",
            "fixedColor": "blue"
          },
          "unit": "s",
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 6,
        "w": 6,
        "x": 18,
        "y": 1
      },
      "options": {
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "orientation": "auto",
        "textMode": "auto",
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto"
      },
      "targets": [
        {
          "expr": "max(apinizer_ai_latency_total_time_seconds_max{provider=~\"$provider\",model=~\"$model\"})",
          "legendFormat": "max",
          "refId": "A"
        }
      ]
    },
    {
      "id": 6,
      "type": "timeseries",
      "title": "Request Rate by Status",
      "description": "sum by (status) (rate(apinizer_ai_requests_total_count[5m])) — SUCCESS/ERROR/BLOCKED breakdown.",
      "datasource": {
        "type": "prometheus",
        "uid": "${prometheus_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "drawStyle": "line",
            "lineWidth": 1,
            "fillOpacity": 12,
            "pointSize": 5,
            "showPoints": "never",
            "spanNulls": false,
            "stacking": {
              "mode": "normal",
              "group": "A"
            }
          },
          "unit": "reqps"
        },
        "overrides": [
          {
            "matcher": {
              "id": "byName",
              "options": "SUCCESS"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "green"
                }
              }
            ]
          },
          {
            "matcher": {
              "id": "byName",
              "options": "ERROR"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "red"
                }
              }
            ]
          },
          {
            "matcher": {
              "id": "byName",
              "options": "BLOCKED"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "orange"
                }
              }
            ]
          }
        ]
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 7
      },
      "options": {
        "legend": {
          "displayMode": "table",
          "placement": "bottom",
          "calcs": [
            "lastNotNull",
            "mean",
            "max"
          ]
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "expr": "sum by (status) (rate(apinizer_ai_requests_total_count{provider=~\"$provider\",model=~\"$model\",projectId=~\"$project\"}[5m]))",
          "legendFormat": "{{status}}",
          "refId": "A"
        }
      ]
    },
    {
      "id": 7,
      "type": "timeseries",
      "title": "Latency Percentiles — p50/p95/p99 (OTLP gen_ai.client.operation.duration)",
      "description": "True percentiles require a real bucketed histogram. apinizer_ai_latency_total_time (Prometheus family) has no buckets; the OTLP gen_ai.client.operation.duration Histogram does. Assumes the collector/backend preserves classic (explicit-bucket) histograms end to end — adjust the query if your backend uses native/exponential histograms instead.",
      "datasource": {
        "type": "prometheus",
        "uid": "${otlp_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "drawStyle": "line",
            "lineWidth": 1,
            "fillOpacity": 4,
            "pointSize": 5,
            "showPoints": "never",
            "spanNulls": false,
            "stacking": {
              "mode": "none",
              "group": "A"
            }
          },
          "unit": "s"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 7
      },
      "options": {
        "legend": {
          "displayMode": "table",
          "placement": "bottom",
          "calcs": [
            "lastNotNull",
            "mean",
            "max"
          ]
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "expr": "histogram_quantile(0.50, sum(rate(gen_ai_client_operation_duration_seconds_bucket{gen_ai_provider_name=~\"$provider\"}[5m])) by (le))",
          "legendFormat": "p50",
          "refId": "A"
        },
        {
          "expr": "histogram_quantile(0.95, sum(rate(gen_ai_client_operation_duration_seconds_bucket{gen_ai_provider_name=~\"$provider\"}[5m])) by (le))",
          "legendFormat": "p95",
          "refId": "B"
        },
        {
          "expr": "histogram_quantile(0.99, sum(rate(gen_ai_client_operation_duration_seconds_bucket{gen_ai_provider_name=~\"$provider\"}[5m])) by (le))",
          "legendFormat": "p99",
          "refId": "C"
        }
      ]
    },
    {
      "id": 8,
      "type": "row",
      "title": "Tokens",
      "collapsed": false,
      "gridPos": {
        "h": 1,
        "w": 24,
        "x": 0,
        "y": 15
      },
      "panels": []
    },
    {
      "id": 9,
      "type": "timeseries",
      "title": "Token Rate — Input / Output / Cached",
      "description": "rate() over the three apinizer_ai_tokens_*_total counters (prompt-cache 'cached' tokens are a subset of what the provider billed as input — see the Cache row for cache-specific panels).",
      "datasource": {
        "type": "prometheus",
        "uid": "${prometheus_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "drawStyle": "line",
            "lineWidth": 1,
            "fillOpacity": 4,
            "pointSize": 5,
            "showPoints": "never",
            "spanNulls": false,
            "stacking": {
              "mode": "none",
              "group": "A"
            }
          },
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 16
      },
      "options": {
        "legend": {
          "displayMode": "table",
          "placement": "bottom",
          "calcs": [
            "lastNotNull",
            "mean",
            "max"
          ]
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "expr": "sum(rate(apinizer_ai_tokens_input_total{provider=~\"$provider\",model=~\"$model\",projectId=~\"$project\"}[5m]))",
          "legendFormat": "input",
          "refId": "A"
        },
        {
          "expr": "sum(rate(apinizer_ai_tokens_output_total{provider=~\"$provider\",model=~\"$model\",projectId=~\"$project\"}[5m]))",
          "legendFormat": "output",
          "refId": "B"
        },
        {
          "expr": "sum(rate(apinizer_ai_tokens_cached_total{provider=~\"$provider\",model=~\"$model\",projectId=~\"$project\"}[5m]))",
          "legendFormat": "cached",
          "refId": "C"
        }
      ]
    },
    {
      "id": 10,
      "type": "bargauge",
      "title": "Top 10 Models by Token Volume (1h)",
      "description": "topk(10, sum by (model) (increase(input_total) + increase(output_total))) over the last hour.",
      "datasource": {
        "type": "prometheus",
        "uid": "${prometheus_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "unit": "short",
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "blue",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 16
      },
      "options": {
        "displayMode": "gradient",
        "orientation": "horizontal",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "showUnfilled": true
      },
      "targets": [
        {
          "expr": "topk(10, sum by (model) (increase(apinizer_ai_tokens_input_total{provider=~\"$provider\",projectId=~\"$project\"}[1h]) + increase(apinizer_ai_tokens_output_total{provider=~\"$provider\",projectId=~\"$project\"}[1h])))",
          "legendFormat": "{{model}}",
          "refId": "A",
          "instant": true
        }
      ]
    },
    {
      "id": 11,
      "type": "row",
      "title": "Cost",
      "collapsed": false,
      "gridPos": {
        "h": 1,
        "w": 24,
        "x": 0,
        "y": 24
      },
      "panels": []
    },
    {
      "id": 12,
      "type": "stat",
      "title": "Cost — Last Hour (USD)",
      "description": "increase(apinizer_ai_cost_micro_usd_total[1h]) / 1e6 — micro-USD counter converted to USD.",
      "datasource": {
        "type": "prometheus",
        "uid": "${prometheus_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds",
            "fixedColor": "blue"
          },
          "unit": "currencyUSD",
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 6,
        "w": 6,
        "x": 0,
        "y": 25
      },
      "options": {
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "orientation": "auto",
        "textMode": "auto",
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto"
      },
      "targets": [
        {
          "expr": "sum(increase(apinizer_ai_cost_micro_usd_total{provider=~\"$provider\",model=~\"$model\",projectId=~\"$project\"}[1h])) / 1e6",
          "legendFormat": "USD/h",
          "refId": "A"
        }
      ]
    },
    {
      "id": 13,
      "type": "timeseries",
      "title": "Cost Rate by Provider (USD/hour)",
      "description": "sum by (provider) (rate(apinizer_ai_cost_micro_usd_total[5m])) / 1e6 * 3600 — hourly-normalized cost rate, stacked by provider.",
      "datasource": {
        "type": "prometheus",
        "uid": "${prometheus_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "drawStyle": "line",
            "lineWidth": 1,
            "fillOpacity": 12,
            "pointSize": 5,
            "showPoints": "never",
            "spanNulls": false,
            "stacking": {
              "mode": "normal",
              "group": "A"
            }
          },
          "unit": "currencyUSD"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 6,
        "w": 18,
        "x": 6,
        "y": 25
      },
      "options": {
        "legend": {
          "displayMode": "table",
          "placement": "bottom",
          "calcs": [
            "lastNotNull",
            "mean",
            "max"
          ]
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "expr": "sum by (provider) (rate(apinizer_ai_cost_micro_usd_total{model=~\"$model\",projectId=~\"$project\"}[5m])) / 1e6 * 3600",
          "legendFormat": "{{provider}}",
          "refId": "A"
        }
      ]
    },
    {
      "id": 14,
      "type": "table",
      "title": "Cost by Project — Last 24h (USD)",
      "description": "sum by (projectId) (increase(apinizer_ai_cost_micro_usd_total[24h])) / 1e6, sorted descending.",
      "datasource": {
        "type": "prometheus",
        "uid": "${prometheus_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "unit": "currencyUSD",
          "custom": {
            "align": "auto",
            "cellOptions": {
              "type": "auto"
            }
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 7,
        "w": 24,
        "x": 0,
        "y": 31
      },
      "options": {
        "showHeader": true,
        "cellHeight": "sm"
      },
      "targets": [
        {
          "expr": "sort_desc(sum by (projectId) (increase(apinizer_ai_cost_micro_usd_total{provider=~\"$provider\",model=~\"$model\"}[24h])) / 1e6)",
          "legendFormat": "",
          "refId": "A",
          "instant": true
        }
      ],
      "transformations": [
        {
          "id": "labelsToFields",
          "options": {}
        }
      ]
    },
    {
      "id": 15,
      "type": "row",
      "title": "Streaming",
      "collapsed": false,
      "gridPos": {
        "h": 1,
        "w": 24,
        "x": 0,
        "y": 38
      },
      "panels": []
    },
    {
      "id": 16,
      "type": "timeseries",
      "title": "TTFT Percentiles — p50/p95/p99 (OTLP)",
      "description": "histogram_quantile over apinizer.ai.client.ttft (OTel Histogram, seconds). Only populated for streaming requests (TTFT=0/absent on unary calls is never recorded — see AiOtelMetrics.record).",
      "datasource": {
        "type": "prometheus",
        "uid": "${otlp_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "drawStyle": "line",
            "lineWidth": 1,
            "fillOpacity": 4,
            "pointSize": 5,
            "showPoints": "never",
            "spanNulls": false,
            "stacking": {
              "mode": "none",
              "group": "A"
            }
          },
          "unit": "s"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 39
      },
      "options": {
        "legend": {
          "displayMode": "table",
          "placement": "bottom",
          "calcs": [
            "lastNotNull",
            "mean",
            "max"
          ]
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "expr": "histogram_quantile(0.50, sum(rate(apinizer_ai_client_ttft_seconds_bucket{gen_ai_provider_name=~\"$provider\"}[5m])) by (le))",
          "legendFormat": "p50",
          "refId": "A"
        },
        {
          "expr": "histogram_quantile(0.95, sum(rate(apinizer_ai_client_ttft_seconds_bucket{gen_ai_provider_name=~\"$provider\"}[5m])) by (le))",
          "legendFormat": "p95",
          "refId": "B"
        },
        {
          "expr": "histogram_quantile(0.99, sum(rate(apinizer_ai_client_ttft_seconds_bucket{gen_ai_provider_name=~\"$provider\"}[5m])) by (le))",
          "legendFormat": "p99",
          "refId": "C"
        }
      ]
    },
    {
      "id": 17,
      "type": "timeseries",
      "title": "TPOT Percentiles — p50/p95/p99 (OTLP)",
      "description": "histogram_quantile over apinizer.ai.client.tpot (OTel Histogram, seconds). Streaming-only, same gate as TTFT.",
      "datasource": {
        "type": "prometheus",
        "uid": "${otlp_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "drawStyle": "line",
            "lineWidth": 1,
            "fillOpacity": 4,
            "pointSize": 5,
            "showPoints": "never",
            "spanNulls": false,
            "stacking": {
              "mode": "none",
              "group": "A"
            }
          },
          "unit": "s"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 39
      },
      "options": {
        "legend": {
          "displayMode": "table",
          "placement": "bottom",
          "calcs": [
            "lastNotNull",
            "mean",
            "max"
          ]
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "expr": "histogram_quantile(0.50, sum(rate(apinizer_ai_client_tpot_seconds_bucket{gen_ai_provider_name=~\"$provider\"}[5m])) by (le))",
          "legendFormat": "p50",
          "refId": "A"
        },
        {
          "expr": "histogram_quantile(0.95, sum(rate(apinizer_ai_client_tpot_seconds_bucket{gen_ai_provider_name=~\"$provider\"}[5m])) by (le))",
          "legendFormat": "p95",
          "refId": "B"
        },
        {
          "expr": "histogram_quantile(0.99, sum(rate(apinizer_ai_client_tpot_seconds_bucket{gen_ai_provider_name=~\"$provider\"}[5m])) by (le))",
          "legendFormat": "p99",
          "refId": "C"
        }
      ]
    },
    {
      "id": 18,
      "type": "text",
      "title": "Prometheus-family fallback (no OTLP export configured)",
      "gridPos": {
        "h": 4,
        "w": 24,
        "x": 0,
        "y": 47
      },
      "options": {
        "mode": "markdown",
        "content": "If native OTLP export (Environment > OpenTelemetry Export > mode=NATIVE) is not enabled, approximate TTFT/TPOT with the Prometheus family instead — averages only, no percentiles:\n\n```promql\nsum(rate(apinizer_ai_latency_ttft_time_seconds_sum[5m])) / sum(rate(apinizer_ai_latency_ttft_time_seconds_count[5m]))\nsum(rate(apinizer_ai_latency_tpot_time_seconds_sum[5m])) / sum(rate(apinizer_ai_latency_tpot_time_seconds_count[5m]))\n```"
      },
      "transparent": false
    },
    {
      "id": 19,
      "type": "row",
      "title": "Guardrail",
      "collapsed": false,
      "gridPos": {
        "h": 1,
        "w": 24,
        "x": 0,
        "y": 51
      },
      "panels": []
    },
    {
      "id": 20,
      "type": "timeseries",
      "title": "External Guardrail Verdicts",
      "description": "sum by (verdict) (rate(apinizer_ai_guardrail_external_total[5m])) — SAFE/UNSAFE/TIMEOUT/ERROR/SKIP, from the external (LLM-judge / third-party) guardrail adapter path only; built-in guardrail hits are not on this counter.",
      "datasource": {
        "type": "prometheus",
        "uid": "${prometheus_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "drawStyle": "line",
            "lineWidth": 1,
            "fillOpacity": 12,
            "pointSize": 5,
            "showPoints": "never",
            "spanNulls": false,
            "stacking": {
              "mode": "normal",
              "group": "A"
            }
          },
          "unit": "short"
        },
        "overrides": [
          {
            "matcher": {
              "id": "byName",
              "options": "SAFE"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "green"
                }
              }
            ]
          },
          {
            "matcher": {
              "id": "byName",
              "options": "UNSAFE"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "red"
                }
              }
            ]
          },
          {
            "matcher": {
              "id": "byName",
              "options": "TIMEOUT"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "orange"
                }
              }
            ]
          },
          {
            "matcher": {
              "id": "byName",
              "options": "ERROR"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "red"
                }
              }
            ]
          },
          {
            "matcher": {
              "id": "byName",
              "options": "SKIP"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "grey"
                }
              }
            ]
          }
        ]
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 52
      },
      "options": {
        "legend": {
          "displayMode": "table",
          "placement": "bottom",
          "calcs": [
            "lastNotNull",
            "mean",
            "max"
          ]
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "expr": "sum by (verdict) (rate(apinizer_ai_guardrail_external_total{projectId=~\"$project\"}[5m]))",
          "legendFormat": "{{verdict}}",
          "refId": "A"
        }
      ]
    },
    {
      "id": 21,
      "type": "timeseries",
      "title": "Fail-Open vs Fail-Closed Outcomes",
      "description": "sum by (outcome) (rate(apinizer_ai_guardrail_external_total[5m])) — PASSED/BLOCKED/FAIL_OPEN/FAIL_CLOSED/SKIPPED.",
      "datasource": {
        "type": "prometheus",
        "uid": "${prometheus_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "drawStyle": "line",
            "lineWidth": 1,
            "fillOpacity": 12,
            "pointSize": 5,
            "showPoints": "never",
            "spanNulls": false,
            "stacking": {
              "mode": "normal",
              "group": "A"
            }
          },
          "unit": "short"
        },
        "overrides": [
          {
            "matcher": {
              "id": "byName",
              "options": "PASSED"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "green"
                }
              }
            ]
          },
          {
            "matcher": {
              "id": "byName",
              "options": "BLOCKED"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "red"
                }
              }
            ]
          },
          {
            "matcher": {
              "id": "byName",
              "options": "FAIL_OPEN"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "orange"
                }
              }
            ]
          },
          {
            "matcher": {
              "id": "byName",
              "options": "FAIL_CLOSED"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "blue"
                }
              }
            ]
          },
          {
            "matcher": {
              "id": "byName",
              "options": "SKIPPED"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "grey"
                }
              }
            ]
          }
        ]
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 52
      },
      "options": {
        "legend": {
          "displayMode": "table",
          "placement": "bottom",
          "calcs": [
            "lastNotNull",
            "mean",
            "max"
          ]
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "expr": "sum by (outcome) (rate(apinizer_ai_guardrail_external_total{projectId=~\"$project\"}[5m]))",
          "legendFormat": "{{outcome}}",
          "refId": "A"
        }
      ]
    },
    {
      "id": 22,
      "type": "timeseries",
      "title": "Shadow-Mode Agreement (builtin vs external)",
      "description": "sum by (agreement) (rate(apinizer_ai_guardrail_shadow_agreement_total[5m])) — AGREE/DISAGREE/EXTERNAL_ERROR. Unbiased ONLY in SHADOW mode: in BUILTIN_PLUS_EXTERNAL a builtin BLOCK short-circuits the external call, so traffic the builtin already blocked never appears here (see AiOtelSemconvMapper/ApinizerMetricsService javadoc K6 bias note). Do not report this ratio as a general agreement rate outside SHADOW sampling.",
      "datasource": {
        "type": "prometheus",
        "uid": "${prometheus_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "drawStyle": "line",
            "lineWidth": 1,
            "fillOpacity": 12,
            "pointSize": 5,
            "showPoints": "never",
            "spanNulls": false,
            "stacking": {
              "mode": "normal",
              "group": "A"
            }
          },
          "unit": "short"
        },
        "overrides": [
          {
            "matcher": {
              "id": "byName",
              "options": "AGREE"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "green"
                }
              }
            ]
          },
          {
            "matcher": {
              "id": "byName",
              "options": "DISAGREE"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "red"
                }
              }
            ]
          },
          {
            "matcher": {
              "id": "byName",
              "options": "EXTERNAL_ERROR"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "orange"
                }
              }
            ]
          }
        ]
      },
      "gridPos": {
        "h": 8,
        "w": 24,
        "x": 0,
        "y": 60
      },
      "options": {
        "legend": {
          "displayMode": "table",
          "placement": "bottom",
          "calcs": [
            "lastNotNull",
            "mean",
            "max"
          ]
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "expr": "sum by (agreement) (rate(apinizer_ai_guardrail_shadow_agreement_total[5m]))",
          "legendFormat": "{{agreement}}",
          "refId": "A"
        }
      ]
    },
    {
      "id": 23,
      "type": "row",
      "title": "Cache",
      "collapsed": false,
      "gridPos": {
        "h": 1,
        "w": 24,
        "x": 0,
        "y": 68
      },
      "panels": []
    },
    {
      "id": 24,
      "type": "timeseries",
      "title": "Provider Prompt-Cache Token Rate",
      "description": "rate(apinizer_ai_tokens_cached_total[5m]) — provider-side prompt-cache tokens (e.g. Anthropic/OpenAI cached input). This is NOT Apinizer's semantic response cache — see the note panel below for that.",
      "datasource": {
        "type": "prometheus",
        "uid": "${prometheus_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "drawStyle": "line",
            "lineWidth": 1,
            "fillOpacity": 4,
            "pointSize": 5,
            "showPoints": "never",
            "spanNulls": false,
            "stacking": {
              "mode": "none",
              "group": "A"
            }
          },
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 69
      },
      "options": {
        "legend": {
          "displayMode": "table",
          "placement": "bottom",
          "calcs": [
            "lastNotNull",
            "mean",
            "max"
          ]
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "expr": "sum(rate(apinizer_ai_tokens_cached_total{provider=~\"$provider\",model=~\"$model\",projectId=~\"$project\"}[5m]))",
          "legendFormat": "cached tokens/s",
          "refId": "A"
        }
      ]
    },
    {
      "id": 25,
      "type": "stat",
      "title": "Cached Share of Input Tokens",
      "description": "cached / (cached + input) — share of input tokens served from the provider's prompt cache.",
      "datasource": {
        "type": "prometheus",
        "uid": "${prometheus_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds",
            "fixedColor": "blue"
          },
          "unit": "percentunit",
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 69
      },
      "options": {
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "orientation": "auto",
        "textMode": "auto",
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto"
      },
      "targets": [
        {
          "expr": "sum(rate(apinizer_ai_tokens_cached_total{provider=~\"$provider\",model=~\"$model\",projectId=~\"$project\"}[5m])) / (sum(rate(apinizer_ai_tokens_cached_total{provider=~\"$provider\",model=~\"$model\",projectId=~\"$project\"}[5m])) + sum(rate(apinizer_ai_tokens_input_total{provider=~\"$provider\",model=~\"$model\",projectId=~\"$project\"}[5m])))",
          "legendFormat": "cached share",
          "refId": "A"
        }
      ]
    },
    {
      "id": 26,
      "type": "text",
      "title": "Semantic cache hit-rate & cost avoided — not a metric today",
      "gridPos": {
        "h": 4,
        "w": 24,
        "x": 0,
        "y": 77
      },
      "options": {
        "mode": "markdown",
        "content": "Apinizer's own semantic response cache (`PolicyAiSemanticCache`) hit/miss signal exists as the span attribute `apinizer.ai.cache.hit` (root AI span, native OTLP export) and in the AI Gateway's Reports/Analytics screens (ES-backed cache-efficiency report) — it is **not** exposed as a dedicated Prometheus or OTLP counter yet, so no PromQL panel can show hit-rate or cost-avoided honestly. Use the AI Trace timeline (filter by `apinizer.ai.cache.hit=true`) or the in-product cache-efficiency report for that view."
      },
      "transparent": false
    },
    {
      "id": 27,
      "type": "row",
      "title": "Reliability",
      "collapsed": false,
      "gridPos": {
        "h": 1,
        "w": 24,
        "x": 0,
        "y": 81
      },
      "panels": []
    },
    {
      "id": 28,
      "type": "timeseries",
      "title": "Request Outcome Breakdown",
      "description": "sum by (status) (rate(apinizer_ai_requests_total_count[5m])) — the closest available reliability signal to a 'success vs failure' view. Not a failover-path breakdown (see note panel below).",
      "datasource": {
        "type": "prometheus",
        "uid": "${prometheus_ds}"
      },
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "drawStyle": "line",
            "lineWidth": 1,
            "fillOpacity": 12,
            "pointSize": 5,
            "showPoints": "never",
            "spanNulls": false,
            "stacking": {
              "mode": "normal",
              "group": "A"
            }
          },
          "unit": "reqps"
        },
        "overrides": [
          {
            "matcher": {
              "id": "byName",
              "options": "SUCCESS"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "green"
                }
              }
            ]
          },
          {
            "matcher": {
              "id": "byName",
              "options": "ERROR"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "red"
                }
              }
            ]
          },
          {
            "matcher": {
              "id": "byName",
              "options": "BLOCKED"
            },
            "properties": [
              {
                "id": "color",
                "value": {
                  "mode": "fixed",
                  "fixedColor": "orange"
                }
              }
            ]
          }
        ]
      },
      "gridPos": {
        "h": 8,
        "w": 24,
        "x": 0,
        "y": 82
      },
      "options": {
        "legend": {
          "displayMode": "table",
          "placement": "bottom",
          "calcs": [
            "lastNotNull",
            "mean",
            "max"
          ]
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "expr": "sum by (status) (rate(apinizer_ai_requests_total_count{provider=~\"$provider\",model=~\"$model\",projectId=~\"$project\"}[5m]))",
          "legendFormat": "{{status}}",
          "refId": "A"
        }
      ]
    },
    {
      "id": 29,
      "type": "text",
      "title": "Failover from→to & VectorDB skip — not a metric today",
      "gridPos": {
        "h": 4,
        "w": 24,
        "x": 0,
        "y": 90
      },
      "options": {
        "mode": "markdown",
        "content": "Per-attempt failover routing (`apinizer.ai.failover.from` on the CLIENT leg spans) and VectorDB-skip events (policy-execution spans, Live Trace only, `emitPolicySpans=true`) are span/trace-level signals with no corresponding Prometheus or OTLP counter — a from→to breakdown cannot be built as a PromQL panel today. Inspect them via the AI Trace timeline UI or a TraceQL query against the OTLP trace backend (e.g. Tempo) on the `apinizer.ai.failover.from` attribute."
      },
      "transparent": false
    }
  ],
  "refresh": "30s",
  "schemaVersion": 39,
  "tags": [
    "apinizer",
    "ai-gateway",
    "genai",
    "otel"
  ],
  "templating": {
    "list": [
      {
        "current": {},
        "hide": 0,
        "includeAll": false,
        "label": "Gateway Prometheus (apinizer_ai_*)",
        "multi": false,
        "name": "prometheus_ds",
        "options": [],
        "query": "prometheus",
        "queryValue": "",
        "refresh": 1,
        "regex": "",
        "skipUrlSync": false,
        "type": "datasource"
      },
      {
        "current": {},
        "hide": 0,
        "includeAll": false,
        "label": "OTLP-backed metrics store (gen_ai.*)",
        "multi": false,
        "name": "otlp_ds",
        "options": [],
        "query": "prometheus",
        "queryValue": "",
        "refresh": 1,
        "regex": "",
        "skipUrlSync": false,
        "type": "datasource",
        "description": "A Prometheus-compatible backend fed by an OTel Collector receiving Apinizer's native OTLP export (e.g. Grafana Mimir, or Prometheus behind the collector's prometheusremotewrite exporter). Not Tempo — traces and metrics are separate signals even though both originate from the same OTLP export."
      },
      {
        "allValue": ".*",
        "current": {
          "text": "All",
          "value": "$__all"
        },
        "datasource": {
          "type": "prometheus",
          "uid": "${prometheus_ds}"
        },
        "definition": "label_values(apinizer_ai_requests_total_count, provider)",
        "hide": 0,
        "includeAll": true,
        "label": "Provider (Prometheus-family value)",
        "multi": true,
        "name": "provider",
        "options": [],
        "query": {
          "query": "label_values(apinizer_ai_requests_total_count, provider)",
          "refId": "provider"
        },
        "refresh": 2,
        "regex": "",
        "skipUrlSync": false,
        "sort": 1,
        "type": "query",
        "description": "Values come from the raw apinizer providerCode (e.g. \"bedrock\", \"vertex\"). The OTLP-family gen_ai.provider.name label uses the normalized OTel well-known name instead (e.g. \"aws.bedrock\", \"gcp.vertex_ai\") — see the OpenTelemetry docs page's provider-name mapping table before reusing this variable's raw value against an OTLP panel's regex filter."
      },
      {
        "allValue": ".*",
        "current": {
          "text": "All",
          "value": "$__all"
        },
        "datasource": {
          "type": "prometheus",
          "uid": "${prometheus_ds}"
        },
        "definition": "label_values(apinizer_ai_requests_total_count{provider=~\"$provider\"}, model)",
        "hide": 0,
        "includeAll": true,
        "label": "Model",
        "multi": true,
        "name": "model",
        "options": [],
        "query": {
          "query": "label_values(apinizer_ai_requests_total_count{provider=~\"$provider\"}, model)",
          "refId": "model"
        },
        "refresh": 2,
        "regex": "",
        "skipUrlSync": false,
        "sort": 1,
        "type": "query"
      },
      {
        "allValue": ".*",
        "current": {
          "text": "All",
          "value": "$__all"
        },
        "datasource": {
          "type": "prometheus",
          "uid": "${prometheus_ds}"
        },
        "definition": "label_values(apinizer_ai_requests_total_count, projectId)",
        "hide": 0,
        "includeAll": true,
        "label": "Project",
        "multi": true,
        "name": "project",
        "options": [],
        "query": {
          "query": "label_values(apinizer_ai_requests_total_count, projectId)",
          "refId": "project"
        },
        "refresh": 2,
        "regex": "",
        "skipUrlSync": false,
        "sort": 1,
        "type": "query"
      }
    ]
  },
  "time": {
    "from": "now-6h",
    "to": "now"
  },
  "timepicker": {},
  "timezone": "",
  "title": "Apinizer AI Gateway",
  "description": "GenAI usage, cost, latency, guardrail and reliability signals from Apinizer AI Gateway — combines the always-on Prometheus apinizer_ai_* family with the optional native OTLP gen_ai.*/apinizer.ai.client.* histograms. See docs.apinizer.com AI Gateway > OpenTelemetry for setup and the full attribute/metric reference.",
  "uid": "apinizer-ai-gateway",
  "version": 1,
  "weekStart": ""
}
