대시보드
대시보드 API를 사용하면 수집 및 쿼리 작업에 이미 사용하고 있는 것과 동일한 API 키를 사용하여 프로그래밍 방식으로 대시보드를 나열, 생성, 편집 및 삭제할 수 있습니다.
지원되는 작업:
- 목록.
GET https://api.telemetry.sh/dashboard - 만들기.
POST https://api.telemetry.sh/dashboard - 편집.
PATCH https://api.telemetry.sh/dashboard - 삭제.
DELETE https://api.telemetry.sh/dashboard
헤더
| 이름 | 유형 | 설명 |
|---|---|---|
Content-Type |
문자열 | application/json여야 합니다. |
Authorization |
문자열 | API 키(원시 키 또는 Bearer <key>) |
범위 규칙:
GET /dashboard는read,write또는read-and-write를 허용합니다.POST /dashboard,PATCH /dashboard및DELETE /dashboard에는write또는read-and-write가 필요합니다.
응답 나열
GET /dashboard는 updated_at DESC에서 주문한 API 키 팀의 모든 대시보드를 반환합니다.
지원되는 쿼리 매개변수:
| 필드 | 유형 | 필수 | 정확한 계약 | 기본값 |
|---|---|---|---|---|
page |
정수 | 아니요 | 양의 정수 페이지 번호입니다. 1보다 작은 값은 거부됩니다. |
1 |
pageSize |
정수 | 아니요 | 양의 정수 페이지 크기. 100보다 큰 값은 100로 고정됩니다. API는 레거시 별칭 page_size도 허용합니다. |
50 |
각 항목에는 대시보드 메타데이터, url, widget_count 및 API 모양의 전체 위젯 목록이 포함됩니다.
최상위 응답:
| 필드 | 유형 | 정확한 계약 |
|---|---|---|
status |
문자열 | 항상 성공하면 "success"입니다. |
pagination |
객체 | 현재 페이지의 페이지 매김 메타데이터입니다. 아래 표를 참조하세요. |
dashboards |
배열 | API 키 팀의 대시보드 개체 배열입니다. 팀에 대시보드가 없는 경우 빈 배열입니다. |
pagination에는 다음이 포함됩니다.
| 필드 | 유형 | 정확한 계약 | 예 |
|---|---|---|---|
page |
정수 | 현재 1 기반 페이지 번호입니다. | 2 |
pageSize |
정수 | 기본값 설정 및 최대 크기 고정 후 효과적인 페이지 크기입니다. | 25 |
total |
정수 | 페이지를 매기기 전 팀의 총 대시보드 수입니다. | 63 |
totalPages |
정수 | 현재 pageSize의 총 페이지 수입니다. total가 0인 경우 0입니다. |
3 |
hasNextPage |
부울 | 현재 페이지 뒤에 다른 페이지가 존재할 때 true. |
true |
hasPreviousPage |
부울 | 현재 페이지 앞에 다른 페이지가 존재할 때 true. |
true |
dashboards의 각 항목에는 다음이 포함됩니다.
| 필드 | 유형 | 정확한 계약 | 예 |
|---|---|---|---|
id |
문자열 | 대시보드 ID | "550e8400-e29b-41d4-a716-446655440000" |
team_id |
문자열 | 소유한 팀 ID입니다. | "a7d4..." |
name |
문자열 | 대시보드 이름. | "Operations Overview" |
slug |
문자열 | 대시보드 슬러그. | "operations-overview" |
description |
문자열 또는 null |
대시보드 설명이 저장되었습니다. | "Core service health and latency" |
created_by |
문자열 또는 null |
UI로 생성된 대시보드의 사용자 ID입니다. API가 생성한 대시보드용 null입니다. |
null |
created_by_api_key_id |
문자열 또는 null |
API가 생성한 대시보드의 팀 API 키 ID입니다. UI로 생성된 대시보드용 null. |
"key_123" |
created_at |
문자열 | 대시보드 테이블의 타임스탬프 문자열입니다. | "2026-03-27T00:09:03.797Z" |
updated_at |
문자열 | 대시보드 테이블의 타임스탬프 문자열입니다. | "2026-03-27T00:09:03.797Z" |
url |
문자열 | Telemetry UI의 상대 대시보드 URL입니다. | "/team/acme/dashboard/operations-overview" |
widget_count |
정수 | 대시보드에 연결된 위젯 수입니다. | 2 |
widgets |
배열 | 생성 및 편집 응답으로 반환된 동일한 모양의 위젯 배열입니다. | [] |
몸체 만들기
| 필드 | 유형 | 필수 | 정확한 계약 | 예 |
|---|---|---|---|---|
name |
문자열 | 예 | 대시보드 이름이 잘렸습니다. 트리밍 후에는 비어 있지 않아야 합니다. | "HTTP Monitoring" |
slug |
문자열 | 아니요 | 선택적 사용자 정의 슬러그. Telemetry는 트리밍, 소문자화, a-z, 0-9, 공백 및 -를 제외한 모든 문자 제거, 공백 실행을 -로 변환, 반복되는 - 축소 및 트리밍을 통해 정규화합니다. 선행/후행 -. 생략하면 Telemetry는 name에서 파생됩니다. 정규화된 결과에는 최소한 하나의 영숫자가 포함되어야 합니다. |
"HTTP Monitoring!!!"는 "http-monitoring"가 됩니다. |
description |
문자열 또는 null |
아니요 | 선택적 설명입니다. 빈 문자열은 null로 정규화됩니다. |
"Core service health and latency" |
widgets |
배열 | 아니요 | 즉시 생성할 선택적 위젯 배열입니다. 생략하면 대시보드가 비어 있게 생성됩니다. 유효하지 않은 위젯이 있으면 400로 전체 요청이 거부됩니다. |
[] |
응답 만들기
POST /dashboard는 저장된 대시보드와 정규화된 위젯 목록이 포함된 201 Created를 반환합니다.
{
"status": "success",
"dashboard": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"team_id": "a7d4...",
"name": "HTTP Monitoring",
"slug": "http-monitoring",
"description": "Core service health and latency",
"created_by": null,
"created_by_api_key_id": "key_123",
"created_at": "2026-03-27T00:09:03.797Z",
"updated_at": "2026-03-27T00:09:03.797Z",
"url": "/team/acme/dashboard/http-monitoring"
},
"widgets": [
{
"id": "0b3cb3f5-1147-4f2f-bf64-5044147c3e9a",
"title": "Errors Per Hour",
"widget_type": "query",
"config": {
"querySql": "SELECT hour, errors FROM error_rollups",
"chartType": "Line Chart",
"xAxis": "hour",
"yAxis": "errors",
"groupBy": null,
"queryId": null,
"sourceUrl": null
},
"layout": {
"x": 0,
"y": 0,
"w": 12,
"h": 4
},
"sort_order": 1
}
]
}
본문 편집
PATCH /dashboard는 부분 업데이트 엔드포인트입니다. 생략된 필드는 변경되지 않습니다.
dashboardId 또는 dashboardSlug로 대상 대시보드를 식별해야 합니다.
| 필드 | 유형 | 필수 | 정확한 계약 | 예 |
|---|---|---|---|---|
dashboardId |
문자열 | dashboardId 또는 dashboardSlug 중 하나 |
편집할 기존 대시보드 ID입니다. 두 식별자가 모두 전송되면 동일한 대시보드를 참조해야 합니다. | "550e8400-e29b-41d4-a716-446655440000" |
dashboardSlug |
문자열 | dashboardId 또는 dashboardSlug 중 하나 |
편집할 기존 대시보드 슬러그입니다. 이것은 새로운 슬러그가 아닌 현재 슬러그입니다. | "http-monitoring" |
name |
문자열 | 아니요 | 새롭게 정리된 대시보드 이름입니다. 제공되는 경우 비어 있지 않아야 합니다. name를 업데이트해도 슬러그가 자동으로 변경되지 않습니다. |
"HTTP Monitoring v2" |
slug |
문자열 | 아니요 | 새로운 슬러그 값. Telemetry는 생성과 동일한 규칙으로 정규화합니다. 생략하면 기존 슬러그가 변경되지 않고 유지됩니다. | "http-monitoring-v2" |
description |
문자열 또는 null |
아니요 | 새로운 대시보드 설명. null 또는 ""는 설명을 지웁니다. 생략하면 기존 설명이 변경되지 않습니다. |
"Updated on-call dashboard" |
widgets |
배열 | 아니요 | 전체 대체 위젯 목록. 생략하면 기존 위젯은 변경되지 않습니다. 제공된 경우 Telemetry는 현재 위젯 세트를 삭제하고 이를 정확히 이 배열의 위젯으로 대체합니다. []는 모든 위젯을 지웁니다. |
[] |
참고:
PATCH는 아직 단일 위젯 추가 또는 편집을 지원하지 않습니다.widgets가 제공되면 API가 전체 위젯 세트를 대체하므로 위젯 ID가 다시 생성됩니다.
응답 수정
PATCH /dashboard는 create와 동일한 응답 형태로 200 OK를 반환합니다.
dashboard에는 저장된 대시보드 메타데이터와url가 포함되어 있습니다.widgets에는 API 모양의 전체 지속 위젯 목록이 포함되어 있습니다.widgets가 교체된 경우 반환된 위젯 ID는 새로 삽입된 행을 반영합니다.
본문 삭제
DELETE /dashboard는 단일 대시보드와 해당 위젯을 모두 삭제합니다.
dashboardId 또는 dashboardSlug로 대상 대시보드를 식별해야 합니다.
| 필드 | 유형 | 필수 | 정확한 계약 | 예 |
|---|---|---|---|---|
dashboardId |
문자열 | dashboardId 또는 dashboardSlug 중 하나 |
삭제할 기존 대시보드 ID입니다. 두 식별자가 모두 전송되면 동일한 대시보드를 참조해야 합니다. | "550e8400-e29b-41d4-a716-446655440000" |
dashboardSlug |
문자열 | dashboardId 또는 dashboardSlug 중 하나 |
삭제할 기존 대시보드 슬러그입니다. | "http-monitoring" |
참고:
- 삭제는 영구적입니다.
- 대시보드를 삭제하면 현재 대시보드에 연결된 위젯도 모두 삭제됩니다.
응답 삭제
DELETE /dashboard는 200 OK를 반환합니다.
{
"status": "success",
"deleted_dashboard": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "HTTP Monitoring",
"slug": "http-monitoring",
"description": "Core service health and latency",
"widget_count": 2,
"url": "/team/acme/dashboard/http-monitoring"
}
}
일반적인 오류
- JSON 본문이 유효하지 않거나 요청 본문이 JSON 개체가 아닌 경우
400 Bad Request page또는pageSize가GET /dashboard에서 양의 정수가 아닌 경우400 Bad Request400 Bad RequestdashboardId또는dashboardSlug가PATCH또는DELETE에 누락된 경우PATCH가 편집 가능한 모든 필드를 생략하는 경우400 Bad Requestname,slug,description또는widgets가 검증에 실패한 경우400 Bad Request- 쿼리 위젯에 읽기 전용이 아닌 SQL이 포함된 경우
400 Bad Request - API 키에 요청된 작업에 대한 권한이 없는 경우
403 Forbidden - API 키가 없거나 잘못된 경우
401 Unauthorized - API 키 팀에 대한 대시보드가 없는 경우
404 Not Found - 같은 팀의 다른 대시보드가 이미 요청한 슬러그를 사용하는 경우
409 Conflict
위젯 필드
widgets의 각 항목은 다음을 지원합니다.
| 필드 | 유형 | 필수 | 정확한 계약 | 예 |
|---|---|---|---|---|
title |
문자열 | 예 | 잘린 위젯 제목. 트리밍 후에는 비어 있지 않아야 합니다. | "Errors Per Hour" |
widget_type |
문자열 | 예 | 정확한 열거형: query, explorer, header 또는 free_text. |
"query" |
config |
객체 | 예 | 위젯 구성 객체. 필수 필드는 widget_type에 따라 다릅니다. |
{ "querySql": "...", "chartType": "Line Chart" } |
layout |
객체 | 아니요 | 선택적 그리드 배치. 생략하면 Telemetry는 위젯 유형 기본값을 사용하여 위젯을 수직으로 쌓습니다. | { "x": 0, "y": 0, "w": 12, "h": 4 } |
레이아웃 이해
Telemetry 대시보드는 12열 그리드를 사용합니다.
layout 객체는 픽셀이 아닌 그리드 단위를 사용합니다.
| 필드 | 유형 | 기본값 | 정확한 계약 | 예 |
|---|---|---|---|---|
x |
정수 | 0 |
음수가 아닌 정수. 0는 가장 왼쪽입니다. 잘못된 값은 0로 대체됩니다. |
0 |
y |
정수 | 다음 열린 행 | 음수가 아닌 정수. 0는 대시보드 상단입니다. 생략하면 Telemetry는 이전 위젯의 y + h 뒤에 위젯을 배치합니다. 잘못된 값은 해당 계산된 행으로 대체됩니다. |
0 |
w |
정수 | 12 |
그리드 열의 양의 정수 너비입니다. 12는 전체 너비를 의미하고 6는 절반 너비를 의미합니다. 잘못된 값은 12로 대체됩니다. |
12 |
h |
정수 | 위젯 유형 기본값 | 그리드 행의 양의 정수 높이입니다. 잘못된 값은 아래 나열된 위젯 유형 기본값으로 대체됩니다. | 4 |
그래서 이것은:
"layout": { "x": 0, "y": 0, "w": 12, "h": 4 }
의미:
- 대시보드 왼쪽 상단에 위젯을 배치하세요.
- 12개 열을 모두 확장하도록 하세요.
- 대시보드 그리드 행을 4개 높이로 만드세요.
이:
"layout": { "x": 6, "y": 0, "w": 6, "h": 4 }
의미:
- 위젯을 맨 윗줄에 배치하세요
- 대시보드 중간에서 시작하세요
- 행의 오른쪽 절반을 차지하게 만드세요
예를 들어 다음 두 위젯은 나란히 렌더링됩니다.
[
{ "layout": { "x": 0, "y": 0, "w": 6, "h": 4 } },
{ "layout": { "x": 6, "y": 0, "w": 6, "h": 4 } }
]
layout를 생략하면 Telemetry는 다음 기본값을 사용하여 위젯을 수직으로 쌓습니다.
x = 0w = 12query및explorer용h = 4header용h = 2free_text용h = 3y는 다음 열린 행에 배치됩니다.
Telemetry는 x 및 w를 12열 그리드에 고정하지 않으며 겹치는 위치를 자동으로 해결하지 않습니다. 예측 가능한 렌더링을 원하는 경우 x + w <= 12를 유지하고 x/y 범위가 겹치지 않도록 하세요.
쿼리 위젯 구성
| 필드 | 유형 | 필수 | 정확한 값 또는 형식 | 예 |
|---|---|---|---|---|
querySql |
문자열 | 예 | 읽기 전용 SQL 문자열이 잘렸습니다. 트리밍 후에는 비어 있지 않아야 합니다. 대시보드 쿼리 위젯은 INSERT, UPDATE, DELETE, DROP, ALTER, TRUNCATE, CREATE와 같은 쓰기 문을 거부합니다. GRANT 및 REVOKE. |
"SELECT endpoint, COUNT(*) AS errors FROM http_logs GROUP BY endpoint" |
chartType |
문자열 | 예 | API로 검증된 정확한 열거형: table, Scatter Plot, Bar Chart, Line Chart 또는 Stacked Area Chart. |
"Line Chart" |
xAxis |
문자열 | 비table 차트에 필수 |
x축에 사용할 잘린 결과 열 이름입니다. Bar Chart의 경우 이는 텍스트/범주형, 숫자 또는 시간형 열일 수 있습니다. Scatter Plot, Line Chart 및 Stacked Area Chart의 경우 숫자 또는 시간형 열을 사용합니다. chartType가 table인 경우에만 빈 문자열일 수 있습니다. |
"hour" |
yAxis |
문자열 | 비table 차트에 필수 |
y축에 사용할 잘린 숫자 결과 열 이름입니다. chartType가 table인 경우에만 빈 문자열일 수 있습니다. |
"errors" |
groupBy |
문자열 또는 null |
아니요 | 차트를 여러 시리즈로 분할하는 데 사용되는 선택적인 잘린 결과 열 이름입니다. null를 사용하거나 그룹화하지 않으려면 생략하세요. |
"service" |
queryId |
문자열 또는 null |
아니요 | 선택적으로 잘린 저장된 쿼리 ID입니다. API는 이를 문자열로 저장하고 그 모양을 검증하지 않습니다. | "550e8400-e29b-41d4-a716-446655440000" |
sourceUrl |
문자열 또는 null |
아니요 | 위젯 제목을 클릭하면 열리는 선택적 UI URL입니다. /team/acme/ops/draft/0?...와 같은 상대 앱 URL을 사용하는 것이 좋습니다. |
"/team/acme/ops/draft/0?tab=chart&chartType=Line+Chart&xAxis=hour&yAxis=errors" |
참고:
- 차트 대신 일반 결과 테이블을 원하는 경우
chartType: "table"를 사용하세요. - 대시보드 쿼리 위젯은 대시보드가 로드될 때 자동 실행되므로 읽기 전용 SQL만 허용됩니다.
table가 아닌 모든 차트의 경우xAxis및yAxis는querySql에서 반환된 실제 열과 일치해야 합니다.Bar Chart의 경우xAxis는 텍스트/범주형, 숫자 또는 시간형일 수 있습니다.Scatter Plot,Line Chart및Stacked Area Chart의 경우xAxis는 숫자 또는 시간 형식이어야 합니다.table가 아닌 모든 차트의 경우yAxis는 숫자여야 합니다.- 범주형
Bar Chartx축의 경우 위젯은 쿼리 결과 순서를 유지합니다. 막대 순서를 제어하려면querySql에서ORDER BY를 사용하세요. sourceUrl를 생략하면 대시보드 UI는 가능한 경우 대체 초안 쿼리 URL을 파생합니다. 파생된 링크는defaultQuery,tab,chartType,xAxis,yAxis및groupBy를 유지합니다.
예: 범주형 막대 차트 x축이 있는 쿼리 위젯
{
"title": "Requests by Endpoint",
"widget_type": "query",
"config": {
"querySql": "SELECT endpoint, COUNT(*) AS requests FROM http_logs GROUP BY endpoint ORDER BY requests DESC",
"chartType": "Bar Chart",
"xAxis": "endpoint",
"yAxis": "requests",
"groupBy": null
}
}
해당 예에서는 다음과 같습니다.
endpoint는 텍스트 X축 열입니다.requests는 숫자형 y축 열입니다.ORDER BY requests DESC는 왼쪽에서 오른쪽 막대 순서를 제어합니다.
헤더 위젯 구성
관련 위젯을 그룹화하는 섹션 제목에는 widget_type: "header"를 사용하세요.
| 필드 | 유형 | 필수 | 정확한 값 또는 형식 | 예 |
|---|---|---|---|---|
description |
문자열 또는 null |
아니요 | 헤더 제목 아래에 표시되는 선택적 마크다운 설명입니다. 빈 문자열은 null로 정규화됩니다. |
"Watch these charts during deploys and incident triage." |
참고:
- 위젯
title는 표시되는 섹션 제목입니다. description는 마크다운을 지원합니다. 원시 HTML은 UI에서 렌더링되기 전에 이스케이프됩니다.
예:
{
"title": "Deploy Health",
"widget_type": "header",
"config": {
"description": "Use this section during rollout checks and incident response."
}
}
무료 텍스트 위젯 구성
독립형 마크다운 메모, 링크 또는 런북 지침에는 widget_type: "free_text"를 사용하세요.
| 필드 | 유형 | 필수 | 정확한 값 또는 형식 | 예 |
|---|---|---|---|---|
content |
문자열 | 예 | 트리밍 후 비어 있지 않은 마크다운 콘텐츠. | "Check [the latency recipe](/sql/api-latency-percentiles) before paging infra." |
참고:
content는 마크다운을 지원합니다. 원시 HTML은 UI에서 렌더링되기 전에 이스케이프됩니다.- UI가 이 구성 요소 유형에 대한 마크다운 본문만 렌더링하더라도 위젯
title는 여전히 API에 필요합니다.
예:
{
"title": "API Runbook Note",
"widget_type": "free_text",
"config": {
"content": "Check the on-call runbook first, then compare request volume with deploy timestamps."
}
}
탐색기 위젯 구성
| 필드 | 유형 | 필수 | 정확한 값 또는 형식 | 예 |
|---|---|---|---|---|
tableName |
문자열 | 예 | 잘린 소스 테이블 이름입니다. 트리밍 후에는 비어 있지 않아야 합니다. | "queue_metrics" |
explorerState |
객체 | 예 | 위젯을 렌더링하는 데 사용되는 전체 탐색 구성입니다. 아래의 세부 필드 표를 참고하세요. | { "graphType": "line", "aggregation": "p95", ... } |
sourceUrl |
문자열 또는 null |
아니요 | 위젯 제목을 클릭하면 열리는 선택적 UI URL입니다. 생략하면 Telemetry는 tableName 및 explorerState에서 대체 탐색 URL을 파생합니다. |
"/team/acme/table/queue_metrics?tab=explore&graphType=line" |
explorerState 필드
| 필드 | 유형 | 필수 | 정확한 값 또는 형식 | 기본값 | 예 |
|---|---|---|---|---|---|
graphType |
문자열 | 예 | API로 검증된 정확한 열거형: samples, table, line, bar, stacked-area. |
"samples" |
"line" |
aggregation |
문자열 | 예 | API에 의해 검증된 정확한 열거형: count, sum, avg, min, max, p50, p90, p95, p99. |
"count" |
"p95" |
metric |
문자열 또는 null |
아니요 | 집계할 잘린 열 또는 필드 경로입니다. count에는 null를 사용하세요. count가 아닌 집계의 경우 이는 기본 측정값이며 제공된 경우 자동 감지된 숫자 selectedColumns보다 우선합니다. |
null |
"latency_ms" |
timeZone |
문자열 또는 null |
아니요 | UTC 또는 America/Los_Angeles 또는 Europe/Berlin와 같은 IANA 시간대 식별자를 사용합니다. API는 현재 비어 있지 않은 문자열을 자르고 저장하지만 나중에 위젯 쿼리가 실행될 때 잘못된 시간대 이름이 실패할 수 있습니다. 생략하면 저장된 구성은 null를 유지하고 UI는 상황에 따라 클라이언트 시간대 또는 UTC로 대체됩니다. |
null |
"America/Los_Angeles" |
timePreset |
문자열 | 예 | 지원되는 값은 1h, 6h, 24h, 7d, 30d, 90d, custom입니다. API는 현재 비어 있지 않은 문자열을 허용하지만 해당 값만 UI 및 SQL 생성기에서 지원됩니다. |
"7d" |
"7d" |
customStart |
문자열 | 아니요 | timePreset가 custom일 때 사용됩니다. 권장 형식: YYYY-MM-DDTHH:mm, YYYY-MM-DD HH:mm, YYYY-MM-DDTHH:mm:ss 또는 YYYY-MM-DDTHH:mm:ss.sss. 선택적으로 Z 또는 -07:00와 같은 숫자 오프셋이 뒤따릅니다. 시간대 접미사가 없으면 값은 timeZone로 해석됩니다. |
설정되지 않음 | "2026-03-20T00:00:00Z" |
customEnd |
문자열 | 아니요 | customStart와 동일한 형식입니다. 사용자 정의 범위에 대해 생략된 경우 쿼리에는 시간 상한이 없습니다. |
설정되지 않음 | "2026-03-26T00:00:00-07:00" |
granularity |
문자열 | 예 | API에 의해 검증된 정확한 열거형: auto, minute, hour, day, week, month. |
"auto" |
"hour" |
splitBy |
문자열 배열 | 예 | 비어 있지 않은 잘린 필드 이름의 배열입니다. 중첩된 JSON 필드에는 attributes.queue_name와 같은 점선 경로가 허용됩니다. |
[] |
["queue_name"] |
seriesLimit |
정수 또는 null |
아니요 | 양의 정수 또는 null. null는 명시적인 시리즈 한도가 없음을 의미합니다. 분할 차트에 가장 유용합니다. |
100 |
10 |
filters |
배열 | 예 | 필터 그룹 배열. 각 그룹은 내부적으로 AND로 연결됩니다. 여러 그룹이 함께 OR로 연결됩니다. 비어 있거나 유효하지 않은 그룹은 정규화 중에 삭제됩니다. | [] |
[] |
selectedColumns |
문자열 배열 | 예 | samples 또는 table 보기에 표시할 비어 있지 않은 잘린 필드 이름의 배열입니다. 점으로 구분된 JSON 경로가 허용됩니다. []를 사용하여 Telemetry가 기본값을 선택하도록 합니다. |
[] |
["timestamp_utc", "queue_name", "latency_ms"] |
orderBy |
문자열 또는 null |
아니요 | 표 형식 결과를 정렬하는 데 사용되는 선택적 필드 이름입니다. 점으로 구분된 JSON 경로가 허용됩니다. | null |
"timestamp_utc" |
limit |
정수 | 예 | 양의 정수 행 또는 그룹 제한. 잘못된 값은 기본값으로 돌아갑니다. | 200 |
200 |
orderDirection |
문자열 | 예 | API로 검증된 정확한 열거형: ASC 또는 DESC. |
"DESC" |
"DESC" |
timePreset 값
| 가치 | 의미 |
|---|---|
1h |
지난 1시간 |
6h |
지난 6시간 |
24h |
지난 24시간 |
7d |
지난 7일 |
30d |
지난 30일 |
90d |
지난 90일 |
custom |
상대 범위 대신 customStart 및 customEnd를 사용하세요. |
문서화되지 않은 timePreset를 보내는 경우 현재 SQL 생성기는 7일 동작으로 돌아갑니다. 위의 값을 지원되는 계약으로 취급하십시오.
granularity: "auto" 동작
granularity가 auto이면 Telemetry는 다음과 같이 해결합니다.
timePreset |
효과적인 세분성 |
|---|---|
1h, 6h, 24h |
minute |
7d |
hour |
30d, 90d, custom |
day |
그룹 및 조건 필터링
filters는 다음과 같은 모양이어야 합니다.
[
{
"logic": "AND",
"conditions": [
{ "field": "queue_name", "operator": "=", "value": "email" },
{ "field": "latency_ms", "operator": ">", "value": "1000" }
]
}
]
filters의 각 항목은 필터 그룹입니다.
| 필드 | 유형 | 필수 | 정확한 값 또는 형식 | 예 |
|---|---|---|---|---|
logic |
문자열 | 예 | AND여야 합니다. 대시보드 생성 API는 모든 그룹을 AND로 정규화합니다. 그룹별 OR가 없습니다. OR을 표현하려면 그룹이 함께 OR되기 때문에 여러 그룹을 사용합니다. |
"AND" |
conditions |
배열 | 예 | 그룹의 필터 조건 배열입니다. 유효한 조건이 0인 그룹은 삭제됩니다. | [{ "field": "queue_name", "operator": "=", "value": "email" }] |
conditions의 각 항목은 다음을 지원합니다.
| 필드 | 유형 | 필수 | 정확한 값 또는 형식 | 예 |
|---|---|---|---|---|
field |
문자열 | 예 | 비어 있지 않은 잘린 필드 경로입니다. attributes.queue_name와 같은 점으로 중첩된 JSON 경로가 지원됩니다. 빈 경로 세그먼트는 허용되지 않습니다. |
"latency_ms" |
operator |
문자열 | 예 | API에 의해 검증된 정확한 열거형: =, !=, >, >=, <, <=, LIKE, NOT LIKE, IS NULL, IS NOT NULL. |
">" |
value |
문자열, 숫자, 부울 또는 null |
보통 | 정규화 중에 문자열로 저장됩니다. IS NULL 및 IS NOT NULL의 경우 ""를 사용하거나 의미 값을 생략합니다. null는 ""가 됩니다. |
"1000" |
생성된 SQL이 실행될 때:
- 그룹 내부의 조건은
AND와 결합됩니다. - 그룹이
OR에 합류했습니다. attributes.queue_name와 같은 점으로 구분된 필드 경로는 중첩된 필드 액세스로 변환됩니다.
예: 빈 대시보드 만들기
예: 대시보드 나열
curl "https://api.telemetry.sh/dashboard?page=1&pageSize=25" \
-H "Authorization: $API_KEY"
예시 응답:
{
"status": "success",
"pagination": {
"page": 1,
"pageSize": 25,
"total": 1,
"totalPages": 1,
"hasNextPage": false,
"hasPreviousPage": false
},
"dashboards": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"team_id": "team_123",
"name": "Operations Overview",
"slug": "operations-overview",
"description": "Core service health and latency",
"created_by": null,
"created_by_api_key_id": "key_123",
"created_at": "2026-03-27T00:09:03.797Z",
"updated_at": "2026-03-27T00:09:03.797Z",
"url": "/team/acme/dashboard/operations-overview",
"widget_count": 1,
"widgets": [
{
"id": "widget_123",
"title": "Requests Per Hour",
"widget_type": "query",
"config": {
"querySql": "SELECT DATE_TRUNC('hour', timestamp_utc) AS hour, COUNT(*) AS requests FROM http_logs GROUP BY 1 ORDER BY 1",
"chartType": "Line Chart",
"xAxis": "hour",
"yAxis": "requests",
"groupBy": null,
"sourceUrl": "/team/acme/ops/draft/0?tab=chart&chartType=Line+Chart&xAxis=hour&yAxis=requests"
},
"layout": { "x": 0, "y": 0, "w": 12, "h": 4 },
"sort_order": 0
}
]
}
]
}
예: 빈 대시보드 만들기
curl -X POST https://api.telemetry.sh/dashboard \
-H "Content-Type: application/json" \
-H "Authorization: $API_KEY" \
-d '{
"name": "Operations Overview",
"description": "Core service health and latency"
}'
예: 대시보드 이름 바꾸기 및 설명 업데이트
curl -X PATCH https://api.telemetry.sh/dashboard \
-H "Content-Type: application/json" \
-H "Authorization: $API_KEY" \
-d '{
"dashboardSlug": "operations-overview",
"name": "Operations Overview v2",
"description": "Updated to focus on API latency and error rates"
}'
예: 기존 대시보드의 모든 위젯 교체
이 요청은 동일한 대시보드를 유지하지만 전체 위젯 세트를 새로운 widgets 어레이로 대체합니다.
curl -X PATCH https://api.telemetry.sh/dashboard \
-H "Content-Type: application/json" \
-H "Authorization: $API_KEY" \
-d '{
"dashboardSlug": "operations-overview",
"widgets": [
{
"title": "Revenue by City",
"widget_type": "explorer",
"config": {
"tableName": "uber_rides",
"explorerState": {
"graphType": "table",
"aggregation": "sum",
"metric": "price",
"timePreset": "30d",
"granularity": "auto",
"splitBy": ["city"],
"filters": [],
"selectedColumns": [],
"orderBy": "price",
"limit": 10,
"orderDirection": "DESC"
}
},
"layout": { "x": 0, "y": 0, "w": 12, "h": 4 }
}
]
}'
예: 대시보드 삭제
curl -X DELETE https://api.telemetry.sh/dashboard \
-H "Content-Type: application/json" \
-H "Authorization: $API_KEY" \
-d '{
"dashboardSlug": "operations-overview"
}'
일반적인 위젯 예
다음 예에서는 POST /dashboard로 보내는 JSON 요청 본문만 보여줍니다.
이 예에서는 다음과 같은 필드가 있는 uber_rides 테이블을 가정합니다.
citypricewait_time_minutesstatususer_idtimestamp_utc
예: 두 개의 일반적인 탐색 위젯이 포함된 대시보드 만들기
이 예에는 다음이 포함됩니다.
- 도시별 탑승 수익을 합산하고 수익별로 내림차순으로 정렬하는 테이블 위젯
- 도시별 평균 대기 시간을 그룹화된 선으로 차트로 표시하는 시계열 위젯
{
"name": "Uber Marketplace Overview",
"widgets": [
{
"title": "Revenue by City",
"widget_type": "explorer",
"config": {
"tableName": "uber_rides",
"explorerState": {
"graphType": "table",
"aggregation": "sum",
"metric": "price",
"timePreset": "30d",
"granularity": "auto",
"splitBy": ["city"],
"filters": [
{
"logic": "AND",
"conditions": [
{ "field": "status", "operator": "=", "value": "completed" }
]
}
],
"selectedColumns": ["city", "price"],
"orderBy": "price",
"limit": 20,
"orderDirection": "DESC"
}
},
"layout": { "x": 0, "y": 0, "w": 6, "h": 4 }
},
{
"title": "Average Wait Time by City",
"widget_type": "explorer",
"config": {
"tableName": "uber_rides",
"explorerState": {
"graphType": "line",
"aggregation": "avg",
"metric": "wait_time_minutes",
"timePreset": "7d",
"granularity": "hour",
"splitBy": ["city"],
"seriesLimit": null,
"filters": [
{
"logic": "AND",
"conditions": [
{ "field": "status", "operator": "=", "value": "completed" }
]
}
],
"selectedColumns": ["city", "wait_time_minutes"],
"limit": 200,
"orderDirection": "ASC"
}
},
"layout": { "x": 6, "y": 0, "w": 6, "h": 4 }
}
]
}
해당 예에서는 다음과 같습니다.
Revenue by City는 탐색 테이블 위젯입니다.selectedColumns: ["city", "price"]와aggregation: "sum"를 더하면city당 하나의 집계된price열이 생성됩니다.orderBy: "price"는 집계된 수익 열을 기준으로 정렬합니다.Average Wait Time by City는 탐색 라인 위젯입니다splitBy: ["city"]는 도시당 하나의 회선을 생성합니다.orderDirection: "ASC"는 시간축을 시간순으로 유지합니다.
예: 코호트 유지 미소 곡선에 대한 쿼리 위젯 만들기
집단 유지는 Explore에서 표현하기가 훨씬 어렵기 때문에 이 예에서는 쿼리 위젯을 사용합니다. 다음을 사용합니다:
- 첫 탑승 코호트 정의
- 뚜렷한 주간 활동 표
- 코호트 규모와 유지된 라이더 간의 결합
읽기 가능한 querySql:
WITH first_rides AS (
SELECT
user_id,
date_trunc('week', MIN(timestamp_utc)) AS cohort_week
FROM
uber_rides
WHERE
status = 'completed'
GROUP BY
user_id
),
weekly_activity AS (
SELECT DISTINCT
user_id,
date_trunc('week', timestamp_utc) AS activity_week
FROM
uber_rides
WHERE
status = 'completed'
),
cohort_activity AS (
SELECT
f.cohort_week,
a.activity_week,
date_part('day', a.activity_week - f.cohort_week) / 7 AS weeks_since_first_ride,
COUNT(DISTINCT a.user_id) AS retained_riders
FROM
first_rides f
JOIN weekly_activity a ON a.user_id = f.user_id
WHERE
a.activity_week >= f.cohort_week
GROUP BY
f.cohort_week,
a.activity_week,
date_part('day', a.activity_week - f.cohort_week) / 7
),
cohort_sizes AS (
SELECT
cohort_week,
COUNT(*) AS cohort_size
FROM
first_rides
GROUP BY
cohort_week
)
SELECT
weeks_since_first_ride,
100.0 * retained_riders / cohort_size AS retention_pct,
CAST(ca.cohort_week AS VARCHAR) AS cohort_week
FROM
cohort_activity ca
JOIN cohort_sizes cs ON ca.cohort_week = cs.cohort_week
WHERE
weeks_since_first_ride BETWEEN 0 AND 12
ORDER BY
weeks_since_first_ride ASC,
cohort_week ASC
{
"name": "Uber Rider Retention",
"widgets": [
{
"title": "Weekly Rider Retention Smile Curves",
"widget_type": "query",
"config": {
"querySql": "WITH first_rides AS ( SELECT user_id, date_trunc('week', MIN(timestamp_utc)) AS cohort_week FROM uber_rides WHERE status = 'completed' GROUP BY user_id ), weekly_activity AS ( SELECT DISTINCT user_id, date_trunc('week', timestamp_utc) AS activity_week FROM uber_rides WHERE status = 'completed' ), cohort_activity AS ( SELECT f.cohort_week, a.activity_week, date_part('day', a.activity_week - f.cohort_week) / 7 AS weeks_since_first_ride, COUNT(DISTINCT a.user_id) AS retained_riders FROM first_rides f JOIN weekly_activity a ON a.user_id = f.user_id WHERE a.activity_week >= f.cohort_week GROUP BY f.cohort_week, a.activity_week, date_part('day', a.activity_week - f.cohort_week) / 7 ), cohort_sizes AS ( SELECT cohort_week, COUNT(*) AS cohort_size FROM first_rides GROUP BY cohort_week ) SELECT weeks_since_first_ride, 100.0 * retained_riders / cohort_size AS retention_pct, CAST(ca.cohort_week AS VARCHAR) AS cohort_week FROM cohort_activity ca JOIN cohort_sizes cs ON ca.cohort_week = cs.cohort_week WHERE weeks_since_first_ride BETWEEN 0 AND 12 ORDER BY weeks_since_first_ride ASC, cohort_week ASC",
"chartType": "Line Chart",
"xAxis": "weeks_since_first_ride",
"yAxis": "retention_pct",
"groupBy": "cohort_week"
},
"layout": { "x": 0, "y": 0, "w": 12, "h": 5 }
}
]
}
해당 예에서는 다음과 같습니다.
weeks_since_first_ride는 x축입니다.retention_pct는 y축입니다.groupBy: "cohort_week"는 가입 코호트당 한 줄을 생성하여 스마일 곡선 스타일 비교를 생성합니다.- 코호트 논리는 여러 CTE 및 조인에 의존하므로 탐색 위젯이 아닌 쿼리 위젯입니다.
응답
성공적인 POST 요청은 201 Created를 반환합니다.
성공적인 PATCH 요청은 200 OK를 반환합니다.
둘 다 다음 모양을 반환합니다.
{
"status": "success",
"dashboard": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"team_id": "team_123",
"name": "HTTP Monitoring",
"slug": "http-monitoring",
"description": null,
"created_by": null,
"created_by_api_key_id": "8dff0c1a-8b36-49c3-9e6b-dc0d3ff51d74",
"created_at": "2026-03-26T00:00:00.000Z",
"updated_at": "2026-03-26T00:00:00.000Z",
"url": "/team/acme/dashboard/http-monitoring"
},
"widgets": [
{
"id": "9a6e4f27-d3bf-4a70-bf3a-38fe63211f93",
"title": "Errors Per Hour",
"widget_type": "query",
"config": {
"queryId": null,
"querySql": "SELECT ...",
"chartType": "Line Chart",
"xAxis": "hour",
"yAxis": "errors",
"groupBy": null,
"sourceUrl": null
},
"layout": {
"x": 0,
"y": 0,
"w": 12,
"h": 4
},
"sort_order": 1
}
]
}
성공적인 DELETE 요청은 삭제 요약과 함께 200 OK를 반환합니다.
{
"status": "success",
"deleted_dashboard": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "HTTP Monitoring",
"slug": "http-monitoring",
"description": null,
"widget_count": 6,
"url": "/team/acme/dashboard/http-monitoring"
}
}
이 API를 통해 생성된 대시보드는 팀 범위이며 대시보드를 생성한 API 키에 귀속됩니다.
- API 키는 사용자가 아니기 때문에 API가 생성한 대시보드의 경우
created_by는null입니다. created_by_api_key_id는 키 생성을 위한 내부team_api_keys.id행입니다.- UI를 통해 생성된 대시보드는 여전히 사용자 ID와 함께
created_by를 사용하고 일반적으로created_by_api_key_id를null로 유지합니다.
팀에 정규화된 슬러그가 이미 존재하는 경우 API는 409 Conflict를 반환합니다.
기타 일반적인 오류:
- 필수 필드가 누락되었거나 유효하지 않은 경우
400 Bad Request - 쿼리 위젯에 읽기 전용이 아닌 SQL이 포함된 경우
400 Bad Request - 팀에 대한 대상 대시보드가 없는 경우
404 Not Found - API 키가 없거나 잘못된 경우
401 Unauthorized - API 키에
read범위만 있는 경우400 Bad Request