From 15cea39136bbdbcae3016b84bd646a3220bd7580 Mon Sep 17 00:00:00 2001 From: Jan Fajerski Date: Mon, 16 Sep 2024 17:45:32 +0200 Subject: [PATCH 1/3] promql: put holt_winters behind experimental feature flag Signed-off-by: Jan Fajerski --- docs/querying/functions.md | 2 ++ promql/parser/functions.go | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/querying/functions.md b/docs/querying/functions.md index e13628c5c..54d0d05dd 100644 --- a/docs/querying/functions.md +++ b/docs/querying/functions.md @@ -382,6 +382,8 @@ variance of observations in a native histogram. ## `holt_winters()` +**This function has to be enabled via the [feature flag](../feature_flags.md#experimental-promql-functions) `--enable-feature=promql-experimental-functions`.** + `holt_winters(v range-vector, sf scalar, tf scalar)` produces a smoothed value for time series based on the range in `v`. The lower the smoothing factor `sf`, the more importance is given to old data. The higher the trend factor `tf`, the diff --git a/promql/parser/functions.go b/promql/parser/functions.go index 99b41321f..4fe3c8093 100644 --- a/promql/parser/functions.go +++ b/promql/parser/functions.go @@ -203,9 +203,10 @@ var Functions = map[string]*Function{ ReturnType: ValueTypeVector, }, "holt_winters": { - Name: "holt_winters", - ArgTypes: []ValueType{ValueTypeMatrix, ValueTypeScalar, ValueTypeScalar}, - ReturnType: ValueTypeVector, + Name: "holt_winters", + ArgTypes: []ValueType{ValueTypeMatrix, ValueTypeScalar, ValueTypeScalar}, + ReturnType: ValueTypeVector, + Experimental: true, }, "hour": { Name: "hour", From 96e5a94d29707d2268feef7bd1c944ed53fd393e Mon Sep 17 00:00:00 2001 From: Jan Fajerski Date: Wed, 18 Sep 2024 11:20:17 +0200 Subject: [PATCH 2/3] promql: rename holt_winters to double_exponential_smoothing Signed-off-by: Jan Fajerski --- docs/querying/functions.md | 11 +- promql/bench_test.go | 2 +- promql/functions.go | 154 +++++++++--------- promql/parser/functions.go | 4 +- promql/promqltest/testdata/functions.test | 6 +- ui-commits | 12 ++ web/ui/mantine-ui/src/promql/functionDocs.tsx | 6 +- web/ui/mantine-ui/src/promql/functionMeta.ts | 4 +- .../src/promql/functionSignatures.ts | 4 +- .../src/complete/promql.terms.ts | 2 +- .../codemirror-promql/src/types/function.ts | 6 +- web/ui/module/lezer-promql/src/highlight.js | 2 +- web/ui/module/lezer-promql/src/promql.grammar | 4 +- 13 files changed, 117 insertions(+), 100 deletions(-) create mode 100644 ui-commits diff --git a/docs/querying/functions.md b/docs/querying/functions.md index 54d0d05dd..9d73b5344 100644 --- a/docs/querying/functions.md +++ b/docs/querying/functions.md @@ -380,17 +380,22 @@ do not show up in the returned vector. Similarly, `histogram_stdvar(v instant-vector)` returns the estimated standard variance of observations in a native histogram. -## `holt_winters()` +## `double_exponential_smoothing()` **This function has to be enabled via the [feature flag](../feature_flags.md#experimental-promql-functions) `--enable-feature=promql-experimental-functions`.** -`holt_winters(v range-vector, sf scalar, tf scalar)` produces a smoothed value +`double_exponential_smoothing(v range-vector, sf scalar, tf scalar)` produces a smoothed value for time series based on the range in `v`. The lower the smoothing factor `sf`, the more importance is given to old data. The higher the trend factor `tf`, the more trends in the data is considered. Both `sf` and `tf` must be between 0 and 1. +For additional details, refer to [NIST Engineering Statistics Handbook](https://www.itl.nist.gov/div898/handbook/pmc/section4/pmc433.htm). +In Prometheus V2 this function was called `holt_winters`. This caused confusion +since the Holt-Winters method usually refers to triple exponential smoothing. +Double exponential smoothing as implemented here is also referred to as "Holt +Linear". -`holt_winters` should only be used with gauges. +`double_exponential_smoothing` should only be used with gauges. ## `hour()` diff --git a/promql/bench_test.go b/promql/bench_test.go index 74e85b054..cd6d1190c 100644 --- a/promql/bench_test.go +++ b/promql/bench_test.go @@ -117,7 +117,7 @@ func rangeQueryCases() []benchCase { }, // Holt-Winters and long ranges. { - expr: "holt_winters(a_X[1d], 0.3, 0.3)", + expr: "double_exponential_smoothing(a_X[1d], 0.3, 0.3)", }, { expr: "changes(a_X[1d])", diff --git a/promql/functions.go b/promql/functions.go index 5bdcce65d..c4a7ee4a4 100644 --- a/promql/functions.go +++ b/promql/functions.go @@ -350,7 +350,7 @@ func calcTrendValue(i int, tf, s0, s1, b float64) float64 { // data. A lower smoothing factor increases the influence of historical data. The trend factor (0 < tf < 1) affects // how trends in historical data will affect the current data. A higher trend factor increases the influence. // of trends. Algorithm taken from https://en.wikipedia.org/wiki/Exponential_smoothing titled: "Double exponential smoothing". -func funcHoltWinters(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) { +func funcDoubleExponentialSmoothing(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) { samples := vals[0].(Matrix)[0] // The smoothing factor argument. @@ -1657,82 +1657,82 @@ func funcYear(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) // FunctionCalls is a list of all functions supported by PromQL, including their types. var FunctionCalls = map[string]FunctionCall{ - "abs": funcAbs, - "absent": funcAbsent, - "absent_over_time": funcAbsentOverTime, - "acos": funcAcos, - "acosh": funcAcosh, - "asin": funcAsin, - "asinh": funcAsinh, - "atan": funcAtan, - "atanh": funcAtanh, - "avg_over_time": funcAvgOverTime, - "ceil": funcCeil, - "changes": funcChanges, - "clamp": funcClamp, - "clamp_max": funcClampMax, - "clamp_min": funcClampMin, - "cos": funcCos, - "cosh": funcCosh, - "count_over_time": funcCountOverTime, - "days_in_month": funcDaysInMonth, - "day_of_month": funcDayOfMonth, - "day_of_week": funcDayOfWeek, - "day_of_year": funcDayOfYear, - "deg": funcDeg, - "delta": funcDelta, - "deriv": funcDeriv, - "exp": funcExp, - "floor": funcFloor, - "histogram_avg": funcHistogramAvg, - "histogram_count": funcHistogramCount, - "histogram_fraction": funcHistogramFraction, - "histogram_quantile": funcHistogramQuantile, - "histogram_sum": funcHistogramSum, - "histogram_stddev": funcHistogramStdDev, - "histogram_stdvar": funcHistogramStdVar, - "holt_winters": funcHoltWinters, - "hour": funcHour, - "idelta": funcIdelta, - "increase": funcIncrease, - "irate": funcIrate, - "label_replace": funcLabelReplace, - "label_join": funcLabelJoin, - "ln": funcLn, - "log10": funcLog10, - "log2": funcLog2, - "last_over_time": funcLastOverTime, - "mad_over_time": funcMadOverTime, - "max_over_time": funcMaxOverTime, - "min_over_time": funcMinOverTime, - "minute": funcMinute, - "month": funcMonth, - "pi": funcPi, - "predict_linear": funcPredictLinear, - "present_over_time": funcPresentOverTime, - "quantile_over_time": funcQuantileOverTime, - "rad": funcRad, - "rate": funcRate, - "resets": funcResets, - "round": funcRound, - "scalar": funcScalar, - "sgn": funcSgn, - "sin": funcSin, - "sinh": funcSinh, - "sort": funcSort, - "sort_desc": funcSortDesc, - "sort_by_label": funcSortByLabel, - "sort_by_label_desc": funcSortByLabelDesc, - "sqrt": funcSqrt, - "stddev_over_time": funcStddevOverTime, - "stdvar_over_time": funcStdvarOverTime, - "sum_over_time": funcSumOverTime, - "tan": funcTan, - "tanh": funcTanh, - "time": funcTime, - "timestamp": funcTimestamp, - "vector": funcVector, - "year": funcYear, + "abs": funcAbs, + "absent": funcAbsent, + "absent_over_time": funcAbsentOverTime, + "acos": funcAcos, + "acosh": funcAcosh, + "asin": funcAsin, + "asinh": funcAsinh, + "atan": funcAtan, + "atanh": funcAtanh, + "avg_over_time": funcAvgOverTime, + "ceil": funcCeil, + "changes": funcChanges, + "clamp": funcClamp, + "clamp_max": funcClampMax, + "clamp_min": funcClampMin, + "cos": funcCos, + "cosh": funcCosh, + "count_over_time": funcCountOverTime, + "days_in_month": funcDaysInMonth, + "day_of_month": funcDayOfMonth, + "day_of_week": funcDayOfWeek, + "day_of_year": funcDayOfYear, + "deg": funcDeg, + "delta": funcDelta, + "deriv": funcDeriv, + "exp": funcExp, + "floor": funcFloor, + "histogram_avg": funcHistogramAvg, + "histogram_count": funcHistogramCount, + "histogram_fraction": funcHistogramFraction, + "histogram_quantile": funcHistogramQuantile, + "histogram_sum": funcHistogramSum, + "histogram_stddev": funcHistogramStdDev, + "histogram_stdvar": funcHistogramStdVar, + "double_exponential_smoothing": funcDoubleExponentialSmoothing, + "hour": funcHour, + "idelta": funcIdelta, + "increase": funcIncrease, + "irate": funcIrate, + "label_replace": funcLabelReplace, + "label_join": funcLabelJoin, + "ln": funcLn, + "log10": funcLog10, + "log2": funcLog2, + "last_over_time": funcLastOverTime, + "mad_over_time": funcMadOverTime, + "max_over_time": funcMaxOverTime, + "min_over_time": funcMinOverTime, + "minute": funcMinute, + "month": funcMonth, + "pi": funcPi, + "predict_linear": funcPredictLinear, + "present_over_time": funcPresentOverTime, + "quantile_over_time": funcQuantileOverTime, + "rad": funcRad, + "rate": funcRate, + "resets": funcResets, + "round": funcRound, + "scalar": funcScalar, + "sgn": funcSgn, + "sin": funcSin, + "sinh": funcSinh, + "sort": funcSort, + "sort_desc": funcSortDesc, + "sort_by_label": funcSortByLabel, + "sort_by_label_desc": funcSortByLabelDesc, + "sqrt": funcSqrt, + "stddev_over_time": funcStddevOverTime, + "stdvar_over_time": funcStdvarOverTime, + "sum_over_time": funcSumOverTime, + "tan": funcTan, + "tanh": funcTanh, + "time": funcTime, + "timestamp": funcTimestamp, + "vector": funcVector, + "year": funcYear, } // AtModifierUnsafeFunctions are the functions whose result diff --git a/promql/parser/functions.go b/promql/parser/functions.go index 4fe3c8093..9d7b56053 100644 --- a/promql/parser/functions.go +++ b/promql/parser/functions.go @@ -202,8 +202,8 @@ var Functions = map[string]*Function{ ArgTypes: []ValueType{ValueTypeScalar, ValueTypeVector}, ReturnType: ValueTypeVector, }, - "holt_winters": { - Name: "holt_winters", + "double_exponential_smoothing": { + Name: "double_exponential_smoothing", ArgTypes: []ValueType{ValueTypeMatrix, ValueTypeScalar, ValueTypeScalar}, ReturnType: ValueTypeVector, Experimental: true, diff --git a/promql/promqltest/testdata/functions.test b/promql/promqltest/testdata/functions.test index 4b025448a..c9af6c4c9 100644 --- a/promql/promqltest/testdata/functions.test +++ b/promql/promqltest/testdata/functions.test @@ -651,7 +651,7 @@ eval_ordered instant at 50m sort_by_label(node_uname_info, "release") node_uname_info{job="node_exporter", instance="4m5", release="1.11.3"} 100 node_uname_info{job="node_exporter", instance="4m1000", release="1.111.3"} 100 -# Tests for holt_winters +# Tests for double_exponential_smoothing clear # positive trends @@ -661,7 +661,7 @@ load 10s http_requests{job="api-server", instance="0", group="canary"} 0+30x1000 300+80x1000 http_requests{job="api-server", instance="1", group="canary"} 0+40x2000 -eval instant at 8000s holt_winters(http_requests[1m], 0.01, 0.1) +eval instant at 8000s double_exponential_smoothing(http_requests[1m], 0.01, 0.1) {job="api-server", instance="0", group="production"} 8000 {job="api-server", instance="1", group="production"} 16000 {job="api-server", instance="0", group="canary"} 24000 @@ -675,7 +675,7 @@ load 10s http_requests{job="api-server", instance="0", group="canary"} 0+30x1000 300-80x1000 http_requests{job="api-server", instance="1", group="canary"} 0-40x1000 0+40x1000 -eval instant at 8000s holt_winters(http_requests[1m], 0.01, 0.1) +eval instant at 8000s double_exponential_smoothing(http_requests[1m], 0.01, 0.1) {job="api-server", instance="0", group="production"} 0 {job="api-server", instance="1", group="production"} -16000 {job="api-server", instance="0", group="canary"} 24000 diff --git a/ui-commits b/ui-commits new file mode 100644 index 000000000..7f34e1f95 --- /dev/null +++ b/ui-commits @@ -0,0 +1,12 @@ +dfec29d8e Fix border color for target pools with one target that is failing +65743bf9b ui: drop template readme +a7c1a951d Add general Mantine overrides CSS file +0757fbbec Make sure that alert element table headers are not wrapped +0180cf31a Factor out common icon and card styles +50af7d589 Fix tree line drawing by using a callback ref +ac01dc903 Explain, vector-to-vector: Do not compute results for set operators +9b0dc68d0 PromQL explain view: Support set operators +57898c792 Refactor and fix time formatting functions, add tests +091fc403c Fiddle with targets table styles to try and improve things a bit +a1908df92 Don't wrap action buttons below metric name in metrics explorer +ac5377873 mantine UI: Distinguish between Not Ready and Stopping diff --git a/web/ui/mantine-ui/src/promql/functionDocs.tsx b/web/ui/mantine-ui/src/promql/functionDocs.tsx index 36c081e86..45fcd03b7 100644 --- a/web/ui/mantine-ui/src/promql/functionDocs.tsx +++ b/web/ui/mantine-ui/src/promql/functionDocs.tsx @@ -1277,17 +1277,17 @@ const funcDocs: Record = {

), - holt_winters: ( + double_exponential_smoothing: ( <>

- holt_winters(v range-vector, sf scalar, tf scalar) produces a smoothed value for time series based on + double_exponential_smoothing(v range-vector, sf scalar, tf scalar) produces a smoothed value for time series based on the range in v. The lower the smoothing factor sf, the more importance is given to old data. The higher the trend factor tf, the more trends in the data is considered. Both sf{' '} and tf must be between 0 and 1.

- holt_winters should only be used with gauges. + double_exponential_smoothing should only be used with gauges.

), diff --git a/web/ui/mantine-ui/src/promql/functionMeta.ts b/web/ui/mantine-ui/src/promql/functionMeta.ts index 631c86e2d..1dec46662 100644 --- a/web/ui/mantine-ui/src/promql/functionMeta.ts +++ b/web/ui/mantine-ui/src/promql/functionMeta.ts @@ -17,7 +17,7 @@ export const functionArgNames: Record = { // exp: [], // floor: [], histogram_quantile: ['target quantile', 'histogram'], - holt_winters: ['input series', 'smoothing factor', 'trend factor'], + double_exponential_smoothing: ['input series', 'smoothing factor', 'trend factor'], hour: ['timestamp (default = vector(time()))'], // idelta: [], // increase: [], @@ -68,7 +68,7 @@ export const functionDescriptions: Record = { exp: 'calculate exponential function for input vector values', floor: 'round down values of input series to nearest integer', histogram_quantile: 'calculate quantiles from histogram buckets', - holt_winters: 'calculate smoothed value of input series', + double_exponential_smoothing: 'calculate smoothed value of input series', hour: 'return the hour of the day for provided timestamps', idelta: 'calculate the difference between the last two samples of a range vector (for counters)', increase: 'calculate the increase in value over a range of time (for counters)', diff --git a/web/ui/mantine-ui/src/promql/functionSignatures.ts b/web/ui/mantine-ui/src/promql/functionSignatures.ts index 9f5b61742..472d54ac5 100644 --- a/web/ui/mantine-ui/src/promql/functionSignatures.ts +++ b/web/ui/mantine-ui/src/promql/functionSignatures.ts @@ -60,8 +60,8 @@ export const functionSignatures: Record = { histogram_stddev: { name: 'histogram_stddev', argTypes: [valueType.vector], variadic: 0, returnType: valueType.vector }, histogram_stdvar: { name: 'histogram_stdvar', argTypes: [valueType.vector], variadic: 0, returnType: valueType.vector }, histogram_sum: { name: 'histogram_sum', argTypes: [valueType.vector], variadic: 0, returnType: valueType.vector }, - holt_winters: { - name: 'holt_winters', + double_exponential_smoothing: { + name: 'double_exponential_smoothing', argTypes: [valueType.matrix, valueType.scalar, valueType.scalar], variadic: 0, returnType: valueType.vector, diff --git a/web/ui/module/codemirror-promql/src/complete/promql.terms.ts b/web/ui/module/codemirror-promql/src/complete/promql.terms.ts index f4f934f50..20cf14d4b 100644 --- a/web/ui/module/codemirror-promql/src/complete/promql.terms.ts +++ b/web/ui/module/codemirror-promql/src/complete/promql.terms.ts @@ -258,7 +258,7 @@ export const functionIdentifierTerms = [ type: 'function', }, { - label: 'holt_winters', + label: 'double_exponential_smoothing', detail: 'function', info: 'Calculate smoothed value of input series', type: 'function', diff --git a/web/ui/module/codemirror-promql/src/types/function.ts b/web/ui/module/codemirror-promql/src/types/function.ts index 2505edc22..4048e2db0 100644 --- a/web/ui/module/codemirror-promql/src/types/function.ts +++ b/web/ui/module/codemirror-promql/src/types/function.ts @@ -46,7 +46,7 @@ import { HistogramStdDev, HistogramStdVar, HistogramSum, - HoltWinters, + DoubleExponentialSmoothing, Hour, Idelta, Increase, @@ -312,8 +312,8 @@ const promqlFunctions: { [key: number]: PromQLFunction } = { variadic: 0, returnType: ValueType.vector, }, - [HoltWinters]: { - name: 'holt_winters', + [DoubleExponentialSmoothing]: { + name: 'double_exponential_smoothing', argTypes: [ValueType.matrix, ValueType.scalar, ValueType.scalar], variadic: 0, returnType: ValueType.vector, diff --git a/web/ui/module/lezer-promql/src/highlight.js b/web/ui/module/lezer-promql/src/highlight.js index 92f27c847..364c4e39a 100644 --- a/web/ui/module/lezer-promql/src/highlight.js +++ b/web/ui/module/lezer-promql/src/highlight.js @@ -20,7 +20,7 @@ export const promQLHighLight = styleTags({ NumberDurationLiteral: tags.number, NumberDurationLiteralInDurationContext: tags.number, Identifier: tags.variableName, - 'Abs Absent AbsentOverTime Acos Acosh Asin Asinh Atan Atanh AvgOverTime Ceil Changes Clamp ClampMax ClampMin Cos Cosh CountOverTime DaysInMonth DayOfMonth DayOfWeek DayOfYear Deg Delta Deriv Exp Floor HistogramAvg HistogramCount HistogramFraction HistogramQuantile HistogramSum HoltWinters Hour Idelta Increase Irate LabelReplace LabelJoin LastOverTime Ln Log10 Log2 MaxOverTime MinOverTime Minute Month Pi PredictLinear PresentOverTime QuantileOverTime Rad Rate Resets Round Scalar Sgn Sin Sinh Sort SortDesc SortByLabel SortByLabelDesc Sqrt StddevOverTime StdvarOverTime SumOverTime Tan Tanh Time Timestamp Vector Year': + 'Abs Absent AbsentOverTime Acos Acosh Asin Asinh Atan Atanh AvgOverTime Ceil Changes Clamp ClampMax ClampMin Cos Cosh CountOverTime DaysInMonth DayOfMonth DayOfWeek DayOfYear Deg Delta Deriv Exp Floor HistogramAvg HistogramCount HistogramFraction HistogramQuantile HistogramSum DoubleExponentialSmoothing Hour Idelta Increase Irate LabelReplace LabelJoin LastOverTime Ln Log10 Log2 MaxOverTime MinOverTime Minute Month Pi PredictLinear PresentOverTime QuantileOverTime Rad Rate Resets Round Scalar Sgn Sin Sinh Sort SortDesc SortByLabel SortByLabelDesc Sqrt StddevOverTime StdvarOverTime SumOverTime Tan Tanh Time Timestamp Vector Year': tags.function(tags.variableName), 'Avg Bottomk Count Count_values Group LimitK LimitRatio Max Min Quantile Stddev Stdvar Sum Topk': tags.operatorKeyword, 'By Without Bool On Ignoring GroupLeft GroupRight Offset Start End': tags.modifier, diff --git a/web/ui/module/lezer-promql/src/promql.grammar b/web/ui/module/lezer-promql/src/promql.grammar index 95c09d25a..977cce44d 100644 --- a/web/ui/module/lezer-promql/src/promql.grammar +++ b/web/ui/module/lezer-promql/src/promql.grammar @@ -141,7 +141,7 @@ FunctionIdentifier { HistogramStdVar | HistogramSum | HistogramAvg | - HoltWinters | + DoubleExponentialSmoothing | Hour | Idelta | Increase | @@ -388,7 +388,7 @@ NumberDurationLiteralInDurationContext { HistogramStdDev { condFn<"histogram_stddev"> } HistogramStdVar { condFn<"histogram_stdvar"> } HistogramSum { condFn<"histogram_sum"> } - HoltWinters { condFn<"holt_winters"> } + DoubleExponentialSmoothing { condFn<"double_exponential_smoothing"> } Hour { condFn<"hour"> } Idelta { condFn<"idelta"> } Increase { condFn<"increase"> } From aa6dd70812c5b2d27e9ff834d22cadb388f3fb87 Mon Sep 17 00:00:00 2001 From: Jan Fajerski Date: Wed, 18 Sep 2024 11:36:42 +0200 Subject: [PATCH 3/3] changelog: record holt_winters rename Signed-off-by: Jan Fajerski --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a60dea169..e515bd370 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## unreleased +* [CHANGE] `holt_winters` is now called `double_exponential_smoothing` and moves behind the [experimental-promql-functions feature flag](https://prometheus.io/docs/prometheus/latest/feature_flags/#experimental-promql-functions). #14930 * [BUGFIX] PromQL: Only return "possible non-counter" annotation when `rate` returns points. #14910 ## 3.0.0-beta.0 / 2024-09-05