2023-04-01 06:25:04 +00:00
|
|
|
package graphite
|
|
|
|
|
|
|
|
import (
|
|
|
|
// embed functions.json file
|
|
|
|
_ "embed"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
|
2023-06-20 05:31:57 +00:00
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httputils"
|
2023-04-01 06:25:04 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// FunctionsHandler implements /functions handler.
|
|
|
|
//
|
|
|
|
// See https://graphite.readthedocs.io/en/latest/functions.html#function-api
|
2023-09-01 07:34:16 +00:00
|
|
|
func FunctionsHandler(w http.ResponseWriter, r *http.Request) error {
|
2023-06-20 05:31:57 +00:00
|
|
|
grouped := httputils.GetBool(r, "grouped")
|
2023-04-01 06:25:04 +00:00
|
|
|
group := r.FormValue("group")
|
2024-07-09 22:14:15 +00:00
|
|
|
result := make(map[string]any)
|
2023-04-01 06:25:04 +00:00
|
|
|
for funcName, fi := range funcs {
|
|
|
|
if group != "" && fi.Group != group {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if grouped {
|
|
|
|
v := result[fi.Group]
|
|
|
|
if v == nil {
|
|
|
|
v = make(map[string]*funcInfo)
|
|
|
|
result[fi.Group] = v
|
|
|
|
}
|
|
|
|
m := v.(map[string]*funcInfo)
|
|
|
|
m[funcName] = fi
|
|
|
|
} else {
|
|
|
|
result[funcName] = fi
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return writeJSON(result, w, r)
|
|
|
|
}
|
|
|
|
|
|
|
|
// FunctionDetailsHandler implements /functions/<func_name> handler.
|
|
|
|
//
|
|
|
|
// See https://graphite.readthedocs.io/en/latest/functions.html#function-api
|
2023-09-01 07:34:16 +00:00
|
|
|
func FunctionDetailsHandler(funcName string, w http.ResponseWriter, r *http.Request) error {
|
2023-04-01 06:25:04 +00:00
|
|
|
result := funcs[funcName]
|
|
|
|
if result == nil {
|
|
|
|
return fmt.Errorf("cannot find function %q", funcName)
|
|
|
|
}
|
|
|
|
return writeJSON(result, w, r)
|
|
|
|
}
|
|
|
|
|
2024-07-09 22:14:15 +00:00
|
|
|
func writeJSON(result any, w http.ResponseWriter, r *http.Request) error {
|
2023-04-01 06:25:04 +00:00
|
|
|
data, err := json.Marshal(result)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("cannot marshal response to JSON: %w", err)
|
|
|
|
}
|
|
|
|
jsonp := r.FormValue("jsonp")
|
|
|
|
contentType := getContentType(jsonp)
|
|
|
|
w.Header().Set("Content-Type", contentType)
|
|
|
|
if jsonp != "" {
|
|
|
|
fmt.Fprintf(w, "%s(", jsonp)
|
|
|
|
}
|
|
|
|
w.Write(data)
|
|
|
|
if jsonp != "" {
|
|
|
|
fmt.Fprintf(w, ")")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//go:embed functions.json
|
|
|
|
var funcsJSON []byte
|
|
|
|
|
|
|
|
type funcInfo struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
Function string `json:"function"`
|
|
|
|
Description string `json:"description"`
|
|
|
|
Module string `json:"module"`
|
|
|
|
Group string `json:"group"`
|
|
|
|
Params json.RawMessage `json:"params"`
|
|
|
|
}
|
|
|
|
|
|
|
|
var funcs = func() map[string]*funcInfo {
|
|
|
|
var m map[string]*funcInfo
|
|
|
|
if err := json.Unmarshal(funcsJSON, &m); err != nil {
|
|
|
|
// Do not use logger.Panicf, since it isn't ready yet.
|
2023-10-25 19:24:01 +00:00
|
|
|
panic(fmt.Errorf("cannot parse funcsJSON: %w", err))
|
2023-04-01 06:25:04 +00:00
|
|
|
}
|
|
|
|
return m
|
|
|
|
}()
|