Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 32 additions & 28 deletions promql/functions.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -1908,10 +1908,12 @@ func init() {
// Values:
// "1" - replace rate/increase/delta with xrate/xincrease/xdelta
// AND remove the x* names (legacy behaviour).
// "x", "X" - point rate/increase/delta at xrate/xincrease/xdelta but
// keep the x* names available.
// "2", - point rate/increase/delta at yrate/yincrease/ydelta but
// "y", "Y" keep the y* names available.
// "x", "X" - point rate/increase/delta at xrate/xincrease/xdelta;
// keep the x* names; preserve upstream implementations as
// _rate/_increase/_delta.
// "2", - point rate/increase/delta at yrate/yincrease/ydelta;
// "y", "Y" keep the y* (and x*) names; preserve upstream
// implementations as _rate/_increase/_delta.
switch os.Getenv("REPLACE_RATE_FUNCS") {
case "1":
FunctionCalls["delta"] = FunctionCalls["xdelta"]
Expand All@@ -1933,37 +1935,39 @@ func init() {
fmt.Println("Successfully replaced rate & friends with xrate & friends (and removed xrate & friends function keys).")

case "x", "X":
repointParserFunctions("delta", "xdelta")
repointParserFunctions("increase", "xincrease")
repointParserFunctions("rate", "xrate")
repointFunction("delta", "xdelta")
repointFunction("increase", "xincrease")
repointFunction("rate", "xrate")
fmt.Println("Successfully replaced rate/increase/delta with xrate/xincrease/xdelta (and left the x* names available as well).")
replaceStandardRateFuncs("x")
fmt.Println("Successfully replaced rate/increase/delta with xrate/xincrease/xdelta; originals available as _rate/_increase/_delta; x* names also available.")

case "2", "y", "Y":
repointParserFunctions("delta", "ydelta")
repointParserFunctions("increase", "yincrease")
repointParserFunctions("rate", "yrate")
repointFunction("delta", "ydelta")
repointFunction("increase", "yincrease")
repointFunction("rate", "yrate")
fmt.Println("Successfully replaced rate/increase/delta with yrate/yincrease/ydelta (and left the y* names available as well).")
replaceStandardRateFuncs("y")
fmt.Println("Successfully replaced rate/increase/delta with yrate/yincrease/ydelta; originals available as _rate/_increase/_delta; y* and x* names also available.")
}
}

// repointParserFunctions makes the parser entry for name resolve to the
// entry currently registered under newName (e.g. "rate" -> "xrate").
// It leaves the newName entry in place.
func repointParserFunctions(name, newName string) {
parser.Functions[name] = parser.Functions[newName]
// replaceStandardRateFuncs preserves upstream delta/increase/rate as
// _delta/_increase/_rate and repoints the standard names at the x* or y* family
// (per replacementPrefix).
func replaceStandardRateFuncs(replacementPrefix string) {
for _, name := range []string{"delta", "increase", "rate"} {
setParserFunctionFrom("_"+name, name)
setFunctionCallFrom("_"+name, name)
replacement := replacementPrefix + name
setParserFunctionFrom(name, replacement)
setFunctionCallFrom(name, replacement)
}
}

// setParserFunctionFrom registers targetName as a copy of sourceName's parser
// metadata, with Name set to targetName.
func setParserFunctionFrom(targetName, sourceName string) {
result := *parser.Functions[sourceName]
result.Name = targetName
parser.Functions[targetName] = &result
}

// repointFunction makes the FunctionCalls entry for name dispatch to the
// implementation currently registered under newName. The newName entry
// is left in place.
func repointFunction(name, newName string) {
FunctionCalls[name] = FunctionCalls[newName]
// setFunctionCallFrom makes targetName dispatch to sourceName's implementation.
func setFunctionCallFrom(targetName, sourceName string) {
FunctionCalls[targetName] = FunctionCalls[sourceName]
}

type vectorByValueHeap Vector
Expand Down
36 changes: 36 additions & 0 deletions promql/replace_rate_funcs_test.go
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
package promql

import (
"os"
"os/exec"
"reflect"
"testing"

"github.com/stretchr/testify/require"

"github.com/prometheus/prometheus/promql/parser"
)

func TestReplaceRateFuncs2(t *testing.T) {
if os.Getenv("PROMQL_TEST_REPLACE_RATE_FUNCS") != "1" {
cmd := exec.Command(os.Args[0], "-test.run=^TestReplaceRateFuncs2$")
cmd.Env = append(os.Environ(),
"REPLACE_RATE_FUNCS=2",
"PROMQL_TEST_REPLACE_RATE_FUNCS=1",
)
out, err := cmd.CombinedOutput()
require.NoError(t, err, "subprocess failed:\n%s", out)
return
}

require.NotNil(t, parser.Functions["rate"])
require.NotNil(t, parser.Functions["yrate"])
require.NotNil(t, parser.Functions["_rate"])
require.NotNil(t, parser.Functions["xrate"])
require.Equal(t, "rate", parser.Functions["rate"].Name)
require.Equal(t, "yrate", parser.Functions["yrate"].Name)
require.Equal(t, "_rate", parser.Functions["_rate"].Name)
require.Equal(t, reflect.ValueOf(FunctionCalls["rate"]).Pointer(), reflect.ValueOf(FunctionCalls["yrate"]).Pointer())
require.NotEqual(t, reflect.ValueOf(FunctionCalls["_rate"]).Pointer(), reflect.ValueOf(FunctionCalls["rate"]).Pointer())
require.NotEqual(t, reflect.ValueOf(FunctionCalls["rate"]).Pointer(), reflect.ValueOf(FunctionCalls["xrate"]).Pointer())
}
Loading