Compare commits

..

2 Commits

Author SHA1 Message Date
Srikanth Chekuri
1251fb7e1d Merge branch 'main' into query-range-v5-openapi-spec 2026-02-09 07:05:46 +05:30
srikanthccv
25e81bef02 chore: add OpenAPI spec for /v5/query_range 2026-02-09 06:26:10 +05:30
5 changed files with 1616 additions and 6 deletions

View File

@@ -3354,6 +3354,62 @@ paths:
summary: Rotate session
tags:
- sessions
/api/v5/query_range:
post:
deprecated: false
description: Execute a composite query over a time range. Supports builder queries
(traces, logs, metrics), formulas, trace operators, PromQL, and ClickHouse
SQL.
operationId: QueryRangeV5
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Querybuildertypesv5QueryRangeRequest'
responses:
"200":
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/Querybuildertypesv5QueryRangeResponse'
status:
type: string
type: object
description: OK
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"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: Query range
tags:
- query
components:
schemas:
AuthtypesAttributeMapping:
@@ -4140,7 +4196,101 @@ components:
type:
type: string
type: object
Querybuildertypesv5AggregationBucket:
properties:
alias:
type: string
anomalyScores:
items:
$ref: '#/components/schemas/Querybuildertypesv5TimeSeries'
type: array
index:
type: integer
lowerBoundSeries:
items:
$ref: '#/components/schemas/Querybuildertypesv5TimeSeries'
type: array
meta:
properties:
unit:
type: string
type: object
predictedSeries:
items:
$ref: '#/components/schemas/Querybuildertypesv5TimeSeries'
type: array
series:
items:
$ref: '#/components/schemas/Querybuildertypesv5TimeSeries'
nullable: true
type: array
upperBoundSeries:
items:
$ref: '#/components/schemas/Querybuildertypesv5TimeSeries'
type: array
type: object
Querybuildertypesv5Bucket:
properties:
step:
format: double
type: number
type: object
Querybuildertypesv5ClickHouseQuery:
properties:
disabled:
type: boolean
legend:
type: string
name:
type: string
query:
type: string
type: object
Querybuildertypesv5ColumnDescriptor:
properties:
aggregationIndex:
format: int64
type: integer
columnType:
$ref: '#/components/schemas/Querybuildertypesv5ColumnType'
description:
type: string
fieldContext:
$ref: '#/components/schemas/TelemetrytypesFieldContext'
fieldDataType:
$ref: '#/components/schemas/TelemetrytypesFieldDataType'
meta:
properties:
unit:
type: string
type: object
name:
type: string
queryName:
type: string
signal:
$ref: '#/components/schemas/TelemetrytypesSignal'
unit:
type: string
type: object
Querybuildertypesv5ColumnType:
enum:
- group
- aggregation
type: string
Querybuildertypesv5CompositeQuery:
description: Composite query containing one or more query envelopes. Each query
envelope specifies its type and corresponding spec.
properties:
queries:
items:
$ref: '#/components/schemas/Querybuildertypesv5QueryEnvelope'
nullable: true
type: array
type: object
Querybuildertypesv5ExecStats:
description: Execution statistics for the query, including rows scanned, bytes
scanned, and duration.
properties:
bytesScanned:
minimum: 0
@@ -4162,10 +4312,109 @@ components:
expression:
type: string
type: object
Querybuildertypesv5FormatOptions:
properties:
fillGaps:
type: boolean
formatTableResultForUI:
type: boolean
type: object
Querybuildertypesv5Function:
properties:
args:
items:
$ref: '#/components/schemas/Querybuildertypesv5FunctionArg'
type: array
name:
$ref: '#/components/schemas/Querybuildertypesv5FunctionName'
type: object
Querybuildertypesv5FunctionArg:
properties:
name:
type: string
value: {}
type: object
Querybuildertypesv5FunctionName:
enum:
- cutoffmin
- cutoffmax
- clampmin
- clampmax
- absolute
- runningdiff
- log2
- log10
- cumulativesum
- ewma3
- ewma5
- ewma7
- median3
- median5
- median7
- timeshift
- anomaly
- fillzero
type: string
Querybuildertypesv5GroupByKey:
properties:
description:
type: string
fieldContext:
$ref: '#/components/schemas/TelemetrytypesFieldContext'
fieldDataType:
$ref: '#/components/schemas/TelemetrytypesFieldDataType'
name:
type: string
signal:
$ref: '#/components/schemas/TelemetrytypesSignal'
unit:
type: string
type: object
Querybuildertypesv5Having:
properties:
expression:
type: string
type: object
Querybuildertypesv5Label:
properties:
key:
$ref: '#/components/schemas/TelemetrytypesTelemetryFieldKey'
value: {}
type: object
Querybuildertypesv5LimitBy:
properties:
keys:
items:
type: string
nullable: true
type: array
value:
type: string
type: object
Querybuildertypesv5LogAggregation:
properties:
alias:
type: string
expression:
type: string
type: object
Querybuildertypesv5MetricAggregation:
properties:
metricName:
type: string
reduceTo:
$ref: '#/components/schemas/Querybuildertypesv5ReduceTo'
spaceAggregation:
type: string
temporality:
type: string
timeAggregation:
type: string
type: object
Querybuildertypesv5OrderBy:
properties:
direction:
type: string
$ref: '#/components/schemas/Querybuildertypesv5OrderDirection'
key:
$ref: '#/components/schemas/Querybuildertypesv5OrderByKey'
type: object
@@ -4174,34 +4423,404 @@ components:
description:
type: string
fieldContext:
type: string
$ref: '#/components/schemas/TelemetrytypesFieldContext'
fieldDataType:
type: string
$ref: '#/components/schemas/TelemetrytypesFieldDataType'
name:
type: string
signal:
type: string
$ref: '#/components/schemas/TelemetrytypesSignal'
unit:
type: string
type: object
Querybuildertypesv5OrderDirection:
enum:
- asc
- desc
type: string
Querybuildertypesv5PromQuery:
properties:
disabled:
type: boolean
legend:
type: string
name:
type: string
query:
type: string
stats:
type: boolean
step:
$ref: '#/components/schemas/Querybuildertypesv5Step'
type: object
Querybuildertypesv5QueryBuilderFormula:
properties:
disabled:
type: boolean
expression:
type: string
functions:
items:
$ref: '#/components/schemas/Querybuildertypesv5Function'
type: array
having:
$ref: '#/components/schemas/Querybuildertypesv5Having'
legend:
type: string
limit:
type: integer
name:
type: string
order:
items:
$ref: '#/components/schemas/Querybuildertypesv5OrderBy'
type: array
type: object
Querybuildertypesv5QueryBuilderQueryGithubComSigNozSignozPkgTypesQuerybuildertypesQuerybuildertypesv5LogAggregation:
properties:
aggregations:
items:
$ref: '#/components/schemas/Querybuildertypesv5LogAggregation'
type: array
cursor:
type: string
disabled:
type: boolean
filter:
$ref: '#/components/schemas/Querybuildertypesv5Filter'
functions:
items:
$ref: '#/components/schemas/Querybuildertypesv5Function'
type: array
groupBy:
items:
$ref: '#/components/schemas/Querybuildertypesv5GroupByKey'
type: array
having:
$ref: '#/components/schemas/Querybuildertypesv5Having'
legend:
type: string
limit:
type: integer
limitBy:
$ref: '#/components/schemas/Querybuildertypesv5LimitBy'
name:
type: string
offset:
type: integer
order:
items:
$ref: '#/components/schemas/Querybuildertypesv5OrderBy'
type: array
secondaryAggregations:
items:
$ref: '#/components/schemas/Querybuildertypesv5SecondaryAggregation'
type: array
selectFields:
items:
$ref: '#/components/schemas/TelemetrytypesTelemetryFieldKey'
type: array
signal:
$ref: '#/components/schemas/TelemetrytypesSignal'
source:
$ref: '#/components/schemas/TelemetrytypesSource'
stepInterval:
$ref: '#/components/schemas/Querybuildertypesv5Step'
type: object
Querybuildertypesv5QueryBuilderQueryGithubComSigNozSignozPkgTypesQuerybuildertypesQuerybuildertypesv5MetricAggregation:
properties:
aggregations:
items:
$ref: '#/components/schemas/Querybuildertypesv5MetricAggregation'
type: array
cursor:
type: string
disabled:
type: boolean
filter:
$ref: '#/components/schemas/Querybuildertypesv5Filter'
functions:
items:
$ref: '#/components/schemas/Querybuildertypesv5Function'
type: array
groupBy:
items:
$ref: '#/components/schemas/Querybuildertypesv5GroupByKey'
type: array
having:
$ref: '#/components/schemas/Querybuildertypesv5Having'
legend:
type: string
limit:
type: integer
limitBy:
$ref: '#/components/schemas/Querybuildertypesv5LimitBy'
name:
type: string
offset:
type: integer
order:
items:
$ref: '#/components/schemas/Querybuildertypesv5OrderBy'
type: array
secondaryAggregations:
items:
$ref: '#/components/schemas/Querybuildertypesv5SecondaryAggregation'
type: array
selectFields:
items:
$ref: '#/components/schemas/TelemetrytypesTelemetryFieldKey'
type: array
signal:
$ref: '#/components/schemas/TelemetrytypesSignal'
source:
$ref: '#/components/schemas/TelemetrytypesSource'
stepInterval:
$ref: '#/components/schemas/Querybuildertypesv5Step'
type: object
Querybuildertypesv5QueryBuilderQueryGithubComSigNozSignozPkgTypesQuerybuildertypesQuerybuildertypesv5TraceAggregation:
properties:
aggregations:
items:
$ref: '#/components/schemas/Querybuildertypesv5TraceAggregation'
type: array
cursor:
type: string
disabled:
type: boolean
filter:
$ref: '#/components/schemas/Querybuildertypesv5Filter'
functions:
items:
$ref: '#/components/schemas/Querybuildertypesv5Function'
type: array
groupBy:
items:
$ref: '#/components/schemas/Querybuildertypesv5GroupByKey'
type: array
having:
$ref: '#/components/schemas/Querybuildertypesv5Having'
legend:
type: string
limit:
type: integer
limitBy:
$ref: '#/components/schemas/Querybuildertypesv5LimitBy'
name:
type: string
offset:
type: integer
order:
items:
$ref: '#/components/schemas/Querybuildertypesv5OrderBy'
type: array
secondaryAggregations:
items:
$ref: '#/components/schemas/Querybuildertypesv5SecondaryAggregation'
type: array
selectFields:
items:
$ref: '#/components/schemas/TelemetrytypesTelemetryFieldKey'
type: array
signal:
$ref: '#/components/schemas/TelemetrytypesSignal'
source:
$ref: '#/components/schemas/TelemetrytypesSource'
stepInterval:
$ref: '#/components/schemas/Querybuildertypesv5Step'
type: object
Querybuildertypesv5QueryBuilderTraceOperator:
properties:
aggregations:
items:
$ref: '#/components/schemas/Querybuildertypesv5TraceAggregation'
type: array
cursor:
type: string
disabled:
type: boolean
expression:
type: string
filter:
$ref: '#/components/schemas/Querybuildertypesv5Filter'
functions:
items:
$ref: '#/components/schemas/Querybuildertypesv5Function'
type: array
groupBy:
items:
$ref: '#/components/schemas/Querybuildertypesv5GroupByKey'
type: array
having:
$ref: '#/components/schemas/Querybuildertypesv5Having'
legend:
type: string
limit:
type: integer
name:
type: string
offset:
type: integer
order:
items:
$ref: '#/components/schemas/Querybuildertypesv5OrderBy'
type: array
returnSpansFrom:
type: string
selectFields:
items:
$ref: '#/components/schemas/TelemetrytypesTelemetryFieldKey'
type: array
stepInterval:
$ref: '#/components/schemas/Querybuildertypesv5Step'
type: object
Querybuildertypesv5QueryData:
oneOf:
- $ref: '#/components/schemas/Querybuildertypesv5TimeSeriesData'
- $ref: '#/components/schemas/Querybuildertypesv5ScalarData'
- $ref: '#/components/schemas/Querybuildertypesv5RawData'
properties:
results:
items: {}
nullable: true
type: array
type: object
Querybuildertypesv5QueryEnvelope:
oneOf:
- $ref: '#/components/schemas/Querybuildertypesv5QueryEnvelopeBuilderTrace'
- $ref: '#/components/schemas/Querybuildertypesv5QueryEnvelopeBuilderLog'
- $ref: '#/components/schemas/Querybuildertypesv5QueryEnvelopeBuilderMetric'
- $ref: '#/components/schemas/Querybuildertypesv5QueryEnvelopeFormula'
- $ref: '#/components/schemas/Querybuildertypesv5QueryEnvelopeTraceOperator'
- $ref: '#/components/schemas/Querybuildertypesv5QueryEnvelopePromQL'
- $ref: '#/components/schemas/Querybuildertypesv5QueryEnvelopeClickHouseSQL'
properties:
spec: {}
type:
$ref: '#/components/schemas/Querybuildertypesv5QueryType'
type: object
Querybuildertypesv5QueryEnvelopeBuilderLog:
properties:
spec:
$ref: '#/components/schemas/Querybuildertypesv5QueryBuilderQueryGithubComSigNozSignozPkgTypesQuerybuildertypesQuerybuildertypesv5LogAggregation'
type:
$ref: '#/components/schemas/Querybuildertypesv5QueryType'
type: object
Querybuildertypesv5QueryEnvelopeBuilderMetric:
properties:
spec:
$ref: '#/components/schemas/Querybuildertypesv5QueryBuilderQueryGithubComSigNozSignozPkgTypesQuerybuildertypesQuerybuildertypesv5MetricAggregation'
type:
$ref: '#/components/schemas/Querybuildertypesv5QueryType'
type: object
Querybuildertypesv5QueryEnvelopeBuilderTrace:
properties:
spec:
$ref: '#/components/schemas/Querybuildertypesv5QueryBuilderQueryGithubComSigNozSignozPkgTypesQuerybuildertypesQuerybuildertypesv5TraceAggregation'
type:
$ref: '#/components/schemas/Querybuildertypesv5QueryType'
type: object
Querybuildertypesv5QueryEnvelopeClickHouseSQL:
properties:
spec:
$ref: '#/components/schemas/Querybuildertypesv5ClickHouseQuery'
type:
$ref: '#/components/schemas/Querybuildertypesv5QueryType'
type: object
Querybuildertypesv5QueryEnvelopeFormula:
properties:
spec:
$ref: '#/components/schemas/Querybuildertypesv5QueryBuilderFormula'
type:
$ref: '#/components/schemas/Querybuildertypesv5QueryType'
type: object
Querybuildertypesv5QueryEnvelopePromQL:
properties:
spec:
$ref: '#/components/schemas/Querybuildertypesv5PromQuery'
type:
$ref: '#/components/schemas/Querybuildertypesv5QueryType'
type: object
Querybuildertypesv5QueryEnvelopeTraceOperator:
properties:
spec:
$ref: '#/components/schemas/Querybuildertypesv5QueryBuilderTraceOperator'
type:
$ref: '#/components/schemas/Querybuildertypesv5QueryType'
type: object
Querybuildertypesv5QueryRangeRequest:
description: Request body for the v5 query range endpoint. Supports builder
queries (traces, logs, metrics), formulas, joins, trace operators, PromQL,
and ClickHouse SQL queries.
example:
compositeQuery:
queries:
- spec:
aggregations:
- alias: span_count
expression: count()
filter:
expression: service.name = 'frontend'
groupBy:
- fieldContext: resource
name: service.name
limit: 10
name: A
order:
- direction: desc
key:
name: span_count
signal: traces
stepInterval: 60s
type: builder_query
end: 1.6409988e+12
requestType: time_series
schemaVersion: v1
start: 1.6409952e+12
properties:
compositeQuery:
$ref: '#/components/schemas/Querybuildertypesv5CompositeQuery'
end:
minimum: 0
type: integer
formatOptions:
$ref: '#/components/schemas/Querybuildertypesv5FormatOptions'
noCache:
type: boolean
requestType:
$ref: '#/components/schemas/Querybuildertypesv5RequestType'
schemaVersion:
type: string
start:
minimum: 0
type: integer
variables:
additionalProperties:
$ref: '#/components/schemas/Querybuildertypesv5VariableItem'
type: object
type: object
Querybuildertypesv5QueryRangeResponse:
description: 'Response from the v5 query range endpoint. The data.results array
contains typed results depending on the requestType: TimeSeriesData for time_series,
ScalarData for scalar, or RawData for raw requests.'
properties:
data:
$ref: '#/components/schemas/Querybuildertypesv5QueryData'
meta:
$ref: '#/components/schemas/Querybuildertypesv5ExecStats'
type:
type: string
$ref: '#/components/schemas/Querybuildertypesv5RequestType'
warning:
$ref: '#/components/schemas/Querybuildertypesv5QueryWarnData'
type: object
Querybuildertypesv5QueryType:
enum:
- builder_query
- builder_formula
- builder_trace_operator
- clickhouse_sql
- promql
type: string
Querybuildertypesv5QueryWarnData:
properties:
message:
@@ -4218,6 +4837,153 @@ components:
message:
type: string
type: object
Querybuildertypesv5RawData:
properties:
nextCursor:
type: string
queryName:
type: string
rows:
items:
$ref: '#/components/schemas/Querybuildertypesv5RawRow'
nullable: true
type: array
type: object
Querybuildertypesv5RawRow:
properties:
data:
additionalProperties: {}
nullable: true
type: object
timestamp:
format: date-time
type: string
type: object
Querybuildertypesv5ReduceTo:
enum:
- sum
- count
- avg
- min
- max
- last
- median
type: string
Querybuildertypesv5RequestType:
enum:
- scalar
- time_series
- raw
- raw_stream
- trace
type: string
Querybuildertypesv5ScalarData:
properties:
columns:
items:
$ref: '#/components/schemas/Querybuildertypesv5ColumnDescriptor'
nullable: true
type: array
data:
items:
items: {}
type: array
nullable: true
type: array
queryName:
type: string
type: object
Querybuildertypesv5SecondaryAggregation:
properties:
alias:
type: string
expression:
type: string
groupBy:
items:
$ref: '#/components/schemas/Querybuildertypesv5GroupByKey'
type: array
limit:
type: integer
limitBy:
$ref: '#/components/schemas/Querybuildertypesv5LimitBy'
order:
items:
$ref: '#/components/schemas/Querybuildertypesv5OrderBy'
type: array
stepInterval:
$ref: '#/components/schemas/Querybuildertypesv5Step'
type: object
Querybuildertypesv5Step:
description: Step interval. Accepts a Go duration string (e.g., "60s", "1m",
"1h") or a number representing seconds (e.g., 60).
oneOf:
- description: Duration string (e.g., "60s", "5m", "1h").
example: 60s
type: string
- description: Duration in seconds.
example: 60
type: number
Querybuildertypesv5TimeSeries:
properties:
labels:
items:
$ref: '#/components/schemas/Querybuildertypesv5Label'
type: array
values:
items:
$ref: '#/components/schemas/Querybuildertypesv5TimeSeriesValue'
nullable: true
type: array
type: object
Querybuildertypesv5TimeSeriesData:
properties:
aggregations:
items:
$ref: '#/components/schemas/Querybuildertypesv5AggregationBucket'
nullable: true
type: array
queryName:
type: string
type: object
Querybuildertypesv5TimeSeriesValue:
properties:
bucket:
$ref: '#/components/schemas/Querybuildertypesv5Bucket'
partial:
type: boolean
timestamp:
format: int64
type: integer
value:
format: double
type: number
values:
items:
format: double
type: number
type: array
type: object
Querybuildertypesv5TraceAggregation:
properties:
alias:
type: string
expression:
type: string
type: object
Querybuildertypesv5VariableItem:
properties:
type:
$ref: '#/components/schemas/Querybuildertypesv5VariableType'
value: {}
type: object
Querybuildertypesv5VariableType:
enum:
- query
- dynamic
- custom
- text
type: string
RenderErrorResponse:
properties:
error:
@@ -4244,6 +5010,48 @@ components:
format: date-time
type: string
type: object
TelemetrytypesFieldContext:
enum:
- metric
- log
- span
- resource
- attribute
- body
type: string
TelemetrytypesFieldDataType:
enum:
- string
- bool
- float64
- int64
- number
type: string
TelemetrytypesSignal:
enum:
- traces
- logs
- metrics
type: string
TelemetrytypesSource:
enum:
- meter
type: string
TelemetrytypesTelemetryFieldKey:
properties:
description:
type: string
fieldContext:
$ref: '#/components/schemas/TelemetrytypesFieldContext'
fieldDataType:
$ref: '#/components/schemas/TelemetrytypesFieldDataType'
name:
type: string
signal:
$ref: '#/components/schemas/TelemetrytypesSignal'
unit:
type: string
type: object
TypesChangePasswordRequest:
properties:
newPassword:

