diff --git a/CHANGELOG.md b/CHANGELOG.md index 009a0488f..2291bc298 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 3.4.0 (not released yet) +## Enhancements: +* add $lttb and $lttbMs macros to allow show down-sampled time series which will contains more outliers than avg or other kind of aggregation, fix https://github.com/Altinity/clickhouse-grafana/issues/500 + # 3.3.1 (2024-12-27) ## Enhancements: * Add using window functions instead of `runningDifference` and `neighbor` for macros, to avoid `allow_deprecated_error_prone_window_functions`, fix https://github.com/Altinity/clickhouse-grafana/issues/572 diff --git a/README.md b/README.md index a397399ff..fdd1ba3c9 100644 --- a/README.md +++ b/README.md @@ -269,6 +269,49 @@ GROUP BY t ORDER BY t ``` +--- +### $lttb(buckets_number, [field1, ... fieldN], x_field, y_field) - allow show down-sampled time series which will contains more outliers than avg or other kind of aggregation + +If bucket_number is `auto`, then it will calculated as `toUInt64( ($to-$from) / $interval )` +Example usage: + +```sql +$lttb(auto, category, event_time, count(*) c) +FROM requests GROUP BY category +``` + +Query will be transformed into: + +```sql +SELECT category, lttb_result.1 AS event_time, lttb_result.2 AS c FROM ( + SELECT category, untuple(arrayJoin(lttb(toUInt64( ($to - $from) / $interval ))(event_time, cont(*) AS c))) AS lttb_result + FROM requests WHERE $timeFilter GROUP BY category +) ORDER BY event_time +``` + +--- + +--- +### $lttbMs(buckets_number, [field1,... fieldN], x_field, y_field) - same as $lttb but for time series with ms + +If bucket_number is `auto`, then it will calculated as `toUInt64( ($__to-$__from) / $__interval_ms )` + +Example usage: + +```sql +$lttbMs(100, event_time, count(*) c) +FROM requests +``` + +Query will be transformed into: + +```sql +SELECT lttb_result.1 AS event_time, lttb_result.2 AS c FROM ( + SELECT untuple(arrayJoin(lttb(100)(event_time, count(*) AS c))) AS lttb_result + FROM requests WHERE $timeFilterMs +) ORDER BY event_time +``` + --- ### $rateColumns(key, value) - is a combination of $columns and $rate diff --git a/docker/clickhouse/init_schema.sql b/docker/clickhouse/init_schema.sql index 7b0ac7ad7..5dc78e347 100644 --- a/docker/clickhouse/init_schema.sql +++ b/docker/clickhouse/init_schema.sql @@ -332,3 +332,19 @@ SELECT toUInt64(now() - INTERVAL number SECOND)*1000000000 + toUInt64(randUniform(0, 1000000000)) AS tUInt64_9, number AS value FROM numbers(86400); + +DROP TABLE IF EXISTS default.test_lttb SYNC; +CREATE TABLE default.test_lttb( + event_time DateTime, + event_time_ms DateTime64(3), + category LowCardinality(String), + requests UInt64 +) ENGINE=MergeTree() ORDER BY event_time; + +INSERT INTO default.test_lttb +SELECT + now() - INTERVAL number SECOND, + now() - INTERVAL number SECOND + INTERVAL randUniform(0, 100) MILLISECOND, + 'category' || toString(number%25), + rand() % 1000000 +FROM numbers(86400); diff --git a/docker/grafana/dashboards/issue_500_lttb_and_lttbMs.json b/docker/grafana/dashboards/issue_500_lttb_and_lttbMs.json new file mode 100644 index 000000000..e8cd583e2 --- /dev/null +++ b/docker/grafana/dashboards/issue_500_lttb_and_lttbMs.json @@ -0,0 +1,183 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "reproduce dashboards for https://github.com/Altinity/clickhouse-grafana/issues/500", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 54, + "links": [], + "panels": [ + { + "datasource": { + "type": "vertamedia-clickhouse-datasource", + "uid": "P7E099F39B84EA795" + }, + "description": "https://github.com/Altinity/clickhouse-grafana/issues/500", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.5.1", + "targets": [ + { + "adHocFilters": [], + "adHocValuesQuery": "", + "add_metadata": true, + "contextWindowSize": "10", + "database": "default", + "datasource": { + "type": "vertamedia-clickhouse-datasource", + "uid": "P7E099F39B84EA795" + }, + "dateTimeColDataType": "event_time", + "dateTimeType": "DATETIME", + "editorMode": "sql", + "extrapolate": true, + "format": "time_series", + "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", + "interval": "", + "intervalFactor": 1, + "query": "$lttb(auto, category, event_time, count()) FROM $table WHERE $timeFilter GROUP BY category", + "refId": "A", + "round": "0s", + "showFormattedSQL": true, + "skip_comments": true, + "table": "test_lttb", + "useWindowFuncForMacros": true + }, + { + "adHocFilters": [], + "adHocValuesQuery": "", + "add_metadata": true, + "contextWindowSize": "10", + "database": "default", + "datasource": { + "type": "vertamedia-clickhouse-datasource", + "uid": "P7E099F39B84EA795" + }, + "dateTimeColDataType": "event_time", + "dateTimeType": "DATETIME", + "editorMode": "sql", + "extrapolate": true, + "format": "time_series", + "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", + "hide": false, + "interval": "", + "intervalFactor": 1, + "query": "$lttbMs(auto, category, event_time, count()) FROM $table WHERE $timeFilter GROUP BY category", + "refId": "B", + "round": "0s", + "showFormattedSQL": true, + "skip_comments": true, + "table": "test_lttb", + "useWindowFuncForMacros": true + } + ], + "title": "$lttb \\ $lttbMs auto buckets", + "type": "timeseries" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 40, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "$lttb and $lttbMs", + "uid": "lttb_lttb_ms", + "version": 2, + "weekStart": "" +} \ No newline at end of file diff --git a/go.mod b/go.mod index 6c0c19ab4..8c9922db8 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.23 require ( github.com/andybalholm/brotli v1.1.1 github.com/dlclark/regexp2 v1.11.4 - github.com/grafana/grafana-plugin-sdk-go v0.260.1 + github.com/grafana/grafana-plugin-sdk-go v0.263.0 github.com/hyperjumptech/jiffy v1.0.0 github.com/klauspost/compress v1.17.11 github.com/stretchr/testify v1.10.0 @@ -15,58 +15,61 @@ require ( require ( github.com/BurntSushi/toml v1.4.0 // indirect github.com/antlr/antlr4 v0.0.0-20200124162019-2d7f727a00b7 // indirect + github.com/apache/arrow-go/v18 v18.1.0 // indirect github.com/apache/arrow/go/v15 v15.0.2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cheekybits/genny v1.0.0 // indirect - github.com/chromedp/cdproto v0.0.0-20241110205750-a72e6703cd9b // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect + github.com/chromedp/cdproto v0.0.0-20250203011601-a3c71a042730 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/elazarl/goproxy v0.0.0-20240909085733-6741dbfc16a1 // indirect + github.com/elazarl/goproxy v1.7.0 // indirect github.com/fatih/color v1.18.0 // indirect - github.com/getkin/kin-openapi v0.128.0 // indirect + github.com/getkin/kin-openapi v0.129.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect - github.com/goccy/go-json v0.10.3 // indirect + github.com/goccy/go-json v0.10.5 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/flatbuffers v24.3.25+incompatible // indirect + github.com/google/flatbuffers v25.1.24+incompatible // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/grafana/otel-profiling-go v0.5.1 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect - github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.0 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect - github.com/hashicorp/go-plugin v1.6.2 // indirect + github.com/hashicorp/go-plugin v1.6.3 // indirect github.com/hashicorp/yamux v0.1.2 // indirect github.com/invopop/yaml v0.3.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/magefile/mage v1.15.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/mailru/easyjson v0.9.0 // indirect github.com/mattetti/filebuffer v1.0.1 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/oasdiff/yaml v0.0.0-20241214135536-5f7845c759c8 // indirect + github.com/oasdiff/yaml3 v0.0.0-20241214160948-977117996672 // indirect github.com/oklog/run v1.1.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pierrec/lz4/v4 v4.1.21 // indirect + github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.60.1 // indirect + github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect @@ -75,28 +78,29 @@ require ( github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a // indirect github.com/urfave/cli v1.22.16 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.57.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.57.0 // indirect - go.opentelemetry.io/contrib/propagators/jaeger v1.32.0 // indirect - go.opentelemetry.io/contrib/samplers/jaegerremote v0.26.0 // indirect - go.opentelemetry.io/otel v1.32.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 // indirect - go.opentelemetry.io/otel/metric v1.32.0 // indirect - go.opentelemetry.io/otel/sdk v1.32.0 // indirect - go.opentelemetry.io/otel/trace v1.32.0 // indirect - go.opentelemetry.io/proto/otlp v1.3.1 // indirect - golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.59.0 // indirect + go.opentelemetry.io/contrib/propagators/jaeger v1.34.0 // indirect + go.opentelemetry.io/contrib/samplers/jaegerremote v0.28.0 // indirect + go.opentelemetry.io/otel v1.34.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 // indirect + go.opentelemetry.io/otel/metric v1.34.0 // indirect + go.opentelemetry.io/otel/sdk v1.34.0 // indirect + go.opentelemetry.io/otel/trace v1.34.0 // indirect + go.opentelemetry.io/proto/otlp v1.5.0 // indirect + golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c // indirect golang.org/x/mod v0.22.0 // indirect - golang.org/x/net v0.33.0 // indirect - golang.org/x/sys v0.28.0 // indirect + golang.org/x/net v0.34.0 // indirect + golang.org/x/sys v0.29.0 // indirect golang.org/x/text v0.21.0 // indirect - golang.org/x/tools v0.27.0 // indirect + golang.org/x/tools v0.29.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 // indirect - google.golang.org/grpc v1.68.0 // indirect - google.golang.org/protobuf v1.35.2 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250127172529-29210b9bc287 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250127172529-29210b9bc287 // indirect + google.golang.org/grpc v1.70.0 // indirect + google.golang.org/protobuf v1.36.4 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index a1f555b8e..d14dc715f 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,8 @@ github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7X github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= github.com/antlr/antlr4 v0.0.0-20200124162019-2d7f727a00b7 h1:4IkFZAFQ87SeXXF6n+nwLyK2K+tcA5OojhBVf2lhg8g= github.com/antlr/antlr4 v0.0.0-20200124162019-2d7f727a00b7/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y= +github.com/apache/arrow-go/v18 v18.1.0 h1:agLwJUiVuwXZdwPYVrlITfx7bndULJ/dggbnLFgDp/Y= +github.com/apache/arrow-go/v18 v18.1.0/go.mod h1:tigU/sIgKNXaesf5d7Y95jBBKS5KsxTqYBKXFsvKzo0= github.com/apache/arrow/go/v15 v15.0.2 h1:60IliRbiyTWCWjERBCkO1W4Qun9svcYoZrSLcyOsMLE= github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+yea1jass9YXgjA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -19,9 +21,13 @@ github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitf github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/chromedp/cdproto v0.0.0-20241110205750-a72e6703cd9b h1:md1Gk5jkNE91SZxFDCMHmKqX0/GsEr1/VTejht0sCbY= github.com/chromedp/cdproto v0.0.0-20241110205750-a72e6703cd9b/go.mod h1:4XqMl3iIW08jtieURWL6Tt5924w21pxirC6th662XUM= +github.com/chromedp/cdproto v0.0.0-20250203011601-a3c71a042730 h1:IEa+Va47x06CJQaLKFoce5iPTRRR5uI/GbeZbxdnYdc= +github.com/chromedp/cdproto v0.0.0-20250203011601-a3c71a042730/go.mod h1:RTGuBeCeabAJGi3OZf71a6cGa7oYBfBP75VJZFLv6SU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -29,6 +35,8 @@ github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yA github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/elazarl/goproxy v0.0.0-20240909085733-6741dbfc16a1 h1:g7YUigN4dW2+zpdusdTTghZ+5Py3BaUMAStvL8Nk+FY= github.com/elazarl/goproxy v0.0.0-20240909085733-6741dbfc16a1/go.mod h1:thX175TtLTzLj3p7N/Q9IiKZ7NF+p72cvL91emV0hzo= +github.com/elazarl/goproxy v1.7.0 h1:EXv2nV4EjM60ZtsEVLYJG4oBXhDGutMKperpHsZ/v+0= +github.com/elazarl/goproxy v1.7.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ= github.com/elazarl/goproxy/ext v0.0.0-20220115173737-adb46da277ac h1:9yrT5tmn9Zc0ytWPASlaPwQfQMQYnRf0RSDe1XvHw0Q= github.com/elazarl/goproxy/ext v0.0.0-20220115173737-adb46da277ac/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= @@ -40,6 +48,8 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.129.0 h1:QGYTNcmyP5X0AtFQ2Dkou9DGBJsUETeLH9rFrJXZh30= +github.com/getkin/kin-openapi v0.129.0/go.mod h1:gmWI+b/J45xqpyK5wJmRRZse5wefA5H0RDMK46kLUtI= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= @@ -54,12 +64,16 @@ github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI= github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/flatbuffers v25.1.24+incompatible h1:4wPqL3K7GzBd1CwyhSd3usxLKOaJN/AC6puCca6Jm7o= +github.com/google/flatbuffers v25.1.24+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -71,6 +85,8 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/grafana/grafana-plugin-sdk-go v0.260.1 h1:KzbooQP9mv/9CPsn+SoUwGuomA8oUxO0iuIq6Rg/ekE= github.com/grafana/grafana-plugin-sdk-go v0.260.1/go.mod h1:JriieK5Oc5v120QKhMs/LO55N0P3YI2ttEiVT1wfYsw= +github.com/grafana/grafana-plugin-sdk-go v0.263.0 h1:y8vo7hUm50Ei7rdeNNivgehHNsOmCjc8wRmBat5yA3w= +github.com/grafana/grafana-plugin-sdk-go v0.263.0/go.mod h1:U43Cnrj/9DNYyvFcNdeUWNjMXTKNB0jcTcQGpWKd2gw= github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8= github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls= github.com/grafana/pyroscope-go/godeltaprof v0.1.8 h1:iwOtYXeeVSAeYefJNaxDytgjKtUuKQbJqgAIjlnicKg= @@ -79,12 +95,18 @@ github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpS github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 h1:kQ0NI7W1B3HwiN5gAYtY+XFItDPbLBwYRxAqbFTyDes= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0/go.mod h1:zrT2dxOAjNFPRGjTUe2Xmb4q4YdUwVvQFV6xiCSf+z0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.0 h1:VD1gqscl4nYs1YxVuSdemTrSgTKrwOWDK0FVFMqm+Cg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.0/go.mod h1:4EgsQoS4TOhJizV+JTFg40qx1Ofh3XmXEQNBpgvNT40= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog= github.com/hashicorp/go-plugin v1.6.2/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q= +github.com/hashicorp/go-plugin v1.6.3 h1:xgHB+ZUSYeuJi96WtxEjzi23uh7YQpznjGh0U0UUrwg= +github.com/hashicorp/go-plugin v1.6.3/go.mod h1:MRobyh+Wc/nYy1V4KAXUiYfzxoYhs7V1mlH1Z7iY2h0= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/hyperjumptech/jiffy v1.0.0 h1:hLfjgh4YQPYFanSmh06nfN2Es7BZ1WF2sQwmZIQ5tHQ= @@ -115,12 +137,16 @@ github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattetti/filebuffer v1.0.1 h1:gG7pyfnSIZCxdoKq+cPa8T0hhYtD9NxCdI4D7PTjRLM= github.com/mattetti/filebuffer v1.0.1/go.mod h1:YdMURNDOttIiruleeVr6f56OrMc+MydEnTcXwtkxNVs= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -140,6 +166,10 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/oasdiff/yaml v0.0.0-20241214135536-5f7845c759c8 h1:9djga8U4+/TQzv5iMlZHZ/qbGQB9V2nlnk2bmiG+uBs= +github.com/oasdiff/yaml v0.0.0-20241214135536-5f7845c759c8/go.mod h1:7tFDb+Y51LcDpn26GccuUgQXUk6t0CXZsivKjyimYX8= +github.com/oasdiff/yaml3 v0.0.0-20241214160948-977117996672 h1:+273wgr7to5QhwOOBE5LwjdNDFAI+8cbJVfB0Zj75aI= +github.com/oasdiff/yaml3 v0.0.0-20241214160948-977117996672/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= @@ -148,6 +178,8 @@ github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= +github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= @@ -156,6 +188,8 @@ github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc= github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -203,34 +237,58 @@ github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.57.0 h1:qtFISDHKolvIxzSs0gIaiPUPR0Cucb0F2coHC7ZLdps= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.57.0/go.mod h1:Y+Pop1Q6hCOnETWTW4NROK/q1hv50hM7yDaUTjG8lp8= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.57.0 h1:7F3XCD6WYzDkwbi8I8N+oYJWquPVScnRosKGgqjsR8c= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.57.0/go.mod h1:Dk3C0BfIlZDZ5c6eVS7TYiH2vssuyUU3vUsgbrR+5V4= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.59.0 h1:iQZYNQ7WwIcYXzOPR46FQv9O0dS1PW16RjvR0TjDOe8= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.59.0/go.mod h1:54CaSNqYEXvpzDh8KPjiMVoWm60t5R0dZRt0leEPgAs= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 h1:DheMAlT6POBP+gh8RUH19EOTnQIor5QE0uSRPtzCpSw= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0/go.mod h1:wZcGmeVO9nzP67aYSLDqXNWK87EZWhi7JWj1v7ZXf94= go.opentelemetry.io/contrib/propagators/jaeger v1.32.0 h1:K/fOyTMD6GELKTIJBaJ9k3ppF2Njt8MeUGBOwfaWXXA= go.opentelemetry.io/contrib/propagators/jaeger v1.32.0/go.mod h1:ISE6hda//MTWvtngG7p4et3OCngsrTVfl7c6DjN17f8= +go.opentelemetry.io/contrib/propagators/jaeger v1.34.0 h1:D3htJISCUU/wOVlKwisVKancWm+2U4h9xDEaiMkiyRE= +go.opentelemetry.io/contrib/propagators/jaeger v1.34.0/go.mod h1:DAX1bsj+uDm2ZuOQH/RgZRx7RQZWyzV5W2WR/0UX8JA= go.opentelemetry.io/contrib/samplers/jaegerremote v0.26.0 h1:/SKXyZLAnuj981HVc8G5ZylYK3qD2W6AYR6cJx5kIHw= go.opentelemetry.io/contrib/samplers/jaegerremote v0.26.0/go.mod h1:cOEzME0M2OKeHB45lJiOKfvUCdg/r75mf7YS5w0tbmE= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.28.0 h1:Xx1N6cDr8iWy1Cz6OcY7oS0ACdt/6HDYTdu4KskuC7s= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.28.0/go.mod h1:iWS+NvC948FyfnJbVfPN9h/8+vr8CR2FPn6XsLRkvH8= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 h1:IJFEoHiytixx8cMiVAO+GmHR6Frwu+u5Ur8njpFO6Ac= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0/go.mod h1:3rHrKNtLIoS0oZwkY2vxi+oJcwFRWdtUyRII+so45p8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 h1:9kV11HXBHZAvuPUZxmMWrH8hZn/6UnHX4K0mu36vNsU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0/go.mod h1:JyA0FHXe22E1NeNiHmVp7kFHglnexDQ7uRWDiiJ1hKQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -238,6 +296,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= +golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc= +golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= @@ -248,6 +308,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -267,6 +329,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= @@ -277,6 +341,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o= golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q= +golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= +golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -285,14 +351,23 @@ golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhS golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.12.0 h1:xKuo6hzt+gMav00meVPUlXwSdoEJP46BR+wdxQEFK2o= gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY= +gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0= google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 h1:pgr/4QbFyktUv9CtQ/Fq4gzEE6/Xs7iCXbktaGzLHbQ= google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697/go.mod h1:+D9ySVjN8nY8YCVjc5O7PZDIdZporIDY3KaGfJunh88= +google.golang.org/genproto/googleapis/api v0.0.0-20250127172529-29210b9bc287 h1:A2ni10G3UlplFrWdCDJTl7D7mJ7GSRm37S+PDimaKRw= +google.golang.org/genproto/googleapis/api v0.0.0-20250127172529-29210b9bc287/go.mod h1:iYONQfRdizDB8JJBybql13nArx91jcUk7zCXEsOofM4= google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 h1:LWZqQOEjDyONlF1H6afSWpAL/znlREo2tHfLoe+8LMA= google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250127172529-29210b9bc287 h1:J1H9f+LEdWAfHcez/4cvaVBox7cOYT+IU6rgqj5x++8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250127172529-29210b9bc287/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= +google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= +google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM= +google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/package.json b/package.json index 9258b9137..18da4b98c 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "create_instrumented": "npx nyc instrument --source-map --nycrc-path .nycrc ./src ./instrumented", "build:test:frontend": "webpack -c ./webpack.config.instrumented.ts --env test", "build:frontend": "webpack -c ./.config/webpack/webpack.config.ts --env production", - "build:wasm": "GOARCH=wasm GOOS=js tinygo build --target wasm ./pkg/backend_wasm.go && gzip -f ./backend_wasm.wasm && mkdir -pv ./src/static/ && mv ./backend_wasm.wasm.gz ./src/static/backend.wasm.gz" + "build:wasm": "GOARCH=wasm GOOS=js tinygo build --target wasm ./pkg/backend_wasm.go && gzip -f ./backend_wasm.wasm && mkdir -pv ./src/static/ && mv -fv ./backend_wasm.wasm.gz ./src/static/backend.wasm.gz" }, "author": "Altinity", "license": "MIT", diff --git a/pkg/backend_wasm.go b/pkg/backend_wasm.go index 76306a983..d47f40d87 100644 --- a/pkg/backend_wasm.go +++ b/pkg/backend_wasm.go @@ -254,14 +254,14 @@ func createQueryWasm(this js.Value, args []js.Value) interface{} { from, err := time.Parse(time.RFC3339, reqData.TimeRange.From) if err != nil { return map[string]interface{}{ - "error": "Invalid from time", + "error": "Invalid `$from` time", } } to, err := time.Parse(time.RFC3339, reqData.TimeRange.To) if err != nil { return map[string]interface{}{ - "error": "Invalid to time", + "error": "Invalid `$to` time", } } diff --git a/pkg/eval/eval_query.go b/pkg/eval/eval_query.go index 09645cb0a..8a2933b85 100644 --- a/pkg/eval/eval_query.go +++ b/pkg/eval/eval_query.go @@ -420,6 +420,12 @@ func (q *EvalQuery) applyMacros(query string, ast *EvalAST) (string, error) { if q.contain(ast, "$columnsMs") { return q.columnsMs(query, ast) } + if q.contain(ast, "$lttb") { + return q.lttb(query, ast) + } + if q.contain(ast, "$lttbMs") { + return q.lttbMs(query, ast) + } if q.contain(ast, "$rateColumnsAggregated") { return q.rateColumnsAggregated(query, ast) } @@ -571,6 +577,80 @@ func (q *EvalQuery) _columns(key, value, beforeMacrosQuery, fromQuery string, us " ORDER BY t", nil } +func (q *EvalQuery) lttb(query string, ast *EvalAST) (string, error) { + macroQueries, err := q._parseMacro("$lttb", query) + if err != nil { + return "", err + } + beforeMacrosQuery, fromQuery := macroQueries[0], macroQueries[1] + if len(fromQuery) < 1 { + return query, nil + } + args := ast.Obj["$lttb"].(*EvalAST).Arr + if args == nil || len(args) < 3 { + return "", fmt.Errorf("amount of arguments must great or equal 3 for $lttb func. Parsed arguments are: %v", ast.Obj["$lttb"]) + } + return q._lttb(beforeMacrosQuery, fromQuery, args, false) +} + +func (q *EvalQuery) lttbMs(query string, ast *EvalAST) (string, error) { + macroQueries, err := q._parseMacro("$lttbMs", query) + if err != nil { + return "", err + } + beforeMacrosQuery, fromQuery := macroQueries[0], macroQueries[1] + if len(fromQuery) < 1 { + return query, nil + } + args := ast.Obj["$lttbMs"].(*EvalAST).Arr + if args == nil || len(args) < 3 { + return "", fmt.Errorf("amount of arguments must great or equal 3 for $lttbMs func. Parsed arguments are: %v", ast.Obj["$lttbMs"]) + } + return q._lttb(beforeMacrosQuery, fromQuery, args, true) +} + +func (q *EvalQuery) _lttb(beforeMacrosQuery string, fromQuery string, args []interface{}, useMs bool) (string, error) { + bucketNumbers := args[0].(string) + if strings.ToLower(strings.Trim(bucketNumbers, " \xA0\t\r\n")) == "auto" { + if useMs { + bucketNumbers = "toUInt64( ($__to - $__from) / $__interval_ms )" + } else { + bucketNumbers = "toUInt64( ($to - $from) / $interval )" + } + } + + var argsExceptLastTwo strings.Builder + if len(args) > 3 { + for i, arg := range args[1 : len(args)-2] { + if i > 0 { + argsExceptLastTwo.WriteString(", ") // Add delimiter after the first element + } + argsExceptLastTwo.WriteString(fmt.Sprintf("%v", arg)) // Convert each element to a string + } + argsExceptLastTwo.WriteString(", ") + } + + xField := args[len(args)-2].(string) + yField := args[len(args)-1].(string) + if xField[len(xField)-1] == ')' || yField[len(yField)-1] == ')' { + return "", fmt.Errorf("some of passed arguments are without aliases: %s, %s", xField, yField) + } + + var xSplit = strings.Split(strings.Trim(xField, " \xA0\t\r\n"), " ") + var xAlias = xSplit[len(xSplit)-1] + + var ySplit = strings.Split(strings.Trim(yField, " \xA0\t\r\n"), " ") + var yAlias = ySplit[len(ySplit)-1] + + fromQuery = q._applyTimeFilter(fromQuery, useMs) + + return beforeMacrosQuery + "SELECT `lttb_result.1` AS " + xAlias + ", " + argsExceptLastTwo.String() + "`lttb_result.2` AS " + yAlias + + " FROM (\n" + + " SELECT " + argsExceptLastTwo.String() + "untuple(arrayJoin(lttb(" + bucketNumbers + ")(" + xField + ", " + yField + "))) AS lttb_result " + + fromQuery + "\n" + + ") ORDER BY " + xAlias, nil +} + func findKeywordOutsideBrackets(query, keyword string) int { bracketDepth := 0 keywordRegex := regexp.MustCompile("(?i)" + regexp.QuoteMeta(keyword)) // Case-insensitive match @@ -803,7 +883,7 @@ func (q *EvalQuery) _fromIndex(query, macro string) (int, error) { var fromRe = regexp.MustCompile("(?im)\\" + macro + "\\([\\w\\s\\S]+?\\)(\\s+FROM\\s+)") var matches = fromRe.FindStringSubmatchIndex(query) if len(matches) == 0 { - return 0, fmt.Errorf("could not find FROM-statement at: %s", query) + return 0, fmt.Errorf("can't find FROM-statement at: %s", query) } var fragmentWithFrom = query[matches[len(matches)-2]:matches[len(matches)-1]] var fromRelativeIndex = strings.Index(strings.ToLower(fragmentWithFrom), "from") @@ -1955,7 +2035,7 @@ const joinsRe = "\\b(" + ")\\b" const onJoinTokenRe = "\\b(using|on)\\b" const tableNameRe = `([A-Za-z0-9_]+|[A-Za-z0-9_]+\\.[A-Za-z0-9_]+)` -const macroFuncRe = "(\\$deltaColumnsAggregated|\\$increaseColumnsAggregated|\\$perSecondColumnsAggregated|\\$rateColumnsAggregated|\\$rateColumns|\\$perSecondColumns|\\$deltaColumns|\\$increaseColumns|\\$rate|\\$perSecond|\\$delta|\\$increase|\\$columnsMs|\\$columns)" +const macroFuncRe = "(\\$deltaColumnsAggregated|\\$increaseColumnsAggregated|\\$perSecondColumnsAggregated|\\$rateColumnsAggregated|\\$rateColumns|\\$perSecondColumns|\\$deltaColumns|\\$increaseColumns|\\$rate|\\$perSecond|\\$delta|\\$increase|\\$columnsMs|\\$columns|\\$lttbMs|\\$lttb)" const condRe = "\\b(or|and)\\b" const inRe = "\\b(global in|global not in|not in|in)\\b(?:\\s+\\[\\s*(?:'[^']*'\\s*,\\s*)*'[^']*'\\s*\\])?" const closureRe = "[\\(\\)\\[\\]]" @@ -2240,6 +2320,16 @@ func PrintAST(AST *EvalAST, tab string) string { result += printItems(AST.Obj["$rateColumnsAggregated"].(*EvalAST), tab, ",") + ")" } + if AST.HasOwnProperty("$lttb") { + result += tab + "$lttb(" + result += printItems(AST.Obj["$lttb"].(*EvalAST), tab, ",") + ")" + } + + if AST.HasOwnProperty("$lttbMs") { + result += tab + "$lttbMs(" + result += printItems(AST.Obj["$lttb"].(*EvalAST), tab, ",") + ")" + } + if AST.HasOwnProperty("with") { result += tab + "WITH" result += printItems(AST.Obj["with"].(*EvalAST), tab, ",") diff --git a/pkg/eval/eval_query_test.go b/pkg/eval/eval_query_test.go index ba9038743..2d9076504 100644 --- a/pkg/eval/eval_query_test.go +++ b/pkg/eval/eval_query_test.go @@ -34,6 +34,48 @@ func newMacrosTestCase(name, query, expected, expectedWithWindow string, fn func func TestMacrosBuilder(t *testing.T) { q := EvalQuery{} testCases := []macrosTestCase{ + // https://github.com/Altinity/clickhouse-grafana/issues/500 + newMacrosTestCase( + "$lttb", + "/* comment */\n$lttb(auto, toStartOfMinute(time) AS x_alias, from_total) FROM requests WHERE type IN ('udp', 'tcp') GROUP BY x_alias", + "/* comment */\nSELECT `lttb_result.1` AS x_alias, `lttb_result.2` AS from_total FROM (\n"+ + " SELECT untuple(arrayJoin(lttb(toUInt64( ($to - $from) / $interval ))(toStartOfMinute(time) AS x_alias, from_total))) AS lttb_result FROM requests WHERE $timeFilter AND type IN ('udp', 'tcp') GROUP BY x_alias\n"+ + ") ORDER BY x_alias", + + "/* comment */\nSELECT `lttb_result.1` AS x_alias, `lttb_result.2` AS from_total FROM (\n"+ + " SELECT untuple(arrayJoin(lttb(toUInt64( ($to - $from) / $interval ))(toStartOfMinute(time) AS x_alias, from_total))) AS lttb_result FROM requests WHERE $timeFilter AND type IN ('udp', 'tcp') GROUP BY x_alias\n"+ + ") ORDER BY x_alias", + + q.lttb, + ), + // https://github.com/Altinity/clickhouse-grafana/issues/500 + newMacrosTestCase( + "$lttb with args", + "/* comment */\n$lttb(auto, category, toStartOfMinute(time) AS x_alias, from_total AS sum_from_total) FROM requests WHERE type IN ('udp', 'tcp') GROUP BY category", + "/* comment */\nSELECT `lttb_result.1` AS x_alias, category, `lttb_result.2` AS sum_from_total FROM (\n"+ + " SELECT category, untuple(arrayJoin(lttb(toUInt64( ($to - $from) / $interval ))(toStartOfMinute(time) AS x_alias, from_total AS sum_from_total))) AS lttb_result FROM requests WHERE $timeFilter AND type IN ('udp', 'tcp') GROUP BY category\n"+ + ") ORDER BY x_alias", + + "/* comment */\nSELECT `lttb_result.1` AS x_alias, category, `lttb_result.2` AS sum_from_total FROM (\n"+ + " SELECT category, untuple(arrayJoin(lttb(toUInt64( ($to - $from) / $interval ))(toStartOfMinute(time) AS x_alias, from_total AS sum_from_total))) AS lttb_result FROM requests WHERE $timeFilter AND type IN ('udp', 'tcp') GROUP BY category\n"+ + ") ORDER BY x_alias", + + q.lttb, + ), + // https://github.com/Altinity/clickhouse-grafana/issues/500 + newMacrosTestCase( + "$lttbMs", + "/* comment */\n$lttbMs(auto, toStartOfMinute(time) AS x_alias, from_total AS sum_from_total) FROM requests WHERE type IN ('udp', 'tcp') GROUP BY x_alias", + "/* comment */\nSELECT `lttb_result.1` AS x_alias, `lttb_result.2` AS sum_from_total FROM (\n"+ + " SELECT untuple(arrayJoin(lttb(toUInt64( ($__to - $__from) / $__interval_ms ))(toStartOfMinute(time) AS x_alias, from_total AS sum_from_total))) AS lttb_result FROM requests WHERE $timeFilterMs AND type IN ('udp', 'tcp') GROUP BY x_alias\n"+ + ") ORDER BY x_alias", + + "/* comment */\nSELECT `lttb_result.1` AS x_alias, `lttb_result.2` AS sum_from_total FROM (\n"+ + " SELECT untuple(arrayJoin(lttb(toUInt64( ($__to - $__from) / $__interval_ms ))(toStartOfMinute(time) AS x_alias, from_total AS sum_from_total))) AS lttb_result FROM requests WHERE $timeFilterMs AND type IN ('udp', 'tcp') GROUP BY x_alias\n"+ + ") ORDER BY x_alias", + + q.lttbMs, + ), newMacrosTestCase( "$rate", "/* comment */ $rate(countIf(Type = 200) AS from_good, countIf(Type != 200) AS from_bad) FROM requests", diff --git a/src/views/QueryEditor/components/QueryTextEditor/QueryMacrosInfo.tsx b/src/views/QueryEditor/components/QueryTextEditor/QueryMacrosInfo.tsx index 03856fa92..93f93474f 100644 --- a/src/views/QueryEditor/components/QueryTextEditor/QueryMacrosInfo.tsx +++ b/src/views/QueryEditor/components/QueryTextEditor/QueryMacrosInfo.tsx @@ -28,6 +28,8 @@ const QueryMacrosInfo = () => { {`$rate(cols...) - function to convert query results as "change rate per interval". Example usage: $rate(countIf(Type = 200) * 60 AS good, countIf(Type != 200) * 60 AS bad) FROM requests\n`} {`$columns(key, value) - function to query values as an array of [key, value], where key would be used as a label. Example usage: $columns(Type, count() c) FROM requests\n`} {`$columnsMs(key, value) - same with $columns but time will in milliseconds. Example usage: $columns(Type, count() c) FROM requests\n`} + {`$lttb(bucket_numbers, x_field, y_fields) - allow get down-sampled result which contains more outliers than avg and any other aggregation. Example usage: $lttbMs(100, event_time, count() c) FROM requests\n`} + {`$lttbMs(bucket_numbers, x_field, y_fields) - same with $lttb but time will in milliseconds. Example usage: $lttbMs(auto, event_time, count() c) FROM requests\n`} {`$rateColumns(key, value) - is a combination of $columns and $rate. Example usage: $rateColumns(Type, count() c) FROM requests\n`} {`$rateColumnsAggregated(key, subkey, aggFunction1, value1, ... aggFunctionN, valueN) - if you need calculate \`$rate\` for higher cardinality dimension and then aggregate by lower cardinality dimension. Example usage: $rateColumnsAggregated(datacenter, concat(datacenter,interface) AS dc_interface, sum, tx_bytes * 1014 AS tx_kbytes, sum, max(rx_bytes) AS rx_bytes) FROM traffic\n`} {`$perSecond(cols...) - converts query results as "change rate per interval" for Counter-like(growing only) metrics\n`} diff --git a/src/views/QueryEditor/components/QueryTextEditor/editor/autocompletions/macros.ts b/src/views/QueryEditor/components/QueryTextEditor/editor/autocompletions/macros.ts index b840c2cb7..b96f1ebf1 100644 --- a/src/views/QueryEditor/components/QueryTextEditor/editor/autocompletions/macros.ts +++ b/src/views/QueryEditor/components/QueryTextEditor/editor/autocompletions/macros.ts @@ -155,6 +155,22 @@ const getMacrosAutocompletion = function () { '\n' + 'Example:\n $columnsMs(OSName, count(*) c) FROM requests', }, + { + name: '$lttb', + def: '$lttb(buckets_number, [field1,...fieldN,] x_field, y_field)', + docText: + 'allow get down-sampled result which contains more outliers than avg and any other aggregation' + + '\n' + + 'Example:\n $lttb(auto, event_time, count(*) c) FROM requests', + }, + { + name: '$lttbMs', + def: '$lttbMs(buckets_number, [field1,...fieldN,], x_field, y_field)', + docText: + 'allow get down-sampled result which contains more outliers than avg and any other aggregation' + + '\n' + + 'Example:\n $lttbMs(100, event_time, count(*) c) FROM requests', + }, { name: '$rateColumns', def: '$rateColumns(key, value)', diff --git a/src/views/QueryEditor/components/QueryTextEditor/editor/constants/macros.ts b/src/views/QueryEditor/components/QueryTextEditor/editor/constants/macros.ts index d0caaef7a..33dd442b5 100644 --- a/src/views/QueryEditor/components/QueryTextEditor/editor/constants/macros.ts +++ b/src/views/QueryEditor/components/QueryTextEditor/editor/constants/macros.ts @@ -26,6 +26,8 @@ export default [ '$increaseColumnsAggregated', '$columns', '$columnsMs', + '$lttb', + '$lttbMs', '$unescape', '$adhoc', '$conditionalTest', diff --git a/tests/testflows/tests/automated/sql_editor.py b/tests/testflows/tests/automated/sql_editor.py index c7575987a..3af657189 100644 --- a/tests/testflows/tests/automated/sql_editor.py +++ b/tests/testflows/tests/automated/sql_editor.py @@ -28,6 +28,8 @@ help_functions = """$rate(cols...) - function to convert query results as "change rate per interval". Example usage: $rate(countIf(Type = 200) * 60 AS good, countIf(Type != 200) * 60 AS bad) FROM requests $columns(key, value) - function to query values as an array of [key, value], where key would be used as a label. Example usage: $columns(Type, count() c) FROM requests $columnsMs(key, value) - same with $columns but time will in milliseconds. Example usage: $columns(Type, count() c) FROM requests +$lttb(bucket_numbers, x_field, y_fields) - allow get down-sampled result which contains more outliers than avg and any other aggregation. Example usage: $lttbMs(100, event_time, count() c) FROM requests +$lttbMs(bucket_numbers, x_field, y_fields) - same with $lttb but time will in milliseconds. Example usage: $lttbMs(auto, event_time, count() c) FROM requests $rateColumns(key, value) - is a combination of $columns and $rate. Example usage: $rateColumns(Type, count() c) FROM requests $rateColumnsAggregated(key, subkey, aggFunction1, value1, ... aggFunctionN, valueN) - if you need calculate `$rate` for higher cardinality dimension and then aggregate by lower cardinality dimension. Example usage: $rateColumnsAggregated(datacenter, concat(datacenter,interface) AS dc_interface, sum, tx_bytes * 1014 AS tx_kbytes, sum, max(rx_bytes) AS rx_bytes) FROM traffic $perSecond(cols...) - converts query results as "change rate per interval" for Counter-like(growing only) metrics