diff --git a/cmd/prometheus/main.go b/cmd/prometheus/main.go index 4193d2364..b458abf68 100644 --- a/cmd/prometheus/main.go +++ b/cmd/prometheus/main.go @@ -117,7 +117,8 @@ type flagConfig struct { featureList []string // These options are extracted from featureList // for ease of use. - enablePromQLAtModifier bool + enablePromQLAtModifier bool + enablePromQLNegativeOffset bool prometheusURL string corsRegexString string @@ -134,6 +135,9 @@ func (c *flagConfig) setFeatureListOptions(logger log.Logger) error { case "promql-at-modifier": c.enablePromQLAtModifier = true level.Info(logger).Log("msg", "Experimental promql-at-modifier enabled") + case "promql-negative-offset": + c.enablePromQLNegativeOffset = true + level.Info(logger).Log("msg", "Experimental promql-negative-offset enabled") case "remote-write-receiver": c.web.RemoteWriteReceiver = true level.Info(logger).Log("msg", "Experimental remote-write-receiver enabled") @@ -441,6 +445,7 @@ func main() { LookbackDelta: time.Duration(cfg.lookbackDelta), NoStepSubqueryIntervalFn: noStepSubqueryInterval.Get, EnableAtModifier: cfg.enablePromQLAtModifier, + EnableNegativeOffset: cfg.enablePromQLNegativeOffset, } queryEngine = promql.NewEngine(opts) diff --git a/docs/disabled_features.md b/docs/disabled_features.md index 431d7b536..21222e0ea 100644 --- a/docs/disabled_features.md +++ b/docs/disabled_features.md @@ -18,6 +18,20 @@ They may be enabled by default in future versions. The `@` modifier lets you specify the evaluation time for instant vector selectors, range vector selectors, and subqueries. More details can be found [here](querying/basics.md#modifier). +## Negative offset in PromQL + +This negative offset is disabled by default since it breaks the invariant +that PromQL does not look ahead of the evaluation time for samples. + +`--enable-feature=promql-negative-offset` + +In contrast to the positive offset modifier, the negative offset modifier lets +one shift a vector into the future. An example in which one may want to use a +negative offset is reviewing past data and making temporal comparisons with +more recent data. + +More details can be found [here](querying/basics.md#offset-modifier). + ## Remote Write Receiver `--enable-feature=remote-write-receiver` diff --git a/docs/querying/basics.md b/docs/querying/basics.md index 7229e8e1a..8c66c5362 100644 --- a/docs/querying/basics.md +++ b/docs/querying/basics.md @@ -204,6 +204,15 @@ The same works for range vectors. This returns the 5-minute rate that rate(http_requests_total[5m] offset 1w) +For comparisons with temporal shifts forward in time, a negative offset +can be specified: + + rate(http_requests_total[5m] offset -1w) + +This feature is enabled by setting `--enable-feature=promql-negative-offset` +flag. See [disabled features](../disabled_features.md) for more details about +this flag. + ### @ modifier The `@` modifier allows changing the evaluation time for individual instant diff --git a/promql/engine.go b/promql/engine.go index 0923bedbc..8d0b1b380 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -211,6 +211,9 @@ type EngineOpts struct { // EnableAtModifier if true enables @ modifier. Disabled otherwise. EnableAtModifier bool + + // EnableNegativeOffset if true enables negative (-) offset values. Disabled otherwise. + EnableNegativeOffset bool } // Engine handles the lifetime of queries from beginning to end. @@ -226,6 +229,7 @@ type Engine struct { lookbackDelta time.Duration noStepSubqueryIntervalFn func(rangeMillis int64) int64 enableAtModifier bool + enableNegativeOffset bool } // NewEngine returns a new engine. @@ -307,6 +311,7 @@ func NewEngine(opts EngineOpts) *Engine { lookbackDelta: opts.LookbackDelta, noStepSubqueryIntervalFn: opts.NoStepSubqueryIntervalFn, enableAtModifier: opts.EnableAtModifier, + enableNegativeOffset: opts.EnableNegativeOffset, } } @@ -388,34 +393,53 @@ func (ng *Engine) newQuery(q storage.Queryable, expr parser.Expr, start, end tim } var ErrValidationAtModifierDisabled = errors.New("@ modifier is disabled") +var ErrValidationNegativeOffsetDisabled = errors.New("negative offset is disabled") func (ng *Engine) validateOpts(expr parser.Expr) error { - if ng.enableAtModifier { + if ng.enableAtModifier && ng.enableNegativeOffset { return nil } + var atModifierUsed, negativeOffsetUsed bool + var validationErr error parser.Inspect(expr, func(node parser.Node, path []parser.Node) error { switch n := node.(type) { case *parser.VectorSelector: if n.Timestamp != nil || n.StartOrEnd == parser.START || n.StartOrEnd == parser.END { - validationErr = ErrValidationAtModifierDisabled - return validationErr + atModifierUsed = true + } + if n.OriginalOffset < 0 { + negativeOffsetUsed = true } case *parser.MatrixSelector: vs := n.VectorSelector.(*parser.VectorSelector) if vs.Timestamp != nil || vs.StartOrEnd == parser.START || vs.StartOrEnd == parser.END { - validationErr = ErrValidationAtModifierDisabled - return validationErr + atModifierUsed = true + } + if vs.OriginalOffset < 0 { + negativeOffsetUsed = true } case *parser.SubqueryExpr: if n.Timestamp != nil || n.StartOrEnd == parser.START || n.StartOrEnd == parser.END { - validationErr = ErrValidationAtModifierDisabled - return validationErr + atModifierUsed = true + } + if n.OriginalOffset < 0 { + negativeOffsetUsed = true } } + + if atModifierUsed && !ng.enableAtModifier { + validationErr = ErrValidationAtModifierDisabled + return validationErr + } + if negativeOffsetUsed && !ng.enableNegativeOffset { + validationErr = ErrValidationNegativeOffsetDisabled + return validationErr + } + return nil }) diff --git a/promql/engine_test.go b/promql/engine_test.go index c3a96a9c2..9dea17315 100644 --- a/promql/engine_test.go +++ b/promql/engine_test.go @@ -2299,6 +2299,18 @@ func TestEngineOptsValidation(t *testing.T) { }, { opts: EngineOpts{EnableAtModifier: true}, query: "rate(metric[1h:1m] @ end())", + }, { + opts: EngineOpts{EnableNegativeOffset: false}, + query: "metric offset -1s", fail: true, expError: ErrValidationNegativeOffsetDisabled, + }, { + opts: EngineOpts{EnableNegativeOffset: true}, + query: "metric offset -1s", + }, { + opts: EngineOpts{EnableAtModifier: true, EnableNegativeOffset: true}, + query: "metric @ 100 offset -2m", + }, { + opts: EngineOpts{EnableAtModifier: true, EnableNegativeOffset: true}, + query: "metric offset -2m @ 100", }, } diff --git a/promql/parser/generated_parser.y b/promql/parser/generated_parser.y index 6f398addf..3f914e4ac 100644 --- a/promql/parser/generated_parser.y +++ b/promql/parser/generated_parser.y @@ -386,6 +386,11 @@ offset_expr: expr OFFSET duration yylex.(*parser).addOffset($1, $3) $$ = $1 } + | expr OFFSET SUB duration + { + yylex.(*parser).addOffset($1, -$4) + $$ = $1 + } | expr OFFSET error { yylex.(*parser).unexpected("offset", "duration"); $$ = $1 } ; diff --git a/promql/parser/generated_parser.y.go b/promql/parser/generated_parser.y.go index 26005236b..e0c5ceac5 100644 --- a/promql/parser/generated_parser.y.go +++ b/promql/parser/generated_parser.y.go @@ -189,13 +189,14 @@ var yyToknames = [...]string{ "START_METRIC_SELECTOR", "startSymbolsEnd", } + var yyStatenames = [...]string{} const yyEofCode = 1 const yyErrCode = 2 const yyInitialStackSize = 16 -//line generated_parser.y:742 +//line generated_parser.y:747 //line yacctab:1 var yyExca = [...]int{ @@ -203,301 +204,300 @@ var yyExca = [...]int{ 1, -1, -2, 0, -1, 33, - 1, 127, - 10, 127, - 22, 127, + 1, 128, + 10, 128, + 22, 128, -2, 0, -1, 56, - 2, 139, - 15, 139, - 61, 139, - 67, 139, - -2, 95, - -1, 57, 2, 140, 15, 140, 61, 140, 67, 140, -2, 96, - -1, 58, + -1, 57, 2, 141, 15, 141, 61, 141, 67, 141, - -2, 98, - -1, 59, + -2, 97, + -1, 58, 2, 142, 15, 142, 61, 142, 67, 142, -2, 99, - -1, 60, + -1, 59, 2, 143, 15, 143, 61, 143, 67, 143, -2, 100, - -1, 61, + -1, 60, 2, 144, 15, 144, 61, 144, 67, 144, - -2, 105, - -1, 62, + -2, 101, + -1, 61, 2, 145, 15, 145, 61, 145, 67, 145, - -2, 107, - -1, 63, + -2, 106, + -1, 62, 2, 146, 15, 146, 61, 146, 67, 146, - -2, 109, - -1, 64, + -2, 108, + -1, 63, 2, 147, 15, 147, 61, 147, 67, 147, -2, 110, - -1, 65, + -1, 64, 2, 148, 15, 148, 61, 148, 67, 148, -2, 111, - -1, 66, + -1, 65, 2, 149, 15, 149, 61, 149, 67, 149, -2, 112, - -1, 67, + -1, 66, 2, 150, 15, 150, 61, 150, 67, 150, -2, 113, - -1, 185, - 12, 192, - 13, 192, - 16, 192, - 17, 192, - 23, 192, - 26, 192, - 32, 192, - 33, 192, - 36, 192, - 42, 192, - 46, 192, - 47, 192, - 48, 192, - 49, 192, - 50, 192, - 51, 192, - 52, 192, - 53, 192, - 54, 192, - 55, 192, - 56, 192, - 57, 192, - 61, 192, - 65, 192, - 67, 192, - -2, 0, + -1, 67, + 2, 151, + 15, 151, + 61, 151, + 67, 151, + -2, 114, -1, 186, - 12, 192, - 13, 192, - 16, 192, - 17, 192, - 23, 192, - 26, 192, - 32, 192, - 33, 192, - 36, 192, - 42, 192, - 46, 192, - 47, 192, - 48, 192, - 49, 192, - 50, 192, - 51, 192, - 52, 192, - 53, 192, - 54, 192, - 55, 192, - 56, 192, - 57, 192, - 61, 192, - 65, 192, - 67, 192, + 12, 193, + 13, 193, + 16, 193, + 17, 193, + 23, 193, + 26, 193, + 32, 193, + 33, 193, + 36, 193, + 42, 193, + 46, 193, + 47, 193, + 48, 193, + 49, 193, + 50, 193, + 51, 193, + 52, 193, + 53, 193, + 54, 193, + 55, 193, + 56, 193, + 57, 193, + 61, 193, + 65, 193, + 67, 193, -2, 0, - -1, 205, - 19, 190, + -1, 187, + 12, 193, + 13, 193, + 16, 193, + 17, 193, + 23, 193, + 26, 193, + 32, 193, + 33, 193, + 36, 193, + 42, 193, + 46, 193, + 47, 193, + 48, 193, + 49, 193, + 50, 193, + 51, 193, + 52, 193, + 53, 193, + 54, 193, + 55, 193, + 56, 193, + 57, 193, + 61, 193, + 65, 193, + 67, 193, -2, 0, - -1, 252, + -1, 207, 19, 191, -2, 0, + -1, 254, + 19, 192, + -2, 0, } const yyPrivate = 57344 -const yyLast = 640 +const yyLast = 638 var yyAct = [...]int{ - - 258, 35, 209, 138, 248, 247, 145, 110, 75, 99, - 98, 143, 6, 101, 183, 123, 184, 100, 261, 102, - 185, 186, 243, 144, 149, 242, 148, 97, 49, 70, - 103, 51, 22, 50, 55, 149, 160, 237, 250, 52, - 150, 118, 68, 206, 262, 259, 148, 205, 18, 19, - 236, 150, 20, 105, 93, 106, 96, 201, 69, 104, - 204, 119, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 241, 175, 101, 13, 95, 146, - 147, 24, 102, 30, 2, 3, 4, 5, 70, 107, - 97, 157, 103, 256, 31, 240, 174, 7, 255, 112, - 263, 151, 80, 81, 156, 161, 155, 158, 153, 111, - 154, 254, 10, 90, 91, 238, 8, 93, 94, 96, - 33, 182, 72, 173, 79, 181, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, - 32, 95, 180, 124, 125, 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, 136, 137, 97, 117, 77, - 116, 165, 115, 167, 253, 168, 164, 114, 1, 76, - 81, 140, 239, 202, 203, 172, 152, 163, 113, 251, - 90, 91, 45, 140, 93, 244, 96, 44, 245, 246, - 170, 34, 249, 49, 70, 112, 51, 22, 50, 139, - 169, 171, 77, 177, 52, 111, 140, 68, 95, 252, - 179, 109, 76, 18, 19, 148, 46, 20, 74, 43, - 42, 122, 71, 69, 149, 41, 40, 56, 57, 58, - 59, 60, 61, 62, 63, 64, 65, 66, 67, 257, - 150, 39, 13, 120, 260, 159, 24, 38, 30, 49, - 70, 121, 51, 22, 50, 37, 36, 47, 265, 141, - 52, 54, 266, 68, 9, 9, 178, 78, 176, 18, - 19, 207, 73, 20, 142, 53, 210, 166, 48, 69, - 108, 0, 0, 56, 57, 58, 59, 60, 61, 62, - 63, 64, 65, 66, 67, 211, 0, 0, 13, 0, - 0, 0, 24, 0, 30, 221, 0, 0, 0, 227, - 0, 0, 0, 264, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 223, 224, 0, 0, 225, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 212, - 214, 216, 217, 218, 226, 228, 231, 232, 233, 234, - 235, 211, 0, 213, 215, 219, 220, 222, 229, 230, - 0, 221, 0, 0, 0, 227, 0, 0, 0, 208, + 260, 35, 211, 138, 250, 249, 146, 110, 75, 99, + 98, 101, 144, 184, 6, 185, 123, 102, 140, 100, + 186, 187, 55, 145, 245, 141, 150, 149, 263, 244, + 49, 70, 103, 51, 22, 50, 150, 118, 161, 252, + 243, 52, 151, 239, 68, 264, 261, 112, 149, 203, + 18, 19, 151, 105, 20, 106, 238, 111, 139, 104, + 69, 242, 119, 240, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 176, 107, 101, 13, + 147, 148, 158, 24, 102, 30, 2, 3, 4, 5, + 97, 258, 103, 7, 208, 157, 257, 175, 207, 166, + 70, 152, 80, 81, 165, 162, 156, 159, 154, 256, + 155, 206, 31, 90, 91, 164, 141, 93, 94, 96, + 117, 183, 116, 174, 265, 182, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, + 79, 95, 181, 202, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 255, 10, + 168, 77, 169, 153, 54, 141, 112, 9, 9, 72, + 141, 76, 32, 241, 204, 205, 111, 173, 34, 97, + 49, 70, 109, 51, 22, 50, 246, 171, 1, 247, + 248, 52, 81, 251, 68, 8, 253, 170, 172, 33, + 18, 19, 90, 91, 20, 97, 93, 46, 96, 45, + 69, 254, 44, 71, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 43, 77, 42, 13, + 95, 122, 93, 24, 96, 30, 41, 76, 40, 39, + 120, 259, 178, 74, 160, 38, 262, 49, 70, 180, + 51, 22, 50, 121, 149, 37, 95, 115, 52, 36, + 267, 68, 114, 150, 268, 47, 142, 18, 19, 179, + 78, 20, 177, 113, 209, 73, 143, 69, 53, 151, + 212, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 213, 167, 48, 13, 108, 0, 0, + 24, 0, 30, 223, 0, 0, 0, 229, 0, 0, + 0, 266, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 225, 226, 0, 0, 227, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 214, 216, 218, + 219, 220, 228, 230, 233, 234, 235, 236, 237, 213, + 0, 215, 217, 221, 222, 224, 231, 232, 0, 223, + 0, 0, 0, 229, 0, 0, 0, 210, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, + 226, 0, 0, 227, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 214, 216, 218, 219, 220, 228, 230, + 233, 234, 235, 236, 237, 0, 0, 215, 217, 221, + 222, 224, 231, 232, 17, 70, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 223, 224, 0, 0, 225, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 212, 214, 216, 217, 218, - 226, 228, 231, 232, 233, 234, 235, 0, 0, 213, - 215, 219, 220, 222, 229, 230, 17, 70, 0, 0, - 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 18, 19, 0, 0, - 20, 0, 17, 31, 0, 0, 22, 0, 0, 0, - 11, 12, 14, 15, 16, 21, 23, 25, 26, 27, - 28, 29, 18, 19, 0, 13, 20, 0, 0, 24, - 0, 30, 0, 0, 0, 0, 11, 12, 14, 15, - 16, 21, 23, 25, 26, 27, 28, 29, 97, 0, - 0, 13, 0, 0, 162, 24, 0, 30, 0, 0, - 80, 81, 82, 0, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 0, 93, 94, 96, 0, 0, - 0, 0, 0, 0, 97, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 80, 81, 82, 95, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 0, 0, 0, 0, 18, 19, 0, 0, 20, 0, + 17, 31, 0, 0, 22, 0, 0, 0, 11, 12, + 14, 15, 16, 21, 23, 25, 26, 27, 28, 29, + 18, 19, 0, 13, 20, 0, 0, 24, 0, 30, + 0, 0, 0, 0, 11, 12, 14, 15, 16, 21, + 23, 25, 26, 27, 28, 29, 97, 0, 0, 13, + 0, 0, 163, 24, 0, 30, 0, 0, 80, 81, + 82, 0, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 0, 93, 94, 96, 0, 0, 0, 0, + 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 80, 81, 82, 95, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 0, 93, + 94, 96, 0, 0, 97, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 80, 81, 82, 0, + 83, 84, 85, 95, 87, 88, 89, 90, 91, 92, 0, 93, 94, 96, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 81, - 82, 0, 83, 84, 85, 95, 87, 88, 89, 90, - 91, 92, 0, 93, 94, 96, 0, 0, 97, 0, + 82, 0, 83, 84, 0, 95, 87, 88, 0, 90, + 91, 92, 0, 93, 94, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 80, 81, 82, 0, 83, 84, 0, 95, 87, 88, - 0, 90, 91, 92, 0, 93, 94, 96, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, + 0, 0, 0, 0, 0, 0, 0, 95, } + var yyPact = [...]int{ - - 10, 87, 430, 430, 181, 404, -1000, -1000, -1000, 81, + 12, 83, 428, 428, 168, 402, -1000, -1000, -1000, 99, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 200, -1000, 122, -1000, 510, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 15, 77, - -1000, 237, -1000, 237, 75, -1000, -1000, -1000, -1000, -1000, + -1000, 225, -1000, 138, -1000, 508, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 17, 77, + -1000, 235, -1000, 235, 87, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 193, -1000, -1000, 160, -1000, -1000, 156, -1000, 19, -1000, - -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, 197, 9, 174, 77, -48, - -1000, 89, 89, 16, -1000, 474, 13, -1000, 159, -1000, - -1000, 161, -1000, -1000, 157, -1000, 73, -1000, 198, 237, - -1000, -50, -42, -1000, 237, 237, 237, 237, 237, 237, - 237, 237, 237, 237, 237, 237, 237, 237, -1000, -1000, - -1000, -1000, 42, -1000, -1000, -1000, -1000, -1000, -1000, 29, - 29, 41, -1000, -1000, -1000, -1000, 349, -1000, -1000, 30, - -1000, 510, -1000, -1000, 97, -1000, 72, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 1, -2, -1000, - -1000, -1000, 143, 89, 89, 89, 89, 13, 76, 76, - 76, 574, 542, 76, 76, 574, 13, 13, 76, 13, - 143, 18, -1000, -1000, -1000, 162, -1000, 91, -1000, -1000, + 164, -1000, -1000, 255, -1000, -1000, 118, -1000, 15, -1000, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, 16, 10, 161, 77, -50, + -1000, 80, 80, 18, -1000, 472, 191, -1000, 97, -1000, + -1000, 158, -1000, -1000, 159, -1000, 74, -1000, 237, 235, + -1000, -51, -42, -1000, 235, 235, 235, 235, 235, 235, + 235, 235, 235, 235, 235, 235, 235, 235, -1000, 107, + -1000, -1000, -1000, 34, -1000, -1000, -1000, -1000, -1000, -1000, + 31, 31, 92, -1000, -1000, -1000, -1000, 347, -1000, -1000, + 36, -1000, 508, -1000, -1000, 45, -1000, 38, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 5, 0, + -1000, -1000, -1000, 165, 80, 80, 80, 80, 191, 76, + 76, 76, 572, 540, 76, 76, 572, 191, 191, 76, + 191, 165, -1000, 19, -1000, -1000, -1000, 156, -1000, 89, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 237, -1000, -1000, - -1000, -1000, 28, 28, -6, -1000, -1000, -1000, -1000, -1000, - -1000, 25, 98, -1000, -1000, 293, -1000, 510, -1000, -1000, - -1000, 28, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 235, + -1000, -1000, -1000, -1000, 29, 29, 4, -1000, -1000, -1000, + -1000, -1000, -1000, 26, 122, -1000, -1000, 291, -1000, 508, + -1000, -1000, -1000, 29, -1000, -1000, -1000, -1000, -1000, } + var yyPgo = [...]int{ - - 0, 280, 7, 278, 2, 277, 276, 261, 275, 274, - 112, 272, 116, 8, 271, 4, 5, 268, 267, 0, - 23, 266, 6, 259, 257, 256, 10, 61, 255, 251, - 1, 247, 245, 9, 243, 34, 241, 226, 225, 221, - 220, 219, 187, 182, 216, 3, 179, 168, 140, + 0, 297, 7, 295, 2, 294, 280, 164, 278, 276, + 159, 275, 195, 8, 274, 4, 5, 272, 270, 0, + 23, 269, 6, 266, 265, 259, 10, 62, 255, 253, + 1, 245, 244, 9, 240, 22, 239, 238, 236, 231, + 228, 226, 212, 209, 207, 3, 196, 188, 172, } -var yyR1 = [...]int{ +var yyR1 = [...]int{ 0, 47, 47, 47, 47, 47, 47, 47, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 25, 25, 25, 25, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 27, 29, 29, 39, 39, 34, 34, 34, 34, 15, 15, 15, 15, 14, 14, 14, 4, 4, 31, - 33, 33, 32, 32, 32, 40, 38, 38, 24, 24, - 24, 9, 9, 36, 42, 42, 42, 42, 42, 43, - 44, 44, 44, 35, 35, 35, 1, 1, 1, 2, - 2, 2, 2, 12, 12, 7, 7, 7, 7, 7, + 33, 33, 32, 32, 32, 40, 38, 38, 38, 24, + 24, 24, 9, 9, 36, 42, 42, 42, 42, 42, + 43, 44, 44, 44, 35, 35, 35, 1, 1, 1, + 2, 2, 2, 2, 12, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 10, 10, 10, 10, 11, - 11, 11, 13, 13, 13, 13, 48, 18, 18, 18, - 18, 17, 17, 17, 17, 17, 21, 21, 21, 3, + 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, + 11, 11, 11, 13, 13, 13, 13, 48, 18, 18, + 18, 18, 17, 17, 17, 17, 17, 21, 21, 21, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 8, 8, 5, 5, 5, - 5, 37, 20, 22, 22, 23, 23, 19, 45, 41, - 46, 46, 16, 16, + 6, 6, 6, 6, 6, 6, 8, 8, 5, 5, + 5, 5, 37, 20, 22, 22, 23, 23, 19, 45, + 41, 46, 46, 16, 16, } -var yyR2 = [...]int{ +var yyR2 = [...]int{ 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 0, 1, 3, 3, 1, 1, 3, 3, 3, 4, 2, 1, 3, 1, 2, 1, 1, 2, - 3, 2, 3, 1, 2, 3, 3, 3, 3, 5, - 3, 1, 1, 4, 6, 6, 5, 4, 3, 2, - 2, 1, 1, 3, 4, 2, 3, 1, 2, 3, - 3, 2, 1, 2, 1, 1, 1, 1, 1, 1, + 3, 2, 3, 1, 2, 3, 3, 4, 3, 3, + 5, 3, 1, 1, 4, 6, 6, 5, 4, 3, + 2, 2, 1, 1, 3, 4, 2, 3, 1, 2, + 3, 3, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 3, 4, 2, 0, 3, - 1, 2, 3, 3, 2, 1, 2, 0, 3, 2, - 1, 1, 3, 1, 3, 4, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 4, 2, 0, + 3, 1, 2, 3, 3, 2, 1, 2, 0, 3, + 2, 1, 1, 3, 1, 3, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, - 0, 1, 0, 1, + 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, + 1, 0, 1, 0, 1, } -var yyChk = [...]int{ +var yyChk = [...]int{ -1000, -47, 74, 75, 76, 77, 2, 10, -12, -7, -10, 46, 47, 61, 48, 49, 50, 12, 32, 33, 36, 51, 16, 52, 65, 53, 54, 55, 56, 57, @@ -511,57 +511,57 @@ var yyChk = [...]int{ 2, 61, 67, 15, -33, -30, -30, -35, -1, 18, -2, 12, 2, 18, 7, 2, 4, 2, 22, -27, -34, -29, -39, 60, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27, -45, 2, - 9, -23, -9, 2, -20, -22, 70, 71, 17, 26, - 42, -45, 2, -33, -26, -15, 15, 2, -15, -32, - 20, -30, 20, 18, 7, 2, -5, 2, 4, 39, - 29, 40, 18, -13, 23, 2, -17, 5, -21, 12, - -20, -22, -30, 64, 66, 62, 63, -30, -30, -30, + -27, -27, -27, -27, -27, -27, -27, -27, -45, 42, + 2, 9, -23, -9, 2, -20, -22, 70, 71, 17, + 26, 42, -45, 2, -33, -26, -15, 15, 2, -15, + -32, 20, -30, 20, 18, 7, 2, -5, 2, 4, + 39, 29, 40, 18, -13, 23, 2, -17, 5, -21, + 12, -20, -22, -30, 64, 66, 62, 63, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, - -30, 15, -20, -20, 19, 6, 2, -14, 20, -4, - -6, 2, 46, 60, 47, 61, 48, 49, 50, 62, - 63, 12, 64, 32, 33, 36, 51, 16, 52, 65, - 66, 53, 54, 55, 56, 57, 20, 7, 18, -2, - 23, 2, 24, 24, -22, -15, -15, -16, -15, -16, - 20, -46, -45, 2, 20, 7, 2, -30, -19, 17, - -19, 24, 19, 2, 20, -4, -19, + -30, -30, -45, 15, -20, -20, 19, 6, 2, -14, + 20, -4, -6, 2, 46, 60, 47, 61, 48, 49, + 50, 62, 63, 12, 64, 32, 33, 36, 51, 16, + 52, 65, 66, 53, 54, 55, 56, 57, 20, 7, + 18, -2, 23, 2, 24, 24, -22, -15, -15, -16, + -15, -16, 20, -46, -45, 2, 20, 7, 2, -30, + -19, 17, -19, 24, 19, 2, 20, -4, -19, } -var yyDef = [...]int{ - 0, -2, 118, 118, 0, 0, 7, 6, 1, 118, - 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 0, 2, -2, 3, 4, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 0, 101, - 181, 0, 189, 0, 81, 82, -2, -2, -2, -2, - -2, -2, -2, -2, -2, -2, -2, -2, 175, 176, - 0, 5, 93, 0, 117, 120, 0, 125, 126, 130, +var yyDef = [...]int{ + 0, -2, 119, 119, 0, 0, 7, 6, 1, 119, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 0, 2, -2, 3, 4, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 0, 102, + 182, 0, 190, 0, 82, 83, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, 176, 177, + 0, 5, 94, 0, 118, 121, 0, 126, 127, 131, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 0, 0, 0, 0, 22, - 23, 0, 0, 0, 59, 0, 79, 80, 0, 85, - 87, 0, 92, 115, 0, 121, 0, 124, 129, 0, + 23, 0, 0, 0, 59, 0, 80, 81, 0, 86, + 88, 0, 93, 116, 0, 122, 0, 125, 130, 0, 41, 46, 47, 43, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 66, 67, - 188, 68, 0, 70, 185, 186, 71, 72, 182, 0, - 0, 0, 78, 20, 21, 24, 0, 53, 25, 0, - 61, 63, 65, 83, 0, 88, 0, 91, 177, 178, - 179, 180, 116, 119, 122, 123, 128, 131, 133, 136, - 137, 138, 26, 0, 0, -2, -2, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 0, 183, 184, 73, -2, 77, 0, 52, 55, - 57, 58, 151, 152, 153, 154, 155, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 60, 64, 84, 86, - 89, 90, 0, 0, 0, 44, 45, 48, 193, 49, - 69, 0, -2, 76, 50, 0, 56, 62, 132, 187, - 134, 0, 74, 75, 51, 54, 135, + 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, + 68, 189, 69, 0, 71, 186, 187, 72, 73, 183, + 0, 0, 0, 79, 20, 21, 24, 0, 53, 25, + 0, 61, 63, 65, 84, 0, 89, 0, 92, 178, + 179, 180, 181, 117, 120, 123, 124, 129, 132, 134, + 137, 138, 139, 26, 0, 0, -2, -2, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 67, 0, 184, 185, 74, -2, 78, 0, + 52, 55, 57, 58, 152, 153, 154, 155, 156, 157, + 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, 60, 64, + 85, 87, 90, 91, 0, 0, 0, 44, 45, 48, + 194, 49, 70, 0, -2, 77, 50, 0, 56, 62, + 133, 188, 135, 0, 75, 76, 51, 54, 136, } -var yyTok1 = [...]int{ +var yyTok1 = [...]int{ 1, } -var yyTok2 = [...]int{ +var yyTok2 = [...]int{ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, @@ -571,6 +571,7 @@ var yyTok2 = [...]int{ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, } + var yyTok3 = [...]int{ 0, } @@ -1244,36 +1245,43 @@ yydefault: yyVAL.node = yyDollar[1].node } case 67: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-4 : yypt+1] //line generated_parser.y:390 { - yylex.(*parser).unexpected("offset", "duration") + yylex.(*parser).addOffset(yyDollar[1].node, -yyDollar[4].duration) yyVAL.node = yyDollar[1].node } case 68: yyDollar = yyS[yypt-3 : yypt+1] -//line generated_parser.y:397 +//line generated_parser.y:395 + { + yylex.(*parser).unexpected("offset", "duration") + yyVAL.node = yyDollar[1].node + } + case 69: + yyDollar = yyS[yypt-3 : yypt+1] +//line generated_parser.y:402 { yylex.(*parser).setTimestamp(yyDollar[1].node, yyDollar[3].float) yyVAL.node = yyDollar[1].node } - case 69: + case 70: yyDollar = yyS[yypt-5 : yypt+1] -//line generated_parser.y:402 +//line generated_parser.y:407 { yylex.(*parser).setAtModifierPreprocessor(yyDollar[1].node, yyDollar[3].item) yyVAL.node = yyDollar[1].node } - case 70: + case 71: yyDollar = yyS[yypt-3 : yypt+1] -//line generated_parser.y:407 +//line generated_parser.y:412 { yylex.(*parser).unexpected("@", "timestamp") yyVAL.node = yyDollar[1].node } - case 73: + case 74: yyDollar = yyS[yypt-4 : yypt+1] -//line generated_parser.y:417 +//line generated_parser.y:422 { var errMsg string vs, ok := yyDollar[1].node.(*VectorSelector) @@ -1296,9 +1304,9 @@ yydefault: EndPos: yylex.(*parser).lastClosing, } } - case 74: + case 75: yyDollar = yyS[yypt-6 : yypt+1] -//line generated_parser.y:442 +//line generated_parser.y:447 { yyVAL.node = &SubqueryExpr{ Expr: yyDollar[1].node.(Expr), @@ -1308,37 +1316,37 @@ yydefault: EndPos: yyDollar[6].item.Pos + 1, } } - case 75: + case 76: yyDollar = yyS[yypt-6 : yypt+1] -//line generated_parser.y:452 +//line generated_parser.y:457 { yylex.(*parser).unexpected("subquery selector", "\"]\"") yyVAL.node = yyDollar[1].node } - case 76: + case 77: yyDollar = yyS[yypt-5 : yypt+1] -//line generated_parser.y:454 +//line generated_parser.y:459 { yylex.(*parser).unexpected("subquery selector", "duration or \"]\"") yyVAL.node = yyDollar[1].node } - case 77: + case 78: yyDollar = yyS[yypt-4 : yypt+1] -//line generated_parser.y:456 +//line generated_parser.y:461 { yylex.(*parser).unexpected("subquery or range", "\":\" or \"]\"") yyVAL.node = yyDollar[1].node } - case 78: + case 79: yyDollar = yyS[yypt-3 : yypt+1] -//line generated_parser.y:458 +//line generated_parser.y:463 { yylex.(*parser).unexpected("subquery selector", "duration") yyVAL.node = yyDollar[1].node } - case 79: + case 80: yyDollar = yyS[yypt-2 : yypt+1] -//line generated_parser.y:468 +//line generated_parser.y:473 { if nl, ok := yyDollar[2].node.(*NumberLiteral); ok { if yyDollar[1].item.Typ == SUB { @@ -1350,9 +1358,9 @@ yydefault: yyVAL.node = &UnaryExpr{Op: yyDollar[1].item.Typ, Expr: yyDollar[2].node.(Expr), StartPos: yyDollar[1].item.Pos} } } - case 80: + case 81: yyDollar = yyS[yypt-2 : yypt+1] -//line generated_parser.y:486 +//line generated_parser.y:491 { vs := yyDollar[2].node.(*VectorSelector) vs.PosRange = mergeRanges(&yyDollar[1].item, vs) @@ -1360,9 +1368,9 @@ yydefault: yylex.(*parser).assembleVectorSelector(vs) yyVAL.node = vs } - case 81: + case 82: yyDollar = yyS[yypt-1 : yypt+1] -//line generated_parser.y:494 +//line generated_parser.y:499 { vs := &VectorSelector{ Name: yyDollar[1].item.Val, @@ -1372,44 +1380,44 @@ yydefault: yylex.(*parser).assembleVectorSelector(vs) yyVAL.node = vs } - case 82: + case 83: yyDollar = yyS[yypt-1 : yypt+1] -//line generated_parser.y:504 +//line generated_parser.y:509 { vs := yyDollar[1].node.(*VectorSelector) yylex.(*parser).assembleVectorSelector(vs) yyVAL.node = vs } - case 83: + case 84: yyDollar = yyS[yypt-3 : yypt+1] -//line generated_parser.y:512 +//line generated_parser.y:517 { yyVAL.node = &VectorSelector{ LabelMatchers: yyDollar[2].matchers, PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[3].item), } } - case 84: + case 85: yyDollar = yyS[yypt-4 : yypt+1] -//line generated_parser.y:519 +//line generated_parser.y:524 { yyVAL.node = &VectorSelector{ LabelMatchers: yyDollar[2].matchers, PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[4].item), } } - case 85: + case 86: yyDollar = yyS[yypt-2 : yypt+1] -//line generated_parser.y:526 +//line generated_parser.y:531 { yyVAL.node = &VectorSelector{ LabelMatchers: []*labels.Matcher{}, PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[2].item), } } - case 86: + case 87: yyDollar = yyS[yypt-3 : yypt+1] -//line generated_parser.y:535 +//line generated_parser.y:540 { if yyDollar[1].matchers != nil { yyVAL.matchers = append(yyDollar[1].matchers, yyDollar[3].matcher) @@ -1417,196 +1425,196 @@ yydefault: yyVAL.matchers = yyDollar[1].matchers } } - case 87: + case 88: yyDollar = yyS[yypt-1 : yypt+1] -//line generated_parser.y:543 +//line generated_parser.y:548 { yyVAL.matchers = []*labels.Matcher{yyDollar[1].matcher} } - case 88: + case 89: yyDollar = yyS[yypt-2 : yypt+1] -//line generated_parser.y:545 +//line generated_parser.y:550 { yylex.(*parser).unexpected("label matching", "\",\" or \"}\"") yyVAL.matchers = yyDollar[1].matchers } - case 89: + case 90: yyDollar = yyS[yypt-3 : yypt+1] -//line generated_parser.y:549 +//line generated_parser.y:554 { yyVAL.matcher = yylex.(*parser).newLabelMatcher(yyDollar[1].item, yyDollar[2].item, yyDollar[3].item) } - case 90: + case 91: yyDollar = yyS[yypt-3 : yypt+1] -//line generated_parser.y:551 +//line generated_parser.y:556 { yylex.(*parser).unexpected("label matching", "string") yyVAL.matcher = nil } - case 91: + case 92: yyDollar = yyS[yypt-2 : yypt+1] -//line generated_parser.y:553 +//line generated_parser.y:558 { yylex.(*parser).unexpected("label matching", "label matching operator") yyVAL.matcher = nil } - case 92: + case 93: yyDollar = yyS[yypt-1 : yypt+1] -//line generated_parser.y:555 +//line generated_parser.y:560 { yylex.(*parser).unexpected("label matching", "identifier or \"}\"") yyVAL.matcher = nil } - case 93: + case 94: yyDollar = yyS[yypt-2 : yypt+1] -//line generated_parser.y:563 +//line generated_parser.y:568 { yyVAL.labels = append(yyDollar[2].labels, labels.Label{Name: labels.MetricName, Value: yyDollar[1].item.Val}) sort.Sort(yyVAL.labels) } - case 94: + case 95: yyDollar = yyS[yypt-1 : yypt+1] -//line generated_parser.y:565 +//line generated_parser.y:570 { yyVAL.labels = yyDollar[1].labels } - case 115: - yyDollar = yyS[yypt-3 : yypt+1] -//line generated_parser.y:572 - { - yyVAL.labels = labels.New(yyDollar[2].labels...) - } case 116: - yyDollar = yyS[yypt-4 : yypt+1] -//line generated_parser.y:574 + yyDollar = yyS[yypt-3 : yypt+1] +//line generated_parser.y:577 { yyVAL.labels = labels.New(yyDollar[2].labels...) } case 117: - yyDollar = yyS[yypt-2 : yypt+1] -//line generated_parser.y:576 + yyDollar = yyS[yypt-4 : yypt+1] +//line generated_parser.y:579 { - yyVAL.labels = labels.New() + yyVAL.labels = labels.New(yyDollar[2].labels...) } case 118: - yyDollar = yyS[yypt-0 : yypt+1] -//line generated_parser.y:578 + yyDollar = yyS[yypt-2 : yypt+1] +//line generated_parser.y:581 { yyVAL.labels = labels.New() } case 119: + yyDollar = yyS[yypt-0 : yypt+1] +//line generated_parser.y:583 + { + yyVAL.labels = labels.New() + } + case 120: yyDollar = yyS[yypt-3 : yypt+1] -//line generated_parser.y:582 +//line generated_parser.y:587 { yyVAL.labels = append(yyDollar[1].labels, yyDollar[3].label) } - case 120: + case 121: yyDollar = yyS[yypt-1 : yypt+1] -//line generated_parser.y:584 +//line generated_parser.y:589 { yyVAL.labels = []labels.Label{yyDollar[1].label} } - case 121: + case 122: yyDollar = yyS[yypt-2 : yypt+1] -//line generated_parser.y:586 +//line generated_parser.y:591 { yylex.(*parser).unexpected("label set", "\",\" or \"}\"") yyVAL.labels = yyDollar[1].labels } - case 122: + case 123: yyDollar = yyS[yypt-3 : yypt+1] -//line generated_parser.y:591 +//line generated_parser.y:596 { yyVAL.label = labels.Label{Name: yyDollar[1].item.Val, Value: yylex.(*parser).unquoteString(yyDollar[3].item.Val)} } - case 123: + case 124: yyDollar = yyS[yypt-3 : yypt+1] -//line generated_parser.y:593 +//line generated_parser.y:598 { yylex.(*parser).unexpected("label set", "string") yyVAL.label = labels.Label{} } - case 124: + case 125: yyDollar = yyS[yypt-2 : yypt+1] -//line generated_parser.y:595 +//line generated_parser.y:600 { yylex.(*parser).unexpected("label set", "\"=\"") yyVAL.label = labels.Label{} } - case 125: + case 126: yyDollar = yyS[yypt-1 : yypt+1] -//line generated_parser.y:597 +//line generated_parser.y:602 { yylex.(*parser).unexpected("label set", "identifier or \"}\"") yyVAL.label = labels.Label{} } - case 126: + case 127: yyDollar = yyS[yypt-2 : yypt+1] -//line generated_parser.y:605 +//line generated_parser.y:610 { yylex.(*parser).generatedParserResult = &seriesDescription{ labels: yyDollar[1].labels, values: yyDollar[2].series, } } - case 127: + case 128: yyDollar = yyS[yypt-0 : yypt+1] -//line generated_parser.y:614 +//line generated_parser.y:619 { yyVAL.series = []SequenceValue{} } - case 128: + case 129: yyDollar = yyS[yypt-3 : yypt+1] -//line generated_parser.y:616 +//line generated_parser.y:621 { yyVAL.series = append(yyDollar[1].series, yyDollar[3].series...) } - case 129: + case 130: yyDollar = yyS[yypt-2 : yypt+1] -//line generated_parser.y:618 +//line generated_parser.y:623 { yyVAL.series = yyDollar[1].series } - case 130: + case 131: yyDollar = yyS[yypt-1 : yypt+1] -//line generated_parser.y:620 +//line generated_parser.y:625 { yylex.(*parser).unexpected("series values", "") yyVAL.series = nil } - case 131: + case 132: yyDollar = yyS[yypt-1 : yypt+1] -//line generated_parser.y:624 +//line generated_parser.y:629 { yyVAL.series = []SequenceValue{{Omitted: true}} } - case 132: + case 133: yyDollar = yyS[yypt-3 : yypt+1] -//line generated_parser.y:626 +//line generated_parser.y:631 { yyVAL.series = []SequenceValue{} for i := uint64(0); i < yyDollar[3].uint; i++ { yyVAL.series = append(yyVAL.series, SequenceValue{Omitted: true}) } } - case 133: + case 134: yyDollar = yyS[yypt-1 : yypt+1] -//line generated_parser.y:633 +//line generated_parser.y:638 { yyVAL.series = []SequenceValue{{Value: yyDollar[1].float}} } - case 134: + case 135: yyDollar = yyS[yypt-3 : yypt+1] -//line generated_parser.y:635 +//line generated_parser.y:640 { yyVAL.series = []SequenceValue{} for i := uint64(0); i <= yyDollar[3].uint; i++ { yyVAL.series = append(yyVAL.series, SequenceValue{Value: yyDollar[1].float}) } } - case 135: + case 136: yyDollar = yyS[yypt-4 : yypt+1] -//line generated_parser.y:642 +//line generated_parser.y:647 { yyVAL.series = []SequenceValue{} for i := uint64(0); i <= yyDollar[4].uint; i++ { @@ -1614,45 +1622,45 @@ yydefault: yyDollar[1].float += yyDollar[2].float } } - case 136: + case 137: yyDollar = yyS[yypt-1 : yypt+1] -//line generated_parser.y:652 +//line generated_parser.y:657 { if yyDollar[1].item.Val != "stale" { yylex.(*parser).unexpected("series values", "number or \"stale\"") } yyVAL.float = math.Float64frombits(value.StaleNaN) } - case 181: + case 182: yyDollar = yyS[yypt-1 : yypt+1] -//line generated_parser.y:683 +//line generated_parser.y:688 { yyVAL.node = &NumberLiteral{ Val: yylex.(*parser).number(yyDollar[1].item.Val), PosRange: yyDollar[1].item.PositionRange(), } } - case 182: + case 183: yyDollar = yyS[yypt-1 : yypt+1] -//line generated_parser.y:691 +//line generated_parser.y:696 { yyVAL.float = yylex.(*parser).number(yyDollar[1].item.Val) } - case 183: + case 184: yyDollar = yyS[yypt-2 : yypt+1] -//line generated_parser.y:693 +//line generated_parser.y:698 { yyVAL.float = yyDollar[2].float } - case 184: + case 185: yyDollar = yyS[yypt-2 : yypt+1] -//line generated_parser.y:694 +//line generated_parser.y:699 { yyVAL.float = -yyDollar[2].float } - case 187: + case 188: yyDollar = yyS[yypt-1 : yypt+1] -//line generated_parser.y:700 +//line generated_parser.y:705 { var err error yyVAL.uint, err = strconv.ParseUint(yyDollar[1].item.Val, 10, 64) @@ -1660,9 +1668,9 @@ yydefault: yylex.(*parser).addParseErrf(yyDollar[1].item.PositionRange(), "invalid repetition in series values: %s", err) } } - case 188: + case 189: yyDollar = yyS[yypt-1 : yypt+1] -//line generated_parser.y:710 +//line generated_parser.y:715 { var err error yyVAL.duration, err = parseDuration(yyDollar[1].item.Val) @@ -1670,24 +1678,24 @@ yydefault: yylex.(*parser).addParseErr(yyDollar[1].item.PositionRange(), err) } } - case 189: + case 190: yyDollar = yyS[yypt-1 : yypt+1] -//line generated_parser.y:721 +//line generated_parser.y:726 { yyVAL.node = &StringLiteral{ Val: yylex.(*parser).unquoteString(yyDollar[1].item.Val), PosRange: yyDollar[1].item.PositionRange(), } } - case 190: + case 191: yyDollar = yyS[yypt-0 : yypt+1] -//line generated_parser.y:734 +//line generated_parser.y:739 { yyVAL.duration = 0 } - case 192: + case 193: yyDollar = yyS[yypt-0 : yypt+1] -//line generated_parser.y:738 +//line generated_parser.y:743 { yyVAL.strings = nil } diff --git a/promql/parser/parse_test.go b/promql/parser/parse_test.go index d4203c16e..475f15f56 100644 --- a/promql/parser/parse_test.go +++ b/promql/parser/parse_test.go @@ -1362,6 +1362,19 @@ var testExpr = []struct { End: 13, }, }, + }, { + input: "foo offset -7m", + expected: &VectorSelector{ + Name: "foo", + OriginalOffset: -7 * time.Minute, + LabelMatchers: []*labels.Matcher{ + MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "foo"), + }, + PosRange: PositionRange{ + Start: 0, + End: 14, + }, + }, }, { input: `foo OFFSET 1h30m`, expected: &VectorSelector{ diff --git a/promql/parser/printer.go b/promql/parser/printer.go index 0b6368ed2..c5f80eb0b 100644 --- a/promql/parser/printer.go +++ b/promql/parser/printer.go @@ -116,8 +116,10 @@ func (node *MatrixSelector) String() string { // Copy the Vector selector before changing the offset vecSelector := *node.VectorSelector.(*VectorSelector) offset := "" - if vecSelector.OriginalOffset != time.Duration(0) { + if vecSelector.OriginalOffset > time.Duration(0) { offset = fmt.Sprintf(" offset %s", model.Duration(vecSelector.OriginalOffset)) + } else if vecSelector.OriginalOffset < time.Duration(0) { + offset = fmt.Sprintf(" offset -%s", model.Duration(-vecSelector.OriginalOffset)) } at := "" if vecSelector.Timestamp != nil { @@ -147,8 +149,10 @@ func (node *SubqueryExpr) String() string { step = model.Duration(node.Step).String() } offset := "" - if node.OriginalOffset != time.Duration(0) { + if node.OriginalOffset > time.Duration(0) { offset = fmt.Sprintf(" offset %s", model.Duration(node.OriginalOffset)) + } else if node.OriginalOffset < time.Duration(0) { + offset = fmt.Sprintf(" offset -%s", model.Duration(-node.OriginalOffset)) } at := "" if node.Timestamp != nil { @@ -187,8 +191,10 @@ func (node *VectorSelector) String() string { labelStrings = append(labelStrings, matcher.String()) } offset := "" - if node.OriginalOffset != time.Duration(0) { + if node.OriginalOffset > time.Duration(0) { offset = fmt.Sprintf(" offset %s", model.Duration(node.OriginalOffset)) + } else if node.OriginalOffset < time.Duration(0) { + offset = fmt.Sprintf(" offset -%s", model.Duration(-node.OriginalOffset)) } at := "" if node.Timestamp != nil { diff --git a/promql/parser/printer_test.go b/promql/parser/printer_test.go index 850026a68..1ad48c3d4 100644 --- a/promql/parser/printer_test.go +++ b/promql/parser/printer_test.go @@ -77,12 +77,18 @@ func TestExprString(t *testing.T) { { in: `a offset 1m`, }, + { + in: `a offset -7m`, + }, { in: `a{c="d"}[5m] offset 1m`, }, { in: `a[5m] offset 1m`, }, + { + in: `a[12m] offset -3m`, + }, { in: `a[1h:5m] offset 1m`, }, diff --git a/web/api/v1/api.go b/web/api/v1/api.go index b6a6fcdb5..9430762cc 100644 --- a/web/api/v1/api.go +++ b/web/api/v1/api.go @@ -354,6 +354,8 @@ func (api *API) query(r *http.Request) (result apiFuncResult) { qry, err := api.QueryEngine.NewInstantQuery(api.Queryable, r.FormValue("query"), ts) if err == promql.ErrValidationAtModifierDisabled { err = errors.New("@ modifier is disabled, use --enable-feature=promql-at-modifier to enable it") + } else if err == promql.ErrValidationNegativeOffsetDisabled { + err = errors.New("negative offset is disabled, use --enable-feature=promql-negative-offset to enable it") } if err != nil { return invalidParamError(err, "query") @@ -432,6 +434,8 @@ func (api *API) queryRange(r *http.Request) (result apiFuncResult) { qry, err := api.QueryEngine.NewRangeQuery(api.Queryable, r.FormValue("query"), start, end, step) if err == promql.ErrValidationAtModifierDisabled { err = errors.New("@ modifier is disabled, use --enable-feature=promql-at-modifier to enable it") + } else if err == promql.ErrValidationNegativeOffsetDisabled { + err = errors.New("negative offset is disabled, use --enable-feature=promql-negative-offset to enable it") } if err != nil { return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}