View File

@@ -11,6 +11,7 @@ import (
"github.com/SigNoz/signoz/pkg/alertmanager"
"github.com/SigNoz/signoz/pkg/apis/fields"
"github.com/SigNoz/signoz/pkg/global"
"github.com/SigNoz/signoz/pkg/http/handler"
"github.com/SigNoz/signoz/pkg/http/middleware"
querierAPI "github.com/SigNoz/signoz/pkg/querier"
baseapp "github.com/SigNoz/signoz/pkg/query-service/app"
@@ -22,6 +23,8 @@ import (
rules "github.com/SigNoz/signoz/pkg/query-service/rules"
"github.com/SigNoz/signoz/pkg/queryparser"
"github.com/SigNoz/signoz/pkg/signoz"
"github.com/SigNoz/signoz/pkg/types/ctxtypes"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/SigNoz/signoz/pkg/version"
"github.com/gorilla/mux"
)
@@ -108,7 +111,22 @@ func (ah *APIHandler) RegisterRoutes(router *mux.Router, am *middleware.AuthZ) {
router.HandleFunc("/api/v4/query_range", am.ViewAccess(ah.queryRangeV4)).Methods(http.MethodPost)
// v5
router.HandleFunc("/api/v5/query_range", am.ViewAccess(ah.queryRangeV5)).Methods(http.MethodPost)
router.Handle("/api/v5/query_range", handler.New(am.ViewAccess(ah.queryRangeV5), handler.OpenAPIDef{
ID: "QueryRangeV5",
Tags: []string{"query"},
Summary: "Query range",
Description: "Execute a composite query over a time range. Supports builder queries (traces, logs, metrics), formulas, joins, trace operators, PromQL, and ClickHouse SQL.",
Request: new(qbtypes.QueryRangeRequest),
RequestContentType: "application/json",
Response: new(qbtypes.QueryRangeResponse),
ResponseContentType: "application/json",
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{http.StatusBadRequest},
SecuritySchemes: []handler.OpenAPISecurityScheme{
{Name: ctxtypes.AuthTypeAPIKey.StringValue(), Scopes: []string{"VIEWER"}},
{Name: ctxtypes.AuthTypeTokenizer.StringValue(), Scopes: []string{"VIEWER"}},
},
})).Methods(http.MethodPost)
router.HandleFunc("/api/v5/substitute_vars", am.ViewAccess(ah.QuerierAPI.ReplaceVariables)).Methods(http.MethodPost)

View File

@@ -2,6 +2,7 @@ package signoz
import (
"context"
"net/http"
"os"
"reflect"
@@ -23,6 +24,8 @@ import (
"github.com/SigNoz/signoz/pkg/modules/session"
"github.com/SigNoz/signoz/pkg/modules/user"
"github.com/SigNoz/signoz/pkg/types/ctxtypes"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/gorilla/mux"
"github.com/swaggest/jsonschema-go"
"github.com/swaggest/openapi-go"
"github.com/swaggest/openapi-go/openapi3"
@@ -57,6 +60,10 @@ func NewOpenAPI(ctx context.Context, instrumentation instrumentation.Instrumenta
return nil, err
}
// Register routes that live outside the APIServer modules
// so they are discovered by the OpenAPI walker.
registerQueryRoutes(apiserver.Router())
reflector := openapi3.NewReflector()
reflector.JSONSchemaReflector().DefaultOptions = append(reflector.JSONSchemaReflector().DefaultOptions, jsonschema.InterceptDefName(func(t reflect.Type, defaultDefName string) string {
if defaultDefName == "RenderSuccessResponse" {
@@ -97,3 +104,25 @@ func (openapi *OpenAPI) CreateAndWrite(path string) error {
return os.WriteFile(path, spec, 0o600)
}
func registerQueryRoutes(router *mux.Router) {
router.Handle("/api/v5/query_range", handler.New(
func(http.ResponseWriter, *http.Request) {},
handler.OpenAPIDef{
ID: "QueryRangeV5",
Tags: []string{"query"},
Summary: "Query range",
Description: "Execute a composite query over a time range. Supports builder queries (traces, logs, metrics), formulas, trace operators, PromQL, and ClickHouse SQL.",
Request: new(qbtypes.QueryRangeRequest),
RequestContentType: "application/json",
Response: new(qbtypes.QueryRangeResponse),
ResponseContentType: "application/json",
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{http.StatusBadRequest},
SecuritySchemes: []handler.OpenAPISecurityScheme{
{Name: ctxtypes.AuthTypeAPIKey.StringValue(), Scopes: []string{"VIEWER"}},
{Name: ctxtypes.AuthTypeTokenizer.StringValue(), Scopes: []string{"VIEWER"}},
},
},
)).Methods(http.MethodPost)
}

View File

@@ -0,0 +1,707 @@
package querybuildertypesv5
import (
"github.com/swaggest/jsonschema-go"
)
// Enum returns the acceptable values for QueryType.
func (QueryType) Enum() []any {
return []any{
QueryTypeBuilder,
QueryTypeFormula,
// Not yet supported.
// QueryTypeSubQuery,
// QueryTypeJoin,
QueryTypeTraceOperator,
QueryTypeClickHouseSQL,
QueryTypePromQL,
}
}
// Enum returns the acceptable values for RequestType.
func (RequestType) Enum() []any {
return []any{
RequestTypeScalar,
RequestTypeTimeSeries,
RequestTypeRaw,
RequestTypeRawStream,
RequestTypeTrace,
// RequestTypeDistribution,
}
}
// Enum returns the acceptable values for FunctionName.
func (FunctionName) Enum() []any {
return []any{
FunctionNameCutOffMin,
FunctionNameCutOffMax,
FunctionNameClampMin,
FunctionNameClampMax,
FunctionNameAbsolute,
FunctionNameRunningDiff,
FunctionNameLog2,
FunctionNameLog10,
FunctionNameCumulativeSum,
FunctionNameEWMA3,
FunctionNameEWMA5,
FunctionNameEWMA7,
FunctionNameMedian3,
FunctionNameMedian5,
FunctionNameMedian7,
FunctionNameTimeShift,
FunctionNameAnomaly,
FunctionNameFillZero,
}
}
// Enum returns the acceptable values for OrderDirection.
func (OrderDirection) Enum() []any {
return []any{
OrderDirectionAsc,
OrderDirectionDesc,
}
}
// Enum returns the acceptable values for ReduceTo.
func (ReduceTo) Enum() []any {
return []any{
ReduceToSum,
ReduceToCount,
ReduceToAvg,
ReduceToMin,
ReduceToMax,
ReduceToLast,
ReduceToMedian,
}
}
// Enum returns the acceptable values for VariableType.
func (VariableType) Enum() []any {
return []any{
QueryVariableType,
DynamicVariableType,
CustomVariableType,
TextBoxVariableType,
}
}
// Enum returns the acceptable values for JoinType.
func (JoinType) Enum() []any {
return []any{
JoinTypeInner,
JoinTypeLeft,
JoinTypeRight,
JoinTypeFull,
JoinTypeCross,
}
}
// Enum returns the acceptable values for ColumnType.
func (ColumnType) Enum() []any {
return []any{
ColumnTypeGroup,
ColumnTypeAggregation,
}
}
// queryEnvelopeBuilderTrace is the OpenAPI schema for a QueryEnvelope with type=builder_query and signal=traces.
type queryEnvelopeBuilderTrace struct {
Type QueryType `json:"type" description:"The type of the query."`
Spec QueryBuilderQuery[TraceAggregation] `json:"spec" description:"The trace builder query specification."`
}
// queryEnvelopeBuilderLog is the OpenAPI schema for a QueryEnvelope with type=builder_query and signal=logs.
type queryEnvelopeBuilderLog struct {
Type QueryType `json:"type" description:"The type of the query."`
Spec QueryBuilderQuery[LogAggregation] `json:"spec" description:"The log builder query specification."`
}
// queryEnvelopeBuilderMetric is the OpenAPI schema for a QueryEnvelope with type=builder_query and signal=metrics.
type queryEnvelopeBuilderMetric struct {
Type QueryType `json:"type" description:"The type of the query."`
Spec QueryBuilderQuery[MetricAggregation] `json:"spec" description:"The metric builder query specification."`
}
// queryEnvelopeFormula is the OpenAPI schema for a QueryEnvelope with type=builder_formula.
type queryEnvelopeFormula struct {
Type QueryType `json:"type" description:"The type of the query."`
Spec QueryBuilderFormula `json:"spec" description:"The formula specification."`
}
// queryEnvelopeJoin is the OpenAPI schema for a QueryEnvelope with type=builder_join.
// type queryEnvelopeJoin struct {
// Type QueryType `json:"type" description:"The type of the query."`
// Spec QueryBuilderJoin `json:"spec" description:"The join specification."`
// }
// queryEnvelopeTraceOperator is the OpenAPI schema for a QueryEnvelope with type=builder_trace_operator.
type queryEnvelopeTraceOperator struct {
Type QueryType `json:"type" description:"The type of the query."`
Spec QueryBuilderTraceOperator `json:"spec" description:"The trace operator specification."`
}
// queryEnvelopePromQL is the OpenAPI schema for a QueryEnvelope with type=promql.
type queryEnvelopePromQL struct {
Type QueryType `json:"type" description:"The type of the query."`
Spec PromQuery `json:"spec" description:"The PromQL query specification."`
}
// queryEnvelopeClickHouseSQL is the OpenAPI schema for a QueryEnvelope with type=clickhouse_sql.
type queryEnvelopeClickHouseSQL struct {
Type QueryType `json:"type" description:"The type of the query."`
Spec ClickHouseQuery `json:"spec" description:"The ClickHouse SQL query specification."`
}
var _ jsonschema.OneOfExposer = QueryEnvelope{}
// JSONSchemaOneOf returns the oneOf variants for the QueryEnvelope discriminated union.
// Each variant represents a different query type with its corresponding spec schema.
func (QueryEnvelope) JSONSchemaOneOf() []any {
return []any{
queryEnvelopeBuilderTrace{},
queryEnvelopeBuilderLog{},
queryEnvelopeBuilderMetric{},
queryEnvelopeFormula{},
// queryEnvelopeJoin{},
queryEnvelopeTraceOperator{},
queryEnvelopePromQL{},
queryEnvelopeClickHouseSQL{},
}
}
var _ jsonschema.Exposer = Step{}
// JSONSchema returns a custom schema for Step that accepts either a duration string or a number (seconds).
func (Step) JSONSchema() (jsonschema.Schema, error) {
s := jsonschema.Schema{}
s.WithDescription("Step interval. Accepts a Go duration string (e.g., \"60s\", \"1m\", \"1h\") or a number representing seconds (e.g., 60).")
strSchema := jsonschema.Schema{}
strSchema.WithType(jsonschema.String.Type())
strSchema.WithExamples("60s", "5m", "1h")
strSchema.WithDescription("Duration string (e.g., \"60s\", \"5m\", \"1h\").")
numSchema := jsonschema.Schema{}
numSchema.WithType(jsonschema.Number.Type())
numSchema.WithExamples(60, 300, 3600)
numSchema.WithDescription("Duration in seconds.")
s.OneOf = []jsonschema.SchemaOrBool{
strSchema.ToSchemaOrBool(),
numSchema.ToSchemaOrBool(),
}
return s, nil
}
var _ jsonschema.OneOfExposer = QueryData{}
// JSONSchemaOneOf documents the polymorphic result types in QueryData.Results.
func (QueryData) JSONSchemaOneOf() []any {
return []any{
TimeSeriesData{},
ScalarData{},
RawData{},
}
}
var _ jsonschema.Preparer = &QueryRangeRequest{}
// PrepareJSONSchema adds examples and description to the QueryRangeRequest schema.
func (q *QueryRangeRequest) PrepareJSONSchema(schema *jsonschema.Schema) error {
schema.WithDescription("Request body for the v5 query range endpoint. Supports builder queries (traces, logs, metrics), formulas, joins, trace operators, PromQL, and ClickHouse SQL queries.")
schema.WithExamples(
// 1. time_series + traces builder: count spans grouped by service, ordered by count
map[string]any{
"schemaVersion": "v1",
"start": 1640995200000,
"end": 1640998800000,
"requestType": "time_series",
"compositeQuery": map[string]any{
"queries": []any{
map[string]any{
"type": "builder_query",
"spec": map[string]any{
"name": "A",
"signal": "traces",
"aggregations": []any{
map[string]any{
"expression": "count()",
"alias": "span_count",
},
},
"stepInterval": "60s",
"filter": map[string]any{
"expression": "service.name = 'frontend'",
},
"groupBy": []any{
map[string]any{
"name": "service.name",
"fieldContext": "resource",
},
},
"order": []any{
map[string]any{
"key": map[string]any{"name": "span_count"},
"direction": "desc",
},
},
"limit": 10,
},
},
},
},
},
// 2. time_series + logs builder: count logs grouped by service
map[string]any{
"schemaVersion": "v1",
"start": 1640995200000,
"end": 1640998800000,
"requestType": "time_series",
"compositeQuery": map[string]any{
"queries": []any{
map[string]any{
"type": "builder_query",
"spec": map[string]any{
"name": "A",
"signal": "logs",
"aggregations": []any{
map[string]any{
"expression": "count()",
"alias": "log_count",
},
},
"stepInterval": "60s",
"filter": map[string]any{
"expression": "severity_text = 'ERROR'",
},
"groupBy": []any{
map[string]any{
"name": "service.name",
"fieldContext": "resource",
},
},
"order": []any{
map[string]any{
"key": map[string]any{"name": "log_count"},
"direction": "desc",
},
},
"limit": 10,
},
},
},
},
},
// 3. time_series + metrics builder (Gauge): latest value averaged across series
map[string]any{
"schemaVersion": "v1",
"start": 1640995200000,
"end": 1640998800000,
"requestType": "time_series",
"compositeQuery": map[string]any{
"queries": []any{
map[string]any{
"type": "builder_query",
"spec": map[string]any{
"name": "A",
"signal": "metrics",
"aggregations": []any{
map[string]any{
"metricName": "system.cpu.utilization",
"timeAggregation": "latest",
"spaceAggregation": "avg",
},
},
"stepInterval": "60s",
"groupBy": []any{
map[string]any{
"name": "host.name",
"fieldContext": "resource",
},
},
},
},
},
},
},
// 4. time_series + metrics builder (Sum): rate of cumulative counter
map[string]any{
"schemaVersion": "v1",
"start": 1640995200000,
"end": 1640998800000,
"requestType": "time_series",
"compositeQuery": map[string]any{
"queries": []any{
map[string]any{
"type": "builder_query",
"spec": map[string]any{
"name": "A",
"signal": "metrics",
"aggregations": []any{
map[string]any{
"metricName": "http.server.duration.count",
"timeAggregation": "rate",
"spaceAggregation": "sum",
},
},
"stepInterval": 120,
"groupBy": []any{
map[string]any{
"name": "service.name",
"fieldContext": "resource",
},
},
},
},
},
},
},
// 5. time_series + metrics builder (Histogram): p99 latency
map[string]any{
"schemaVersion": "v1",
"start": 1640995200000,
"end": 1640998800000,
"requestType": "time_series",
"compositeQuery": map[string]any{
"queries": []any{
map[string]any{
"type": "builder_query",
"spec": map[string]any{
"name": "A",
"signal": "metrics",
"aggregations": []any{
map[string]any{
"metricName": "http.server.duration.bucket",
"spaceAggregation": "p99",
},
},
"stepInterval": "60s",
"groupBy": []any{
map[string]any{
"name": "service.name",
"fieldContext": "resource",
},
},
},
},
},
},
},
// 6. raw + logs builder: fetch raw log records
map[string]any{
"schemaVersion": "v1",
"start": 1640995200000,
"end": 1640998800000,
"requestType": "raw",
"compositeQuery": map[string]any{
"queries": []any{
map[string]any{
"type": "builder_query",
"spec": map[string]any{
"name": "A",
"signal": "logs",
"filter": map[string]any{
"expression": "severity_text = 'ERROR'",
},
"selectFields": []any{
map[string]any{
"name": "body",
"fieldContext": "log",
},
map[string]any{
"name": "service.name",
"fieldContext": "resource",
},
},
"order": []any{
map[string]any{
"key": map[string]any{"name": "timestamp", "fieldContext": "log"},
"direction": "desc",
},
map[string]any{
"key": map[string]any{"name": "id"},
"direction": "desc",
},
},
"limit": 50,
"offset": 0,
},
},
},
},
},
// 7. raw + traces builder: fetch raw span records
map[string]any{
"schemaVersion": "v1",
"start": 1640995200000,
"end": 1640998800000,
"requestType": "raw",
"compositeQuery": map[string]any{
"queries": []any{
map[string]any{
"type": "builder_query",
"spec": map[string]any{
"name": "A",
"signal": "traces",
"filter": map[string]any{
"expression": "service.name = 'frontend' AND has_error = true",
},
"selectFields": []any{
map[string]any{
"name": "name",
"fieldContext": "span",
},
map[string]any{
"name": "duration_nano",
"fieldContext": "span",
},
},
"order": []any{
map[string]any{
"key": map[string]any{"name": "timestamp", "fieldContext": "span"},
"direction": "desc",
},
},
"limit": 100,
},
},
},
},
},
// 8. scalar + traces builder: total span count as a single value
map[string]any{
"schemaVersion": "v1",
"start": 1640995200000,
"end": 1640998800000,
"requestType": "scalar",
"compositeQuery": map[string]any{
"queries": []any{
map[string]any{
"type": "builder_query",
"spec": map[string]any{
"name": "A",
"signal": "traces",
"aggregations": []any{
map[string]any{
"expression": "count()",
"alias": "span_count",
},
},
"filter": map[string]any{
"expression": "service.name = 'frontend'",
},
},
},
},
},
},
// 9. scalar + logs builder: total error log count as a single value
map[string]any{
"schemaVersion": "v1",
"start": 1640995200000,
"end": 1640998800000,
"requestType": "scalar",
"compositeQuery": map[string]any{
"queries": []any{
map[string]any{
"type": "builder_query",
"spec": map[string]any{
"name": "A",
"signal": "logs",
"aggregations": []any{
map[string]any{
"expression": "count()",
"alias": "error_count",
},
},
"filter": map[string]any{
"expression": "severity_text = 'ERROR'",
},
},
},
},
},
},
// 10. scalar + metrics builder: single reduced value with reduceTo
map[string]any{
"schemaVersion": "v1",
"start": 1640995200000,
"end": 1640998800000,
"requestType": "scalar",
"compositeQuery": map[string]any{
"queries": []any{
map[string]any{
"type": "builder_query",
"spec": map[string]any{
"name": "A",
"signal": "metrics",
"aggregations": []any{
map[string]any{
"metricName": "http.server.duration.count",
"timeAggregation": "rate",
"spaceAggregation": "sum",
"reduceTo": "sum",
},
},
"stepInterval": "60s",
},
},
},
},
},
// 11. builder formula: error rate from two trace queries
map[string]any{
"schemaVersion": "v1",
"start": 1640995200000,
"end": 1640998800000,
"requestType": "time_series",
"compositeQuery": map[string]any{
"queries": []any{
map[string]any{
"type": "builder_query",
"spec": map[string]any{
"name": "A",
"signal": "traces",
"aggregations": []any{
map[string]any{
"expression": "countIf(has_error = true)",
},
},
"stepInterval": "60s",
"groupBy": []any{
map[string]any{
"name": "service.name",
"fieldContext": "resource",
},
},
},
},
map[string]any{
"type": "builder_query",
"spec": map[string]any{
"name": "B",
"signal": "traces",
"aggregations": []any{
map[string]any{
"expression": "count()",
},
},
"stepInterval": "60s",
"groupBy": []any{
map[string]any{
"name": "service.name",
"fieldContext": "resource",
},
},
},
},
map[string]any{
"type": "builder_formula",
"spec": map[string]any{
"name": "error_rate",
"expression": "A / B * 100",
},
},
},
},
},
// 12. PromQL query with UTF-8 dot metric name
map[string]any{
"schemaVersion": "v1",
"start": 1640995200000,
"end": 1640998800000,
"requestType": "time_series",
"compositeQuery": map[string]any{
"queries": []any{
map[string]any{
"type": "promql",
"spec": map[string]any{
"name": "request_rate",
"query": "sum(rate({\"http.server.duration.count\"}[5m])) by (\"service.name\")",
"step": 60,
},
},
},
},
},
// 13. ClickHouse SQL — time_series
map[string]any{
"schemaVersion": "v1",
"start": 1640995200000,
"end": 1640998800000,
"requestType": "time_series",
"compositeQuery": map[string]any{
"queries": []any{
map[string]any{
"type": "clickhouse_sql",
"spec": map[string]any{
"name": "span_rate",
"query": "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, count() AS value FROM signoz_traces.distributed_signoz_index_v3 WHERE timestamp >= $start_datetime AND timestamp <= $end_datetime GROUP BY ts ORDER BY ts",
},
},
},
},
},
// 14. ClickHouse SQL — raw
map[string]any{
"schemaVersion": "v1",
"start": 1640995200000,
"end": 1640998800000,
"requestType": "raw",
"compositeQuery": map[string]any{
"queries": []any{
map[string]any{
"type": "clickhouse_sql",
"spec": map[string]any{
"name": "recent_errors",
"query": "SELECT timestamp, body FROM signoz_logs.distributed_logs_v2 WHERE timestamp >= $start_timestamp_nano AND timestamp <= $end_timestamp_nano AND severity_text = 'ERROR' ORDER BY timestamp DESC LIMIT 100",
},
},
},
},
},
// 15. ClickHouse SQL — scalar
map[string]any{
"schemaVersion": "v1",
"start": 1640995200000,
"end": 1640998800000,
"requestType": "scalar",
"compositeQuery": map[string]any{
"queries": []any{
map[string]any{
"type": "clickhouse_sql",
"spec": map[string]any{
"name": "total_spans",
"query": "SELECT count() AS value FROM signoz_traces.distributed_signoz_index_v3 WHERE timestamp >= $start_datetime AND timestamp <= $end_datetime",
},
},
},
},
},
)
return nil
}
var _ jsonschema.Preparer = &QueryRangeResponse{}
// PrepareJSONSchema adds description to the QueryRangeResponse schema.
func (q *QueryRangeResponse) PrepareJSONSchema(schema *jsonschema.Schema) error {
schema.WithDescription("Response from the v5 query range endpoint. The data.results array contains typed results depending on the requestType: TimeSeriesData for time_series, ScalarData for scalar, or RawData for raw requests.")
return nil
}
var _ jsonschema.Preparer = &CompositeQuery{}
// PrepareJSONSchema adds description to the CompositeQuery schema.
func (c *CompositeQuery) PrepareJSONSchema(schema *jsonschema.Schema) error {
schema.WithDescription("Composite query containing one or more query envelopes. Each query envelope specifies its type and corresponding spec.")
return nil
}
var _ jsonschema.Preparer = &ExecStats{}
// PrepareJSONSchema adds description to the ExecStats schema.
func (e *ExecStats) PrepareJSONSchema(schema *jsonschema.Schema) error {
schema.WithDescription("Execution statistics for the query, including rows scanned, bytes scanned, and duration.")
return nil
}

View File

@@ -0,0 +1,48 @@
package telemetrytypes
// Enum returns the acceptable values for Signal.
func (Signal) Enum() []any {
return []any{
SignalTraces,
SignalLogs,
SignalMetrics,
}
}
// Enum returns the acceptable values for FieldContext.
func (FieldContext) Enum() []any {
return []any{
FieldContextMetric,
FieldContextLog,
FieldContextSpan,
// FieldContextTrace,
FieldContextResource,
// FieldContextScope,
FieldContextAttribute,
// FieldContextEvent,
FieldContextBody,
}
}
// Enum returns the acceptable values for Source.
func (Source) Enum() []any {
return []any{
SourceMeter,
}
}
// Enum returns the acceptable values for FieldDataType.
func (FieldDataType) Enum() []any {
return []any{
FieldDataTypeString,
FieldDataTypeBool,
FieldDataTypeFloat64,
FieldDataTypeInt64,
FieldDataTypeNumber,
// FieldDataTypeArrayString,
// FieldDataTypeArrayFloat64,
// FieldDataTypeArrayBool,
// FieldDataTypeArrayInt64,
// FieldDataTypeArrayNumber,
}
}