# Look up the Control Plane and Service IDs so the dashboard's gateway_service
# preset filter resolves to the scoped UUID Konnect expects.
CP_ID=$(kongctl get gateway control-plane "${KONNECT_CONTROL_PLANE_NAME}" \
--pat "${KONNECT_TOKEN}" -o json --jq '.id' -r)
SERVICE_ID=$(kongctl api get "/v2/control-planes/${CP_ID}/core-entities/services" \
--pat "${KONNECT_TOKEN}" -o json \
--jq '.data[] | select(.name=="github-copilot-byok") | .id' -r)
if [ -z "${CP_ID}" ] || [ -z "${SERVICE_ID}" ]; then
echo "Refusing to create dashboard: CP_ID='${CP_ID}' SERVICE_ID='${SERVICE_ID}'."
echo "Confirm the apply step succeeded and the Service is visible in Konnect, then retry."
exit 1
fi
EXISTING_DASHBOARDS=$(kongctl api get "/v2/dashboards?filter%5Blabels.recipe%5D=github-copilot-byok-recipe" \
--pat "${KONNECT_TOKEN}" -o json --jq '.data | length')
if [ "${EXISTING_DASHBOARDS}" -gt 0 ]; then
echo "Copilot Usage dashboard already exists. Reusing."
else
cat <<'EOF' | jq --arg ref "${CP_ID}:${SERVICE_ID}" '.definition.preset_filters[0].value = [$ref]' > copilot-usage-dashboard.json
{
"name": "Copilot Usage",
"definition": {
"tiles": [
{
"id": "c0f1ee01-0000-4000-8000-000000000001",
"type": "chart",
"layout": { "size": { "cols": 2, "rows": 1 }, "position": { "col": 0, "row": 0 } },
"definition": {
"chart": { "type": "single_value", "chart_title": "Total cost ($)" },
"query": {
"filters": [
{ "field": "ai_provider", "operator": "not_empty" },
{ "field": "ai_provider", "value": ["UNSPECIFIED"], "operator": "not_in" }
],
"metrics": ["cost"],
"datasource": "llm_usage",
"dimensions": []
}
}
},
{
"id": "c0f1ee01-0000-4000-8000-000000000002",
"type": "chart",
"layout": { "size": { "cols": 2, "rows": 1 }, "position": { "col": 2, "row": 0 } },
"definition": {
"chart": { "type": "single_value", "chart_title": "Total tokens" },
"query": {
"filters": [
{ "field": "ai_provider", "operator": "not_empty" },
{ "field": "ai_provider", "value": ["UNSPECIFIED"], "operator": "not_in" }
],
"metrics": ["total_tokens"],
"datasource": "llm_usage",
"dimensions": []
}
}
},
{
"id": "c0f1ee01-0000-4000-8000-000000000003",
"type": "chart",
"layout": { "size": { "cols": 2, "rows": 1 }, "position": { "col": 4, "row": 0 } },
"definition": {
"chart": { "type": "single_value", "chart_title": "Total Copilot requests" },
"query": {
"filters": [
{ "field": "ai_provider", "operator": "not_empty" },
{ "field": "ai_provider", "value": ["UNSPECIFIED"], "operator": "not_in" }
],
"metrics": ["ai_request_count"],
"datasource": "llm_usage",
"dimensions": []
}
}
},
{
"id": "c0f1ee01-0000-4000-8000-000000000004",
"type": "chart",
"layout": { "size": { "cols": 3, "rows": 2 }, "position": { "col": 0, "row": 1 } },
"definition": {
"chart": { "type": "top_n", "chart_title": "Top Copilot models by usage" },
"query": {
"limit": 10,
"filters": [],
"metrics": ["total_tokens", "ai_request_count"],
"datasource": "llm_usage",
"dimensions": ["ai_request_model"]
}
}
},
{
"id": "c0f1ee01-0000-4000-8000-000000000005",
"type": "chart",
"layout": { "size": { "cols": 3, "rows": 2 }, "position": { "col": 3, "row": 1 } },
"definition": {
"chart": { "type": "timeseries_line", "stacked": false, "chart_title": "Model usage trend (top 5)" },
"query": {
"limit": 5,
"filters": [
{ "field": "ai_provider", "operator": "not_empty" },
{ "field": "ai_provider", "value": ["UNSPECIFIED"], "operator": "not_in" }
],
"metrics": ["total_tokens"],
"datasource": "llm_usage",
"dimensions": ["ai_request_model", "time"]
}
}
},
{
"id": "c0f1ee01-0000-4000-8000-000000000006",
"type": "chart",
"layout": { "size": { "cols": 2, "rows": 2 }, "position": { "col": 0, "row": 3 } },
"definition": {
"chart": { "type": "donut", "chart_title": "Copilot health check" },
"query": {
"filters": [
{ "field": "gateway_service", "operator": "not_empty" },
{ "field": "ai_provider", "operator": "not_empty" },
{ "field": "ai_provider", "value": ["UNSPECIFIED"], "operator": "not_in" }
],
"metrics": ["ai_request_count"],
"datasource": "llm_usage",
"dimensions": ["status_code_grouped"]
}
}
},
{
"id": "c0f1ee01-0000-4000-8000-000000000007",
"type": "chart",
"layout": { "size": { "cols": 2, "rows": 2 }, "position": { "col": 2, "row": 3 } },
"definition": {
"chart": { "type": "donut", "chart_title": "Copilot provider usage" },
"query": {
"filters": [
{ "field": "gateway_service", "operator": "not_empty" },
{ "field": "ai_provider", "operator": "not_empty" },
{ "field": "ai_provider", "value": ["UNSPECIFIED"], "operator": "not_in" }
],
"metrics": ["ai_request_count"],
"datasource": "llm_usage",
"dimensions": ["ai_provider"]
}
}
},
{
"id": "c0f1ee01-0000-4000-8000-000000000008",
"type": "chart",
"layout": { "size": { "cols": 2, "rows": 2 }, "position": { "col": 4, "row": 3 } },
"definition": {
"chart": { "type": "timeseries_bar", "stacked": true, "chart_title": "LLM latency (avg)" },
"query": {
"filters": [
{ "field": "ai_request_model", "operator": "not_empty" },
{ "field": "ai_request_model", "value": ["UNSPECIFIED"], "operator": "not_in" }
],
"metrics": ["llm_latency_average"],
"datasource": "llm_usage",
"dimensions": ["ai_request_model", "time"]
}
}
},
{
"id": "c0f1ee01-0000-4000-8000-000000000009",
"type": "chart",
"layout": { "size": { "cols": 3, "rows": 2 }, "position": { "col": 0, "row": 9 } },
"definition": {
"chart": { "type": "horizontal_bar", "stacked": true, "chart_title": "Copilot usage by developer (requests)" },
"query": {
"filters": [
{ "field": "consumer", "operator": "not_empty" }
],
"metrics": ["ai_request_count"],
"datasource": "llm_usage",
"dimensions": ["consumer"]
}
}
},
{
"id": "c0f1ee01-0000-4000-8000-00000000000a",
"type": "chart",
"layout": { "size": { "cols": 3, "rows": 2 }, "position": { "col": 3, "row": 9 } },
"definition": {
"chart": { "type": "vertical_bar", "stacked": true, "chart_title": "Copilot usage by developer (tokens)" },
"query": {
"filters": [
{ "field": "consumer", "operator": "not_empty" }
],
"metrics": ["total_tokens"],
"datasource": "llm_usage",
"dimensions": ["consumer"]
}
}
},
{
"id": "c0f1ee01-0000-4000-8000-00000000000b",
"type": "chart",
"layout": { "size": { "cols": 2, "rows": 2 }, "position": { "col": 0, "row": 11 } },
"definition": {
"chart": { "type": "vertical_bar", "stacked": true, "chart_title": "AI security report (401 / 403 / 429)" },
"query": {
"filters": [
{ "field": "status_code", "value": ["401", "403", "429"], "operator": "in" }
],
"metrics": ["request_count"],
"datasource": "api_usage",
"dimensions": ["status_code", "consumer"]
}
}
},
{
"id": "c0f1ee01-0000-4000-8000-00000000000c",
"type": "chart",
"layout": { "size": { "cols": 3, "rows": 2 }, "position": { "col": 2, "row": 11 } },
"definition": {
"chart": { "type": "timeseries_bar", "stacked": true, "chart_title": "Monthly spend trends" },
"query": {
"limit": 10,
"filters": [],
"metrics": ["cost"],
"datasource": "llm_usage",
"dimensions": ["ai_request_model", "time"],
"time_range": { "type": "relative", "time_range": "30d" },
"granularity": "daily"
}
}
}
],
"template_id": "AI_GATEWAY",
"preset_filters": [
{ "field": "gateway_service", "value": [], "operator": "in" }
]
},
"labels": {
"recipe": "github-copilot-byok-recipe"
}
}
EOF
DASHBOARD_ID=$(kongctl api post /v2/dashboards \
-f copilot-usage-dashboard.json \
--pat "${KONNECT_TOKEN}" -o json --jq '.id' -r)
rm -f copilot-usage-dashboard.json
echo "Created Copilot Usage dashboard (id: ${DASHBOARD_ID}). Open it in Konnect at Observability → Custom dashboards → 'Copilot Usage'."
fi