mirror of
https://github.com/SigNoz/signoz.git
synced 2026-04-27 22:20:29 +01:00
Compare commits
1 Commits
feat/billi
...
feat/overv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85a0289957 |
107
ai-o11y-overview.json
Normal file
107
ai-o11y-overview.json
Normal file
@@ -0,0 +1,107 @@
|
||||
{
|
||||
"title": "AI Observability Overview",
|
||||
"description": "AI / LLM observability overview — cost, tokens, latency, errors, RED for tool calls, and time to first token. Scoped by model, environment and service (apply via the variable bar).",
|
||||
"tags": ["ai", "llm", "genai", "overview"],
|
||||
"version": "v5",
|
||||
"variables": {
|
||||
"model": {
|
||||
"id": "a1000000-0000-0000-0000-000000000001",
|
||||
"name": "model",
|
||||
"key": "model",
|
||||
"description": "LLM model",
|
||||
"type": "QUERY",
|
||||
"sort": "ASC",
|
||||
"multiSelect": true,
|
||||
"showALLOption": true,
|
||||
"allSelected": true,
|
||||
"queryValue": "SELECT DISTINCT stringTagMap['gen_ai.request.model'] AS model FROM signoz_traces.distributed_signoz_index_v3 WHERE has(stringTagMap, 'gen_ai.request.model') AND timestamp >= now() - INTERVAL 1 DAY",
|
||||
"customValue": "",
|
||||
"textboxValue": "",
|
||||
"selectedValue": [],
|
||||
"order": 0,
|
||||
"modificationUUID": "a1000000-0000-0000-0000-000000000011"
|
||||
},
|
||||
"environment": {
|
||||
"id": "a1000000-0000-0000-0000-000000000002",
|
||||
"name": "environment",
|
||||
"key": "environment",
|
||||
"description": "Deployment environment",
|
||||
"type": "QUERY",
|
||||
"sort": "ASC",
|
||||
"multiSelect": true,
|
||||
"showALLOption": true,
|
||||
"allSelected": true,
|
||||
"queryValue": "SELECT DISTINCT resourceTagsMap['deployment.environment'] AS environment FROM signoz_traces.distributed_signoz_index_v3 WHERE has(resourceTagsMap, 'deployment.environment') AND timestamp >= now() - INTERVAL 1 DAY",
|
||||
"customValue": "",
|
||||
"textboxValue": "",
|
||||
"selectedValue": [],
|
||||
"order": 1,
|
||||
"modificationUUID": "a1000000-0000-0000-0000-000000000012"
|
||||
},
|
||||
"service_name": {
|
||||
"id": "a1000000-0000-0000-0000-000000000003",
|
||||
"name": "service_name",
|
||||
"key": "service_name",
|
||||
"description": "Service name",
|
||||
"type": "QUERY",
|
||||
"sort": "ASC",
|
||||
"multiSelect": true,
|
||||
"showALLOption": true,
|
||||
"allSelected": true,
|
||||
"queryValue": "SELECT DISTINCT serviceName FROM signoz_traces.distributed_signoz_index_v3 WHERE timestamp >= now() - INTERVAL 1 DAY",
|
||||
"customValue": "",
|
||||
"textboxValue": "",
|
||||
"selectedValue": [],
|
||||
"order": 2,
|
||||
"modificationUUID": "a1000000-0000-0000-0000-000000000013"
|
||||
}
|
||||
},
|
||||
"layout": [
|
||||
{"i": "11111111-1111-1111-1111-111111111111", "x": 0, "y": 0, "w": 3, "h": 3, "moved": false, "static": false},
|
||||
{"i": "22222222-2222-2222-2222-222222222222", "x": 3, "y": 0, "w": 3, "h": 3, "moved": false, "static": false},
|
||||
{"i": "33333333-3333-3333-3333-333333333333", "x": 6, "y": 0, "w": 2, "h": 3, "moved": false, "static": false},
|
||||
{"i": "44444444-4444-4444-4444-444444444444", "x": 8, "y": 0, "w": 2, "h": 3, "moved": false, "static": false},
|
||||
{"i": "55555555-5555-5555-5555-555555555555", "x": 10, "y": 0, "w": 2, "h": 3, "moved": false, "static": false},
|
||||
{"i": "66666666-6666-6666-6666-666666666666", "x": 0, "y": 3, "w": 6, "h": 4, "moved": false, "static": false},
|
||||
{"i": "77777777-7777-7777-7777-777777777777", "x": 6, "y": 3, "w": 6, "h": 4, "moved": false, "static": false},
|
||||
{"i": "88888888-8888-8888-8888-888888888888", "x": 0, "y": 7, "w": 6, "h": 4, "moved": false, "static": false},
|
||||
{"i": "99999999-9999-9999-9999-999999999999", "x": 6, "y": 7, "w": 6, "h": 4, "moved": false, "static": false},
|
||||
{"i": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "x": 0, "y": 11, "w": 4, "h": 4, "moved": false, "static": false},
|
||||
{"i": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "x": 4, "y": 11, "w": 4, "h": 4, "moved": false, "static": false},
|
||||
{"i": "cccccccc-cccc-cccc-cccc-cccccccccccc", "x": 8, "y": 11, "w": 4, "h": 4, "moved": false, "static": false},
|
||||
{"i": "dddddddd-dddd-dddd-dddd-dddddddddddd", "x": 0, "y": 15, "w": 4, "h": 4, "moved": false, "static": false},
|
||||
{"i": "eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee", "x": 4, "y": 15, "w": 4, "h": 4, "moved": false, "static": false},
|
||||
{"i": "ffffffff-ffff-ffff-ffff-ffffffffffff", "x": 8, "y": 15, "w": 4, "h": 4, "moved": false, "static": false}
|
||||
],
|
||||
"widgets": [
|
||||
{"id": "11111111-1111-1111-1111-111111111111", "title": "Total cost", "description": "Total LLM cost across all calls. Requires gen_ai.usage.cost attribute.", "panelTypes": "value", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "none", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "q1111111-1111-1111-1111-111111111111", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "sum(gen_ai.usage.cost)"}], "filter": {"expression": ""}, "groupBy": [], "expression": "A", "orderBy": [], "legend": "", "disabled": false, "having": {"expression": ""}, "limit": null, "reduceTo": "sum"}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "22222222-2222-2222-2222-222222222222", "title": "Total tokens", "description": "Sum of input + output tokens.", "panelTypes": "value", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "short", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "q2222222-2222-2222-2222-222222222222", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "sum(gen_ai.usage.input_tokens) + sum(gen_ai.usage.output_tokens)"}], "filter": {"expression": ""}, "groupBy": [], "expression": "A", "orderBy": [], "legend": "", "disabled": false, "having": {"expression": ""}, "limit": null, "reduceTo": "sum"}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "33333333-3333-3333-3333-333333333333", "title": "Avg latency (p95)", "description": "p95 latency of LLM spans.", "panelTypes": "value", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "ns", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "q3333333-3333-3333-3333-333333333333", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "p95(duration_nano)"}], "filter": {"expression": "gen_ai.system != ''"}, "groupBy": [], "expression": "A", "orderBy": [], "legend": "", "disabled": false, "having": {"expression": ""}, "limit": null, "reduceTo": "avg"}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "44444444-4444-4444-4444-444444444444", "title": "Error rate", "description": "Error rate as a percentage of total LLM calls.", "panelTypes": "value", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "percent", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "q4444444-4444-4444-4444-444444444444", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "countIf(has_error = true) * 100 / count()"}], "filter": {"expression": "gen_ai.system != ''"}, "groupBy": [], "expression": "A", "orderBy": [], "legend": "", "disabled": false, "having": {"expression": ""}, "limit": null, "reduceTo": "avg"}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "55555555-5555-5555-5555-555555555555", "title": "TTFT (p95)", "description": "p95 time to first token.", "panelTypes": "value", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "ms", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "q5555555-5555-5555-5555-555555555555", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "p95(gen_ai.server.ttft)"}], "filter": {"expression": ""}, "groupBy": [], "expression": "A", "orderBy": [], "legend": "", "disabled": false, "having": {"expression": ""}, "limit": null, "reduceTo": "avg"}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "66666666-6666-6666-6666-666666666666", "title": "Cost over time", "description": "Cost by model over time.", "panelTypes": "graph", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "none", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "q6666666-6666-6666-6666-666666666666", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "sum(gen_ai.usage.cost)"}], "filter": {"expression": ""}, "groupBy": [{"key": "gen_ai.request.model", "dataType": "string", "type": "tag", "isColumn": false, "isJSON": false}], "expression": "A", "orderBy": [], "legend": "{{gen_ai.request.model}}", "disabled": false, "having": {"expression": ""}, "limit": null}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "77777777-7777-7777-7777-777777777777", "title": "Token usage over time", "description": "Input vs output tokens over time.", "panelTypes": "graph", "nullZeroValues": "zero", "opacity": "1", "isStacked": true, "fillSpans": false, "yAxisUnit": "short", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "q7777777-7777-7777-7777-777777777777", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "sum(gen_ai.usage.input_tokens)"}], "filter": {"expression": ""}, "groupBy": [], "expression": "A", "orderBy": [], "legend": "Input", "disabled": false, "having": {"expression": ""}, "limit": null}, {"queryName": "B", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "sum(gen_ai.usage.output_tokens)"}], "filter": {"expression": ""}, "groupBy": [], "expression": "B", "orderBy": [], "legend": "Output", "disabled": false, "having": {"expression": ""}, "limit": null}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "88888888-8888-8888-8888-888888888888", "title": "LLM call latency percentiles", "description": "p50, p90, p95, p99 latency by model.", "panelTypes": "table", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "ns", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "q8888888-8888-8888-8888-888888888888", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "p50(duration_nano)"}, {"expression": "p90(duration_nano)"}, {"expression": "p95(duration_nano)"}, {"expression": "p99(duration_nano)"}], "filter": {"expression": "gen_ai.system != ''"}, "groupBy": [{"key": "gen_ai.request.model", "dataType": "string", "type": "tag", "isColumn": false, "isJSON": false}], "expression": "A", "orderBy": [], "legend": "{{gen_ai.request.model}}", "disabled": false, "having": {"expression": ""}, "limit": null}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "99999999-9999-9999-9999-999999999999", "title": "LLM call latency over time", "description": "p95 latency trend by model.", "panelTypes": "graph", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "ns", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "q9999999-9999-9999-9999-999999999999", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "p95(duration_nano)"}], "filter": {"expression": "gen_ai.system != ''"}, "groupBy": [{"key": "gen_ai.request.model", "dataType": "string", "type": "tag", "isColumn": false, "isJSON": false}], "expression": "A", "orderBy": [], "legend": "{{gen_ai.request.model}}", "disabled": false, "having": {"expression": ""}, "limit": null}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "title": "Error count", "description": "Errors grouped by error type.", "panelTypes": "graph", "nullZeroValues": "zero", "opacity": "1", "isStacked": true, "fillSpans": false, "yAxisUnit": "short", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "qaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "count()"}], "filter": {"expression": "has_error = true AND gen_ai.system != ''"}, "groupBy": [{"key": "gen_ai.error.type", "dataType": "string", "type": "tag", "isColumn": false, "isJSON": false}], "expression": "A", "orderBy": [], "legend": "{{gen_ai.error.type}}", "disabled": false, "having": {"expression": ""}, "limit": null}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "title": "Time to first token", "description": "p95 TTFT by model.", "panelTypes": "graph", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "ms", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "qbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "p95(gen_ai.server.ttft)"}], "filter": {"expression": ""}, "groupBy": [{"key": "gen_ai.request.model", "dataType": "string", "type": "tag", "isColumn": false, "isJSON": false}], "expression": "A", "orderBy": [], "legend": "{{gen_ai.request.model}}", "disabled": false, "having": {"expression": ""}, "limit": null}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "cccccccc-cccc-cccc-cccc-cccccccccccc", "title": "Top 10 span names", "description": "Top span names by count across GenAI spans.", "panelTypes": "table", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "none", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "qccccccc-cccc-cccc-cccc-cccccccccccc", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "count()"}], "filter": {"expression": "gen_ai.system != ''"}, "groupBy": [{"key": "name", "dataType": "string", "type": "tag", "isColumn": true, "isJSON": false}], "expression": "A", "orderBy": [{"columnName": "count()", "order": "desc"}], "legend": "{{name}}", "disabled": false, "having": {"expression": ""}, "limit": 10}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "dddddddd-dddd-dddd-dddd-dddddddddddd", "title": "Tool call rate", "description": "Tool call rate per second.", "panelTypes": "graph", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "reqps", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "qddddddd-dddd-dddd-dddd-dddddddddddd", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "rate()"}], "filter": {"expression": "name = 'execute_tool'"}, "groupBy": [], "expression": "A", "orderBy": [], "legend": "req/s", "disabled": false, "having": {"expression": ""}, "limit": null}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee", "title": "Tool error rate", "description": "Percentage of tool calls that errored.", "panelTypes": "graph", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "percent", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "qeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "countIf(has_error = true) * 100 / count()"}], "filter": {"expression": "name = 'execute_tool'"}, "groupBy": [], "expression": "A", "orderBy": [], "legend": "error %", "disabled": false, "having": {"expression": ""}, "limit": null}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "ffffffff-ffff-ffff-ffff-ffffffffffff", "title": "Tool duration (p50)", "description": "Median tool call duration.", "panelTypes": "graph", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "ns", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "qfffffff-ffff-ffff-ffff-ffffffffffff", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "p50(duration_nano)"}], "filter": {"expression": "name = 'execute_tool'"}, "groupBy": [], "expression": "A", "orderBy": [], "legend": "p50", "disabled": false, "having": {"expression": ""}, "limit": null}], "queryFormulas": [], "queryTraceOperator": []}}}
|
||||
]
|
||||
}
|
||||
@@ -2001,6 +2001,8 @@ components:
|
||||
type: boolean
|
||||
org_id:
|
||||
type: string
|
||||
source:
|
||||
type: string
|
||||
updatedAt:
|
||||
format: date-time
|
||||
type: string
|
||||
@@ -2023,6 +2025,27 @@ components:
|
||||
publicDashboard:
|
||||
$ref: '#/components/schemas/DashboardtypesGettablePublicDasbhboard'
|
||||
type: object
|
||||
DashboardtypesGettableSystemDashboard:
|
||||
properties:
|
||||
createdAt:
|
||||
format: date-time
|
||||
type: string
|
||||
createdBy:
|
||||
type: string
|
||||
data:
|
||||
$ref: '#/components/schemas/DashboardtypesStorableDashboardData'
|
||||
id:
|
||||
type: string
|
||||
orgId:
|
||||
type: string
|
||||
source:
|
||||
type: string
|
||||
updatedAt:
|
||||
format: date-time
|
||||
type: string
|
||||
updatedBy:
|
||||
type: string
|
||||
type: object
|
||||
DashboardtypesPostablePublicDashboard:
|
||||
properties:
|
||||
defaultTimeRange:
|
||||
@@ -2040,6 +2063,11 @@ components:
|
||||
timeRangeEnabled:
|
||||
type: boolean
|
||||
type: object
|
||||
DashboardtypesUpdatableSystemDashboard:
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/components/schemas/DashboardtypesStorableDashboardData'
|
||||
type: object
|
||||
ErrorsJSON:
|
||||
properties:
|
||||
code:
|
||||
@@ -8876,6 +8904,160 @@ paths:
|
||||
summary: Updates my service account
|
||||
tags:
|
||||
- serviceaccount
|
||||
/api/v1/system/{source}/dashboard:
|
||||
delete:
|
||||
deprecated: false
|
||||
description: This endpoint drops any customisation to the system dashboard and
|
||||
sets the defaults.
|
||||
operationId: DeleteSystemDashboard
|
||||
parameters:
|
||||
- in: path
|
||||
name: source
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"204":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: string
|
||||
description: No Content
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- EDITOR
|
||||
- tokenizer:
|
||||
- EDITOR
|
||||
summary: Reset system dashboard to defaults
|
||||
tags:
|
||||
- system-dashboard
|
||||
get:
|
||||
deprecated: false
|
||||
description: This endpoint returns the system dashboard for the callers org
|
||||
keyed by source (e.g. ai-o11y-overview).
|
||||
operationId: GetSystemDashboard
|
||||
parameters:
|
||||
- in: path
|
||||
name: source
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/components/schemas/DashboardtypesGettableSystemDashboard'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- VIEWER
|
||||
- tokenizer:
|
||||
- VIEWER
|
||||
summary: Get system dashboard
|
||||
tags:
|
||||
- system-dashboard
|
||||
put:
|
||||
deprecated: false
|
||||
description: This endpoint replaces the system dashboard for the callers org
|
||||
with the provided payload.
|
||||
operationId: UpdateSystemDashboard
|
||||
parameters:
|
||||
- in: path
|
||||
name: source
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DashboardtypesUpdatableSystemDashboard'
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/components/schemas/DashboardtypesGettableSystemDashboard'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- EDITOR
|
||||
- tokenizer:
|
||||
- EDITOR
|
||||
summary: Update system dashboard
|
||||
tags:
|
||||
- system-dashboard
|
||||
/api/v1/testChannel:
|
||||
post:
|
||||
deprecated: true
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/modules/rulestatehistory"
|
||||
"github.com/SigNoz/signoz/pkg/modules/serviceaccount"
|
||||
"github.com/SigNoz/signoz/pkg/modules/session"
|
||||
"github.com/SigNoz/signoz/pkg/modules/systemdashboard"
|
||||
"github.com/SigNoz/signoz/pkg/modules/user"
|
||||
"github.com/SigNoz/signoz/pkg/querier"
|
||||
"github.com/SigNoz/signoz/pkg/ruler"
|
||||
@@ -48,6 +49,7 @@ type provider struct {
|
||||
flaggerHandler flagger.Handler
|
||||
dashboardModule dashboard.Module
|
||||
dashboardHandler dashboard.Handler
|
||||
systemDashboardHandler systemdashboard.Handler
|
||||
metricsExplorerHandler metricsexplorer.Handler
|
||||
gatewayHandler gateway.Handler
|
||||
fieldsHandler fields.Handler
|
||||
@@ -76,6 +78,7 @@ func NewFactory(
|
||||
flaggerHandler flagger.Handler,
|
||||
dashboardModule dashboard.Module,
|
||||
dashboardHandler dashboard.Handler,
|
||||
systemDashboardHandler systemdashboard.Handler,
|
||||
metricsExplorerHandler metricsexplorer.Handler,
|
||||
gatewayHandler gateway.Handler,
|
||||
fieldsHandler fields.Handler,
|
||||
@@ -107,6 +110,7 @@ func NewFactory(
|
||||
flaggerHandler,
|
||||
dashboardModule,
|
||||
dashboardHandler,
|
||||
systemDashboardHandler,
|
||||
metricsExplorerHandler,
|
||||
gatewayHandler,
|
||||
fieldsHandler,
|
||||
@@ -140,6 +144,7 @@ func newProvider(
|
||||
flaggerHandler flagger.Handler,
|
||||
dashboardModule dashboard.Module,
|
||||
dashboardHandler dashboard.Handler,
|
||||
systemDashboardHandler systemdashboard.Handler,
|
||||
metricsExplorerHandler metricsexplorer.Handler,
|
||||
gatewayHandler gateway.Handler,
|
||||
fieldsHandler fields.Handler,
|
||||
@@ -171,6 +176,7 @@ func newProvider(
|
||||
flaggerHandler: flaggerHandler,
|
||||
dashboardModule: dashboardModule,
|
||||
dashboardHandler: dashboardHandler,
|
||||
systemDashboardHandler: systemDashboardHandler,
|
||||
metricsExplorerHandler: metricsExplorerHandler,
|
||||
gatewayHandler: gatewayHandler,
|
||||
fieldsHandler: fieldsHandler,
|
||||
@@ -236,6 +242,10 @@ func (provider *provider) AddToRouter(router *mux.Router) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := provider.addSystemDashboardRoutes(router); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := provider.addMetricsExplorerRoutes(router); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
66
pkg/apiserver/signozapiserver/systemdashboard.go
Normal file
66
pkg/apiserver/signozapiserver/systemdashboard.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package signozapiserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/http/handler"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/types/dashboardtypes"
|
||||
)
|
||||
|
||||
func (provider *provider) addSystemDashboardRoutes(router *mux.Router) error {
|
||||
if err := router.Handle("/api/v1/system/{source}/dashboard", handler.New(provider.authZ.ViewAccess(provider.systemDashboardHandler.Get), handler.OpenAPIDef{
|
||||
ID: "GetSystemDashboard",
|
||||
Tags: []string{"system-dashboard"},
|
||||
Summary: "Get system dashboard",
|
||||
Description: "This endpoint returns the system dashboard for the callers org keyed by source (e.g. ai-o11y-overview).",
|
||||
Request: nil,
|
||||
RequestContentType: "",
|
||||
Response: new(dashboardtypes.GettableSystemDashboard),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/system/{source}/dashboard", handler.New(provider.authZ.EditAccess(provider.systemDashboardHandler.Update), handler.OpenAPIDef{
|
||||
ID: "UpdateSystemDashboard",
|
||||
Tags: []string{"system-dashboard"},
|
||||
Summary: "Update system dashboard",
|
||||
Description: "This endpoint replaces the system dashboard for the callers org with the provided payload.",
|
||||
Request: new(dashboardtypes.UpdatableSystemDashboard),
|
||||
RequestContentType: "application/json",
|
||||
Response: new(dashboardtypes.GettableSystemDashboard),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleEditor),
|
||||
})).Methods(http.MethodPut).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/system/{source}/dashboard", handler.New(provider.authZ.EditAccess(provider.systemDashboardHandler.Delete), handler.OpenAPIDef{
|
||||
ID: "DeleteSystemDashboard",
|
||||
Tags: []string{"system-dashboard"},
|
||||
Summary: "Reset system dashboard to defaults",
|
||||
Description: "This endpoint drops any customisation to the system dashboard and sets the defaults.",
|
||||
Request: nil,
|
||||
RequestContentType: "",
|
||||
Response: nil,
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusNoContent,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleEditor),
|
||||
})).Methods(http.MethodDelete).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -21,7 +21,7 @@ func NewStore(sqlstore sqlstore.SQLStore) dashboardtypes.Store {
|
||||
func (store *store) Create(ctx context.Context, storabledashboard *dashboardtypes.StorableDashboard) error {
|
||||
_, err := store.
|
||||
sqlstore.
|
||||
BunDB().
|
||||
BunDBCtx(ctx).
|
||||
NewInsert().
|
||||
Model(storabledashboard).
|
||||
Exec(ctx)
|
||||
@@ -55,6 +55,7 @@ func (store *store) Get(ctx context.Context, orgID valuer.UUID, id valuer.UUID)
|
||||
Model(storableDashboard).
|
||||
Where("id = ?", id).
|
||||
Where("org_id = ?", orgID).
|
||||
Where("source = ?", "").
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
return nil, store.sqlstore.WrapNotFoundErrf(err, errors.CodeNotFound, "dashboard with id %s doesn't exist", id)
|
||||
@@ -63,6 +64,23 @@ func (store *store) Get(ctx context.Context, orgID valuer.UUID, id valuer.UUID)
|
||||
return storableDashboard, nil
|
||||
}
|
||||
|
||||
func (store *store) GetBySource(ctx context.Context, orgID valuer.UUID, source string) (*dashboardtypes.StorableDashboard, error) {
|
||||
storableDashboard := new(dashboardtypes.StorableDashboard)
|
||||
err := store.
|
||||
sqlstore.
|
||||
BunDBCtx(ctx).
|
||||
NewSelect().
|
||||
Model(storableDashboard).
|
||||
Where("org_id = ?", orgID).
|
||||
Where("source = ?", source).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
return nil, store.sqlstore.WrapNotFoundErrf(err, errors.CodeNotFound, "system dashboard with source %s doesn't exist", source)
|
||||
}
|
||||
|
||||
return storableDashboard, nil
|
||||
}
|
||||
|
||||
func (store *store) GetPublic(ctx context.Context, dashboardID string) (*dashboardtypes.StorablePublicDashboard, error) {
|
||||
storable := new(dashboardtypes.StorablePublicDashboard)
|
||||
err := store.
|
||||
@@ -124,6 +142,7 @@ func (store *store) List(ctx context.Context, orgID valuer.UUID) ([]*dashboardty
|
||||
NewSelect().
|
||||
Model(&storableDashboards).
|
||||
Where("org_id = ?", orgID).
|
||||
Where("source = ?", "").
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -158,6 +177,7 @@ func (store *store) Update(ctx context.Context, orgID valuer.UUID, storableDashb
|
||||
Model(storableDashboard).
|
||||
WherePK().
|
||||
Where("org_id = ?", orgID).
|
||||
Where("source = ?", "").
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return store.sqlstore.WrapNotFoundErrf(err, errors.CodeNotFound, "dashboard with id %s doesn't exist", storableDashboard.ID)
|
||||
@@ -166,6 +186,23 @@ func (store *store) Update(ctx context.Context, orgID valuer.UUID, storableDashb
|
||||
return nil
|
||||
}
|
||||
|
||||
func (store *store) UpdateBySource(ctx context.Context, orgID valuer.UUID, source string, storableDashboard *dashboardtypes.StorableDashboard) error {
|
||||
_, err := store.
|
||||
sqlstore.
|
||||
BunDBCtx(ctx).
|
||||
NewUpdate().
|
||||
Model(storableDashboard).
|
||||
WherePK().
|
||||
Where("org_id = ?", orgID).
|
||||
Where("source = ?", source).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return store.sqlstore.WrapNotFoundErrf(err, errors.CodeNotFound, "system dashboard with source %s doesn't exist", source)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (store *store) UpdatePublic(ctx context.Context, storable *dashboardtypes.StorablePublicDashboard) error {
|
||||
_, err := store.
|
||||
sqlstore.
|
||||
@@ -189,6 +226,7 @@ func (store *store) Delete(ctx context.Context, orgID valuer.UUID, id valuer.UUI
|
||||
Model(new(dashboardtypes.StorableDashboard)).
|
||||
Where("id = ?", id).
|
||||
Where("org_id = ?", orgID).
|
||||
Where("source = ?", "").
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return store.sqlstore.WrapNotFoundErrf(err, errors.CodeNotFound, "dashboard with id %s doesn't exist", id)
|
||||
@@ -197,6 +235,22 @@ func (store *store) Delete(ctx context.Context, orgID valuer.UUID, id valuer.UUI
|
||||
return nil
|
||||
}
|
||||
|
||||
func (store *store) DeleteBySource(ctx context.Context, orgID valuer.UUID, source string) error {
|
||||
_, err := store.
|
||||
sqlstore.
|
||||
BunDBCtx(ctx).
|
||||
NewDelete().
|
||||
Model(new(dashboardtypes.StorableDashboard)).
|
||||
Where("org_id = ?", orgID).
|
||||
Where("source = ?", source).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return store.sqlstore.WrapNotFoundErrf(err, errors.CodeNotFound, "system dashboard with source %s doesn't exist", source)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (store *store) DeletePublic(ctx context.Context, dashboardID string) error {
|
||||
_, err := store.
|
||||
sqlstore.
|
||||
|
||||
@@ -6,18 +6,20 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||
"github.com/SigNoz/signoz/pkg/modules/quickfilter"
|
||||
"github.com/SigNoz/signoz/pkg/modules/systemdashboard"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
)
|
||||
|
||||
type setter struct {
|
||||
store types.OrganizationStore
|
||||
alertmanager alertmanager.Alertmanager
|
||||
quickfilter quickfilter.Module
|
||||
store types.OrganizationStore
|
||||
alertmanager alertmanager.Alertmanager
|
||||
quickfilter quickfilter.Module
|
||||
systemDashboard systemdashboard.Module
|
||||
}
|
||||
|
||||
func NewSetter(store types.OrganizationStore, alertmanager alertmanager.Alertmanager, quickfilter quickfilter.Module) organization.Setter {
|
||||
return &setter{store: store, alertmanager: alertmanager, quickfilter: quickfilter}
|
||||
func NewSetter(store types.OrganizationStore, alertmanager alertmanager.Alertmanager, quickfilter quickfilter.Module, systemDashboard systemdashboard.Module) organization.Setter {
|
||||
return &setter{store: store, alertmanager: alertmanager, quickfilter: quickfilter, systemDashboard: systemDashboard}
|
||||
}
|
||||
|
||||
func (module *setter) Create(ctx context.Context, organization *types.Organization, createManagedRoles func(context.Context, valuer.UUID) error) error {
|
||||
@@ -33,6 +35,10 @@ func (module *setter) Create(ctx context.Context, organization *types.Organizati
|
||||
return err
|
||||
}
|
||||
|
||||
if err := module.systemDashboard.SetDefaultConfig(ctx, organization.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := createManagedRoles(ctx, organization.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
132
pkg/modules/systemdashboard/implsystemdashboard/handler.go
Normal file
132
pkg/modules/systemdashboard/implsystemdashboard/handler.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package implsystemdashboard
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/http/render"
|
||||
"github.com/SigNoz/signoz/pkg/modules/systemdashboard"
|
||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||
"github.com/SigNoz/signoz/pkg/types/dashboardtypes"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
)
|
||||
|
||||
type handler struct {
|
||||
module systemdashboard.Module
|
||||
}
|
||||
|
||||
func NewHandler(module systemdashboard.Module) systemdashboard.Handler {
|
||||
return &handler{module: module}
|
||||
}
|
||||
|
||||
func (handler *handler) Get(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
claims, err := authtypes.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
orgID, err := valuer.NewUUID(claims.OrgID)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
source, err := parseSource(r)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
dashboard, err := handler.module.Get(ctx, orgID, source)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(rw, http.StatusOK, dashboardtypes.NewGettableSystemDashboardFromDashboard(dashboard))
|
||||
}
|
||||
|
||||
func (handler *handler) Update(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
claims, err := authtypes.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
orgID, err := valuer.NewUUID(claims.OrgID)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
source, err := parseSource(r)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
req := dashboardtypes.UpdatableSystemDashboard{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
dashboard, err := handler.module.Update(ctx, orgID, source, claims.Email, req.Data)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(rw, http.StatusOK, dashboardtypes.NewGettableSystemDashboardFromDashboard(dashboard))
|
||||
}
|
||||
|
||||
func (handler *handler) Delete(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
claims, err := authtypes.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
orgID, err := valuer.NewUUID(claims.OrgID)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
source, err := parseSource(r)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := handler.module.Delete(ctx, orgID, source); err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(rw, http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
func parseSource(r *http.Request) (dashboardtypes.Source, error) {
|
||||
raw := mux.Vars(r)["source"]
|
||||
if raw == "" {
|
||||
return dashboardtypes.Source{}, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "source is missing in the path")
|
||||
}
|
||||
|
||||
return dashboardtypes.NewSource(raw)
|
||||
}
|
||||
87
pkg/modules/systemdashboard/implsystemdashboard/module.go
Normal file
87
pkg/modules/systemdashboard/implsystemdashboard/module.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package implsystemdashboard
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/modules/systemdashboard"
|
||||
"github.com/SigNoz/signoz/pkg/types/dashboardtypes"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
)
|
||||
|
||||
type module struct {
|
||||
store dashboardtypes.Store
|
||||
}
|
||||
|
||||
func NewModule(store dashboardtypes.Store) systemdashboard.Module {
|
||||
return &module{store: store}
|
||||
}
|
||||
|
||||
func (module *module) Get(ctx context.Context, orgID valuer.UUID, source dashboardtypes.Source) (*dashboardtypes.Dashboard, error) {
|
||||
storableDashboard, err := module.store.GetBySource(ctx, orgID, source.StringValue())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return dashboardtypes.NewDashboardFromStorableDashboard(storableDashboard), nil
|
||||
}
|
||||
|
||||
func (module *module) Update(ctx context.Context, orgID valuer.UUID, source dashboardtypes.Source, updatedBy string, data dashboardtypes.UpdatableDashboard) (*dashboardtypes.Dashboard, error) {
|
||||
storableDashboard, err := module.store.GetBySource(ctx, orgID, source.StringValue())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
storableDashboard.Data = data
|
||||
storableDashboard.UpdatedBy = updatedBy
|
||||
storableDashboard.UpdatedAt = time.Now()
|
||||
|
||||
if err := module.store.UpdateBySource(ctx, orgID, source.StringValue(), storableDashboard); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return dashboardtypes.NewDashboardFromStorableDashboard(storableDashboard), nil
|
||||
}
|
||||
|
||||
func (module *module) Delete(ctx context.Context, orgID valuer.UUID, source dashboardtypes.Source) error {
|
||||
return module.store.RunInTx(ctx, func(ctx context.Context) error {
|
||||
if err := module.store.DeleteBySource(ctx, orgID, source.StringValue()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return module.setDefaultForSource(ctx, orgID, source)
|
||||
})
|
||||
}
|
||||
|
||||
func (module *module) SetDefaultConfig(ctx context.Context, orgID valuer.UUID) error {
|
||||
for _, source := range dashboardtypes.AllSources {
|
||||
if err := module.setDefaultForSource(ctx, orgID, source); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (module *module) setDefaultForSource(ctx context.Context, orgID valuer.UUID, source dashboardtypes.Source) error {
|
||||
existing, err := module.store.GetBySource(ctx, orgID, source.StringValue())
|
||||
if err != nil && !errors.Ast(err, errors.TypeNotFound) {
|
||||
return err
|
||||
}
|
||||
if existing != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
dashboard, err := dashboardtypes.NewSystemDashboardDefault(orgID, source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
storableDashboard, err := dashboardtypes.NewStorableDashboardFromDashboard(dashboard)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return module.store.Create(ctx, storableDashboard)
|
||||
}
|
||||
24
pkg/modules/systemdashboard/systemdashboard.go
Normal file
24
pkg/modules/systemdashboard/systemdashboard.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package systemdashboard
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/types/dashboardtypes"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
)
|
||||
|
||||
type Module interface {
|
||||
Get(ctx context.Context, orgID valuer.UUID, source dashboardtypes.Source) (*dashboardtypes.Dashboard, error)
|
||||
Update(ctx context.Context, orgID valuer.UUID, source dashboardtypes.Source, updatedBy string, data dashboardtypes.UpdatableDashboard) (*dashboardtypes.Dashboard, error)
|
||||
Delete(ctx context.Context, orgID valuer.UUID, source dashboardtypes.Source) error
|
||||
SetDefaultConfig(ctx context.Context, orgID valuer.UUID) error
|
||||
}
|
||||
|
||||
// Handler defines the HTTP handler interface for system dashboard endpoints.
|
||||
// /api/v1/system/{source}/dashboard.
|
||||
type Handler interface {
|
||||
Get(http.ResponseWriter, *http.Request)
|
||||
Update(http.ResponseWriter, *http.Request)
|
||||
Delete(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
@@ -38,6 +38,8 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/modules/services/implservices"
|
||||
"github.com/SigNoz/signoz/pkg/modules/spanpercentile"
|
||||
"github.com/SigNoz/signoz/pkg/modules/spanpercentile/implspanpercentile"
|
||||
"github.com/SigNoz/signoz/pkg/modules/systemdashboard"
|
||||
"github.com/SigNoz/signoz/pkg/modules/systemdashboard/implsystemdashboard"
|
||||
"github.com/SigNoz/signoz/pkg/modules/tracefunnel"
|
||||
"github.com/SigNoz/signoz/pkg/modules/tracefunnel/impltracefunnel"
|
||||
"github.com/SigNoz/signoz/pkg/querier"
|
||||
@@ -49,6 +51,7 @@ type Handlers struct {
|
||||
SavedView savedview.Handler
|
||||
Apdex apdex.Handler
|
||||
Dashboard dashboard.Handler
|
||||
SystemDashboard systemdashboard.Handler
|
||||
QuickFilter quickfilter.Handler
|
||||
TraceFunnel tracefunnel.Handler
|
||||
RawDataExport rawdataexport.Handler
|
||||
@@ -90,6 +93,7 @@ func NewHandlers(
|
||||
SavedView: implsavedview.NewHandler(modules.SavedView),
|
||||
Apdex: implapdex.NewHandler(modules.Apdex),
|
||||
Dashboard: impldashboard.NewHandler(modules.Dashboard, providerSettings, authz),
|
||||
SystemDashboard: implsystemdashboard.NewHandler(modules.SystemDashboard),
|
||||
QuickFilter: implquickfilter.NewHandler(modules.QuickFilter),
|
||||
TraceFunnel: impltracefunnel.NewHandler(modules.TraceFunnel),
|
||||
RawDataExport: implrawdataexport.NewHandler(modules.RawDataExport),
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/modules/authdomain/implauthdomain"
|
||||
"github.com/SigNoz/signoz/pkg/modules/cloudintegration"
|
||||
"github.com/SigNoz/signoz/pkg/modules/dashboard"
|
||||
"github.com/SigNoz/signoz/pkg/modules/dashboard/impldashboard"
|
||||
"github.com/SigNoz/signoz/pkg/modules/metricsexplorer"
|
||||
"github.com/SigNoz/signoz/pkg/modules/metricsexplorer/implmetricsexplorer"
|
||||
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||
@@ -37,6 +38,8 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/modules/session/implsession"
|
||||
"github.com/SigNoz/signoz/pkg/modules/spanpercentile"
|
||||
"github.com/SigNoz/signoz/pkg/modules/spanpercentile/implspanpercentile"
|
||||
"github.com/SigNoz/signoz/pkg/modules/systemdashboard"
|
||||
"github.com/SigNoz/signoz/pkg/modules/systemdashboard/implsystemdashboard"
|
||||
"github.com/SigNoz/signoz/pkg/modules/tracefunnel"
|
||||
"github.com/SigNoz/signoz/pkg/modules/tracefunnel/impltracefunnel"
|
||||
"github.com/SigNoz/signoz/pkg/modules/user"
|
||||
@@ -61,6 +64,7 @@ type Modules struct {
|
||||
SavedView savedview.Module
|
||||
Apdex apdex.Module
|
||||
Dashboard dashboard.Module
|
||||
SystemDashboard systemdashboard.Module
|
||||
QuickFilter quickfilter.Module
|
||||
TraceFunnel tracefunnel.Module
|
||||
RawDataExport rawdataexport.Module
|
||||
@@ -98,7 +102,8 @@ func NewModules(
|
||||
cloudIntegrationModule cloudintegration.Module,
|
||||
) Modules {
|
||||
quickfilter := implquickfilter.NewModule(implquickfilter.NewStore(sqlstore))
|
||||
orgSetter := implorganization.NewSetter(implorganization.NewStore(sqlstore), alertmanager, quickfilter)
|
||||
systemDashboard := implsystemdashboard.NewModule(impldashboard.NewStore(sqlstore))
|
||||
orgSetter := implorganization.NewSetter(implorganization.NewStore(sqlstore), alertmanager, quickfilter, systemDashboard)
|
||||
userSetter := impluser.NewSetter(impluser.NewStore(sqlstore, providerSettings), tokenizer, emailing, providerSettings, orgSetter, authz, analytics, config.User, userRoleStore, userGetter)
|
||||
ruleStore := sqlrulestore.NewRuleStore(sqlstore, queryParser, providerSettings)
|
||||
|
||||
@@ -109,6 +114,7 @@ func NewModules(
|
||||
SavedView: implsavedview.NewModule(sqlstore),
|
||||
Apdex: implapdex.NewModule(sqlstore),
|
||||
Dashboard: dashboard,
|
||||
SystemDashboard: systemDashboard,
|
||||
UserSetter: userSetter,
|
||||
UserGetter: userGetter,
|
||||
QuickFilter: quickfilter,
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/modules/rulestatehistory"
|
||||
"github.com/SigNoz/signoz/pkg/modules/serviceaccount"
|
||||
"github.com/SigNoz/signoz/pkg/modules/session"
|
||||
"github.com/SigNoz/signoz/pkg/modules/systemdashboard"
|
||||
"github.com/SigNoz/signoz/pkg/modules/user"
|
||||
"github.com/SigNoz/signoz/pkg/querier"
|
||||
"github.com/SigNoz/signoz/pkg/ruler"
|
||||
@@ -60,6 +61,7 @@ func NewOpenAPI(ctx context.Context, instrumentation instrumentation.Instrumenta
|
||||
struct{ flagger.Handler }{},
|
||||
struct{ dashboard.Module }{},
|
||||
struct{ dashboard.Handler }{},
|
||||
struct{ systemdashboard.Handler }{},
|
||||
struct{ metricsexplorer.Handler }{},
|
||||
struct{ gateway.Handler }{},
|
||||
struct{ fields.Handler }{},
|
||||
|
||||
@@ -194,6 +194,7 @@ func NewSQLMigrationProviderFactories(
|
||||
sqlmigration.NewDeprecateAPIKeyFactory(sqlstore, sqlschema),
|
||||
sqlmigration.NewServiceAccountAuthzactory(sqlstore),
|
||||
sqlmigration.NewDropUserDeletedAtFactory(sqlstore, sqlschema),
|
||||
sqlmigration.NewAddSystemDashboardFactory(sqlstore, sqlschema),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -270,6 +271,7 @@ func NewAPIServerProviderFactories(orgGetter organization.Getter, authz authz.Au
|
||||
handlers.FlaggerHandler,
|
||||
modules.Dashboard,
|
||||
handlers.Dashboard,
|
||||
handlers.SystemDashboard,
|
||||
handlers.MetricsExplorer,
|
||||
handlers.GatewayHandler,
|
||||
handlers.Fields,
|
||||
|
||||
120
pkg/sqlmigration/077_add_system_dashboard.go
Normal file
120
pkg/sqlmigration/077_add_system_dashboard.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/types/dashboardtypes"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
)
|
||||
|
||||
type addSystemDashboard struct {
|
||||
sqlstore sqlstore.SQLStore
|
||||
sqlschema sqlschema.SQLSchema
|
||||
}
|
||||
|
||||
func NewAddSystemDashboardFactory(sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_system_dashboard"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return &addSystemDashboard{sqlstore: sqlstore, sqlschema: sqlschema}, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (migration *addSystemDashboard) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addSystemDashboard) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
exists, err := migration.sqlstore.Dialect().ColumnExists(ctx, tx, "dashboard", "source")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
table, uniqueConstraints, err := migration.sqlschema.GetTable(ctx, sqlschema.TableName("dashboard"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
column := &sqlschema.Column{
|
||||
Name: sqlschema.ColumnName("source"),
|
||||
DataType: sqlschema.DataTypeText,
|
||||
Nullable: false,
|
||||
}
|
||||
|
||||
sqls := migration.sqlschema.Operator().AddColumn(table, uniqueConstraints, column, "")
|
||||
for _, sql := range sqls {
|
||||
if _, err := tx.ExecContext(ctx, string(sql)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var orgIDs []string
|
||||
if err := tx.NewSelect().Model((*types.Organization)(nil)).Column("id").Scan(ctx, &orgIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, rawOrgID := range orgIDs {
|
||||
orgID, err := valuer.NewUUID(rawOrgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, source := range dashboardtypes.AllSources {
|
||||
count, err := tx.NewSelect().
|
||||
Model((*dashboardtypes.StorableDashboard)(nil)).
|
||||
Where("org_id = ?", orgID).
|
||||
Where("source = ?", source.StringValue()).
|
||||
Count(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
dashboard, err := dashboardtypes.NewSystemDashboardDefault(orgID, source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
storable, err := dashboardtypes.NewStorableDashboardFromDashboard(dashboard)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := tx.NewInsert().Model(storable).Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addSystemDashboard) Down(context.Context, *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
107
pkg/types/dashboardtypes/ai_o11y_overview.json
Normal file
107
pkg/types/dashboardtypes/ai_o11y_overview.json
Normal file
@@ -0,0 +1,107 @@
|
||||
{
|
||||
"title": "AI Observability Overview",
|
||||
"description": "AI / LLM observability overview — cost, tokens, latency, errors, RED for tool calls, and time to first token. Scoped by model, environment and service (apply via the variable bar).",
|
||||
"tags": ["ai", "llm", "genai", "overview"],
|
||||
"version": "v5",
|
||||
"variables": {
|
||||
"model": {
|
||||
"id": "a1000000-0000-0000-0000-000000000001",
|
||||
"name": "model",
|
||||
"key": "model",
|
||||
"description": "LLM model",
|
||||
"type": "QUERY",
|
||||
"sort": "ASC",
|
||||
"multiSelect": true,
|
||||
"showALLOption": true,
|
||||
"allSelected": true,
|
||||
"queryValue": "SELECT DISTINCT stringTagMap['gen_ai.request.model'] AS model FROM signoz_traces.distributed_signoz_index_v3 WHERE has(stringTagMap, 'gen_ai.request.model') AND timestamp >= now() - INTERVAL 1 DAY",
|
||||
"customValue": "",
|
||||
"textboxValue": "",
|
||||
"selectedValue": [],
|
||||
"order": 0,
|
||||
"modificationUUID": "a1000000-0000-0000-0000-000000000011"
|
||||
},
|
||||
"environment": {
|
||||
"id": "a1000000-0000-0000-0000-000000000002",
|
||||
"name": "environment",
|
||||
"key": "environment",
|
||||
"description": "Deployment environment",
|
||||
"type": "QUERY",
|
||||
"sort": "ASC",
|
||||
"multiSelect": true,
|
||||
"showALLOption": true,
|
||||
"allSelected": true,
|
||||
"queryValue": "SELECT DISTINCT resourceTagsMap['deployment.environment'] AS environment FROM signoz_traces.distributed_signoz_index_v3 WHERE has(resourceTagsMap, 'deployment.environment') AND timestamp >= now() - INTERVAL 1 DAY",
|
||||
"customValue": "",
|
||||
"textboxValue": "",
|
||||
"selectedValue": [],
|
||||
"order": 1,
|
||||
"modificationUUID": "a1000000-0000-0000-0000-000000000012"
|
||||
},
|
||||
"service_name": {
|
||||
"id": "a1000000-0000-0000-0000-000000000003",
|
||||
"name": "service_name",
|
||||
"key": "service_name",
|
||||
"description": "Service name",
|
||||
"type": "QUERY",
|
||||
"sort": "ASC",
|
||||
"multiSelect": true,
|
||||
"showALLOption": true,
|
||||
"allSelected": true,
|
||||
"queryValue": "SELECT DISTINCT serviceName FROM signoz_traces.distributed_signoz_index_v3 WHERE timestamp >= now() - INTERVAL 1 DAY",
|
||||
"customValue": "",
|
||||
"textboxValue": "",
|
||||
"selectedValue": [],
|
||||
"order": 2,
|
||||
"modificationUUID": "a1000000-0000-0000-0000-000000000013"
|
||||
}
|
||||
},
|
||||
"layout": [
|
||||
{"i": "11111111-1111-1111-1111-111111111111", "x": 0, "y": 0, "w": 3, "h": 3, "moved": false, "static": false},
|
||||
{"i": "22222222-2222-2222-2222-222222222222", "x": 3, "y": 0, "w": 3, "h": 3, "moved": false, "static": false},
|
||||
{"i": "33333333-3333-3333-3333-333333333333", "x": 6, "y": 0, "w": 2, "h": 3, "moved": false, "static": false},
|
||||
{"i": "44444444-4444-4444-4444-444444444444", "x": 8, "y": 0, "w": 2, "h": 3, "moved": false, "static": false},
|
||||
{"i": "55555555-5555-5555-5555-555555555555", "x": 10, "y": 0, "w": 2, "h": 3, "moved": false, "static": false},
|
||||
{"i": "66666666-6666-6666-6666-666666666666", "x": 0, "y": 3, "w": 6, "h": 4, "moved": false, "static": false},
|
||||
{"i": "77777777-7777-7777-7777-777777777777", "x": 6, "y": 3, "w": 6, "h": 4, "moved": false, "static": false},
|
||||
{"i": "88888888-8888-8888-8888-888888888888", "x": 0, "y": 7, "w": 6, "h": 4, "moved": false, "static": false},
|
||||
{"i": "99999999-9999-9999-9999-999999999999", "x": 6, "y": 7, "w": 6, "h": 4, "moved": false, "static": false},
|
||||
{"i": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "x": 0, "y": 11, "w": 4, "h": 4, "moved": false, "static": false},
|
||||
{"i": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "x": 4, "y": 11, "w": 4, "h": 4, "moved": false, "static": false},
|
||||
{"i": "cccccccc-cccc-cccc-cccc-cccccccccccc", "x": 8, "y": 11, "w": 4, "h": 4, "moved": false, "static": false},
|
||||
{"i": "dddddddd-dddd-dddd-dddd-dddddddddddd", "x": 0, "y": 15, "w": 4, "h": 4, "moved": false, "static": false},
|
||||
{"i": "eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee", "x": 4, "y": 15, "w": 4, "h": 4, "moved": false, "static": false},
|
||||
{"i": "ffffffff-ffff-ffff-ffff-ffffffffffff", "x": 8, "y": 15, "w": 4, "h": 4, "moved": false, "static": false}
|
||||
],
|
||||
"widgets": [
|
||||
{"id": "11111111-1111-1111-1111-111111111111", "title": "Total cost", "description": "Total LLM cost across all calls. Requires gen_ai.usage.cost attribute.", "panelTypes": "value", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "none", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "q1111111-1111-1111-1111-111111111111", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "sum(gen_ai.usage.cost)"}], "filter": {"expression": ""}, "groupBy": [], "expression": "A", "orderBy": [], "legend": "", "disabled": false, "having": {"expression": ""}, "limit": null, "reduceTo": "sum"}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "22222222-2222-2222-2222-222222222222", "title": "Total tokens", "description": "Sum of input + output tokens.", "panelTypes": "value", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "short", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "q2222222-2222-2222-2222-222222222222", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "sum(gen_ai.usage.input_tokens) + sum(gen_ai.usage.output_tokens)"}], "filter": {"expression": ""}, "groupBy": [], "expression": "A", "orderBy": [], "legend": "", "disabled": false, "having": {"expression": ""}, "limit": null, "reduceTo": "sum"}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "33333333-3333-3333-3333-333333333333", "title": "Avg latency (p95)", "description": "p95 latency of LLM spans.", "panelTypes": "value", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "ns", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "q3333333-3333-3333-3333-333333333333", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "p95(duration_nano)"}], "filter": {"expression": "gen_ai.system != ''"}, "groupBy": [], "expression": "A", "orderBy": [], "legend": "", "disabled": false, "having": {"expression": ""}, "limit": null, "reduceTo": "avg"}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "44444444-4444-4444-4444-444444444444", "title": "Error rate", "description": "Error rate as a percentage of total LLM calls.", "panelTypes": "value", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "percent", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "q4444444-4444-4444-4444-444444444444", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "countIf(has_error = true) * 100 / count()"}], "filter": {"expression": "gen_ai.system != ''"}, "groupBy": [], "expression": "A", "orderBy": [], "legend": "", "disabled": false, "having": {"expression": ""}, "limit": null, "reduceTo": "avg"}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "55555555-5555-5555-5555-555555555555", "title": "TTFT (p95)", "description": "p95 time to first token.", "panelTypes": "value", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "ms", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "q5555555-5555-5555-5555-555555555555", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "p95(gen_ai.server.ttft)"}], "filter": {"expression": ""}, "groupBy": [], "expression": "A", "orderBy": [], "legend": "", "disabled": false, "having": {"expression": ""}, "limit": null, "reduceTo": "avg"}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "66666666-6666-6666-6666-666666666666", "title": "Cost over time", "description": "Cost by model over time.", "panelTypes": "graph", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "none", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "q6666666-6666-6666-6666-666666666666", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "sum(gen_ai.usage.cost)"}], "filter": {"expression": ""}, "groupBy": [{"key": "gen_ai.request.model", "dataType": "string", "type": "tag", "isColumn": false, "isJSON": false}], "expression": "A", "orderBy": [], "legend": "{{gen_ai.request.model}}", "disabled": false, "having": {"expression": ""}, "limit": null}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "77777777-7777-7777-7777-777777777777", "title": "Token usage over time", "description": "Input vs output tokens over time.", "panelTypes": "graph", "nullZeroValues": "zero", "opacity": "1", "isStacked": true, "fillSpans": false, "yAxisUnit": "short", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "q7777777-7777-7777-7777-777777777777", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "sum(gen_ai.usage.input_tokens)"}], "filter": {"expression": ""}, "groupBy": [], "expression": "A", "orderBy": [], "legend": "Input", "disabled": false, "having": {"expression": ""}, "limit": null}, {"queryName": "B", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "sum(gen_ai.usage.output_tokens)"}], "filter": {"expression": ""}, "groupBy": [], "expression": "B", "orderBy": [], "legend": "Output", "disabled": false, "having": {"expression": ""}, "limit": null}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "88888888-8888-8888-8888-888888888888", "title": "LLM call latency percentiles", "description": "p50, p90, p95, p99 latency by model.", "panelTypes": "table", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "ns", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "q8888888-8888-8888-8888-888888888888", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "p50(duration_nano)"}, {"expression": "p90(duration_nano)"}, {"expression": "p95(duration_nano)"}, {"expression": "p99(duration_nano)"}], "filter": {"expression": "gen_ai.system != ''"}, "groupBy": [{"key": "gen_ai.request.model", "dataType": "string", "type": "tag", "isColumn": false, "isJSON": false}], "expression": "A", "orderBy": [], "legend": "{{gen_ai.request.model}}", "disabled": false, "having": {"expression": ""}, "limit": null}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "99999999-9999-9999-9999-999999999999", "title": "LLM call latency over time", "description": "p95 latency trend by model.", "panelTypes": "graph", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "ns", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "q9999999-9999-9999-9999-999999999999", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "p95(duration_nano)"}], "filter": {"expression": "gen_ai.system != ''"}, "groupBy": [{"key": "gen_ai.request.model", "dataType": "string", "type": "tag", "isColumn": false, "isJSON": false}], "expression": "A", "orderBy": [], "legend": "{{gen_ai.request.model}}", "disabled": false, "having": {"expression": ""}, "limit": null}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "title": "Error count", "description": "Errors grouped by error type.", "panelTypes": "graph", "nullZeroValues": "zero", "opacity": "1", "isStacked": true, "fillSpans": false, "yAxisUnit": "short", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "qaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "count()"}], "filter": {"expression": "has_error = true AND gen_ai.system != ''"}, "groupBy": [{"key": "gen_ai.error.type", "dataType": "string", "type": "tag", "isColumn": false, "isJSON": false}], "expression": "A", "orderBy": [], "legend": "{{gen_ai.error.type}}", "disabled": false, "having": {"expression": ""}, "limit": null}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "title": "Time to first token", "description": "p95 TTFT by model.", "panelTypes": "graph", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "ms", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "qbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "p95(gen_ai.server.ttft)"}], "filter": {"expression": ""}, "groupBy": [{"key": "gen_ai.request.model", "dataType": "string", "type": "tag", "isColumn": false, "isJSON": false}], "expression": "A", "orderBy": [], "legend": "{{gen_ai.request.model}}", "disabled": false, "having": {"expression": ""}, "limit": null}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "cccccccc-cccc-cccc-cccc-cccccccccccc", "title": "Top 10 span names", "description": "Top span names by count across GenAI spans.", "panelTypes": "table", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "none", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "qccccccc-cccc-cccc-cccc-cccccccccccc", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "count()"}], "filter": {"expression": "gen_ai.system != ''"}, "groupBy": [{"key": "name", "dataType": "string", "type": "tag", "isColumn": true, "isJSON": false}], "expression": "A", "orderBy": [{"columnName": "count()", "order": "desc"}], "legend": "{{name}}", "disabled": false, "having": {"expression": ""}, "limit": 10}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "dddddddd-dddd-dddd-dddd-dddddddddddd", "title": "Tool call rate", "description": "Tool call rate per second.", "panelTypes": "graph", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "reqps", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "qddddddd-dddd-dddd-dddd-dddddddddddd", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "rate()"}], "filter": {"expression": "name = 'execute_tool'"}, "groupBy": [], "expression": "A", "orderBy": [], "legend": "req/s", "disabled": false, "having": {"expression": ""}, "limit": null}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee", "title": "Tool error rate", "description": "Percentage of tool calls that errored.", "panelTypes": "graph", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "percent", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "qeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "countIf(has_error = true) * 100 / count()"}], "filter": {"expression": "name = 'execute_tool'"}, "groupBy": [], "expression": "A", "orderBy": [], "legend": "error %", "disabled": false, "having": {"expression": ""}, "limit": null}], "queryFormulas": [], "queryTraceOperator": []}}},
|
||||
|
||||
{"id": "ffffffff-ffff-ffff-ffff-ffffffffffff", "title": "Tool duration (p50)", "description": "Median tool call duration.", "panelTypes": "graph", "nullZeroValues": "zero", "opacity": "1", "isStacked": false, "fillSpans": false, "yAxisUnit": "ns", "timePreferance": "GLOBAL_TIME", "softMax": null, "softMin": null, "thresholds": [], "selectedLogFields": [], "selectedTracesFields": [], "query": {"queryType": "builder", "promql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "clickhouse_sql": [{"disabled": false, "legend": "", "name": "A", "query": ""}], "id": "qfffffff-ffff-ffff-ffff-ffffffffffff", "builder": {"queryData": [{"queryName": "A", "stepInterval": 60, "dataSource": "traces", "aggregations": [{"expression": "p50(duration_nano)"}], "filter": {"expression": "name = 'execute_tool'"}, "groupBy": [], "expression": "A", "orderBy": [], "legend": "p50", "disabled": false, "having": {"expression": ""}, "limit": null}], "queryFormulas": [], "queryTraceOperator": []}}}
|
||||
]
|
||||
}
|
||||
@@ -37,6 +37,7 @@ type StorableDashboard struct {
|
||||
Data StorableDashboardData `bun:"data,type:text,notnull"`
|
||||
Locked bool `bun:"locked,notnull,default:false"`
|
||||
OrgID valuer.UUID `bun:"org_id,notnull"`
|
||||
Source string `bun:"source,type:text,notnull"`
|
||||
}
|
||||
|
||||
type Dashboard struct {
|
||||
@@ -47,6 +48,7 @@ type Dashboard struct {
|
||||
Data StorableDashboardData `json:"data"`
|
||||
Locked bool `json:"locked"`
|
||||
OrgID valuer.UUID `json:"org_id"`
|
||||
Source string `json:"source"`
|
||||
}
|
||||
|
||||
type LockUnlockDashboard struct {
|
||||
@@ -86,6 +88,7 @@ func NewStorableDashboardFromDashboard(dashboard *Dashboard) (*StorableDashboard
|
||||
OrgID: dashboard.OrgID,
|
||||
Data: dashboard.Data,
|
||||
Locked: dashboard.Locked,
|
||||
Source: dashboard.Source,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -108,6 +111,31 @@ func NewDashboard(orgID valuer.UUID, createdBy string, storableDashboardData Sto
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewSystemDashboard builds a Dashboard owned by the system idetified by source (e.g. "ai-o11y-overview")
|
||||
func NewSystemDashboard(orgID valuer.UUID, source string, data StorableDashboardData) (*Dashboard, error) {
|
||||
if source == "" {
|
||||
return nil, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "source is required for a system dashboard")
|
||||
}
|
||||
|
||||
currentTime := time.Now()
|
||||
|
||||
return &Dashboard{
|
||||
ID: valuer.GenerateUUID().StringValue(),
|
||||
TimeAuditable: types.TimeAuditable{
|
||||
CreatedAt: currentTime,
|
||||
UpdatedAt: currentTime,
|
||||
},
|
||||
UserAuditable: types.UserAuditable{
|
||||
CreatedBy: "system",
|
||||
UpdatedBy: "system",
|
||||
},
|
||||
OrgID: orgID,
|
||||
Data: data,
|
||||
Locked: false,
|
||||
Source: source,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewDashboardFromStorableDashboard(storableDashboard *StorableDashboard) *Dashboard {
|
||||
return &Dashboard{
|
||||
ID: storableDashboard.ID.StringValue(),
|
||||
@@ -122,6 +150,7 @@ func NewDashboardFromStorableDashboard(storableDashboard *StorableDashboard) *Da
|
||||
OrgID: storableDashboard.OrgID,
|
||||
Data: storableDashboard.Data,
|
||||
Locked: storableDashboard.Locked,
|
||||
Source: storableDashboard.Source,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,6 +183,7 @@ func NewGettableDashboardFromDashboard(dashboard *Dashboard) (*GettableDashboard
|
||||
OrgID: dashboard.OrgID,
|
||||
Data: dashboard.Data,
|
||||
Locked: dashboard.Locked,
|
||||
Source: dashboard.Source,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
30
pkg/types/dashboardtypes/defaults.go
Normal file
30
pkg/types/dashboardtypes/defaults.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package dashboardtypes
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
)
|
||||
|
||||
//go:embed ai_o11y_overview.json
|
||||
var aIO11yOverviewJSON []byte
|
||||
|
||||
func NewSystemDashboardDefault(orgID valuer.UUID, source Source) (*Dashboard, error) {
|
||||
switch source {
|
||||
case SourceAIO11yOverview:
|
||||
return newAIO11yOverviewDefault(orgID)
|
||||
default:
|
||||
return nil, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "no defaults registered for system dashboard source %s", source.StringValue())
|
||||
}
|
||||
}
|
||||
|
||||
func newAIO11yOverviewDefault(orgID valuer.UUID) (*Dashboard, error) {
|
||||
data := StorableDashboardData{}
|
||||
if err := json.Unmarshal(aIO11yOverviewJSON, &data); err != nil {
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, "failed to unmarshal embedded ai-o11y-overview default")
|
||||
}
|
||||
|
||||
return NewSystemDashboard(orgID, SourceAIO11yOverview.StringValue(), data)
|
||||
}
|
||||
44
pkg/types/dashboardtypes/source.go
Normal file
44
pkg/types/dashboardtypes/source.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package dashboardtypes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
)
|
||||
|
||||
type Source struct {
|
||||
valuer.String
|
||||
}
|
||||
|
||||
var (
|
||||
SourceAIO11yOverview = Source{valuer.NewString("ai-o11y-overview")}
|
||||
)
|
||||
|
||||
var AllSources = []Source{
|
||||
SourceAIO11yOverview,
|
||||
}
|
||||
|
||||
func NewSource(s string) (Source, error) {
|
||||
switch s {
|
||||
case SourceAIO11yOverview.StringValue():
|
||||
return SourceAIO11yOverview, nil
|
||||
default:
|
||||
return Source{}, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "invalid system dashboard source: %s", s)
|
||||
}
|
||||
}
|
||||
|
||||
func (source *Source) UnmarshalJSON(data []byte) error {
|
||||
var str string
|
||||
if err := json.Unmarshal(data, &str); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s, err := NewSource(str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*source = s
|
||||
return nil
|
||||
}
|
||||
@@ -13,6 +13,8 @@ type Store interface {
|
||||
|
||||
Get(context.Context, valuer.UUID, valuer.UUID) (*StorableDashboard, error)
|
||||
|
||||
GetBySource(context.Context, valuer.UUID, string) (*StorableDashboard, error)
|
||||
|
||||
GetPublic(context.Context, string) (*StorablePublicDashboard, error)
|
||||
|
||||
GetDashboardByOrgsAndPublicID(context.Context, []string, string) (*StorableDashboard, error)
|
||||
@@ -25,10 +27,14 @@ type Store interface {
|
||||
|
||||
Update(context.Context, valuer.UUID, *StorableDashboard) error
|
||||
|
||||
UpdateBySource(context.Context, valuer.UUID, string, *StorableDashboard) error
|
||||
|
||||
UpdatePublic(context.Context, *StorablePublicDashboard) error
|
||||
|
||||
Delete(context.Context, valuer.UUID, valuer.UUID) error
|
||||
|
||||
DeleteBySource(context.Context, valuer.UUID, string) error
|
||||
|
||||
DeletePublic(context.Context, string) error
|
||||
|
||||
RunInTx(context.Context, func(context.Context) error) error
|
||||
|
||||
35
pkg/types/dashboardtypes/system_dashboard.go
Normal file
35
pkg/types/dashboardtypes/system_dashboard.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package dashboardtypes
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
)
|
||||
|
||||
type GettableSystemDashboard struct {
|
||||
ID string `json:"id"`
|
||||
OrgID valuer.UUID `json:"orgId"`
|
||||
Source string `json:"source"`
|
||||
Data StorableDashboardData `json:"data"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
CreatedBy string `json:"createdBy"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
UpdatedBy string `json:"updatedBy"`
|
||||
}
|
||||
|
||||
type UpdatableSystemDashboard struct {
|
||||
Data StorableDashboardData `json:"data"`
|
||||
}
|
||||
|
||||
func NewGettableSystemDashboardFromDashboard(dashboard *Dashboard) *GettableSystemDashboard {
|
||||
return &GettableSystemDashboard{
|
||||
ID: dashboard.ID,
|
||||
OrgID: dashboard.OrgID,
|
||||
Source: dashboard.Source,
|
||||
Data: dashboard.Data,
|
||||
CreatedAt: dashboard.CreatedAt,
|
||||
CreatedBy: dashboard.CreatedBy,
|
||||
UpdatedAt: dashboard.UpdatedAt,
|
||||
UpdatedBy: dashboard.UpdatedBy,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user