diff --git a/app/victoria-logs/Makefile b/app/victoria-logs/Makefile deleted file mode 100644 index 2af385130f..0000000000 --- a/app/victoria-logs/Makefile +++ /dev/null @@ -1,113 +0,0 @@ -# All these commands must run from repository root. - -victoria-logs: - APP_NAME=victoria-logs $(MAKE) app-local - -victoria-logs-race: - APP_NAME=victoria-logs RACE=-race $(MAKE) app-local - -victoria-logs-prod: - APP_NAME=victoria-logs $(MAKE) app-via-docker - -victoria-logs-pure-prod: - APP_NAME=victoria-logs $(MAKE) app-via-docker-pure - -victoria-logs-linux-amd64-prod: - APP_NAME=victoria-logs $(MAKE) app-via-docker-linux-amd64 - -victoria-logs-linux-arm-prod: - APP_NAME=victoria-logs $(MAKE) app-via-docker-linux-arm - -victoria-logs-linux-arm64-prod: - APP_NAME=victoria-logs $(MAKE) app-via-docker-linux-arm64 - -victoria-logs-linux-ppc64le-prod: - APP_NAME=victoria-logs $(MAKE) app-via-docker-linux-ppc64le - -victoria-logs-linux-386-prod: - APP_NAME=victoria-logs $(MAKE) app-via-docker-linux-386 - -victoria-logs-darwin-amd64-prod: - APP_NAME=victoria-logs $(MAKE) app-via-docker-darwin-amd64 - -victoria-logs-darwin-arm64-prod: - APP_NAME=victoria-logs $(MAKE) app-via-docker-darwin-arm64 - -victoria-logs-freebsd-amd64-prod: - APP_NAME=victoria-logs $(MAKE) app-via-docker-freebsd-amd64 - -victoria-logs-openbsd-amd64-prod: - APP_NAME=victoria-logs $(MAKE) app-via-docker-openbsd-amd64 - -victoria-logs-windows-amd64-prod: - APP_NAME=victoria-logs $(MAKE) app-via-docker-windows-amd64 - -package-victoria-logs: - APP_NAME=victoria-logs $(MAKE) package-via-docker - -package-victoria-logs-pure: - APP_NAME=victoria-logs $(MAKE) package-via-docker-pure - -package-victoria-logs-amd64: - APP_NAME=victoria-logs $(MAKE) package-via-docker-amd64 - -package-victoria-logs-arm: - APP_NAME=victoria-logs $(MAKE) package-via-docker-arm - -package-victoria-logs-arm64: - APP_NAME=victoria-logs $(MAKE) package-via-docker-arm64 - -package-victoria-logs-ppc64le: - APP_NAME=victoria-logs $(MAKE) package-via-docker-ppc64le - -package-victoria-logs-386: - APP_NAME=victoria-logs $(MAKE) package-via-docker-386 - -publish-victoria-logs: - APP_NAME=victoria-logs $(MAKE) publish-via-docker - -victoria-logs-linux-amd64: - APP_NAME=victoria-logs CGO_ENABLED=1 GOOS=linux GOARCH=amd64 $(MAKE) app-local-goos-goarch - -victoria-logs-linux-arm: - APP_NAME=victoria-logs CGO_ENABLED=0 GOOS=linux GOARCH=arm $(MAKE) app-local-goos-goarch - -victoria-logs-linux-arm64: - APP_NAME=victoria-logs CGO_ENABLED=0 GOOS=linux GOARCH=arm64 $(MAKE) app-local-goos-goarch - -victoria-logs-linux-ppc64le: - APP_NAME=victoria-logs CGO_ENABLED=0 GOOS=linux GOARCH=ppc64le $(MAKE) app-local-goos-goarch - -victoria-logs-linux-s390x: - APP_NAME=victoria-logs CGO_ENABLED=0 GOOS=linux GOARCH=s390x $(MAKE) app-local-goos-goarch - -victoria-logs-linux-loong64: - APP_NAME=victoria-logs CGO_ENABLED=0 GOOS=linux GOARCH=loong64 $(MAKE) app-local-goos-goarch - -victoria-logs-linux-386: - APP_NAME=victoria-logs CGO_ENABLED=0 GOOS=linux GOARCH=386 $(MAKE) app-local-goos-goarch - -victoria-logs-darwin-amd64: - APP_NAME=victoria-logs CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 $(MAKE) app-local-goos-goarch - -victoria-logs-darwin-arm64: - APP_NAME=victoria-logs CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 $(MAKE) app-local-goos-goarch - -victoria-logs-freebsd-amd64: - APP_NAME=victoria-logs CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 $(MAKE) app-local-goos-goarch - -victoria-logs-openbsd-amd64: - APP_NAME=victoria-logs CGO_ENABLED=0 GOOS=openbsd GOARCH=amd64 $(MAKE) app-local-goos-goarch - -victoria-logs-windows-amd64: - GOARCH=amd64 APP_NAME=victoria-logs $(MAKE) app-local-windows-goarch - -victoria-logs-pure: - APP_NAME=victoria-logs $(MAKE) app-local-pure - -run-victoria-logs: - mkdir -p victoria-logs-data - DOCKER_OPTS='-v $(shell pwd)/victoria-logs-data:/victoria-logs-data' \ - APP_NAME=victoria-logs \ - ARGS='' \ - $(MAKE) run-via-docker diff --git a/app/victoria-logs/README.md b/app/victoria-logs/README.md new file mode 100644 index 0000000000..5456a353a1 --- /dev/null +++ b/app/victoria-logs/README.md @@ -0,0 +1 @@ +VictoriaLogs source code has been moved to [github.com/VictoriaMetrics/VictoriaLogs](https://github.com/VictoriaMetrics/VictoriaLogs/). diff --git a/app/victoria-logs/deployment/Dockerfile b/app/victoria-logs/deployment/Dockerfile deleted file mode 100644 index f1de0c39ba..0000000000 --- a/app/victoria-logs/deployment/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -ARG base_image=non-existing -FROM $base_image - -EXPOSE 9428 - -ENTRYPOINT ["/victoria-logs-prod"] -ARG src_binary=non-existing -COPY $src_binary ./victoria-logs-prod diff --git a/app/victoria-logs/main.go b/app/victoria-logs/main.go deleted file mode 100644 index 0cedf6207a..0000000000 --- a/app/victoria-logs/main.go +++ /dev/null @@ -1,113 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "net/http" - "os" - "time" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert" - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlselect" - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlstorage" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/buildinfo" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/envflag" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/fs" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/procutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/pushmetrics" -) - -var ( - httpListenAddrs = flagutil.NewArrayString("httpListenAddr", "TCP address to listen for incoming http requests. See also -httpListenAddr.useProxyProtocol") - useProxyProtocol = flagutil.NewArrayBool("httpListenAddr.useProxyProtocol", "Whether to use proxy protocol for connections accepted at the given -httpListenAddr . "+ - "See https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt . "+ - "With enabled proxy protocol http server cannot serve regular /metrics endpoint. Use -pushmetrics.url for metrics pushing") -) - -func main() { - // Write flags and help message to stdout, since it is easier to grep or pipe. - flag.CommandLine.SetOutput(os.Stdout) - flag.Usage = usage - envflag.Parse() - buildinfo.Init() - logger.Init() - - listenAddrs := *httpListenAddrs - if len(listenAddrs) == 0 { - listenAddrs = []string{":9428"} - } - logger.Infof("starting VictoriaLogs at %q...", listenAddrs) - startTime := time.Now() - - vlstorage.Init() - vlselect.Init() - - insertutil.SetLogRowsStorage(&vlstorage.Storage{}) - vlinsert.Init() - - go httpserver.Serve(listenAddrs, requestHandler, httpserver.ServeOptions{ - UseProxyProtocol: useProxyProtocol, - }) - logger.Infof("started VictoriaLogs in %.3f seconds; see https://docs.victoriametrics.com/victorialogs/", time.Since(startTime).Seconds()) - - pushmetrics.Init() - sig := procutil.WaitForSigterm() - logger.Infof("received signal %s", sig) - pushmetrics.Stop() - - logger.Infof("gracefully shutting down webservice at %q", listenAddrs) - startTime = time.Now() - if err := httpserver.Stop(listenAddrs); err != nil { - logger.Fatalf("cannot stop the webservice: %s", err) - } - logger.Infof("successfully shut down the webservice in %.3f seconds", time.Since(startTime).Seconds()) - - vlinsert.Stop() - vlselect.Stop() - vlstorage.Stop() - - fs.MustStopDirRemover() - - logger.Infof("the VictoriaLogs has been stopped in %.3f seconds", time.Since(startTime).Seconds()) -} - -func requestHandler(w http.ResponseWriter, r *http.Request) bool { - if r.URL.Path == "/" { - if r.Method != http.MethodGet { - return false - } - w.Header().Add("Content-Type", "text/html; charset=utf-8") - fmt.Fprintf(w, "

Single-node VictoriaLogs


") - fmt.Fprintf(w, "See docs at https://docs.victoriametrics.com/victorialogs/
") - fmt.Fprintf(w, "Useful endpoints:
") - httpserver.WriteAPIHelp(w, [][2]string{ - {"select/vmui", "Web UI for VictoriaLogs"}, - {"metrics", "available service metrics"}, - {"flags", "command-line flags"}, - }) - return true - } - if vlinsert.RequestHandler(w, r) { - return true - } - if vlselect.RequestHandler(w, r) { - return true - } - if vlstorage.RequestHandler(w, r) { - return true - } - return false -} - -func usage() { - const s = ` -victoria-logs is a log management and analytics service. - -See the docs at https://docs.victoriametrics.com/victorialogs/ -` - flagutil.Usage(s) -} diff --git a/app/victoria-logs/multiarch/Dockerfile b/app/victoria-logs/multiarch/Dockerfile deleted file mode 100644 index f27828d81d..0000000000 --- a/app/victoria-logs/multiarch/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -# See https://medium.com/on-docker/use-multi-stage-builds-to-inject-ca-certs-ad1e8f01de1b -ARG certs_image=non-existing -ARG root_image=non-existing -FROM $certs_image AS certs -RUN apk update && apk upgrade && apk --update --no-cache add ca-certificates - -FROM $root_image -COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt -EXPOSE 9428 -ENTRYPOINT ["/victoria-logs-prod"] -ARG TARGETARCH -COPY victoria-logs-linux-${TARGETARCH}-prod ./victoria-logs-prod diff --git a/app/vlagent/Makefile b/app/vlagent/Makefile deleted file mode 100644 index 9dc0af315a..0000000000 --- a/app/vlagent/Makefile +++ /dev/null @@ -1,106 +0,0 @@ -# All these commands must run from repository root. - -vlagent: - APP_NAME=vlagent $(MAKE) app-local - -vlagent-race: - APP_NAME=vlagent RACE=-race $(MAKE) app-local - -vlagent-prod: - APP_NAME=vlagent $(MAKE) app-via-docker - -vlagent-pure-prod: - APP_NAME=vlagent $(MAKE) app-via-docker-pure - -vlagent-linux-amd64-prod: - APP_NAME=vlagent $(MAKE) app-via-docker-linux-amd64 - -vlagent-linux-arm-prod: - APP_NAME=vlagent $(MAKE) app-via-docker-linux-arm - -vlagent-linux-arm64-prod: - APP_NAME=vlagent $(MAKE) app-via-docker-linux-arm64 - -vlagent-linux-ppc64le-prod: - APP_NAME=vlagent $(MAKE) app-via-docker-linux-ppc64le - -vlagent-linux-386-prod: - APP_NAME=vlagent $(MAKE) app-via-docker-linux-386 - -vlagent-darwin-amd64-prod: - APP_NAME=vlagent $(MAKE) app-via-docker-darwin-amd64 - -vlagent-darwin-arm64-prod: - APP_NAME=vlagent $(MAKE) app-via-docker-darwin-arm64 - -vlagent-freebsd-amd64-prod: - APP_NAME=vlagent $(MAKE) app-via-docker-freebsd-amd64 - -vlagent-openbsd-amd64-prod: - APP_NAME=vlagent $(MAKE) app-via-docker-openbsd-amd64 - -vlagent-windows-amd64-prod: - APP_NAME=vlagent $(MAKE) app-via-docker-windows-amd64 - -package-vlagent: - APP_NAME=vlagent $(MAKE) package-via-docker - -package-vlagent-pure: - APP_NAME=vlagent $(MAKE) package-via-docker-pure - -package-vlagent-amd64: - APP_NAME=vlagent $(MAKE) package-via-docker-amd64 - -package-vlagent-arm: - APP_NAME=vlagent $(MAKE) package-via-docker-arm - -package-vlagent-arm64: - APP_NAME=vlagent $(MAKE) package-via-docker-arm64 - -package-vlagent-ppc64le: - APP_NAME=vlagent $(MAKE) package-via-docker-ppc64le - -package-vlagent-386: - APP_NAME=vlagent $(MAKE) package-via-docker-386 - -publish-vlagent: - APP_NAME=vlagent $(MAKE) publish-via-docker - -vlagent-linux-amd64: - APP_NAME=vlagent CGO_ENABLED=1 GOOS=linux GOARCH=amd64 $(MAKE) app-local-goos-goarch - -vlagent-linux-arm: - APP_NAME=vlagent CGO_ENABLED=0 GOOS=linux GOARCH=arm $(MAKE) app-local-goos-goarch - -vlagent-linux-arm64: - APP_NAME=vlagent CGO_ENABLED=0 GOOS=linux GOARCH=arm64 $(MAKE) app-local-goos-goarch - -vlagent-linux-ppc64le: - APP_NAME=vlagent CGO_ENABLED=0 GOOS=linux GOARCH=ppc64le $(MAKE) app-local-goos-goarch - -vlagent-linux-s390x: - APP_NAME=vlagent CGO_ENABLED=0 GOOS=linux GOARCH=s390x $(MAKE) app-local-goos-goarch - -vlagent-linux-loong64: - APP_NAME=vlagent CGO_ENABLED=0 GOOS=linux GOARCH=loong64 $(MAKE) app-local-goos-goarch - -vlagent-linux-386: - APP_NAME=vlagent CGO_ENABLED=0 GOOS=linux GOARCH=386 $(MAKE) app-local-goos-goarch - -vlagent-darwin-amd64: - APP_NAME=vlagent CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 $(MAKE) app-local-goos-goarch - -vlagent-darwin-arm64: - APP_NAME=vlagent CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 $(MAKE) app-local-goos-goarch - -vlagent-freebsd-amd64: - APP_NAME=vlagent CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 $(MAKE) app-local-goos-goarch - -vlagent-openbsd-amd64: - APP_NAME=vlagent CGO_ENABLED=0 GOOS=openbsd GOARCH=amd64 $(MAKE) app-local-goos-goarch - -vlagent-windows-amd64: - GOARCH=amd64 APP_NAME=vlagent $(MAKE) app-local-windows-goarch - -vlagent-pure: - APP_NAME=vlagent $(MAKE) app-local-pure diff --git a/app/vlagent/README.md b/app/vlagent/README.md index 451e289bd4..5456a353a1 100644 --- a/app/vlagent/README.md +++ b/app/vlagent/README.md @@ -1,3 +1 @@ -See vlagent docs [here](https://docs.victoriametrics.com/victorialogs/vlagent/). - -vlagent docs can be edited at [docs/vlagent.md](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/docs/victorialogs/vlagent.md). +VictoriaLogs source code has been moved to [github.com/VictoriaMetrics/VictoriaLogs](https://github.com/VictoriaMetrics/VictoriaLogs/). diff --git a/app/vlagent/deployment/Dockerfile b/app/vlagent/deployment/Dockerfile deleted file mode 100644 index 0a81dc63a9..0000000000 --- a/app/vlagent/deployment/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -ARG base_image=non-existing -FROM $base_image - -EXPOSE 9429 - -ENTRYPOINT ["/vlagent-prod"] -ARG src_binary=non-existing -COPY $src_binary ./vlagent-prod diff --git a/app/vlagent/main.go b/app/vlagent/main.go deleted file mode 100644 index 14eae2a75c..0000000000 --- a/app/vlagent/main.go +++ /dev/null @@ -1,97 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "net/http" - "os" - "time" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlagent/remotewrite" - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert" - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/buildinfo" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/envflag" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/procutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/pushmetrics" -) - -var ( - httpListenAddrs = flagutil.NewArrayString("httpListenAddr", "TCP address to listen for incoming http requests. "+ - "Set this flag to empty value in order to disable listening on any port. This mode may be useful for running multiple vlagent instances on the same server. "+ - "Note that /targets and /metrics pages aren't available if -httpListenAddr=''. See also -tls and -httpListenAddr.useProxyProtocol") - useProxyProtocol = flagutil.NewArrayBool("httpListenAddr.useProxyProtocol", "Whether to use proxy protocol for connections accepted at the corresponding -httpListenAddr . "+ - "See https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt . "+ - "With enabled proxy protocol http server cannot serve regular /metrics endpoint. Use -pushmetrics.url for metrics pushing") -) - -func main() { - // Write flags and help message to stdout, since it is easier to grep or pipe. - flag.CommandLine.SetOutput(os.Stdout) - flag.Usage = usage - envflag.Parse() - buildinfo.Init() - remotewrite.InitSecretFlags() - logger.Init() - - remotewrite.Init() - vlinsert.Init() - - insertutil.SetLogRowsStorage(&remotewrite.Storage{}) - listenAddrs := *httpListenAddrs - if len(listenAddrs) == 0 { - listenAddrs = []string{":9429"} - } - logger.Infof("starting vlagent at %q...", listenAddrs) - startTime := time.Now() - go httpserver.Serve(listenAddrs, requestHandler, httpserver.ServeOptions{ - UseProxyProtocol: useProxyProtocol, - }) - logger.Infof("started vlagent in %.3f seconds", time.Since(startTime).Seconds()) - - pushmetrics.Init() - sig := procutil.WaitForSigterm() - logger.Infof("received signal %s", sig) - pushmetrics.Stop() - - startTime = time.Now() - logger.Infof("gracefully shutting down webservice at %q", listenAddrs) - if err := httpserver.Stop(listenAddrs); err != nil { - logger.Fatalf("cannot stop the webservice: %s", err) - } - vlinsert.Stop() - remotewrite.Stop() - logger.Infof("successfully shut down the webservice in %.3f seconds", time.Since(startTime).Seconds()) - logger.Infof("successfully stopped vlagent in %.3f seconds", time.Since(startTime).Seconds()) -} - -// RequestHandler handles insert requests for VictoriaLogs -func requestHandler(w http.ResponseWriter, r *http.Request) bool { - if r.URL.Path == "/" { - if r.Method != http.MethodGet { - return false - } - w.Header().Add("Content-Type", "text/html; charset=utf-8") - fmt.Fprintf(w, "

vlagent

") - fmt.Fprintf(w, "See docs at https://docs.victoriametrics.com/victorialogs/vlagent/
") - fmt.Fprintf(w, "Useful endpoints:
") - httpserver.WriteAPIHelp(w, [][2]string{ - {"metrics", "available service metrics"}, - {"flags", "command-line flags"}, - }) - return true - } - return vlinsert.RequestHandler(w, r) -} - -func usage() { - const s = ` -vlagent collects logs via popular data ingestion protocols and routes it to VictoriaLogs. - -See the docs at https://docs.victoriametrics.com/victorialogs/vlagent/ . -` - flagutil.Usage(s) -} diff --git a/app/vlagent/multiarch/Dockerfile b/app/vlagent/multiarch/Dockerfile deleted file mode 100644 index 289a0ab018..0000000000 --- a/app/vlagent/multiarch/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -# See https://medium.com/on-docker/use-multi-stage-builds-to-inject-ca-certs-ad1e8f01de1b -ARG certs_image=non-existing -ARG root_image=non-existing -FROM $certs_image AS certs -RUN apk update && apk upgrade && apk --update --no-cache add ca-certificates - -FROM $root_image -COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt -EXPOSE 9429 -ENTRYPOINT ["/vlagent-prod"] -ARG TARGETARCH -COPY vlagent-linux-${TARGETARCH}-prod ./vlagent-prod diff --git a/app/vlagent/remotewrite/client.go b/app/vlagent/remotewrite/client.go deleted file mode 100644 index 4cbbde9d70..0000000000 --- a/app/vlagent/remotewrite/client.go +++ /dev/null @@ -1,462 +0,0 @@ -package remotewrite - -import ( - "bytes" - "errors" - "fmt" - "io" - "net/http" - "net/url" - "strconv" - "strings" - "sync" - "time" - - "github.com/VictoriaMetrics/metrics" - - "github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httputil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/persistentqueue" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/ratelimiter" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/timerpool" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/timeutil" -) - -var ( - rateLimit = flagutil.NewArrayInt("remoteWrite.rateLimit", 0, "Optional rate limit in bytes per second for data sent to the corresponding -remoteWrite.url. "+ - "By default, the rate limit is disabled. It can be useful for limiting load on remote storage when big amounts of buffered data ") - sendTimeout = flagutil.NewArrayDuration("remoteWrite.sendTimeout", time.Minute, "Timeout for sending a single block of data to the corresponding -remoteWrite.url") - retryMinInterval = flagutil.NewArrayDuration("remoteWrite.retryMinInterval", time.Second, "The minimum delay between retry attempts to send a block of data to the corresponding -remoteWrite.url. Every next retry attempt will double the delay to prevent hammering of remote database. See also -remoteWrite.retryMaxTime") - retryMaxTime = flagutil.NewArrayDuration("remoteWrite.retryMaxTime", time.Minute, "The max time spent on retry attempts to send a block of data to the corresponding -remoteWrite.url. Change this value if it is expected for -remoteWrite.url to be unreachable for more than -remoteWrite.retryMaxTime. See also -remoteWrite.retryMinInterval") - proxyURL = flagutil.NewArrayString("remoteWrite.proxyURL", "Optional proxy URL for writing data to the corresponding -remoteWrite.url. "+ - "Supported proxies: http, https, socks5. Example: -remoteWrite.proxyURL=socks5://proxy:1234") - - tlsHandshakeTimeout = flagutil.NewArrayDuration("remoteWrite.tlsHandshakeTimeout", 20*time.Second, "The timeout for establishing tls connections to the corresponding -remoteWrite.url") - tlsInsecureSkipVerify = flagutil.NewArrayBool("remoteWrite.tlsInsecureSkipVerify", "Whether to skip tls verification when connecting to the corresponding -remoteWrite.url") - tlsCertFile = flagutil.NewArrayString("remoteWrite.tlsCertFile", "Optional path to client-side TLS certificate file to use when connecting "+ - "to the corresponding -remoteWrite.url") - tlsKeyFile = flagutil.NewArrayString("remoteWrite.tlsKeyFile", "Optional path to client-side TLS certificate key to use when connecting to the corresponding -remoteWrite.url") - tlsCAFile = flagutil.NewArrayString("remoteWrite.tlsCAFile", "Optional path to TLS CA file to use for verifying connections to the corresponding -remoteWrite.url. "+ - "By default, system CA is used") - tlsServerName = flagutil.NewArrayString("remoteWrite.tlsServerName", "Optional TLS server name to use for connections to the corresponding -remoteWrite.url. "+ - "By default, the server name from -remoteWrite.url is used") - - headers = flagutil.NewArrayString("remoteWrite.headers", "Optional HTTP headers to send with each request to the corresponding -remoteWrite.url. "+ - "For example, -remoteWrite.headers='My-Auth:foobar' would send 'My-Auth: foobar' HTTP header with every request to the corresponding -remoteWrite.url. "+ - "Multiple headers must be delimited by '^^': -remoteWrite.headers='header1:value1^^header2:value2'") - - basicAuthUsername = flagutil.NewArrayString("remoteWrite.basicAuth.username", "Optional basic auth username to use for the corresponding -remoteWrite.url") - basicAuthPassword = flagutil.NewArrayString("remoteWrite.basicAuth.password", "Optional basic auth password to use for the corresponding -remoteWrite.url") - basicAuthPasswordFile = flagutil.NewArrayString("remoteWrite.basicAuth.passwordFile", "Optional path to basic auth password to use for the corresponding -remoteWrite.url. "+ - "The file is re-read every second") - bearerToken = flagutil.NewArrayString("remoteWrite.bearerToken", "Optional bearer auth token to use for the corresponding -remoteWrite.url") - bearerTokenFile = flagutil.NewArrayString("remoteWrite.bearerTokenFile", "Optional path to bearer token file to use for the corresponding -remoteWrite.url. "+ - "The token is re-read from the file every second") - - oauth2ClientID = flagutil.NewArrayString("remoteWrite.oauth2.clientID", "Optional OAuth2 clientID to use for the corresponding -remoteWrite.url") - oauth2ClientSecret = flagutil.NewArrayString("remoteWrite.oauth2.clientSecret", "Optional OAuth2 clientSecret to use for the corresponding -remoteWrite.url") - oauth2ClientSecretFile = flagutil.NewArrayString("remoteWrite.oauth2.clientSecretFile", "Optional OAuth2 clientSecretFile to use for the corresponding -remoteWrite.url") - oauth2EndpointParams = flagutil.NewArrayString("remoteWrite.oauth2.endpointParams", "Optional OAuth2 endpoint parameters to use for the corresponding -remoteWrite.url . "+ - `The endpoint parameters must be set in JSON format: {"param1":"value1",...,"paramN":"valueN"}`) - oauth2TokenURL = flagutil.NewArrayString("remoteWrite.oauth2.tokenUrl", "Optional OAuth2 tokenURL to use for the corresponding -remoteWrite.url") - oauth2Scopes = flagutil.NewArrayString("remoteWrite.oauth2.scopes", "Optional OAuth2 scopes to use for the corresponding -remoteWrite.url. Scopes must be delimited by ';'") -) - -type client struct { - sanitizedURL string - remoteWriteURL string - - fq *persistentqueue.FastQueue - hc *http.Client - - retryMinInterval time.Duration - retryMaxTime time.Duration - - sendBlock func(block []byte) bool - authCfg *promauth.Config - - rl *ratelimiter.RateLimiter - - bytesSent *metrics.Counter - blocksSent *metrics.Counter - requestDuration *metrics.Histogram - requestsOKCount *metrics.Counter - errorsCount *metrics.Counter - packetsDropped *metrics.Counter - rateLimit *metrics.Gauge - retriesCount *metrics.Counter - sendDuration *metrics.FloatCounter - - wg sync.WaitGroup - stopCh chan struct{} -} - -func newHTTPClient(argIdx int, remoteWriteURL, sanitizedURL string, fq *persistentqueue.FastQueue, concurrency int) *client { - authCfg, err := getAuthConfig(argIdx) - if err != nil { - logger.Fatalf("cannot initialize auth config for -remoteWrite.url=%q: %s", remoteWriteURL, err) - } - - tr := httputil.NewTransport(false, "vlagent_remotewrite") - tr.TLSHandshakeTimeout = tlsHandshakeTimeout.GetOptionalArg(argIdx) - tr.MaxConnsPerHost = 2 * concurrency - tr.MaxIdleConnsPerHost = 2 * concurrency - tr.IdleConnTimeout = time.Minute - tr.WriteBufferSize = 64 * 1024 - - pURL := proxyURL.GetOptionalArg(argIdx) - if len(pURL) > 0 { - if !strings.Contains(pURL, "://") { - logger.Fatalf("cannot parse -remoteWrite.proxyURL=%q: it must start with `http://`, `https://` or `socks5://`", pURL) - } - pu, err := url.Parse(pURL) - if err != nil { - logger.Fatalf("cannot parse -remoteWrite.proxyURL=%q: %s", pURL, err) - } - tr.Proxy = http.ProxyURL(pu) - } - hc := &http.Client{ - Transport: authCfg.NewRoundTripper(tr), - Timeout: sendTimeout.GetOptionalArg(argIdx), - } - c := &client{ - sanitizedURL: sanitizedURL, - remoteWriteURL: remoteWriteURL, - authCfg: authCfg, - fq: fq, - hc: hc, - retryMinInterval: retryMinInterval.GetOptionalArg(argIdx), - retryMaxTime: retryMaxTime.GetOptionalArg(argIdx), - stopCh: make(chan struct{}), - } - c.sendBlock = c.sendBlockHTTP - return c -} - -func (c *client) init(argIdx, concurrency int, sanitizedURL string) { - limitReached := metrics.GetOrCreateCounter(fmt.Sprintf(`vlagent_remotewrite_rate_limit_reached_total{url=%q}`, c.sanitizedURL)) - if bytesPerSec := rateLimit.GetOptionalArg(argIdx); bytesPerSec > 0 { - logger.Infof("applying %d bytes per second rate limit for -remoteWrite.url=%q", bytesPerSec, sanitizedURL) - c.rl = ratelimiter.New(int64(bytesPerSec), limitReached, c.stopCh) - } - c.bytesSent = metrics.GetOrCreateCounter(fmt.Sprintf(`vlagent_remotewrite_bytes_sent_total{url=%q}`, c.sanitizedURL)) - c.blocksSent = metrics.GetOrCreateCounter(fmt.Sprintf(`vlagent_remotewrite_blocks_sent_total{url=%q}`, c.sanitizedURL)) - c.rateLimit = metrics.GetOrCreateGauge(fmt.Sprintf(`vlagent_remotewrite_rate_limit{url=%q}`, c.sanitizedURL), func() float64 { - return float64(rateLimit.GetOptionalArg(argIdx)) - }) - c.requestDuration = metrics.GetOrCreateHistogram(fmt.Sprintf(`vlagent_remotewrite_duration_seconds{url=%q}`, c.sanitizedURL)) - c.requestsOKCount = metrics.GetOrCreateCounter(fmt.Sprintf(`vlagent_remotewrite_requests_total{url=%q, status_code="2XX"}`, c.sanitizedURL)) - c.errorsCount = metrics.GetOrCreateCounter(fmt.Sprintf(`vlagent_remotewrite_errors_total{url=%q}`, c.sanitizedURL)) - c.packetsDropped = metrics.GetOrCreateCounter(fmt.Sprintf(`vlagent_remotewrite_packets_dropped_total{url=%q}`, c.sanitizedURL)) - c.retriesCount = metrics.GetOrCreateCounter(fmt.Sprintf(`vlagent_remotewrite_retries_count_total{url=%q}`, c.sanitizedURL)) - c.sendDuration = metrics.GetOrCreateFloatCounter(fmt.Sprintf(`vlagent_remotewrite_send_duration_seconds_total{url=%q}`, c.sanitizedURL)) - metrics.GetOrCreateGauge(fmt.Sprintf(`vlagent_remotewrite_queues{url=%q}`, c.sanitizedURL), func() float64 { - return float64(*queues) - }) - for i := 0; i < concurrency; i++ { - c.wg.Add(1) - go func() { - defer c.wg.Done() - c.runWorker() - }() - } - logger.Infof("initialized client for -remoteWrite.url=%q", c.sanitizedURL) -} - -func (c *client) MustStop() { - close(c.stopCh) - c.wg.Wait() - logger.Infof("stopped client for -remoteWrite.url=%q", c.sanitizedURL) -} - -func getAuthConfig(argIdx int) (*promauth.Config, error) { - headersValue := headers.GetOptionalArg(argIdx) - var hdrs []string - if headersValue != "" { - hdrs = strings.Split(headersValue, "^^") - } - username := basicAuthUsername.GetOptionalArg(argIdx) - password := basicAuthPassword.GetOptionalArg(argIdx) - passwordFile := basicAuthPasswordFile.GetOptionalArg(argIdx) - var basicAuthCfg *promauth.BasicAuthConfig - if username != "" || password != "" || passwordFile != "" { - basicAuthCfg = &promauth.BasicAuthConfig{ - Username: username, - Password: promauth.NewSecret(password), - PasswordFile: passwordFile, - } - } - - token := bearerToken.GetOptionalArg(argIdx) - tokenFile := bearerTokenFile.GetOptionalArg(argIdx) - - var oauth2Cfg *promauth.OAuth2Config - clientSecret := oauth2ClientSecret.GetOptionalArg(argIdx) - clientSecretFile := oauth2ClientSecretFile.GetOptionalArg(argIdx) - if clientSecretFile != "" || clientSecret != "" { - endpointParamsJSON := oauth2EndpointParams.GetOptionalArg(argIdx) - endpointParams, err := flagutil.ParseJSONMap(endpointParamsJSON) - if err != nil { - return nil, fmt.Errorf("cannot parse JSON for -remoteWrite.oauth2.endpointParams=%s: %w", endpointParamsJSON, err) - } - oauth2Cfg = &promauth.OAuth2Config{ - ClientID: oauth2ClientID.GetOptionalArg(argIdx), - ClientSecret: promauth.NewSecret(clientSecret), - ClientSecretFile: clientSecretFile, - EndpointParams: endpointParams, - TokenURL: oauth2TokenURL.GetOptionalArg(argIdx), - Scopes: strings.Split(oauth2Scopes.GetOptionalArg(argIdx), ";"), - } - } - - tlsCfg := &promauth.TLSConfig{ - CAFile: tlsCAFile.GetOptionalArg(argIdx), - CertFile: tlsCertFile.GetOptionalArg(argIdx), - KeyFile: tlsKeyFile.GetOptionalArg(argIdx), - ServerName: tlsServerName.GetOptionalArg(argIdx), - InsecureSkipVerify: tlsInsecureSkipVerify.GetOptionalArg(argIdx), - } - - opts := &promauth.Options{ - BasicAuth: basicAuthCfg, - BearerToken: token, - BearerTokenFile: tokenFile, - OAuth2: oauth2Cfg, - TLSConfig: tlsCfg, - Headers: hdrs, - } - authCfg, err := opts.NewConfig() - if err != nil { - return nil, fmt.Errorf("cannot populate auth config for remoteWrite idx: %d, err: %w", argIdx, err) - } - return authCfg, nil -} - -func (c *client) runWorker() { - var ok bool - var block []byte - ch := make(chan bool, 1) - for { - block, ok = c.fq.MustReadBlock(block[:0]) - if !ok { - return - } - if len(block) == 0 { - // skip empty data blocks from sending - continue - } - go func() { - startTime := time.Now() - ch <- c.sendBlock(block) - c.sendDuration.Add(time.Since(startTime).Seconds()) - }() - select { - case ok := <-ch: - if ok { - // The block has been sent successfully - continue - } - // Return unsent block to the queue. - c.fq.MustWriteBlockIgnoreDisabledPQ(block) - return - case <-c.stopCh: - // c must be stopped. Wait for a while in the hope the block will be sent. - graceDuration := 5 * time.Second - select { - case ok := <-ch: - if !ok { - // Return unsent block to the queue. - c.fq.MustWriteBlockIgnoreDisabledPQ(block) - } - case <-time.After(graceDuration): - // Return unsent block to the queue. - c.fq.MustWriteBlockIgnoreDisabledPQ(block) - } - return - } - } -} - -func (c *client) doRequest(url string, body []byte) (*http.Response, error) { - req, err := c.newRequest(url, body) - if err != nil { - return nil, err - } - resp, err := c.hc.Do(req) - if err == nil { - return resp, nil - } - if !errors.Is(err, io.EOF) && !errors.Is(err, io.ErrUnexpectedEOF) { - return nil, err - } - // It is likely connection became stale or timed out during the first request. - // Make another attempt in hope request will succeed. - // If not, the error should be handled by the caller as usual. - // This should help with https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4139 - req, err = c.newRequest(url, body) - if err != nil { - return nil, fmt.Errorf("second attempt: %w", err) - } - resp, err = c.hc.Do(req) - if err != nil { - return nil, fmt.Errorf("second attempt: %w", err) - } - return resp, nil -} - -func (c *client) newRequest(url string, body []byte) (*http.Request, error) { - reqBody := bytes.NewBuffer(body) - req, err := http.NewRequest(http.MethodPost, url, reqBody) - if err != nil { - logger.Panicf("BUG: unexpected error from http.NewRequest(%q): %s", url, err) - } - err = c.authCfg.SetHeaders(req, true) - if err != nil { - return nil, err - } - h := req.Header - h.Set("User-Agent", "vlagent") - h.Set("Content-Encoding", "zstd") - h.Set("Content-Type", "application/octet-stream") - - return req, nil -} - -// sendBlockHTTP sends the given block to c.remoteWriteURL. -// -// The function returns false only if c.stopCh is closed. -// Otherwise, it tries sending the block to remote storage indefinitely. -func (c *client) sendBlockHTTP(block []byte) bool { - c.rl.Register(len(block)) - maxRetryDuration := timeutil.AddJitterToDuration(c.retryMaxTime) - retryDuration := timeutil.AddJitterToDuration(c.retryMinInterval) - retriesCount := 0 - -again: - startTime := time.Now() - resp, err := c.doRequest(c.remoteWriteURL, block) - c.requestDuration.UpdateDuration(startTime) - if err != nil { - c.errorsCount.Inc() - retryDuration *= 2 - if retryDuration > maxRetryDuration { - retryDuration = maxRetryDuration - } - remoteWriteRetryLogger.Warnf("couldn't send a block with size %d bytes to %q: %s; re-sending the block in %.3f seconds", - len(block), c.sanitizedURL, err, retryDuration.Seconds()) - t := timerpool.Get(retryDuration) - select { - case <-c.stopCh: - timerpool.Put(t) - return false - case <-t.C: - timerpool.Put(t) - } - c.retriesCount.Inc() - goto again - } - - statusCode := resp.StatusCode - if statusCode/100 == 2 { - _ = resp.Body.Close() - c.requestsOKCount.Inc() - c.bytesSent.Add(len(block)) - c.blocksSent.Inc() - return true - } - - metrics.GetOrCreateCounter(fmt.Sprintf(`vlagent_remotewrite_requests_total{url=%q, status_code="%d"}`, c.sanitizedURL, statusCode)).Inc() - if statusCode == 400 || statusCode == 404 { - logBlockRejected(block, c.sanitizedURL, resp) - _ = resp.Body.Close() - c.packetsDropped.Inc() - return true - } - // Unexpected status code returned - retriesCount++ - retryAfterHeader := parseRetryAfterHeader(resp.Header.Get("Retry-After")) - retryDuration = getRetryDuration(retryAfterHeader, retryDuration, maxRetryDuration) - - // Handle response - body, err := io.ReadAll(resp.Body) - _ = resp.Body.Close() - if err != nil { - logger.Errorf("cannot read response body from %q during retry #%d: %s", c.sanitizedURL, retriesCount, err) - } else { - logger.Errorf("unexpected status code received after sending a block with size %d bytes to %q during retry #%d: %d; response body=%q; "+ - "re-sending the block in %.3f seconds", len(block), c.sanitizedURL, retriesCount, statusCode, body, retryDuration.Seconds()) - } - t := timerpool.Get(retryDuration) - select { - case <-c.stopCh: - timerpool.Put(t) - return false - case <-t.C: - timerpool.Put(t) - } - c.retriesCount.Inc() - goto again -} - -var remoteWriteRejectedLogger = logger.WithThrottler("remoteWriteRejected", 5*time.Second) -var remoteWriteRetryLogger = logger.WithThrottler("remoteWriteRetry", 5*time.Second) - -// getRetryDuration returns retry duration. -// retryAfterDuration has the highest priority. -// If retryAfterDuration is not specified, retryDuration gets doubled. -// retryDuration can't exceed maxRetryDuration. -// -// Also see: https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6097 -func getRetryDuration(retryAfterDuration, retryDuration, maxRetryDuration time.Duration) time.Duration { - // retryAfterDuration has the highest priority duration - if retryAfterDuration > 0 { - return timeutil.AddJitterToDuration(retryAfterDuration) - } - - // default backoff retry policy - retryDuration *= 2 - if retryDuration > maxRetryDuration { - retryDuration = maxRetryDuration - } - - return retryDuration -} - -func logBlockRejected(block []byte, sanitizedURL string, resp *http.Response) { - body, err := io.ReadAll(resp.Body) - if err != nil { - remoteWriteRejectedLogger.Errorf("sending a block with size %d bytes to %q was rejected (skipping the block): status code %d; "+ - "failed to read response body: %s", - len(block), sanitizedURL, resp.StatusCode, err) - } else { - remoteWriteRejectedLogger.Errorf("sending a block with size %d bytes to %q was rejected (skipping the block): status code %d; response body: %s", - len(block), sanitizedURL, resp.StatusCode, string(body)) - } -} - -// parseRetryAfterHeader parses `Retry-After` value retrieved from HTTP response header. -// retryAfterString should be in either HTTP-date or a number of seconds. -// It will return time.Duration(0) if `retryAfterString` does not follow RFC 7231. -func parseRetryAfterHeader(retryAfterString string) (retryAfterDuration time.Duration) { - if retryAfterString == "" { - return retryAfterDuration - } - - defer func() { - v := retryAfterDuration.Seconds() - logger.Infof("'Retry-After: %s' parsed into %.2f second(s)", retryAfterString, v) - }() - - // Retry-After could be in "Mon, 02 Jan 2006 15:04:05 GMT" format. - if parsedTime, err := time.Parse(http.TimeFormat, retryAfterString); err == nil { - return time.Duration(time.Until(parsedTime).Seconds()) * time.Second - } - // Retry-After could be in seconds. - if seconds, err := strconv.Atoi(retryAfterString); err == nil { - return time.Duration(seconds) * time.Second - } - - return 0 -} diff --git a/app/vlagent/remotewrite/client_test.go b/app/vlagent/remotewrite/client_test.go deleted file mode 100644 index fda56e2f85..0000000000 --- a/app/vlagent/remotewrite/client_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package remotewrite - -import ( - "math" - "net/http" - "testing" - "time" -) - -func TestCalculateRetryDuration(t *testing.T) { - // `testFunc` call `calculateRetryDuration` for `n` times - // and evaluate if the result of `calculateRetryDuration` is - // 1. >= expectMinDuration - // 2. <= expectMinDuration + 10% (see timeutil.AddJitterToDuration) - f := func(retryAfterDuration, retryDuration time.Duration, n int, expectMinDuration time.Duration) { - t.Helper() - - for i := 0; i < n; i++ { - retryDuration = getRetryDuration(retryAfterDuration, retryDuration, time.Minute) - } - - expectMaxDuration := helper(expectMinDuration) - expectMinDuration = expectMinDuration - (1000 * time.Millisecond) // Avoid edge case when calculating time.Until(now) - - if !(retryDuration >= expectMinDuration && retryDuration <= expectMaxDuration) { - t.Fatalf( - "incorrect retry duration, want (ms): [%d, %d], got (ms): %d", - expectMinDuration.Milliseconds(), expectMaxDuration.Milliseconds(), - retryDuration.Milliseconds(), - ) - } - } - - // Call calculateRetryDuration for 1 time. - { - // default backoff policy - f(0, time.Second, 1, 2*time.Second) - // default backoff policy exceed max limit" - f(0, 10*time.Minute, 1, time.Minute) - - // retry after > default backoff policy - f(10*time.Second, 1*time.Second, 1, 10*time.Second) - // retry after < default backoff policy - f(1*time.Second, 10*time.Second, 1, 1*time.Second) - // retry after invalid and < default backoff policy - f(0, time.Second, 1, 2*time.Second) - - } - - // Call calculateRetryDuration for multiple times. - { - // default backoff policy 2 times - f(0, time.Second, 2, 4*time.Second) - // default backoff policy 3 times - f(0, time.Second, 3, 8*time.Second) - // default backoff policy N times exceed max limit - f(0, time.Second, 10, time.Minute) - - // retry after 120s 1 times - f(120*time.Second, time.Second, 1, 120*time.Second) - // retry after 120s 2 times - f(120*time.Second, time.Second, 2, 120*time.Second) - } -} - -func TestParseRetryAfterHeader(t *testing.T) { - f := func(retryAfterString string, expectResult time.Duration) { - t.Helper() - - result := parseRetryAfterHeader(retryAfterString) - // expect `expectResult == result` when retryAfterString is in seconds or invalid - // expect the difference between result and expectResult to be lower than 10% - if !(expectResult == result || math.Abs(float64(expectResult-result))/float64(expectResult) < 0.10) { - t.Fatalf( - "incorrect retry after duration, want (ms): %d, got (ms): %d", - expectResult.Milliseconds(), result.Milliseconds(), - ) - } - } - - // retry after header in seconds - f("10", 10*time.Second) - // retry after header in date time - f(time.Now().Add(30*time.Second).UTC().Format(http.TimeFormat), 30*time.Second) - // retry after header invalid - f("invalid-retry-after", 0) - // retry after header not in GMT - f(time.Now().Add(10*time.Second).Format("Mon, 02 Jan 2006 15:04:05 FAKETZ"), 0) -} - -// helper calculate the max possible time duration calculated by timeutil.AddJitterToDuration. -func helper(d time.Duration) time.Duration { - dv := d / 10 - if dv > 10*time.Second { - dv = 10 * time.Second - } - - return d + dv -} diff --git a/app/vlagent/remotewrite/pendinglogrows.go b/app/vlagent/remotewrite/pendinglogrows.go deleted file mode 100644 index 7e9c78072f..0000000000 --- a/app/vlagent/remotewrite/pendinglogrows.go +++ /dev/null @@ -1,158 +0,0 @@ -package remotewrite - -import ( - "flag" - "sync" - "sync/atomic" - "time" - - "github.com/VictoriaMetrics/metrics" - - "github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/encoding/zstd" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/fasttime" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/persistentqueue" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/timeutil" -) - -var ( - maxUnpackedBlockSize = flagutil.NewBytes("remoteWrite.maxBlockSize", 8*1024*1024, "The maximum block size to send to remote storage. Bigger blocks may improve performance at the cost of the increased memory usage.") - flushInterval = flag.Duration("remoteWrite.flushInterval", time.Second, "Interval for flushing the data to remote storage. "+ - "This option takes effect only when less than 2MB of data per second are pushed to -remoteWrite.url") -) - -type pendingLogs struct { - lastFlushTime atomic.Uint64 - - // The queue to send blocks to. - fq *persistentqueue.FastQueue - - // mu protects wr - mu sync.Mutex - wr writeRequest - - stopCh chan struct{} - periodicFlusherWG sync.WaitGroup -} - -func newPendingLogs(fq *persistentqueue.FastQueue) *pendingLogs { - pl := &pendingLogs{ - fq: fq, - stopCh: make(chan struct{}), - } - - pl.periodicFlusherWG.Add(1) - go func() { - defer pl.periodicFlusherWG.Done() - pl.periodicFlusher() - }() - - return pl -} - -func (pl *pendingLogs) add(lr *logstorage.LogRows) { - lr.ForEachRow(func(_ uint64, r *logstorage.InsertRow) { - pl.addLogRow(r) - }) -} - -func (pl *pendingLogs) addLogRow(r *logstorage.InsertRow) { - bb := bbPool.Get() - bb.B = r.Marshal(bb.B) - - pl.mu.Lock() - _, _ = pl.wr.pendingData.Write(bb.B) - pl.wr.pendingLogRowsCount++ - if len(pl.wr.pendingData.B) > maxUnpackedBlockSize.IntN() { - pl.mustFlushLocked() - } - pl.mu.Unlock() - bbPool.Put(bb) -} - -func (pl *pendingLogs) mustFlushLocked() { - pl.lastFlushTime.Store(fasttime.UnixTimestamp()) - pl.wr.push(func(b []byte) { - if !pl.fq.TryWriteBlock(b) { - logger.Fatalf("BUG: TryWriteBlock cannot return false") - } - }) - pl.wr.reset() -} - -func (pl *pendingLogs) periodicFlusher() { - flushSeconds := int64(flushInterval.Seconds()) - if flushSeconds <= 0 { - flushSeconds = 1 - } - d := timeutil.AddJitterToDuration(*flushInterval) - ticker := time.NewTicker(d) - defer ticker.Stop() - for { - select { - case <-pl.stopCh: - pl.mu.Lock() - pl.mustFlushOnStop() - pl.mu.Unlock() - return - case <-ticker.C: - if fasttime.UnixTimestamp()-pl.lastFlushTime.Load() < uint64(flushSeconds) { - continue - } - } - pl.mu.Lock() - pl.mustFlushLocked() - pl.mu.Unlock() - } -} - -// mustFlushOnStop force pushes wr data -// -// This is needed in order to properly save in-memory data to persistent queue on graceful shutdown. -func (pl *pendingLogs) mustFlushOnStop() { - pl.wr.push(pl.fq.MustWriteBlockIgnoreDisabledPQ) - pl.wr.reset() -} - -func (pl *pendingLogs) mustStop() { - close(pl.stopCh) - pl.periodicFlusherWG.Wait() -} - -type writeRequest struct { - pendingData bytesutil.ByteBuffer - pendingLogRowsCount int64 -} - -func (wr *writeRequest) push(pushBlock func([]byte)) { - if len(wr.pendingData.B) == 0 { - return - } - b := wr.pendingData.B - - zb := compressBufPool.Get() - zb.B = zstd.CompressLevel(zb.B[:0], b, 1) - zbLen := len(zb.B) - pushBlock(zb.B) - compressBufPool.Put(zb) - blockSizeBytes.Update(float64(zbLen)) - blockSizeLogRows.Update(float64(wr.pendingLogRowsCount)) -} - -func (wr *writeRequest) reset() { - wr.pendingData.Reset() - wr.pendingLogRowsCount = 0 -} - -var ( - blockSizeBytes = metrics.NewHistogram(`vlagent_remotewrite_block_size_bytes`) - blockSizeLogRows = metrics.NewHistogram(`vlagent_remotewrite_block_size_rows`) -) - -var ( - compressBufPool bytesutil.ByteBufferPool - bbPool bytesutil.ByteBufferPool -) diff --git a/app/vlagent/remotewrite/remotewrite.go b/app/vlagent/remotewrite/remotewrite.go deleted file mode 100644 index 2ff66db120..0000000000 --- a/app/vlagent/remotewrite/remotewrite.go +++ /dev/null @@ -1,277 +0,0 @@ -package remotewrite - -import ( - "flag" - "fmt" - "net/url" - "path/filepath" - "sync" - "sync/atomic" - - "github.com/VictoriaMetrics/metrics" - "github.com/cespare/xxhash/v2" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlstorage/netinsert" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/cgroup" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/fs" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/memory" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/persistentqueue" -) - -var ( - remoteWriteURLs = flagutil.NewArrayString("remoteWrite.url", "Remote storage URL to write data to. It must support VictoriaLogs native protocol. "+ - "Example url: http://:9428/internal/insert. "+ - "Pass multiple -remoteWrite.url options in order to replicate the collected data to multiple remote storage systems.") - maxPendingBytesPerURL = flagutil.NewArrayBytes("remoteWrite.maxDiskUsagePerURL", 0, "The maximum file-based buffer size in bytes at -remoteWrite.tmpDataPath "+ - "for each -remoteWrite.url. When buffer size reaches the configured maximum, then old data is dropped when adding new data to the buffer. "+ - "Buffered data is stored in ~500MB chunks. It is recommended to set the value for this flag to a multiple of the block size 500MB. "+ - "Disk usage is unlimited if the value is set to 0") - - tmpDataPath = flag.String("remoteWrite.tmpDataPath", "vlagent-remotewrite-data", "Path to directory for storing pending data, which isn't sent to the configured -remoteWrite.url . "+ - "See also -remoteWrite.maxDiskUsagePerURL") - queues = flag.Int("remoteWrite.queues", cgroup.AvailableCPUs()*2, "The number of concurrent queues to each -remoteWrite.url. Set more queues if default number of queues "+ - "isn't enough for sending high volume of collected data to remote storage. "+ - "Default value depends on the number of available CPU cores. It should work fine in most cases since it minimizes resource usage") - - showRemoteWriteURL = flag.Bool("remoteWrite.showURL", false, "Whether to show -remoteWrite.url in the exported metrics. "+ - "It is hidden by default, since it can contain sensitive info such as auth key") -) - -// rwctxsGlobal contains statically populated entries when -remoteWrite.url is specified. -var rwctxsGlobal []*remoteWriteCtx - -// Storage implements insertutil.LogRowsStorage interface -type Storage struct{} - -// MustAddRows implements insertutil.LogRowsStorage interface -func (*Storage) MustAddRows(lr *logstorage.LogRows) { - pushToRemoteStorages(lr) -} - -// CanWriteData implements insertutil.LogRowsStorage interface -func (*Storage) CanWriteData() error { - return nil -} - -// maxQueues limits the maximum value for `-remoteWrite.queues`. There is no sense in setting too high value, -// since it may lead to high memory usage due to big number of buffers. -var maxQueues = cgroup.AvailableCPUs() * 16 - -const persistentQueueDirname = "persistent-queue" - -// InitSecretFlags must be called after flag.Parse and before any logging. -func InitSecretFlags() { - if !*showRemoteWriteURL { - // remoteWrite.url can contain authentication codes, so hide it at `/metrics` output. - flagutil.RegisterSecretFlag("remoteWrite.url") - } -} - -// Init initializes remotewrite. -// -// It must be called after flag.Parse(). -// -// Stop must be called for graceful shutdown. -func Init() { - if len(*remoteWriteURLs) == 0 { - logger.Fatalf("at least one `-remoteWrite.url` command-line flag must be set") - } - if *queues > maxQueues { - *queues = maxQueues - } - if *queues <= 0 { - *queues = 1 - } - initRemoteWriteCtxs(*remoteWriteURLs) - dropDanglingQueues() -} - -// Stop stops remotewrite. -// -// It is expected that nobody calls TryPush during and after the call to this func. -func Stop() { - for _, rwctx := range rwctxsGlobal { - rwctx.mustStop() - } - rwctxsGlobal = nil -} - -func dropDanglingQueues() { - // Remove dangling persistent queues, if any. - // This is required for the case when the number of queues has been changed or URL have been changed. - // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4014 - // - // In case if there were many persistent queues with identical *remoteWriteURLs - // the queue with the last index will be dropped. - // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6140 - existingQueues := make(map[string]struct{}, len(rwctxsGlobal)) - for _, rwctx := range rwctxsGlobal { - existingQueues[rwctx.fq.Dirname()] = struct{}{} - } - - queuesDir := filepath.Join(*tmpDataPath, persistentQueueDirname) - files := fs.MustReadDir(queuesDir) - removed := 0 - for _, f := range files { - dirname := f.Name() - if _, ok := existingQueues[dirname]; !ok { - logger.Infof("removing dangling queue %q", dirname) - fullPath := filepath.Join(queuesDir, dirname) - fs.MustRemoveAll(fullPath) - removed++ - } - } - if removed > 0 { - logger.Infof("removed %d dangling queues from %q, active queues: %d", removed, *tmpDataPath, len(rwctxsGlobal)) - } -} - -func initRemoteWriteCtxs(urls []string) { - if len(urls) == 0 { - logger.Panicf("BUG: urls must be non-empty") - } - - maxInmemoryBlocks := memory.Allowed() / len(urls) / 10000 - if maxInmemoryBlocks / *queues > 100 { - // There is no much sense in keeping higher number of blocks in memory, - // since this means that the producer outperforms consumer and the queue - // will continue growing. It is better storing the queue to file. - maxInmemoryBlocks = 100 * *queues - } - if maxInmemoryBlocks < 2 { - maxInmemoryBlocks = 2 - } - rwctxs := make([]*remoteWriteCtx, len(urls)) - rwctxIdx := make([]int, len(urls)) - for i, remoteWriteURLRaw := range urls { - remoteWriteURL, err := url.Parse(remoteWriteURLRaw) - if err != nil { - logger.Fatalf("invalid -remoteWrite.url=%q: %s", remoteWriteURL, err) - } - sanitizedURL := fmt.Sprintf("%d:secret-url", i+1) - if *showRemoteWriteURL { - sanitizedURL = fmt.Sprintf("%d:%s", i+1, remoteWriteURL) - } - rwctxs[i] = newRemoteWriteCtx(i, remoteWriteURL, maxInmemoryBlocks, sanitizedURL) - rwctxIdx[i] = i - } - - rwctxsGlobal = rwctxs -} - -func pushToRemoteStorages(lr *logstorage.LogRows) { - rwctxs := rwctxsGlobal - if len(rwctxs) == 1 { - // fast path - rwctxs[0].push(lr) - return - } - // Push samples to remote storage systems in parallel in order to reduce - // the time needed for sending the data to multiple remote storage systems. - var wg sync.WaitGroup - for _, rwctx := range rwctxs { - wg.Add(1) - go func(rwctx *remoteWriteCtx) { - defer wg.Done() - rwctx.push(lr) - - }(rwctx) - } - wg.Wait() -} - -type remoteWriteCtx struct { - idx int - fq *persistentqueue.FastQueue - c *client - - pls []*pendingLogs - pssNextIdx atomic.Uint64 -} - -func newRemoteWriteCtx(argIdx int, remoteWriteURL *url.URL, maxInmemoryBlocks int, sanitizedURL string) *remoteWriteCtx { - // protocol version is required by victoria-logs - q := remoteWriteURL.Query() - q.Set("version", netinsert.ProtocolVersion) - remoteWriteURL.RawQuery = q.Encode() - - // strip query params, otherwise changing params resets pq - pqURL := *remoteWriteURL - pqURL.RawQuery = "" - pqURL.Fragment = "" - h := xxhash.Sum64([]byte(pqURL.String())) - queuePath := filepath.Join(*tmpDataPath, persistentQueueDirname, fmt.Sprintf("%d_%016X", argIdx+1, h)) - maxPendingBytes := maxPendingBytesPerURL.GetOptionalArg(argIdx) - if maxPendingBytes != 0 && maxPendingBytes < persistentqueue.DefaultChunkFileSize { - // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4195 - logger.Warnf("rounding the -remoteWrite.maxDiskUsagePerURL=%d to the minimum supported value: %d", maxPendingBytes, persistentqueue.DefaultChunkFileSize) - maxPendingBytes = persistentqueue.DefaultChunkFileSize - } - - fq := persistentqueue.MustOpenFastQueue(queuePath, sanitizedURL, maxInmemoryBlocks, maxPendingBytes, false) - _ = metrics.GetOrCreateGauge(fmt.Sprintf(`vlagent_remotewrite_pending_data_bytes{path=%q, url=%q}`, queuePath, sanitizedURL), func() float64 { - return float64(fq.GetPendingBytes()) - }) - _ = metrics.GetOrCreateGauge(fmt.Sprintf(`vlagent_remotewrite_pending_inmemory_blocks{path=%q, url=%q}`, queuePath, sanitizedURL), func() float64 { - return float64(fq.GetInmemoryQueueLen()) - }) - _ = metrics.GetOrCreateGauge(fmt.Sprintf(`vlagent_remotewrite_queue_blocked{path=%q, url=%q}`, queuePath, sanitizedURL), func() float64 { - if fq.IsWriteBlocked() { - return 1 - } - return 0 - }) - - var c *client - switch remoteWriteURL.Scheme { - case "http", "https": - c = newHTTPClient(argIdx, remoteWriteURL.String(), sanitizedURL, fq, *queues) - default: - logger.Fatalf("unsupported scheme: %s for remoteWriteURL: %s, want `http`, `https`", remoteWriteURL.Scheme, sanitizedURL) - } - c.init(argIdx, *queues, sanitizedURL) - - // Initialize pss - plsLen := *queues - if n := cgroup.AvailableCPUs(); plsLen > n { - // There is no sense in running more than availableCPUs concurrent pendingLogs, - // since every pendingLogs can saturate up to a single CPU. - plsLen = n - } - pls := make([]*pendingLogs, plsLen) - for i := range pls { - pls[i] = newPendingLogs(fq) - } - - rwctx := &remoteWriteCtx{ - idx: argIdx, - fq: fq, - c: c, - pls: pls, - } - - return rwctx -} - -func (rwctx *remoteWriteCtx) push(lr *logstorage.LogRows) { - pls := rwctx.pls - idx := rwctx.pssNextIdx.Add(1) % uint64(len(pls)) - pls[idx].add(lr) -} - -func (rwctx *remoteWriteCtx) mustStop() { - for _, ps := range rwctx.pls { - ps.mustStop() - } - rwctx.idx = 0 - rwctx.pls = nil - rwctx.fq.UnblockAllReaders() - rwctx.c.MustStop() - rwctx.c = nil - - rwctx.fq.MustClose() - rwctx.fq = nil -} diff --git a/app/vlinsert/README.md b/app/vlinsert/README.md new file mode 100644 index 0000000000..5456a353a1 --- /dev/null +++ b/app/vlinsert/README.md @@ -0,0 +1 @@ +VictoriaLogs source code has been moved to [github.com/VictoriaMetrics/VictoriaLogs](https://github.com/VictoriaMetrics/VictoriaLogs/). diff --git a/app/vlinsert/datadog/datadog.go b/app/vlinsert/datadog/datadog.go deleted file mode 100644 index f331e63a2d..0000000000 --- a/app/vlinsert/datadog/datadog.go +++ /dev/null @@ -1,260 +0,0 @@ -package datadog - -import ( - "bytes" - "fmt" - "net/http" - "strconv" - "time" - - "github.com/VictoriaMetrics/metrics" - "github.com/valyala/fastjson" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/protoparserutil" -) - -var ( - datadogStreamFields = flagutil.NewArrayString("datadog.streamFields", "Comma-separated list of fields to use as log stream fields for logs ingested via DataDog protocol. "+ - "See https://docs.victoriametrics.com/victorialogs/data-ingestion/datadog-agent/#stream-fields") - datadogIgnoreFields = flagutil.NewArrayString("datadog.ignoreFields", "Comma-separated list of fields to ignore for logs ingested via DataDog protocol. "+ - "See https://docs.victoriametrics.com/victorialogs/data-ingestion/datadog-agent/#dropping-fields") - - maxRequestSize = flagutil.NewBytes("datadog.maxRequestSize", 64*1024*1024, "The maximum size in bytes of a single DataDog request") -) - -var parserPool fastjson.ParserPool - -// RequestHandler processes Datadog insert requests -func RequestHandler(path string, w http.ResponseWriter, r *http.Request) bool { - switch path { - case "/insert/datadog/api/v1/validate": - fmt.Fprintf(w, `{}`) - return true - case "/insert/datadog/api/v2/logs": - return datadogLogsIngestion(w, r) - default: - return false - } -} - -func datadogLogsIngestion(w http.ResponseWriter, r *http.Request) bool { - w.Header().Add("Content-Type", "application/json") - startTime := time.Now() - v2LogsRequestsTotal.Inc() - - var ts int64 - if tsValue := r.Header.Get("dd-message-timestamp"); tsValue != "" && tsValue != "0" { - var err error - ts, err = strconv.ParseInt(tsValue, 10, 64) - if err != nil { - httpserver.Errorf(w, r, "could not parse dd-message-timestamp header value: %s", err) - return true - } - ts *= 1e6 - } else { - ts = startTime.UnixNano() - } - - cp, err := insertutil.GetCommonParams(r) - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return true - } - - if len(cp.StreamFields) == 0 { - cp.StreamFields = *datadogStreamFields - } - if len(cp.IgnoreFields) == 0 { - cp.IgnoreFields = *datadogIgnoreFields - } - - if err := insertutil.CanWriteData(); err != nil { - httpserver.Errorf(w, r, "%s", err) - return true - } - - encoding := r.Header.Get("Content-Encoding") - err = protoparserutil.ReadUncompressedData(r.Body, encoding, maxRequestSize, func(data []byte) error { - lmp := cp.NewLogMessageProcessor("datadog", false) - err := readLogsRequest(ts, data, lmp) - lmp.MustClose() - return err - }) - if err != nil { - httpserver.Errorf(w, r, "cannot read DataDog protocol data: %s", err) - return true - } - - // update v2LogsRequestDuration only for successfully parsed requests - // There is no need in updating v2LogsRequestDuration for request errors, - // since their timings are usually much smaller than the timing for successful request parsing. - v2LogsRequestDuration.UpdateDuration(startTime) - w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) - return true -} - -var ( - v2LogsRequestsTotal = metrics.NewCounter(`vl_http_requests_total{path="/insert/datadog/api/v2/logs"}`) - v2LogsRequestDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/insert/datadog/api/v2/logs"}`) -) - -// datadog message field has two formats: -// - regular log message with string text -// - nested json format for serverless plugins -// which has the following format: -// {"message": {"message": "text","lamdba": {"arn": "string","requestID": "string"}, "timestamp": int64} } -// -// See https://github.com/DataDog/datadog-lambda-extension/blob/28b90c7e4e985b72d60b5f5a5147c69c7ac693c4/bottlecap/src/logs/lambda/mod.rs#L24 -func appendMsgFields(fields []logstorage.Field, v *fastjson.Value) ([]logstorage.Field, error) { - switch v.Type() { - case fastjson.TypeString: - val := v.GetStringBytes() - fields = append(fields, logstorage.Field{ - Name: "_msg", - Value: bytesutil.ToUnsafeString(val), - }) - case fastjson.TypeObject: - var firstErr error - v.GetObject().Visit(func(k []byte, v *fastjson.Value) { - if firstErr != nil { - return - } - switch bytesutil.ToUnsafeString(k) { - case "message": - val := v.GetStringBytes() - fields = append(fields, logstorage.Field{ - Name: "_msg", - Value: bytesutil.ToUnsafeString(val), - }) - case "status": - val := v.GetStringBytes() - fields = append(fields, logstorage.Field{ - Name: "status", - Value: bytesutil.ToUnsafeString(val), - }) - case "lamdba": - obj, err := v.Object() - if err != nil { - firstErr = err - firstErr = fmt.Errorf("unexpected lambda value type for %q:%q; want object", k, v) - return - } - obj.Visit(func(k []byte, v *fastjson.Value) { - if firstErr != nil { - return - } - val, err := v.StringBytes() - if err != nil { - firstErr = fmt.Errorf("unexpected lambda label value type for %q:%q; want string", k, v) - return - } - fields = append(fields, logstorage.Field{ - Name: bytesutil.ToUnsafeString(k), - Value: bytesutil.ToUnsafeString(val), - }) - }) - - } - }) - default: - return fields, fmt.Errorf("unsupported message type %q", v.Type().String()) - } - return fields, nil -} - -// readLogsRequest parses data according to DataDog logs format -// https://docs.datadoghq.com/api/latest/logs/#send-logs -func readLogsRequest(ts int64, data []byte, lmp insertutil.LogMessageProcessor) error { - p := parserPool.Get() - defer parserPool.Put(p) - v, err := p.ParseBytes(data) - if err != nil { - return fmt.Errorf("cannot parse JSON request body: %w", err) - } - records, err := v.Array() - if err != nil { - return fmt.Errorf("cannot extract array from parsed JSON: %w", err) - } - - var fields []logstorage.Field - for _, r := range records { - o, err := r.Object() - if err != nil { - return fmt.Errorf("could not extract log record: %w", err) - } - o.Visit(func(k []byte, v *fastjson.Value) { - if err != nil { - return - } - switch bytesutil.ToUnsafeString(k) { - case "message": - fields, err = appendMsgFields(fields, v) - if err != nil { - return - } - case "timestamp": - val, e := v.Int64() - if e != nil { - err = fmt.Errorf("failed to parse timestamp for %q:%q", k, v) - } - if val > 0 { - ts = val * 1e6 - } - case "ddtags": - // https://docs.datadoghq.com/getting_started/tagging/ - val, e := v.StringBytes() - if e != nil { - err = fmt.Errorf("unexpected label value type for %q:%q; want string", k, v) - return - } - var pair []byte - idx := 0 - for idx >= 0 { - idx = bytes.IndexByte(val, ',') - if idx < 0 { - pair = val - } else { - pair = val[:idx] - val = val[idx+1:] - } - if len(pair) > 0 { - n := bytes.IndexByte(pair, ':') - if n < 0 { - // No tag value. - fields = append(fields, logstorage.Field{ - Name: bytesutil.ToUnsafeString(pair), - Value: "no_label_value", - }) - } - fields = append(fields, logstorage.Field{ - Name: bytesutil.ToUnsafeString(pair[:n]), - Value: bytesutil.ToUnsafeString(pair[n+1:]), - }) - } - } - default: - val, e := v.StringBytes() - if e != nil { - err = fmt.Errorf("unexpected label value type for %q:%q; want string", k, v) - return - } - fields = append(fields, logstorage.Field{ - Name: bytesutil.ToUnsafeString(k), - Value: bytesutil.ToUnsafeString(val), - }) - } - }) - if err != nil { - return err - } - lmp.AddRow(ts, fields, nil) - fields = fields[:0] - } - return nil -} diff --git a/app/vlinsert/datadog/datadog_test.go b/app/vlinsert/datadog/datadog_test.go deleted file mode 100644 index 261a196c5d..0000000000 --- a/app/vlinsert/datadog/datadog_test.go +++ /dev/null @@ -1,104 +0,0 @@ -package datadog - -import ( - "testing" - "time" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" -) - -func TestReadLogsRequestFailure(t *testing.T) { - f := func(data string) { - t.Helper() - - ts := time.Now().UnixNano() - - lmp := &insertutil.TestLogMessageProcessor{} - if err := readLogsRequest(ts, []byte(data), lmp); err == nil { - t.Fatalf("expecting non-empty error") - } - if err := lmp.Verify(nil, ""); err != nil { - t.Fatalf("unexpected error: %s", err) - } - } - f("foobar") - f(`{}`) - f(`["create":{}]`) - f(`{"create":{}} -foobar`) -} - -func TestReadLogsRequestSuccess(t *testing.T) { - f := func(data string, rowsExpected int, resultExpected string) { - t.Helper() - - ts := time.Now().UnixNano() - var timestampsExpected []int64 - for i := 0; i < rowsExpected; i++ { - timestampsExpected = append(timestampsExpected, ts) - } - lmp := &insertutil.TestLogMessageProcessor{} - if err := readLogsRequest(ts, []byte(data), lmp); err != nil { - t.Fatalf("unexpected error: %s", err) - } - if err := lmp.Verify(timestampsExpected, resultExpected); err != nil { - t.Fatalf("unexpected error: %s", err) - } - } - - // Verify non-empty data - data := `[ - { - "ddsource":"nginx", - "ddtags":"tag1:value1,tag2:value2", - "hostname":"127.0.0.1", - "message":"bar", - "service":"test" - }, { - "ddsource":"nginx", - "ddtags":"tag1:value1,tag2:value2", - "hostname":"127.0.0.1", - "message":{"message": "nested"}, - "service":"test" - }, { - "ddsource":"nginx", - "ddtags":"tag1:value1,tag2:value2", - "hostname":"127.0.0.1", - "message":"foobar", - "service":"test" - }, { - "ddsource":"nginx", - "ddtags":"tag1:value1,tag2:value2", - "hostname":"127.0.0.1", - "message":"baz", - "service":"test" - }, { - "ddsource":"nginx", - "ddtags":"tag1:value1,tag2:value2", - "hostname":"127.0.0.1", - "message":"xyz", - "service":"test" - }, { - "ddsource": "nginx", - "ddtags":"tag1:value1,tag2:value2,", - "hostname":"127.0.0.1", - "message":"xyz", - "service":"test" - }, { - "ddsource":"nginx", - "ddtags":",tag1:value1,tag2:value2", - "hostname":"127.0.0.1", - "message":"xyz", - "service":"test" - } - ]` - rowsExpected := 7 - resultExpected := `{"ddsource":"nginx","tag1":"value1","tag2":"value2","hostname":"127.0.0.1","_msg":"bar","service":"test"} -{"ddsource":"nginx","tag1":"value1","tag2":"value2","hostname":"127.0.0.1","_msg":"nested","service":"test"} -{"ddsource":"nginx","tag1":"value1","tag2":"value2","hostname":"127.0.0.1","_msg":"foobar","service":"test"} -{"ddsource":"nginx","tag1":"value1","tag2":"value2","hostname":"127.0.0.1","_msg":"baz","service":"test"} -{"ddsource":"nginx","tag1":"value1","tag2":"value2","hostname":"127.0.0.1","_msg":"xyz","service":"test"} -{"ddsource":"nginx","tag1":"value1","tag2":"value2","hostname":"127.0.0.1","_msg":"xyz","service":"test"} -{"ddsource":"nginx","tag1":"value1","tag2":"value2","hostname":"127.0.0.1","_msg":"xyz","service":"test"}` - f(data, rowsExpected, resultExpected) -} diff --git a/app/vlinsert/elasticsearch/bulk_response.qtpl b/app/vlinsert/elasticsearch/bulk_response.qtpl deleted file mode 100644 index f2b499d0e6..0000000000 --- a/app/vlinsert/elasticsearch/bulk_response.qtpl +++ /dev/null @@ -1,20 +0,0 @@ -{% stripspace %} - -{% func BulkResponse(n int, tookMs int64) %} -{ - "took":{%dl tookMs %}, - "errors":false, - "items":[ - {% for i := 0; i < n; i++ %} - { - "create":{ - "status":201 - } - } - {% if i+1 < n %},{% endif %} - {% endfor %} - ] -} -{% endfunc %} - -{% endstripspace %} diff --git a/app/vlinsert/elasticsearch/bulk_response.qtpl.go b/app/vlinsert/elasticsearch/bulk_response.qtpl.go deleted file mode 100644 index 5bd6c5a58f..0000000000 --- a/app/vlinsert/elasticsearch/bulk_response.qtpl.go +++ /dev/null @@ -1,69 +0,0 @@ -// Code generated by qtc from "bulk_response.qtpl". DO NOT EDIT. -// See https://github.com/valyala/quicktemplate for details. - -//line app/vlinsert/elasticsearch/bulk_response.qtpl:3 -package elasticsearch - -//line app/vlinsert/elasticsearch/bulk_response.qtpl:3 -import ( - qtio422016 "io" - - qt422016 "github.com/valyala/quicktemplate" -) - -//line app/vlinsert/elasticsearch/bulk_response.qtpl:3 -var ( - _ = qtio422016.Copy - _ = qt422016.AcquireByteBuffer -) - -//line app/vlinsert/elasticsearch/bulk_response.qtpl:3 -func StreamBulkResponse(qw422016 *qt422016.Writer, n int, tookMs int64) { -//line app/vlinsert/elasticsearch/bulk_response.qtpl:3 - qw422016.N().S(`{"took":`) -//line app/vlinsert/elasticsearch/bulk_response.qtpl:5 - qw422016.N().DL(tookMs) -//line app/vlinsert/elasticsearch/bulk_response.qtpl:5 - qw422016.N().S(`,"errors":false,"items":[`) -//line app/vlinsert/elasticsearch/bulk_response.qtpl:8 - for i := 0; i < n; i++ { -//line app/vlinsert/elasticsearch/bulk_response.qtpl:8 - qw422016.N().S(`{"create":{"status":201}}`) -//line app/vlinsert/elasticsearch/bulk_response.qtpl:14 - if i+1 < n { -//line app/vlinsert/elasticsearch/bulk_response.qtpl:14 - qw422016.N().S(`,`) -//line app/vlinsert/elasticsearch/bulk_response.qtpl:14 - } -//line app/vlinsert/elasticsearch/bulk_response.qtpl:15 - } -//line app/vlinsert/elasticsearch/bulk_response.qtpl:15 - qw422016.N().S(`]}`) -//line app/vlinsert/elasticsearch/bulk_response.qtpl:18 -} - -//line app/vlinsert/elasticsearch/bulk_response.qtpl:18 -func WriteBulkResponse(qq422016 qtio422016.Writer, n int, tookMs int64) { -//line app/vlinsert/elasticsearch/bulk_response.qtpl:18 - qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vlinsert/elasticsearch/bulk_response.qtpl:18 - StreamBulkResponse(qw422016, n, tookMs) -//line app/vlinsert/elasticsearch/bulk_response.qtpl:18 - qt422016.ReleaseWriter(qw422016) -//line app/vlinsert/elasticsearch/bulk_response.qtpl:18 -} - -//line app/vlinsert/elasticsearch/bulk_response.qtpl:18 -func BulkResponse(n int, tookMs int64) string { -//line app/vlinsert/elasticsearch/bulk_response.qtpl:18 - qb422016 := qt422016.AcquireByteBuffer() -//line app/vlinsert/elasticsearch/bulk_response.qtpl:18 - WriteBulkResponse(qb422016, n, tookMs) -//line app/vlinsert/elasticsearch/bulk_response.qtpl:18 - qs422016 := string(qb422016.B) -//line app/vlinsert/elasticsearch/bulk_response.qtpl:18 - qt422016.ReleaseByteBuffer(qb422016) -//line app/vlinsert/elasticsearch/bulk_response.qtpl:18 - return qs422016 -//line app/vlinsert/elasticsearch/bulk_response.qtpl:18 -} diff --git a/app/vlinsert/elasticsearch/elasticsearch.go b/app/vlinsert/elasticsearch/elasticsearch.go deleted file mode 100644 index fd0f0bba8b..0000000000 --- a/app/vlinsert/elasticsearch/elasticsearch.go +++ /dev/null @@ -1,253 +0,0 @@ -package elasticsearch - -import ( - "flag" - "fmt" - "io" - "net/http" - "strings" - "time" - - "github.com/VictoriaMetrics/metrics" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/bufferedwriter" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/protoparserutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/timeutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/writeconcurrencylimiter" -) - -var ( - elasticsearchVersion = flag.String("elasticsearch.version", "8.9.0", "Elasticsearch version to report to client") -) - -// RequestHandler processes Elasticsearch insert requests -func RequestHandler(path string, w http.ResponseWriter, r *http.Request) bool { - w.Header().Add("Content-Type", "application/json") - // This header is needed for Logstash - w.Header().Set("X-Elastic-Product", "Elasticsearch") - - if strings.HasPrefix(path, "/insert/elasticsearch/_ilm/policy") { - // Return fake response for Elasticsearch ilm request. - fmt.Fprintf(w, `{}`) - return true - } - if strings.HasPrefix(path, "/insert/elasticsearch/_index_template") { - // Return fake response for Elasticsearch index template request. - fmt.Fprintf(w, `{}`) - return true - } - if strings.HasPrefix(path, "/insert/elasticsearch/_ingest") { - // Return fake response for Elasticsearch ingest pipeline request. - // See: https://www.elastic.co/guide/en/elasticsearch/reference/8.8/put-pipeline-api.html - fmt.Fprintf(w, `{}`) - return true - } - if strings.HasPrefix(path, "/insert/elasticsearch/_nodes") { - // Return fake response for Elasticsearch nodes discovery request. - // See: https://www.elastic.co/guide/en/elasticsearch/reference/8.8/cluster.html - fmt.Fprintf(w, `{}`) - return true - } - if strings.HasPrefix(path, "/insert/elasticsearch/logstash") || strings.HasPrefix(path, "/insert/elasticsearch/_logstash") { - // Return fake response for Logstash APIs requests. - // See: https://www.elastic.co/guide/en/elasticsearch/reference/8.8/logstash-apis.html - fmt.Fprintf(w, `{}`) - return true - } - switch path { - // some clients may omit trailing slash - // see https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8353 - case "/insert/elasticsearch/", "/insert/elasticsearch": - switch r.Method { - case http.MethodGet: - // Return fake response for Elasticsearch ping request. - // See the latest available version for Elasticsearch at https://github.com/elastic/elasticsearch/releases - fmt.Fprintf(w, `{ - "version": { - "number": %q - } - }`, *elasticsearchVersion) - case http.MethodHead: - // Return empty response for Logstash ping request. - } - - return true - case "/insert/elasticsearch/_license": - // Return fake response for Elasticsearch license request. - fmt.Fprintf(w, `{ - "license": { - "uid": "cbff45e7-c553-41f7-ae4f-9205eabd80xx", - "type": "oss", - "status": "active", - "expiry_date_in_millis" : 4000000000000 - } - }`) - return true - case "/insert/elasticsearch/_bulk": - startTime := time.Now() - bulkRequestsTotal.Inc() - - cp, err := insertutil.GetCommonParams(r) - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return true - } - if err := insertutil.CanWriteData(); err != nil { - httpserver.Errorf(w, r, "%s", err) - return true - } - lmp := cp.NewLogMessageProcessor("elasticsearch_bulk", true) - encoding := r.Header.Get("Content-Encoding") - streamName := fmt.Sprintf("remoteAddr=%s, requestURI=%q", httpserver.GetQuotedRemoteAddr(r), r.RequestURI) - n, err := readBulkRequest(streamName, r.Body, encoding, cp.TimeFields, cp.MsgFields, lmp) - lmp.MustClose() - if err != nil { - logger.Warnf("cannot decode log message #%d in /_bulk request: %s, stream fields: %s", n, err, cp.StreamFields) - return true - } - - tookMs := time.Since(startTime).Milliseconds() - bw := bufferedwriter.Get(w) - defer bufferedwriter.Put(bw) - WriteBulkResponse(bw, n, tookMs) - _ = bw.Flush() - - // update bulkRequestDuration only for successfully parsed requests - // There is no need in updating bulkRequestDuration for request errors, - // since their timings are usually much smaller than the timing for successful request parsing. - bulkRequestDuration.UpdateDuration(startTime) - - return true - default: - return false - } -} - -var ( - bulkRequestsTotal = metrics.NewCounter(`vl_http_requests_total{path="/insert/elasticsearch/_bulk"}`) - bulkRequestDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/insert/elasticsearch/_bulk"}`) -) - -func readBulkRequest(streamName string, r io.Reader, encoding string, timeFields, msgFields []string, lmp insertutil.LogMessageProcessor) (int, error) { - // See https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html - - reader, err := protoparserutil.GetUncompressedReader(r, encoding) - if err != nil { - return 0, fmt.Errorf("cannot decode Elasticsearch protocol data: %w", err) - } - defer protoparserutil.PutUncompressedReader(reader) - - wcr := writeconcurrencylimiter.GetReader(reader) - defer writeconcurrencylimiter.PutReader(wcr) - - lr := insertutil.NewLineReader(streamName, wcr) - - n := 0 - for { - ok, err := readBulkLine(lr, timeFields, msgFields, lmp) - wcr.DecConcurrency() - if err != nil || !ok { - return n, err - } - n++ - } -} - -func readBulkLine(lr *insertutil.LineReader, timeFields, msgFields []string, lmp insertutil.LogMessageProcessor) (bool, error) { - var line []byte - - // Read the command, must be "create" or "index" - for len(line) == 0 { - if !lr.NextLine() { - err := lr.Err() - return false, err - } - line = lr.Line - } - lineStr := bytesutil.ToUnsafeString(line) - if !strings.Contains(lineStr, `"create"`) && !strings.Contains(lineStr, `"index"`) { - return false, fmt.Errorf(`unexpected command %q; expecting "create" or "index"`, line) - } - - // Decode log message - if !lr.NextLine() { - if err := lr.Err(); err != nil { - return false, err - } - return false, fmt.Errorf(`missing log message after the "create" or "index" command`) - } - line = lr.Line - if len(line) == 0 { - // Special case - the line could be too long, so it was skipped. - // Continue parsing next lines. - return true, nil - } - p := logstorage.GetJSONParser() - if err := p.ParseLogMessage(line); err != nil { - return false, fmt.Errorf("cannot parse json-encoded log entry: %w", err) - } - - ts, err := extractTimestampFromFields(timeFields, p.Fields) - if err != nil { - return false, fmt.Errorf("cannot parse timestamp: %w", err) - } - if ts == 0 { - ts = time.Now().UnixNano() - } - logstorage.RenameField(p.Fields, msgFields, "_msg") - lmp.AddRow(ts, p.Fields, nil) - logstorage.PutJSONParser(p) - - return true, nil -} - -func extractTimestampFromFields(timeFields []string, fields []logstorage.Field) (int64, error) { - for _, timeField := range timeFields { - for i := range fields { - f := &fields[i] - if f.Name != timeField { - continue - } - timestamp, err := parseElasticsearchTimestamp(f.Value) - if err != nil { - return 0, err - } - f.Value = "" - return timestamp, nil - } - } - return 0, nil -} - -func parseElasticsearchTimestamp(s string) (int64, error) { - if s == "0" || s == "" { - // Special case - zero or empty timestamp must be substituted - // with the current time by the caller. - return 0, nil - } - if len(s) < len("YYYY-MM-DD") || s[len("YYYY")] != '-' { - // Try parsing timestamp in seconds or milliseconds - nsecs, ok := timeutil.TryParseUnixTimestamp(s) - if !ok { - return 0, fmt.Errorf("cannot parse unix timestamp %q", s) - } - return nsecs, nil - } - if len(s) == len("YYYY-MM-DD") { - t, err := time.Parse("2006-01-02", s) - if err != nil { - return 0, fmt.Errorf("cannot parse date %q: %w", s, err) - } - return t.UnixNano(), nil - } - nsecs, ok := logstorage.TryParseTimestampRFC3339Nano(s) - if !ok { - return 0, fmt.Errorf("cannot parse timestamp %q", s) - } - return nsecs, nil -} diff --git a/app/vlinsert/elasticsearch/elasticsearch_test.go b/app/vlinsert/elasticsearch/elasticsearch_test.go deleted file mode 100644 index 310a08bee1..0000000000 --- a/app/vlinsert/elasticsearch/elasticsearch_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package elasticsearch - -import ( - "bytes" - "fmt" - "github.com/golang/snappy" - "github.com/klauspost/compress/gzip" - "github.com/klauspost/compress/zlib" - "github.com/klauspost/compress/zstd" - "io" - "testing" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" -) - -func TestReadBulkRequest_Failure(t *testing.T) { - f := func(data string) { - t.Helper() - - tlp := &insertutil.TestLogMessageProcessor{} - r := bytes.NewBufferString(data) - rows, err := readBulkRequest("test", r, "", []string{"_time"}, []string{"_msg"}, tlp) - if err == nil { - t.Fatalf("expecting non-empty error") - } - if rows != 0 { - t.Fatalf("unexpected non-zero rows=%d", rows) - } - } - f("foobar") - f(`{}`) - f(`{"create":{}}`) - f(`{"creat":{}} -{}`) - f(`{"create":{}} -foobar`) -} - -func TestReadBulkRequest_Success(t *testing.T) { - f := func(data, encoding, timeField, msgField string, timestampsExpected []int64, resultExpected string) { - t.Helper() - - timeFields := []string{"non_existing_foo", timeField, "non_existing_bar"} - msgFields := []string{"non_existing_foo", msgField, "non_exiting_bar"} - tlp := &insertutil.TestLogMessageProcessor{} - - // Read the request without compression - r := bytes.NewBufferString(data) - rows, err := readBulkRequest("test", r, "", timeFields, msgFields, tlp) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } - if rows != len(timestampsExpected) { - t.Fatalf("unexpected rows read; got %d; want %d", rows, len(timestampsExpected)) - } - if err := tlp.Verify(timestampsExpected, resultExpected); err != nil { - t.Fatal(err) - } - - // Read the request with compression - tlp = &insertutil.TestLogMessageProcessor{} - if encoding != "" { - data = compressData(data, encoding) - } - r = bytes.NewBufferString(data) - rows, err = readBulkRequest("test", r, encoding, timeFields, msgFields, tlp) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } - if rows != len(timestampsExpected) { - t.Fatalf("unexpected rows read; got %d; want %d", rows, len(timestampsExpected)) - } - if err := tlp.Verify(timestampsExpected, resultExpected); err != nil { - t.Fatalf("verification failure after compression: %s", err) - } - } - - // Verify an empty data - f("", "gzip", "_time", "_msg", nil, "") - f("\n", "gzip", "_time", "_msg", nil, "") - f("\n\n", "gzip", "_time", "_msg", nil, "") - - // Verify non-empty data - data := `{"create":{"_index":"filebeat-8.8.0"}} -{"@timestamp":"2023-06-06T04:48:11.735Z","log":{"offset":71770,"file":{"path":"/var/log/auth.log"}},"message":"foobar"} -{"create":{"_index":"filebeat-8.8.0"}} -{"@timestamp":"2023-06-06 04:48:12.735+01:00","message":"baz"} -{"index":{"_index":"filebeat-8.8.0"}} -{"message":"xyz","@timestamp":"1686026893735","x":"y"} -{"create":{"_index":"filebeat-8.8.0"}} -{"message":"qwe rty","@timestamp":"1686026893"} -{"create":{"_index":"filebeat-8.8.0"}} -{"message":"qwe rty float","@timestamp":"1686026123.62"} -` - timeField := "@timestamp" - msgField := "message" - timestampsExpected := []int64{1686026891735000000, 1686023292735000000, 1686026893735000000, 1686026893000000000, 1686026123620000000} - resultExpected := `{"log.offset":"71770","log.file.path":"/var/log/auth.log","_msg":"foobar"} -{"_msg":"baz"} -{"_msg":"xyz","x":"y"} -{"_msg":"qwe rty"} -{"_msg":"qwe rty float"}` - f(data, "zstd", timeField, msgField, timestampsExpected, resultExpected) -} - -func compressData(s string, encoding string) string { - var bb bytes.Buffer - var zw io.WriteCloser - switch encoding { - case "gzip": - zw = gzip.NewWriter(&bb) - case "zstd": - zw, _ = zstd.NewWriter(&bb) - case "snappy": - return string(snappy.Encode(nil, []byte(s))) - case "deflate": - zw = zlib.NewWriter(&bb) - default: - panic(fmt.Errorf("%q encoding is not supported", encoding)) - } - if _, err := zw.Write([]byte(s)); err != nil { - panic(fmt.Errorf("unexpected error when compressing data: %w", err)) - } - if err := zw.Close(); err != nil { - panic(fmt.Errorf("unexpected error when closing gzip writer: %w", err)) - } - return bb.String() -} diff --git a/app/vlinsert/elasticsearch/elasticsearch_timing_test.go b/app/vlinsert/elasticsearch/elasticsearch_timing_test.go deleted file mode 100644 index 88b49f9c87..0000000000 --- a/app/vlinsert/elasticsearch/elasticsearch_timing_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package elasticsearch - -import ( - "bytes" - "fmt" - "testing" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil" -) - -func BenchmarkReadBulkRequest(b *testing.B) { - b.Run("encoding:none", func(b *testing.B) { - benchmarkReadBulkRequest(b, "") - }) - b.Run("encoding:gzip", func(b *testing.B) { - benchmarkReadBulkRequest(b, "gzip") - }) - b.Run("encoding:zstd", func(b *testing.B) { - benchmarkReadBulkRequest(b, "zstd") - }) - b.Run("encoding:deflate", func(b *testing.B) { - benchmarkReadBulkRequest(b, "deflate") - }) - b.Run("encoding:snappy", func(b *testing.B) { - benchmarkReadBulkRequest(b, "snappy") - }) -} - -func benchmarkReadBulkRequest(b *testing.B, encoding string) { - data := `{"create":{"_index":"filebeat-8.8.0"}} -{"@timestamp":"2023-06-06T04:48:11.735Z","log":{"offset":71770,"file":{"path":"/var/log/auth.log"}},"message":"foobar"} -{"create":{"_index":"filebeat-8.8.0"}} -{"@timestamp":"2023-06-06T04:48:12.735Z","message":"baz"} -{"create":{"_index":"filebeat-8.8.0"}} -{"message":"xyz","@timestamp":"2023-06-06T04:48:13.735Z","x":"y"} -` - if encoding != "" { - data = compressData(data, encoding) - } - dataBytes := bytesutil.ToUnsafeBytes(data) - - timeFields := []string{"@timestamp"} - msgFields := []string{"message"} - blp := &insertutil.BenchmarkLogMessageProcessor{} - - b.ReportAllocs() - b.SetBytes(int64(len(data))) - b.RunParallel(func(pb *testing.PB) { - r := &bytes.Reader{} - for pb.Next() { - r.Reset(dataBytes) - _, err := readBulkRequest("test", r, encoding, timeFields, msgFields, blp) - if err != nil { - panic(fmt.Errorf("unexpected error: %w", err)) - } - } - }) -} diff --git a/app/vlinsert/insertutil/common_params.go b/app/vlinsert/insertutil/common_params.go deleted file mode 100644 index 1cb8784549..0000000000 --- a/app/vlinsert/insertutil/common_params.go +++ /dev/null @@ -1,345 +0,0 @@ -package insertutil - -import ( - "flag" - "fmt" - "net/http" - "strconv" - "strings" - "sync" - "sync/atomic" - "time" - - "github.com/VictoriaMetrics/metrics" - - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httputil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/timeutil" -) - -var ( - defaultMsgValue = flag.String("defaultMsgValue", "missing _msg field; see https://docs.victoriametrics.com/victorialogs/keyconcepts/#message-field", - "Default value for _msg field if the ingested log entry doesn't contain it; see https://docs.victoriametrics.com/victorialogs/keyconcepts/#message-field") -) - -// CommonParams contains common HTTP parameters used by log ingestion APIs. -// -// See https://docs.victoriametrics.com/victorialogs/data-ingestion/#http-parameters -type CommonParams struct { - TenantID logstorage.TenantID - TimeFields []string - MsgFields []string - StreamFields []string - IgnoreFields []string - DecolorizeFields []string - ExtraFields []logstorage.Field - - IsTimeFieldSet bool - Debug bool - DebugRequestURI string - DebugRemoteAddr string -} - -// GetCommonParams returns CommonParams from r. -func GetCommonParams(r *http.Request) (*CommonParams, error) { - // Extract tenantID - tenantID, err := logstorage.GetTenantIDFromRequest(r) - if err != nil { - return nil, err - } - - var isTimeFieldSet bool - timeFields := []string{"_time"} - if tfs := httputil.GetArray(r, "_time_field", "VL-Time-Field"); len(tfs) > 0 { - isTimeFieldSet = true - timeFields = tfs - } - - msgFields := httputil.GetArray(r, "_msg_field", "VL-Msg-Field") - streamFields := httputil.GetArray(r, "_stream_fields", "VL-Stream-Fields") - ignoreFields := httputil.GetArray(r, "ignore_fields", "VL-Ignore-Fields") - decolorizeFields := httputil.GetArray(r, "decolorize_fields", "VL-Decolorize-Fields") - - extraFields, err := getExtraFields(r) - if err != nil { - return nil, err - } - - debug := false - if dv := httputil.GetRequestValue(r, "debug", "VL-Debug"); dv != "" { - debug, err = strconv.ParseBool(dv) - if err != nil { - return nil, fmt.Errorf("cannot parse debug=%q: %w", dv, err) - } - } - debugRequestURI := "" - debugRemoteAddr := "" - if debug { - debugRequestURI = httpserver.GetRequestURI(r) - debugRemoteAddr = httpserver.GetQuotedRemoteAddr(r) - } - - cp := &CommonParams{ - TenantID: tenantID, - TimeFields: timeFields, - MsgFields: msgFields, - StreamFields: streamFields, - IgnoreFields: ignoreFields, - DecolorizeFields: decolorizeFields, - ExtraFields: extraFields, - - IsTimeFieldSet: isTimeFieldSet, - Debug: debug, - DebugRequestURI: debugRequestURI, - DebugRemoteAddr: debugRemoteAddr, - } - - return cp, nil -} - -func getExtraFields(r *http.Request) ([]logstorage.Field, error) { - efs := httputil.GetArray(r, "extra_fields", "VL-Extra-Fields") - if len(efs) == 0 { - return nil, nil - } - - extraFields := make([]logstorage.Field, len(efs)) - for i, ef := range efs { - n := strings.Index(ef, "=") - if n <= 0 || n == len(ef)-1 { - return nil, fmt.Errorf(`invalid extra_field format: %q; must be in the form "field=value"`, ef) - } - extraFields[i] = logstorage.Field{ - Name: ef[:n], - Value: ef[n+1:], - } - } - return extraFields, nil -} - -// GetCommonParamsForSyslog returns common params needed for parsing syslog messages and storing them to the given tenantID. -func GetCommonParamsForSyslog(tenantID logstorage.TenantID, streamFields, ignoreFields, decolorizeFields []string, extraFields []logstorage.Field) *CommonParams { - // See https://docs.victoriametrics.com/victorialogs/logsql/#unpack_syslog-pipe - if streamFields == nil { - streamFields = []string{ - "hostname", - "app_name", - "proc_id", - } - } - cp := &CommonParams{ - TenantID: tenantID, - TimeFields: []string{ - "timestamp", - }, - MsgFields: []string{ - "message", - }, - StreamFields: streamFields, - IgnoreFields: ignoreFields, - DecolorizeFields: decolorizeFields, - ExtraFields: extraFields, - } - - return cp -} - -// LogRowsStorage is an interface for ingesting logs into the storage. -type LogRowsStorage interface { - // MustAddRows must add lr to the underlying storage. - MustAddRows(lr *logstorage.LogRows) - - // CanWriteData must returns non-nil error if logs cannot be added to the underlying storage. - CanWriteData() error -} - -var logRowsStorage LogRowsStorage - -// SetLogRowsStorage sets the storage for writing data to via LogMessageProcessor. -// -// This function must be called before using LogMessageProcessor and CanWriteData from this package. -func SetLogRowsStorage(storage LogRowsStorage) { - logRowsStorage = storage -} - -// CanWriteData returns non-nil error if data cannot be written to the underlying storage. -func CanWriteData() error { - return logRowsStorage.CanWriteData() -} - -// LogMessageProcessor is an interface for log message processors. -type LogMessageProcessor interface { - // AddRow must add row to the LogMessageProcessor with the given timestamp and fields. - // - // If streamFields is non-nil, then the given streamFields must be used as log stream fields instead of pre-configured fields. - // - // The LogMessageProcessor implementation cannot hold references to fields, since the caller can reuse them. - AddRow(timestamp int64, fields, streamFields []logstorage.Field) - - // MustClose() must flush all the remaining fields and free up resources occupied by LogMessageProcessor. - MustClose() -} - -type logMessageProcessor struct { - mu sync.Mutex - wg sync.WaitGroup - stopCh chan struct{} - lastFlushTime time.Time - - cp *CommonParams - lr *logstorage.LogRows - - rowsIngestedTotal *metrics.Counter - bytesIngestedTotal *metrics.Counter - flushDuration *metrics.Summary -} - -func (lmp *logMessageProcessor) initPeriodicFlush() { - lmp.lastFlushTime = time.Now() - - lmp.wg.Add(1) - go func() { - defer lmp.wg.Done() - - d := timeutil.AddJitterToDuration(time.Second) - ticker := time.NewTicker(d) - defer ticker.Stop() - - for { - select { - case <-lmp.stopCh: - return - case <-ticker.C: - lmp.mu.Lock() - if time.Since(lmp.lastFlushTime) >= d { - lmp.flushLocked() - } - lmp.mu.Unlock() - } - } - }() -} - -// AddRow adds new log message to lmp with the given timestamp and fields. -// -// If streamFields is non-nil, then it is used as log stream fields instead of the pre-configured stream fields. -func (lmp *logMessageProcessor) AddRow(timestamp int64, fields, streamFields []logstorage.Field) { - lmp.rowsIngestedTotal.Inc() - n := logstorage.EstimatedJSONRowLen(fields) - lmp.bytesIngestedTotal.Add(n) - - if len(fields) > *MaxFieldsPerLine { - line := logstorage.MarshalFieldsToJSON(nil, fields) - logger.Warnf("dropping log line with %d fields; it exceeds -insert.maxFieldsPerLine=%d; %s", len(fields), *MaxFieldsPerLine, line) - rowsDroppedTotalTooManyFields.Inc() - return - } - - lmp.mu.Lock() - defer lmp.mu.Unlock() - - lmp.lr.MustAdd(lmp.cp.TenantID, timestamp, fields, streamFields) - - if lmp.cp.Debug { - s := lmp.lr.GetRowString(0) - lmp.lr.ResetKeepSettings() - logger.Infof("remoteAddr=%s; requestURI=%s; ignoring log entry because of `debug` arg: %s", lmp.cp.DebugRemoteAddr, lmp.cp.DebugRequestURI, s) - rowsDroppedTotalDebug.Inc() - return - } - if lmp.lr.NeedFlush() { - lmp.flushLocked() - } -} - -// InsertRowProcessor is used by native data ingestion protocol parser. -type InsertRowProcessor interface { - // AddInsertRow must add r to the underlying storage. - AddInsertRow(r *logstorage.InsertRow) -} - -// AddInsertRow adds r to lmp. -func (lmp *logMessageProcessor) AddInsertRow(r *logstorage.InsertRow) { - lmp.rowsIngestedTotal.Inc() - n := logstorage.EstimatedJSONRowLen(r.Fields) - lmp.bytesIngestedTotal.Add(n) - - if len(r.Fields) > *MaxFieldsPerLine { - line := logstorage.MarshalFieldsToJSON(nil, r.Fields) - logger.Warnf("dropping log line with %d fields; it exceeds -insert.maxFieldsPerLine=%d; %s", len(r.Fields), *MaxFieldsPerLine, line) - rowsDroppedTotalTooManyFields.Inc() - return - } - - lmp.mu.Lock() - defer lmp.mu.Unlock() - - lmp.lr.MustAddInsertRow(r) - - if lmp.cp.Debug { - s := lmp.lr.GetRowString(0) - lmp.lr.ResetKeepSettings() - logger.Infof("remoteAddr=%s; requestURI=%s; ignoring log entry because of `debug` arg: %s", lmp.cp.DebugRemoteAddr, lmp.cp.DebugRequestURI, s) - rowsDroppedTotalDebug.Inc() - return - } - if lmp.lr.NeedFlush() { - lmp.flushLocked() - } -} - -// flushLocked must be called under locked lmp.mu. -func (lmp *logMessageProcessor) flushLocked() { - start := time.Now() - lmp.lastFlushTime = start - logRowsStorage.MustAddRows(lmp.lr) - lmp.lr.ResetKeepSettings() - lmp.flushDuration.UpdateDuration(start) -} - -// MustClose flushes the remaining data to the underlying storage and closes lmp. -func (lmp *logMessageProcessor) MustClose() { - close(lmp.stopCh) - lmp.wg.Wait() - - lmp.flushLocked() - logstorage.PutLogRows(lmp.lr) - lmp.lr = nil - messageProcessorCount.Add(-1) -} - -// NewLogMessageProcessor returns new LogMessageProcessor for the given cp. -// -// MustClose() must be called on the returned LogMessageProcessor when it is no longer needed. -func (cp *CommonParams) NewLogMessageProcessor(protocolName string, isStreamMode bool) LogMessageProcessor { - lr := logstorage.GetLogRows(cp.StreamFields, cp.IgnoreFields, cp.DecolorizeFields, cp.ExtraFields, *defaultMsgValue) - rowsIngestedTotal := metrics.GetOrCreateCounter(fmt.Sprintf("vl_rows_ingested_total{type=%q}", protocolName)) - bytesIngestedTotal := metrics.GetOrCreateCounter(fmt.Sprintf("vl_bytes_ingested_total{type=%q}", protocolName)) - flushDuration := metrics.GetOrCreateSummary(fmt.Sprintf("vl_insert_flush_duration_seconds{type=%q}", protocolName)) - lmp := &logMessageProcessor{ - cp: cp, - lr: lr, - - rowsIngestedTotal: rowsIngestedTotal, - bytesIngestedTotal: bytesIngestedTotal, - flushDuration: flushDuration, - - stopCh: make(chan struct{}), - } - - if isStreamMode { - lmp.initPeriodicFlush() - } - - messageProcessorCount.Add(1) - return lmp -} - -var ( - rowsDroppedTotalDebug = metrics.NewCounter(`vl_rows_dropped_total{reason="debug"}`) - rowsDroppedTotalTooManyFields = metrics.NewCounter(`vl_rows_dropped_total{reason="too_many_fields"}`) - _ = metrics.NewGauge(`vl_insert_processors_count`, func() float64 { return float64(messageProcessorCount.Load()) }) - messageProcessorCount atomic.Int64 -) diff --git a/app/vlinsert/insertutil/flags.go b/app/vlinsert/insertutil/flags.go deleted file mode 100644 index 87ab2f5ef3..0000000000 --- a/app/vlinsert/insertutil/flags.go +++ /dev/null @@ -1,17 +0,0 @@ -package insertutil - -import ( - "flag" - - "github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil" -) - -var ( - // MaxLineSizeBytes is the maximum length of a single line for /insert/* handlers - MaxLineSizeBytes = flagutil.NewBytes("insert.maxLineSizeBytes", 256*1024, "The maximum size of a single line, which can be read by /insert/* handlers; "+ - "see https://docs.victoriametrics.com/victorialogs/faq/#what-length-a-log-record-is-expected-to-have") - - // MaxFieldsPerLine is the maximum number of fields per line for /insert/* handlers - MaxFieldsPerLine = flag.Int("insert.maxFieldsPerLine", 1000, "The maximum number of log fields per line, which can be read by /insert/* handlers; "+ - "see https://docs.victoriametrics.com/victorialogs/faq/#how-many-fields-a-single-log-entry-may-contain") -) diff --git a/app/vlinsert/insertutil/line_reader.go b/app/vlinsert/insertutil/line_reader.go deleted file mode 100644 index 8653629205..0000000000 --- a/app/vlinsert/insertutil/line_reader.go +++ /dev/null @@ -1,158 +0,0 @@ -package insertutil - -import ( - "bytes" - "errors" - "fmt" - "io" - - "github.com/VictoriaMetrics/metrics" - - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/slicesutil" -) - -// LineReader reads newline-delimited lines from the underlying reader -type LineReader struct { - // Line contains the next line read after the call to NextLine - // - // The Line contents is valid until the next call to NextLine. - Line []byte - - // name is the LineReader name - name string - - // r is the underlying reader to read data from - r io.Reader - - // buf is a buffer for reading the next line - buf []byte - - // bufOffset is the offset at buf to read the next line from - bufOffset int - - // err is the last error when reading data from r - err error - - // eofReached is set to true when all the data is read from r - eofReached bool -} - -// NewLineReader returns LineReader for r. -func NewLineReader(name string, r io.Reader) *LineReader { - return &LineReader{ - name: name, - r: r, - } -} - -// NextLine reads the next line from the underlying reader. -// -// It returns true if the next line is successfully read into Line. -// If the line length exceeds MaxLineSizeBytes, then this line is skipped -// and an empty line is returned instead. -// -// If false is returned, then no more lines left to read from r. -// Check for Err in this case. -func (lr *LineReader) NextLine() bool { - for { - lr.Line = nil - if lr.bufOffset >= len(lr.buf) { - if lr.err != nil || lr.eofReached { - return false - } - if !lr.readMoreData() { - return false - } - if lr.bufOffset >= len(lr.buf) && lr.eofReached { - return false - } - } - - buf := lr.buf[lr.bufOffset:] - if n := bytes.IndexByte(buf, '\n'); n >= 0 { - lr.Line = buf[:n] - lr.bufOffset += n + 1 - return true - } - if lr.eofReached { - lr.Line = buf - lr.bufOffset += len(buf) - return true - } - if !lr.readMoreData() { - return false - } - } -} - -// Err returns the last error after NextLine call. -func (lr *LineReader) Err() error { - if lr.err == nil { - return nil - } - return fmt.Errorf("%s: %s", lr.name, lr.err) -} - -func (lr *LineReader) readMoreData() bool { - if lr.bufOffset > 0 { - lr.buf = append(lr.buf[:0], lr.buf[lr.bufOffset:]...) - lr.bufOffset = 0 - } - - bufLen := len(lr.buf) - if bufLen >= MaxLineSizeBytes.IntN() { - ok, skippedBytes := lr.skipUntilNextLine() - logger.Warnf("%s: the line length exceeds -insert.maxLineSizeBytes=%d; skipping it; total skipped bytes=%d", - lr.name, MaxLineSizeBytes.IntN(), skippedBytes) - tooLongLinesSkipped.Inc() - return ok - } - - lr.buf = slicesutil.SetLength(lr.buf, MaxLineSizeBytes.IntN()) - n, err := lr.r.Read(lr.buf[bufLen:]) - lr.buf = lr.buf[:bufLen+n] - if err != nil { - if errors.Is(err, io.EOF) { - lr.eofReached = true - return true - } - lr.err = fmt.Errorf("cannot read the next line: %s", err) - } - return n > 0 -} - -var tooLongLinesSkipped = metrics.NewCounter("vl_too_long_lines_skipped_total") - -func (lr *LineReader) skipUntilNextLine() (bool, int) { - - // Initialize skipped bytes count with MaxLineSizeBytes because - // we've already read that many bytes without encountering a newline, - // indicating the line size exceeds the maximum allowed limit. - skipSizeBytes := MaxLineSizeBytes.IntN() - - for { - lr.buf = slicesutil.SetLength(lr.buf, MaxLineSizeBytes.IntN()) - n, err := lr.r.Read(lr.buf) - skipSizeBytes += n - lr.buf = lr.buf[:n] - if err != nil { - if errors.Is(err, io.EOF) { - lr.eofReached = true - lr.buf = lr.buf[:0] - return true, skipSizeBytes - } - lr.err = fmt.Errorf("cannot skip the current line: %s", err) - return false, skipSizeBytes - } - if n := bytes.IndexByte(lr.buf, '\n'); n >= 0 { - // Include skipped bytes before \n, including the newline itself. - skipSizeBytes += n + 1 - len(lr.buf) - // Include \n in the buf, so too long line is replaced with an empty line. - // This is needed for maintaining synchorinzation consistency between lines - // in protocols such as Elasticsearch bulk import. - lr.buf = append(lr.buf[:0], lr.buf[n:]...) - return true, skipSizeBytes - } - } -} diff --git a/app/vlinsert/insertutil/line_reader_test.go b/app/vlinsert/insertutil/line_reader_test.go deleted file mode 100644 index bced3b894b..0000000000 --- a/app/vlinsert/insertutil/line_reader_test.go +++ /dev/null @@ -1,164 +0,0 @@ -package insertutil - -import ( - "bytes" - "fmt" - "io" - "reflect" - "testing" -) - -func TestLineReader_Success(t *testing.T) { - f := func(data string, linesExpected []string) { - t.Helper() - - r := bytes.NewBufferString(data) - lr := NewLineReader("foo", r) - var lines []string - for lr.NextLine() { - lines = append(lines, string(lr.Line)) - } - if err := lr.Err(); err != nil { - t.Fatalf("unexpected error: %s", err) - } - if lr.NextLine() { - t.Fatalf("expecting error on the second call to NextLine()") - } - if len(lr.Line) > 0 { - t.Fatalf("unexpected non-empty line after failed NextLine(): %q", lr.Line) - } - if !reflect.DeepEqual(lines, linesExpected) { - t.Fatalf("unexpected lines\ngot\n%q\nwant\n%q", lines, linesExpected) - } - } - - f("", nil) - f("\n", []string{""}) - f("\n\n", []string{"", ""}) - f("foo", []string{"foo"}) - f("foo\n", []string{"foo"}) - f("\nfoo", []string{"", "foo"}) - f("foo\n\n", []string{"foo", ""}) - f("foo\nbar", []string{"foo", "bar"}) - f("foo\nbar\n", []string{"foo", "bar"}) - f("\nfoo\n\nbar\n\n", []string{"", "foo", "", "bar", ""}) -} - -func TestLineReader_SkipUntilNextLine(t *testing.T) { - f := func(data string, linesExpected []string) { - t.Helper() - - r := bytes.NewBufferString(data) - lr := NewLineReader("foo", r) - var lines []string - for lr.NextLine() { - lines = append(lines, string(lr.Line)) - } - if err := lr.Err(); err != nil { - t.Fatalf("unexpected error for data=%q: %s", data, err) - } - if lr.NextLine() { - t.Fatalf("expecting error on the second call to NextLine()") - } - if !reflect.DeepEqual(lines, linesExpected) { - t.Fatalf("unexpected lines for data=%q\ngot\n%q\nwant\n%q", data, lines, linesExpected) - } - } - - for _, overflow := range []int{0, 100, MaxLineSizeBytes.IntN(), MaxLineSizeBytes.IntN() + 1, 2 * MaxLineSizeBytes.IntN()} { - longLineLen := MaxLineSizeBytes.IntN() + overflow - longLine := string(make([]byte, longLineLen)) - - // Single long line - data := longLine - f(data, nil) - - // Multiple long lines - data = longLine + "\n" + longLine - f(data, []string{""}) - - data = longLine + "\n" + longLine + "\n" - f(data, []string{"", ""}) - - // Long line in the middle - data = "foo\n" + longLine + "\nbar" - f(data, []string{"foo", "", "bar"}) - - // Multiple long lines in the middle - data = "foo\n" + longLine + "\n" + longLine + "\nbar" - f(data, []string{"foo", "", "", "bar"}) - - // Long line in the end - data = "foo\n" + longLine - f(data, []string{"foo"}) - - // Long line in the end - data = "foo\n" + longLine + "\n" - f(data, []string{"foo", ""}) - } -} - -func TestLineReader_Failure(t *testing.T) { - f := func(data string, linesExpected []string) { - t.Helper() - - fr := &failureReader{ - r: bytes.NewBufferString(data), - } - lr := NewLineReader("foo", fr) - var lines []string - for lr.NextLine() { - lines = append(lines, string(lr.Line)) - } - if err := lr.Err(); err == nil { - t.Fatalf("expecting non-nil error") - } - if lr.NextLine() { - t.Fatalf("expecting error on the second call to NextLine()") - } - if err := lr.Err(); err == nil { - t.Fatalf("expecting non-nil error on the second call") - } - if !reflect.DeepEqual(lines, linesExpected) { - t.Fatalf("unexpected lines\ngot\n%q\nwant\n%q", lines, linesExpected) - } - } - - f("", nil) - f("foo", nil) - f("foo\n", []string{"foo"}) - f("\n", []string{""}) - f("foo\nbar", []string{"foo"}) - f("foo\nbar\n", []string{"foo", "bar"}) - f("\nfoo\nbar\n\n", []string{"", "foo", "bar", ""}) - - // long line - longLineLen := MaxLineSizeBytes.IntN() - for _, overflow := range []int{0, 100, MaxLineSizeBytes.IntN(), MaxLineSizeBytes.IntN() + 1, 2 * MaxLineSizeBytes.IntN()} { - longLine := string(make([]byte, longLineLen+overflow)) - - data := longLine - f(data, nil) - - data = "foo\n" + longLine - f(data, []string{"foo"}) - - data = longLine + "\nfoo" - f(data, []string{""}) - - data = longLine + "\nfoo\n" - f(data, []string{"", "foo"}) - } -} - -type failureReader struct { - r io.Reader -} - -func (r *failureReader) Read(p []byte) (int, error) { - n, _ := r.r.Read(p) - if n > 0 { - return n, nil - } - return 0, fmt.Errorf("some error") -} diff --git a/app/vlinsert/insertutil/testutils.go b/app/vlinsert/insertutil/testutils.go deleted file mode 100644 index 3ca6fe8d54..0000000000 --- a/app/vlinsert/insertutil/testutils.go +++ /dev/null @@ -1,56 +0,0 @@ -package insertutil - -import ( - "fmt" - "reflect" - "strings" - - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" -) - -// TestLogMessageProcessor implements LogMessageProcessor for testing. -type TestLogMessageProcessor struct { - timestamps []int64 - rows []string -} - -// AddRow adds row with the given timestamp and fields to tlp -func (tlp *TestLogMessageProcessor) AddRow(timestamp int64, fields, streamFields []logstorage.Field) { - if streamFields != nil { - panic(fmt.Errorf("BUG: streamFields must be nil; got %v", streamFields)) - } - tlp.timestamps = append(tlp.timestamps, timestamp) - tlp.rows = append(tlp.rows, string(logstorage.MarshalFieldsToJSON(nil, fields))) -} - -// MustClose closes tlp. -func (tlp *TestLogMessageProcessor) MustClose() { -} - -// Verify verifies the number of rows, timestamps and results after AddRow calls. -func (tlp *TestLogMessageProcessor) Verify(timestampsExpected []int64, resultExpected string) error { - result := strings.Join(tlp.rows, "\n") - if len(tlp.rows) != len(timestampsExpected) { - return fmt.Errorf("unexpected rows read; got %d; want %d;\nrows read:\n%s\nrows wanted\n%s", len(tlp.rows), len(timestampsExpected), result, resultExpected) - } - - if !reflect.DeepEqual(tlp.timestamps, timestampsExpected) { - return fmt.Errorf("unexpected timestamps;\ngot\n%d\nwant\n%d", tlp.timestamps, timestampsExpected) - } - if result != resultExpected { - return fmt.Errorf("unexpected result;\ngot\n%s\nwant\n%s", result, resultExpected) - } - - return nil -} - -// BenchmarkLogMessageProcessor implements LogMessageProcessor for benchmarks. -type BenchmarkLogMessageProcessor struct{} - -// AddRow implements LogMessageProcessor interface. -func (blp *BenchmarkLogMessageProcessor) AddRow(_ int64, _, _ []logstorage.Field) { -} - -// MustClose implements LogMessageProcessor interface. -func (blp *BenchmarkLogMessageProcessor) MustClose() { -} diff --git a/app/vlinsert/insertutil/timestamp.go b/app/vlinsert/insertutil/timestamp.go deleted file mode 100644 index cb05d3cbbd..0000000000 --- a/app/vlinsert/insertutil/timestamp.go +++ /dev/null @@ -1,57 +0,0 @@ -package insertutil - -import ( - "fmt" - "time" - - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/timeutil" -) - -// ExtractTimestampFromFields extracts timestamp in nanoseconds from the first field the name from timeFields at fields. -// -// The value for the corresponding timeFields is set to empty string after returning from the function, -// so it could be ignored during data ingestion. -// -// The current timestamp is returned if fields do not contain a field with timeField name or if the timeField value is empty. -func ExtractTimestampFromFields(timeFields []string, fields []logstorage.Field) (int64, error) { - for _, timeField := range timeFields { - for i := range fields { - f := &fields[i] - if f.Name != timeField { - continue - } - nsecs, err := parseTimestamp(f.Value) - if err != nil { - return 0, fmt.Errorf("cannot parse timestamp from field %q: %s", f.Name, err) - } - f.Value = "" - if nsecs == 0 { - nsecs = time.Now().UnixNano() - } - return nsecs, nil - } - } - return time.Now().UnixNano(), nil -} - -func parseTimestamp(s string) (int64, error) { - // "-" is a nil timestamp value, if the syslog - // application is incapable of obtaining system time - // https://datatracker.ietf.org/doc/html/rfc5424#section-6.2.3 - if s == "" || s == "0" || s == "-" { - return time.Now().UnixNano(), nil - } - if len(s) <= len("YYYY") || s[len("YYYY")] != '-' { - nsecs, ok := timeutil.TryParseUnixTimestamp(s) - if !ok { - return 0, fmt.Errorf("cannot parse unix timestamp %q", s) - } - return nsecs, nil - } - nsecs, ok := logstorage.TryParseTimestampRFC3339Nano(s) - if !ok { - return 0, fmt.Errorf("cannot unmarshal rfc3339 timestamp %q", s) - } - return nsecs, nil -} diff --git a/app/vlinsert/insertutil/timestamp_test.go b/app/vlinsert/insertutil/timestamp_test.go deleted file mode 100644 index 3cf2081d07..0000000000 --- a/app/vlinsert/insertutil/timestamp_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package insertutil - -import ( - "testing" - - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" -) - -func TestExtractTimestampFromFields_Success(t *testing.T) { - f := func(timeField string, fields []logstorage.Field, nsecsExpected int64) { - t.Helper() - - nsecs, err := ExtractTimestampFromFields([]string{timeField}, fields) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } - if nsecs != nsecsExpected { - t.Fatalf("unexpected nsecs; got %d; want %d", nsecs, nsecsExpected) - } - - for _, f := range fields { - if f.Name == timeField { - if f.Value != "" { - t.Fatalf("unexpected value for field %s; got %q; want %q", timeField, f.Value, "") - } - } - } - } - - // UTC time - f("time", []logstorage.Field{ - {Name: "foo", Value: "bar"}, - {Name: "time", Value: "2024-06-18T23:37:20Z"}, - }, 1718753840000000000) - - // Time with timezone - f("time", []logstorage.Field{ - {Name: "foo", Value: "bar"}, - {Name: "time", Value: "2024-06-18T23:37:20+08:00"}, - }, 1718725040000000000) - - // SQL datetime format - f("time", []logstorage.Field{ - {Name: "foo", Value: "bar"}, - {Name: "time", Value: "2024-06-18 23:37:20.123-05:30"}, - }, 1718773640123000000) - - // Time with nanosecond precision - f("time", []logstorage.Field{ - {Name: "time", Value: "2024-06-18T23:37:20.123456789-05:30"}, - {Name: "foo", Value: "bar"}, - }, 1718773640123456789) - - // Unix timestamp in nanoseconds - f("time", []logstorage.Field{ - {Name: "foo", Value: "bar"}, - {Name: "time", Value: "1718773640123456789"}, - }, 1718773640123456789) - - // Unix timestamp in microseconds - f("time", []logstorage.Field{ - {Name: "foo", Value: "bar"}, - {Name: "time", Value: "1718773640123456"}, - }, 1718773640123456000) - - // Unix timestamp in milliseconds - f("time", []logstorage.Field{ - {Name: "foo", Value: "bar"}, - {Name: "time", Value: "1718773640123"}, - }, 1718773640123000000) - - // Unix timestamp in seconds - f("time", []logstorage.Field{ - {Name: "foo", Value: "bar"}, - {Name: "time", Value: "1718773640"}, - }, 1718773640000000000) -} - -func TestExtractTimestampFromFields_Now(t *testing.T) { - f := func(timeField string, fields []logstorage.Field) { - t.Helper() - - nsecs, err := ExtractTimestampFromFields([]string{timeField}, fields) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } - if nsecs < 1 { - t.Fatalf("expected generated timestamp, got error: %s", err) - } - } - - // RFC5424 allows `-` for nil timestamp (log ingestion time) - f("time", []logstorage.Field{ - {Name: "time", Value: "-"}, - }) - - f("time", []logstorage.Field{ - {Name: "time", Value: ""}, - }) - - f("time", []logstorage.Field{ - {Name: "time", Value: "0"}, - }) -} - -func TestExtractTimestampFromFields_Error(t *testing.T) { - f := func(s string) { - t.Helper() - - fields := []logstorage.Field{ - {Name: "time", Value: s}, - } - nsecs, err := ExtractTimestampFromFields([]string{"time"}, fields) - if err == nil { - t.Fatalf("expecting non-nil error") - } - if nsecs != 0 { - t.Fatalf("unexpected nsecs; got %d; want %d", nsecs, 0) - } - } - - // invalid time - f("foobar") - - // incomplete time - f("2024-06-18") - f("2024-06-18T23:37") -} diff --git a/app/vlinsert/internalinsert/internalinsert.go b/app/vlinsert/internalinsert/internalinsert.go deleted file mode 100644 index e4f31f1a1b..0000000000 --- a/app/vlinsert/internalinsert/internalinsert.go +++ /dev/null @@ -1,88 +0,0 @@ -package internalinsert - -import ( - "fmt" - "net/http" - "time" - - "github.com/VictoriaMetrics/metrics" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlstorage/netinsert" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/protoparserutil" -) - -var ( - maxRequestSize = flagutil.NewBytes("internalinsert.maxRequestSize", 64*1024*1024, "The maximum size in bytes of a single request, which can be accepted at /internal/insert HTTP endpoint") -) - -// RequestHandler processes /internal/insert requests. -func RequestHandler(w http.ResponseWriter, r *http.Request) { - startTime := time.Now() - if r.Method != "POST" { - w.WriteHeader(http.StatusMethodNotAllowed) - return - } - version := r.FormValue("version") - if version != netinsert.ProtocolVersion { - httpserver.Errorf(w, r, "unsupported protocol version=%q; want %q", version, netinsert.ProtocolVersion) - return - } - - requestsTotal.Inc() - - cp, err := insertutil.GetCommonParams(r) - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - if err := insertutil.CanWriteData(); err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - - encoding := r.Header.Get("Content-Encoding") - err = protoparserutil.ReadUncompressedData(r.Body, encoding, maxRequestSize, func(data []byte) error { - lmp := cp.NewLogMessageProcessor("internalinsert", false) - irp := lmp.(insertutil.InsertRowProcessor) - err := parseData(irp, data) - lmp.MustClose() - return err - }) - if err != nil { - errorsTotal.Inc() - httpserver.Errorf(w, r, "cannot parse internal insert request: %s", err) - return - } - - requestDuration.UpdateDuration(startTime) -} - -func parseData(irp insertutil.InsertRowProcessor, data []byte) error { - r := logstorage.GetInsertRow() - src := data - i := 0 - for len(src) > 0 { - tail, err := r.UnmarshalInplace(src) - if err != nil { - return fmt.Errorf("cannot parse row #%d: %s", i, err) - } - src = tail - i++ - - irp.AddInsertRow(r) - } - logstorage.PutInsertRow(r) - - return nil -} - -var ( - requestsTotal = metrics.NewCounter(`vl_http_requests_total{path="/internal/insert"}`) - errorsTotal = metrics.NewCounter(`vl_http_errors_total{path="/internal/insert"}`) - - requestDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/internal/insert"}`) -) diff --git a/app/vlinsert/journald/journald.go b/app/vlinsert/journald/journald.go deleted file mode 100644 index 931686d875..0000000000 --- a/app/vlinsert/journald/journald.go +++ /dev/null @@ -1,377 +0,0 @@ -package journald - -import ( - "bytes" - "encoding/binary" - "errors" - "flag" - "fmt" - "io" - "net/http" - "slices" - "strconv" - "strings" - "sync" - "time" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/protoparserutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/writeconcurrencylimiter" - "github.com/VictoriaMetrics/metrics" -) - -// See https://github.com/systemd/systemd/blob/main/src/libsystemd/sd-journal/journal-file.c#L1703 -const maxFieldNameLen = 64 - -var ( - journaldStreamFields = flagutil.NewArrayString("journald.streamFields", "Comma-separated list of fields to use as log stream fields for logs ingested over journald protocol. "+ - "See https://docs.victoriametrics.com/victorialogs/data-ingestion/journald/#stream-fields") - journaldIgnoreFields = flagutil.NewArrayString("journald.ignoreFields", "Comma-separated list of fields to ignore for logs ingested over journald protocol. "+ - "See https://docs.victoriametrics.com/victorialogs/data-ingestion/journald/#dropping-fields") - journaldTimeField = flag.String("journald.timeField", "__REALTIME_TIMESTAMP", "Field to use as a log timestamp for logs ingested via journald protocol. "+ - "See https://docs.victoriametrics.com/victorialogs/data-ingestion/journald/#time-field") - journaldTenantID = flag.String("journald.tenantID", "0:0", "TenantID for logs ingested via the Journald endpoint. "+ - "See https://docs.victoriametrics.com/victorialogs/data-ingestion/journald/#multitenancy") - journaldIncludeEntryMetadata = flag.Bool("journald.includeEntryMetadata", false, "Include Journald fields with double underscore prefixes") -) - -func getCommonParams(r *http.Request) (*insertutil.CommonParams, error) { - cp, err := insertutil.GetCommonParams(r) - if err != nil { - return nil, err - } - if cp.TenantID.AccountID == 0 && cp.TenantID.ProjectID == 0 { - tenantID, err := logstorage.ParseTenantID(*journaldTenantID) - if err != nil { - return nil, fmt.Errorf("cannot parse -journald.tenantID=%q for journald: %w", *journaldTenantID, err) - } - cp.TenantID = tenantID - } - - if !cp.IsTimeFieldSet { - cp.TimeFields = []string{*journaldTimeField} - } - if len(cp.StreamFields) == 0 { - cp.StreamFields = getStreamFields() - } - if len(cp.IgnoreFields) == 0 { - cp.IgnoreFields = *journaldIgnoreFields - } - cp.MsgFields = []string{"MESSAGE"} - return cp, nil -} - -func getStreamFields() []string { - if len(*journaldStreamFields) > 0 { - return *journaldStreamFields - } - return defaultStreamFields -} - -var defaultStreamFields = []string{ - "_MACHINE_ID", - "_HOSTNAME", - "_SYSTEMD_UNIT", -} - -// RequestHandler processes Journald Export insert requests -func RequestHandler(path string, w http.ResponseWriter, r *http.Request) bool { - switch path { - case "/insert/journald/upload": - if r.Header.Get("Content-Type") != "application/vnd.fdo.journal" { - httpserver.Errorf(w, r, "only application/vnd.fdo.journal encoding is supported for Journald") - return true - } - handleJournald(r, w) - return true - default: - return false - } -} - -// handleJournald parses Journal binary entries -func handleJournald(r *http.Request, w http.ResponseWriter) { - startTime := time.Now() - requestsTotal.Inc() - - cp, err := getCommonParams(r) - if err != nil { - errorsTotal.Inc() - httpserver.Errorf(w, r, "cannot parse common params from request: %s", err) - return - } - - if err := insertutil.CanWriteData(); err != nil { - errorsTotal.Inc() - httpserver.Errorf(w, r, "%s", err) - return - } - - encoding := r.Header.Get("Content-Encoding") - reader, err := protoparserutil.GetUncompressedReader(r.Body, encoding) - if err != nil { - errorsTotal.Inc() - logger.Errorf("cannot decode journald request: %s", err) - return - } - - lmp := cp.NewLogMessageProcessor("journald", true) - streamName := fmt.Sprintf("remoteAddr=%s, requestURI=%q", httpserver.GetQuotedRemoteAddr(r), r.RequestURI) - err = processStreamInternal(streamName, reader, lmp, cp) - protoparserutil.PutUncompressedReader(reader) - lmp.MustClose() - if err != nil { - errorsTotal.Inc() - httpserver.Errorf(w, r, "cannot read journald protocol data: %s", err) - return - } - - // systemd starting release v258 will support compression, which starts working after negotiation: it expects supported compression - // algorithms list in Accept-Encoding response header in a format "[:][;:]" - // See https://github.com/systemd/systemd/pull/34822 - w.Header().Set("Accept-Encoding", "zstd") - - // update requestDuration only for successfully parsed requests - // There is no need in updating requestDuration for request errors, - // since their timings are usually much smaller than the timing for successful request parsing. - requestDuration.UpdateDuration(startTime) -} - -var ( - requestsTotal = metrics.NewCounter(`vl_http_requests_total{path="/insert/journald/upload"}`) - errorsTotal = metrics.NewCounter(`vl_http_errors_total{path="/insert/journald/upload"}`) - requestDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/insert/journald/upload"}`) -) - -func processStreamInternal(streamName string, r io.Reader, lmp insertutil.LogMessageProcessor, cp *insertutil.CommonParams) error { - wcr := writeconcurrencylimiter.GetReader(r) - defer writeconcurrencylimiter.PutReader(wcr) - - lr := insertutil.NewLineReader("journald", wcr) - - for { - err := readJournaldLogEntry(streamName, lr, lmp, cp) - wcr.DecConcurrency() - if err != nil { - if errors.Is(err, io.EOF) { - return nil - } - return fmt.Errorf("%s: %w", streamName, err) - } - } -} - -type fieldsBuf struct { - fields []logstorage.Field - - buf []byte - name []byte - value []byte -} - -func (fb *fieldsBuf) reset() { - fb.fields = fb.fields[:0] - fb.buf = fb.buf[:0] - fb.name = fb.name[:0] - fb.value = fb.value[:0] -} - -func (fb *fieldsBuf) addField(name, value string) { - bufLen := len(fb.buf) - fb.buf = append(fb.buf, name...) - nameCopy := bytesutil.ToUnsafeString(fb.buf[bufLen:]) - - bufLen = len(fb.buf) - fb.buf = append(fb.buf, value...) - valueCopy := bytesutil.ToUnsafeString(fb.buf[bufLen:]) - - fb.fields = append(fb.fields, logstorage.Field{ - Name: nameCopy, - Value: valueCopy, - }) -} - -func (fb *fieldsBuf) appendNextLineToValue(lr *insertutil.LineReader) error { - if !lr.NextLine() { - if err := lr.Err(); err != nil { - return err - } - return fmt.Errorf("unexpected end of stream") - } - fb.value = append(fb.value, lr.Line...) - fb.value = append(fb.value, '\n') - return nil -} - -func getFieldsBuf() *fieldsBuf { - fb := fieldsBufPool.Get() - if fb == nil { - return &fieldsBuf{} - } - return fb.(*fieldsBuf) -} - -func putFieldsBuf(fb *fieldsBuf) { - fb.reset() - fieldsBufPool.Put(fb) -} - -var fieldsBufPool sync.Pool - -// readJournaldLogEntry reads a single log entry in Journald format. -// -// See https://systemd.io/JOURNAL_EXPORT_FORMATS/#journal-export-format -func readJournaldLogEntry(streamName string, lr *insertutil.LineReader, lmp insertutil.LogMessageProcessor, cp *insertutil.CommonParams) error { - var ts int64 - var name, value string - - fb := getFieldsBuf() - defer putFieldsBuf(fb) - - if !lr.NextLine() { - if err := lr.Err(); err != nil { - return fmt.Errorf("cannot read the first field: %w", err) - } - return io.EOF - } - - for { - line := lr.Line - if len(line) == 0 { - // The end of a single log entry. Write it to the storage - if len(fb.fields) > 0 { - if ts == 0 { - ts = time.Now().UnixNano() - } - lmp.AddRow(ts, fb.fields, nil) - } - return nil - } - - // line could be either "key=value" or "key" - // according to https://systemd.io/JOURNAL_EXPORT_FORMATS/#journal-export-format - if n := bytes.IndexByte(line, '='); n >= 0 { - // line = "key=value" - fb.name = append(fb.name[:0], line[:n]...) - name = bytesutil.ToUnsafeString(fb.name) - - fb.value = append(fb.value[:0], line[n+1:]...) - value = bytesutil.ToUnsafeString(fb.value) - } else { - // line = "key" - // Parse the binary-encoded value from the next line according to "key\nvalue\n" format - fb.name = append(fb.name[:0], line...) - name = bytesutil.ToUnsafeString(fb.name) - - fb.value = fb.value[:0] - for len(fb.value) < 8 { - if err := fb.appendNextLineToValue(lr); err != nil { - return fmt.Errorf("cannot read value size: %w", err) - } - } - size := binary.LittleEndian.Uint64(fb.value[:8]) - - // Read the value until its length exceeds the given size - the last char in the read value will always be '\n' - // because it is appended by appendNextLineToValue(). - for uint64(len(fb.value[8:])) <= size { - if err := fb.appendNextLineToValue(lr); err != nil { - return fmt.Errorf("cannot read %q value with size %d bytes; read only %d bytes: %w", fb.name, size, len(fb.value[8:]), err) - } - } - value = bytesutil.ToUnsafeString(fb.value[8 : len(fb.value)-1]) - if uint64(len(value)) != size { - return fmt.Errorf("unexpected %q value size; got %d bytes; want %d bytes; value: %q", fb.name, len(value), size, value) - } - } - - if !lr.NextLine() { - if err := lr.Err(); err != nil { - return fmt.Errorf("cannot read the next log field: %w", err) - } - - // add the last log field below before the return - } - - if len(name) > maxFieldNameLen { - logger.Errorf("%s: field name size should not exceed %d bytes; got %d bytes: %q; skipping this field", streamName, maxFieldNameLen, len(name), name) - continue - } - if !isValidFieldName(name) { - logger.Errorf("%s: invalid field name %q; it must consist of `A-Z0-9_` chars and must start from non-digit char; skipping this field", streamName, name) - continue - } - - if slices.Contains(cp.TimeFields, name) { - t, err := strconv.ParseInt(value, 10, 64) - if err != nil { - logger.Errorf("%s: cannot parse timestamp from the field %q: %w; using the current timestamp", streamName, name, err) - ts = 0 - } else { - // Convert journald microsecond timestamp to nanoseconds - ts = t * 1e3 - } - continue - } - - if slices.Contains(cp.MsgFields, name) { - name = "_msg" - } - - if name == "PRIORITY" { - priority := journaldPriorityToLevel(value) - fb.addField("level", priority) - } - - if !strings.HasPrefix(name, "__") || *journaldIncludeEntryMetadata { - fb.addField(name, value) - } - } -} - -func journaldPriorityToLevel(priority string) string { - // See https://wiki.archlinux.org/title/Systemd/Journal#Priority_level - // and https://grafana.com/docs/grafana/latest/explore/logs-integration/#log-level - switch priority { - case "0": - return "emerg" - case "1": - return "alert" - case "2": - return "critical" - case "3": - return "error" - case "4": - return "warning" - case "5": - return "notice" - case "6": - return "info" - case "7": - return "debug" - default: - return priority - } -} - -func isValidFieldName(s string) bool { - if len(s) == 0 { - return false - } - c := s[0] - if !(c >= 'A' && c <= 'Z' || c == '_') { - return false - } - - for i := 1; i < len(s); i++ { - c := s[i] - if !(c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '_') { - return false - } - } - return true -} diff --git a/app/vlinsert/journald/journald_test.go b/app/vlinsert/journald/journald_test.go deleted file mode 100644 index f3254e9e80..0000000000 --- a/app/vlinsert/journald/journald_test.go +++ /dev/null @@ -1,166 +0,0 @@ -package journald - -import ( - "bytes" - "net/http" - "testing" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" -) - -func TestIsValidFieldName(t *testing.T) { - f := func(name string, resultExpected bool) { - t.Helper() - - result := isValidFieldName(name) - if result != resultExpected { - t.Fatalf("unexpected result for isValidJournaldFieldName(%q); got %v; want %v", name, result, resultExpected) - } - } - - f("", false) - f("a", false) - f("1", false) - f("_", true) - f("X", true) - f("Xa", false) - f("X_343", true) - f("X_0123456789_AZ", true) - f("SDDFD sdf", false) -} - -func TestGetCommonParams_TimeField(t *testing.T) { - f := func(timeFieldHeader, expectedTimeField string) { - t.Helper() - - req, err := http.NewRequest("POST", "/insert/journald/upload", nil) - if err != nil { - t.Fatalf("unexpected error creating request: %s", err) - } - - if timeFieldHeader != "" { - req.Header.Set("VL-Time-Field", timeFieldHeader) - } - - cp, err := getCommonParams(req) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } - - if len(cp.TimeFields) != 1 || cp.TimeFields[0] != expectedTimeField { - t.Fatalf("unexpected TimeFields; got %v; want [%s]", cp.TimeFields, expectedTimeField) - } - } - - // Test default behavior - when no custom time field is specified, journald uses __REALTIME_TIMESTAMP - f("", "__REALTIME_TIMESTAMP") - - // Test custom time field - when a custom time field is specified via HTTP header, it's respected - f("custom_time", "custom_time") -} - -func TestPushJournald_Success(t *testing.T) { - f := func(src string, timestampsExpected []int64, resultExpected string) { - t.Helper() - - tlp := &insertutil.TestLogMessageProcessor{} - - r, err := http.NewRequest("GET", "https://foo.bar/baz", nil) - if err != nil { - t.Fatalf("cannot create request: %s", err) - } - cp, err := getCommonParams(r) - if err != nil { - t.Fatalf("cannot create commonParams: %s", err) - } - - buf := bytes.NewBufferString(src) - if err := processStreamInternal("test", buf, tlp, cp); err != nil { - t.Fatalf("unexpected error: %s", err) - } - - if err := tlp.Verify(timestampsExpected, resultExpected); err != nil { - t.Fatal(err) - } - } - - // Single event - f("__REALTIME_TIMESTAMP=91723819283\nMESSAGE=Test message\n\n", - []int64{91723819283000}, - "{\"_msg\":\"Test message\"}", - ) - - // Multiple events - f("__REALTIME_TIMESTAMP=91723819283\nPRIORITY=3\nMESSAGE=Test message\n\n__REALTIME_TIMESTAMP=91723819284\nMESSAGE=Test message2\n", - []int64{91723819283000, 91723819284000}, - "{\"level\":\"error\",\"PRIORITY\":\"3\",\"_msg\":\"Test message\"}\n{\"_msg\":\"Test message2\"}", - ) - - // Parse binary data - f("__CURSOR=s=e0afe8412a6a49d2bfcf66aa7927b588;i=1f06;b=f778b6e2f7584a77b991a2366612a7b5;m=300bdfd420;t=62526e1182354;x=930dc44b370963b7\nE=JobStateChanged\n__REALTIME_TIMESTAMP=1729698775704404\n__MONOTONIC_TIMESTAMP=206357648416\n__SEQNUM=7942\n__SEQNUM_ID=e0afe8412a6a49d2bfcf66aa7927b588\n_BOOT_ID=f778b6e2f7584a77b991a2366612a7b5\n_UID=0\n_GID=0\n_MACHINE_ID=a4a970370c30a925df02a13c67167847\n_HOSTNAME=ecd5e4555787\n_RUNTIME_SCOPE=system\n_TRANSPORT=journal\n_CAP_EFFECTIVE=1ffffffffff\n_SYSTEMD_CGROUP=/init.scope\n_SYSTEMD_UNIT=init.scope\n_SYSTEMD_SLICE=-.slice\nCODE_FILE=\nCODE_LINE=1\nCODE_FUNC=\nSYSLOG_IDENTIFIER=python3\n_COMM=python3\n_EXE=/usr/bin/python3.12\n_CMDLINE=python3\nMESSAGE\n\x13\x00\x00\x00\x00\x00\x00\x00foo\nbar\n\n\nasda\nasda\n_PID=2763\n_SOURCE_REALTIME_TIMESTAMP=1729698775704375\n\n", - []int64{1729698775704404000}, - "{\"E\":\"JobStateChanged\",\"_BOOT_ID\":\"f778b6e2f7584a77b991a2366612a7b5\",\"_UID\":\"0\",\"_GID\":\"0\",\"_MACHINE_ID\":\"a4a970370c30a925df02a13c67167847\",\"_HOSTNAME\":\"ecd5e4555787\",\"_RUNTIME_SCOPE\":\"system\",\"_TRANSPORT\":\"journal\",\"_CAP_EFFECTIVE\":\"1ffffffffff\",\"_SYSTEMD_CGROUP\":\"/init.scope\",\"_SYSTEMD_UNIT\":\"init.scope\",\"_SYSTEMD_SLICE\":\"-.slice\",\"CODE_FILE\":\"\\u003cstdin>\",\"CODE_LINE\":\"1\",\"CODE_FUNC\":\"\\u003cmodule>\",\"SYSLOG_IDENTIFIER\":\"python3\",\"_COMM\":\"python3\",\"_EXE\":\"/usr/bin/python3.12\",\"_CMDLINE\":\"python3\",\"_msg\":\"foo\\nbar\\n\\n\\nasda\\nasda\",\"_PID\":\"2763\",\"_SOURCE_REALTIME_TIMESTAMP\":\"1729698775704375\"}", - ) - - // Parse binary data with trailing newline - f("__REALTIME_TIMESTAMP=1729698775704404\n_CMDLINE=python3\nMESSAGE\n\x14\x00\x00\x00\x00\x00\x00\x00foo\nbar\n\n\nasda\nasda\n\n_PID=2763\n\n", - []int64{1729698775704404000}, - `{"_CMDLINE":"python3","_msg":"foo\nbar\n\n\nasda\nasda\n","_PID":"2763"}`, - ) - f("__REALTIME_TIMESTAMP=1729698775704404\n_CMDLINE=python3\nMESSAGE\n\x00\x00\x00\x00\x00\x00\x00\x00\n_PID=2763\n\n", - []int64{1729698775704404000}, - `{"_CMDLINE":"python3","_PID":"2763"}`, - ) - f("__REALTIME_TIMESTAMP=1729698775704404\n_CMDLINE=python3\nMESSAGE\n\x0A\x00\x00\x00\x00\x00\x00\x00123456789\n\n_PID=2763\n\n", - []int64{1729698775704404000}, - `{"_CMDLINE":"python3","_msg":"123456789\n","_PID":"2763"}`, - ) - f("__REALTIME_TIMESTAMP=1729698775704404\n_CMDLINE=python3\nMESSAGE\n\x0A\x00\x00\x00\x00\x00\x00\x001234567890\n_PID=2763\n\n", - []int64{1729698775704404000}, - `{"_CMDLINE":"python3","_msg":"1234567890","_PID":"2763"}`, - ) - - // Empty field name must be ignored - f("__REALTIME_TIMESTAMP=91723819283\na=b\n=Test message", nil, "") - f("__REALTIME_TIMESTAMP=91723819284\nMESSAGE=Test message2\n\n__REALTIME_TIMESTAMP=91723819283\n=Test message\n", []int64{91723819284000}, `{"_msg":"Test message2"}`) - - // field name starting with number must be ignored - f("__REALTIME_TIMESTAMP=91723819283\n1incorrect=Test message\n\n__REALTIME_TIMESTAMP=91723819284\nMESSAGE=Test message2\n\n", []int64{91723819284000}, `{"_msg":"Test message2"}`) - - // field name exceeding 64 bytes limit must be ignored - f("__REALTIME_TIMESTAMP=91723819283\ntoolooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongcorrecooooooooooooong=Test message\n", nil, "") - - // field name with invalid chars must be ignored - f("__REALTIME_TIMESTAMP=91723819283\nbadC!@$!@$as=Test message\n", nil, "") -} - -func TestPushJournald_Failure(t *testing.T) { - f := func(data string) { - t.Helper() - - tlp := &insertutil.TestLogMessageProcessor{} - - r, err := http.NewRequest("GET", "https://foo.bar/baz", nil) - if err != nil { - t.Fatalf("cannot create request: %s", err) - } - cp, err := getCommonParams(r) - if err != nil { - t.Fatalf("cannot create commonParams: %s", err) - } - - buf := bytes.NewBufferString(data) - if err := processStreamInternal("test", buf, tlp, cp); err == nil { - t.Fatalf("expecting non-nil error") - } - } - - // too short binary encoded message - f("__CURSOR=s=e0afe8412a6a49d2bfcf66aa7927b588;i=1f06;b=f778b6e2f7584a77b991a2366612a7b5;m=300bdfd420;t=62526e1182354;x=930dc44b370963b7\n__REALTIME_TIMESTAMP=1729698775704404\nMESSAGE\n\x13\x00\x00\x00\x00\x00\x00\x00foo\nbar\n\n\nasdaasd") - f("__REALTIME_TIMESTAMP=1729698775704404\n_CMDLINE=python3\nMESSAGE\n\x00\x00\x00\x00\x00\x00\x00\x00_PID=2763\n\n") - f("__REALTIME_TIMESTAMP=1729698775704404\n_CMDLINE=python3\nMESSAGE\n\x0A\x00\x00\x00\x00\x00\x00\x001234567890_PID=2763\n\n") - f("__REALTIME_TIMESTAMP=1729698775704404\n_CMDLINE=python3\nMESSAGE\n\x0A\x00\x00\x00\x00\x00\x00\x00123456789\n_PID=2763\n\n") - - // too long binary encoded message - f("__CURSOR=s=e0afe8412a6a49d2bfcf66aa7927b588;i=1f06;b=f778b6e2f7584a77b991a2366612a7b5;m=300bdfd420;t=62526e1182354;x=930dc44b370963b7\n__REALTIME_TIMESTAMP=1729698775704404\nMESSAGE\n\x13\x00\x00\x00\x00\x00\x00\x00foo\nbar\n\n\nasdaasdakljlsfd") -} diff --git a/app/vlinsert/journald/journald_timing_test.go b/app/vlinsert/journald/journald_timing_test.go deleted file mode 100644 index 94d40cd4d9..0000000000 --- a/app/vlinsert/journald/journald_timing_test.go +++ /dev/null @@ -1,82 +0,0 @@ -package journald - -import ( - "bytes" - "encoding/binary" - "fmt" - "strings" - "testing" - "time" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" -) - -func BenchmarkIsValidFieldName(b *testing.B) { - b.ReportAllocs() - b.SetBytes(int64(len(benchmarkFields))) - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - for _, field := range benchmarkFields { - if !isValidFieldName(field) { - panic(fmt.Errorf("cannot validate field %q", field)) - } - } - } - }) -} - -var benchmarkFields = strings.Split( - "E,_BOOT_ID,_UID,_GID,_MACHINE_ID,_HOSTNAME,_RUNTIME_SCOPE,_TRANSPORT,_CAP_EFFECTIVE,_SYSTEMD_CGROUP,_SYSTEMD_UNIT,"+ - "_SYSTEMD_SLICE,CODE_FILE,CODE_LINE,CODE_FUNC,SYSLOG_IDENTIFIER,_COMM,_EXE,_CMDLINE,MESSAGE,_PID,_SOURCE_REALTIME_TIMESTAMP,_REALTIME_TIMESTAMP", - ",") - -func BenchmarkPushJournaldPerformance(b *testing.B) { - cp := &insertutil.CommonParams{ - TimeFields: []string{"__REALTIME_TIMESTAMP"}, - MsgFields: []string{"MESSAGE"}, - } - const dataChunkSize = 1024 * 1024 - - data := generateJournaldData(dataChunkSize) - - b.ReportAllocs() - b.SetBytes(int64(len(data))) - b.RunParallel(func(pb *testing.PB) { - r := &bytes.Reader{} - blp := &insertutil.BenchmarkLogMessageProcessor{} - for pb.Next() { - r.Reset(data) - if err := processStreamInternal("performance_test", r, blp, cp); err != nil { - panic(fmt.Errorf("unexpected error: %w", err)) - } - } - }) -} - -func generateJournaldData(size int) []byte { - var buf []byte - timestamp := time.Now().UnixMicro() - binaryMsg := []byte("binary message data for performance test") - var sizeBuf [8]byte - - for len(buf) < size { - timestamp++ - - var entry string - // Generate a mix of simple and binary messages - if timestamp%10 == 0 { - // Generate binary message - binary.LittleEndian.PutUint64(sizeBuf[:], uint64(len(binaryMsg))) - entry = fmt.Sprintf("__REALTIME_TIMESTAMP=%d\nMESSAGE\n%s%s\n\n", - timestamp, - sizeBuf[:], - binaryMsg, - ) - } else { - // Generate simple message - entry = fmt.Sprintf("__REALTIME_TIMESTAMP=%d\nMESSAGE=Performance test message %d\n\n", timestamp, timestamp) - } - buf = append(buf, entry...) - } - return buf -} diff --git a/app/vlinsert/jsonline/jsonline.go b/app/vlinsert/jsonline/jsonline.go deleted file mode 100644 index 0e0433721a..0000000000 --- a/app/vlinsert/jsonline/jsonline.go +++ /dev/null @@ -1,123 +0,0 @@ -package jsonline - -import ( - "fmt" - "io" - "net/http" - "time" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/protoparserutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/writeconcurrencylimiter" - "github.com/VictoriaMetrics/metrics" -) - -// RequestHandler processes jsonline insert requests -func RequestHandler(w http.ResponseWriter, r *http.Request) { - startTime := time.Now() - w.Header().Add("Content-Type", "application/json") - - if r.Method != "POST" { - w.WriteHeader(http.StatusMethodNotAllowed) - return - } - - requestsTotal.Inc() - - cp, err := insertutil.GetCommonParams(r) - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - if err := insertutil.CanWriteData(); err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - - encoding := r.Header.Get("Content-Encoding") - reader, err := protoparserutil.GetUncompressedReader(r.Body, encoding) - if err != nil { - logger.Errorf("cannot decode jsonline request: %s", err) - return - } - defer protoparserutil.PutUncompressedReader(reader) - - lmp := cp.NewLogMessageProcessor("jsonline", true) - streamName := fmt.Sprintf("remoteAddr=%s, requestURI=%q", httpserver.GetQuotedRemoteAddr(r), r.RequestURI) - err = processStreamInternal(streamName, reader, cp.TimeFields, cp.MsgFields, lmp) - lmp.MustClose() - if err != nil { - httpserver.Errorf(w, r, "cannot process jsonline request; error: %s", err) - return - } - - requestDuration.UpdateDuration(startTime) -} - -func processStreamInternal(streamName string, r io.Reader, timeFields, msgFields []string, lmp insertutil.LogMessageProcessor) error { - wcr := writeconcurrencylimiter.GetReader(r) - defer writeconcurrencylimiter.PutReader(wcr) - - lr := insertutil.NewLineReader(streamName, wcr) - - n := 0 - errors := 0 - var lastError error - for { - ok, err := readLine(lr, timeFields, msgFields, lmp) - wcr.DecConcurrency() - if err != nil { - lastError = err - errors++ - logger.Warnf("jsonline: cannot read line #%d in /jsonline request: %s", n, err) - } - if !ok { - break - } - n++ - } - errorsTotal.Add(errors) - - if errors > 0 && n == errors { - // Return an error if no logs were processed and there were errors - return lastError - } - - return nil -} - -func readLine(lr *insertutil.LineReader, timeFields, msgFields []string, lmp insertutil.LogMessageProcessor) (bool, error) { - var line []byte - for len(line) == 0 { - if !lr.NextLine() { - err := lr.Err() - return false, err - } - line = lr.Line - } - - p := logstorage.GetJSONParser() - defer logstorage.PutJSONParser(p) - - if err := p.ParseLogMessage(line); err != nil { - return true, fmt.Errorf("%s; line contents: %q", err, line) - } - ts, err := insertutil.ExtractTimestampFromFields(timeFields, p.Fields) - if err != nil { - return true, fmt.Errorf("%s; line contents: %q", err, line) - } - logstorage.RenameField(p.Fields, msgFields, "_msg") - lmp.AddRow(ts, p.Fields, nil) - - return true, nil -} - -var ( - requestsTotal = metrics.NewCounter(`vl_http_requests_total{path="/insert/jsonline"}`) - errorsTotal = metrics.NewCounter(`vl_http_errors_total{path="/insert/jsonline"}`) - - requestDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/insert/jsonline"}`) -) diff --git a/app/vlinsert/jsonline/jsonline_test.go b/app/vlinsert/jsonline/jsonline_test.go deleted file mode 100644 index 2620d29ac5..0000000000 --- a/app/vlinsert/jsonline/jsonline_test.go +++ /dev/null @@ -1,97 +0,0 @@ -package jsonline - -import ( - "bytes" - "strings" - "testing" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" -) - -func TestProcessStreamInternalSuccess(t *testing.T) { - f := func(data, timeField, msgField string, timestampsExpected []int64, resultExpected string) { - t.Helper() - - timeFields := []string{timeField} - msgFields := []string{msgField} - tlp := &insertutil.TestLogMessageProcessor{} - r := bytes.NewBufferString(data) - if err := processStreamInternal("test", r, timeFields, msgFields, tlp); err != nil { - t.Fatalf("unexpected error: %s", err) - } - - if err := tlp.Verify(timestampsExpected, resultExpected); err != nil { - t.Fatal(err) - } - } - - data := `{"@timestamp":"2023-06-06T04:48:11.735Z","log":{"offset":71770,"file":{"path":"/var/log/auth.log"}},"message":"foobar"} -{"@timestamp":"2023-06-06T04:48:12.735+01:00","message":"baz"} -{"message":"xyz","@timestamp":"2023-06-06 04:48:13.735Z","x":"y"} -` - timeField := "@timestamp" - msgField := "message" - timestampsExpected := []int64{1686026891735000000, 1686023292735000000, 1686026893735000000} - resultExpected := `{"log.offset":"71770","log.file.path":"/var/log/auth.log","_msg":"foobar"} -{"_msg":"baz"} -{"_msg":"xyz","x":"y"}` - f(data, timeField, msgField, timestampsExpected, resultExpected) - - // Non-existing msgField - data = `{"@timestamp":"2023-06-06T04:48:11.735Z","log":{"offset":71770,"file":{"path":"/var/log/auth.log"}},"message":"foobar"} -{"@timestamp":"2023-06-06T04:48:12.735+01:00","message":"baz"} -` - timeField = "@timestamp" - msgField = "foobar" - timestampsExpected = []int64{1686026891735000000, 1686023292735000000} - resultExpected = `{"log.offset":"71770","log.file.path":"/var/log/auth.log","message":"foobar"} -{"message":"baz"}` - f(data, timeField, msgField, timestampsExpected, resultExpected) - - // invalid lines among valid lines - data = ` -dsfodmasd - -{"time":"2023-06-06T04:48:11.735Z","log":{"offset":71770,"file":{"path":"/var/log/auth.log"}},"message":"foobar"} -invalid line -{"time":"2023-06-06T04:48:12.735+01:00","message":"baz"} -asbsdf - -` - timeField = "time" - msgField = "message" - timestampsExpected = []int64{1686026891735000000, 1686023292735000000} - resultExpected = `{"log.offset":"71770","log.file.path":"/var/log/auth.log","_msg":"foobar"} -{"_msg":"baz"}` - f(data, timeField, msgField, timestampsExpected, resultExpected) -} - -func TestProcessStreamInternalFailure(t *testing.T) { - f := func(data string) { - t.Helper() - - tlp := &insertutil.TestLogMessageProcessor{} - r := strings.NewReader(data) - if err := processStreamInternal("test", r, []string{"time"}, nil, tlp); err == nil { - t.Fatalf("expected error, got nil") - } - - if err := tlp.Verify(nil, ""); err != nil { - t.Fatalf("unexpected error: %s", err) - } - } - - // invalid json - f("foobar") - - f(`foo -bar`) - - f(` -foo - -`) - - // invalid timestamp field - f(`{"time":"foobar"}`) -} diff --git a/app/vlinsert/loki/loki.go b/app/vlinsert/loki/loki.go deleted file mode 100644 index 2366c20357..0000000000 --- a/app/vlinsert/loki/loki.go +++ /dev/null @@ -1,86 +0,0 @@ -package loki - -import ( - "flag" - "fmt" - "net/http" - "strconv" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httputil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" -) - -var disableMessageParsing = flag.Bool("loki.disableMessageParsing", false, "Whether to disable automatic parsing of JSON-encoded log fields inside Loki log message into distinct log fields") - -// RequestHandler processes Loki insert requests -func RequestHandler(path string, w http.ResponseWriter, r *http.Request) bool { - switch path { - case "/insert/loki/api/v1/push": - handleInsert(r, w) - return true - case "/insert/loki/ready": - // See https://grafana.com/docs/loki/latest/api/#identify-ready-loki-instance - w.WriteHeader(http.StatusOK) - w.Write([]byte("ready")) - return true - default: - return false - } -} - -// See https://grafana.com/docs/loki/latest/api/#push-log-entries-to-loki -func handleInsert(r *http.Request, w http.ResponseWriter) { - contentType := r.Header.Get("Content-Type") - switch contentType { - case "application/json": - handleJSON(r, w) - default: - // Protobuf request body should be handled by default according to https://grafana.com/docs/loki/latest/api/#push-log-entries-to-loki - handleProtobuf(r, w) - } -} - -type commonParams struct { - cp *insertutil.CommonParams - - // Whether to parse JSON inside plaintext log message. - // - // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8486 - parseMessage bool -} - -func getCommonParams(r *http.Request) (*commonParams, error) { - cp, err := insertutil.GetCommonParams(r) - if err != nil { - return nil, err - } - - // If parsed tenant is (0,0) it is likely to be default tenant - // Try parsing tenant from Loki headers - if cp.TenantID.AccountID == 0 && cp.TenantID.ProjectID == 0 { - org := r.Header.Get("X-Scope-OrgID") - if org != "" { - tenantID, err := logstorage.ParseTenantID(org) - if err != nil { - return nil, err - } - cp.TenantID = tenantID - } - - } - - parseMessage := !*disableMessageParsing - if rv := httputil.GetRequestValue(r, "disable_message_parsing", "VL-Loki-Disable-Message-Parsing"); rv != "" { - bv, err := strconv.ParseBool(rv) - if err != nil { - return nil, fmt.Errorf("cannot parse dusable_message_parsing=%q: %s", rv, err) - } - parseMessage = !bv - } - - return &commonParams{ - cp: cp, - parseMessage: parseMessage, - }, nil -} diff --git a/app/vlinsert/loki/loki_json.go b/app/vlinsert/loki/loki_json.go deleted file mode 100644 index c05d2e9b6f..0000000000 --- a/app/vlinsert/loki/loki_json.go +++ /dev/null @@ -1,230 +0,0 @@ -package loki - -import ( - "fmt" - "net/http" - "time" - - "github.com/VictoriaMetrics/metrics" - "github.com/valyala/fastjson" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/protoparserutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/timeutil" -) - -var maxRequestSize = flagutil.NewBytes("loki.maxRequestSize", 64*1024*1024, "The maximum size in bytes of a single Loki request") - -var parserPool fastjson.ParserPool - -func handleJSON(r *http.Request, w http.ResponseWriter) { - startTime := time.Now() - requestsJSONTotal.Inc() - - cp, err := getCommonParams(r) - if err != nil { - httpserver.Errorf(w, r, "cannot parse common params from request: %s", err) - return - } - if err := insertutil.CanWriteData(); err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - - encoding := r.Header.Get("Content-Encoding") - err = protoparserutil.ReadUncompressedData(r.Body, encoding, maxRequestSize, func(data []byte) error { - lmp := cp.cp.NewLogMessageProcessor("loki_json", false) - useDefaultStreamFields := len(cp.cp.StreamFields) == 0 - err := parseJSONRequest(data, lmp, cp.cp.MsgFields, useDefaultStreamFields, cp.parseMessage) - lmp.MustClose() - return err - }) - if err != nil { - httpserver.Errorf(w, r, "cannot read Loki json data: %s", err) - return - } - - // update requestJSONDuration only for successfully parsed requests - // There is no need in updating requestJSONDuration for request errors, - // since their timings are usually much smaller than the timing for successful request parsing. - requestJSONDuration.UpdateDuration(startTime) - - // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8505 - w.WriteHeader(http.StatusNoContent) -} - -var ( - requestsJSONTotal = metrics.NewCounter(`vl_http_requests_total{path="/insert/loki/api/v1/push",format="json"}`) - requestJSONDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/insert/loki/api/v1/push",format="json"}`) -) - -func parseJSONRequest(data []byte, lmp insertutil.LogMessageProcessor, msgFields []string, useDefaultStreamFields, parseMessage bool) error { - p := parserPool.Get() - defer parserPool.Put(p) - - v, err := p.ParseBytes(data) - if err != nil { - return fmt.Errorf("cannot parse JSON request body: %w", err) - } - - streamsV := v.Get("streams") - if streamsV == nil { - return fmt.Errorf("missing `streams` item in the parsed JSON") - } - streams, err := streamsV.Array() - if err != nil { - return fmt.Errorf("`streams` item in the parsed JSON must contain an array; got %q", streamsV) - } - - fields := getFields() - defer putFields(fields) - - var msgParser *logstorage.JSONParser - if parseMessage { - msgParser = logstorage.GetJSONParser() - defer logstorage.PutJSONParser(msgParser) - } - - currentTimestamp := time.Now().UnixNano() - - for _, stream := range streams { - // populate common labels from `stream` dict - fields.fields = fields.fields[:0] - labelsV := stream.Get("stream") - var labels *fastjson.Object - if labelsV != nil { - o, err := labelsV.Object() - if err != nil { - return fmt.Errorf("`stream` item in the parsed JSON must contain an object; got %q", labelsV) - } - labels = o - } - labels.Visit(func(k []byte, v *fastjson.Value) { - vStr, errLocal := v.StringBytes() - if errLocal != nil { - err = fmt.Errorf("unexpected label value type for %q:%q; want string", k, v) - return - } - fields.fields = append(fields.fields, logstorage.Field{ - Name: bytesutil.ToUnsafeString(k), - Value: bytesutil.ToUnsafeString(vStr), - }) - }) - if err != nil { - return fmt.Errorf("error when parsing `stream` object: %w", err) - } - - // populate messages from `values` array - linesV := stream.Get("values") - if linesV == nil { - return fmt.Errorf("missing `values` item in the parsed `stream` object %q", stream) - } - lines, err := linesV.Array() - if err != nil { - return fmt.Errorf("`values` item in the parsed JSON must contain an array; got %q", linesV) - } - - commonFieldsLen := len(fields.fields) - for _, line := range lines { - fields.fields = fields.fields[:commonFieldsLen] - - lineA, err := line.Array() - if err != nil { - return fmt.Errorf("unexpected contents of `values` item; want array; got %q", line) - } - if len(lineA) < 2 || len(lineA) > 3 { - return fmt.Errorf("unexpected number of values in `values` item array %q; got %d want 2 or 3", line, len(lineA)) - } - - // parse timestamp - timestamp, err := lineA[0].StringBytes() - if err != nil { - return fmt.Errorf("unexpected log timestamp type for %q; want string", lineA[0]) - } - ts, err := parseLokiTimestamp(bytesutil.ToUnsafeString(timestamp)) - if err != nil { - return fmt.Errorf("cannot parse log timestamp %q: %w", timestamp, err) - } - if ts == 0 { - ts = currentTimestamp - } - - // parse structured metadata - see https://grafana.com/docs/loki/latest/reference/loki-http-api/#ingest-logs - if len(lineA) > 2 { - structuredMetadata, err := lineA[2].Object() - if err != nil { - return fmt.Errorf("unexpected structured metadata type for %q; want JSON object", lineA[2]) - } - - structuredMetadata.Visit(func(k []byte, v *fastjson.Value) { - vStr, errLocal := v.StringBytes() - if errLocal != nil { - err = fmt.Errorf("unexpected label value type for %q:%q; want string", k, v) - return - } - - fields.fields = append(fields.fields, logstorage.Field{ - Name: bytesutil.ToUnsafeString(k), - Value: bytesutil.ToUnsafeString(vStr), - }) - }) - if err != nil { - return fmt.Errorf("error when parsing `structuredMetadata` object: %w", err) - } - } - - // parse log message - msg, err := lineA[1].StringBytes() - if err != nil { - return fmt.Errorf("unexpected log message type for %q; want string", lineA[1]) - } - allowMsgRenaming := false - fields.fields, allowMsgRenaming = addMsgField(fields.fields, msgParser, bytesutil.ToUnsafeString(msg)) - - var streamFields []logstorage.Field - if useDefaultStreamFields { - streamFields = fields.fields[:commonFieldsLen] - } - if allowMsgRenaming { - logstorage.RenameField(fields.fields[commonFieldsLen:], msgFields, "_msg") - } - lmp.AddRow(ts, fields.fields, streamFields) - } - } - - return nil -} - -func addMsgField(dst []logstorage.Field, msgParser *logstorage.JSONParser, msg string) ([]logstorage.Field, bool) { - if msgParser == nil || len(msg) < 2 || msg[0] != '{' || msg[len(msg)-1] != '}' { - return append(dst, logstorage.Field{ - Name: "_msg", - Value: msg, - }), false - } - if msgParser != nil && len(msg) >= 2 && msg[0] == '{' && msg[len(msg)-1] == '}' { - if err := msgParser.ParseLogMessage(bytesutil.ToUnsafeBytes(msg)); err == nil { - return append(dst, msgParser.Fields...), true - } - } - return append(dst, logstorage.Field{ - Name: "_msg", - Value: msg, - }), false -} - -func parseLokiTimestamp(s string) (int64, error) { - if s == "" { - // Special case - an empty timestamp must be substituted with the current time by the caller. - return 0, nil - } - nsecs, ok := timeutil.TryParseUnixTimestamp(s) - if !ok { - return 0, fmt.Errorf("cannot parse unix timestamp %q", s) - } - return nsecs, nil -} diff --git a/app/vlinsert/loki/loki_json_test.go b/app/vlinsert/loki/loki_json_test.go deleted file mode 100644 index 7424db9ec5..0000000000 --- a/app/vlinsert/loki/loki_json_test.go +++ /dev/null @@ -1,169 +0,0 @@ -package loki - -import ( - "testing" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" -) - -func TestParseJSONRequest_Failure(t *testing.T) { - f := func(s string) { - t.Helper() - - tlp := &insertutil.TestLogMessageProcessor{} - if err := parseJSONRequest([]byte(s), tlp, nil, false, false); err == nil { - t.Fatalf("expecting non-nil error") - } - if err := tlp.Verify(nil, ""); err != nil { - t.Fatalf("unexpected error: %s", err) - } - } - f(``) - - // Invalid json - f(`{}`) - f(`[]`) - f(`"foo"`) - f(`123`) - - // invalid type for `streams` item - f(`{"streams":123}`) - - // Missing `values` item - f(`{"streams":[{}]}`) - - // Invalid type for `values` item - f(`{"streams":[{"values":"foobar"}]}`) - - // Invalid type for `stream` item - f(`{"streams":[{"stream":[],"values":[]}]}`) - - // Invalid type for `values` individual item - f(`{"streams":[{"values":[123]}]}`) - - // Invalid length of `values` individual item - f(`{"streams":[{"values":[[]]}]}`) - f(`{"streams":[{"values":[["123"]]}]}`) - f(`{"streams":[{"values":[["123","456","789","8123"]]}]}`) - - // Invalid type for timestamp inside `values` individual item - f(`{"streams":[{"values":[[123,"456"]}]}`) - - // Invalid type for log message - f(`{"streams":[{"values":[["123",1234]]}]}`) - - // invalid structured metadata type - f(`{"streams":[{"values":[["1577836800000000001", "foo bar", ["metadata_1", "md_value"]]]}]}`) - - // structured metadata with unexpected value type - f(`{"streams":[{"values":[["1577836800000000001", "foo bar", {"metadata_1": 1}]] }]}`) -} - -func TestParseJSONRequest_Success(t *testing.T) { - f := func(s string, timestampsExpected []int64, resultExpected string) { - t.Helper() - - tlp := &insertutil.TestLogMessageProcessor{} - - if err := parseJSONRequest([]byte(s), tlp, nil, false, false); err != nil { - t.Fatalf("unexpected error: %s", err) - } - if err := tlp.Verify(timestampsExpected, resultExpected); err != nil { - t.Fatal(err) - } - } - - // Empty streams - f(`{"streams":[]}`, nil, ``) - f(`{"streams":[{"values":[]}]}`, nil, ``) - f(`{"streams":[{"stream":{},"values":[]}]}`, nil, ``) - f(`{"streams":[{"stream":{"foo":"bar"},"values":[]}]}`, nil, ``) - - // Empty stream labels - f(`{"streams":[{"values":[["1577836800000000001", "foo bar"]]}]}`, []int64{1577836800000000001}, `{"_msg":"foo bar"}`) - f(`{"streams":[{"stream":{},"values":[["1577836800000000001", "foo bar"]]}]}`, []int64{1577836800000000001}, `{"_msg":"foo bar"}`) - - // Non-empty stream labels - f(`{"streams":[{"stream":{ - "label1": "value1", - "label2": "value2" -},"values":[ - ["1577836800000000001", "foo bar"], - ["1686026123.62", "abc"], - ["147.78369e9", "foobar"] -]}]}`, []int64{1577836800000000001, 1686026123620000000, 147783690000000000}, `{"label1":"value1","label2":"value2","_msg":"foo bar"} -{"label1":"value1","label2":"value2","_msg":"abc"} -{"label1":"value1","label2":"value2","_msg":"foobar"}`) - - // Multiple streams - f(`{ - "streams": [ - { - "stream": { - "foo": "bar", - "a": "b" - }, - "values": [ - ["1577836800000000001", "foo bar"], - ["1577836900005000002", "abc"] - ] - }, - { - "stream": { - "x": "y" - }, - "values": [ - ["1877836900005000002", "yx"] - ] - } - ] -}`, []int64{1577836800000000001, 1577836900005000002, 1877836900005000002}, `{"foo":"bar","a":"b","_msg":"foo bar"} -{"foo":"bar","a":"b","_msg":"abc"} -{"x":"y","_msg":"yx"}`) - - // values with metadata - f(`{"streams":[{"values":[["1577836800000000001", "foo bar", {"metadata_1": "md_value"}]]}]}`, []int64{1577836800000000001}, `{"metadata_1":"md_value","_msg":"foo bar"}`) - f(`{"streams":[{"values":[["1577836800000000001", "foo bar", {}]]}]}`, []int64{1577836800000000001}, `{"_msg":"foo bar"}`) -} - -func TestParseJSONRequest_ParseMessage(t *testing.T) { - f := func(s string, msgFields []string, timestampsExpected []int64, resultExpected string) { - t.Helper() - - tlp := &insertutil.TestLogMessageProcessor{} - - if err := parseJSONRequest([]byte(s), tlp, msgFields, false, true); err != nil { - t.Fatalf("unexpected error: %s", err) - } - if err := tlp.Verify(timestampsExpected, resultExpected); err != nil { - t.Fatal(err) - } - } - - f(`{ - "streams": [ - { - "stream": { - "foo": "bar", - "a": "b" - }, - "values": [ - ["1577836800000000001", "{\"user_id\":\"123\"}"], - ["1577836900005000002", "abc", {"trace_id":"pqw"}], - ["1577836900005000003", "{def}"] - ] - }, - { - "stream": { - "x": "y" - }, - "values": [ - ["1877836900005000004", "{\"trace_id\":\"111\",\"parent_id\":\"abc\"}"] - ] - } - ] -}`, []string{"a", "trace_id"}, []int64{1577836800000000001, 1577836900005000002, 1577836900005000003, 1877836900005000004}, `{"foo":"bar","a":"b","user_id":"123"} -{"foo":"bar","a":"b","trace_id":"pqw","_msg":"abc"} -{"foo":"bar","a":"b","_msg":"{def}"} -{"x":"y","_msg":"111","parent_id":"abc"}`) -} diff --git a/app/vlinsert/loki/loki_json_timing_test.go b/app/vlinsert/loki/loki_json_timing_test.go deleted file mode 100644 index 59821d3873..0000000000 --- a/app/vlinsert/loki/loki_json_timing_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package loki - -import ( - "fmt" - "strconv" - "testing" - "time" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" -) - -func BenchmarkParseJSONRequest(b *testing.B) { - for _, streams := range []int{5, 10} { - for _, rows := range []int{100, 1000} { - for _, labels := range []int{10, 50} { - b.Run(fmt.Sprintf("streams_%d/rows_%d/labels_%d", streams, rows, labels), func(b *testing.B) { - benchmarkParseJSONRequest(b, streams, rows, labels) - }) - } - } - } -} - -func benchmarkParseJSONRequest(b *testing.B, streams, rows, labels int) { - blp := &insertutil.BenchmarkLogMessageProcessor{} - b.ReportAllocs() - b.SetBytes(int64(streams * rows)) - b.RunParallel(func(pb *testing.PB) { - data := getJSONBody(streams, rows, labels) - for pb.Next() { - if err := parseJSONRequest(data, blp, nil, false, true); err != nil { - panic(fmt.Errorf("unexpected error: %w", err)) - } - } - }) -} - -func getJSONBody(streams, rows, labels int) []byte { - body := append([]byte{}, `{"streams":[`...) - now := time.Now().UnixNano() - valuePrefix := fmt.Sprintf(`["%d","value_`, now) - - for i := 0; i < streams; i++ { - body = append(body, `{"stream":{`...) - - for j := 0; j < labels; j++ { - body = append(body, `"label_`...) - body = strconv.AppendInt(body, int64(j), 10) - body = append(body, `":"value_`...) - body = strconv.AppendInt(body, int64(j), 10) - body = append(body, '"') - if j < labels-1 { - body = append(body, ',') - } - - } - body = append(body, `}, "values":[`...) - - for j := 0; j < rows; j++ { - body = append(body, valuePrefix...) - body = strconv.AppendInt(body, int64(j), 10) - body = append(body, `"]`...) - if j < rows-1 { - body = append(body, ',') - } - } - - body = append(body, `]}`...) - if i < streams-1 { - body = append(body, ',') - } - - } - - body = append(body, `]}`...) - - return body -} diff --git a/app/vlinsert/loki/loki_protobuf.go b/app/vlinsert/loki/loki_protobuf.go deleted file mode 100644 index a65b0c86c9..0000000000 --- a/app/vlinsert/loki/loki_protobuf.go +++ /dev/null @@ -1,218 +0,0 @@ -package loki - -import ( - "fmt" - "net/http" - "strconv" - "strings" - "sync" - "time" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/protoparserutil" - "github.com/VictoriaMetrics/metrics" -) - -var ( - pushReqsPool sync.Pool -) - -func handleProtobuf(r *http.Request, w http.ResponseWriter) { - startTime := time.Now() - requestsProtobufTotal.Inc() - - cp, err := getCommonParams(r) - if err != nil { - httpserver.Errorf(w, r, "cannot parse common params from request: %s", err) - return - } - if err := insertutil.CanWriteData(); err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - - encoding := r.Header.Get("Content-Encoding") - if encoding == "" { - // Loki protocol uses snappy compression by default. - // See https://grafana.com/docs/loki/latest/reference/loki-http-api/#ingest-logs - encoding = "snappy" - } - err = protoparserutil.ReadUncompressedData(r.Body, encoding, maxRequestSize, func(data []byte) error { - lmp := cp.cp.NewLogMessageProcessor("loki_protobuf", false) - useDefaultStreamFields := len(cp.cp.StreamFields) == 0 - err := parseProtobufRequest(data, lmp, cp.cp.MsgFields, useDefaultStreamFields, cp.parseMessage) - lmp.MustClose() - return err - }) - if err != nil { - httpserver.Errorf(w, r, "cannot read Loki protobuf data: %s", err) - return - } - - // update requestProtobufDuration only for successfully parsed requests - // There is no need in updating requestProtobufDuration for request errors, - // since their timings are usually much smaller than the timing for successful request parsing. - requestProtobufDuration.UpdateDuration(startTime) - - // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8505 - w.WriteHeader(http.StatusNoContent) -} - -var ( - requestsProtobufTotal = metrics.NewCounter(`vl_http_requests_total{path="/insert/loki/api/v1/push",format="protobuf"}`) - requestProtobufDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/insert/loki/api/v1/push",format="protobuf"}`) -) - -func parseProtobufRequest(data []byte, lmp insertutil.LogMessageProcessor, msgFields []string, useDefaultStreamFields, parseMessage bool) error { - req := getPushRequest() - defer putPushRequest(req) - - err := req.UnmarshalProtobuf(data) - if err != nil { - return fmt.Errorf("cannot parse request body: %w", err) - } - - fields := getFields() - defer putFields(fields) - - var msgParser *logstorage.JSONParser - if parseMessage { - msgParser = logstorage.GetJSONParser() - defer logstorage.PutJSONParser(msgParser) - } - - streams := req.Streams - currentTimestamp := time.Now().UnixNano() - - for i := range streams { - stream := &streams[i] - // st.Labels contains labels for the stream. - // Labels are same for all entries in the stream. - fields.fields, err = parsePromLabels(fields.fields[:0], stream.Labels) - if err != nil { - return fmt.Errorf("cannot parse stream labels %q: %w", stream.Labels, err) - } - commonFieldsLen := len(fields.fields) - - entries := stream.Entries - for j := range entries { - e := &entries[j] - fields.fields = fields.fields[:commonFieldsLen] - - for _, lp := range e.StructuredMetadata { - fields.fields = append(fields.fields, logstorage.Field{ - Name: lp.Name, - Value: lp.Value, - }) - } - - allowMsgRenaming := false - fields.fields, allowMsgRenaming = addMsgField(fields.fields, msgParser, e.Line) - - ts := e.Timestamp.UnixNano() - if ts == 0 { - ts = currentTimestamp - } - - var streamFields []logstorage.Field - if useDefaultStreamFields { - streamFields = fields.fields[:commonFieldsLen] - } - if allowMsgRenaming { - logstorage.RenameField(fields.fields[commonFieldsLen:], msgFields, "_msg") - } - lmp.AddRow(ts, fields.fields, streamFields) - } - } - return nil -} - -func getFields() *fields { - v := fieldsPool.Get() - if v == nil { - return &fields{} - } - return v.(*fields) -} - -func putFields(f *fields) { - f.fields = f.fields[:0] - fieldsPool.Put(f) -} - -var fieldsPool sync.Pool - -type fields struct { - fields []logstorage.Field -} - -// parsePromLabels parses log fields in Prometheus text exposition format from s, appends them to dst and returns the result. -// -// See test data of promtail for examples: https://github.com/grafana/loki/blob/a24ef7b206e0ca63ee74ca6ecb0a09b745cd2258/pkg/push/types_test.go -func parsePromLabels(dst []logstorage.Field, s string) ([]logstorage.Field, error) { - // Make sure s is wrapped into `{...}` - s = strings.TrimSpace(s) - if len(s) < 2 { - return nil, fmt.Errorf("too short string to parse: %q", s) - } - if s[0] != '{' { - return nil, fmt.Errorf("missing `{` at the beginning of %q", s) - } - if s[len(s)-1] != '}' { - return nil, fmt.Errorf("missing `}` at the end of %q", s) - } - s = s[1 : len(s)-1] - - for len(s) > 0 { - // Parse label name - n := strings.IndexByte(s, '=') - if n < 0 { - return nil, fmt.Errorf("cannot find `=` char for label value at %s", s) - } - name := s[:n] - s = s[n+1:] - - // Parse label value - qs, err := strconv.QuotedPrefix(s) - if err != nil { - return nil, fmt.Errorf("cannot parse value for label %q at %s: %w", name, s, err) - } - s = s[len(qs):] - value, err := strconv.Unquote(qs) - if err != nil { - return nil, fmt.Errorf("cannot unquote value %q for label %q: %w", qs, name, err) - } - - // Append the found field to dst. - dst = append(dst, logstorage.Field{ - Name: name, - Value: value, - }) - - // Check whether there are other labels remaining - if len(s) == 0 { - break - } - if !strings.HasPrefix(s, ",") { - return nil, fmt.Errorf("missing `,` char at %s", s) - } - s = s[1:] - s = strings.TrimPrefix(s, " ") - } - return dst, nil -} - -func getPushRequest() *PushRequest { - v := pushReqsPool.Get() - if v == nil { - return &PushRequest{} - } - return v.(*PushRequest) -} - -func putPushRequest(req *PushRequest) { - req.reset() - pushReqsPool.Put(req) -} diff --git a/app/vlinsert/loki/loki_protobuf_test.go b/app/vlinsert/loki/loki_protobuf_test.go deleted file mode 100644 index 9e74ddeae2..0000000000 --- a/app/vlinsert/loki/loki_protobuf_test.go +++ /dev/null @@ -1,218 +0,0 @@ -package loki - -import ( - "fmt" - "strings" - "testing" - "time" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" -) - -type testLogMessageProcessor struct { - pr PushRequest -} - -func (tlp *testLogMessageProcessor) AddRow(timestamp int64, fields, streamFields []logstorage.Field) { - if streamFields != nil { - panic(fmt.Errorf("unexpected non-nil streamFields: %v", streamFields)) - } - msg := "" - for _, f := range fields { - if f.Name == "_msg" { - msg = f.Value - } - } - var a []string - for _, f := range fields { - if f.Name == "_msg" { - continue - } - item := fmt.Sprintf("%s=%q", f.Name, f.Value) - a = append(a, item) - } - labels := "{" + strings.Join(a, ", ") + "}" - tlp.pr.Streams = append(tlp.pr.Streams, Stream{ - Labels: labels, - Entries: []Entry{ - { - Timestamp: time.Unix(0, timestamp), - Line: strings.Clone(msg), - }, - }, - }) -} - -func (tlp *testLogMessageProcessor) MustClose() { -} - -func TestParseProtobufRequest_Success(t *testing.T) { - f := func(s string, timestampsExpected []int64, resultExpected string) { - t.Helper() - - tlp := &testLogMessageProcessor{} - if err := parseJSONRequest([]byte(s), tlp, nil, false, false); err != nil { - t.Fatalf("unexpected error: %s", err) - } - if len(tlp.pr.Streams) != len(timestampsExpected) { - t.Fatalf("unexpected number of streams; got %d; want %d", len(tlp.pr.Streams), len(timestampsExpected)) - } - - data := tlp.pr.MarshalProtobuf(nil) - - tlp2 := &insertutil.TestLogMessageProcessor{} - if err := parseProtobufRequest(data, tlp2, nil, false, false); err != nil { - t.Fatalf("unexpected error: %s", err) - } - if err := tlp2.Verify(timestampsExpected, resultExpected); err != nil { - t.Fatal(err) - } - } - - // Empty streams - f(`{"streams":[]}`, nil, ``) - f(`{"streams":[{"values":[]}]}`, nil, ``) - f(`{"streams":[{"stream":{},"values":[]}]}`, nil, ``) - f(`{"streams":[{"stream":{"foo":"bar"},"values":[]}]}`, nil, ``) - - // Empty stream labels - f(`{"streams":[{"values":[["1577836800000000001", "foo bar"]]}]}`, []int64{1577836800000000001}, `{"_msg":"foo bar"}`) - f(`{"streams":[{"stream":{},"values":[["1577836800000000001", "foo bar"]]}]}`, []int64{1577836800000000001}, `{"_msg":"foo bar"}`) - - // Non-empty stream labels - f(`{"streams":[{"stream":{ - "label1": "value1", - "label2": "value2" -},"values":[ - ["1577836800000000001", "foo bar"], - ["1477836900005000002", "abc"], - ["147.78369e9", "foobar"] -]}]}`, []int64{1577836800000000001, 1477836900005000002, 147783690000000000}, `{"label1":"value1","label2":"value2","_msg":"foo bar"} -{"label1":"value1","label2":"value2","_msg":"abc"} -{"label1":"value1","label2":"value2","_msg":"foobar"}`) - - // Multiple streams - f(`{ - "streams": [ - { - "stream": { - "foo": "bar", - "a": "b" - }, - "values": [ - ["1577836800000000001", "foo bar"], - ["1577836900005000002", "abc"] - ] - }, - { - "stream": { - "x": "y" - }, - "values": [ - ["1877836900005000002", "yx"] - ] - } - ] -}`, []int64{1577836800000000001, 1577836900005000002, 1877836900005000002}, `{"foo":"bar","a":"b","_msg":"foo bar"} -{"foo":"bar","a":"b","_msg":"abc"} -{"x":"y","_msg":"yx"}`) -} - -func TestParseProtobufRequest_ParseMessage(t *testing.T) { - f := func(s string, msgFields []string, timestampsExpected []int64, resultExpected string) { - t.Helper() - - tlp := &testLogMessageProcessor{} - if err := parseJSONRequest([]byte(s), tlp, nil, false, false); err != nil { - t.Fatalf("unexpected error: %s", err) - } - if len(tlp.pr.Streams) != len(timestampsExpected) { - t.Fatalf("unexpected number of streams; got %d; want %d", len(tlp.pr.Streams), len(timestampsExpected)) - } - - data := tlp.pr.MarshalProtobuf(nil) - - tlp2 := &insertutil.TestLogMessageProcessor{} - if err := parseProtobufRequest(data, tlp2, msgFields, false, true); err != nil { - t.Fatalf("unexpected error: %s", err) - } - if err := tlp2.Verify(timestampsExpected, resultExpected); err != nil { - t.Fatal(err) - } - } - - f(`{ - "streams": [ - { - "stream": { - "foo": "bar", - "a": "b" - }, - "values": [ - ["1577836800000000001", "{\"user_id\":\"123\"}"], - ["1577836900005000002", "abc", {"trace_id":"pqw"}], - ["1577836900005000003", "{def}"] - ] - }, - { - "stream": { - "x": "y" - }, - "values": [ - ["1877836900005000004", "{\"trace_id\":\"432\",\"parent_id\":\"qwerty\"}"] - ] - } - ] -}`, []string{"a", "trace_id"}, []int64{1577836800000000001, 1577836900005000002, 1577836900005000003, 1877836900005000004}, `{"foo":"bar","a":"b","user_id":"123"} -{"foo":"bar","a":"b","trace_id":"pqw","_msg":"abc"} -{"foo":"bar","a":"b","_msg":"{def}"} -{"x":"y","_msg":"432","parent_id":"qwerty"}`) -} - -func TestParsePromLabels_Success(t *testing.T) { - f := func(s string) { - t.Helper() - fields, err := parsePromLabels(nil, s) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } - - var a []string - for _, f := range fields { - a = append(a, fmt.Sprintf("%s=%q", f.Name, f.Value)) - } - result := "{" + strings.Join(a, ", ") + "}" - if result != s { - t.Fatalf("unexpected result;\ngot\n%s\nwant\n%s", result, s) - } - } - - f("{}") - f(`{foo="bar"}`) - f(`{foo="bar", baz="x", y="z"}`) - f(`{foo="ba\"r\\z\n", a="", b="\"\\"}`) -} - -func TestParsePromLabels_Failure(t *testing.T) { - f := func(s string) { - t.Helper() - fields, err := parsePromLabels(nil, s) - if err == nil { - t.Fatalf("expecting non-nil error") - } - if len(fields) > 0 { - t.Fatalf("unexpected non-empty fields: %s", fields) - } - } - - f("") - f("{") - f(`{foo}`) - f(`{foo=bar}`) - f(`{foo="bar}`) - f(`{foo="ba\",r}`) - f(`{foo="bar" baz="aa"}`) - f(`foobar`) - f(`foo{bar="baz"}`) -} diff --git a/app/vlinsert/loki/loki_protobuf_timing_test.go b/app/vlinsert/loki/loki_protobuf_timing_test.go deleted file mode 100644 index 9349f70c37..0000000000 --- a/app/vlinsert/loki/loki_protobuf_timing_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package loki - -import ( - "fmt" - "strconv" - "testing" - "time" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil" -) - -func BenchmarkParseProtobufRequest(b *testing.B) { - for _, streams := range []int{5, 10} { - for _, rows := range []int{100, 1000} { - for _, labels := range []int{10, 50} { - b.Run(fmt.Sprintf("streams_%d/rows_%d/labels_%d", streams, rows, labels), func(b *testing.B) { - benchmarkParseProtobufRequest(b, streams, rows, labels) - }) - } - } - } -} - -func benchmarkParseProtobufRequest(b *testing.B, streams, rows, labels int) { - blp := &insertutil.BenchmarkLogMessageProcessor{} - b.ReportAllocs() - b.SetBytes(int64(streams * rows)) - b.RunParallel(func(pb *testing.PB) { - body := getProtobufBody(streams, rows, labels) - for pb.Next() { - if err := parseProtobufRequest(body, blp, nil, false, true); err != nil { - panic(fmt.Errorf("unexpected error: %w", err)) - } - } - }) -} - -func getProtobufBody(streamsCount, rowsCount, labelsCount int) []byte { - var b []byte - var entries []Entry - streams := make([]Stream, streamsCount) - for i := range streams { - b = b[:0] - b = append(b, '{') - for j := 0; j < labelsCount; j++ { - b = append(b, "label_"...) - b = strconv.AppendInt(b, int64(j), 10) - b = append(b, `="value_`...) - b = strconv.AppendInt(b, int64(j), 10) - b = append(b, '"') - if j < labelsCount-1 { - b = append(b, ',') - } - } - b = append(b, '}') - labels := string(b) - - var rowsBuf []byte - entriesLen := len(entries) - for j := 0; j < rowsCount; j++ { - rowsBufLen := len(rowsBuf) - rowsBuf = append(rowsBuf, "value_"...) - rowsBuf = strconv.AppendInt(rowsBuf, int64(j), 10) - entries = append(entries, Entry{ - Timestamp: time.Now(), - Line: bytesutil.ToUnsafeString(rowsBuf[rowsBufLen:]), - }) - } - - st := &streams[i] - st.Labels = labels - st.Entries = entries[entriesLen:] - } - pr := PushRequest{ - Streams: streams, - } - - return pr.MarshalProtobuf(nil) -} diff --git a/app/vlinsert/loki/pb.go b/app/vlinsert/loki/pb.go deleted file mode 100644 index 805e0ddfda..0000000000 --- a/app/vlinsert/loki/pb.go +++ /dev/null @@ -1,302 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: push_request.proto -// source: https://raw.githubusercontent.com/grafana/loki/main/pkg/push/push_request.proto -// Licensed under the Apache License, Version 2.0 (the "License"); -// https://github.com/grafana/loki/blob/main/pkg/push/LICENSE - -package loki - -import ( - "fmt" - "time" - - "github.com/VictoriaMetrics/easyproto" -) - -var mp easyproto.MarshalerPool - -// PushRequest represents Loki PushRequest -// -// See https://github.com/grafana/loki/blob/ada4b7b8713385fbe9f5984a5a0aaaddf1a7b851/pkg/push/push.proto#L14 -type PushRequest struct { - Streams []Stream - - entriesBuf []Entry - labelPairBuf []LabelPair -} - -func (pr *PushRequest) reset() { - pr.Streams = pr.Streams[:0] - - pr.entriesBuf = pr.entriesBuf[:0] - pr.labelPairBuf = pr.labelPairBuf[:0] -} - -// UnmarshalProtobuf unmarshals pr from protobuf message at src. -// -// pr remains valid until src is modified. -func (pr *PushRequest) UnmarshalProtobuf(src []byte) error { - pr.reset() - var err error - pr.entriesBuf, pr.labelPairBuf, err = pr.unmarshalProtobuf(pr.entriesBuf, pr.labelPairBuf, src) - return err -} - -// MarshalProtobuf marshals r to protobuf message, appends it to dst and returns the result. -func (pr *PushRequest) MarshalProtobuf(dst []byte) []byte { - m := mp.Get() - pr.marshalProtobuf(m.MessageMarshaler()) - dst = m.Marshal(dst) - mp.Put(m) - return dst -} - -func (pr *PushRequest) marshalProtobuf(mm *easyproto.MessageMarshaler) { - for _, s := range pr.Streams { - s.marshalProtobuf(mm.AppendMessage(1)) - } -} - -func (pr *PushRequest) unmarshalProtobuf(entriesBuf []Entry, labelPairBuf []LabelPair, src []byte) ([]Entry, []LabelPair, error) { - // message PushRequest { - // repeated Stream streams = 1; - // } - var err error - var fc easyproto.FieldContext - for len(src) > 0 { - src, err = fc.NextField(src) - if err != nil { - return entriesBuf, labelPairBuf, fmt.Errorf("cannot read next field in PushRequest: %w", err) - } - switch fc.FieldNum { - case 1: - data, ok := fc.MessageData() - if !ok { - return entriesBuf, labelPairBuf, fmt.Errorf("cannot read Stream data") - } - pr.Streams = append(pr.Streams, Stream{}) - s := &pr.Streams[len(pr.Streams)-1] - entriesBuf, labelPairBuf, err = s.unmarshalProtobuf(entriesBuf, labelPairBuf, data) - if err != nil { - return entriesBuf, labelPairBuf, fmt.Errorf("cannot unmarshal Stream: %w", err) - } - } - } - return entriesBuf, labelPairBuf, nil -} - -// Stream represents Loki stream. -// -// See https://github.com/grafana/loki/blob/ada4b7b8713385fbe9f5984a5a0aaaddf1a7b851/pkg/push/push.proto#L23 -type Stream struct { - Labels string - Entries []Entry -} - -func (s *Stream) marshalProtobuf(mm *easyproto.MessageMarshaler) { - mm.AppendString(1, s.Labels) - for _, e := range s.Entries { - e.marshalProtobuf(mm.AppendMessage(2)) - } -} - -func (s *Stream) unmarshalProtobuf(entriesBuf []Entry, labelPairBuf []LabelPair, src []byte) ([]Entry, []LabelPair, error) { - // message Stream { - // string labels = 1; - // repeated Entry entries = 2; - // } - var err error - var fc easyproto.FieldContext - entriesBufLen := len(entriesBuf) - for len(src) > 0 { - src, err = fc.NextField(src) - if err != nil { - return entriesBuf, labelPairBuf, fmt.Errorf("cannot read next field in Stream: %w", err) - } - switch fc.FieldNum { - case 1: - labels, ok := fc.String() - if !ok { - return entriesBuf, labelPairBuf, fmt.Errorf("cannot read labels") - } - s.Labels = labels - case 2: - data, ok := fc.MessageData() - if !ok { - return entriesBuf, labelPairBuf, fmt.Errorf("cannot read Entry data") - } - entriesBuf = append(entriesBuf, Entry{}) - e := &entriesBuf[len(entriesBuf)-1] - labelPairBuf, err = e.unmarshalProtobuf(labelPairBuf, data) - if err != nil { - return entriesBuf, labelPairBuf, fmt.Errorf("cannot unmarshal Entry: %w", err) - } - } - } - s.Entries = entriesBuf[entriesBufLen:] - return entriesBuf, labelPairBuf, nil -} - -// Entry represents Loki entry. -// -// See https://github.com/grafana/loki/blob/ada4b7b8713385fbe9f5984a5a0aaaddf1a7b851/pkg/push/push.proto#L38 -type Entry struct { - Timestamp time.Time - Line string - StructuredMetadata []LabelPair -} - -func (e *Entry) marshalProtobuf(mm *easyproto.MessageMarshaler) { - marshalTime(mm, 1, e.Timestamp) - mm.AppendString(2, e.Line) - for _, lp := range e.StructuredMetadata { - lp.marshalProtobuf(mm.AppendMessage(3)) - } -} - -func (e *Entry) unmarshalProtobuf(labelPairBuf []LabelPair, src []byte) ([]LabelPair, error) { - // message Entry { - // Timestamp timestamp = 1; - // string line = 2; - // repeated LabelPair structuredMetadata = 3; - // } - var err error - var fc easyproto.FieldContext - labelPairBufLen := len(labelPairBuf) - for len(src) > 0 { - src, err = fc.NextField(src) - if err != nil { - return labelPairBuf, fmt.Errorf("cannot read next field in Entry: %w", err) - } - switch fc.FieldNum { - case 1: - data, ok := fc.MessageData() - if !ok { - return labelPairBuf, fmt.Errorf("cannot read Timestamp data") - } - timestamp, err := unmarshalTime(data) - if err != nil { - return labelPairBuf, fmt.Errorf("cannot unmarshal Timestamp: %w", err) - } - e.Timestamp = timestamp - case 2: - line, ok := fc.String() - if !ok { - return labelPairBuf, fmt.Errorf("cannot read Line") - } - e.Line = line - case 3: - data, ok := fc.MessageData() - if !ok { - return labelPairBuf, fmt.Errorf("cannot read StructuredMetadata") - } - labelPairBuf = append(labelPairBuf, LabelPair{}) - lp := &labelPairBuf[len(labelPairBuf)-1] - if err := lp.unmarshalProtobuf(data); err != nil { - return labelPairBuf, fmt.Errorf("cannot unmarshal StructuredMetadata: %w", err) - } - } - } - e.StructuredMetadata = labelPairBuf[labelPairBufLen:] - return labelPairBuf, nil -} - -// LabelPair represents Loki label pair. -// -// See https://github.com/grafana/loki/blob/ada4b7b8713385fbe9f5984a5a0aaaddf1a7b851/pkg/push/push.proto#L33 -type LabelPair struct { - Name string - Value string -} - -func (lp *LabelPair) marshalProtobuf(mm *easyproto.MessageMarshaler) { - mm.AppendString(1, lp.Name) - mm.AppendString(2, lp.Value) -} - -func (lp *LabelPair) unmarshalProtobuf(src []byte) (err error) { - // message LabelPair { - // string name = 1; - // string value = 2; - // } - var fc easyproto.FieldContext - for len(src) > 0 { - src, err = fc.NextField(src) - if err != nil { - return fmt.Errorf("cannot read next field in LabelPair: %w", err) - } - switch fc.FieldNum { - case 1: - name, ok := fc.String() - if !ok { - return fmt.Errorf("cannot read name") - } - lp.Name = name - case 2: - value, ok := fc.String() - if !ok { - return fmt.Errorf("cannot unmarshal value") - } - lp.Value = value - } - } - return nil -} - -func marshalTime(mm *easyproto.MessageMarshaler, fieldNum uint32, timestamp time.Time) { - nsecs := timestamp.UnixNano() - ts := Timestamp{ - Seconds: nsecs / 1e9, - Nanos: int32(nsecs % 1e9), - } - ts.marshalProtobuf(mm.AppendMessage(fieldNum)) -} - -func unmarshalTime(src []byte) (time.Time, error) { - var ts Timestamp - if err := ts.unmarshalProtobuf(src); err != nil { - return time.Time{}, err - } - timestamp := time.Unix(ts.Seconds, int64(ts.Nanos)).UTC() - return timestamp, nil -} - -// Timestamp is protobuf well-known timestamp type. -type Timestamp struct { - Seconds int64 - Nanos int32 -} - -func (ts *Timestamp) marshalProtobuf(mm *easyproto.MessageMarshaler) { - mm.AppendInt64(1, ts.Seconds) - mm.AppendInt32(2, ts.Nanos) -} - -func (ts *Timestamp) unmarshalProtobuf(src []byte) (err error) { - // message Timestamp { - // int64 seconds = 1; - // int32 nanos = 2; - // } - var fc easyproto.FieldContext - for len(src) > 0 { - src, err = fc.NextField(src) - if err != nil { - return fmt.Errorf("cannot read next field in Timestamp: %w", err) - } - switch fc.FieldNum { - case 1: - seconds, ok := fc.Int64() - if !ok { - return fmt.Errorf("cannot read Seconds") - } - ts.Seconds = seconds - case 2: - nanos, ok := fc.Int32() - if !ok { - return fmt.Errorf("cannot read Nanos") - } - ts.Nanos = nanos - } - } - return nil -} diff --git a/app/vlinsert/main.go b/app/vlinsert/main.go deleted file mode 100644 index 1272d9718a..0000000000 --- a/app/vlinsert/main.go +++ /dev/null @@ -1,88 +0,0 @@ -package vlinsert - -import ( - "flag" - "fmt" - "net/http" - "strings" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/datadog" - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/elasticsearch" - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/internalinsert" - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/journald" - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/jsonline" - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/loki" - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/opentelemetry" - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/syslog" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver" -) - -var ( - disableInsert = flag.Bool("insert.disable", false, "Whether to disable /insert/* HTTP endpoints") - disableInternal = flag.Bool("internalinsert.disable", false, "Whether to disable /internal/insert HTTP endpoint") -) - -// Init initializes vlinsert -func Init() { - syslog.MustInit() -} - -// Stop stops vlinsert -func Stop() { - syslog.MustStop() -} - -// RequestHandler handles insert requests for VictoriaLogs -func RequestHandler(w http.ResponseWriter, r *http.Request) bool { - path := strings.ReplaceAll(r.URL.Path, "//", "/") - - if strings.HasPrefix(path, "/insert/") { - if *disableInsert { - httpserver.Errorf(w, r, "requests to /insert/* are disabled with -insert.disable command-line flag") - return true - } - - return insertHandler(w, r, path) - } - - if path == "/internal/insert" { - if *disableInternal || *disableInsert { - httpserver.Errorf(w, r, "requests to /internal/insert are disabled with -internalinsert.disable or -insert.disable command-line flag") - return true - } - internalinsert.RequestHandler(w, r) - return true - } - - return false -} - -func insertHandler(w http.ResponseWriter, r *http.Request, path string) bool { - switch path { - case "/insert/jsonline": - jsonline.RequestHandler(w, r) - return true - case "/insert/ready": - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - fmt.Fprintf(w, `{"status":"ok"}`) - return true - } - switch { - // some clients may omit trailing slash at elasticsearch protocol. - // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8353 - case strings.HasPrefix(path, "/insert/elasticsearch"): - return elasticsearch.RequestHandler(path, w, r) - - case strings.HasPrefix(path, "/insert/loki/"): - return loki.RequestHandler(path, w, r) - case strings.HasPrefix(path, "/insert/opentelemetry/"): - return opentelemetry.RequestHandler(path, w, r) - case strings.HasPrefix(path, "/insert/journald/"): - return journald.RequestHandler(path, w, r) - case strings.HasPrefix(path, "/insert/datadog/"): - return datadog.RequestHandler(path, w, r) - } - - return false -} diff --git a/app/vlinsert/opentelemetry/opentelemetry.go b/app/vlinsert/opentelemetry/opentelemetry.go deleted file mode 100644 index 979abb0be0..0000000000 --- a/app/vlinsert/opentelemetry/opentelemetry.go +++ /dev/null @@ -1,153 +0,0 @@ -package opentelemetry - -import ( - "fmt" - "net/http" - "time" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/opentelemetry/pb" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/protoparserutil" - "github.com/VictoriaMetrics/metrics" -) - -var maxRequestSize = flagutil.NewBytes("opentelemetry.maxRequestSize", 64*1024*1024, "The maximum size in bytes of a single OpenTelemetry request") - -// RequestHandler processes Opentelemetry insert requests -func RequestHandler(path string, w http.ResponseWriter, r *http.Request) bool { - switch path { - // use the same path as opentelemetry collector - // https://opentelemetry.io/docs/specs/otlp/#otlphttp-request - case "/insert/opentelemetry/v1/logs": - if r.Header.Get("Content-Type") == "application/json" { - httpserver.Errorf(w, r, "json encoding isn't supported for opentelemetry format. Use protobuf encoding") - return true - } - handleProtobuf(r, w) - return true - default: - return false - } -} - -func handleProtobuf(r *http.Request, w http.ResponseWriter) { - startTime := time.Now() - requestsProtobufTotal.Inc() - - cp, err := insertutil.GetCommonParams(r) - if err != nil { - httpserver.Errorf(w, r, "cannot parse common params from request: %s", err) - return - } - if err := insertutil.CanWriteData(); err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - - encoding := r.Header.Get("Content-Encoding") - err = protoparserutil.ReadUncompressedData(r.Body, encoding, maxRequestSize, func(data []byte) error { - lmp := cp.NewLogMessageProcessor("opentelelemtry_protobuf", false) - useDefaultStreamFields := len(cp.StreamFields) == 0 - err := pushProtobufRequest(data, lmp, cp.MsgFields, useDefaultStreamFields) - lmp.MustClose() - return err - }) - if err != nil { - httpserver.Errorf(w, r, "cannot read OpenTelemetry protocol data: %s", err) - return - } - - // update requestProtobufDuration only for successfully parsed requests - // There is no need in updating requestProtobufDuration for request errors, - // since their timings are usually much smaller than the timing for successful request parsing. - requestProtobufDuration.UpdateDuration(startTime) -} - -var ( - requestsProtobufTotal = metrics.NewCounter(`vl_http_requests_total{path="/insert/opentelemetry/v1/logs",format="protobuf"}`) - errorsTotal = metrics.NewCounter(`vl_http_errors_total{path="/insert/opentelemetry/v1/logs",format="protobuf"}`) - - requestProtobufDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/insert/opentelemetry/v1/logs",format="protobuf"}`) -) - -func pushProtobufRequest(data []byte, lmp insertutil.LogMessageProcessor, msgFields []string, useDefaultStreamFields bool) error { - var req pb.ExportLogsServiceRequest - if err := req.UnmarshalProtobuf(data); err != nil { - errorsTotal.Inc() - return fmt.Errorf("cannot unmarshal request from %d bytes: %w", len(data), err) - } - - var commonFields []logstorage.Field - for _, rl := range req.ResourceLogs { - commonFields = commonFields[:0] - commonFields = appendKeyValues(commonFields, rl.Resource.Attributes, "") - commonFieldsLen := len(commonFields) - for _, sc := range rl.ScopeLogs { - commonFields = pushFieldsFromScopeLogs(&sc, commonFields[:commonFieldsLen], lmp, msgFields, useDefaultStreamFields) - } - } - - return nil -} - -func pushFieldsFromScopeLogs(sc *pb.ScopeLogs, commonFields []logstorage.Field, lmp insertutil.LogMessageProcessor, msgFields []string, useDefaultStreamFields bool) []logstorage.Field { - fields := commonFields - for _, lr := range sc.LogRecords { - fields = fields[:len(commonFields)] - if lr.Body.KeyValueList != nil { - fields = appendKeyValues(fields, lr.Body.KeyValueList.Values, "") - logstorage.RenameField(fields[len(commonFields):], msgFields, "_msg") - } else { - fields = append(fields, logstorage.Field{ - Name: "_msg", - Value: lr.Body.FormatString(true), - }) - } - fields = appendKeyValues(fields, lr.Attributes, "") - if len(lr.TraceID) > 0 { - fields = append(fields, logstorage.Field{ - Name: "trace_id", - Value: lr.TraceID, - }) - } - if len(lr.SpanID) > 0 { - fields = append(fields, logstorage.Field{ - Name: "span_id", - Value: lr.SpanID, - }) - } - fields = append(fields, logstorage.Field{ - Name: "severity", - Value: lr.FormatSeverity(), - }) - - var streamFields []logstorage.Field - if useDefaultStreamFields { - streamFields = commonFields - } - lmp.AddRow(lr.ExtractTimestampNano(), fields, streamFields) - } - return fields -} - -func appendKeyValues(fields []logstorage.Field, kvs []*pb.KeyValue, parentField string) []logstorage.Field { - for _, attr := range kvs { - fieldName := attr.Key - if parentField != "" { - fieldName = parentField + "." + fieldName - } - - if attr.Value.KeyValueList != nil { - fields = appendKeyValues(fields, attr.Value.KeyValueList.Values, fieldName) - } else { - fields = append(fields, logstorage.Field{ - Name: fieldName, - Value: attr.Value.FormatString(true), - }) - } - } - return fields -} diff --git a/app/vlinsert/opentelemetry/opentelemetry_test.go b/app/vlinsert/opentelemetry/opentelemetry_test.go deleted file mode 100644 index 35996eb047..0000000000 --- a/app/vlinsert/opentelemetry/opentelemetry_test.go +++ /dev/null @@ -1,208 +0,0 @@ -package opentelemetry - -import ( - "testing" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/opentelemetry/pb" -) - -func TestPushProtoOk(t *testing.T) { - f := func(src []pb.ResourceLogs, timestampsExpected []int64, resultExpected string) { - t.Helper() - lr := pb.ExportLogsServiceRequest{ - ResourceLogs: src, - } - - pData := lr.MarshalProtobuf(nil) - tlp := &insertutil.TestLogMessageProcessor{} - if err := pushProtobufRequest(pData, tlp, nil, false); err != nil { - t.Fatalf("unexpected error: %s", err) - } - - if err := tlp.Verify(timestampsExpected, resultExpected); err != nil { - t.Fatal(err) - } - } - - // single line without resource attributes - f([]pb.ResourceLogs{ - { - ScopeLogs: []pb.ScopeLogs{ - { - LogRecords: []pb.LogRecord{ - {Attributes: []*pb.KeyValue{}, TimeUnixNano: 1234, SeverityNumber: 1, Body: pb.AnyValue{StringValue: ptrTo("log-line-message")}}, - }, - }, - }, - }, - }, - []int64{1234}, - `{"_msg":"log-line-message","severity":"Trace"}`, - ) - - // severities mapping - f([]pb.ResourceLogs{ - { - ScopeLogs: []pb.ScopeLogs{ - { - LogRecords: []pb.LogRecord{ - {Attributes: []*pb.KeyValue{}, TimeUnixNano: 1234, SeverityNumber: 1, Body: pb.AnyValue{StringValue: ptrTo("log-line-message")}}, - {Attributes: []*pb.KeyValue{}, TimeUnixNano: 1234, SeverityNumber: 13, Body: pb.AnyValue{StringValue: ptrTo("log-line-message")}}, - {Attributes: []*pb.KeyValue{}, TimeUnixNano: 1234, SeverityNumber: 24, Body: pb.AnyValue{StringValue: ptrTo("log-line-message")}}, - }, - }, - }, - }, - }, - []int64{1234, 1234, 1234}, - `{"_msg":"log-line-message","severity":"Trace"} -{"_msg":"log-line-message","severity":"Warn"} -{"_msg":"log-line-message","severity":"Fatal4"}`, - ) - - // multi-line with resource attributes - f([]pb.ResourceLogs{ - { - Resource: pb.Resource{ - Attributes: []*pb.KeyValue{ - {Key: "logger", Value: &pb.AnyValue{StringValue: ptrTo("context")}}, - {Key: "instance_id", Value: &pb.AnyValue{IntValue: ptrTo[int64](10)}}, - {Key: "node_taints", Value: &pb.AnyValue{KeyValueList: &pb.KeyValueList{ - Values: []*pb.KeyValue{ - {Key: "role", Value: &pb.AnyValue{StringValue: ptrTo("dev")}}, - {Key: "cluster_load_percent", Value: &pb.AnyValue{DoubleValue: ptrTo(0.55)}}, - }, - }}}, - }, - }, - ScopeLogs: []pb.ScopeLogs{ - { - LogRecords: []pb.LogRecord{ - {Attributes: []*pb.KeyValue{}, TimeUnixNano: 1234, SeverityNumber: 1, Body: pb.AnyValue{StringValue: ptrTo("log-line-message")}}, - {Attributes: []*pb.KeyValue{}, TimeUnixNano: 1235, SeverityNumber: 25, Body: pb.AnyValue{StringValue: ptrTo("log-line-message-msg-2")}}, - {Attributes: []*pb.KeyValue{}, TimeUnixNano: 1236, SeverityNumber: -1, Body: pb.AnyValue{StringValue: ptrTo("log-line-message-msg-2")}}, - }, - }, - }, - }, - }, - []int64{1234, 1235, 1236}, - `{"logger":"context","instance_id":"10","node_taints.role":"dev","node_taints.cluster_load_percent":"0.55","_msg":"log-line-message","severity":"Trace"} -{"logger":"context","instance_id":"10","node_taints.role":"dev","node_taints.cluster_load_percent":"0.55","_msg":"log-line-message-msg-2","severity":"Unspecified"} -{"logger":"context","instance_id":"10","node_taints.role":"dev","node_taints.cluster_load_percent":"0.55","_msg":"log-line-message-msg-2","severity":"Unspecified"}`, - ) - - // multi-scope with resource attributes and multi-line - f([]pb.ResourceLogs{ - { - Resource: pb.Resource{ - Attributes: []*pb.KeyValue{ - {Key: "logger", Value: &pb.AnyValue{StringValue: ptrTo("context")}}, - {Key: "instance_id", Value: &pb.AnyValue{IntValue: ptrTo[int64](10)}}, - {Key: "node_taints", Value: &pb.AnyValue{KeyValueList: &pb.KeyValueList{ - Values: []*pb.KeyValue{ - {Key: "role", Value: &pb.AnyValue{StringValue: ptrTo("dev")}}, - {Key: "cluster_load_percent", Value: &pb.AnyValue{DoubleValue: ptrTo(0.55)}}, - }, - }}}, - }, - }, - ScopeLogs: []pb.ScopeLogs{ - { - LogRecords: []pb.LogRecord{ - {TimeUnixNano: 1234, SeverityNumber: 1, Body: pb.AnyValue{StringValue: ptrTo("log-line-message")}}, - {TimeUnixNano: 1235, SeverityNumber: 5, Body: pb.AnyValue{StringValue: ptrTo("log-line-message-msg-2")}}, - }, - }, - }, - }, - { - ScopeLogs: []pb.ScopeLogs{ - { - LogRecords: []pb.LogRecord{ - {TimeUnixNano: 2345, SeverityNumber: 10, Body: pb.AnyValue{StringValue: ptrTo("log-line-resource-scope-1-0-0")}}, - {TimeUnixNano: 2346, SeverityNumber: 10, Body: pb.AnyValue{StringValue: ptrTo("log-line-resource-scope-1-0-1")}}, - }, - }, - { - LogRecords: []pb.LogRecord{ - {TimeUnixNano: 2347, SeverityNumber: 12, Body: pb.AnyValue{StringValue: ptrTo("log-line-resource-scope-1-1-0")}}, - {TraceID: "1234", SpanID: "45", ObservedTimeUnixNano: 2348, SeverityNumber: 12, Body: pb.AnyValue{StringValue: ptrTo("log-line-resource-scope-1-1-1")}}, - {TraceID: "4bf92f3577b34da6a3ce929d0e0e4736", SpanID: "00f067aa0ba902b7", ObservedTimeUnixNano: 3333, Body: pb.AnyValue{StringValue: ptrTo("log-line-resource-scope-1-1-2")}}, - }, - }, - }, - }, - }, - []int64{1234, 1235, 2345, 2346, 2347, 2348, 3333}, - `{"logger":"context","instance_id":"10","node_taints.role":"dev","node_taints.cluster_load_percent":"0.55","_msg":"log-line-message","severity":"Trace"} -{"logger":"context","instance_id":"10","node_taints.role":"dev","node_taints.cluster_load_percent":"0.55","_msg":"log-line-message-msg-2","severity":"Debug"} -{"_msg":"log-line-resource-scope-1-0-0","severity":"Info2"} -{"_msg":"log-line-resource-scope-1-0-1","severity":"Info2"} -{"_msg":"log-line-resource-scope-1-1-0","severity":"Info4"} -{"_msg":"log-line-resource-scope-1-1-1","trace_id":"1234","span_id":"45","severity":"Info4"} -{"_msg":"log-line-resource-scope-1-1-2","trace_id":"4bf92f3577b34da6a3ce929d0e0e4736","span_id":"00f067aa0ba902b7","severity":"Unspecified"}`, - ) - - // nested fields - f([]pb.ResourceLogs{ - { - ScopeLogs: []pb.ScopeLogs{ - { - LogRecords: []pb.LogRecord{ - { - TimeUnixNano: 1234, - Body: pb.AnyValue{StringValue: ptrTo("nested fields")}, - Attributes: []*pb.KeyValue{ - {Key: "error", Value: &pb.AnyValue{KeyValueList: &pb.KeyValueList{Values: []*pb.KeyValue{ - { - Key: "type", - Value: &pb.AnyValue{StringValue: ptrTo("document_parsing_exception")}, - }, - { - Key: "reason", - Value: &pb.AnyValue{StringValue: ptrTo("failed to parse field [_msg] of type [text]")}, - }, - { - Key: "caused_by", - Value: &pb.AnyValue{KeyValueList: &pb.KeyValueList{Values: []*pb.KeyValue{ - { - Key: "type", - Value: &pb.AnyValue{StringValue: ptrTo("x_content_parse_exception")}, - }, - { - Key: "reason", - Value: &pb.AnyValue{StringValue: ptrTo("unexpected end-of-input in VALUE_STRING")}, - }, - { - Key: "caused_by", - Value: &pb.AnyValue{KeyValueList: &pb.KeyValueList{Values: []*pb.KeyValue{ - { - Key: "type", - Value: &pb.AnyValue{StringValue: ptrTo("json_e_o_f_exception")}, - }, - { - Key: "reason", - Value: &pb.AnyValue{StringValue: ptrTo("eof")}, - }, - }}}, - }, - }}}, - }, - }}}}, - }, - }, - }, - }, - }, - }, - }, []int64{1234}, - `{"_msg":"nested fields","error.type":"document_parsing_exception","error.reason":"failed to parse field [_msg] of type [text]",`+ - `"error.caused_by.type":"x_content_parse_exception","error.caused_by.reason":"unexpected end-of-input in VALUE_STRING",`+ - `"error.caused_by.caused_by.type":"json_e_o_f_exception","error.caused_by.caused_by.reason":"eof","severity":"Unspecified"}`) -} - -func ptrTo[T any](s T) *T { - return &s -} diff --git a/app/vlinsert/opentelemetry/opentelemetry_timing_test.go b/app/vlinsert/opentelemetry/opentelemetry_timing_test.go deleted file mode 100644 index 84a4a05f5e..0000000000 --- a/app/vlinsert/opentelemetry/opentelemetry_timing_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package opentelemetry - -import ( - "fmt" - "testing" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/opentelemetry/pb" -) - -func BenchmarkParseProtobufRequest(b *testing.B) { - for _, scopes := range []int{1, 2} { - for _, rows := range []int{100, 1000} { - for _, attributes := range []int{5, 10} { - b.Run(fmt.Sprintf("scopes_%d/rows_%d/attributes_%d", scopes, rows, attributes), func(b *testing.B) { - benchmarkParseProtobufRequest(b, scopes, rows, attributes) - }) - } - } - } -} - -func benchmarkParseProtobufRequest(b *testing.B, streams, rows, labels int) { - blp := &insertutil.BenchmarkLogMessageProcessor{} - b.ReportAllocs() - b.SetBytes(int64(streams * rows)) - b.RunParallel(func(pb *testing.PB) { - body := getProtobufBody(streams, rows, labels) - for pb.Next() { - if err := pushProtobufRequest(body, blp, nil, false); err != nil { - panic(fmt.Errorf("unexpected error: %w", err)) - } - } - }) -} - -func getProtobufBody(scopesCount, rowsCount, attributesCount int) []byte { - msg := "12345678910" - - attrValues := []*pb.AnyValue{ - {StringValue: ptrTo("string-attribute")}, - {IntValue: ptrTo[int64](12345)}, - {DoubleValue: ptrTo(3.14)}, - } - attrs := make([]*pb.KeyValue, attributesCount) - for j := 0; j < attributesCount; j++ { - attrs[j] = &pb.KeyValue{ - Key: fmt.Sprintf("key-%d", j), - Value: attrValues[j%3], - } - } - entries := make([]pb.LogRecord, rowsCount) - for j := 0; j < rowsCount; j++ { - entries[j] = pb.LogRecord{ - TimeUnixNano: 12345678910, ObservedTimeUnixNano: 12345678910, Body: pb.AnyValue{StringValue: &msg}, - } - } - scopes := make([]pb.ScopeLogs, scopesCount) - - for j := 0; j < scopesCount; j++ { - scopes[j] = pb.ScopeLogs{ - LogRecords: entries, - } - } - - pr := pb.ExportLogsServiceRequest{ - ResourceLogs: []pb.ResourceLogs{ - { - Resource: pb.Resource{ - Attributes: attrs, - }, - ScopeLogs: scopes, - }, - }, - } - - return pr.MarshalProtobuf(nil) -} diff --git a/app/vlinsert/syslog/syslog.go b/app/vlinsert/syslog/syslog.go deleted file mode 100644 index 3b9749c410..0000000000 --- a/app/vlinsert/syslog/syslog.go +++ /dev/null @@ -1,607 +0,0 @@ -package syslog - -import ( - "bufio" - "crypto/tls" - "encoding/json" - "errors" - "flag" - "fmt" - "io" - "net" - "sort" - "strconv" - "strings" - "sync" - "sync/atomic" - "time" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/cgroup" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/ingestserver" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/netutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/protoparserutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/slicesutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/writeconcurrencylimiter" - "github.com/VictoriaMetrics/metrics" -) - -var ( - syslogTimezone = flag.String("syslog.timezone", "Local", "Timezone to use when parsing timestamps in RFC3164 syslog messages. Timezone must be a valid IANA Time Zone. "+ - "For example: America/New_York, Europe/Berlin, Etc/GMT+3 . See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/") - - streamFieldsTCP = flagutil.NewArrayString("syslog.streamFields.tcp", "Fields to use as log stream labels for logs ingested via the corresponding -syslog.listenAddr.tcp. "+ - `See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#stream-fields`) - streamFieldsUDP = flagutil.NewArrayString("syslog.streamFields.udp", "Fields to use as log stream labels for logs ingested via the corresponding -syslog.listenAddr.udp. "+ - `See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#stream-fields`) - - ignoreFieldsTCP = flagutil.NewArrayString("syslog.ignoreFields.tcp", "Fields to ignore at logs ingested via the corresponding -syslog.listenAddr.tcp. "+ - `See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#dropping-fields`) - ignoreFieldsUDP = flagutil.NewArrayString("syslog.ignoreFields.udp", "Fields to ignore at logs ingested via the corresponding -syslog.listenAddr.udp. "+ - `See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#dropping-fields`) - - decolorizeFieldsTCP = flagutil.NewArrayString("syslog.decolorizeFields.tcp", "Fields to remove ANSI color codes across logs ingested via the corresponding -syslog.listenAddr.tcp. "+ - `See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#decolorizing-fields`) - decolorizeFieldsUDP = flagutil.NewArrayString("syslog.decolorizeFields.udp", "Fields to remove ANSI color codes across logs ingested via the corresponding -syslog.listenAddr.udp. "+ - `See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#decolorizing-fields`) - - extraFieldsTCP = flagutil.NewArrayString("syslog.extraFields.tcp", "Fields to add to logs ingested via the corresponding -syslog.listenAddr.tcp. "+ - `See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#adding-extra-fields`) - extraFieldsUDP = flagutil.NewArrayString("syslog.extraFields.udp", "Fields to add to logs ingested via the corresponding -syslog.listenAddr.udp. "+ - `See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#adding-extra-fields`) - - tenantIDTCP = flagutil.NewArrayString("syslog.tenantID.tcp", "TenantID for logs ingested via the corresponding -syslog.listenAddr.tcp. "+ - "See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#multitenancy") - tenantIDUDP = flagutil.NewArrayString("syslog.tenantID.udp", "TenantID for logs ingested via the corresponding -syslog.listenAddr.udp. "+ - "See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#multitenancy") - - listenAddrTCP = flagutil.NewArrayString("syslog.listenAddr.tcp", "Comma-separated list of TCP addresses to listen to for Syslog messages. "+ - "See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/") - listenAddrUDP = flagutil.NewArrayString("syslog.listenAddr.udp", "Comma-separated list of UDP address to listen to for Syslog messages. "+ - "See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/") - - tlsEnable = flagutil.NewArrayBool("syslog.tls", "Whether to enable TLS for receiving syslog messages at the corresponding -syslog.listenAddr.tcp. "+ - "The corresponding -syslog.tlsCertFile and -syslog.tlsKeyFile must be set if -syslog.tls is set. See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#security") - tlsCertFile = flagutil.NewArrayString("syslog.tlsCertFile", "Path to file with TLS certificate for the corresponding -syslog.listenAddr.tcp if the corresponding -syslog.tls is set. "+ - "Prefer ECDSA certs instead of RSA certs as RSA certs are slower. The provided certificate file is automatically re-read every second, so it can be dynamically updated. "+ - "See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#security") - tlsKeyFile = flagutil.NewArrayString("syslog.tlsKeyFile", "Path to file with TLS key for the corresponding -syslog.listenAddr.tcp if the corresponding -syslog.tls is set. "+ - "The provided key file is automatically re-read every second, so it can be dynamically updated. "+ - "See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#security") - tlsCipherSuites = flagutil.NewArrayString("syslog.tlsCipherSuites", "Optional list of TLS cipher suites for -syslog.listenAddr.tcp if -syslog.tls is set. "+ - "See the list of supported cipher suites at https://pkg.go.dev/crypto/tls#pkg-constants . "+ - "See also https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#security") - tlsMinVersion = flag.String("syslog.tlsMinVersion", "TLS13", "The minimum TLS version to use for -syslog.listenAddr.tcp if -syslog.tls is set. "+ - "Supported values: TLS10, TLS11, TLS12, TLS13. "+ - "See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#security") - - compressMethodTCP = flagutil.NewArrayString("syslog.compressMethod.tcp", "Compression method for syslog messages received at the corresponding -syslog.listenAddr.tcp. "+ - "Supported values: none, gzip, deflate. See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#compression") - compressMethodUDP = flagutil.NewArrayString("syslog.compressMethod.udp", "Compression method for syslog messages received at the corresponding -syslog.listenAddr.udp. "+ - "Supported values: none, gzip, deflate. See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#compression") - - useLocalTimestampTCP = flagutil.NewArrayBool("syslog.useLocalTimestamp.tcp", "Whether to use local timestamp instead of the original timestamp for the ingested syslog messages "+ - "at the corresponding -syslog.listenAddr.tcp. See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#log-timestamps") - useLocalTimestampUDP = flagutil.NewArrayBool("syslog.useLocalTimestamp.udp", "Whether to use local timestamp instead of the original timestamp for the ingested syslog messages "+ - "at the corresponding -syslog.listenAddr.udp. See https://docs.victoriametrics.com/victorialogs/data-ingestion/syslog/#log-timestamps") -) - -// MustInit initializes syslog parser at the given -syslog.listenAddr.tcp and -syslog.listenAddr.udp ports -// -// This function must be called after flag.Parse(). -// -// MustStop() must be called in order to free up resources occupied by the initialized syslog parser. -func MustInit() { - if workersStopCh != nil { - logger.Panicf("BUG: MustInit() called twice without MustStop() call") - } - workersStopCh = make(chan struct{}) - - for argIdx, addr := range *listenAddrTCP { - workersWG.Add(1) - go func(addr string, argIdx int) { - runTCPListener(addr, argIdx) - workersWG.Done() - }(addr, argIdx) - } - - for argIdx, addr := range *listenAddrUDP { - workersWG.Add(1) - go func(addr string, argIdx int) { - runUDPListener(addr, argIdx) - workersWG.Done() - }(addr, argIdx) - } - - currentYear := time.Now().Year() - globalCurrentYear.Store(int64(currentYear)) - workersWG.Add(1) - go func() { - ticker := time.NewTicker(time.Minute) - for { - select { - case <-workersStopCh: - ticker.Stop() - workersWG.Done() - return - case <-ticker.C: - currentYear := time.Now().Year() - globalCurrentYear.Store(int64(currentYear)) - } - } - }() - - if *syslogTimezone != "" { - tz, err := time.LoadLocation(*syslogTimezone) - if err != nil { - logger.Fatalf("cannot parse -syslog.timezone=%q: %s", *syslogTimezone, err) - } - globalTimezone = tz - } else { - globalTimezone = time.Local - } -} - -var ( - globalCurrentYear atomic.Int64 - globalTimezone *time.Location -) - -var ( - workersWG sync.WaitGroup - workersStopCh chan struct{} -) - -// MustStop stops syslog parser initialized via MustInit() -func MustStop() { - close(workersStopCh) - workersWG.Wait() - workersStopCh = nil -} - -func runUDPListener(addr string, argIdx int) { - ln, err := net.ListenPacket(netutil.GetUDPNetwork(), addr) - if err != nil { - logger.Fatalf("cannot start UDP syslog server at %q: %s", addr, err) - } - - tenantIDStr := tenantIDUDP.GetOptionalArg(argIdx) - tenantID, err := logstorage.ParseTenantID(tenantIDStr) - if err != nil { - logger.Fatalf("cannot parse -syslog.tenantID.udp=%q for -syslog.listenAddr.udp=%q: %s", tenantIDStr, addr, err) - } - - compressMethod := compressMethodUDP.GetOptionalArg(argIdx) - checkCompressMethod(compressMethod, addr, "udp") - - useLocalTimestamp := useLocalTimestampUDP.GetOptionalArg(argIdx) - - streamFieldsStr := streamFieldsUDP.GetOptionalArg(argIdx) - streamFields, err := parseFieldsList(streamFieldsStr) - if err != nil { - logger.Fatalf("cannot parse -syslog.streamFields.udp=%q for -syslog.listenAddr.udp=%q: %s", streamFieldsStr, addr, err) - } - - ignoreFieldsStr := ignoreFieldsUDP.GetOptionalArg(argIdx) - ignoreFields, err := parseFieldsList(ignoreFieldsStr) - if err != nil { - logger.Fatalf("cannot parse -syslog.ignoreFields.udp=%q for -syslog.listenAddr.udp=%q: %s", ignoreFieldsStr, addr, err) - } - - decolorizeFieldsStr := decolorizeFieldsUDP.GetOptionalArg(argIdx) - decolorizeFields, err := parseFieldsList(decolorizeFieldsStr) - if err != nil { - logger.Fatalf("cannot parse -syslog.decolorizeFields.udp=%q for -syslog.listenAddr.udp=%q: %s", decolorizeFieldsStr, addr, err) - } - - extraFieldsStr := extraFieldsUDP.GetOptionalArg(argIdx) - extraFields, err := parseExtraFields(extraFieldsStr) - if err != nil { - logger.Fatalf("cannot parse -syslog.extraFields.udp=%q for -syslog.listenAddr.udp=%q: %s", extraFieldsStr, addr, err) - } - - doneCh := make(chan struct{}) - go func() { - serveUDP(ln, tenantID, compressMethod, useLocalTimestamp, streamFields, ignoreFields, decolorizeFields, extraFields) - close(doneCh) - }() - - logger.Infof("started accepting syslog messages at -syslog.listenAddr.udp=%q", addr) - <-workersStopCh - if err := ln.Close(); err != nil { - logger.Fatalf("syslog: cannot close UDP listener at %s: %s", addr, err) - } - <-doneCh - logger.Infof("finished accepting syslog messages at -syslog.listenAddr.udp=%q", addr) -} - -func runTCPListener(addr string, argIdx int) { - var tlsConfig *tls.Config - if tlsEnable.GetOptionalArg(argIdx) { - certFile := tlsCertFile.GetOptionalArg(argIdx) - keyFile := tlsKeyFile.GetOptionalArg(argIdx) - tc, err := netutil.GetServerTLSConfig(certFile, keyFile, *tlsMinVersion, *tlsCipherSuites) - if err != nil { - logger.Fatalf("cannot load TLS cert from -syslog.tlsCertFile=%q, -syslog.tlsKeyFile=%q, -syslog.tlsMinVersion=%q, -syslog.tlsCipherSuites=%q: %s", - certFile, keyFile, *tlsMinVersion, *tlsCipherSuites, err) - } - tlsConfig = tc - } - ln, err := netutil.NewTCPListener("syslog", addr, false, tlsConfig) - if err != nil { - logger.Fatalf("syslog: cannot start TCP listener at %s: %s", addr, err) - } - - tenantIDStr := tenantIDTCP.GetOptionalArg(argIdx) - tenantID, err := logstorage.ParseTenantID(tenantIDStr) - if err != nil { - logger.Fatalf("cannot parse -syslog.tenantID.tcp=%q for -syslog.listenAddr.tcp=%q: %s", tenantIDStr, addr, err) - } - - compressMethod := compressMethodTCP.GetOptionalArg(argIdx) - checkCompressMethod(compressMethod, addr, "tcp") - - useLocalTimestamp := useLocalTimestampTCP.GetOptionalArg(argIdx) - - streamFieldsStr := streamFieldsTCP.GetOptionalArg(argIdx) - streamFields, err := parseFieldsList(streamFieldsStr) - if err != nil { - logger.Fatalf("cannot parse -syslog.streamFields.tcp=%q for -syslog.listenAddr.tcp=%q: %s", streamFieldsStr, addr, err) - } - - ignoreFieldsStr := ignoreFieldsTCP.GetOptionalArg(argIdx) - ignoreFields, err := parseFieldsList(ignoreFieldsStr) - if err != nil { - logger.Fatalf("cannot parse -syslog.ignoreFields.tcp=%q for -syslog.listenAddr.tcp=%q: %s", ignoreFieldsStr, addr, err) - } - - decolorizeFieldsStr := decolorizeFieldsTCP.GetOptionalArg(argIdx) - decolorizeFields, err := parseFieldsList(decolorizeFieldsStr) - if err != nil { - logger.Fatalf("cannot parse -syslog.decolorizeFields.tcp=%q for -syslog.listenAddr.tcp=%q: %s", decolorizeFieldsStr, addr, err) - } - - extraFieldsStr := extraFieldsTCP.GetOptionalArg(argIdx) - extraFields, err := parseExtraFields(extraFieldsStr) - if err != nil { - logger.Fatalf("cannot parse -syslog.extraFields.tcp=%q for -syslog.listenAddr.tcp=%q: %s", extraFieldsStr, addr, err) - } - - doneCh := make(chan struct{}) - go func() { - serveTCP(ln, tenantID, compressMethod, useLocalTimestamp, streamFields, ignoreFields, decolorizeFields, extraFields) - close(doneCh) - }() - - logger.Infof("started accepting syslog messages at -syslog.listenAddr.tcp=%q", addr) - <-workersStopCh - if err := ln.Close(); err != nil { - logger.Fatalf("syslog: cannot close TCP listener at %s: %s", addr, err) - } - <-doneCh - logger.Infof("finished accepting syslog messages at -syslog.listenAddr.tcp=%q", addr) -} - -func checkCompressMethod(compressMethod, addr, protocol string) { - switch compressMethod { - case "", "none", "zstd", "gzip", "deflate": - return - default: - logger.Fatalf("unsupported -syslog.compressMethod.%s=%q for -syslog.listenAddr.%s=%q; supported values: 'none', 'zstd', 'gzip', 'deflate'", protocol, compressMethod, protocol, addr) - } -} - -func serveUDP(ln net.PacketConn, tenantID logstorage.TenantID, encoding string, useLocalTimestamp bool, streamFields, ignoreFields, decolorizeFields []string, extraFields []logstorage.Field) { - gomaxprocs := cgroup.AvailableCPUs() - var wg sync.WaitGroup - localAddr := ln.LocalAddr() - for i := 0; i < gomaxprocs; i++ { - wg.Add(1) - go func() { - defer wg.Done() - cp := insertutil.GetCommonParamsForSyslog(tenantID, streamFields, ignoreFields, decolorizeFields, extraFields) - var bb bytesutil.ByteBuffer - bb.B = bytesutil.ResizeNoCopyNoOverallocate(bb.B, 64*1024) - for { - bb.Reset() - bb.B = bb.B[:cap(bb.B)] - n, remoteAddr, err := ln.ReadFrom(bb.B) - if err != nil { - udpErrorsTotal.Inc() - var ne net.Error - if errors.As(err, &ne) { - if ne.Temporary() { - logger.Errorf("syslog: temporary error when listening for UDP at %q: %s", localAddr, err) - time.Sleep(time.Second) - continue - } - if strings.Contains(err.Error(), "use of closed network connection") { - break - } - } - logger.Errorf("syslog: cannot read UDP data from %s at %s: %s", remoteAddr, localAddr, err) - continue - } - bb.B = bb.B[:n] - udpRequestsTotal.Inc() - if err := processStream("udp", bb.NewReader(), encoding, useLocalTimestamp, cp); err != nil { - logger.Errorf("syslog: cannot process UDP data from %s at %s: %s", remoteAddr, localAddr, err) - } - } - }() - } - wg.Wait() -} - -func serveTCP(ln net.Listener, tenantID logstorage.TenantID, encoding string, useLocalTimestamp bool, streamFields, ignoreFields, decolorizeFields []string, extraFields []logstorage.Field) { - var cm ingestserver.ConnsMap - cm.Init("syslog") - - var wg sync.WaitGroup - addr := ln.Addr() - for { - c, err := ln.Accept() - if err != nil { - var ne net.Error - if errors.As(err, &ne) { - if ne.Temporary() { - logger.Errorf("syslog: temporary error when listening for TCP addr %q: %s", addr, err) - time.Sleep(time.Second) - continue - } - if strings.Contains(err.Error(), "use of closed network connection") { - break - } - logger.Fatalf("syslog: unrecoverable error when accepting TCP connections at %q: %s", addr, err) - } - logger.Fatalf("syslog: unexpected error when accepting TCP connections at %q: %s", addr, err) - } - if !cm.Add(c) { - _ = c.Close() - break - } - - wg.Add(1) - go func() { - cp := insertutil.GetCommonParamsForSyslog(tenantID, streamFields, ignoreFields, decolorizeFields, extraFields) - if err := processStream("tcp", c, encoding, useLocalTimestamp, cp); err != nil { - logger.Errorf("syslog: cannot process TCP data at %q: %s", addr, err) - } - - cm.Delete(c) - _ = c.Close() - wg.Done() - }() - } - - cm.CloseAll(0) - wg.Wait() -} - -// processStream parses a stream of syslog messages from r and ingests them into vlstorage. -func processStream(protocol string, r io.Reader, encoding string, useLocalTimestamp bool, cp *insertutil.CommonParams) error { - if err := insertutil.CanWriteData(); err != nil { - return err - } - - lmp := cp.NewLogMessageProcessor("syslog_"+protocol, true) - err := processStreamInternal(r, encoding, useLocalTimestamp, lmp) - lmp.MustClose() - - return err -} - -func processStreamInternal(r io.Reader, encoding string, useLocalTimestamp bool, lmp insertutil.LogMessageProcessor) error { - reader, err := protoparserutil.GetUncompressedReader(r, encoding) - if err != nil { - return fmt.Errorf("cannot decode syslog data: %w", err) - } - defer protoparserutil.PutUncompressedReader(reader) - - return processUncompressedStream(reader, useLocalTimestamp, lmp) -} - -func processUncompressedStream(r io.Reader, useLocalTimestamp bool, lmp insertutil.LogMessageProcessor) error { - wcr := writeconcurrencylimiter.GetReader(r) - defer writeconcurrencylimiter.PutReader(wcr) - - slr := getSyslogLineReader(wcr) - defer putSyslogLineReader(slr) - - n := 0 - for { - ok := slr.nextLine() - wcr.DecConcurrency() - if !ok { - break - } - - currentYear := int(globalCurrentYear.Load()) - err := processLine(slr.line, currentYear, globalTimezone, useLocalTimestamp, lmp) - if err != nil { - errorsTotal.Inc() - return fmt.Errorf("cannot read line #%d: %s", n, err) - } - n++ - } - return slr.Error() -} - -type syslogLineReader struct { - line []byte - - br *bufio.Reader - err error -} - -func (slr *syslogLineReader) reset(r io.Reader) { - slr.line = slr.line[:0] - slr.br.Reset(r) - slr.err = nil -} - -// Error returns the last error occurred in slr. -func (slr *syslogLineReader) Error() error { - if slr.err == nil || slr.err == io.EOF { - return nil - } - return slr.err -} - -// nextLine reads the next syslog line from slr and stores it at slr.line. -// -// false is returned if the next line cannot be read. Error() must be called in this case -// in order to verify whether there is an error or just slr stream has been finished. -func (slr *syslogLineReader) nextLine() bool { - if slr.err != nil { - return false - } - -again: - prefix, err := slr.br.ReadSlice(' ') - if err != nil { - if err != io.EOF { - slr.err = fmt.Errorf("cannot read message frame prefix: %w", err) - return false - } - if len(prefix) == 0 { - slr.err = err - return false - } - } - // skip empty lines - for len(prefix) > 0 && prefix[0] == '\n' { - prefix = prefix[1:] - } - if len(prefix) == 0 { - // An empty prefix or a prefix with empty lines - try reading yet another prefix. - goto again - } - - if prefix[0] >= '0' && prefix[0] <= '9' { - // This is octet-counting method. See https://www.ietf.org/archive/id/draft-gerhards-syslog-plain-tcp-07.html#msgxfer - msgLenStr := bytesutil.ToUnsafeString(prefix[:len(prefix)-1]) - msgLen, err := strconv.ParseUint(msgLenStr, 10, 64) - if err != nil { - slr.err = fmt.Errorf("cannot parse message length from %q: %w", msgLenStr, err) - return false - } - if maxMsgLen := insertutil.MaxLineSizeBytes.IntN(); msgLen > uint64(maxMsgLen) { - slr.err = fmt.Errorf("cannot read message longer than %d bytes; msgLen=%d", maxMsgLen, msgLen) - return false - } - slr.line = slicesutil.SetLength(slr.line, int(msgLen)) - if _, err := io.ReadFull(slr.br, slr.line); err != nil { - slr.err = fmt.Errorf("cannot read message with size %d bytes: %w", msgLen, err) - return false - } - return true - } - - // This is octet-stuffing method. See https://www.ietf.org/archive/id/draft-gerhards-syslog-plain-tcp-07.html#octet-stuffing-legacy - slr.line = append(slr.line[:0], prefix...) - for { - line, err := slr.br.ReadSlice('\n') - if err == nil { - slr.line = append(slr.line, line[:len(line)-1]...) - return true - } - if err == io.EOF { - slr.line = append(slr.line, line...) - return true - } - if err == bufio.ErrBufferFull { - slr.line = append(slr.line, line...) - continue - } - slr.err = fmt.Errorf("cannot read message in octet-stuffing method: %w", err) - return false - } -} - -func getSyslogLineReader(r io.Reader) *syslogLineReader { - v := syslogLineReaderPool.Get() - if v == nil { - br := bufio.NewReaderSize(r, 64*1024) - return &syslogLineReader{ - br: br, - } - } - slr := v.(*syslogLineReader) - slr.reset(r) - return slr -} - -func putSyslogLineReader(slr *syslogLineReader) { - syslogLineReaderPool.Put(slr) -} - -var syslogLineReaderPool sync.Pool - -func processLine(line []byte, currentYear int, timezone *time.Location, useLocalTimestamp bool, lmp insertutil.LogMessageProcessor) error { - p := logstorage.GetSyslogParser(currentYear, timezone) - lineStr := bytesutil.ToUnsafeString(line) - p.Parse(lineStr) - - var ts int64 - if useLocalTimestamp { - ts = time.Now().UnixNano() - } else { - nsecs, err := insertutil.ExtractTimestampFromFields(timeFields, p.Fields) - if err != nil { - return fmt.Errorf("cannot get timestamp from syslog line %q: %w", line, err) - } - ts = nsecs - } - logstorage.RenameField(p.Fields, msgFields, "_msg") - lmp.AddRow(ts, p.Fields, nil) - logstorage.PutSyslogParser(p) - - return nil -} - -var timeFields = []string{"timestamp"} -var msgFields = []string{"message"} - -var ( - errorsTotal = metrics.NewCounter(`vl_errors_total{type="syslog"}`) - - udpRequestsTotal = metrics.NewCounter(`vl_udp_reqests_total{type="syslog"}`) - udpErrorsTotal = metrics.NewCounter(`vl_udp_errors_total{type="syslog"}`) -) - -func parseFieldsList(s string) ([]string, error) { - if s == "" { - return nil, nil - } - - var a []string - err := json.Unmarshal([]byte(s), &a) - return a, err -} - -func parseExtraFields(s string) ([]logstorage.Field, error) { - if s == "" { - return nil, nil - } - - var m map[string]string - if err := json.Unmarshal([]byte(s), &m); err != nil { - return nil, err - } - fields := make([]logstorage.Field, 0, len(m)) - for k, v := range m { - fields = append(fields, logstorage.Field{ - Name: k, - Value: v, - }) - } - sort.Slice(fields, func(i, j int) bool { - return fields[i].Name < fields[j].Name - }) - return fields, nil -} diff --git a/app/vlinsert/syslog/syslog_test.go b/app/vlinsert/syslog/syslog_test.go deleted file mode 100644 index eb59283bbe..0000000000 --- a/app/vlinsert/syslog/syslog_test.go +++ /dev/null @@ -1,129 +0,0 @@ -package syslog - -import ( - "bytes" - "reflect" - "testing" - "time" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutil" -) - -func TestSyslogLineReader_Success(t *testing.T) { - f := func(data string, linesExpected []string) { - t.Helper() - - r := bytes.NewBufferString(data) - slr := getSyslogLineReader(r) - defer putSyslogLineReader(slr) - - var lines []string - for slr.nextLine() { - lines = append(lines, string(slr.line)) - } - if err := slr.Error(); err != nil { - t.Fatalf("unexpected error: %s", err) - } - if !reflect.DeepEqual(lines, linesExpected) { - t.Fatalf("unexpected lines read;\ngot\n%q\nwant\n%q", lines, linesExpected) - } - } - - f("", nil) - f("\n", nil) - f("\n\n\n", nil) - - f("foobar", []string{"foobar"}) - f("foobar\n", []string{"foobar\n"}) - f("\n\nfoo\n\nbar\n\n", []string{"foo\n\nbar\n\n"}) - - f(`Jun 3 12:08:33 abcd systemd: Starting Update the local ESM caches...`, []string{"Jun 3 12:08:33 abcd systemd: Starting Update the local ESM caches..."}) - - f(`Jun 3 12:08:33 abcd systemd: Starting Update the local ESM caches... - -48 <165>Jun 4 12:08:33 abcd systemd[345]: abc defg<123>1 2023-06-03T17:42:12.345Z mymachine.example.com appname 12345 ID47 [exampleSDID@32473 iut="3" eventSource="Application 123 = ] 56" eventID="11211"] This is a test message with structured data. - -`, []string{ - "Jun 3 12:08:33 abcd systemd: Starting Update the local ESM caches...", - "<165>Jun 4 12:08:33 abcd systemd[345]: abc defg", - `<123>1 2023-06-03T17:42:12.345Z mymachine.example.com appname 12345 ID47 [exampleSDID@32473 iut="3" eventSource="Application 123 = ] 56" eventID="11211"] This is a test message with structured data.`, - }) -} - -func TestSyslogLineReader_Failure(t *testing.T) { - f := func(data string) { - t.Helper() - - r := bytes.NewBufferString(data) - slr := getSyslogLineReader(r) - defer putSyslogLineReader(slr) - - if slr.nextLine() { - t.Fatalf("expecting failure to read the first line") - } - if err := slr.Error(); err == nil { - t.Fatalf("expecting non-nil error") - } - } - - // invalid format for message size - f("12foo bar") - - // too big message size - f("123 aa") - f("1233423432 abc") -} - -func TestProcessStreamInternal_Success(t *testing.T) { - f := func(data string, currentYear int, timestampsExpected []int64, resultExpected string) { - t.Helper() - - MustInit() - defer MustStop() - - globalTimezone = time.UTC - globalCurrentYear.Store(int64(currentYear)) - - tlp := &insertutil.TestLogMessageProcessor{} - r := bytes.NewBufferString(data) - if err := processStreamInternal(r, "", false, tlp); err != nil { - t.Fatalf("unexpected error: %s", err) - } - if err := tlp.Verify(timestampsExpected, resultExpected); err != nil { - t.Fatal(err) - } - } - - data := `Jun 3 12:08:33 abcd systemd: Starting Update the local ESM caches... - -48 <165>Jun 4 12:08:33 abcd systemd[345]: abc defg<123>1 2023-06-03T17:42:12.345Z mymachine.example.com appname 12345 ID47 [exampleSDID@32473 iut="3" eventSource="Application 123 = ] 56" eventID="11211"] This is a test message with structured data. -` - currentYear := 2023 - timestampsExpected := []int64{1685794113000000000, 1685880513000000000, 1685814132345000000} - resultExpected := `{"format":"rfc3164","hostname":"abcd","app_name":"systemd","_msg":"Starting Update the local ESM caches..."} -{"priority":"165","facility_keyword":"local4","level":"notice","facility":"20","severity":"5","format":"rfc3164","hostname":"abcd","app_name":"systemd","proc_id":"345","_msg":"abc defg"} -{"priority":"123","facility_keyword":"solaris-cron","level":"error","facility":"15","severity":"3","format":"rfc5424","hostname":"mymachine.example.com","app_name":"appname","proc_id":"12345","msg_id":"ID47","exampleSDID@32473.iut":"3","exampleSDID@32473.eventSource":"Application 123 = ] 56","exampleSDID@32473.eventID":"11211","_msg":"This is a test message with structured data."}` - f(data, currentYear, timestampsExpected, resultExpected) -} - -func TestProcessStreamInternal_Failure(t *testing.T) { - f := func(data string) { - t.Helper() - - MustInit() - defer MustStop() - - tlp := &insertutil.TestLogMessageProcessor{} - r := bytes.NewBufferString(data) - if err := processStreamInternal(r, "", false, tlp); err == nil { - t.Fatalf("expecting non-nil error") - } - } - - // invalid format for message size - f("12foo bar") - - // too big message size - f("123 foo") - f("123456789 bar") -} diff --git a/app/vlogscli/Makefile b/app/vlogscli/Makefile deleted file mode 100644 index 1c51a081db..0000000000 --- a/app/vlogscli/Makefile +++ /dev/null @@ -1,109 +0,0 @@ -# All these commands must run from repository root. - -vlogscli: - APP_NAME=vlogscli $(MAKE) app-local - -vlogscli-race: - APP_NAME=vlogscli RACE=-race $(MAKE) app-local - -vlogscli-prod: - APP_NAME=vlogscli $(MAKE) app-via-docker - -vlogscli-pure-prod: - APP_NAME=vlogscli $(MAKE) app-via-docker-pure - -vlogscli-linux-amd64-prod: - APP_NAME=vlogscli $(MAKE) app-via-docker-linux-amd64 - -vlogscli-linux-arm-prod: - APP_NAME=vlogscli $(MAKE) app-via-docker-linux-arm - -vlogscli-linux-arm64-prod: - APP_NAME=vlogscli $(MAKE) app-via-docker-linux-arm64 - -vlogscli-linux-ppc64le-prod: - APP_NAME=vlogscli $(MAKE) app-via-docker-linux-ppc64le - -vlogscli-linux-386-prod: - APP_NAME=vlogscli $(MAKE) app-via-docker-linux-386 - -vlogscli-darwin-amd64-prod: - APP_NAME=vlogscli $(MAKE) app-via-docker-darwin-amd64 - -vlogscli-darwin-arm64-prod: - APP_NAME=vlogscli $(MAKE) app-via-docker-darwin-arm64 - -vlogscli-freebsd-amd64-prod: - APP_NAME=vlogscli $(MAKE) app-via-docker-freebsd-amd64 - -vlogscli-openbsd-amd64-prod: - APP_NAME=vlogscli $(MAKE) app-via-docker-openbsd-amd64 - -vlogscli-windows-amd64-prod: - APP_NAME=vlogscli $(MAKE) app-via-docker-windows-amd64 - -package-vlogscli: - APP_NAME=vlogscli $(MAKE) package-via-docker - -package-vlogscli-pure: - APP_NAME=vlogscli $(MAKE) package-via-docker-pure - -package-vlogscli-amd64: - APP_NAME=vlogscli $(MAKE) package-via-docker-amd64 - -package-vlogscli-arm: - APP_NAME=vlogscli $(MAKE) package-via-docker-arm - -package-vlogscli-arm64: - APP_NAME=vlogscli $(MAKE) package-via-docker-arm64 - -package-vlogscli-ppc64le: - APP_NAME=vlogscli $(MAKE) package-via-docker-ppc64le - -package-vlogscli-386: - APP_NAME=vlogscli $(MAKE) package-via-docker-386 - -publish-vlogscli: - APP_NAME=vlogscli $(MAKE) publish-via-docker - -vlogscli-linux-amd64: - APP_NAME=vlogscli CGO_ENABLED=1 GOOS=linux GOARCH=amd64 $(MAKE) app-local-goos-goarch - -vlogscli-linux-arm: - APP_NAME=vlogscli CGO_ENABLED=0 GOOS=linux GOARCH=arm $(MAKE) app-local-goos-goarch - -vlogscli-linux-arm64: - APP_NAME=vlogscli CGO_ENABLED=0 GOOS=linux GOARCH=arm64 $(MAKE) app-local-goos-goarch - -vlogscli-linux-ppc64le: - APP_NAME=vlogscli CGO_ENABLED=0 GOOS=linux GOARCH=ppc64le $(MAKE) app-local-goos-goarch - -vlogscli-linux-s390x: - APP_NAME=vlogscli CGO_ENABLED=0 GOOS=linux GOARCH=s390x $(MAKE) app-local-goos-goarch - -vlogscli-linux-loong64: - APP_NAME=vlogscli CGO_ENABLED=0 GOOS=linux GOARCH=loong64 $(MAKE) app-local-goos-goarch - -vlogscli-linux-386: - APP_NAME=vlogscli CGO_ENABLED=0 GOOS=linux GOARCH=386 $(MAKE) app-local-goos-goarch - -vlogscli-darwin-amd64: - APP_NAME=vlogscli CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 $(MAKE) app-local-goos-goarch - -vlogscli-darwin-arm64: - APP_NAME=vlogscli CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 $(MAKE) app-local-goos-goarch - -vlogscli-freebsd-amd64: - APP_NAME=vlogscli CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 $(MAKE) app-local-goos-goarch - -vlogscli-openbsd-amd64: - APP_NAME=vlogscli CGO_ENABLED=0 GOOS=openbsd GOARCH=amd64 $(MAKE) app-local-goos-goarch - -vlogscli-windows-amd64: - GOARCH=amd64 APP_NAME=vlogscli $(MAKE) app-local-windows-goarch - -vlogscli-pure: - APP_NAME=vlogscli $(MAKE) app-local-pure - -run-vlogscli: - APP_NAME=vlogscli $(MAKE) run-via-docker diff --git a/app/vlogscli/README.md b/app/vlogscli/README.md index b81550500f..5456a353a1 100644 --- a/app/vlogscli/README.md +++ b/app/vlogscli/README.md @@ -1,5 +1 @@ -# vlogscli - -Command-line utility for querying [VictoriaLogs](https://docs.victoriametrics.com/victorialogs/). - -See [these docs](https://docs.victoriametrics.com/victorialogs/querying/vlogscli/). +VictoriaLogs source code has been moved to [github.com/VictoriaMetrics/VictoriaLogs](https://github.com/VictoriaMetrics/VictoriaLogs/). diff --git a/app/vlogscli/deployment/Dockerfile b/app/vlogscli/deployment/Dockerfile deleted file mode 100644 index 45b2d6346a..0000000000 --- a/app/vlogscli/deployment/Dockerfile +++ /dev/null @@ -1,6 +0,0 @@ -ARG base_image=non-existing -FROM $base_image - -ENTRYPOINT ["/vlogscli-prod"] -ARG src_binary=non-existing -COPY $src_binary ./vlogscli-prod diff --git a/app/vlogscli/json_prettifier.go b/app/vlogscli/json_prettifier.go deleted file mode 100644 index 4ad1632032..0000000000 --- a/app/vlogscli/json_prettifier.go +++ /dev/null @@ -1,245 +0,0 @@ -package main - -import ( - "bufio" - "encoding/json" - "fmt" - "io" - "sort" - "strings" - "sync" - - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" -) - -type outputMode int - -const ( - outputModeJSONMultiline = outputMode(0) - outputModeJSONSingleline = outputMode(1) - outputModeLogfmt = outputMode(2) - outputModeCompact = outputMode(3) -) - -func getOutputFormatter(outputMode outputMode) func(w io.Writer, fields []logstorage.Field) error { - switch outputMode { - case outputModeJSONMultiline: - return func(w io.Writer, fields []logstorage.Field) error { - return writeJSONObject(w, fields, true) - } - case outputModeJSONSingleline: - return func(w io.Writer, fields []logstorage.Field) error { - return writeJSONObject(w, fields, false) - } - case outputModeLogfmt: - return writeLogfmtObject - case outputModeCompact: - return writeCompactObject - default: - panic(fmt.Errorf("BUG: unexpected outputMode=%d", outputMode)) - } -} - -type jsonPrettifier struct { - r io.ReadCloser - formatter func(w io.Writer, fields []logstorage.Field) error - - d *json.Decoder - - pr *io.PipeReader - pw *io.PipeWriter - bw *bufio.Writer - - wg sync.WaitGroup -} - -func newJSONPrettifier(r io.ReadCloser, outputMode outputMode) *jsonPrettifier { - d := json.NewDecoder(r) - pr, pw := io.Pipe() - bw := bufio.NewWriter(pw) - - formatter := getOutputFormatter(outputMode) - - jp := &jsonPrettifier{ - r: r, - formatter: formatter, - - d: d, - - pr: pr, - pw: pw, - bw: bw, - } - - jp.wg.Add(1) - go func() { - defer jp.wg.Done() - err := jp.prettifyJSONLines() - jp.closePipesWithError(err) - }() - - return jp -} - -func (jp *jsonPrettifier) closePipesWithError(err error) { - _ = jp.pr.CloseWithError(err) - _ = jp.pw.CloseWithError(err) -} - -func (jp *jsonPrettifier) prettifyJSONLines() error { - for jp.d.More() { - fields, err := readNextJSONObject(jp.d) - if err != nil { - return err - } - sort.Slice(fields, func(i, j int) bool { - return fields[i].Name < fields[j].Name - }) - if err := jp.formatter(jp.bw, fields); err != nil { - return err - } - - // Flush bw after every output line in order to show results as soon as they appear. - if err := jp.bw.Flush(); err != nil { - return err - } - } - return nil -} - -func (jp *jsonPrettifier) Close() error { - jp.closePipesWithError(io.ErrUnexpectedEOF) - err := jp.r.Close() - jp.wg.Wait() - return err -} - -func (jp *jsonPrettifier) Read(p []byte) (int, error) { - return jp.pr.Read(p) -} - -func readNextJSONObject(d *json.Decoder) ([]logstorage.Field, error) { - t, err := d.Token() - if err != nil { - return nil, fmt.Errorf("cannot read '{': %w", err) - } - delim, ok := t.(json.Delim) - if !ok || delim.String() != "{" { - return nil, fmt.Errorf("unexpected token read; got %q; want '{'", delim) - } - - var fields []logstorage.Field - for { - // Read object key - t, err := d.Token() - if err != nil { - return nil, fmt.Errorf("cannot read JSON object key or closing brace: %w", err) - } - delim, ok := t.(json.Delim) - if ok { - if delim.String() == "}" { - return fields, nil - } - return nil, fmt.Errorf("unexpected delimiter read; got %q; want '}'", delim) - } - key, ok := t.(string) - if !ok { - return nil, fmt.Errorf("unexpected token read for object key: %v; want string or '}'", t) - } - - // read object value - t, err = d.Token() - if err != nil { - return nil, fmt.Errorf("cannot read JSON object value: %w", err) - } - value, ok := t.(string) - if !ok { - return nil, fmt.Errorf("unexpected token read for object value: %v; want string", t) - } - - fields = append(fields, logstorage.Field{ - Name: key, - Value: value, - }) - } -} - -func writeLogfmtObject(w io.Writer, fields []logstorage.Field) error { - data := logstorage.MarshalFieldsToLogfmt(nil, fields) - _, err := fmt.Fprintf(w, "%s\n", data) - return err -} - -func writeCompactObject(w io.Writer, fields []logstorage.Field) error { - if len(fields) == 1 { - // Just write field value as is without name - _, err := fmt.Fprintf(w, "%s\n", fields[0].Value) - return err - } - if len(fields) == 2 && (fields[0].Name == "_time" || fields[1].Name == "_time") { - // Write _time\tfieldValue as is - if fields[0].Name == "_time" { - _, err := fmt.Fprintf(w, "%s\t%s\n", fields[0].Value, fields[1].Value) - return err - } - _, err := fmt.Fprintf(w, "%s\t%s\n", fields[1].Value, fields[0].Value) - return err - } - - // Fall back to logfmt - return writeLogfmtObject(w, fields) -} - -func writeJSONObject(w io.Writer, fields []logstorage.Field, isMultiline bool) error { - if len(fields) == 0 { - fmt.Fprintf(w, "{}\n") - return nil - } - - fmt.Fprintf(w, "{") - writeNewlineIfNeeded(w, isMultiline) - if err := writeJSONObjectKeyValue(w, fields[0], isMultiline); err != nil { - return err - } - for _, f := range fields[1:] { - fmt.Fprintf(w, ",") - writeNewlineIfNeeded(w, isMultiline) - if err := writeJSONObjectKeyValue(w, f, isMultiline); err != nil { - return err - } - } - writeNewlineIfNeeded(w, isMultiline) - fmt.Fprintf(w, "}\n") - return nil -} - -func writeNewlineIfNeeded(w io.Writer, isMultiline bool) { - if isMultiline { - fmt.Fprintf(w, "\n") - } -} - -func writeJSONObjectKeyValue(w io.Writer, f logstorage.Field, isMultiline bool) error { - key := getJSONString(f.Name) - value := getJSONString(f.Value) - if isMultiline { - _, err := fmt.Fprintf(w, " %s: %s", key, value) - return err - } - _, err := fmt.Fprintf(w, "%s:%s", key, value) - return err -} - -func getJSONString(s string) string { - data, err := json.Marshal(s) - if err != nil { - panic(fmt.Errorf("unexpected error when marshaling string to JSON: %w", err)) - } - return jsonHTMLReplacer.Replace(string(data)) -} - -var jsonHTMLReplacer = strings.NewReplacer( - `\u003c`, "\u003c", - `\u003e`, "\u003e", - `\u0026`, "\u0026", -) diff --git a/app/vlogscli/less_wrapper.go b/app/vlogscli/less_wrapper.go deleted file mode 100644 index 1e3a6022a1..0000000000 --- a/app/vlogscli/less_wrapper.go +++ /dev/null @@ -1,123 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "io" - "os" - "os/exec" - "os/signal" - "sync" - "syscall" - - "github.com/mattn/go-isatty" -) - -func isTerminal() bool { - return isatty.IsTerminal(os.Stdout.Fd()) && isatty.IsTerminal(os.Stderr.Fd()) -} - -func readWithLess(r io.Reader, disableColors, wrapLongLines bool) error { - if !isTerminal() { - // Just write everything to stdout if no terminal is available. - _, err := io.Copy(os.Stdout, r) - if err != nil && !isErrPipe(err) { - return fmt.Errorf("error when forwarding data to stdout: %w", err) - } - if err := os.Stdout.Sync(); err != nil { - return fmt.Errorf("cannot sync data to stdout: %w", err) - } - return nil - } - - pr, pw, err := os.Pipe() - if err != nil { - return fmt.Errorf("cannot create pipe: %w", err) - } - defer func() { - _ = pr.Close() - _ = pw.Close() - }() - - // Ignore Ctrl+C in the current process, so 'less' could handle it properly - cancel := ignoreSignals(os.Interrupt) - defer cancel() - - // Start 'less' process - path, err := exec.LookPath("less") - if err != nil { - return fmt.Errorf("cannot find 'less' command: %w", err) - } - opts := []string{"less", "-F", "-X"} - if !disableColors { - opts = append(opts, "-R") - } - if !wrapLongLines { - opts = append(opts, "-S") - } - p, err := os.StartProcess(path, opts, &os.ProcAttr{ - Env: append(os.Environ(), "LESSCHARSET=utf-8"), - Files: []*os.File{pr, os.Stdout, os.Stderr}, - }) - if err != nil { - return fmt.Errorf("cannot start 'less' process: %w", err) - } - - // Close pr after 'less' finishes in a parallel goroutine - // in order to unblock forwarding data to stopped 'less' below. - waitch := make(chan *os.ProcessState) - go func() { - // Wait for 'less' process to finish. - ps, err := p.Wait() - if err != nil { - fatalf("unexpected error when waiting for 'less' process: %w", err) - } - _ = pr.Close() - waitch <- ps - }() - - // Forward data from r to 'less' - _, err = io.Copy(pw, r) - _ = pw.Sync() - _ = pw.Close() - - // Wait until 'less' finished - ps := <-waitch - - // Verify 'less' status. - if !ps.Success() { - return fmt.Errorf("'less' finished with unexpected code %d", ps.ExitCode()) - } - - if err != nil && !isErrPipe(err) { - return fmt.Errorf("error when forwarding data to 'less': %w", err) - } - - return nil -} - -func isErrPipe(err error) bool { - return errors.Is(err, syscall.EPIPE) || errors.Is(err, io.ErrClosedPipe) -} - -func ignoreSignals(sigs ...os.Signal) func() { - ch := make(chan os.Signal, 1) - signal.Notify(ch, sigs...) - - var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() - for { - _, ok := <-ch - if !ok { - return - } - } - }() - return func() { - signal.Stop(ch) - close(ch) - wg.Wait() - } -} diff --git a/app/vlogscli/main.go b/app/vlogscli/main.go deleted file mode 100644 index ae738accc3..0000000000 --- a/app/vlogscli/main.go +++ /dev/null @@ -1,457 +0,0 @@ -package main - -import ( - "context" - "errors" - "flag" - "fmt" - "io" - "io/fs" - "net/http" - "net/url" - "os" - "os/signal" - "strconv" - "strings" - "syscall" - "time" - - "github.com/ergochat/readline" - - "github.com/VictoriaMetrics/VictoriaMetrics/lib/buildinfo" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/envflag" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" -) - -var ( - datasourceURL = flag.String("datasource.url", "http://localhost:9428/select/logsql/query", "URL for querying VictoriaLogs; "+ - "see https://docs.victoriametrics.com/victorialogs/querying/#querying-logs . See also -tail.url") - tailURL = flag.String("tail.url", "", "URL for live tailing queries to VictoriaLogs; see https://docs.victoriametrics.com/victorialogs/querying/#live-tailing ."+ - "The url is automatically detected from -datasource.url by replacing /query with /tail at the end if -tail.url is empty") - historyFile = flag.String("historyFile", "vlogscli-history", "Path to file with command history") - header = flagutil.NewArrayString("header", "Optional header to pass in request -datasource.url in the form 'HeaderName: value'") - accountID = flag.Int("accountID", 0, "Account ID to query; see https://docs.victoriametrics.com/victorialogs/#multitenancy") - projectID = flag.Int("projectID", 0, "Project ID to query; see https://docs.victoriametrics.com/victorialogs/#multitenancy") -) - -const ( - firstLinePrompt = ";> " - nextLinePrompt = "" -) - -func main() { - // Write flags and help message to stdout, since it is easier to grep or pipe. - flag.CommandLine.SetOutput(os.Stdout) - flag.Usage = usage - envflag.Parse() - buildinfo.Init() - logger.InitNoLogFlags() - - hes, err := parseHeaders(*header) - if err != nil { - fatalf("cannot parse -header command-line flag: %s", err) - } - headers = hes - - incompleteLine := "" - cfg := &readline.Config{ - Prompt: firstLinePrompt, - DisableAutoSaveHistory: true, - Listener: func(line []rune, pos int, _ rune) ([]rune, int, bool) { - incompleteLine = string(line) - return line, pos, false - }, - } - rl, err := readline.NewFromConfig(cfg) - if err != nil { - fatalf("cannot initialize readline: %s", err) - } - - fmt.Fprintf(rl, "sending queries to -datasource.url=%s\n", *datasourceURL) - fmt.Fprintf(rl, `type ? and press enter to see available commands`+"\n") - runReadlineLoop(rl, &incompleteLine) - - if err := rl.Close(); err != nil { - fatalf("cannot close readline: %s", err) - } - -} - -func runReadlineLoop(rl *readline.Instance, incompleteLine *string) { - historyLines, err := loadFromHistory(*historyFile) - if err != nil { - fatalf("cannot load query history: %s", err) - } - for _, line := range historyLines { - if err := rl.SaveToHistory(line); err != nil { - fatalf("cannot initialize query history: %s", err) - } - } - - outputMode := outputModeJSONMultiline - disableColors := true - wrapLongLines := false - s := "" - for { - line, err := rl.ReadLine() - if err != nil { - switch err { - case io.EOF: - if s != "" { - // This is non-interactive query execution. - executeQuery(context.Background(), rl, s, outputMode, disableColors, wrapLongLines) - } - return - case readline.ErrInterrupt: - if s == "" && *incompleteLine == "" { - fmt.Fprintf(rl, "interrupted\n") - os.Exit(128 + int(syscall.SIGINT)) - } - // Default value for Ctrl+C - clear the prompt and store the incompletely entered line into history - s += *incompleteLine - historyLines = pushToHistory(rl, historyLines, s) - s = "" - rl.SetPrompt(firstLinePrompt) - continue - default: - fatalf("unexpected error in readline: %s", err) - } - } - - s += line - if s == "" { - // Skip empty lines - continue - } - - if isQuitCommand(s) { - fmt.Fprintf(rl, "bye!\n") - _ = pushToHistory(rl, historyLines, s) - return - } - if isHelpCommand(s) { - printCommandsHelp(rl) - historyLines = pushToHistory(rl, historyLines, s) - s = "" - continue - } - if s == `\s` { - fmt.Fprintf(rl, "singleline json output mode\n") - outputMode = outputModeJSONSingleline - historyLines = pushToHistory(rl, historyLines, s) - s = "" - continue - } - if s == `\m` { - fmt.Fprintf(rl, "multiline json output mode\n") - outputMode = outputModeJSONMultiline - historyLines = pushToHistory(rl, historyLines, s) - s = "" - continue - } - if s == `\c` { - fmt.Fprintf(rl, "compact output mode\n") - outputMode = outputModeCompact - historyLines = pushToHistory(rl, historyLines, s) - s = "" - continue - } - if s == `\logfmt` { - fmt.Fprintf(rl, "logfmt output mode\n") - outputMode = outputModeLogfmt - historyLines = pushToHistory(rl, historyLines, s) - s = "" - continue - } - if s == `\wrap_long_lines` { - if wrapLongLines { - wrapLongLines = false - fmt.Fprintf(rl, "wrapping of long lines is disabled\n") - } else { - wrapLongLines = true - fmt.Fprintf(rl, "wrapping of long lines is enabled\n") - } - historyLines = pushToHistory(rl, historyLines, s) - s = "" - continue - } - if s == `\disable_colors` { - if !disableColors { - disableColors = true - fmt.Fprintf(rl, `disabled colors in compact output mode; enter \enable_colors for enabling it`+"\n") - } - historyLines = pushToHistory(rl, historyLines, s) - s = "" - continue - } - if s == `\enable_colors` { - if disableColors { - disableColors = false - fmt.Fprintf(rl, `enabled colors in compact output mode; type \disable_colors for disabling it`+"\n") - } - historyLines = pushToHistory(rl, historyLines, s) - s = "" - continue - } - if line != "" && !strings.HasSuffix(line, ";") { - // Assume the query is incomplete and allow the user finishing the query on the next line - s += "\n" - rl.SetPrompt(nextLinePrompt) - continue - } - - // Execute the query - ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) - executeQuery(ctx, rl, s, outputMode, disableColors, wrapLongLines) - cancel() - - historyLines = pushToHistory(rl, historyLines, s) - s = "" - rl.SetPrompt(firstLinePrompt) - } -} - -func pushToHistory(rl *readline.Instance, historyLines []string, s string) []string { - s = strings.TrimSpace(s) - if len(historyLines) == 0 || historyLines[len(historyLines)-1] != s { - historyLines = append(historyLines, s) - if len(historyLines) > 500 { - historyLines = historyLines[len(historyLines)-500:] - } - if err := saveToHistory(*historyFile, historyLines); err != nil { - fatalf("cannot save query history: %s", err) - } - } - if err := rl.SaveToHistory(s); err != nil { - fatalf("cannot update query history: %s", err) - } - return historyLines -} - -func loadFromHistory(filePath string) ([]string, error) { - data, err := os.ReadFile(filePath) - if err != nil { - if errors.Is(err, fs.ErrNotExist) { - return nil, nil - } - return nil, err - } - linesQuoted := strings.Split(string(data), "\n") - lines := make([]string, 0, len(linesQuoted)) - i := 0 - for _, lineQuoted := range linesQuoted { - i++ - if lineQuoted == "" { - continue - } - line, err := strconv.Unquote(lineQuoted) - if err != nil { - return nil, fmt.Errorf("cannot parse line #%d at %s: %w; line: [%s]", i, filePath, err, line) - } - lines = append(lines, line) - } - return lines, nil -} - -func saveToHistory(filePath string, lines []string) error { - linesQuoted := make([]string, len(lines)) - for i, line := range lines { - lineQuoted := strconv.Quote(line) - linesQuoted[i] = lineQuoted - } - data := strings.Join(linesQuoted, "\n") - return os.WriteFile(filePath, []byte(data), 0600) -} - -func isQuitCommand(s string) bool { - switch s { - case `\q`, "q", "quit", "exit": - return true - default: - return false - } -} - -func isHelpCommand(s string) bool { - switch s { - case `\h`, "h", "help", "?": - return true - default: - return false - } -} - -func printCommandsHelp(w io.Writer) { - fmt.Fprintf(w, "%s", `Available commands: -\q - quit -\h - show this help -\s - singleline json output mode -\m - multiline json output mode -\c - compact output mode -\logfmt - logfmt output mode -\wrap_long_lines - toggles wrapping long lines -\enable_colors - enable ANSI colors in compact output mode -\disable_colors - disable ANSI colors in compact output mode -\tail - live tail results - -See https://docs.victoriametrics.com/victorialogs/querying/vlogscli/ for more details -`) -} - -func executeQuery(ctx context.Context, output io.Writer, qStr string, outputMode outputMode, disableColors, wrapLongLines bool) { - if strings.HasPrefix(qStr, `\tail `) { - tailQuery(ctx, output, qStr, outputMode) - return - } - - respBody := getQueryResponse(ctx, output, qStr, outputMode, *datasourceURL) - if respBody == nil { - return - } - defer func() { - _ = respBody.Close() - }() - - if err := readWithLess(respBody, disableColors, wrapLongLines); err != nil { - fmt.Fprintf(output, "error when reading query response: %s\n", err) - return - } -} - -func tailQuery(ctx context.Context, output io.Writer, qStr string, outputMode outputMode) { - qStr = strings.TrimPrefix(qStr, `\tail `) - qURL, err := getTailURL() - if err != nil { - fmt.Fprintf(output, "%s\n", err) - return - } - - respBody := getQueryResponse(ctx, output, qStr, outputMode, qURL) - if respBody == nil { - return - } - defer func() { - _ = respBody.Close() - }() - - if _, err := io.Copy(output, respBody); err != nil { - if !errors.Is(err, context.Canceled) && !isErrPipe(err) { - fmt.Fprintf(output, "error when live tailing query response: %s\n", err) - } - fmt.Fprintf(output, "\n") - return - } -} - -func getTailURL() (string, error) { - if *tailURL != "" { - return *tailURL, nil - } - - u, err := url.Parse(*datasourceURL) - if err != nil { - return "", fmt.Errorf("cannot parse -datasource.url=%q: %w", *datasourceURL, err) - } - if !strings.HasSuffix(u.Path, "/query") { - return "", fmt.Errorf("cannot find /query suffix in -datasource.url=%q", *datasourceURL) - } - u.Path = u.Path[:len(u.Path)-len("/query")] + "/tail" - return u.String(), nil -} - -func getQueryResponse(ctx context.Context, output io.Writer, qStr string, outputMode outputMode, qURL string) io.ReadCloser { - // Parse the query and convert it to canonical view. - qStr = strings.TrimSuffix(qStr, ";") - q, err := logstorage.ParseQuery(qStr) - if err != nil { - fmt.Fprintf(output, "cannot parse query: %s\n", err) - return nil - } - qStr = q.String() - fmt.Fprintf(output, "executing [%s]...", qStr) - - // Prepare HTTP request for qURL - args := make(url.Values) - args.Set("query", qStr) - data := strings.NewReader(args.Encode()) - - req, err := http.NewRequestWithContext(ctx, "POST", qURL, data) - if err != nil { - panic(fmt.Errorf("BUG: cannot prepare request to server: %w", err)) - } - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - for _, h := range headers { - req.Header.Set(h.Name, h.Value) - } - req.Header.Set("AccountID", strconv.Itoa(*accountID)) - req.Header.Set("ProjectID", strconv.Itoa(*projectID)) - - // Execute HTTP request at qURL - startTime := time.Now() - resp, err := httpClient.Do(req) - queryDuration := time.Since(startTime) - fmt.Fprintf(output, "; duration: %.3fs\n", queryDuration.Seconds()) - if err != nil { - if errors.Is(err, context.Canceled) { - fmt.Fprintf(output, "\n") - } else { - fmt.Fprintf(output, "cannot execute query: %s\n", err) - } - return nil - } - - // Verify response code - if resp.StatusCode != http.StatusOK { - body, err := io.ReadAll(resp.Body) - if err != nil { - body = []byte(fmt.Sprintf("cannot read response body: %s", err)) - } - fmt.Fprintf(output, "unexpected status code: %d; response body:\n%s\n", resp.StatusCode, body) - return nil - } - - // Prettify the response body - jp := newJSONPrettifier(resp.Body, outputMode) - - return jp -} - -var httpClient = &http.Client{} - -var headers []headerEntry - -type headerEntry struct { - Name string - Value string -} - -func parseHeaders(a []string) ([]headerEntry, error) { - hes := make([]headerEntry, len(a)) - for i, s := range a { - a := strings.SplitN(s, ":", 2) - if len(a) != 2 { - return nil, fmt.Errorf("cannot parse header=%q; it must contain at least one ':'; for example, 'Cookie: foo'", s) - } - hes[i] = headerEntry{ - Name: strings.TrimSpace(a[0]), - Value: strings.TrimSpace(a[1]), - } - } - return hes, nil -} - -func fatalf(format string, args ...any) { - fmt.Fprintf(os.Stderr, format+"\n", args...) - os.Exit(1) -} - -func usage() { - const s = ` -vlogscli is a command-line tool for querying VictoriaLogs. - -See the docs at https://docs.victoriametrics.com/victorialogs/querying/vlogscli/ -` - flagutil.Usage(s) -} diff --git a/app/vlogscli/multiarch/Dockerfile b/app/vlogscli/multiarch/Dockerfile deleted file mode 100644 index e3592e0ba0..0000000000 --- a/app/vlogscli/multiarch/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -# See https://medium.com/on-docker/use-multi-stage-builds-to-inject-ca-certs-ad1e8f01de1b -ARG certs_image=non-existing -ARG root_image=non-existing -FROM $certs_image AS certs -RUN apk update && apk upgrade && apk --update --no-cache add ca-certificates - -FROM $root_image -COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt -ENTRYPOINT ["/vlogscli-prod"] -ARG TARGETARCH -COPY vlogscli-linux-${TARGETARCH}-prod ./vlogscli-prod diff --git a/app/vlselect/README.md b/app/vlselect/README.md new file mode 100644 index 0000000000..5456a353a1 --- /dev/null +++ b/app/vlselect/README.md @@ -0,0 +1 @@ +VictoriaLogs source code has been moved to [github.com/VictoriaMetrics/VictoriaLogs](https://github.com/VictoriaMetrics/VictoriaLogs/). diff --git a/app/vlselect/internalselect/internalselect.go b/app/vlselect/internalselect/internalselect.go deleted file mode 100644 index c1cd74e389..0000000000 --- a/app/vlselect/internalselect/internalselect.go +++ /dev/null @@ -1,316 +0,0 @@ -package internalselect - -import ( - "context" - "fmt" - "net/http" - "strconv" - "sync" - "time" - - "github.com/VictoriaMetrics/metrics" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlstorage" - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlstorage/netselect" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/atomicutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/encoding" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/encoding/zstd" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/netutil" -) - -// RequestHandler processes requests to /internal/select/* -func RequestHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { - startTime := time.Now() - - path := r.URL.Path - rh := requestHandlers[path] - if rh == nil { - httpserver.Errorf(w, r, "unsupported endpoint requested: %s", path) - return - } - - metrics.GetOrCreateCounter(fmt.Sprintf(`vl_http_requests_total{path=%q}`, path)).Inc() - if err := rh(ctx, w, r); err != nil && !netutil.IsTrivialNetworkError(err) { - metrics.GetOrCreateCounter(fmt.Sprintf(`vl_http_request_errors_total{path=%q}`, path)).Inc() - httpserver.Errorf(w, r, "%s", err) - // The return is skipped intentionally in order to track the duration of failed queries. - } - metrics.GetOrCreateSummary(fmt.Sprintf(`vl_http_request_duration_seconds{path=%q}`, path)).UpdateDuration(startTime) -} - -var requestHandlers = map[string]func(ctx context.Context, w http.ResponseWriter, r *http.Request) error{ - "/internal/select/query": processQueryRequest, - "/internal/select/field_names": processFieldNamesRequest, - "/internal/select/field_values": processFieldValuesRequest, - "/internal/select/stream_field_names": processStreamFieldNamesRequest, - "/internal/select/stream_field_values": processStreamFieldValuesRequest, - "/internal/select/streams": processStreamsRequest, - "/internal/select/stream_ids": processStreamIDsRequest, -} - -func processQueryRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) error { - cp, err := getCommonParams(r, netselect.QueryProtocolVersion) - if err != nil { - return err - } - - w.Header().Set("Content-Type", "application/octet-stream") - - var wLock sync.Mutex - var dataLenBuf []byte - - sendBuf := func(bb *bytesutil.ByteBuffer) error { - if len(bb.B) == 0 { - return nil - } - - data := bb.B - if !cp.DisableCompression { - bufLen := len(bb.B) - bb.B = zstd.CompressLevel(bb.B, bb.B, 1) - data = bb.B[bufLen:] - } - - wLock.Lock() - dataLenBuf = encoding.MarshalUint64(dataLenBuf[:0], uint64(len(data))) - _, err := w.Write(dataLenBuf) - if err == nil { - _, err = w.Write(data) - } - wLock.Unlock() - - // Reset the sent buf - bb.Reset() - - return err - } - - var bufs atomicutil.Slice[bytesutil.ByteBuffer] - - var errGlobalLock sync.Mutex - var errGlobal error - - writeBlock := func(workerID uint, db *logstorage.DataBlock) { - if errGlobal != nil { - return - } - - bb := bufs.Get(workerID) - - bb.B = db.Marshal(bb.B) - - if len(bb.B) < 1024*1024 { - // Fast path - the bb is too small to be sent to the client yet. - return - } - - // Slow path - the bb must be sent to the client. - if err := sendBuf(bb); err != nil { - errGlobalLock.Lock() - if errGlobal != nil { - errGlobal = err - } - errGlobalLock.Unlock() - } - } - - if err := vlstorage.RunQuery(ctx, cp.TenantIDs, cp.Query, writeBlock); err != nil { - return err - } - if errGlobal != nil { - return errGlobal - } - - // Send the remaining data - for _, bb := range bufs.All() { - if err := sendBuf(bb); err != nil { - return err - } - } - - return nil -} - -func processFieldNamesRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) error { - cp, err := getCommonParams(r, netselect.FieldNamesProtocolVersion) - if err != nil { - return err - } - - fieldNames, err := vlstorage.GetFieldNames(ctx, cp.TenantIDs, cp.Query) - if err != nil { - return fmt.Errorf("cannot obtain field names: %w", err) - } - - return writeValuesWithHits(w, fieldNames, cp.DisableCompression) -} - -func processFieldValuesRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) error { - cp, err := getCommonParams(r, netselect.FieldValuesProtocolVersion) - if err != nil { - return err - } - - fieldName := r.FormValue("field") - - limit, err := getInt64FromRequest(r, "limit") - if err != nil { - return err - } - - fieldValues, err := vlstorage.GetFieldValues(ctx, cp.TenantIDs, cp.Query, fieldName, uint64(limit)) - if err != nil { - return fmt.Errorf("cannot obtain field values: %w", err) - } - - return writeValuesWithHits(w, fieldValues, cp.DisableCompression) -} - -func processStreamFieldNamesRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) error { - cp, err := getCommonParams(r, netselect.StreamFieldNamesProtocolVersion) - if err != nil { - return err - } - - fieldNames, err := vlstorage.GetStreamFieldNames(ctx, cp.TenantIDs, cp.Query) - if err != nil { - return fmt.Errorf("cannot obtain stream field names: %w", err) - } - - return writeValuesWithHits(w, fieldNames, cp.DisableCompression) -} - -func processStreamFieldValuesRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) error { - cp, err := getCommonParams(r, netselect.StreamFieldValuesProtocolVersion) - if err != nil { - return err - } - - fieldName := r.FormValue("field") - - limit, err := getInt64FromRequest(r, "limit") - if err != nil { - return err - } - - fieldValues, err := vlstorage.GetStreamFieldValues(ctx, cp.TenantIDs, cp.Query, fieldName, uint64(limit)) - if err != nil { - return fmt.Errorf("cannot obtain stream field values: %w", err) - } - - return writeValuesWithHits(w, fieldValues, cp.DisableCompression) -} - -func processStreamsRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) error { - cp, err := getCommonParams(r, netselect.StreamsProtocolVersion) - if err != nil { - return err - } - - limit, err := getInt64FromRequest(r, "limit") - if err != nil { - return err - } - - streams, err := vlstorage.GetStreams(ctx, cp.TenantIDs, cp.Query, uint64(limit)) - if err != nil { - return fmt.Errorf("cannot obtain streams: %w", err) - } - - return writeValuesWithHits(w, streams, cp.DisableCompression) -} - -func processStreamIDsRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) error { - cp, err := getCommonParams(r, netselect.StreamIDsProtocolVersion) - if err != nil { - return err - } - - limit, err := getInt64FromRequest(r, "limit") - if err != nil { - return err - } - - streamIDs, err := vlstorage.GetStreamIDs(ctx, cp.TenantIDs, cp.Query, uint64(limit)) - if err != nil { - return fmt.Errorf("cannot obtain streams: %w", err) - } - - return writeValuesWithHits(w, streamIDs, cp.DisableCompression) -} - -type commonParams struct { - TenantIDs []logstorage.TenantID - Query *logstorage.Query - - DisableCompression bool -} - -func getCommonParams(r *http.Request, expectedProtocolVersion string) (*commonParams, error) { - version := r.FormValue("version") - if version != expectedProtocolVersion { - return nil, fmt.Errorf("unexpected version=%q; want %q", version, expectedProtocolVersion) - } - - tenantIDsStr := r.FormValue("tenant_ids") - tenantIDs, err := logstorage.UnmarshalTenantIDs([]byte(tenantIDsStr)) - if err != nil { - return nil, fmt.Errorf("cannot unmarshal tenant_ids=%q: %w", tenantIDsStr, err) - } - - timestamp, err := getInt64FromRequest(r, "timestamp") - if err != nil { - return nil, err - } - - qStr := r.FormValue("query") - q, err := logstorage.ParseQueryAtTimestamp(qStr, timestamp) - if err != nil { - return nil, fmt.Errorf("cannot unmarshal query=%q: %w", qStr, err) - } - - s := r.FormValue("disable_compression") - disableCompression, err := strconv.ParseBool(s) - if err != nil { - return nil, fmt.Errorf("cannot parse disable_compression=%q: %w", s, err) - } - - cp := &commonParams{ - TenantIDs: tenantIDs, - Query: q, - - DisableCompression: disableCompression, - } - return cp, nil -} - -func writeValuesWithHits(w http.ResponseWriter, vhs []logstorage.ValueWithHits, disableCompression bool) error { - var b []byte - for i := range vhs { - b = vhs[i].Marshal(b) - } - - if !disableCompression { - b = zstd.CompressLevel(nil, b, 1) - } - - w.Header().Set("Content-Type", "application/octet-stream") - - if _, err := w.Write(b); err != nil { - return fmt.Errorf("cannot send response to the client: %w", err) - } - - return nil -} - -func getInt64FromRequest(r *http.Request, argName string) (int64, error) { - s := r.FormValue(argName) - n, err := strconv.ParseInt(s, 10, 64) - if err != nil { - return 0, fmt.Errorf("cannot parse %s=%q: %w", argName, s, err) - } - return n, nil -} diff --git a/app/vlselect/logsql/facets_response.qtpl b/app/vlselect/logsql/facets_response.qtpl deleted file mode 100644 index 1f55efed32..0000000000 --- a/app/vlselect/logsql/facets_response.qtpl +++ /dev/null @@ -1,49 +0,0 @@ -{% import ( - "slices" -) %} - -{% stripspace %} - -{% func FacetsResponse(m map[string][]facetEntry) %} -{ - {% code - sortedKeys := make([]string, 0, len(m)) - for k := range m { - sortedKeys = append(sortedKeys, k) - } - slices.Sort(sortedKeys) - %} - "facets":[ - {% if len(sortedKeys) > 0 %} - {%= facetsLine(m, sortedKeys[0]) %} - {% for _, k := range sortedKeys[1:] %} - ,{%= facetsLine(m, k) %} - {% endfor %} - {% endif %} - ] -} -{% endfunc %} - -{% func facetsLine(m map[string][]facetEntry, k string) %} -{ - "field_name":{%q= k %}, - "values":[ - {% code fes := m[k] %} - {% if len(fes) > 0 %} - {%= facetLine(fes[0]) %} - {% for _, fe := range fes[1:] %} - ,{%= facetLine(fe) %} - {% endfor %} - {% endif %} - ] -} -{% endfunc %} - -{% func facetLine(fe facetEntry) %} -{ - "field_value":{%q= fe.value %}, - "hits":{%s= fe.hits %} -} -{% endfunc %} - -{% endstripspace %} diff --git a/app/vlselect/logsql/facets_response.qtpl.go b/app/vlselect/logsql/facets_response.qtpl.go deleted file mode 100644 index 45f71f53ca..0000000000 --- a/app/vlselect/logsql/facets_response.qtpl.go +++ /dev/null @@ -1,178 +0,0 @@ -// Code generated by qtc from "facets_response.qtpl". DO NOT EDIT. -// See https://github.com/valyala/quicktemplate for details. - -//line app/vlselect/logsql/facets_response.qtpl:1 -package logsql - -//line app/vlselect/logsql/facets_response.qtpl:1 -import ( - "slices" -) - -//line app/vlselect/logsql/facets_response.qtpl:7 -import ( - qtio422016 "io" - - qt422016 "github.com/valyala/quicktemplate" -) - -//line app/vlselect/logsql/facets_response.qtpl:7 -var ( - _ = qtio422016.Copy - _ = qt422016.AcquireByteBuffer -) - -//line app/vlselect/logsql/facets_response.qtpl:7 -func StreamFacetsResponse(qw422016 *qt422016.Writer, m map[string][]facetEntry) { -//line app/vlselect/logsql/facets_response.qtpl:7 - qw422016.N().S(`{`) -//line app/vlselect/logsql/facets_response.qtpl:10 - sortedKeys := make([]string, 0, len(m)) - for k := range m { - sortedKeys = append(sortedKeys, k) - } - slices.Sort(sortedKeys) - -//line app/vlselect/logsql/facets_response.qtpl:15 - qw422016.N().S(`"facets":[`) -//line app/vlselect/logsql/facets_response.qtpl:17 - if len(sortedKeys) > 0 { -//line app/vlselect/logsql/facets_response.qtpl:18 - streamfacetsLine(qw422016, m, sortedKeys[0]) -//line app/vlselect/logsql/facets_response.qtpl:19 - for _, k := range sortedKeys[1:] { -//line app/vlselect/logsql/facets_response.qtpl:19 - qw422016.N().S(`,`) -//line app/vlselect/logsql/facets_response.qtpl:20 - streamfacetsLine(qw422016, m, k) -//line app/vlselect/logsql/facets_response.qtpl:21 - } -//line app/vlselect/logsql/facets_response.qtpl:22 - } -//line app/vlselect/logsql/facets_response.qtpl:22 - qw422016.N().S(`]}`) -//line app/vlselect/logsql/facets_response.qtpl:25 -} - -//line app/vlselect/logsql/facets_response.qtpl:25 -func WriteFacetsResponse(qq422016 qtio422016.Writer, m map[string][]facetEntry) { -//line app/vlselect/logsql/facets_response.qtpl:25 - qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vlselect/logsql/facets_response.qtpl:25 - StreamFacetsResponse(qw422016, m) -//line app/vlselect/logsql/facets_response.qtpl:25 - qt422016.ReleaseWriter(qw422016) -//line app/vlselect/logsql/facets_response.qtpl:25 -} - -//line app/vlselect/logsql/facets_response.qtpl:25 -func FacetsResponse(m map[string][]facetEntry) string { -//line app/vlselect/logsql/facets_response.qtpl:25 - qb422016 := qt422016.AcquireByteBuffer() -//line app/vlselect/logsql/facets_response.qtpl:25 - WriteFacetsResponse(qb422016, m) -//line app/vlselect/logsql/facets_response.qtpl:25 - qs422016 := string(qb422016.B) -//line app/vlselect/logsql/facets_response.qtpl:25 - qt422016.ReleaseByteBuffer(qb422016) -//line app/vlselect/logsql/facets_response.qtpl:25 - return qs422016 -//line app/vlselect/logsql/facets_response.qtpl:25 -} - -//line app/vlselect/logsql/facets_response.qtpl:27 -func streamfacetsLine(qw422016 *qt422016.Writer, m map[string][]facetEntry, k string) { -//line app/vlselect/logsql/facets_response.qtpl:27 - qw422016.N().S(`{"field_name":`) -//line app/vlselect/logsql/facets_response.qtpl:29 - qw422016.N().Q(k) -//line app/vlselect/logsql/facets_response.qtpl:29 - qw422016.N().S(`,"values":[`) -//line app/vlselect/logsql/facets_response.qtpl:31 - fes := m[k] - -//line app/vlselect/logsql/facets_response.qtpl:32 - if len(fes) > 0 { -//line app/vlselect/logsql/facets_response.qtpl:33 - streamfacetLine(qw422016, fes[0]) -//line app/vlselect/logsql/facets_response.qtpl:34 - for _, fe := range fes[1:] { -//line app/vlselect/logsql/facets_response.qtpl:34 - qw422016.N().S(`,`) -//line app/vlselect/logsql/facets_response.qtpl:35 - streamfacetLine(qw422016, fe) -//line app/vlselect/logsql/facets_response.qtpl:36 - } -//line app/vlselect/logsql/facets_response.qtpl:37 - } -//line app/vlselect/logsql/facets_response.qtpl:37 - qw422016.N().S(`]}`) -//line app/vlselect/logsql/facets_response.qtpl:40 -} - -//line app/vlselect/logsql/facets_response.qtpl:40 -func writefacetsLine(qq422016 qtio422016.Writer, m map[string][]facetEntry, k string) { -//line app/vlselect/logsql/facets_response.qtpl:40 - qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vlselect/logsql/facets_response.qtpl:40 - streamfacetsLine(qw422016, m, k) -//line app/vlselect/logsql/facets_response.qtpl:40 - qt422016.ReleaseWriter(qw422016) -//line app/vlselect/logsql/facets_response.qtpl:40 -} - -//line app/vlselect/logsql/facets_response.qtpl:40 -func facetsLine(m map[string][]facetEntry, k string) string { -//line app/vlselect/logsql/facets_response.qtpl:40 - qb422016 := qt422016.AcquireByteBuffer() -//line app/vlselect/logsql/facets_response.qtpl:40 - writefacetsLine(qb422016, m, k) -//line app/vlselect/logsql/facets_response.qtpl:40 - qs422016 := string(qb422016.B) -//line app/vlselect/logsql/facets_response.qtpl:40 - qt422016.ReleaseByteBuffer(qb422016) -//line app/vlselect/logsql/facets_response.qtpl:40 - return qs422016 -//line app/vlselect/logsql/facets_response.qtpl:40 -} - -//line app/vlselect/logsql/facets_response.qtpl:42 -func streamfacetLine(qw422016 *qt422016.Writer, fe facetEntry) { -//line app/vlselect/logsql/facets_response.qtpl:42 - qw422016.N().S(`{"field_value":`) -//line app/vlselect/logsql/facets_response.qtpl:44 - qw422016.N().Q(fe.value) -//line app/vlselect/logsql/facets_response.qtpl:44 - qw422016.N().S(`,"hits":`) -//line app/vlselect/logsql/facets_response.qtpl:45 - qw422016.N().S(fe.hits) -//line app/vlselect/logsql/facets_response.qtpl:45 - qw422016.N().S(`}`) -//line app/vlselect/logsql/facets_response.qtpl:47 -} - -//line app/vlselect/logsql/facets_response.qtpl:47 -func writefacetLine(qq422016 qtio422016.Writer, fe facetEntry) { -//line app/vlselect/logsql/facets_response.qtpl:47 - qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vlselect/logsql/facets_response.qtpl:47 - streamfacetLine(qw422016, fe) -//line app/vlselect/logsql/facets_response.qtpl:47 - qt422016.ReleaseWriter(qw422016) -//line app/vlselect/logsql/facets_response.qtpl:47 -} - -//line app/vlselect/logsql/facets_response.qtpl:47 -func facetLine(fe facetEntry) string { -//line app/vlselect/logsql/facets_response.qtpl:47 - qb422016 := qt422016.AcquireByteBuffer() -//line app/vlselect/logsql/facets_response.qtpl:47 - writefacetLine(qb422016, fe) -//line app/vlselect/logsql/facets_response.qtpl:47 - qs422016 := string(qb422016.B) -//line app/vlselect/logsql/facets_response.qtpl:47 - qt422016.ReleaseByteBuffer(qb422016) -//line app/vlselect/logsql/facets_response.qtpl:47 - return qs422016 -//line app/vlselect/logsql/facets_response.qtpl:47 -} diff --git a/app/vlselect/logsql/hits_response.qtpl b/app/vlselect/logsql/hits_response.qtpl deleted file mode 100644 index 687c634b61..0000000000 --- a/app/vlselect/logsql/hits_response.qtpl +++ /dev/null @@ -1,70 +0,0 @@ -{% import ( - "slices" - - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" -) %} - -{% stripspace %} - -// FieldsForHits formats labels for /select/logsql/hits response -{% func FieldsForHits(columns []logstorage.BlockColumn, rowIdx int) %} -{ - {% if len(columns) > 0 %} - {%q= columns[0].Name %}:{%q= columns[0].Values[rowIdx] %} - {% for _, c := range columns[1:] %} - ,{%q= c.Name %}:{%q= c.Values[rowIdx] %} - {% endfor %} - {% endif %} -} -{% endfunc %} - -{% func HitsSeries(m map[string]*hitsSeries) %} -{ - {% code - sortedKeys := make([]string, 0, len(m)) - for k := range m { - sortedKeys = append(sortedKeys, k) - } - slices.Sort(sortedKeys) - %} - "hits":[ - {% if len(sortedKeys) > 0 %} - {%= hitsSeriesLine(m, sortedKeys[0]) %} - {% for _, k := range sortedKeys[1:] %} - ,{%= hitsSeriesLine(m, k) %} - {% endfor %} - {% endif %} - ] -} -{% endfunc %} - -{% func hitsSeriesLine(m map[string]*hitsSeries, k string) %} -{ - {% code - hs := m[k] - hs.sort() - timestamps := hs.timestamps - hits := hs.hits - %} - "fields":{%s= k %}, - "timestamps":[ - {% if len(timestamps) > 0 %} - {%q= timestamps[0] %} - {% for _, ts := range timestamps[1:] %} - ,{%q= ts %} - {% endfor %} - {% endif %} - ], - "values":[ - {% if len(hits) > 0 %} - {%dul= hits[0] %} - {% for _, v := range hits[1:] %} - ,{%dul= v %} - {% endfor %} - {% endif %} - ], - "total":{%dul= hs.hitsTotal %} -} -{% endfunc %} - -{% endstripspace %} diff --git a/app/vlselect/logsql/hits_response.qtpl.go b/app/vlselect/logsql/hits_response.qtpl.go deleted file mode 100644 index dcbd1e3afa..0000000000 --- a/app/vlselect/logsql/hits_response.qtpl.go +++ /dev/null @@ -1,223 +0,0 @@ -// Code generated by qtc from "hits_response.qtpl". DO NOT EDIT. -// See https://github.com/valyala/quicktemplate for details. - -//line app/vlselect/logsql/hits_response.qtpl:1 -package logsql - -//line app/vlselect/logsql/hits_response.qtpl:1 -import ( - "slices" - - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" -) - -// FieldsForHits formats labels for /select/logsql/hits response - -//line app/vlselect/logsql/hits_response.qtpl:10 -import ( - qtio422016 "io" - - qt422016 "github.com/valyala/quicktemplate" -) - -//line app/vlselect/logsql/hits_response.qtpl:10 -var ( - _ = qtio422016.Copy - _ = qt422016.AcquireByteBuffer -) - -//line app/vlselect/logsql/hits_response.qtpl:10 -func StreamFieldsForHits(qw422016 *qt422016.Writer, columns []logstorage.BlockColumn, rowIdx int) { -//line app/vlselect/logsql/hits_response.qtpl:10 - qw422016.N().S(`{`) -//line app/vlselect/logsql/hits_response.qtpl:12 - if len(columns) > 0 { -//line app/vlselect/logsql/hits_response.qtpl:13 - qw422016.N().Q(columns[0].Name) -//line app/vlselect/logsql/hits_response.qtpl:13 - qw422016.N().S(`:`) -//line app/vlselect/logsql/hits_response.qtpl:13 - qw422016.N().Q(columns[0].Values[rowIdx]) -//line app/vlselect/logsql/hits_response.qtpl:14 - for _, c := range columns[1:] { -//line app/vlselect/logsql/hits_response.qtpl:14 - qw422016.N().S(`,`) -//line app/vlselect/logsql/hits_response.qtpl:15 - qw422016.N().Q(c.Name) -//line app/vlselect/logsql/hits_response.qtpl:15 - qw422016.N().S(`:`) -//line app/vlselect/logsql/hits_response.qtpl:15 - qw422016.N().Q(c.Values[rowIdx]) -//line app/vlselect/logsql/hits_response.qtpl:16 - } -//line app/vlselect/logsql/hits_response.qtpl:17 - } -//line app/vlselect/logsql/hits_response.qtpl:17 - qw422016.N().S(`}`) -//line app/vlselect/logsql/hits_response.qtpl:19 -} - -//line app/vlselect/logsql/hits_response.qtpl:19 -func WriteFieldsForHits(qq422016 qtio422016.Writer, columns []logstorage.BlockColumn, rowIdx int) { -//line app/vlselect/logsql/hits_response.qtpl:19 - qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vlselect/logsql/hits_response.qtpl:19 - StreamFieldsForHits(qw422016, columns, rowIdx) -//line app/vlselect/logsql/hits_response.qtpl:19 - qt422016.ReleaseWriter(qw422016) -//line app/vlselect/logsql/hits_response.qtpl:19 -} - -//line app/vlselect/logsql/hits_response.qtpl:19 -func FieldsForHits(columns []logstorage.BlockColumn, rowIdx int) string { -//line app/vlselect/logsql/hits_response.qtpl:19 - qb422016 := qt422016.AcquireByteBuffer() -//line app/vlselect/logsql/hits_response.qtpl:19 - WriteFieldsForHits(qb422016, columns, rowIdx) -//line app/vlselect/logsql/hits_response.qtpl:19 - qs422016 := string(qb422016.B) -//line app/vlselect/logsql/hits_response.qtpl:19 - qt422016.ReleaseByteBuffer(qb422016) -//line app/vlselect/logsql/hits_response.qtpl:19 - return qs422016 -//line app/vlselect/logsql/hits_response.qtpl:19 -} - -//line app/vlselect/logsql/hits_response.qtpl:21 -func StreamHitsSeries(qw422016 *qt422016.Writer, m map[string]*hitsSeries) { -//line app/vlselect/logsql/hits_response.qtpl:21 - qw422016.N().S(`{`) -//line app/vlselect/logsql/hits_response.qtpl:24 - sortedKeys := make([]string, 0, len(m)) - for k := range m { - sortedKeys = append(sortedKeys, k) - } - slices.Sort(sortedKeys) - -//line app/vlselect/logsql/hits_response.qtpl:29 - qw422016.N().S(`"hits":[`) -//line app/vlselect/logsql/hits_response.qtpl:31 - if len(sortedKeys) > 0 { -//line app/vlselect/logsql/hits_response.qtpl:32 - streamhitsSeriesLine(qw422016, m, sortedKeys[0]) -//line app/vlselect/logsql/hits_response.qtpl:33 - for _, k := range sortedKeys[1:] { -//line app/vlselect/logsql/hits_response.qtpl:33 - qw422016.N().S(`,`) -//line app/vlselect/logsql/hits_response.qtpl:34 - streamhitsSeriesLine(qw422016, m, k) -//line app/vlselect/logsql/hits_response.qtpl:35 - } -//line app/vlselect/logsql/hits_response.qtpl:36 - } -//line app/vlselect/logsql/hits_response.qtpl:36 - qw422016.N().S(`]}`) -//line app/vlselect/logsql/hits_response.qtpl:39 -} - -//line app/vlselect/logsql/hits_response.qtpl:39 -func WriteHitsSeries(qq422016 qtio422016.Writer, m map[string]*hitsSeries) { -//line app/vlselect/logsql/hits_response.qtpl:39 - qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vlselect/logsql/hits_response.qtpl:39 - StreamHitsSeries(qw422016, m) -//line app/vlselect/logsql/hits_response.qtpl:39 - qt422016.ReleaseWriter(qw422016) -//line app/vlselect/logsql/hits_response.qtpl:39 -} - -//line app/vlselect/logsql/hits_response.qtpl:39 -func HitsSeries(m map[string]*hitsSeries) string { -//line app/vlselect/logsql/hits_response.qtpl:39 - qb422016 := qt422016.AcquireByteBuffer() -//line app/vlselect/logsql/hits_response.qtpl:39 - WriteHitsSeries(qb422016, m) -//line app/vlselect/logsql/hits_response.qtpl:39 - qs422016 := string(qb422016.B) -//line app/vlselect/logsql/hits_response.qtpl:39 - qt422016.ReleaseByteBuffer(qb422016) -//line app/vlselect/logsql/hits_response.qtpl:39 - return qs422016 -//line app/vlselect/logsql/hits_response.qtpl:39 -} - -//line app/vlselect/logsql/hits_response.qtpl:41 -func streamhitsSeriesLine(qw422016 *qt422016.Writer, m map[string]*hitsSeries, k string) { -//line app/vlselect/logsql/hits_response.qtpl:41 - qw422016.N().S(`{`) -//line app/vlselect/logsql/hits_response.qtpl:44 - hs := m[k] - hs.sort() - timestamps := hs.timestamps - hits := hs.hits - -//line app/vlselect/logsql/hits_response.qtpl:48 - qw422016.N().S(`"fields":`) -//line app/vlselect/logsql/hits_response.qtpl:49 - qw422016.N().S(k) -//line app/vlselect/logsql/hits_response.qtpl:49 - qw422016.N().S(`,"timestamps":[`) -//line app/vlselect/logsql/hits_response.qtpl:51 - if len(timestamps) > 0 { -//line app/vlselect/logsql/hits_response.qtpl:52 - qw422016.N().Q(timestamps[0]) -//line app/vlselect/logsql/hits_response.qtpl:53 - for _, ts := range timestamps[1:] { -//line app/vlselect/logsql/hits_response.qtpl:53 - qw422016.N().S(`,`) -//line app/vlselect/logsql/hits_response.qtpl:54 - qw422016.N().Q(ts) -//line app/vlselect/logsql/hits_response.qtpl:55 - } -//line app/vlselect/logsql/hits_response.qtpl:56 - } -//line app/vlselect/logsql/hits_response.qtpl:56 - qw422016.N().S(`],"values":[`) -//line app/vlselect/logsql/hits_response.qtpl:59 - if len(hits) > 0 { -//line app/vlselect/logsql/hits_response.qtpl:60 - qw422016.N().DUL(hits[0]) -//line app/vlselect/logsql/hits_response.qtpl:61 - for _, v := range hits[1:] { -//line app/vlselect/logsql/hits_response.qtpl:61 - qw422016.N().S(`,`) -//line app/vlselect/logsql/hits_response.qtpl:62 - qw422016.N().DUL(v) -//line app/vlselect/logsql/hits_response.qtpl:63 - } -//line app/vlselect/logsql/hits_response.qtpl:64 - } -//line app/vlselect/logsql/hits_response.qtpl:64 - qw422016.N().S(`],"total":`) -//line app/vlselect/logsql/hits_response.qtpl:66 - qw422016.N().DUL(hs.hitsTotal) -//line app/vlselect/logsql/hits_response.qtpl:66 - qw422016.N().S(`}`) -//line app/vlselect/logsql/hits_response.qtpl:68 -} - -//line app/vlselect/logsql/hits_response.qtpl:68 -func writehitsSeriesLine(qq422016 qtio422016.Writer, m map[string]*hitsSeries, k string) { -//line app/vlselect/logsql/hits_response.qtpl:68 - qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vlselect/logsql/hits_response.qtpl:68 - streamhitsSeriesLine(qw422016, m, k) -//line app/vlselect/logsql/hits_response.qtpl:68 - qt422016.ReleaseWriter(qw422016) -//line app/vlselect/logsql/hits_response.qtpl:68 -} - -//line app/vlselect/logsql/hits_response.qtpl:68 -func hitsSeriesLine(m map[string]*hitsSeries, k string) string { -//line app/vlselect/logsql/hits_response.qtpl:68 - qb422016 := qt422016.AcquireByteBuffer() -//line app/vlselect/logsql/hits_response.qtpl:68 - writehitsSeriesLine(qb422016, m, k) -//line app/vlselect/logsql/hits_response.qtpl:68 - qs422016 := string(qb422016.B) -//line app/vlselect/logsql/hits_response.qtpl:68 - qt422016.ReleaseByteBuffer(qb422016) -//line app/vlselect/logsql/hits_response.qtpl:68 - return qs422016 -//line app/vlselect/logsql/hits_response.qtpl:68 -} diff --git a/app/vlselect/logsql/logsql.go b/app/vlselect/logsql/logsql.go deleted file mode 100644 index 37c308d14b..0000000000 --- a/app/vlselect/logsql/logsql.go +++ /dev/null @@ -1,1335 +0,0 @@ -package logsql - -import ( - "context" - "fmt" - "io" - "math" - "net/http" - "regexp" - "slices" - "sort" - "strconv" - "strings" - "sync" - "sync/atomic" - "time" - - "github.com/VictoriaMetrics/metrics" - "github.com/valyala/fastjson" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlstorage" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/atomicutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httputil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/timeutil" -) - -// ProcessFacetsRequest handles /select/logsql/facets request. -// -// See https://docs.victoriametrics.com/victorialogs/querying/#querying-facets -func ProcessFacetsRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) { - q, tenantIDs, err := parseCommonArgs(r) - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - - limit, err := httputil.GetInt(r, "limit") - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - maxValuesPerField, err := httputil.GetInt(r, "max_values_per_field") - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - maxValueLen, err := httputil.GetInt(r, "max_value_len") - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - keepConstFields := httputil.GetBool(r, "keep_const_fields") - - // Pipes must be dropped, since it is expected facets are obtained - // from the real logs stored in the database. - q.DropAllPipes() - - q.AddFacetsPipe(limit, maxValuesPerField, maxValueLen, keepConstFields) - - var mLock sync.Mutex - m := make(map[string][]facetEntry) - writeBlock := func(_ uint, db *logstorage.DataBlock) { - rowsCount := db.RowsCount() - if rowsCount == 0 { - return - } - - columns := db.Columns - if len(columns) != 3 { - logger.Panicf("BUG: expecting 3 columns; got %d columns", len(columns)) - } - - fieldNames := columns[0].Values - fieldValues := columns[1].Values - hits := columns[2].Values - - bb := blockResultPool.Get() - for i := range fieldNames { - fieldName := strings.Clone(fieldNames[i]) - fieldValue := strings.Clone(fieldValues[i]) - hitsStr := strings.Clone(hits[i]) - - mLock.Lock() - m[fieldName] = append(m[fieldName], facetEntry{ - value: fieldValue, - hits: hitsStr, - }) - mLock.Unlock() - } - blockResultPool.Put(bb) - } - - // Execute the query - if err := vlstorage.RunQuery(ctx, tenantIDs, q, writeBlock); err != nil { - httpserver.Errorf(w, r, "cannot execute query [%s]: %s", q, err) - return - } - - // Write response - w.Header().Set("Content-Type", "application/json") - WriteFacetsResponse(w, m) -} - -type facetEntry struct { - value string - hits string -} - -// ProcessHitsRequest handles /select/logsql/hits request. -// -// See https://docs.victoriametrics.com/victorialogs/querying/#querying-hits-stats -func ProcessHitsRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) { - q, tenantIDs, err := parseCommonArgs(r) - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - - // Obtain step - stepStr := r.FormValue("step") - if stepStr == "" { - stepStr = "1d" - } - step, err := timeutil.ParseDuration(stepStr) - if err != nil { - httpserver.Errorf(w, r, "cannot parse 'step' arg: %s", err) - return - } - if step <= 0 { - httpserver.Errorf(w, r, "'step' must be bigger than zero") - return - } - - // Obtain offset - offsetStr := r.FormValue("offset") - if offsetStr == "" { - offsetStr = "0s" - } - offset, err := timeutil.ParseDuration(offsetStr) - if err != nil { - httpserver.Errorf(w, r, "cannot parse 'offset' arg: %s", err) - return - } - - // Obtain field entries - fields := r.Form["field"] - - // Obtain limit on the number of top fields entries. - fieldsLimit, err := httputil.GetInt(r, "fields_limit") - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - if fieldsLimit < 0 { - fieldsLimit = 0 - } - - // Pipes must be dropped, since it is expected hits are obtained - // from the real logs stored in the database. - q.DropAllPipes() - - q.AddCountByTimePipe(int64(step), int64(offset), fields) - - var mLock sync.Mutex - m := make(map[string]*hitsSeries) - writeBlock := func(_ uint, db *logstorage.DataBlock) { - rowsCount := db.RowsCount() - if rowsCount == 0 { - return - } - - columns := db.Columns - timestampValues := columns[0].Values - hitsValues := columns[len(columns)-1].Values - columns = columns[1 : len(columns)-1] - - bb := blockResultPool.Get() - for i := 0; i < rowsCount; i++ { - timestampStr := strings.Clone(timestampValues[i]) - hitsStr := strings.Clone(hitsValues[i]) - hits, err := strconv.ParseUint(hitsStr, 10, 64) - if err != nil { - logger.Panicf("BUG: cannot parse hitsStr=%q: %s", hitsStr, err) - } - - bb.Reset() - WriteFieldsForHits(bb, columns, i) - - mLock.Lock() - hs, ok := m[string(bb.B)] - if !ok { - k := string(bb.B) - hs = &hitsSeries{} - m[k] = hs - } - hs.timestamps = append(hs.timestamps, timestampStr) - hs.hits = append(hs.hits, hits) - hs.hitsTotal += hits - mLock.Unlock() - } - blockResultPool.Put(bb) - } - - // Execute the query - if err := vlstorage.RunQuery(ctx, tenantIDs, q, writeBlock); err != nil { - httpserver.Errorf(w, r, "cannot execute query [%s]: %s", q, err) - return - } - - m = getTopHitsSeries(m, fieldsLimit) - - // Write response - w.Header().Set("Content-Type", "application/json") - WriteHitsSeries(w, m) -} - -var blockResultPool bytesutil.ByteBufferPool - -func getTopHitsSeries(m map[string]*hitsSeries, fieldsLimit int) map[string]*hitsSeries { - if fieldsLimit <= 0 || fieldsLimit >= len(m) { - return m - } - - type fieldsHits struct { - fieldsStr string - hs *hitsSeries - } - a := make([]fieldsHits, 0, len(m)) - for fieldsStr, hs := range m { - a = append(a, fieldsHits{ - fieldsStr: fieldsStr, - hs: hs, - }) - } - sort.Slice(a, func(i, j int) bool { - return a[i].hs.hitsTotal > a[j].hs.hitsTotal - }) - - hitsOther := make(map[string]uint64) - for _, x := range a[fieldsLimit:] { - for i, timestampStr := range x.hs.timestamps { - hitsOther[timestampStr] += x.hs.hits[i] - } - } - var hsOther hitsSeries - for timestampStr, hits := range hitsOther { - hsOther.timestamps = append(hsOther.timestamps, timestampStr) - hsOther.hits = append(hsOther.hits, hits) - hsOther.hitsTotal += hits - } - - mNew := make(map[string]*hitsSeries, fieldsLimit+1) - for _, x := range a[:fieldsLimit] { - mNew[x.fieldsStr] = x.hs - } - mNew["{}"] = &hsOther - - return mNew -} - -type hitsSeries struct { - hitsTotal uint64 - timestamps []string - hits []uint64 -} - -func (hs *hitsSeries) sort() { - sort.Sort(hs) -} - -func (hs *hitsSeries) Len() int { - return len(hs.timestamps) -} - -func (hs *hitsSeries) Swap(i, j int) { - hs.timestamps[i], hs.timestamps[j] = hs.timestamps[j], hs.timestamps[i] - hs.hits[i], hs.hits[j] = hs.hits[j], hs.hits[i] -} - -func (hs *hitsSeries) Less(i, j int) bool { - return hs.timestamps[i] < hs.timestamps[j] -} - -// ProcessFieldNamesRequest handles /select/logsql/field_names request. -// -// See https://docs.victoriametrics.com/victorialogs/querying/#querying-field-names -func ProcessFieldNamesRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) { - q, tenantIDs, err := parseCommonArgs(r) - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - - // Pipes must be dropped, since it is expected field names are obtained - // from the real logs stored in the database. - q.DropAllPipes() - - // Obtain field names for the given query - fieldNames, err := vlstorage.GetFieldNames(ctx, tenantIDs, q) - if err != nil { - httpserver.Errorf(w, r, "cannot obtain field names: %s", err) - return - } - - // Write results - w.Header().Set("Content-Type", "application/json") - WriteValuesWithHitsJSON(w, fieldNames) -} - -// ProcessFieldValuesRequest handles /select/logsql/field_values request. -// -// See https://docs.victoriametrics.com/victorialogs/querying/#querying-field-values -func ProcessFieldValuesRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) { - q, tenantIDs, err := parseCommonArgs(r) - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - - // Parse fieldName query arg - fieldName := r.FormValue("field") - if fieldName == "" { - httpserver.Errorf(w, r, "missing 'field' query arg") - return - } - - // Parse limit query arg - limit, err := httputil.GetInt(r, "limit") - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - if limit < 0 { - limit = 0 - } - - // Pipes must be dropped, since it is expected field values are obtained - // from the real logs stored in the database. - q.DropAllPipes() - - // Obtain unique values for the given field - values, err := vlstorage.GetFieldValues(ctx, tenantIDs, q, fieldName, uint64(limit)) - if err != nil { - httpserver.Errorf(w, r, "cannot obtain values for field %q: %s", fieldName, err) - return - } - - // Write results - w.Header().Set("Content-Type", "application/json") - WriteValuesWithHitsJSON(w, values) -} - -// ProcessStreamFieldNamesRequest processes /select/logsql/stream_field_names request. -// -// See https://docs.victoriametrics.com/victorialogs/querying/#querying-stream-field-names -func ProcessStreamFieldNamesRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) { - q, tenantIDs, err := parseCommonArgs(r) - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - - // Pipes must be dropped, since it is expected stream field names are obtained - // from the real logs stored in the database. - q.DropAllPipes() - - // Obtain stream field names for the given query - names, err := vlstorage.GetStreamFieldNames(ctx, tenantIDs, q) - if err != nil { - httpserver.Errorf(w, r, "cannot obtain stream field names: %s", err) - } - - // Write results - w.Header().Set("Content-Type", "application/json") - WriteValuesWithHitsJSON(w, names) -} - -// ProcessStreamFieldValuesRequest processes /select/logsql/stream_field_values request. -// -// See https://docs.victoriametrics.com/victorialogs/querying/#querying-stream-field-values -func ProcessStreamFieldValuesRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) { - q, tenantIDs, err := parseCommonArgs(r) - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - - // Parse fieldName query arg - fieldName := r.FormValue("field") - if fieldName == "" { - httpserver.Errorf(w, r, "missing 'field' query arg") - return - } - - // Parse limit query arg - limit, err := httputil.GetInt(r, "limit") - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - if limit < 0 { - limit = 0 - } - - // Pipes must be dropped, since it is expected stream field values are obtained - // from the real logs stored in the database. - q.DropAllPipes() - - // Obtain stream field values for the given query and the given fieldName - values, err := vlstorage.GetStreamFieldValues(ctx, tenantIDs, q, fieldName, uint64(limit)) - if err != nil { - httpserver.Errorf(w, r, "cannot obtain stream field values: %s", err) - } - - // Write results - w.Header().Set("Content-Type", "application/json") - WriteValuesWithHitsJSON(w, values) -} - -// ProcessStreamIDsRequest processes /select/logsql/stream_ids request. -// -// See https://docs.victoriametrics.com/victorialogs/querying/#querying-stream_ids -func ProcessStreamIDsRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) { - q, tenantIDs, err := parseCommonArgs(r) - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - - // Parse limit query arg - limit, err := httputil.GetInt(r, "limit") - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - if limit < 0 { - limit = 0 - } - - // Pipes must be dropped, since it is expected stream ids are obtained - // from the real logs stored in the database. - q.DropAllPipes() - - // Obtain streamIDs for the given query - streamIDs, err := vlstorage.GetStreamIDs(ctx, tenantIDs, q, uint64(limit)) - if err != nil { - httpserver.Errorf(w, r, "cannot obtain stream_ids: %s", err) - } - - // Write results - w.Header().Set("Content-Type", "application/json") - WriteValuesWithHitsJSON(w, streamIDs) -} - -// ProcessStreamsRequest processes /select/logsql/streams request. -// -// See https://docs.victoriametrics.com/victorialogs/querying/#querying-streams -func ProcessStreamsRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) { - q, tenantIDs, err := parseCommonArgs(r) - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - - // Parse limit query arg - limit, err := httputil.GetInt(r, "limit") - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - if limit < 0 { - limit = 0 - } - - // Pipes must be dropped, since it is expected stream are obtained - // from the real logs stored in the database. - q.DropAllPipes() - - // Obtain streams for the given query - streams, err := vlstorage.GetStreams(ctx, tenantIDs, q, uint64(limit)) - if err != nil { - httpserver.Errorf(w, r, "cannot obtain streams: %s", err) - } - - // Write results - w.Header().Set("Content-Type", "application/json") - WriteValuesWithHitsJSON(w, streams) -} - -// ProcessLiveTailRequest processes live tailing request to /select/logsq/tail -// -// See https://docs.victoriametrics.com/victorialogs/querying/#live-tailing -func ProcessLiveTailRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) { - liveTailRequests.Inc() - defer liveTailRequests.Dec() - - q, tenantIDs, err := parseCommonArgs(r) - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - if !q.CanLiveTail() { - httpserver.Errorf(w, r, "the query [%s] cannot be used in live tailing; "+ - "see https://docs.victoriametrics.com/victorialogs/querying/#live-tailing for details", q) - return - } - - refreshIntervalMsecs, err := httputil.GetDuration(r, "refresh_interval", 1000) - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - refreshInterval := time.Millisecond * time.Duration(refreshIntervalMsecs) - - startOffsetMsecs, err := httputil.GetDuration(r, "start_offset", 5*1000) - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - startOffset := startOffsetMsecs * 1e6 - - offsetMsecs, err := httputil.GetDuration(r, "offset", 1000) - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - offset := offsetMsecs * 1e6 - - ctxWithCancel, cancel := context.WithCancel(ctx) - tp := newTailProcessor(cancel) - - ticker := time.NewTicker(refreshInterval) - defer ticker.Stop() - - end := time.Now().UnixNano() - offset - start := end - startOffset - doneCh := ctxWithCancel.Done() - flusher, ok := w.(http.Flusher) - if !ok { - logger.Panicf("BUG: it is expected that http.ResponseWriter (%T) supports http.Flusher interface", w) - } - - w.Header().Set("Content-Type", "application/x-ndjson") - w.Header().Set("Access-Control-Allow-Origin", "*") - flusher.Flush() - - qOrig := q - for { - q = qOrig.CloneWithTimeFilter(end, start, end) - if err := vlstorage.RunQuery(ctxWithCancel, tenantIDs, q, tp.writeBlock); err != nil { - httpserver.Errorf(w, r, "cannot execute tail query [%s]: %s", q, err) - return - } - resultRows, err := tp.getTailRows() - if err != nil { - httpserver.Errorf(w, r, "cannot get tail results for query [%q]: %s", q, err) - return - } - if len(resultRows) > 0 { - WriteJSONRows(w, resultRows) - flusher.Flush() - } - - select { - case <-doneCh: - return - case <-ticker.C: - start = end - tailOffsetNsecs - end = time.Now().UnixNano() - offset - } - } -} - -var liveTailRequests = metrics.NewCounter(`vl_live_tailing_requests`) - -const tailOffsetNsecs = 5e9 - -type logRow struct { - timestamp int64 - fields []logstorage.Field -} - -func sortLogRows(rows []logRow) { - sort.SliceStable(rows, func(i, j int) bool { - return rows[i].timestamp < rows[j].timestamp - }) -} - -type tailProcessor struct { - cancel func() - - mu sync.Mutex - - perStreamRows map[string][]logRow - lastTimestamps map[string]int64 - - err error -} - -func newTailProcessor(cancel func()) *tailProcessor { - return &tailProcessor{ - cancel: cancel, - - perStreamRows: make(map[string][]logRow), - lastTimestamps: make(map[string]int64), - } -} - -func (tp *tailProcessor) writeBlock(_ uint, db *logstorage.DataBlock) { - if db.RowsCount() == 0 { - return - } - - tp.mu.Lock() - defer tp.mu.Unlock() - - if tp.err != nil { - return - } - - // Make sure columns contain _time field, since it is needed for proper tail work. - timestamps, ok := db.GetTimestamps(nil) - if !ok { - tp.err = fmt.Errorf("missing _time field") - tp.cancel() - return - } - - // Copy block rows to tp.perStreamRows - for i, timestamp := range timestamps { - streamID := "" - fields := make([]logstorage.Field, len(db.Columns)) - for j, c := range db.Columns { - name := strings.Clone(c.Name) - value := strings.Clone(c.Values[i]) - - fields[j] = logstorage.Field{ - Name: name, - Value: value, - } - - if name == "_stream_id" { - streamID = value - } - } - - tp.perStreamRows[streamID] = append(tp.perStreamRows[streamID], logRow{ - timestamp: timestamp, - fields: fields, - }) - } -} - -func (tp *tailProcessor) getTailRows() ([][]logstorage.Field, error) { - if tp.err != nil { - return nil, tp.err - } - - var resultRows []logRow - for streamID, rows := range tp.perStreamRows { - sortLogRows(rows) - - lastTimestamp, ok := tp.lastTimestamps[streamID] - if ok { - // Skip already written rows - for len(rows) > 0 && rows[0].timestamp <= lastTimestamp { - rows = rows[1:] - } - } - if len(rows) > 0 { - resultRows = append(resultRows, rows...) - tp.lastTimestamps[streamID] = rows[len(rows)-1].timestamp - } - } - clear(tp.perStreamRows) - - sortLogRows(resultRows) - - tailRows := make([][]logstorage.Field, len(resultRows)) - for i, row := range resultRows { - tailRows[i] = row.fields - } - - return tailRows, nil -} - -// ProcessStatsQueryRangeRequest handles /select/logsql/stats_query_range request. -// -// See https://docs.victoriametrics.com/victorialogs/querying/#querying-log-range-stats -func ProcessStatsQueryRangeRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) { - q, tenantIDs, err := parseCommonArgs(r) - if err != nil { - httpserver.SendPrometheusError(w, r, err) - return - } - - // Obtain step - stepStr := r.FormValue("step") - if stepStr == "" { - stepStr = "1d" - } - step, err := timeutil.ParseDuration(stepStr) - if err != nil { - err = fmt.Errorf("cannot parse 'step' arg: %s", err) - httpserver.SendPrometheusError(w, r, err) - return - } - if step <= 0 { - err := fmt.Errorf("'step' must be bigger than zero") - httpserver.SendPrometheusError(w, r, err) - return - } - - // Obtain `by(...)` fields from the last `| stats` pipe in q. - // Add `_time:step` to the `by(...)` list. - byFields, err := q.GetStatsByFieldsAddGroupingByTime(int64(step)) - if err != nil { - httpserver.SendPrometheusError(w, r, err) - return - } - - m := make(map[string]*statsSeries) - var mLock sync.Mutex - - writeBlock := func(_ uint, db *logstorage.DataBlock) { - rowsCount := db.RowsCount() - - columns := db.Columns - clonedColumnNames := make([]string, len(columns)) - for i, c := range columns { - clonedColumnNames[i] = strings.Clone(c.Name) - } - for i := 0; i < rowsCount; i++ { - // Do not move q.GetTimestamp() outside writeBlock, since ts - // must be initialized to query timestamp for every processed log row. - // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8312 - ts := q.GetTimestamp() - labels := make([]logstorage.Field, 0, len(byFields)) - for j, c := range columns { - if c.Name == "_time" { - nsec, ok := logstorage.TryParseTimestampRFC3339Nano(c.Values[i]) - if ok { - ts = nsec - continue - } - } - if slices.Contains(byFields, c.Name) { - labels = append(labels, logstorage.Field{ - Name: clonedColumnNames[j], - Value: strings.Clone(c.Values[i]), - }) - } - } - - var dst []byte - for j, c := range columns { - if !slices.Contains(byFields, c.Name) { - name := clonedColumnNames[j] - dst = dst[:0] - dst = append(dst, name...) - dst = logstorage.MarshalFieldsToJSON(dst, labels) - key := string(dst) - p := statsPoint{ - Timestamp: ts, - Value: strings.Clone(c.Values[i]), - } - - mLock.Lock() - ss := m[key] - if ss == nil { - ss = &statsSeries{ - key: key, - Name: name, - Labels: labels, - } - m[key] = ss - } - ss.Points = append(ss.Points, p) - mLock.Unlock() - } - } - } - } - - if err := vlstorage.RunQuery(ctx, tenantIDs, q, writeBlock); err != nil { - err = fmt.Errorf("cannot execute query [%s]: %s", q, err) - httpserver.SendPrometheusError(w, r, err) - return - } - - // Sort the collected stats by time - rows := make([]*statsSeries, 0, len(m)) - for _, ss := range m { - points := ss.Points - sort.Slice(points, func(i, j int) bool { - return points[i].Timestamp < points[j].Timestamp - }) - rows = append(rows, ss) - } - sort.Slice(rows, func(i, j int) bool { - return rows[i].key < rows[j].key - }) - - w.Header().Set("Content-Type", "application/json") - WriteStatsQueryRangeResponse(w, rows) -} - -type statsSeries struct { - key string - - Name string - Labels []logstorage.Field - Points []statsPoint -} - -type statsPoint struct { - Timestamp int64 - Value string -} - -// ProcessStatsQueryRequest handles /select/logsql/stats_query request. -// -// See https://docs.victoriametrics.com/victorialogs/querying/#querying-log-stats -func ProcessStatsQueryRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) { - q, tenantIDs, err := parseCommonArgs(r) - if err != nil { - httpserver.SendPrometheusError(w, r, err) - return - } - - // Obtain `by(...)` fields from the last `| stats` pipe in q. - byFields, err := q.GetStatsByFields() - if err != nil { - httpserver.SendPrometheusError(w, r, err) - return - } - - var rows []statsRow - var rowsLock sync.Mutex - - timestamp := q.GetTimestamp() - writeBlock := func(_ uint, db *logstorage.DataBlock) { - rowsCount := db.RowsCount() - columns := db.Columns - clonedColumnNames := make([]string, len(columns)) - for i, c := range columns { - clonedColumnNames[i] = strings.Clone(c.Name) - } - for i := 0; i < rowsCount; i++ { - labels := make([]logstorage.Field, 0, len(byFields)) - for j, c := range columns { - if slices.Contains(byFields, c.Name) { - labels = append(labels, logstorage.Field{ - Name: clonedColumnNames[j], - Value: strings.Clone(c.Values[i]), - }) - } - } - - for j, c := range columns { - if !slices.Contains(byFields, c.Name) { - r := statsRow{ - Name: clonedColumnNames[j], - Labels: labels, - Timestamp: timestamp, - Value: strings.Clone(c.Values[i]), - } - - rowsLock.Lock() - rows = append(rows, r) - rowsLock.Unlock() - } - } - } - } - - if err := vlstorage.RunQuery(ctx, tenantIDs, q, writeBlock); err != nil { - err = fmt.Errorf("cannot execute query [%s]: %s", q, err) - httpserver.SendPrometheusError(w, r, err) - return - } - - w.Header().Set("Content-Type", "application/json") - WriteStatsQueryResponse(w, rows) -} - -type statsRow struct { - Name string - Labels []logstorage.Field - Timestamp int64 - Value string -} - -// ProcessQueryRequest handles /select/logsql/query request. -// -// See https://docs.victoriametrics.com/victorialogs/querying/#querying-logs -func ProcessQueryRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) { - q, tenantIDs, err := parseCommonArgs(r) - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - - // Parse limit query arg - limit, err := httputil.GetInt(r, "limit") - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - - sw := &syncWriter{ - w: w, - } - - var bwShards atomicutil.Slice[bufferedWriter] - bwShards.Init = func(shard *bufferedWriter) { - shard.sw = sw - } - defer func() { - shards := bwShards.All() - for _, shard := range shards { - shard.FlushIgnoreErrors() - } - }() - - w.Header().Set("Content-Type", "application/stream+json") - - if limit > 0 { - if q.CanReturnLastNResults() { - rows, err := getLastNQueryResults(ctx, tenantIDs, q, limit) - if err != nil { - httpserver.Errorf(w, r, "%s", err) - return - } - bw := bwShards.Get(0) - for i := range rows { - bw.buf = logstorage.MarshalFieldsToJSON(bw.buf, rows[i].fields) - bw.buf = append(bw.buf, '\n') - if len(bw.buf) > 16*1024 { - bw.FlushIgnoreErrors() - } - } - return - } - - q.AddPipeLimit(uint64(limit)) - } - - writeBlock := func(workerID uint, db *logstorage.DataBlock) { - rowsCount := db.RowsCount() - if rowsCount == 0 { - return - } - columns := db.Columns - - bw := bwShards.Get(workerID) - for i := 0; i < rowsCount; i++ { - WriteJSONRow(bw, columns, i) - if len(bw.buf) > 16*1024 { - bw.FlushIgnoreErrors() - } - } - } - - if err := vlstorage.RunQuery(ctx, tenantIDs, q, writeBlock); err != nil { - httpserver.Errorf(w, r, "cannot execute query [%s]: %s", q, err) - return - } -} - -type syncWriter struct { - mu sync.Mutex - w io.Writer -} - -func (sw *syncWriter) Write(p []byte) (int, error) { - sw.mu.Lock() - n, err := sw.w.Write(p) - sw.mu.Unlock() - return n, err -} - -type bufferedWriter struct { - buf []byte - sw *syncWriter -} - -func (bw *bufferedWriter) Write(p []byte) (int, error) { - bw.buf = append(bw.buf, p...) - - // Do not send bw.buf to bw.sw here, since the data at bw.buf may be incomplete (it must end with '\n') - - return len(p), nil -} - -func (bw *bufferedWriter) FlushIgnoreErrors() { - _, _ = bw.sw.Write(bw.buf) - bw.buf = bw.buf[:0] -} - -func getLastNQueryResults(ctx context.Context, tenantIDs []logstorage.TenantID, q *logstorage.Query, limit int) ([]logRow, error) { - limitUpper := 2 * limit - q.AddPipeLimit(uint64(limitUpper)) - - rows, err := getQueryResultsWithLimit(ctx, tenantIDs, q, limitUpper) - if err != nil { - return nil, err - } - if len(rows) < limitUpper { - // Fast path - the requested time range contains up to limitUpper rows. - rows = getLastNRows(rows, limit) - return rows, nil - } - - // Slow path - adjust time range for selecting up to limitUpper rows - start, end := q.GetFilterTimeRange() - d := end/2 - start/2 - start += d - - qOrig := q - for { - timestamp := qOrig.GetTimestamp() - q = qOrig.CloneWithTimeFilter(timestamp, start, end) - rows, err := getQueryResultsWithLimit(ctx, tenantIDs, q, limitUpper) - if err != nil { - return nil, err - } - - if d == 0 || start >= end { - // The [start ... end] time range equals one nanosecond. - // Just return up to limit rows. - if len(rows) > limit { - rows = rows[:limit] - } - return rows, nil - } - - dLastBit := d & 1 - d /= 2 - - if len(rows) >= limitUpper { - // The number of found rows on the [start ... end] time range exceeds limitUpper, - // so reduce the time range to [start+d ... end]. - start += d - continue - } - if len(rows) >= limit { - // The number of found rows is in the range [limit ... limitUpper). - // This means that found rows contains the needed limit rows with the biggest timestamps. - rows = getLastNRows(rows, limit) - return rows, nil - } - - // The number of found rows on [start ... end] time range is below the limit. - // This means the time range doesn't cover the needed logs, so it must be extended. - - if len(rows) == 0 { - // The [start ... end] time range doesn't contain any rows, so change it to [start-d ... start). - end = start - 1 - start -= d + dLastBit - continue - } - - // The number of found rows on [start ... end] time range is bigger than 0 but smaller than limit. - // Increase the time range to [start-d ... end]. - start -= d + dLastBit - } -} - -func getLastNRows(rows []logRow, limit int) []logRow { - sortLogRows(rows) - if len(rows) > limit { - rows = rows[len(rows)-limit:] - } - return rows -} - -func getQueryResultsWithLimit(ctx context.Context, tenantIDs []logstorage.TenantID, q *logstorage.Query, limit int) ([]logRow, error) { - ctxWithCancel, cancel := context.WithCancel(ctx) - defer cancel() - - var missingTimeColumn atomic.Bool - var rows []logRow - var rowsLock sync.Mutex - writeBlock := func(_ uint, db *logstorage.DataBlock) { - if missingTimeColumn.Load() { - return - } - - columns := db.Columns - clonedColumnNames := make([]string, len(columns)) - for i, c := range columns { - clonedColumnNames[i] = strings.Clone(c.Name) - } - - timestamps, ok := db.GetTimestamps(nil) - if !ok { - missingTimeColumn.Store(true) - cancel() - return - } - - for i, timestamp := range timestamps { - fields := make([]logstorage.Field, len(columns)) - for j := range columns { - f := &fields[j] - f.Name = clonedColumnNames[j] - f.Value = strings.Clone(columns[j].Values[i]) - } - - rowsLock.Lock() - rows = append(rows, logRow{ - timestamp: timestamp, - fields: fields, - }) - rowsLock.Unlock() - } - - if len(rows) >= limit { - cancel() - } - } - err := vlstorage.RunQuery(ctxWithCancel, tenantIDs, q, writeBlock) - - if missingTimeColumn.Load() { - return nil, fmt.Errorf("missing _time column in the result for the query [%s]", q) - } - - return rows, err -} - -func parseCommonArgs(r *http.Request) (*logstorage.Query, []logstorage.TenantID, error) { - // Extract tenantID - tenantID, err := logstorage.GetTenantIDFromRequest(r) - if err != nil { - return nil, nil, fmt.Errorf("cannot obtain tenanID: %w", err) - } - tenantIDs := []logstorage.TenantID{tenantID} - - // Parse optional start and end args - start, okStart, err := getTimeNsec(r, "start") - if err != nil { - return nil, nil, err - } - end, okEnd, err := getTimeNsec(r, "end") - if err != nil { - return nil, nil, err - } - - // Parse optional time arg - timestamp, okTime, err := getTimeNsec(r, "time") - if err != nil { - return nil, nil, err - } - if !okTime { - // If time arg is missing, then evaluate query either at the end timestamp (if it is set) - // or at the current timestamp (if end query arg isn't set) - if okEnd { - timestamp = end - } else { - timestamp = time.Now().UnixNano() - } - } - - // decrease timestamp by one nanosecond in order to avoid capturing logs belonging - // to the first nanosecond at the next period of time (month, week, day, hour, etc.) - timestamp-- - - // Parse query - qStr := r.FormValue("query") - q, err := logstorage.ParseQueryAtTimestamp(qStr, timestamp) - if err != nil { - return nil, nil, fmt.Errorf("cannot parse query [%s]: %s", qStr, err) - } - - if okStart || okEnd { - // Add _time:[start, end] filter if start or end args were set. - if !okStart { - start = math.MinInt64 - } - if !okEnd { - end = math.MaxInt64 - } - q.AddTimeFilter(start, end) - } - - // Parse optional extra_filters - for _, extraFiltersStr := range r.Form["extra_filters"] { - extraFilters, err := parseExtraFilters(extraFiltersStr) - if err != nil { - return nil, nil, err - } - q.AddExtraFilters(extraFilters) - } - - // Parse optional extra_stream_filters - for _, extraStreamFiltersStr := range r.Form["extra_stream_filters"] { - extraStreamFilters, err := parseExtraStreamFilters(extraStreamFiltersStr) - if err != nil { - return nil, nil, err - } - q.AddExtraFilters(extraStreamFilters) - } - - return q, tenantIDs, nil -} - -func getTimeNsec(r *http.Request, argName string) (int64, bool, error) { - s := r.FormValue(argName) - if s == "" { - return 0, false, nil - } - currentTimestamp := time.Now().UnixNano() - nsecs, err := timeutil.ParseTimeAt(s, currentTimestamp) - if err != nil { - return 0, false, fmt.Errorf("cannot parse %s=%s: %w", argName, s, err) - } - return nsecs, true, nil -} - -func parseExtraFilters(s string) (*logstorage.Filter, error) { - if s == "" { - return nil, nil - } - if !strings.HasPrefix(s, `{"`) { - return logstorage.ParseFilter(s) - } - - // Extra filters in the form {"field":"value",...}. - kvs, err := parseExtraFiltersJSON(s) - if err != nil { - return nil, err - } - - filters := make([]string, len(kvs)) - for i, kv := range kvs { - if len(kv.values) == 1 { - filters[i] = fmt.Sprintf("%q:=%q", kv.key, kv.values[0]) - } else { - orValues := make([]string, len(kv.values)) - for j, v := range kv.values { - orValues[j] = fmt.Sprintf("%q", v) - } - filters[i] = fmt.Sprintf("%q:in(%s)", kv.key, strings.Join(orValues, ",")) - } - } - s = strings.Join(filters, " ") - return logstorage.ParseFilter(s) -} - -func parseExtraStreamFilters(s string) (*logstorage.Filter, error) { - if s == "" { - return nil, nil - } - if !strings.HasPrefix(s, `{"`) { - return logstorage.ParseFilter(s) - } - - // Extra stream filters in the form {"field":"value",...}. - kvs, err := parseExtraFiltersJSON(s) - if err != nil { - return nil, err - } - - filters := make([]string, len(kvs)) - for i, kv := range kvs { - if len(kv.values) == 1 { - filters[i] = fmt.Sprintf("%q=%q", kv.key, kv.values[0]) - } else { - orValues := make([]string, len(kv.values)) - for j, v := range kv.values { - orValues[j] = regexp.QuoteMeta(v) - } - filters[i] = fmt.Sprintf("%q=~%q", kv.key, strings.Join(orValues, "|")) - } - } - s = "{" + strings.Join(filters, ",") + "}" - return logstorage.ParseFilter(s) -} - -type extraFilter struct { - key string - values []string -} - -func parseExtraFiltersJSON(s string) ([]extraFilter, error) { - v, err := fastjson.Parse(s) - if err != nil { - return nil, err - } - o := v.GetObject() - - var errOuter error - var filters []extraFilter - o.Visit(func(k []byte, v *fastjson.Value) { - if errOuter != nil { - return - } - switch v.Type() { - case fastjson.TypeString: - filters = append(filters, extraFilter{ - key: string(k), - values: []string{string(v.GetStringBytes())}, - }) - case fastjson.TypeArray: - a := v.GetArray() - if len(a) == 0 { - return - } - orValues := make([]string, len(a)) - for i, av := range a { - ov, err := av.StringBytes() - if err != nil { - errOuter = fmt.Errorf("cannot obtain string item at the array for key %q; item: %s", k, av) - return - } - orValues[i] = string(ov) - } - filters = append(filters, extraFilter{ - key: string(k), - values: orValues, - }) - default: - errOuter = fmt.Errorf("unexpected type of value for key %q: %s; value: %s", k, v.Type(), v) - } - }) - if errOuter != nil { - return nil, errOuter - } - return filters, nil -} diff --git a/app/vlselect/logsql/logsql.qtpl b/app/vlselect/logsql/logsql.qtpl deleted file mode 100644 index b462e8cbc6..0000000000 --- a/app/vlselect/logsql/logsql.qtpl +++ /dev/null @@ -1,32 +0,0 @@ -{% import ( - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" -) %} - -{% stripspace %} - -// ValuesWithHitsJSON generates JSON from the given values. -{% func ValuesWithHitsJSON(values []logstorage.ValueWithHits) %} -{ - "values":{%= valuesWithHitsJSONArray(values) %} -} -{% endfunc %} - -{% func valuesWithHitsJSONArray(values []logstorage.ValueWithHits) %} -[ - {% if len(values) > 0 %} - {%= valueWithHitsJSON(values[0]) %} - {% for _, v := range values[1:] %} - ,{%= valueWithHitsJSON(v) %} - {% endfor %} - {% endif %} -] -{% endfunc %} - -{% func valueWithHitsJSON(v logstorage.ValueWithHits) %} -{ - "value":{%q= v.Value %}, - "hits":{%dul= v.Hits %} -} -{% endfunc %} - -{% endstripspace %} diff --git a/app/vlselect/logsql/logsql.qtpl.go b/app/vlselect/logsql/logsql.qtpl.go deleted file mode 100644 index 47ff291b93..0000000000 --- a/app/vlselect/logsql/logsql.qtpl.go +++ /dev/null @@ -1,152 +0,0 @@ -// Code generated by qtc from "logsql.qtpl". DO NOT EDIT. -// See https://github.com/valyala/quicktemplate for details. - -//line app/vlselect/logsql/logsql.qtpl:1 -package logsql - -//line app/vlselect/logsql/logsql.qtpl:1 -import ( - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" -) - -// ValuesWithHitsJSON generates JSON from the given values. - -//line app/vlselect/logsql/logsql.qtpl:8 -import ( - qtio422016 "io" - - qt422016 "github.com/valyala/quicktemplate" -) - -//line app/vlselect/logsql/logsql.qtpl:8 -var ( - _ = qtio422016.Copy - _ = qt422016.AcquireByteBuffer -) - -//line app/vlselect/logsql/logsql.qtpl:8 -func StreamValuesWithHitsJSON(qw422016 *qt422016.Writer, values []logstorage.ValueWithHits) { -//line app/vlselect/logsql/logsql.qtpl:8 - qw422016.N().S(`{"values":`) -//line app/vlselect/logsql/logsql.qtpl:10 - streamvaluesWithHitsJSONArray(qw422016, values) -//line app/vlselect/logsql/logsql.qtpl:10 - qw422016.N().S(`}`) -//line app/vlselect/logsql/logsql.qtpl:12 -} - -//line app/vlselect/logsql/logsql.qtpl:12 -func WriteValuesWithHitsJSON(qq422016 qtio422016.Writer, values []logstorage.ValueWithHits) { -//line app/vlselect/logsql/logsql.qtpl:12 - qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vlselect/logsql/logsql.qtpl:12 - StreamValuesWithHitsJSON(qw422016, values) -//line app/vlselect/logsql/logsql.qtpl:12 - qt422016.ReleaseWriter(qw422016) -//line app/vlselect/logsql/logsql.qtpl:12 -} - -//line app/vlselect/logsql/logsql.qtpl:12 -func ValuesWithHitsJSON(values []logstorage.ValueWithHits) string { -//line app/vlselect/logsql/logsql.qtpl:12 - qb422016 := qt422016.AcquireByteBuffer() -//line app/vlselect/logsql/logsql.qtpl:12 - WriteValuesWithHitsJSON(qb422016, values) -//line app/vlselect/logsql/logsql.qtpl:12 - qs422016 := string(qb422016.B) -//line app/vlselect/logsql/logsql.qtpl:12 - qt422016.ReleaseByteBuffer(qb422016) -//line app/vlselect/logsql/logsql.qtpl:12 - return qs422016 -//line app/vlselect/logsql/logsql.qtpl:12 -} - -//line app/vlselect/logsql/logsql.qtpl:14 -func streamvaluesWithHitsJSONArray(qw422016 *qt422016.Writer, values []logstorage.ValueWithHits) { -//line app/vlselect/logsql/logsql.qtpl:14 - qw422016.N().S(`[`) -//line app/vlselect/logsql/logsql.qtpl:16 - if len(values) > 0 { -//line app/vlselect/logsql/logsql.qtpl:17 - streamvalueWithHitsJSON(qw422016, values[0]) -//line app/vlselect/logsql/logsql.qtpl:18 - for _, v := range values[1:] { -//line app/vlselect/logsql/logsql.qtpl:18 - qw422016.N().S(`,`) -//line app/vlselect/logsql/logsql.qtpl:19 - streamvalueWithHitsJSON(qw422016, v) -//line app/vlselect/logsql/logsql.qtpl:20 - } -//line app/vlselect/logsql/logsql.qtpl:21 - } -//line app/vlselect/logsql/logsql.qtpl:21 - qw422016.N().S(`]`) -//line app/vlselect/logsql/logsql.qtpl:23 -} - -//line app/vlselect/logsql/logsql.qtpl:23 -func writevaluesWithHitsJSONArray(qq422016 qtio422016.Writer, values []logstorage.ValueWithHits) { -//line app/vlselect/logsql/logsql.qtpl:23 - qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vlselect/logsql/logsql.qtpl:23 - streamvaluesWithHitsJSONArray(qw422016, values) -//line app/vlselect/logsql/logsql.qtpl:23 - qt422016.ReleaseWriter(qw422016) -//line app/vlselect/logsql/logsql.qtpl:23 -} - -//line app/vlselect/logsql/logsql.qtpl:23 -func valuesWithHitsJSONArray(values []logstorage.ValueWithHits) string { -//line app/vlselect/logsql/logsql.qtpl:23 - qb422016 := qt422016.AcquireByteBuffer() -//line app/vlselect/logsql/logsql.qtpl:23 - writevaluesWithHitsJSONArray(qb422016, values) -//line app/vlselect/logsql/logsql.qtpl:23 - qs422016 := string(qb422016.B) -//line app/vlselect/logsql/logsql.qtpl:23 - qt422016.ReleaseByteBuffer(qb422016) -//line app/vlselect/logsql/logsql.qtpl:23 - return qs422016 -//line app/vlselect/logsql/logsql.qtpl:23 -} - -//line app/vlselect/logsql/logsql.qtpl:25 -func streamvalueWithHitsJSON(qw422016 *qt422016.Writer, v logstorage.ValueWithHits) { -//line app/vlselect/logsql/logsql.qtpl:25 - qw422016.N().S(`{"value":`) -//line app/vlselect/logsql/logsql.qtpl:27 - qw422016.N().Q(v.Value) -//line app/vlselect/logsql/logsql.qtpl:27 - qw422016.N().S(`,"hits":`) -//line app/vlselect/logsql/logsql.qtpl:28 - qw422016.N().DUL(v.Hits) -//line app/vlselect/logsql/logsql.qtpl:28 - qw422016.N().S(`}`) -//line app/vlselect/logsql/logsql.qtpl:30 -} - -//line app/vlselect/logsql/logsql.qtpl:30 -func writevalueWithHitsJSON(qq422016 qtio422016.Writer, v logstorage.ValueWithHits) { -//line app/vlselect/logsql/logsql.qtpl:30 - qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vlselect/logsql/logsql.qtpl:30 - streamvalueWithHitsJSON(qw422016, v) -//line app/vlselect/logsql/logsql.qtpl:30 - qt422016.ReleaseWriter(qw422016) -//line app/vlselect/logsql/logsql.qtpl:30 -} - -//line app/vlselect/logsql/logsql.qtpl:30 -func valueWithHitsJSON(v logstorage.ValueWithHits) string { -//line app/vlselect/logsql/logsql.qtpl:30 - qb422016 := qt422016.AcquireByteBuffer() -//line app/vlselect/logsql/logsql.qtpl:30 - writevalueWithHitsJSON(qb422016, v) -//line app/vlselect/logsql/logsql.qtpl:30 - qs422016 := string(qb422016.B) -//line app/vlselect/logsql/logsql.qtpl:30 - qt422016.ReleaseByteBuffer(qb422016) -//line app/vlselect/logsql/logsql.qtpl:30 - return qs422016 -//line app/vlselect/logsql/logsql.qtpl:30 -} diff --git a/app/vlselect/logsql/logsql_test.go b/app/vlselect/logsql/logsql_test.go deleted file mode 100644 index 913d9a9875..0000000000 --- a/app/vlselect/logsql/logsql_test.go +++ /dev/null @@ -1,103 +0,0 @@ -package logsql - -import ( - "testing" -) - -func TestParseExtraFilters_Success(t *testing.T) { - f := func(s, resultExpected string) { - t.Helper() - - f, err := parseExtraFilters(s) - if err != nil { - t.Fatalf("unexpected error in parseExtraFilters: %s", err) - } - result := f.String() - if result != resultExpected { - t.Fatalf("unexpected result\ngot\n%s\nwant\n%s", result, resultExpected) - } - } - - f("", "") - - // JSON string - f(`{"foo":"bar"}`, `foo:=bar`) - f(`{"foo":["bar","baz"]}`, `foo:in(bar,baz)`) - f(`{"z":"=b ","c":["d","e,"],"a":[],"_msg":"x"}`, `z:="=b " c:in(d,"e,") =x`) - - // LogsQL filter - f(`foobar`, `foobar`) - f(`foo:bar`, `foo:bar`) - f(`foo:(bar or baz) error _time:5m {"foo"=bar,baz="z"}`, `{foo="bar",baz="z"} (foo:bar or foo:baz) error _time:5m`) -} - -func TestParseExtraFilters_Failure(t *testing.T) { - f := func(s string) { - t.Helper() - - _, err := parseExtraFilters(s) - if err == nil { - t.Fatalf("expecting non-nil error") - } - } - - // Invalid JSON - f(`{"foo"}`) - f(`[1,2]`) - f(`{"foo":[1]}`) - - // Invliad LogsQL filter - f(`foo:(bar`) - - // excess pipe - f(`foo | count()`) -} - -func TestParseExtraStreamFilters_Success(t *testing.T) { - f := func(s, resultExpected string) { - t.Helper() - - f, err := parseExtraStreamFilters(s) - if err != nil { - t.Fatalf("unexpected error in parseExtraStreamFilters: %s", err) - } - result := f.String() - if result != resultExpected { - t.Fatalf("unexpected result;\ngot\n%s\nwant\n%s", result, resultExpected) - } - } - - f("", "") - - // JSON string - f(`{"foo":"bar"}`, `{foo="bar"}`) - f(`{"foo":["bar","baz"]}`, `{foo=~"bar|baz"}`) - f(`{"z":"b","c":["d","e|\""],"a":[],"_msg":"x"}`, `{z="b",c=~"d|e\\|\"",_msg="x"}`) - - // LogsQL filter - f(`foobar`, `foobar`) - f(`foo:bar`, `foo:bar`) - f(`foo:(bar or baz) error _time:5m {"foo"=bar,baz="z"}`, `{foo="bar",baz="z"} (foo:bar or foo:baz) error _time:5m`) -} - -func TestParseExtraStreamFilters_Failure(t *testing.T) { - f := func(s string) { - t.Helper() - - _, err := parseExtraStreamFilters(s) - if err == nil { - t.Fatalf("expecting non-nil error") - } - } - - // Invalid JSON - f(`{"foo"}`) - f(`[1,2]`) - f(`{"foo":[1]}`) - - // Invliad LogsQL filter - f(`foo:(bar`) - - // excess pipe - f(`foo | count()`) -} diff --git a/app/vlselect/logsql/query_response.qtpl b/app/vlselect/logsql/query_response.qtpl deleted file mode 100644 index e02b371b4b..0000000000 --- a/app/vlselect/logsql/query_response.qtpl +++ /dev/null @@ -1,64 +0,0 @@ -{% import ( - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" -) %} - -{% stripspace %} - -// JSONRow creates JSON row from the given fields. -{% func JSONRow(columns []logstorage.BlockColumn, rowIdx int) %} - {% code - i := 0 - for i < len(columns) && columns[i].Values[rowIdx] == "" { - i++ - } - columns = columns[i:] - %} - {% if len(columns) == 0 %} - {% return %} - {% endif %} - { - {% code c := &columns[0] %} - {%q= c.Name %}:{%q= c.Values[rowIdx] %} - {% code columns = columns[1:] %} - {% for colIdx := range columns %} - {% code - c := &columns[colIdx] - v := c.Values[rowIdx] - %} - {% if v == "" %} - {% continue %} - {% endif %} - ,{%q= c.Name %}:{%q= c.Values[rowIdx] %} - {% endfor %} - }{% newline %} -{% endfunc %} - -// JSONRows prints formatted rows -{% func JSONRows(rows [][]logstorage.Field) %} - {% if len(rows) == 0 %} - {% return %} - {% endif %} - {% for _, fields := range rows %} - {% code fields = logstorage.SkipLeadingFieldsWithoutValues(fields) %} - {% if len(fields) == 0 %} - {% continue %} - {% endif %} - { - {% if len(fields) > 0 %} - {% code - f := fields[0] - fields = fields[1:] - %} - {%q= f.Name %}:{%q= f.Value %} - {% for _, f := range fields %} - {% if f.Value == "" %} - {% continue %} - {% endif %} - ,{%q= f.Name %}:{%q= f.Value %} - {% endfor %} - {% endif %} - }{% newline %} - {% endfor %} -{% endfunc %} - -{% endstripspace %} diff --git a/app/vlselect/logsql/query_response.qtpl.go b/app/vlselect/logsql/query_response.qtpl.go deleted file mode 100644 index 232755ddaf..0000000000 --- a/app/vlselect/logsql/query_response.qtpl.go +++ /dev/null @@ -1,201 +0,0 @@ -// Code generated by qtc from "query_response.qtpl". DO NOT EDIT. -// See https://github.com/valyala/quicktemplate for details. - -//line app/vlselect/logsql/query_response.qtpl:1 -package logsql - -//line app/vlselect/logsql/query_response.qtpl:1 -import ( - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage" -) - -// JSONRow creates JSON row from the given fields. - -//line app/vlselect/logsql/query_response.qtpl:8 -import ( - qtio422016 "io" - - qt422016 "github.com/valyala/quicktemplate" -) - -//line app/vlselect/logsql/query_response.qtpl:8 -var ( - _ = qtio422016.Copy - _ = qt422016.AcquireByteBuffer -) - -//line app/vlselect/logsql/query_response.qtpl:8 -func StreamJSONRow(qw422016 *qt422016.Writer, columns []logstorage.BlockColumn, rowIdx int) { -//line app/vlselect/logsql/query_response.qtpl:10 - i := 0 - for i < len(columns) && columns[i].Values[rowIdx] == "" { - i++ - } - columns = columns[i:] - -//line app/vlselect/logsql/query_response.qtpl:16 - if len(columns) == 0 { -//line app/vlselect/logsql/query_response.qtpl:17 - return -//line app/vlselect/logsql/query_response.qtpl:18 - } -//line app/vlselect/logsql/query_response.qtpl:18 - qw422016.N().S(`{`) -//line app/vlselect/logsql/query_response.qtpl:20 - c := &columns[0] - -//line app/vlselect/logsql/query_response.qtpl:21 - qw422016.N().Q(c.Name) -//line app/vlselect/logsql/query_response.qtpl:21 - qw422016.N().S(`:`) -//line app/vlselect/logsql/query_response.qtpl:21 - qw422016.N().Q(c.Values[rowIdx]) -//line app/vlselect/logsql/query_response.qtpl:22 - columns = columns[1:] - -//line app/vlselect/logsql/query_response.qtpl:23 - for colIdx := range columns { -//line app/vlselect/logsql/query_response.qtpl:25 - c := &columns[colIdx] - v := c.Values[rowIdx] - -//line app/vlselect/logsql/query_response.qtpl:28 - if v == "" { -//line app/vlselect/logsql/query_response.qtpl:29 - continue -//line app/vlselect/logsql/query_response.qtpl:30 - } -//line app/vlselect/logsql/query_response.qtpl:30 - qw422016.N().S(`,`) -//line app/vlselect/logsql/query_response.qtpl:31 - qw422016.N().Q(c.Name) -//line app/vlselect/logsql/query_response.qtpl:31 - qw422016.N().S(`:`) -//line app/vlselect/logsql/query_response.qtpl:31 - qw422016.N().Q(c.Values[rowIdx]) -//line app/vlselect/logsql/query_response.qtpl:32 - } -//line app/vlselect/logsql/query_response.qtpl:32 - qw422016.N().S(`}`) -//line app/vlselect/logsql/query_response.qtpl:33 - qw422016.N().S(` -`) -//line app/vlselect/logsql/query_response.qtpl:34 -} - -//line app/vlselect/logsql/query_response.qtpl:34 -func WriteJSONRow(qq422016 qtio422016.Writer, columns []logstorage.BlockColumn, rowIdx int) { -//line app/vlselect/logsql/query_response.qtpl:34 - qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vlselect/logsql/query_response.qtpl:34 - StreamJSONRow(qw422016, columns, rowIdx) -//line app/vlselect/logsql/query_response.qtpl:34 - qt422016.ReleaseWriter(qw422016) -//line app/vlselect/logsql/query_response.qtpl:34 -} - -//line app/vlselect/logsql/query_response.qtpl:34 -func JSONRow(columns []logstorage.BlockColumn, rowIdx int) string { -//line app/vlselect/logsql/query_response.qtpl:34 - qb422016 := qt422016.AcquireByteBuffer() -//line app/vlselect/logsql/query_response.qtpl:34 - WriteJSONRow(qb422016, columns, rowIdx) -//line app/vlselect/logsql/query_response.qtpl:34 - qs422016 := string(qb422016.B) -//line app/vlselect/logsql/query_response.qtpl:34 - qt422016.ReleaseByteBuffer(qb422016) -//line app/vlselect/logsql/query_response.qtpl:34 - return qs422016 -//line app/vlselect/logsql/query_response.qtpl:34 -} - -// JSONRows prints formatted rows - -//line app/vlselect/logsql/query_response.qtpl:37 -func StreamJSONRows(qw422016 *qt422016.Writer, rows [][]logstorage.Field) { -//line app/vlselect/logsql/query_response.qtpl:38 - if len(rows) == 0 { -//line app/vlselect/logsql/query_response.qtpl:39 - return -//line app/vlselect/logsql/query_response.qtpl:40 - } -//line app/vlselect/logsql/query_response.qtpl:41 - for _, fields := range rows { -//line app/vlselect/logsql/query_response.qtpl:42 - fields = logstorage.SkipLeadingFieldsWithoutValues(fields) - -//line app/vlselect/logsql/query_response.qtpl:43 - if len(fields) == 0 { -//line app/vlselect/logsql/query_response.qtpl:44 - continue -//line app/vlselect/logsql/query_response.qtpl:45 - } -//line app/vlselect/logsql/query_response.qtpl:45 - qw422016.N().S(`{`) -//line app/vlselect/logsql/query_response.qtpl:47 - if len(fields) > 0 { -//line app/vlselect/logsql/query_response.qtpl:49 - f := fields[0] - fields = fields[1:] - -//line app/vlselect/logsql/query_response.qtpl:52 - qw422016.N().Q(f.Name) -//line app/vlselect/logsql/query_response.qtpl:52 - qw422016.N().S(`:`) -//line app/vlselect/logsql/query_response.qtpl:52 - qw422016.N().Q(f.Value) -//line app/vlselect/logsql/query_response.qtpl:53 - for _, f := range fields { -//line app/vlselect/logsql/query_response.qtpl:54 - if f.Value == "" { -//line app/vlselect/logsql/query_response.qtpl:55 - continue -//line app/vlselect/logsql/query_response.qtpl:56 - } -//line app/vlselect/logsql/query_response.qtpl:56 - qw422016.N().S(`,`) -//line app/vlselect/logsql/query_response.qtpl:57 - qw422016.N().Q(f.Name) -//line app/vlselect/logsql/query_response.qtpl:57 - qw422016.N().S(`:`) -//line app/vlselect/logsql/query_response.qtpl:57 - qw422016.N().Q(f.Value) -//line app/vlselect/logsql/query_response.qtpl:58 - } -//line app/vlselect/logsql/query_response.qtpl:59 - } -//line app/vlselect/logsql/query_response.qtpl:59 - qw422016.N().S(`}`) -//line app/vlselect/logsql/query_response.qtpl:60 - qw422016.N().S(` -`) -//line app/vlselect/logsql/query_response.qtpl:61 - } -//line app/vlselect/logsql/query_response.qtpl:62 -} - -//line app/vlselect/logsql/query_response.qtpl:62 -func WriteJSONRows(qq422016 qtio422016.Writer, rows [][]logstorage.Field) { -//line app/vlselect/logsql/query_response.qtpl:62 - qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vlselect/logsql/query_response.qtpl:62 - StreamJSONRows(qw422016, rows) -//line app/vlselect/logsql/query_response.qtpl:62 - qt422016.ReleaseWriter(qw422016) -//line app/vlselect/logsql/query_response.qtpl:62 -} - -//line app/vlselect/logsql/query_response.qtpl:62 -func JSONRows(rows [][]logstorage.Field) string { -//line app/vlselect/logsql/query_response.qtpl:62 - qb422016 := qt422016.AcquireByteBuffer() -//line app/vlselect/logsql/query_response.qtpl:62 - WriteJSONRows(qb422016, rows) -//line app/vlselect/logsql/query_response.qtpl:62 - qs422016 := string(qb422016.B) -//line app/vlselect/logsql/query_response.qtpl:62 - qt422016.ReleaseByteBuffer(qb422016) -//line app/vlselect/logsql/query_response.qtpl:62 - return qs422016 -//line app/vlselect/logsql/query_response.qtpl:62 -} diff --git a/app/vlselect/logsql/stats_query_range_response.qtpl b/app/vlselect/logsql/stats_query_range_response.qtpl deleted file mode 100644 index 2c71233f05..0000000000 --- a/app/vlselect/logsql/stats_query_range_response.qtpl +++ /dev/null @@ -1,52 +0,0 @@ -{% stripspace %} - -// StatsQueryRangeResponse generates response for /select/logsql/stats_query_range -{% func StatsQueryRangeResponse(rows []*statsSeries) %} -{ - "status":"success", - "data":{ - "resultType":"matrix", - "result":[ - {% if len(rows) > 0 %} - {%= formatStatsSeries(rows[0]) %} - {% code rows = rows[1:] %} - {% for i := range rows %} - ,{%= formatStatsSeries(rows[i]) %} - {% endfor %} - {% endif %} - ] - } -} -{% endfunc %} - -{% func formatStatsSeries(ss *statsSeries) %} -{ - "metric":{ - "__name__":{%q= ss.Name %} - {% if len(ss.Labels) > 0 %} - {% for _, label := range ss.Labels %} - ,{%q= label.Name %}:{%q= label.Value %} - {% endfor %} - {% endif %} - }, - "values":[ - {% code points := ss.Points %} - {% if len(points) > 0 %} - {%= formatStatsPoint(&points[0]) %} - {% code points = points[1:] %} - {% for i := range points %} - ,{%= formatStatsPoint(&points[i]) %} - {% endfor %} - {% endif %} - ] -} -{% endfunc %} - -{% func formatStatsPoint(p *statsPoint) %} -[ - {%f= float64(p.Timestamp)/1e9 %}, - {%q= p.Value %} -] -{% endfunc %} - -{% endstripspace %} diff --git a/app/vlselect/logsql/stats_query_range_response.qtpl.go b/app/vlselect/logsql/stats_query_range_response.qtpl.go deleted file mode 100644 index ac8afd72f4..0000000000 --- a/app/vlselect/logsql/stats_query_range_response.qtpl.go +++ /dev/null @@ -1,188 +0,0 @@ -// Code generated by qtc from "stats_query_range_response.qtpl". DO NOT EDIT. -// See https://github.com/valyala/quicktemplate for details. - -// StatsQueryRangeResponse generates response for /select/logsql/stats_query_range - -//line app/vlselect/logsql/stats_query_range_response.qtpl:4 -package logsql - -//line app/vlselect/logsql/stats_query_range_response.qtpl:4 -import ( - qtio422016 "io" - - qt422016 "github.com/valyala/quicktemplate" -) - -//line app/vlselect/logsql/stats_query_range_response.qtpl:4 -var ( - _ = qtio422016.Copy - _ = qt422016.AcquireByteBuffer -) - -//line app/vlselect/logsql/stats_query_range_response.qtpl:4 -func StreamStatsQueryRangeResponse(qw422016 *qt422016.Writer, rows []*statsSeries) { -//line app/vlselect/logsql/stats_query_range_response.qtpl:4 - qw422016.N().S(`{"status":"success","data":{"resultType":"matrix","result":[`) -//line app/vlselect/logsql/stats_query_range_response.qtpl:10 - if len(rows) > 0 { -//line app/vlselect/logsql/stats_query_range_response.qtpl:11 - streamformatStatsSeries(qw422016, rows[0]) -//line app/vlselect/logsql/stats_query_range_response.qtpl:12 - rows = rows[1:] - -//line app/vlselect/logsql/stats_query_range_response.qtpl:13 - for i := range rows { -//line app/vlselect/logsql/stats_query_range_response.qtpl:13 - qw422016.N().S(`,`) -//line app/vlselect/logsql/stats_query_range_response.qtpl:14 - streamformatStatsSeries(qw422016, rows[i]) -//line app/vlselect/logsql/stats_query_range_response.qtpl:15 - } -//line app/vlselect/logsql/stats_query_range_response.qtpl:16 - } -//line app/vlselect/logsql/stats_query_range_response.qtpl:16 - qw422016.N().S(`]}}`) -//line app/vlselect/logsql/stats_query_range_response.qtpl:20 -} - -//line app/vlselect/logsql/stats_query_range_response.qtpl:20 -func WriteStatsQueryRangeResponse(qq422016 qtio422016.Writer, rows []*statsSeries) { -//line app/vlselect/logsql/stats_query_range_response.qtpl:20 - qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vlselect/logsql/stats_query_range_response.qtpl:20 - StreamStatsQueryRangeResponse(qw422016, rows) -//line app/vlselect/logsql/stats_query_range_response.qtpl:20 - qt422016.ReleaseWriter(qw422016) -//line app/vlselect/logsql/stats_query_range_response.qtpl:20 -} - -//line app/vlselect/logsql/stats_query_range_response.qtpl:20 -func StatsQueryRangeResponse(rows []*statsSeries) string { -//line app/vlselect/logsql/stats_query_range_response.qtpl:20 - qb422016 := qt422016.AcquireByteBuffer() -//line app/vlselect/logsql/stats_query_range_response.qtpl:20 - WriteStatsQueryRangeResponse(qb422016, rows) -//line app/vlselect/logsql/stats_query_range_response.qtpl:20 - qs422016 := string(qb422016.B) -//line app/vlselect/logsql/stats_query_range_response.qtpl:20 - qt422016.ReleaseByteBuffer(qb422016) -//line app/vlselect/logsql/stats_query_range_response.qtpl:20 - return qs422016 -//line app/vlselect/logsql/stats_query_range_response.qtpl:20 -} - -//line app/vlselect/logsql/stats_query_range_response.qtpl:22 -func streamformatStatsSeries(qw422016 *qt422016.Writer, ss *statsSeries) { -//line app/vlselect/logsql/stats_query_range_response.qtpl:22 - qw422016.N().S(`{"metric":{"__name__":`) -//line app/vlselect/logsql/stats_query_range_response.qtpl:25 - qw422016.N().Q(ss.Name) -//line app/vlselect/logsql/stats_query_range_response.qtpl:26 - if len(ss.Labels) > 0 { -//line app/vlselect/logsql/stats_query_range_response.qtpl:27 - for _, label := range ss.Labels { -//line app/vlselect/logsql/stats_query_range_response.qtpl:27 - qw422016.N().S(`,`) -//line app/vlselect/logsql/stats_query_range_response.qtpl:28 - qw422016.N().Q(label.Name) -//line app/vlselect/logsql/stats_query_range_response.qtpl:28 - qw422016.N().S(`:`) -//line app/vlselect/logsql/stats_query_range_response.qtpl:28 - qw422016.N().Q(label.Value) -//line app/vlselect/logsql/stats_query_range_response.qtpl:29 - } -//line app/vlselect/logsql/stats_query_range_response.qtpl:30 - } -//line app/vlselect/logsql/stats_query_range_response.qtpl:30 - qw422016.N().S(`},"values":[`) -//line app/vlselect/logsql/stats_query_range_response.qtpl:33 - points := ss.Points - -//line app/vlselect/logsql/stats_query_range_response.qtpl:34 - if len(points) > 0 { -//line app/vlselect/logsql/stats_query_range_response.qtpl:35 - streamformatStatsPoint(qw422016, &points[0]) -//line app/vlselect/logsql/stats_query_range_response.qtpl:36 - points = points[1:] - -//line app/vlselect/logsql/stats_query_range_response.qtpl:37 - for i := range points { -//line app/vlselect/logsql/stats_query_range_response.qtpl:37 - qw422016.N().S(`,`) -//line app/vlselect/logsql/stats_query_range_response.qtpl:38 - streamformatStatsPoint(qw422016, &points[i]) -//line app/vlselect/logsql/stats_query_range_response.qtpl:39 - } -//line app/vlselect/logsql/stats_query_range_response.qtpl:40 - } -//line app/vlselect/logsql/stats_query_range_response.qtpl:40 - qw422016.N().S(`]}`) -//line app/vlselect/logsql/stats_query_range_response.qtpl:43 -} - -//line app/vlselect/logsql/stats_query_range_response.qtpl:43 -func writeformatStatsSeries(qq422016 qtio422016.Writer, ss *statsSeries) { -//line app/vlselect/logsql/stats_query_range_response.qtpl:43 - qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vlselect/logsql/stats_query_range_response.qtpl:43 - streamformatStatsSeries(qw422016, ss) -//line app/vlselect/logsql/stats_query_range_response.qtpl:43 - qt422016.ReleaseWriter(qw422016) -//line app/vlselect/logsql/stats_query_range_response.qtpl:43 -} - -//line app/vlselect/logsql/stats_query_range_response.qtpl:43 -func formatStatsSeries(ss *statsSeries) string { -//line app/vlselect/logsql/stats_query_range_response.qtpl:43 - qb422016 := qt422016.AcquireByteBuffer() -//line app/vlselect/logsql/stats_query_range_response.qtpl:43 - writeformatStatsSeries(qb422016, ss) -//line app/vlselect/logsql/stats_query_range_response.qtpl:43 - qs422016 := string(qb422016.B) -//line app/vlselect/logsql/stats_query_range_response.qtpl:43 - qt422016.ReleaseByteBuffer(qb422016) -//line app/vlselect/logsql/stats_query_range_response.qtpl:43 - return qs422016 -//line app/vlselect/logsql/stats_query_range_response.qtpl:43 -} - -//line app/vlselect/logsql/stats_query_range_response.qtpl:45 -func streamformatStatsPoint(qw422016 *qt422016.Writer, p *statsPoint) { -//line app/vlselect/logsql/stats_query_range_response.qtpl:45 - qw422016.N().S(`[`) -//line app/vlselect/logsql/stats_query_range_response.qtpl:47 - qw422016.N().F(float64(p.Timestamp) / 1e9) -//line app/vlselect/logsql/stats_query_range_response.qtpl:47 - qw422016.N().S(`,`) -//line app/vlselect/logsql/stats_query_range_response.qtpl:48 - qw422016.N().Q(p.Value) -//line app/vlselect/logsql/stats_query_range_response.qtpl:48 - qw422016.N().S(`]`) -//line app/vlselect/logsql/stats_query_range_response.qtpl:50 -} - -//line app/vlselect/logsql/stats_query_range_response.qtpl:50 -func writeformatStatsPoint(qq422016 qtio422016.Writer, p *statsPoint) { -//line app/vlselect/logsql/stats_query_range_response.qtpl:50 - qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vlselect/logsql/stats_query_range_response.qtpl:50 - streamformatStatsPoint(qw422016, p) -//line app/vlselect/logsql/stats_query_range_response.qtpl:50 - qt422016.ReleaseWriter(qw422016) -//line app/vlselect/logsql/stats_query_range_response.qtpl:50 -} - -//line app/vlselect/logsql/stats_query_range_response.qtpl:50 -func formatStatsPoint(p *statsPoint) string { -//line app/vlselect/logsql/stats_query_range_response.qtpl:50 - qb422016 := qt422016.AcquireByteBuffer() -//line app/vlselect/logsql/stats_query_range_response.qtpl:50 - writeformatStatsPoint(qb422016, p) -//line app/vlselect/logsql/stats_query_range_response.qtpl:50 - qs422016 := string(qb422016.B) -//line app/vlselect/logsql/stats_query_range_response.qtpl:50 - qt422016.ReleaseByteBuffer(qb422016) -//line app/vlselect/logsql/stats_query_range_response.qtpl:50 - return qs422016 -//line app/vlselect/logsql/stats_query_range_response.qtpl:50 -} diff --git a/app/vlselect/logsql/stats_query_response.qtpl b/app/vlselect/logsql/stats_query_response.qtpl deleted file mode 100644 index 3d818546bf..0000000000 --- a/app/vlselect/logsql/stats_query_response.qtpl +++ /dev/null @@ -1,36 +0,0 @@ -{% stripspace %} - -// StatsQueryResponse generates response for /select/logsql/stats_query -{% func StatsQueryResponse(rows []statsRow) %} -{ - "status":"success", - "data":{ - "resultType":"vector", - "result":[ - {% if len(rows) > 0 %} - {%= formatStatsRow(&rows[0]) %} - {% code rows = rows[1:] %} - {% for i := range rows %} - ,{%= formatStatsRow(&rows[i]) %} - {% endfor %} - {% endif %} - ] - } -} -{% endfunc %} - -{% func formatStatsRow(r *statsRow) %} -{ - "metric":{ - "__name__":{%q= r.Name %} - {% if len(r.Labels) > 0 %} - {% for _, label := range r.Labels %} - ,{%q= label.Name %}:{%q= label.Value %} - {% endfor %} - {% endif %} - }, - "value":[{%f= float64(r.Timestamp)/1e9 %},{%q= r.Value %}] -} -{% endfunc %} - -{% endstripspace %} diff --git a/app/vlselect/logsql/stats_query_response.qtpl.go b/app/vlselect/logsql/stats_query_response.qtpl.go deleted file mode 100644 index 2548a18c39..0000000000 --- a/app/vlselect/logsql/stats_query_response.qtpl.go +++ /dev/null @@ -1,133 +0,0 @@ -// Code generated by qtc from "stats_query_response.qtpl". DO NOT EDIT. -// See https://github.com/valyala/quicktemplate for details. - -// StatsQueryResponse generates response for /select/logsql/stats_query - -//line app/vlselect/logsql/stats_query_response.qtpl:4 -package logsql - -//line app/vlselect/logsql/stats_query_response.qtpl:4 -import ( - qtio422016 "io" - - qt422016 "github.com/valyala/quicktemplate" -) - -//line app/vlselect/logsql/stats_query_response.qtpl:4 -var ( - _ = qtio422016.Copy - _ = qt422016.AcquireByteBuffer -) - -//line app/vlselect/logsql/stats_query_response.qtpl:4 -func StreamStatsQueryResponse(qw422016 *qt422016.Writer, rows []statsRow) { -//line app/vlselect/logsql/stats_query_response.qtpl:4 - qw422016.N().S(`{"status":"success","data":{"resultType":"vector","result":[`) -//line app/vlselect/logsql/stats_query_response.qtpl:10 - if len(rows) > 0 { -//line app/vlselect/logsql/stats_query_response.qtpl:11 - streamformatStatsRow(qw422016, &rows[0]) -//line app/vlselect/logsql/stats_query_response.qtpl:12 - rows = rows[1:] - -//line app/vlselect/logsql/stats_query_response.qtpl:13 - for i := range rows { -//line app/vlselect/logsql/stats_query_response.qtpl:13 - qw422016.N().S(`,`) -//line app/vlselect/logsql/stats_query_response.qtpl:14 - streamformatStatsRow(qw422016, &rows[i]) -//line app/vlselect/logsql/stats_query_response.qtpl:15 - } -//line app/vlselect/logsql/stats_query_response.qtpl:16 - } -//line app/vlselect/logsql/stats_query_response.qtpl:16 - qw422016.N().S(`]}}`) -//line app/vlselect/logsql/stats_query_response.qtpl:20 -} - -//line app/vlselect/logsql/stats_query_response.qtpl:20 -func WriteStatsQueryResponse(qq422016 qtio422016.Writer, rows []statsRow) { -//line app/vlselect/logsql/stats_query_response.qtpl:20 - qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vlselect/logsql/stats_query_response.qtpl:20 - StreamStatsQueryResponse(qw422016, rows) -//line app/vlselect/logsql/stats_query_response.qtpl:20 - qt422016.ReleaseWriter(qw422016) -//line app/vlselect/logsql/stats_query_response.qtpl:20 -} - -//line app/vlselect/logsql/stats_query_response.qtpl:20 -func StatsQueryResponse(rows []statsRow) string { -//line app/vlselect/logsql/stats_query_response.qtpl:20 - qb422016 := qt422016.AcquireByteBuffer() -//line app/vlselect/logsql/stats_query_response.qtpl:20 - WriteStatsQueryResponse(qb422016, rows) -//line app/vlselect/logsql/stats_query_response.qtpl:20 - qs422016 := string(qb422016.B) -//line app/vlselect/logsql/stats_query_response.qtpl:20 - qt422016.ReleaseByteBuffer(qb422016) -//line app/vlselect/logsql/stats_query_response.qtpl:20 - return qs422016 -//line app/vlselect/logsql/stats_query_response.qtpl:20 -} - -//line app/vlselect/logsql/stats_query_response.qtpl:22 -func streamformatStatsRow(qw422016 *qt422016.Writer, r *statsRow) { -//line app/vlselect/logsql/stats_query_response.qtpl:22 - qw422016.N().S(`{"metric":{"__name__":`) -//line app/vlselect/logsql/stats_query_response.qtpl:25 - qw422016.N().Q(r.Name) -//line app/vlselect/logsql/stats_query_response.qtpl:26 - if len(r.Labels) > 0 { -//line app/vlselect/logsql/stats_query_response.qtpl:27 - for _, label := range r.Labels { -//line app/vlselect/logsql/stats_query_response.qtpl:27 - qw422016.N().S(`,`) -//line app/vlselect/logsql/stats_query_response.qtpl:28 - qw422016.N().Q(label.Name) -//line app/vlselect/logsql/stats_query_response.qtpl:28 - qw422016.N().S(`:`) -//line app/vlselect/logsql/stats_query_response.qtpl:28 - qw422016.N().Q(label.Value) -//line app/vlselect/logsql/stats_query_response.qtpl:29 - } -//line app/vlselect/logsql/stats_query_response.qtpl:30 - } -//line app/vlselect/logsql/stats_query_response.qtpl:30 - qw422016.N().S(`},"value":[`) -//line app/vlselect/logsql/stats_query_response.qtpl:32 - qw422016.N().F(float64(r.Timestamp) / 1e9) -//line app/vlselect/logsql/stats_query_response.qtpl:32 - qw422016.N().S(`,`) -//line app/vlselect/logsql/stats_query_response.qtpl:32 - qw422016.N().Q(r.Value) -//line app/vlselect/logsql/stats_query_response.qtpl:32 - qw422016.N().S(`]}`) -//line app/vlselect/logsql/stats_query_response.qtpl:34 -} - -//line app/vlselect/logsql/stats_query_response.qtpl:34 -func writeformatStatsRow(qq422016 qtio422016.Writer, r *statsRow) { -//line app/vlselect/logsql/stats_query_response.qtpl:34 - qw422016 := qt422016.AcquireWriter(qq422016) -//line app/vlselect/logsql/stats_query_response.qtpl:34 - streamformatStatsRow(qw422016, r) -//line app/vlselect/logsql/stats_query_response.qtpl:34 - qt422016.ReleaseWriter(qw422016) -//line app/vlselect/logsql/stats_query_response.qtpl:34 -} - -//line app/vlselect/logsql/stats_query_response.qtpl:34 -func formatStatsRow(r *statsRow) string { -//line app/vlselect/logsql/stats_query_response.qtpl:34 - qb422016 := qt422016.AcquireByteBuffer() -//line app/vlselect/logsql/stats_query_response.qtpl:34 - writeformatStatsRow(qb422016, r) -//line app/vlselect/logsql/stats_query_response.qtpl:34 - qs422016 := string(qb422016.B) -//line app/vlselect/logsql/stats_query_response.qtpl:34 - qt422016.ReleaseByteBuffer(qb422016) -//line app/vlselect/logsql/stats_query_response.qtpl:34 - return qs422016 -//line app/vlselect/logsql/stats_query_response.qtpl:34 -} diff --git a/app/vlselect/main.go b/app/vlselect/main.go deleted file mode 100644 index e9c8805993..0000000000 --- a/app/vlselect/main.go +++ /dev/null @@ -1,324 +0,0 @@ -package vlselect - -import ( - "context" - "embed" - "flag" - "fmt" - "net/http" - "strings" - "time" - - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlselect/internalselect" - "github.com/VictoriaMetrics/VictoriaMetrics/app/vlselect/logsql" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/cgroup" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/httputil" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" - "github.com/VictoriaMetrics/metrics" -) - -var ( - maxConcurrentRequests = flag.Int("search.maxConcurrentRequests", getDefaultMaxConcurrentRequests(), "The maximum number of concurrent search requests. "+ - "It shouldn't be high, since a single request can saturate all the CPU cores, while many concurrently executed requests may require high amounts of memory. "+ - "See also -search.maxQueueDuration") - maxQueueDuration = flag.Duration("search.maxQueueDuration", 10*time.Second, "The maximum time the search request waits for execution when -search.maxConcurrentRequests "+ - "limit is reached; see also -search.maxQueryDuration") - maxQueryDuration = flag.Duration("search.maxQueryDuration", time.Second*30, "The maximum duration for query execution. It can be overridden to a smaller value on a per-query basis via 'timeout' query arg") - - disableSelect = flag.Bool("select.disable", false, "Whether to disable /select/* HTTP endpoints") - disableInternal = flag.Bool("internalselect.disable", false, "Whether to disable /internal/select/* HTTP endpoints") -) - -func getDefaultMaxConcurrentRequests() int { - n := cgroup.AvailableCPUs() - if n <= 4 { - n *= 2 - } - if n > 16 { - // A single request can saturate all the CPU cores, so there is no sense - // in allowing higher number of concurrent requests - they will just contend - // for unavailable CPU time. - n = 16 - } - return n -} - -// Init initializes vlselect -func Init() { - concurrencyLimitCh = make(chan struct{}, *maxConcurrentRequests) -} - -// Stop stops vlselect -func Stop() { -} - -var concurrencyLimitCh chan struct{} - -var ( - concurrencyLimitReached = metrics.NewCounter(`vl_concurrent_select_limit_reached_total`) - concurrencyLimitTimeout = metrics.NewCounter(`vl_concurrent_select_limit_timeout_total`) - - _ = metrics.NewGauge(`vl_concurrent_select_capacity`, func() float64 { - return float64(cap(concurrencyLimitCh)) - }) - _ = metrics.NewGauge(`vl_concurrent_select_current`, func() float64 { - return float64(len(concurrencyLimitCh)) - }) -) - -//go:embed vmui -var vmuiFiles embed.FS - -var vmuiFileServer = http.FileServer(http.FS(vmuiFiles)) - -// RequestHandler handles select requests for VictoriaLogs -func RequestHandler(w http.ResponseWriter, r *http.Request) bool { - path := strings.ReplaceAll(r.URL.Path, "//", "/") - - if strings.HasPrefix(path, "/select/") { - if *disableSelect { - httpserver.Errorf(w, r, "requests to /select/* are disabled with -select.disable command-line flag") - return true - } - - return selectHandler(w, r, path) - } - - if strings.HasPrefix(path, "/internal/select/") { - if *disableInternal || *disableSelect { - httpserver.Errorf(w, r, "requests to /internal/select/* are disabled with -internalselect.disable or -select.disable command-line flag") - return true - } - internalselect.RequestHandler(r.Context(), w, r) - return true - } - - return false -} - -func selectHandler(w http.ResponseWriter, r *http.Request, path string) bool { - ctx := r.Context() - - if path == "/select/vmui" { - // VMUI access via incomplete url without `/` in the end. Redirect to complete url. - // Use relative redirect, since the hostname and path prefix may be incorrect if VictoriaMetrics - // is hidden behind vmauth or similar proxy. - _ = r.ParseForm() - newURL := "vmui/?" + r.Form.Encode() - httpserver.Redirect(w, newURL) - return true - } - if strings.HasPrefix(path, "/select/vmui/") { - if strings.HasPrefix(path, "/select/vmui/static/") { - // Allow clients caching static contents for long period of time, since it shouldn't change over time. - // Path to static contents (such as js and css) must be changed whenever its contents is changed. - // See https://developer.chrome.com/docs/lighthouse/performance/uses-long-cache-ttl/ - w.Header().Set("Cache-Control", "max-age=31536000") - } - r.URL.Path = strings.TrimPrefix(path, "/select") - vmuiFileServer.ServeHTTP(w, r) - return true - } - - if path == "/select/logsql/tail" { - logsqlTailRequests.Inc() - // Process live tailing request without timeout, since it is OK to run live tailing requests for very long time. - // Also do not apply concurrency limit to tail requests, since these limits are intended for non-tail requests. - logsql.ProcessLiveTailRequest(ctx, w, r) - return true - } - - // Limit the number of concurrent queries, which can consume big amounts of CPU time. - startTime := time.Now() - d := getMaxQueryDuration(r) - ctxWithTimeout, cancel := context.WithTimeout(ctx, d) - defer cancel() - - if !incRequestConcurrency(ctxWithTimeout, w, r) { - return true - } - defer decRequestConcurrency() - - ok := processSelectRequest(ctxWithTimeout, w, r, path) - if !ok { - return false - } - - logRequestErrorIfNeeded(ctxWithTimeout, w, r, startTime) - return true -} - -func logRequestErrorIfNeeded(ctx context.Context, w http.ResponseWriter, r *http.Request, startTime time.Time) { - err := ctx.Err() - switch err { - case nil: - // nothing to do - case context.Canceled: - // do not log canceled requests, since they are expected and legal. - case context.DeadlineExceeded: - err = &httpserver.ErrorWithStatusCode{ - Err: fmt.Errorf("the request couldn't be executed in %.3f seconds; possible solutions: "+ - "to increase -search.maxQueryDuration=%s; to pass bigger value to 'timeout' query arg", time.Since(startTime).Seconds(), maxQueryDuration), - StatusCode: http.StatusServiceUnavailable, - } - httpserver.Errorf(w, r, "%s", err) - default: - httpserver.Errorf(w, r, "unexpected error: %s", err) - } -} - -func incRequestConcurrency(ctx context.Context, w http.ResponseWriter, r *http.Request) bool { - startTime := time.Now() - stopCh := ctx.Done() - select { - case concurrencyLimitCh <- struct{}{}: - return true - default: - // Sleep for a while until giving up. This should resolve short bursts in requests. - concurrencyLimitReached.Inc() - select { - case concurrencyLimitCh <- struct{}{}: - return true - case <-stopCh: - switch ctx.Err() { - case context.Canceled: - remoteAddr := httpserver.GetQuotedRemoteAddr(r) - requestURI := httpserver.GetRequestURI(r) - logger.Infof("client has canceled the pending request after %.3f seconds: remoteAddr=%s, requestURI: %q", - time.Since(startTime).Seconds(), remoteAddr, requestURI) - case context.DeadlineExceeded: - concurrencyLimitTimeout.Inc() - err := &httpserver.ErrorWithStatusCode{ - Err: fmt.Errorf("couldn't start executing the request in %.3f seconds, since -search.maxConcurrentRequests=%d concurrent requests "+ - "are executed. Possible solutions: to reduce query load; to add more compute resources to the server; "+ - "to increase -search.maxQueueDuration=%s; to increase -search.maxQueryDuration=%s; to increase -search.maxConcurrentRequests; "+ - "to pass bigger value to 'timeout' query arg", - time.Since(startTime).Seconds(), *maxConcurrentRequests, maxQueueDuration, maxQueryDuration), - StatusCode: http.StatusServiceUnavailable, - } - httpserver.Errorf(w, r, "%s", err) - } - return false - } - } -} - -func decRequestConcurrency() { - <-concurrencyLimitCh -} - -func processSelectRequest(ctx context.Context, w http.ResponseWriter, r *http.Request, path string) bool { - httpserver.EnableCORS(w, r) - startTime := time.Now() - switch path { - case "/select/logsql/facets": - logsqlFacetsRequests.Inc() - logsql.ProcessFacetsRequest(ctx, w, r) - logsqlFacetsDuration.UpdateDuration(startTime) - return true - case "/select/logsql/field_names": - logsqlFieldNamesRequests.Inc() - logsql.ProcessFieldNamesRequest(ctx, w, r) - logsqlFieldNamesDuration.UpdateDuration(startTime) - return true - case "/select/logsql/field_values": - logsqlFieldValuesRequests.Inc() - logsql.ProcessFieldValuesRequest(ctx, w, r) - logsqlFieldValuesDuration.UpdateDuration(startTime) - return true - case "/select/logsql/hits": - logsqlHitsRequests.Inc() - logsql.ProcessHitsRequest(ctx, w, r) - logsqlHitsDuration.UpdateDuration(startTime) - return true - case "/select/logsql/query": - logsqlQueryRequests.Inc() - logsql.ProcessQueryRequest(ctx, w, r) - logsqlQueryDuration.UpdateDuration(startTime) - return true - case "/select/logsql/stats_query": - logsqlStatsQueryRequests.Inc() - logsql.ProcessStatsQueryRequest(ctx, w, r) - logsqlStatsQueryDuration.UpdateDuration(startTime) - return true - case "/select/logsql/stats_query_range": - logsqlStatsQueryRangeRequests.Inc() - logsql.ProcessStatsQueryRangeRequest(ctx, w, r) - logsqlStatsQueryRangeDuration.UpdateDuration(startTime) - return true - case "/select/logsql/stream_field_names": - logsqlStreamFieldNamesRequests.Inc() - logsql.ProcessStreamFieldNamesRequest(ctx, w, r) - logsqlStreamFieldNamesDuration.UpdateDuration(startTime) - return true - case "/select/logsql/stream_field_values": - logsqlStreamFieldValuesRequests.Inc() - logsql.ProcessStreamFieldValuesRequest(ctx, w, r) - logsqlStreamFieldValuesDuration.UpdateDuration(startTime) - return true - case "/select/logsql/stream_ids": - logsqlStreamIDsRequests.Inc() - logsql.ProcessStreamIDsRequest(ctx, w, r) - logsqlStreamIDsDuration.UpdateDuration(startTime) - return true - case "/select/logsql/streams": - logsqlStreamsRequests.Inc() - logsql.ProcessStreamsRequest(ctx, w, r) - logsqlStreamsDuration.UpdateDuration(startTime) - return true - default: - return false - } -} - -// getMaxQueryDuration returns the maximum duration for query from r. -func getMaxQueryDuration(r *http.Request) time.Duration { - dms, err := httputil.GetDuration(r, "timeout", 0) - if err != nil { - dms = 0 - } - d := time.Duration(dms) * time.Millisecond - if d <= 0 || d > *maxQueryDuration { - d = *maxQueryDuration - } - return d -} - -var ( - logsqlFacetsRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/facets"}`) - logsqlFacetsDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/facets"}`) - - logsqlFieldNamesRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/field_names"}`) - logsqlFieldNamesDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/field_names"}`) - - logsqlFieldValuesRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/field_values"}`) - logsqlFieldValuesDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/field_values"}`) - - logsqlHitsRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/hits"}`) - logsqlHitsDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/hits"}`) - - logsqlQueryRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/query"}`) - logsqlQueryDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/query"}`) - - logsqlStatsQueryRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/stats_query"}`) - logsqlStatsQueryDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/stats_query"}`) - - logsqlStatsQueryRangeRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/stats_query_range"}`) - logsqlStatsQueryRangeDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/stats_query_range"}`) - - logsqlStreamFieldNamesRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/stream_field_names"}`) - logsqlStreamFieldNamesDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/stream_field_names"}`) - - logsqlStreamFieldValuesRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/stream_field_values"}`) - logsqlStreamFieldValuesDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/stream_field_values"}`) - - logsqlStreamIDsRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/stream_ids"}`) - logsqlStreamIDsDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/stream_ids"}`) - - logsqlStreamsRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/streams"}`) - logsqlStreamsDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/streams"}`) - - // no need to track duration for tail requests, as they usually take long time - logsqlTailRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/tail"}`) -) diff --git a/app/vlselect/vmui/assets/MetricsQL-Ckl-MH95.md b/app/vlselect/vmui/assets/MetricsQL-Ckl-MH95.md deleted file mode 100644 index 7d6456b09d..0000000000 --- a/app/vlselect/vmui/assets/MetricsQL-Ckl-MH95.md +++ /dev/null @@ -1,2372 +0,0 @@ ---- -weight: 23 -title: MetricsQL -menu: - docs: - parent: 'victoriametrics' - weight: 23 -tags: - - metrics -aliases: -- /ExtendedPromQL.html -- /MetricsQL.html -- /metricsql/index.html -- /metricsql/ ---- -[VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics) implements MetricsQL - -query language inspired by [PromQL](https://prometheus.io/docs/prometheus/latest/querying/basics/). -MetricsQL is backwards-compatible with PromQL, so Grafana dashboards backed by Prometheus datasource should work -the same after switching from Prometheus to VictoriaMetrics. -However, there are some [intentional differences](https://medium.com/@romanhavronenko/victoriametrics-promql-compliance-d4318203f51e) between these two languages. - -[Standalone MetricsQL package](https://godoc.org/github.com/VictoriaMetrics/metricsql) can be used for parsing MetricsQL in external apps. - -If you are unfamiliar with PromQL, then it is suggested reading [this tutorial for beginners](https://medium.com/@valyala/promql-tutorial-for-beginners-9ab455142085) -and introduction into [basic querying via MetricsQL](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#metricsql). - -The following functionality is implemented differently in MetricsQL compared to PromQL. This improves user experience: - -* MetricsQL takes into account the last [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) before the lookbehind window - in square brackets for [increase](#increase) and [rate](#rate) functions. This allows returning the exact results users expect for `increase(metric[$__interval])` queries - instead of incomplete results Prometheus returns for such queries. Prometheus misses the increase between the last sample before the lookbehind window - and the first sample inside the lookbehind window. -* MetricsQL doesn't extrapolate [rate](#rate) and [increase](#increase) function results, so it always returns the expected results. For example, it returns - integer results from `increase()` over slow-changing integer counter. Prometheus in this case returns unexpected fractional results, - which may significantly differ from the expected results. This addresses [this issue from Prometheus](https://github.com/prometheus/prometheus/issues/3746). - See technical details about VictoriaMetrics and Prometheus calculations for [rate](#rate) - and [increase](#increase) [in this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1215#issuecomment-850305711). -* MetricsQL returns the expected non-empty responses for [rate](#rate) function when Grafana or [vmui](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#vmui) - passes `step` values smaller than the interval between [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) - to [/api/v1/query_range](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#range-query). - This addresses [this issue from Grafana](https://github.com/grafana/grafana/issues/11451). - See also [this blog post](https://www.percona.com/blog/2020/02/28/better-prometheus-rate-function-with-victoriametrics/). -* MetricsQL treats `scalar` type the same as `instant vector` without labels, since subtle differences between these types usually confuse users. - See [the corresponding Prometheus docs](https://prometheus.io/docs/prometheus/latest/querying/basics/#expression-language-data-types) for details. -* MetricsQL removes all the `NaN` values from the output, so some queries like `(-1)^0.5` return empty results in VictoriaMetrics, - while returning a series of `NaN` values in Prometheus. Note that Grafana doesn't draw any lines or dots for `NaN` values, - so the end result looks the same for both VictoriaMetrics and Prometheus. -* MetricsQL keeps metric names after applying functions, which don't change the meaning of the original time series. - For example, [min_over_time(foo)](#min_over_time) or [round(foo)](#round) leaves `foo` metric name in the result. - See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/674) for details. - -Read more about the differences between PromQL and MetricsQL in [this article](https://medium.com/@romanhavronenko/victoriametrics-promql-compliance-d4318203f51e). - -Other PromQL functionality should work the same in MetricsQL. -[File an issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues) if you notice discrepancies between PromQL and MetricsQL results other than mentioned above. - -## MetricsQL features - -MetricsQL implements [PromQL](https://medium.com/@valyala/promql-tutorial-for-beginners-9ab455142085) -and provides additional functionality mentioned below, which is aimed towards solving practical cases. -Feel free [filing a feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues) if you think MetricsQL misses certain useful functionality. - -This functionality can be evaluated at [VictoriaMetrics demo playground](https://play.victoriametrics.com/select/accounting/1/6a716b0f-38bc-4856-90ce-448fd713e3fe/prometheus/graph/) -or at your own [VictoriaMetrics instance](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#how-to-start-victoriametrics). - -The list of MetricsQL features on top of PromQL: - -* Graphite-compatible filters can be passed via `{__graphite__="foo.*.bar"}` syntax. - See [these docs](https://docs.victoriametrics.com/victoriametrics/integrations/graphite/#selecting-graphite-metrics). - VictoriaMetrics can be used as Graphite datasource in Grafana. See [these docs](https://docs.victoriametrics.com/victoriametrics/integrations/graphite/#graphite-api-usage) for details. - See also [label_graphite_group](#label_graphite_group) function, which can be used for extracting the given groups from Graphite metric name. -* Lookbehind window in square brackets for [rollup functions](#rollup-functions) may be omitted. VictoriaMetrics automatically selects the lookbehind window - depending on the `step` query arg passed to [/api/v1/query_range](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#range-query) - and the real interval between [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) (aka `scrape_interval`). - For instance, the following query is valid in VictoriaMetrics: `rate(node_network_receive_bytes_total)`. - It is roughly equivalent to `rate(node_network_receive_bytes_total[$__interval])` when used in Grafana. - The difference is documented in [rate() docs](#rate). -* Numeric values can contain `_` delimiters for better readability. For example, `1_234_567_890` can be used in queries instead of `1234567890`. -* [Series selectors](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering) accept multiple `or` filters. For example, `{env="prod",job="a" or env="dev",job="b"}` - selects series with `{env="prod",job="a"}` or `{env="dev",job="b"}` labels. - See [these docs](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering-by-multiple-or-filters) for details. -* Support for matching against multiple numeric constants via `q == (C1, ..., CN)` and `q != (C1, ..., CN)` syntax. For example, `status_code == (300, 301, 304)` - returns `status_code` metrics with one of `300`, `301` or `304` values. -* Support for `group_left(*)` and `group_right(*)` for copying all the labels from time series on the `one` side - of [many-to-one operations](https://prometheus.io/docs/prometheus/latest/querying/operators/#many-to-one-and-one-to-many-vector-matches). - The copied label names may clash with the existing label names, so MetricsQL provides an ability to add prefix to the copied metric names - via `group_left(*) prefix "..."` syntax. - For example, the following query copies all the `namespace`-related labels from `kube_namespace_labels` to `kube_pod_info` series, - while adding `ns_` prefix to the copied labels: `kube_pod_info * on(namespace) group_left(*) prefix "ns_" kube_namespace_labels`. - Labels from the `on()` list aren't copied. -* [Aggregate functions](#aggregate-functions) accept arbitrary number of args. - For example, `avg(q1, q2, q3)` would return the average values for every point across time series returned by `q1`, `q2` and `q3`. -* [@ modifier](https://prometheus.io/docs/prometheus/latest/querying/basics/#modifier) can be put anywhere in the query. - For example, `sum(foo) @ end()` calculates `sum(foo)` at the `end` timestamp of the selected time range `[start ... end]`. -* Arbitrary subexpression can be used as [@ modifier](https://prometheus.io/docs/prometheus/latest/querying/basics/#modifier). - For example, `foo @ (end() - 1h)` calculates `foo` at the `end - 1 hour` timestamp on the selected time range `[start ... end]`. -* [offset](https://prometheus.io/docs/prometheus/latest/querying/basics/#offset-modifier), lookbehind window in square brackets - and `step` value for [subquery](#subqueries) may refer to the current step aka `$__interval` value from Grafana with `[Ni]` syntax. - For instance, `rate(metric[10i] offset 5i)` would return per-second rate over a range covering 10 previous steps with the offset of 5 steps. -* [offset](https://prometheus.io/docs/prometheus/latest/querying/basics/#offset-modifier) may be put anywhere in the query. For instance, `sum(foo) offset 24h`. -* Lookbehind window in square brackets and [offset](https://prometheus.io/docs/prometheus/latest/querying/basics/#offset-modifier) may be fractional. - For instance, `rate(node_network_receive_bytes_total[1.5m] offset 0.5d)`. -* The duration suffix is optional. The duration is in seconds if the suffix is missing. - For example, `rate(m[300] offset 1800)` is equivalent to `rate(m[5m]) offset 30m`. -* The duration can be placed anywhere in the query. For example, `sum_over_time(m[1h]) / 1h` is equivalent to `sum_over_time(m[1h]) / 3600`. -* Numeric values can have `K`, `Ki`, `M`, `Mi`, `G`, `Gi`, `T` and `Ti` suffixes. For example, `8K` is equivalent to `8000`, while `1.2Mi` is equivalent to `1.2*1024*1024`. -* Trailing commas on all the lists are allowed - label filters, function args and with expressions. - For instance, the following queries are valid: `m{foo="bar",}`, `f(a, b,)`, `WITH (x=y,) x`. - This simplifies maintenance of multi-line queries. -* Metric names and label names may contain any unicode letter. For example `ტემპერატურა{πόλη="Київ"}` is a valid MetricsQL expression. -* Metric names and labels names may contain escaped chars. For example, `foo\-bar{baz\=aa="b"}` is valid expression. - It returns time series with name `foo-bar` containing label `baz=aa` with value `b`. - Additionally, the following escape sequences are supported: - - `\xXX`, where `XX` is hexadecimal representation of the escaped ascii char. - - `\uXXXX`, where `XXXX` is a hexadecimal representation of the escaped unicode char. -* Aggregate functions support optional `limit N` suffix in order to limit the number of output series. - For example, `sum(x) by (y) limit 3` limits the number of output time series after the aggregation to 3. - All the other time series are dropped. -* [histogram_quantile](#histogram_quantile) accepts optional third arg - `boundsLabel`. - In this case it returns `lower` and `upper` bounds for the estimated percentile. - See [this issue for details](https://github.com/prometheus/prometheus/issues/5706). -* `default` binary operator. `q1 default q2` fills gaps in `q1` with the corresponding values from `q2`. See also [drop_empty_series](#drop_empty_series). -* `if` binary operator. `q1 if q2` removes values from `q1` for missing values from `q2`. -* `ifnot` binary operator. `q1 ifnot q2` removes values from `q1` for existing values from `q2`. -* `WITH` templates. This feature simplifies writing and managing complex queries. - Go to [WITH templates playground](https://play.victoriametrics.com/select/accounting/1/6a716b0f-38bc-4856-90ce-448fd713e3fe/expand-with-exprs) and try it. -* String literals may be concatenated. This is useful with `WITH` templates: - `WITH (commonPrefix="long_metric_prefix_") {__name__=commonPrefix+"suffix1"} / {__name__=commonPrefix+"suffix2"}`. -* `keep_metric_names` modifier can be applied to all the [rollup functions](#rollup-functions), [transform functions](#transform-functions) - and [binary operators](https://prometheus.io/docs/prometheus/latest/querying/operators/#binary-operators). - This modifier prevents from dropping metric names in function results. See [these docs](#keep_metric_names). - -## keep_metric_names - -By default, metric names are dropped after applying functions or [binary operators](https://prometheus.io/docs/prometheus/latest/querying/operators/#binary-operators), -since they may change the meaning of the original time series. -This may result in `duplicate time series` error when the function is applied to multiple time series with different names. -This error can be fixed by applying `keep_metric_names` modifier to the function or binary operator. - -For example: -- `rate({__name__=~"foo|bar"}) keep_metric_names` leaves `foo` and `bar` metric names in the returned time series. -- `({__name__=~"foo|bar"} / 10) keep_metric_names` leaves `foo` and `bar` metric names in the returned time series. - -## MetricsQL functions - -If you are unfamiliar with PromQL, then please read [this tutorial](https://medium.com/@valyala/promql-tutorial-for-beginners-9ab455142085) at first. - -MetricsQL provides the following functions: - -* [Rollup functions](#rollup-functions) -* [Transform functions](#transform-functions) -* [Label manipulation functions](#label-manipulation-functions) -* [Aggregate functions](#aggregate-functions) - -### Rollup functions - -**Rollup functions** (aka range functions or window functions) calculate rollups over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window for the [selected time series](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). -For example, `avg_over_time(temperature[24h])` calculates the average temperature over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) for the last 24 hours. - -Additional details: - -* If rollup functions are used for building graphs in Grafana, then the rollup is calculated independently per each point on the graph. - For example, every point for `avg_over_time(temperature[24h])` graph shows the average temperature for the last 24 hours ending at this point. - The interval between points is set as `step` query arg passed by Grafana to [/api/v1/query_range](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#range-query). -* If the given [series selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering) returns multiple time series, - then rollups are calculated individually per each returned series. -* If lookbehind window in square brackets is missing, then it is automatically set to the following value: - - To `step` value passed to [/api/v1/query_range](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#range-query) or [/api/v1/query](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#instant-query) - for all the [rollup functions](#rollup-functions) except of [default_rollup](#default_rollup) and [rate](#rate). This value is known as `$__interval` in Grafana or `1i` in MetricsQL. - For example, `avg_over_time(temperature)` is automatically transformed to `avg_over_time(temperature[1i])`. - - To the `max(step, scrape_interval)`, where `scrape_interval` is the interval between [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) - for [default_rollup](#default_rollup) and [rate](#rate) functions. This allows avoiding unexpected gaps on the graph when `step` is smaller than `scrape_interval`. -* Every [series selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering) in MetricsQL must be wrapped into a rollup function. - Otherwise, it is automatically wrapped into [default_rollup](#default_rollup). For example, `foo{bar="baz"}` - is automatically converted to `default_rollup(foo{bar="baz"})` before performing the calculations. -* If something other than [series selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering) is passed to rollup function, - then the inner arg is automatically converted to a [subquery](#subqueries). -* All the rollup functions accept optional `keep_metric_names` modifier. If it is set, then the function keeps metric names in results. - See [these docs](#keep_metric_names). - -See also [implicit query conversions](#implicit-query-conversions). - -The list of supported rollup functions: - -#### absent_over_time - -`absent_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which returns 1 -if the given lookbehind window `d` doesn't contain [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples). Otherwise, it returns an empty result. - -This function is supported by PromQL. - -See also [present_over_time](#present_over_time). - -#### aggr_over_time - -`aggr_over_time(("rollup_func1", "rollup_func2", ...), series_selector[d])` is a [rollup function](#rollup-functions), -which calculates all the listed `rollup_func*` for [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) on the given lookbehind window `d`. -The calculations are performed individually per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -`rollup_func*` can contain any rollup function. For instance, `aggr_over_time(("min_over_time", "max_over_time", "rate"), m[d])` -would calculate [min_over_time](#min_over_time), [max_over_time](#max_over_time) and [rate](#rate) for `m[d]`. - -#### ascent_over_time - -`ascent_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates -ascent of [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) values on the given lookbehind window `d`. The calculations are performed individually -per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -This function is useful for tracking height gains in GPS tracking. Metric names are stripped from the resulting rollups. - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -See also [descent_over_time](#descent_over_time). - -#### avg_over_time - -`avg_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the average value -over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) on the given lookbehind window `d` per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -This function is supported by PromQL. - -See also [median_over_time](#median_over_time), [min_over_time](#min_over_time) and [max_over_time](#max_over_time). - -#### changes - -`changes(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the number of times -the [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) changed on the given lookbehind window `d` per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Unlike `changes()` in Prometheus it takes into account the change from the last sample before the given lookbehind window `d`. -See [this article](https://medium.com/@romanhavronenko/victoriametrics-promql-compliance-d4318203f51e) for details. - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [changes_prometheus](#changes_prometheus). - -#### changes_prometheus - -`changes_prometheus(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the number of times -the [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) changed on the given lookbehind window `d` per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -It doesn't take into account the change from the last sample before the given lookbehind window `d` in the same way as Prometheus does. -See [this article](https://medium.com/@romanhavronenko/victoriametrics-promql-compliance-d4318203f51e) for details. - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [changes](#changes). - -#### count_eq_over_time - -`count_eq_over_time(series_selector[d], eq)` is a [rollup function](#rollup-functions), which calculates the number of [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d`, which are equal to `eq`. It is calculated independently per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [count_over_time](#count_over_time), [share_eq_over_time](#share_eq_over_time) and [count_values_over_time](#count_values_over_time). - -#### count_gt_over_time - -`count_gt_over_time(series_selector[d], gt)` is a [rollup function](#rollup-functions), which calculates the number of [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d`, which are bigger than `gt`. It is calculated independently per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [count_over_time](#count_over_time) and [share_gt_over_time](#share_gt_over_time). - -#### count_le_over_time - -`count_le_over_time(series_selector[d], le)` is a [rollup function](#rollup-functions), which calculates the number of [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d`, which don't exceed `le`. It is calculated independently per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [count_over_time](#count_over_time) and [share_le_over_time](#share_le_over_time). - -#### count_ne_over_time - -`count_ne_over_time(series_selector[d], ne)` is a [rollup function](#rollup-functions), which calculates the number of [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d`, which aren't equal to `ne`. It is calculated independently per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [count_over_time](#count_over_time) and [count_eq_over_time](#count_eq_over_time). - -#### count_over_time - -`count_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the number of [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [count_le_over_time](#count_le_over_time), [count_gt_over_time](#count_gt_over_time), [count_eq_over_time](#count_eq_over_time) and [count_ne_over_time](#count_ne_over_time). - -#### count_values_over_time - -`count_values_over_time("label", series_selector[d])` is a [rollup function](#rollup-functions), which counts the number of [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -with the same value over the given lookbehind window and stores the counts in a time series with an additional `label`, which contains each initial value. -The results are calculated independently per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [count_eq_over_time](#count_eq_over_time), [count_values](#count_values) and [distinct_over_time](#distinct_over_time) and [label_match](#label_match). - -#### decreases_over_time - -`decreases_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the number of [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -value decreases over the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -See also [increases_over_time](#increases_over_time). - -#### default_rollup - -`default_rollup(series_selector[d])` is a [rollup function](#rollup-functions), which returns the last [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -value on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). -Compared to [last_over_time](#last_over_time) it accounts for [staleness markers](https://docs.victoriametrics.com/victoriametrics/vmagent/#prometheus-staleness-markers) to detect stale series. - -If the lookbehind window is skipped in square brackets, then it is automatically calculated as `max(step, scrape_interval)`, where `step` is the query arg value -passed to [/api/v1/query_range](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#range-query) or [/api/v1/query](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#instant-query), -while `scrape_interval` is the interval between [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) for the selected time series. -This allows avoiding unexpected gaps on the graph when `step` is smaller than the `scrape_interval`. - -#### delta - -`delta(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the difference between -the last sample before the given lookbehind window `d` and the last sample at the given lookbehind window `d` -per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -The behaviour of `delta()` function in MetricsQL is slightly different to the behaviour of `delta()` function in Prometheus. -See [this article](https://medium.com/@romanhavronenko/victoriametrics-promql-compliance-d4318203f51e) for details. - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [increase](#increase) and [delta_prometheus](#delta_prometheus). - -#### delta_prometheus - -`delta_prometheus(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the difference between -the first and the last samples at the given lookbehind window `d` per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -The behaviour of `delta_prometheus()` is close to the behaviour of `delta()` function in Prometheus. -See [this article](https://medium.com/@romanhavronenko/victoriametrics-promql-compliance-d4318203f51e) for details. - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -See also [delta](#delta). - -#### deriv - -`deriv(series_selector[d])` is a [rollup function](#rollup-functions), which calculates per-second derivative over the given lookbehind window `d` -per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). -The derivative is calculated using linear regression. - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [deriv_fast](#deriv_fast) and [ideriv](#ideriv). - -#### deriv_fast - -`deriv_fast(series_selector[d])` is a [rollup function](#rollup-functions), which calculates per-second derivative -using the first and the last [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) on the given lookbehind window `d` per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -See also [deriv](#deriv) and [ideriv](#ideriv). - -#### descent_over_time - -`descent_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates descent of [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -values on the given lookbehind window `d`. The calculations are performed individually per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -This function is useful for tracking height loss in GPS tracking. - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -See also [ascent_over_time](#ascent_over_time). - -#### distinct_over_time - -`distinct_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which returns the number of unique [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -values on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -See also [count_values_over_time](#count_values_over_time). - -#### duration_over_time - -`duration_over_time(series_selector[d], max_interval)` is a [rollup function](#rollup-functions), which returns the duration in seconds -when time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering) were present -over the given lookbehind window `d`. It is expected that intervals between adjacent samples per each series don't exceed the `max_interval`. -Otherwise, such intervals are considered as gaps and aren't counted. - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -See also [lifetime](#lifetime) and [lag](#lag). - -#### first_over_time - -`first_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which returns the first [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -value on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -See also [last_over_time](#last_over_time) and [tfirst_over_time](#tfirst_over_time). - -#### geomean_over_time - -`geomean_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates [geometric mean](https://en.wikipedia.org/wiki/Geometric_mean) -over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) on the given lookbehind window `d` per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -#### histogram_over_time - -`histogram_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates -[VictoriaMetrics histogram](https://godoc.org/github.com/VictoriaMetrics/metrics#Histogram) over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d`. It is calculated individually per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). -The resulting histograms are useful to pass to [histogram_quantile](#histogram_quantile) for calculating quantiles -over multiple [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). -For example, the following query calculates median temperature by country over the last 24 hours: - -`histogram_quantile(0.5, sum(histogram_over_time(temperature[24h])) by (vmrange,country))`. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -#### hoeffding_bound_lower - -`hoeffding_bound_lower(phi, series_selector[d])` is a [rollup function](#rollup-functions), which calculates -lower [Hoeffding bound](https://en.wikipedia.org/wiki/Hoeffding%27s_inequality) for the given `phi` in the range `[0...1]`. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [hoeffding_bound_upper](#hoeffding_bound_upper). - -#### hoeffding_bound_upper - -`hoeffding_bound_upper(phi, series_selector[d])` is a [rollup function](#rollup-functions), which calculates -upper [Hoeffding bound](https://en.wikipedia.org/wiki/Hoeffding%27s_inequality) for the given `phi` in the range `[0...1]`. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [hoeffding_bound_lower](#hoeffding_bound_lower). - -#### holt_winters - -`holt_winters(series_selector[d], sf, tf)` is a [rollup function](#rollup-functions), which calculates Holt-Winters value -(aka [double exponential smoothing](https://en.wikipedia.org/wiki/Exponential_smoothing#Double_exponential_smoothing)) for [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -over the given lookbehind window `d` using the given smoothing factor `sf` and the given trend factor `tf`. -Both `sf` and `tf` must be in the range `[0...1]`. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -This function is supported by PromQL. - -See also [range_linear_regression](#range_linear_regression). - -#### idelta - -`idelta(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the difference between the last two [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [delta](#delta). - -#### ideriv - -`ideriv(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the per-second derivative based -on the last two [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -over the given lookbehind window `d`. The derivative is calculated independently per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -See also [deriv](#deriv). - -#### increase - -`increase(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the increase over the given lookbehind window `d` -per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Unlike Prometheus, it takes into account the last sample before the given lookbehind window `d` when calculating the result. -See [this article](https://medium.com/@romanhavronenko/victoriametrics-promql-compliance-d4318203f51e) for details. - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [counters](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#counter). - -This function is supported by PromQL. - -See also [increase_pure](#increase_pure), [increase_prometheus](#increase_prometheus) and [delta](#delta). - -#### increase_prometheus - -`increase_prometheus(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the increase -over the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). -It doesn't take into account the last sample before the given lookbehind window `d` when calculating the result in the same way as Prometheus does. -See [this article](https://medium.com/@romanhavronenko/victoriametrics-promql-compliance-d4318203f51e) for details. - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [counters](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#counter). - -See also [increase_pure](#increase_pure) and [increase](#increase). - -#### increase_pure - -`increase_pure(series_selector[d])` is a [rollup function](#rollup-functions), which works the same as [increase](#increase) except -of the following corner case - it assumes that [counters](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#counter) always start from 0, -while [increase](#increase) ignores the first value in a series if it is too big. - -This function is usually applied to [counters](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#counter). - -See also [increase](#increase) and [increase_prometheus](#increase_prometheus). - -#### increases_over_time - -`increases_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the number of [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -value increases over the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -See also [decreases_over_time](#decreases_over_time). - -#### integrate - -`integrate(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the integral over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -#### irate - -`irate(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the "instant" per-second increase rate over -the last two [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [counters](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#counter). - -This function is supported by PromQL. - -See also [rate](#rate) and [rollup_rate](#rollup_rate). - -#### lag - -`lag(series_selector[d])` is a [rollup function](#rollup-functions), which returns the duration in seconds between the last sample -on the given lookbehind window `d` and the timestamp of the current point. It is calculated independently per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -See also [lifetime](#lifetime) and [duration_over_time](#duration_over_time). - -#### last_over_time - -`last_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which returns the last [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -value on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -This function is supported by PromQL. - -See also [first_over_time](#first_over_time) and [tlast_over_time](#tlast_over_time). - -#### lifetime - -`lifetime(series_selector[d])` is a [rollup function](#rollup-functions), which returns the duration in seconds between the last and the first sample -on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -See also [duration_over_time](#duration_over_time) and [lag](#lag). - -#### mad_over_time - -`mad_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates [median absolute deviation](https://en.wikipedia.org/wiki/Median_absolute_deviation) -over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) on the given lookbehind window `d` per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [mad](#mad), [range_mad](#range_mad) and [outlier_iqr_over_time](#outlier_iqr_over_time). - -#### max_over_time - -`max_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the maximum value over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -This function is supported by PromQL. - -See also [tmax_over_time](#tmax_over_time) and [min_over_time](#min_over_time). - -#### median_over_time - -`median_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates median value over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [avg_over_time](#avg_over_time). - -#### min_over_time - -`min_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the minimum value over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -This function is supported by PromQL. - -See also [tmin_over_time](#tmin_over_time) and [max_over_time](#max_over_time). - -#### mode_over_time - -`mode_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates [mode](https://en.wikipedia.org/wiki/Mode_(statistics)) -for [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) on the given lookbehind window `d`. It is calculated individually per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). It is expected that [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -values are discrete. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -#### outlier_iqr_over_time - -`outlier_iqr_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which returns the last sample on the given lookbehind window `d` -if its value is either smaller than the `q25-1.5*iqr` or bigger than `q75+1.5*iqr` where: -- `iqr` is an [Interquartile range](https://en.wikipedia.org/wiki/Interquartile_range) over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) on the lookbehind window `d` -- `q25` and `q75` are 25th and 75th [percentiles](https://en.wikipedia.org/wiki/Percentile) over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) on the lookbehind window `d`. - -The `outlier_iqr_over_time()` is useful for detecting anomalies in gauge values based on the previous history of values. -For example, `outlier_iqr_over_time(memory_usage_bytes[1h])` triggers when `memory_usage_bytes` suddenly goes outside the usual value range for the last hour. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [outliers_iqr](#outliers_iqr). - -#### predict_linear - -`predict_linear(series_selector[d], t)` is a [rollup function](#rollup-functions), which calculates the value `t` seconds in the future using -linear interpolation over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) on the given lookbehind window `d`. -The predicted value is calculated individually per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -This function is supported by PromQL. - -See also [range_linear_regression](#range_linear_regression). - -#### present_over_time - -`present_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which returns 1 if there is at least a single [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d`. Otherwise, an empty result is returned. - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -#### quantile_over_time - -`quantile_over_time(phi, series_selector[d])` is a [rollup function](#rollup-functions), which calculates `phi`-quantile over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). -The `phi` value must be in the range `[0...1]`. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -This function is supported by PromQL. - -See also [quantiles_over_time](#quantiles_over_time). - -#### quantiles_over_time - -`quantiles_over_time("phiLabel", phi1, ..., phiN, series_selector[d])` is a [rollup function](#rollup-functions), which calculates `phi*`-quantiles -over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) on the given lookbehind window `d` per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). -The function returns individual series per each `phi*` with `{phiLabel="phi*"}` label. `phi*` values must be in the range `[0...1]`. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [quantile_over_time](#quantile_over_time). - -#### range_over_time - -`range_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates value range over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). -E.g. it calculates `max_over_time(series_selector[d]) - min_over_time(series_selector[d])`. - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -#### rate - -`rate(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the average per-second increase rate -over the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -If the lookbehind window is skipped in square brackets, then it is automatically calculated as `max(step, scrape_interval)`, where `step` is the query arg value -passed to [/api/v1/query_range](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#range-query) or [/api/v1/query](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#instant-query), -while `scrape_interval` is the interval between [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) for the selected time series. -This allows avoiding unexpected gaps on the graph when `step` is smaller than the `scrape_interval`. - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [irate](#irate), [rollup_rate](#rollup_rate) and [rate_prometheus](#rate_prometheus). - -#### rate_prometheus - -`rate_prometheus(series_selector[d])` {{% available_from "#" %}} is a [rollup function](#rollup-functions), which calculates the average per-second -increase rate over the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). -The resulting calculation is equivalent to `increase_prometheus(series_selector[d]) / d`. - -It doesn't take into account the last sample before the given lookbehind window `d` when calculating the result in the same way as Prometheus does. -See [this article](https://medium.com/@romanhavronenko/victoriametrics-promql-compliance-d4318203f51e) for details. - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [counters](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#counter). - -See also [increase_prometheus](#increase_prometheus) and [rate](#rate). - - -#### rate_over_sum - -`rate_over_sum(series_selector[d])` is a [rollup function](#rollup-functions), which calculates per-second rate over the sum of [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d`. The calculations are performed individually per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -#### resets - -`resets(series_selector[d])` is a [rollup function](#rollup-functions), which returns the number -of [counter](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#counter) resets over the given lookbehind window `d` -per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [counters](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#counter). - -This function is supported by PromQL. - -#### rollup - -`rollup(series_selector[d])` is a [rollup function](#rollup-functions), which calculates `min`, `max` and `avg` values for [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` and returns them in time series with `rollup="min"`, `rollup="max"` and `rollup="avg"` additional labels. -These values are calculated individually per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Optional 2nd argument `"min"`, `"max"` or `"avg"` can be passed to keep only one calculation result and without adding a label. -See also [label_match](#label_match). - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [rollup_rate](#rollup_rate). - -#### rollup_candlestick - -`rollup_candlestick(series_selector[d])` is a [rollup function](#rollup-functions), which calculates `open`, `high`, `low` and `close` values (aka OHLC) -over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) on the given lookbehind window `d` and returns them in time series -with `rollup="open"`, `rollup="high"`, `rollup="low"` and `rollup="close"` additional labels. -The calculations are performed individually per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). This function is useful for financial applications. - -Optional 2nd argument `"open"`, `"high"` or `"low"` or `"close"` can be passed to keep only one calculation result and without adding a label. -See also [label_match](#label_match). - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -#### rollup_delta - -`rollup_delta(series_selector[d])` is a [rollup function](#rollup-functions), which calculates differences between adjacent [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` and returns `min`, `max` and `avg` values for the calculated differences -and returns them in time series with `rollup="min"`, `rollup="max"` and `rollup="avg"` additional labels. -The calculations are performed individually per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Optional 2nd argument `"min"`, `"max"` or `"avg"` can be passed to keep only one calculation result and without adding a label. -See also [label_match](#label_match). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -See also [rollup_increase](#rollup_increase). - -#### rollup_deriv - -`rollup_deriv(series_selector[d])` is a [rollup function](#rollup-functions), which calculates per-second derivatives -for adjacent [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) on the given lookbehind window `d` and returns `min`, `max` and `avg` values -for the calculated per-second derivatives and returns them in time series with `rollup="min"`, `rollup="max"` and `rollup="avg"` additional labels. -The calculations are performed individually per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Optional 2nd argument `"min"`, `"max"` or `"avg"` can be passed to keep only one calculation result and without adding a label. -See also [label_match](#label_match). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -See also [rollup](#rollup) and [rollup_rate](#rollup_rate). - -#### rollup_increase - -`rollup_increase(series_selector[d])` is a [rollup function](#rollup-functions), which calculates increases for adjacent [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` and returns `min`, `max` and `avg` values for the calculated increases -and returns them in time series with `rollup="min"`, `rollup="max"` and `rollup="avg"` additional labels. -The calculations are performed individually per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Optional 2nd argument `"min"`, `"max"` or `"avg"` can be passed to keep only one calculation result and without adding a label. -See also [label_match](#label_match). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. See also [rollup_delta](#rollup_delta). - -This function is usually applied to [counters](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#counter). - -See also [rollup](#rollup) and [rollup_rate](#rollup_rate). - -#### rollup_rate - -`rollup_rate(series_selector[d])` is a [rollup function](#rollup-functions), which calculates per-second change rates -for adjacent [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` and returns `min`, `max` and `avg` values for the calculated per-second change rates -and returns them in time series with `rollup="min"`, `rollup="max"` and `rollup="avg"` additional labels. -The calculations are performed individually per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -See [this article](https://valyala.medium.com/why-irate-from-prometheus-doesnt-capture-spikes-45f9896d7832) in order to understand better -when to use `rollup_rate()`. - -Optional 2nd argument `"min"`, `"max"` or `"avg"` can be passed to keep only one calculation result and without adding a label. -See also [label_match](#label_match). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [counters](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#counter). - -See also [rollup](#rollup) and [rollup_increase](#rollup_increase). - -#### rollup_scrape_interval - -`rollup_scrape_interval(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the interval in seconds between -adjacent [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) on the given lookbehind window `d` and returns `min`, `max` and `avg` values for the calculated interval -and returns them in time series with `rollup="min"`, `rollup="max"` and `rollup="avg"` additional labels. -The calculations are performed individually per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Optional 2nd argument `"min"`, `"max"` or `"avg"` can be passed to keep only one calculation result and without adding a label. -See also [label_match](#label_match). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. See also [scrape_interval](#scrape_interval). - -#### scrape_interval - -`scrape_interval(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the average interval in seconds -between [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -See also [rollup_scrape_interval](#rollup_scrape_interval). - -#### share_gt_over_time - -`share_gt_over_time(series_selector[d], gt)` is a [rollup function](#rollup-functions), which returns share (in the range `[0...1]`) -of [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d`, which are bigger than `gt`. It is calculated independently per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -This function is useful for calculating SLI and SLO. Example: `share_gt_over_time(up[24h], 0)` - returns service availability for the last 24 hours. - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [share_le_over_time](#share_le_over_time) and [count_gt_over_time](#count_gt_over_time). - -#### share_le_over_time - -`share_le_over_time(series_selector[d], le)` is a [rollup function](#rollup-functions), which returns share (in the range `[0...1]`) -of [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d`, which are smaller or equal to `le`. It is calculated independently per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -This function is useful for calculating SLI and SLO. Example: `share_le_over_time(memory_usage_bytes[24h], 100*1024*1024)` returns -the share of time series values for the last 24 hours when memory usage was below or equal to 100MB. - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [share_gt_over_time](#share_gt_over_time) and [count_le_over_time](#count_le_over_time). - -#### share_eq_over_time - -`share_eq_over_time(series_selector[d], eq)` is a [rollup function](#rollup-functions), which returns share (in the range `[0...1]`) -of [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d`, which are equal to `eq`. It is calculated independently per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [count_eq_over_time](#count_eq_over_time). - -#### stale_samples_over_time - -`stale_samples_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the number -of [staleness markers](https://docs.victoriametrics.com/victoriametrics/vmagent/#prometheus-staleness-markers) on the given lookbehind window `d` -per each time series matching the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -#### stddev_over_time - -`stddev_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates standard deviation over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -This function is supported by PromQL. - -See also [stdvar_over_time](#stdvar_over_time). - -#### stdvar_over_time - -`stdvar_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates standard variance over [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -This function is supported by PromQL. - -See also [stddev_over_time](#stddev_over_time). - -#### sum_eq_over_time - -`sum_eq_over_time(series_selector[d], eq)` is a [rollup function](#rollup-functions), which calculates the sum of [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -values equal to `eq` on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [sum_over_time](#sum_over_time) and [count_eq_over_time](#count_eq_over_time). - -#### sum_gt_over_time - -`sum_gt_over_time(series_selector[d], gt)` is a [rollup function](#rollup-functions), which calculates the sum of [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -values bigger than `gt` on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [sum_over_time](#sum_over_time) and [count_gt_over_time](#count_gt_over_time). - -#### sum_le_over_time - -`sum_le_over_time(series_selector[d], le)` is a [rollup function](#rollup-functions), which calculates the sum of [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -values smaller or equal to `le` on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [sum_over_time](#sum_over_time) and [count_le_over_time](#count_le_over_time). - -#### sum_over_time - -`sum_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the sum of [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) values -on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -This function is supported by PromQL. - -#### sum2_over_time - -`sum2_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the sum of squares for [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -values on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -#### timestamp - -`timestamp(series_selector[d])` is a [rollup function](#rollup-functions), which returns the timestamp in seconds with millisecond precision -for the last [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [time](#time) and [now](#now). - -#### timestamp_with_name - -`timestamp_with_name(series_selector[d])` is a [rollup function](#rollup-functions), which returns the timestamp in seconds with millisecond precision -for the last [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are preserved in the resulting rollups. - -See also [timestamp](#timestamp) and [keep_metric_names](#keep_metric_names) modifier. - -#### tfirst_over_time - -`tfirst_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which returns the timestamp in seconds with millisecond precision -for the first [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -on the given lookbehind window `d` per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -See also [first_over_time](#first_over_time). - -#### tlast_change_over_time - -`tlast_change_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which returns the timestamp in seconds with millisecond precision for the last change -per each time series returned from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering) on the given lookbehind window `d`. - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -See also [last_over_time](#last_over_time). - -#### tlast_over_time - -`tlast_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which is an alias for [timestamp](#timestamp). - -See also [tlast_change_over_time](#tlast_change_over_time). - -#### tmax_over_time - -`tmax_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which returns the timestamp in seconds with millisecond precision -for the [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -with the maximum value on the given lookbehind window `d`. It is calculated independently per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -See also [max_over_time](#max_over_time). - -#### tmin_over_time - -`tmin_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which returns the timestamp in seconds with millisecond precision -for the [raw sample](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) -with the minimum value on the given lookbehind window `d`. It is calculated independently per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -See also [min_over_time](#min_over_time). - -#### zscore_over_time - -`zscore_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which returns [z-score](https://en.wikipedia.org/wiki/Standard_score) -for [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) on the given lookbehind window `d`. It is calculated independently per each time series returned -from the given [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering). - -Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is usually applied to [gauges](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#gauge). - -See also [zscore](#zscore), [range_trim_zscore](#range_trim_zscore) and [outlier_iqr_over_time](#outlier_iqr_over_time). - - -### Transform functions - -**Transform functions** calculate transformations over [rollup results](#rollup-functions). -For example, `abs(delta(temperature[24h]))` calculates the absolute value for every point of every time series -returned from the rollup `delta(temperature[24h])`. - -Additional details: - -* If transform function is applied directly to a [series selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering), - then the [default_rollup()](#default_rollup) function is automatically applied before calculating the transformations. - For example, `abs(temperature)` is implicitly transformed to `abs(default_rollup(temperature))`. -* All the transform functions accept optional `keep_metric_names` modifier. If it is set, - then the function doesn't drop metric names from the resulting time series. See [these docs](#keep_metric_names). - -See also [implicit query conversions](#implicit-query-conversions). - -The list of supported transform functions: - -#### abs - -`abs(q)` is a [transform function](#transform-functions), which calculates the absolute value for every point of every time series returned by `q`. - -This function is supported by PromQL. - -#### absent - -`absent(q)` is a [transform function](#transform-functions), which returns 1 if `q` has no points. Otherwise, returns an empty result. - -This function is supported by PromQL. - -See also [absent_over_time](#absent_over_time). - -#### acos - -`acos(q)` is a [transform function](#transform-functions), which returns [inverse cosine](https://en.wikipedia.org/wiki/Inverse_trigonometric_functions) -for every point of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [asin](#asin) and [cos](#cos). - -#### acosh - -`acosh(q)` is a [transform function](#transform-functions), which returns -[inverse hyperbolic cosine](https://en.wikipedia.org/wiki/Inverse_hyperbolic_functions#Inverse_hyperbolic_cosine) for every point of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [sinh](#cosh). - -#### asin - -`asin(q)` is a [transform function](#transform-functions), which returns [inverse sine](https://en.wikipedia.org/wiki/Inverse_trigonometric_functions) -for every point of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [acos](#acos) and [sin](#sin). - -#### asinh - -`asinh(q)` is a [transform function](#transform-functions), which returns -[inverse hyperbolic sine](https://en.wikipedia.org/wiki/Inverse_hyperbolic_functions#Inverse_hyperbolic_sine) for every point of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [sinh](#sinh). - -#### atan - -`atan(q)` is a [transform function](#transform-functions), which returns [inverse tangent](https://en.wikipedia.org/wiki/Inverse_trigonometric_functions) -for every point of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [tan](#tan). - -#### atanh - -`atanh(q)` is a [transform function](#transform-functions), which returns -[inverse hyperbolic tangent](https://en.wikipedia.org/wiki/Inverse_hyperbolic_functions#Inverse_hyperbolic_tangent) for every point of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [tanh](#tanh). - -#### bitmap_and - -`bitmap_and(q, mask)` is a [transform function](#transform-functions), which calculates bitwise `v & mask` for every `v` point of every time series returned from `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -#### bitmap_or - -`bitmap_or(q, mask)` is a [transform function](#transform-functions), which calculates bitwise `v | mask` for every `v` point of every time series returned from `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -#### bitmap_xor - -`bitmap_xor(q, mask)` is a [transform function](#transform-functions), which calculates bitwise `v ^ mask` for every `v` point of every time series returned from `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -#### buckets_limit - -`buckets_limit(limit, buckets)` is a [transform function](#transform-functions), which limits the number -of [histogram buckets](https://valyala.medium.com/improving-histogram-usability-for-prometheus-and-grafana-bc7e5df0e350) to the given `limit`. - -See also [prometheus_buckets](#prometheus_buckets) and [histogram_quantile](#histogram_quantile). - -#### ceil - -`ceil(q)` is a [transform function](#transform-functions), which rounds every point for every time series returned by `q` to the upper nearest integer. - -This function is supported by PromQL. - -See also [floor](#floor) and [round](#round). - -#### clamp - -`clamp(q, min, max)` is a [transform function](#transform-functions), which clamps every point for every time series returned by `q` with the given `min` and `max` values. - -This function is supported by PromQL. - -See also [clamp_min](#clamp_min) and [clamp_max](#clamp_max). - -#### clamp_max - -`clamp_max(q, max)` is a [transform function](#transform-functions), which clamps every point for every time series returned by `q` with the given `max` value. - -This function is supported by PromQL. - -See also [clamp](#clamp) and [clamp_min](#clamp_min). - -#### clamp_min - -`clamp_min(q, min)` is a [transform function](#transform-functions), which clamps every point for every time series returned by `q` with the given `min` value. - -This function is supported by PromQL. - -See also [clamp](#clamp) and [clamp_max](#clamp_max). - -#### cos - -`cos(q)` is a [transform function](#transform-functions), which returns `cos(v)` for every `v` point of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [sin](#sin). - -#### cosh - -`cosh(q)` is a [transform function](#transform-functions), which returns [hyperbolic cosine](https://en.wikipedia.org/wiki/Hyperbolic_functions) -for every point of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [acosh](#acosh). - -#### day_of_month - -`day_of_month(q)` is a [transform function](#transform-functions), which returns the day of month for every point of every time series returned by `q`. -It is expected that `q` returns unix timestamps. The returned values are in the range `[1...31]`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [day_of_week](#day_of_week) and [day_of_year](#day_of_year). - -#### day_of_week - -`day_of_week(q)` is a [transform function](#transform-functions), which returns the day of week for every point of every time series returned by `q`. -It is expected that `q` returns unix timestamps. The returned values are in the range `[0...6]`, where `0` means Sunday and `6` means Saturday. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [day_of_month](#day_of_month) and [day_of_year](#day_of_year). - -#### day_of_year - -`day_of_year(q)` is a [transform function](#transform-functions), which returns the day of year for every point of every time series returned by `q`. -It is expected that `q` returns unix timestamps. The returned values are in the range `[1...365]` for non-leap years, and `[1 to 366]` in leap years. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [day_of_week](#day_of_week) and [day_of_month](#day_of_month). - -#### days_in_month - -`days_in_month(q)` is a [transform function](#transform-functions), which returns the number of days in the month identified -by every point of every time series returned by `q`. It is expected that `q` returns unix timestamps. -The returned values are in the range `[28...31]`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -#### deg - -`deg(q)` is a [transform function](#transform-functions), which converts [Radians to degrees](https://en.wikipedia.org/wiki/Radian#Conversions) -for every point of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [rad](#rad). - -#### drop_empty_series - -`drop_empty_series(q)` is a [transform function](#transform-functions), which drops empty series from `q`. - -This function can be used when `default` operator should be applied only to non-empty series. For example, -`drop_empty_series(temperature < 30) default 42` returns series, which have at least a single sample smaller than 30 on the selected time range, -while filling gaps in the returned series with 42. - -On the other hand `(temperature < 30) default 40` returns all the `temperature` series, even if they have no samples smaller than 30, -by replacing all the values bigger or equal to 30 with 40. - -#### end - -`end()` is a [transform function](#transform-functions), which returns the unix timestamp in seconds for the last point. -It is known as `end` query arg passed to [/api/v1/query_range](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#range-query). - -See also [start](#start), [time](#time) and [now](#now). - -#### exp - -`exp(q)` is a [transform function](#transform-functions), which calculates the `e^v` for every point `v` of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [ln](#ln). - -#### floor - -`floor(q)` is a [transform function](#transform-functions), which rounds every point for every time series returned by `q` to the lower nearest integer. - -This function is supported by PromQL. - -See also [ceil](#ceil) and [round](#round). - -#### histogram_avg - -`histogram_avg(buckets)` is a [transform function](#transform-functions), which calculates the average value for the given `buckets`. -It can be used for calculating the average over the given time range across multiple time series. -For example, `histogram_avg(sum(histogram_over_time(response_time_duration_seconds[5m])) by (vmrange,job))` would return the average response time -per each `job` over the last 5 minutes. - -#### histogram_quantile - -`histogram_quantile(phi, buckets)` is a [transform function](#transform-functions), which calculates `phi`-[percentile](https://en.wikipedia.org/wiki/Percentile) -over the given [histogram buckets](https://valyala.medium.com/improving-histogram-usability-for-prometheus-and-grafana-bc7e5df0e350). -`phi` must be in the range `[0...1]`. For example, `histogram_quantile(0.5, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))` -would return median request duration for all the requests during the last 5 minutes. - -The function accepts optional third arg - `boundsLabel`. In this case it returns `lower` and `upper` bounds for the estimated percentile with the given `boundsLabel` label. -See [this issue for details](https://github.com/prometheus/prometheus/issues/5706). - -When the [percentile](https://en.wikipedia.org/wiki/Percentile) is calculated over multiple histograms, -then all the input histograms **must** have buckets with identical boundaries, e.g. they must have the same set of `le` or `vmrange` labels. -Otherwise, the returned result may be invalid. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3231) for details. - -This function is supported by PromQL (except of the `boundLabel` arg). - -See also [histogram_quantiles](#histogram_quantiles), [histogram_share](#histogram_share) and [quantile](#quantile). - -#### histogram_quantiles - -`histogram_quantiles("phiLabel", phi1, ..., phiN, buckets)` is a [transform function](#transform-functions), which calculates the given `phi*`-quantiles -over the given [histogram buckets](https://valyala.medium.com/improving-histogram-usability-for-prometheus-and-grafana-bc7e5df0e350). -Argument `phi*` must be in the range `[0...1]`. For example, `histogram_quantiles('le', 0.3, 0.5, sum(rate(http_request_duration_seconds_bucket[5m]) by (le))`. -Each calculated quantile is returned in a separate time series with the corresponding `{phiLabel="phi*"}` label. - -See also [histogram_quantile](#histogram_quantile). - -#### histogram_share - -`histogram_share(le, buckets)` is a [transform function](#transform-functions), which calculates the share (in the range `[0...1]`) -for `buckets` that fall below `le`. This function is useful for calculating SLI and SLO. This is inverse to [histogram_quantile](#histogram_quantile). - -The function accepts optional third arg - `boundsLabel`. In this case it returns `lower` and `upper` bounds for the estimated share with the given `boundsLabel` label. - -#### histogram_stddev - -`histogram_stddev(buckets)` is a [transform function](#transform-functions), which calculates standard deviation for the given `buckets`. - -#### histogram_stdvar - -`histogram_stdvar(buckets)` is a [transform function](#transform-functions), which calculates standard variance for the given `buckets`. -It can be used for calculating standard deviation over the given time range across multiple time series. -For example, `histogram_stdvar(sum(histogram_over_time(temperature[24])) by (vmrange,country))` would return standard deviation -for the temperature per each country over the last 24 hours. - -#### hour - -`hour(q)` is a [transform function](#transform-functions), which returns the hour for every point of every time series returned by `q`. -It is expected that `q` returns unix timestamps. The returned values are in the range `[0...23]`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -#### interpolate - -`interpolate(q)` is a [transform function](#transform-functions), which fills gaps with linearly interpolated values calculated -from the last and the next non-empty points per each time series returned by `q`. - -See also [keep_last_value](#keep_last_value) and [keep_next_value](#keep_next_value). - -#### keep_last_value - -`keep_last_value(q)` is a [transform function](#transform-functions), which fills gaps with the value of the last non-empty point -in every time series returned by `q`. - -See also [keep_next_value](#keep_next_value) and [interpolate](#interpolate). - -#### keep_next_value - -`keep_next_value(q)` is a [transform function](#transform-functions), which fills gaps with the value of the next non-empty point -in every time series returned by `q`. - -See also [keep_last_value](#keep_last_value) and [interpolate](#interpolate). - -#### limit_offset - -`limit_offset(limit, offset, q)` is a [transform function](#transform-functions), which skips `offset` time series from series returned by `q` -and then returns up to `limit` of the remaining time series per each group. - -This allows implementing simple paging for `q` time series. See also [limitk](#limitk). - -#### ln - -`ln(q)` is a [transform function](#transform-functions), which calculates `ln(v)` for every point `v` of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [exp](#exp) and [log2](#log2). - -#### log2 - -`log2(q)` is a [transform function](#transform-functions), which calculates `log2(v)` for every point `v` of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [log10](#log10) and [ln](#ln). - -#### log10 - -`log10(q)` is a [transform function](#transform-functions), which calculates `log10(v)` for every point `v` of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [log2](#log2) and [ln](#ln). - -#### minute - -`minute(q)` is a [transform function](#transform-functions), which returns the minute for every point of every time series returned by `q`. -It is expected that `q` returns unix timestamps. The returned values are in the range `[0...59]`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -#### month - -`month(q)` is a [transform function](#transform-functions), which returns the month for every point of every time series returned by `q`. -It is expected that `q` returns unix timestamps. The returned values are in the range `[1...12]`, where `1` means January and `12` means December. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -#### now - -`now()` is a [transform function](#transform-functions), which returns the current timestamp as a floating-point value in seconds. - -See also [time](#time). - -#### pi - -`pi()` is a [transform function](#transform-functions), which returns [Pi number](https://en.wikipedia.org/wiki/Pi). - -This function is supported by PromQL. - -#### rad - -`rad(q)` is a [transform function](#transform-functions), which converts [degrees to Radians](https://en.wikipedia.org/wiki/Radian#Conversions) -for every point of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -See also [deg](#deg). - -#### prometheus_buckets - -`prometheus_buckets(buckets)` is a [transform function](#transform-functions), which converts -[VictoriaMetrics histogram buckets](https://valyala.medium.com/improving-histogram-usability-for-prometheus-and-grafana-bc7e5df0e350) with `vmrange` labels -to Prometheus histogram buckets with `le` labels. This may be useful for building heatmaps in Grafana. - -See also [histogram_quantile](#histogram_quantile) and [buckets_limit](#buckets_limit). - -#### rand - -`rand(seed)` is a [transform function](#transform-functions), which returns pseudo-random numbers on the range `[0...1]` with even distribution. -Optional `seed` can be used as a seed for pseudo-random number generator. - -See also [rand_normal](#rand_normal) and [rand_exponential](#rand_exponential). - -#### rand_exponential - -`rand_exponential(seed)` is a [transform function](#transform-functions), which returns pseudo-random numbers -with [exponential distribution](https://en.wikipedia.org/wiki/Exponential_distribution). Optional `seed` can be used as a seed for pseudo-random number generator. - -See also [rand](#rand) and [rand_normal](#rand_normal). - -#### rand_normal - -`rand_normal(seed)` is a [transform function](#transform-functions), which returns pseudo-random numbers -with [normal distribution](https://en.wikipedia.org/wiki/Normal_distribution). Optional `seed` can be used as a seed for pseudo-random number generator. - -See also [rand](#rand) and [rand_exponential](#rand_exponential). - -#### range_avg - -`range_avg(q)` is a [transform function](#transform-functions), which calculates the avg value across points per each time series returned by `q`. - -#### range_first - -`range_first(q)` is a [transform function](#transform-functions), which returns the value for the first point per each time series returned by `q`. - -#### range_last - -`range_last(q)` is a [transform function](#transform-functions), which returns the value for the last point per each time series returned by `q`. - -#### range_linear_regression - -`range_linear_regression(q)` is a [transform function](#transform-functions), which calculates [simple linear regression](https://en.wikipedia.org/wiki/Simple_linear_regression) -over the selected time range per each time series returned by `q`. This function is useful for capacity planning and predictions. - -#### range_mad - -`range_mad(q)` is a [transform function](#transform-functions), which calculates the [median absolute deviation](https://en.wikipedia.org/wiki/Median_absolute_deviation) -across points per each time series returned by `q`. - -See also [mad](#mad) and [mad_over_time](#mad_over_time). - -#### range_max - -`range_max(q)` is a [transform function](#transform-functions), which calculates the max value across points per each time series returned by `q`. - -#### range_median - -`range_median(q)` is a [transform function](#transform-functions), which calculates the median value across points per each time series returned by `q`. - -#### range_min - -`range_min(q)` is a [transform function](#transform-functions), which calculates the min value across points per each time series returned by `q`. - -#### range_normalize - -`range_normalize(q1, ...)` is a [transform function](#transform-functions), which normalizes values for time series returned by `q1, ...` into `[0 ... 1]` range. -This function is useful for correlating time series with distinct value ranges. - -See also [share](#share). - -#### range_quantile - -`range_quantile(phi, q)` is a [transform function](#transform-functions), which returns `phi`-quantile across points per each time series returned by `q`. -`phi` must be in the range `[0...1]`. - -#### range_stddev - -`range_stddev(q)` is a [transform function](#transform-functions), which calculates [standard deviation](https://en.wikipedia.org/wiki/Standard_deviation) -per each time series returned by `q` on the selected time range. - -#### range_stdvar - -`range_stdvar(q)` is a [transform function](#transform-functions), which calculates [standard variance](https://en.wikipedia.org/wiki/Variance) -per each time series returned by `q` on the selected time range. - -#### range_sum - -`range_sum(q)` is a [transform function](#transform-functions), which calculates the sum of points per each time series returned by `q`. - -#### range_trim_outliers - -`range_trim_outliers(k, q)` is a [transform function](#transform-functions), which drops points located farther than `k*range_mad(q)` -from the `range_median(q)`. E.g. it is equivalent to the following query: `q ifnot (abs(q - range_median(q)) > k*range_mad(q))`. - -See also [range_trim_spikes](#range_trim_spikes) and [range_trim_zscore](#range_trim_zscore). - -#### range_trim_spikes - -`range_trim_spikes(phi, q)` is a [transform function](#transform-functions), which drops `phi` percent of biggest spikes from time series returned by `q`. -The `phi` must be in the range `[0..1]`, where `0` means `0%` and `1` means `100%`. - -See also [range_trim_outliers](#range_trim_outliers) and [range_trim_zscore](#range_trim_zscore). - -#### range_trim_zscore - -`range_trim_zscore(z, q)` is a [transform function](#transform-functions), which drops points located farther than `z*range_stddev(q)` -from the `range_avg(q)`. E.g. it is equivalent to the following query: `q ifnot (abs(q - range_avg(q)) > z*range_avg(q))`. - -See also [range_trim_outliers](#range_trim_outliers) and [range_trim_spikes](#range_trim_spikes). - -#### range_zscore - -`range_zscore(q)` is a [transform function](#transform-functions), which calculates [z-score](https://en.wikipedia.org/wiki/Standard_score) -for points returned by `q`, e.g. it is equivalent to the following query: `(q - range_avg(q)) / range_stddev(q)`. - -#### remove_resets - -`remove_resets(q)` is a [transform function](#transform-functions), which removes counter resets from time series returned by `q`. - -#### round - -`round(q, nearest)` is a [transform function](#transform-functions), which rounds every point of every time series returned by `q` to the `nearest` multiple. -If `nearest` is missing then the rounding is performed to the nearest integer. - -This function is supported by PromQL. - -See also [floor](#floor) and [ceil](#ceil). - -#### ru - -`ru(free, max)` is a [transform function](#transform-functions), which calculates resource utilization in the range `[0%...100%]` for the given `free` and `max` resources. -For instance, `ru(node_memory_MemFree_bytes, node_memory_MemTotal_bytes)` returns memory utilization over [node_exporter](https://github.com/prometheus/node_exporter) metrics. - -#### running_avg - -`running_avg(q)` is a [transform function](#transform-functions), which calculates the running avg per each time series returned by `q`. - -#### running_max - -`running_max(q)` is a [transform function](#transform-functions), which calculates the running max per each time series returned by `q`. - -#### running_min - -`running_min(q)` is a [transform function](#transform-functions), which calculates the running min per each time series returned by `q`. - -#### running_sum - -`running_sum(q)` is a [transform function](#transform-functions), which calculates the running sum per each time series returned by `q`. - -#### scalar - -`scalar(q)` is a [transform function](#transform-functions), which returns `q` if `q` contains only a single time series. Otherwise, it returns nothing. - -This function is supported by PromQL. - -#### sgn - -`sgn(q)` is a [transform function](#transform-functions), which returns `1` if `v>0`, `-1` if `v<0` and `0` if `v==0` for every point `v` -of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -#### sin - -`sin(q)` is a [transform function](#transform-functions), which returns `sin(v)` for every `v` point of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by MetricsQL. - -See also [cos](#cos). - -#### sinh - -`sinh(q)` is a [transform function](#transform-functions), which returns [hyperbolic sine](https://en.wikipedia.org/wiki/Hyperbolic_functions) -for every point of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by MetricsQL. - -See also [cosh](#cosh). - -#### tan - -`tan(q)` is a [transform function](#transform-functions), which returns `tan(v)` for every `v` point of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by MetricsQL. - -See also [atan](#atan). - -#### tanh - -`tanh(q)` is a [transform function](#transform-functions), which returns [hyperbolic tangent](https://en.wikipedia.org/wiki/Hyperbolic_functions) -for every point of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by MetricsQL. - -See also [atanh](#atanh). - -#### smooth_exponential - -`smooth_exponential(q, sf)` is a [transform function](#transform-functions), which smooths points per each time series returned -by `q` using [exponential moving average](https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average) with the given smooth factor `sf`. - -#### sort - -`sort(q)` is a [transform function](#transform-functions), which sorts series in ascending order by the last point in every time series returned by `q`. - -This function is supported by PromQL. - -See also [sort_desc](#sort_desc) and [sort_by_label](#sort_by_label). - -#### sort_desc - -`sort_desc(q)` is a [transform function](#transform-functions), which sorts series in descending order by the last point in every time series returned by `q`. - -This function is supported by PromQL. - -See also [sort](#sort) and [sort_by_label](#sort_by_label_desc). - -#### sqrt - -`sqrt(q)` is a [transform function](#transform-functions), which calculates square root for every point of every time series returned by `q`. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -#### start - -`start()` is a [transform function](#transform-functions), which returns unix timestamp in seconds for the first point. - -It is known as `start` query arg passed to [/api/v1/query_range](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#range-query). - -See also [end](#end), [time](#time) and [now](#now). - -#### step - -`step()` is a [transform function](#transform-functions), which returns the step in seconds (aka interval) between the returned points. -It is known as `step` query arg passed to [/api/v1/query_range](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#range-query). - -See also [start](#start) and [end](#end). - -#### time - -`time()` is a [transform function](#transform-functions), which returns unix timestamp for every returned point. - -This function is supported by PromQL. - -See also [timestamp](#timestamp), [now](#now), [start](#start) and [end](#end). - -#### timezone_offset - -`timezone_offset(tz)` is a [transform function](#transform-functions), which returns offset in seconds for the given timezone `tz` relative to UTC. -This can be useful when combining with datetime-related functions. For example, `day_of_week(time()+timezone_offset("America/Los_Angeles"))` -would return weekdays for `America/Los_Angeles` time zone. - -Special `Local` time zone can be used for returning an offset for the time zone set on the host where VictoriaMetrics runs. - -See [the list of supported timezones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). - -#### ttf - -`ttf(free)` is a [transform function](#transform-functions), which estimates the time in seconds needed to exhaust `free` resources. -For instance, `ttf(node_filesystem_avail_byte)` returns the time to storage space exhaustion. This function may be useful for capacity planning. - -#### union - -`union(q1, ..., qN)` is a [transform function](#transform-functions), which returns a union of time series returned from `q1`, ..., `qN`. -The `union` function name can be skipped - the following queries are equivalent: `union(q1, q2)` and `(q1, q2)`. - -It is expected that each `q*` query returns time series with unique sets of labels. -Otherwise, only the first time series out of series with identical set of labels is returned. -Use [alias](#alias) and [label_set](#label_set) functions for giving unique labelsets per each `q*` query: - -#### vector - -`vector(q)` is a [transform function](#transform-functions), which returns `q`, e.g. it does nothing in MetricsQL. - -This function is supported by PromQL. - -#### year - -`year(q)` is a [transform function](#transform-functions), which returns the year for every point of every time series returned by `q`. -It is expected that `q` returns unix timestamps. - -Metric names are stripped from the resulting series. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. - -This function is supported by PromQL. - -### Label manipulation functions - -**Label manipulation functions** perform manipulations with labels on the selected [rollup results](#rollup-functions). - -Additional details: - -* If label manipulation function is applied directly to a [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering), - then the [default_rollup()](#default_rollup) function is automatically applied before performing the label transformation. - For example, `alias(temperature, "foo")` is implicitly transformed to `alias(default_rollup(temperature), "foo")`. - -See also [implicit query conversions](#implicit-query-conversions). - -The list of supported label manipulation functions: - -#### alias - -`alias(q, "name")` is [label manipulation function](#label-manipulation-functions), which sets the given `name` to all the time series returned by `q`. -For example, `alias(up, "foobar")` would rename `up` series to `foobar` series. - - -#### drop_common_labels - -`drop_common_labels(q1, ...., qN)` is [label manipulation function](#label-manipulation-functions), which drops common `label="value"` pairs -among time series returned from `q1, ..., qN`. - -#### label_copy - -`label_copy(q, "src_label1", "dst_label1", ..., "src_labelN", "dst_labelN")` is [label manipulation function](#label-manipulation-functions), -which copies label values from `src_label*` to `dst_label*` for all the time series returned by `q`. -If `src_label` is empty, then the corresponding `dst_label` is left untouched. - -#### label_del - -`label_del(q, "label1", ..., "labelN")` is [label manipulation function](#label-manipulation-functions), which deletes the given `label*` labels -from all the time series returned by `q`. - -#### label_graphite_group - -`label_graphite_group(q, groupNum1, ... groupNumN)` is [label manipulation function](#label-manipulation-functions), which replaces metric names -returned from `q` with the given Graphite group values concatenated via `.` char. - -For example, `label_graphite_group({__graphite__="foo*.bar.*"}, 0, 2)` would substitute `foo.bar.` metric names with `foo.`. - -This function is useful for aggregating Graphite metrics with [aggregate functions](#aggregate-functions). For example, the following query would return per-app memory usage: - -``` -sum by (__name__) ( - label_graphite_group({__graphite__="app*.host*.memory_usage"}, 0) -) -``` - -#### label_join - -`label_join(q, "dst_label", "separator", "src_label1", ..., "src_labelN")` is [label manipulation function](#label-manipulation-functions), -which joins `src_label*` values with the given `separator` and stores the result in `dst_label`. -This is performed individually per each time series returned by `q`. -For example, `label_join(up{instance="xxx",job="yyy"}, "foo", "-", "instance", "job")` would store `xxx-yyy` label value into `foo` label. - -This function is supported by PromQL. - -#### label_keep - -`label_keep(q, "label1", ..., "labelN")` is [label manipulation function](#label-manipulation-functions), which deletes all the labels -except of the listed `label*` labels in all the time series returned by `q`. - -#### label_lowercase - -`label_lowercase(q, "label1", ..., "labelN")` is [label manipulation function](#label-manipulation-functions), which lowercases values -for the given `label*` labels in all the time series returned by `q`. - -#### label_map - -`label_map(q, "label", "src_value1", "dst_value1", ..., "src_valueN", "dst_valueN")` is [label manipulation function](#label-manipulation-functions), -which maps `label` values from `src_*` to `dst*` for all the time series returned by `q`. - -#### label_match - -`label_match(q, "label", "regexp")` is [label manipulation function](#label-manipulation-functions), -which drops time series from `q` with `label` not matching the given `regexp`. -This function can be useful after [rollup](#rollup)-like functions, which may return multiple time series for every input series. - -See also [label_mismatch](#label_mismatch) and [labels_equal](#labels_equal). - -#### label_mismatch - -`label_mismatch(q, "label", "regexp")` is [label manipulation function](#label-manipulation-functions), -which drops time series from `q` with `label` matching the given `regexp`. -This function can be useful after [rollup](#rollup)-like functions, which may return multiple time series for every input series. - -See also [label_match](#label_match) and [labels_equal](#labels_equal). - -#### label_move - -`label_move(q, "src_label1", "dst_label1", ..., "src_labelN", "dst_labelN")` is [label manipulation function](#label-manipulation-functions), -which moves label values from `src_label*` to `dst_label*` for all the time series returned by `q`. -If `src_label` is empty, then the corresponding `dst_label` is left untouched. - -#### label_replace - -`label_replace(q, "dst_label", "replacement", "src_label", "regex")` is [label manipulation function](#label-manipulation-functions), -which applies the given `regex` to `src_label` and stores the `replacement` in `dst_label` if the given `regex` matches `src_label`. -The `replacement` may contain references to regex captures such as `$1`, `$2`, etc. -These references are substituted by the corresponding regex captures. -For example, `label_replace(up{job="node-exporter"}, "foo", "bar-$1", "job", "node-(.+)")` would store `bar-exporter` label value into `foo` label. - -This function is supported by PromQL. - -#### label_set - -`label_set(q, "label1", "value1", ..., "labelN", "valueN")` is [label manipulation function](#label-manipulation-functions), -which sets `{label1="value1", ..., labelN="valueN"}` labels to all the time series returned by `q`. - -#### label_transform - -`label_transform(q, "label", "regexp", "replacement")` is [label manipulation function](#label-manipulation-functions), -which substitutes all the `regexp` occurrences by the given `replacement` in the given `label`. - -#### label_uppercase - -`label_uppercase(q, "label1", ..., "labelN")` is [label manipulation function](#label-manipulation-functions), -which uppercases values for the given `label*` labels in all the time series returned by `q`. - -See also [label_lowercase](#label_lowercase). - -#### label_value - -`label_value(q, "label")` is [label manipulation function](#label-manipulation-functions), which returns numeric values -for the given `label` for every time series returned by `q`. - -For example, if `label_value(foo, "bar")` is applied to `foo{bar="1.234"}`, then it will return a time series -`foo{bar="1.234"}` with `1.234` value. Function will return no data for non-numeric label values. - -#### labels_equal - -`labels_equal(q, "label1", "label2", ...)` is [label manipulation function](#label-manipulation-functions), which returns `q` series with identical values for the listed labels -"label1", "label2", etc. - -See also [label_match](#label_match) and [label_mismatch](#label_mismatch). - -#### sort_by_label - -`sort_by_label(q, "label1", ... "labelN")` is [label manipulation function](#label-manipulation-functions), which sorts series in ascending order by the given set of labels. -For example, `sort_by_label(foo, "bar")` would sort `foo` series by values of the label `bar` in these series. - -See also [sort_by_label_desc](#sort_by_label_desc) and [sort_by_label_numeric](#sort_by_label_numeric). - -#### sort_by_label_desc - -`sort_by_label_desc(q, "label1", ... "labelN")` is [label manipulation function](#label-manipulation-functions), which sorts series in descending order by the given set of labels. -For example, `sort_by_label(foo, "bar")` would sort `foo` series by values of the label `bar` in these series. - -See also [sort_by_label](#sort_by_label) and [sort_by_label_numeric_desc](#sort_by_label_numeric_desc). - -#### sort_by_label_numeric - -`sort_by_label_numeric(q, "label1", ... "labelN")` is [label manipulation function](#label-manipulation-functions), which sorts series in ascending order by the given set of labels -using [numeric sort](https://www.gnu.org/software/coreutils/manual/html_node/Version-sort-is-not-the-same-as-numeric-sort.html). -For example, if `foo` series have `bar` label with values `1`, `101`, `15` and `2`, then `sort_by_label_numeric(foo, "bar")` would return series -in the following order of `bar` label values: `1`, `2`, `15` and `101`. - -See also [sort_by_label_numeric_desc](#sort_by_label_numeric_desc) and [sort_by_label](#sort_by_label). - -#### sort_by_label_numeric_desc - -`sort_by_label_numeric_desc(q, "label1", ... "labelN")` is [label manipulation function](#label-manipulation-functions), which sorts series in descending order -by the given set of labels using [numeric sort](https://www.gnu.org/software/coreutils/manual/html_node/Version-sort-is-not-the-same-as-numeric-sort.html). -For example, if `foo` series have `bar` label with values `1`, `101`, `15` and `2`, then `sort_by_label_numeric(foo, "bar")` -would return series in the following order of `bar` label values: `101`, `15`, `2` and `1`. - -See also [sort_by_label_numeric](#sort_by_label_numeric) and [sort_by_label_desc](#sort_by_label_desc). - - -### Aggregate functions - -**Aggregate functions** calculate aggregates over groups of [rollup results](#rollup-functions). - -Additional details: - -* By default, a single group is used for aggregation. Multiple independent groups can be set up by specifying grouping labels - in `by` and `without` modifiers. For example, `count(up) by (job)` would group [rollup results](#rollup-functions) by `job` label value - and calculate the [count](#count) aggregate function independently per each group, while `count(up) without (instance)` - would group [rollup results](#rollup-functions) by all the labels except `instance` before calculating [count](#count) aggregate function independently per each group. - Multiple labels can be put in `by` and `without` modifiers. -* If the aggregate function is applied directly to a [series_selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering), - then the [default_rollup()](#default_rollup) function is automatically applied before calculating the aggregate. - For example, `count(up)` is implicitly transformed to `count(default_rollup(up))`. -* Aggregate functions accept arbitrary number of args. For example, `avg(q1, q2, q3)` would return the average values for every point - across time series returned by `q1`, `q2` and `q3`. -* Aggregate functions support optional `limit N` suffix, which can be used for limiting the number of output groups. - For example, `sum(x) by (y) limit 3` limits the number of groups for the aggregation to 3. All the other groups are ignored. - -See also [implicit query conversions](#implicit-query-conversions). - -The list of supported aggregate functions: - -#### any - -`any(q) by (group_labels)` is [aggregate function](#aggregate-functions), which returns a single series per `group_labels` out of time series returned by `q`. - -See also [group](#group). - -#### avg - -`avg(q) by (group_labels)` is [aggregate function](#aggregate-functions), which returns the average value per `group_labels` for time series returned by `q`. -The aggregate is calculated individually per each group of points with the same timestamp. - -This function is supported by PromQL. - -#### bottomk - -`bottomk(k, q)` is [aggregate function](#aggregate-functions), which returns up to `k` points with the smallest values across all the time series returned by `q`. -The aggregate is calculated individually per each group of points with the same timestamp. - -This function is supported by PromQL. - -See also [topk](#topk), [bottomk_min](#bottomk_min) and [#bottomk_last](#bottomk_last). - -#### bottomk_avg - -`bottomk_avg(k, q, "other_label=other_value")` is [aggregate function](#aggregate-functions), which returns up to `k` time series from `q` with the smallest averages. -If an optional `other_label=other_value` arg is set, then the sum of the remaining time series is returned with the given label. -For example, `bottomk_avg(3, sum(process_resident_memory_bytes) by (job), "job=other")` would return up to 3 time series -with the smallest averages plus a time series with `{job="other"}` label with the sum of the remaining series if any. - -See also [topk_avg](#topk_avg). - -#### bottomk_last - -`bottomk_last(k, q, "other_label=other_value")` is [aggregate function](#aggregate-functions), which returns up to `k` time series from `q` with the smallest last values. -If an optional `other_label=other_value` arg is set, then the sum of the remaining time series is returned with the given label. -For example, `bottomk_max(3, sum(process_resident_memory_bytes) by (job), "job=other")` would return up to 3 time series -with the smallest maximums plus a time series with `{job="other"}` label with the sum of the remaining series if any. - -See also [topk_last](#topk_last). - -#### bottomk_max - -`bottomk_max(k, q, "other_label=other_value")` is [aggregate function](#aggregate-functions), which returns up to `k` time series from `q` with the smallest maximums. -If an optional `other_label=other_value` arg is set, then the sum of the remaining time series is returned with the given label. -For example, `bottomk_max(3, sum(process_resident_memory_bytes) by (job), "job=other")` would return up to 3 time series -with the smallest maximums plus a time series with `{job="other"}` label with the sum of the remaining series if any. - -See also [topk_max](#topk_max). - -#### bottomk_median - -`bottomk_median(k, q, "other_label=other_value")` is [aggregate function](#aggregate-functions), which returns up to `k` time series from `q` with the smallest medians. -If an optional`other_label=other_value` arg is set, then the sum of the remaining time series is returned with the given label. -For example, `bottomk_median(3, sum(process_resident_memory_bytes) by (job), "job=other")` would return up to 3 time series -with the smallest medians plus a time series with `{job="other"}` label with the sum of the remaining series if any. - -See also [topk_median](#topk_median). - -#### bottomk_min - -`bottomk_min(k, q, "other_label=other_value")` is [aggregate function](#aggregate-functions), which returns up to `k` time series from `q` with the smallest minimums. -If an optional `other_label=other_value` arg is set, then the sum of the remaining time series is returned with the given label. -For example, `bottomk_min(3, sum(process_resident_memory_bytes) by (job), "job=other")` would return up to 3 time series -with the smallest minimums plus a time series with `{job="other"}` label with the sum of the remaining series if any. - -See also [topk_min](#topk_min). - -#### count - -`count(q) by (group_labels)` is [aggregate function](#aggregate-functions), which returns the number of non-empty points per `group_labels` -for time series returned by `q`. The aggregate is calculated individually per each group of points with the same timestamp. - -This function is supported by PromQL. - -#### count_values - -`count_values("label", q)` is [aggregate function](#aggregate-functions), which counts the number of points with the same value -and stores the counts in a time series with an additional `label`, which contains each initial value. -The aggregate is calculated individually per each group of points with the same timestamp. - -This function is supported by PromQL. - -See also [count_values_over_time](#count_values_over_time) and [label_match](#label_match). - -#### distinct - -`distinct(q)` is [aggregate function](#aggregate-functions), which calculates the number of unique values per each group of points with the same timestamp. - -See also [distinct_over_time](#distinct_over_time). - -#### geomean - -`geomean(q)` is [aggregate function](#aggregate-functions), which calculates geometric mean per each group of points with the same timestamp. - -#### group - -`group(q) by (group_labels)` is [aggregate function](#aggregate-functions), which returns `1` per each `group_labels` for time series returned by `q`. - -This function is supported by PromQL. See also [any](#any). - -#### histogram - -`histogram(q)` is [aggregate function](#aggregate-functions), which calculates -[VictoriaMetrics histogram](https://valyala.medium.com/improving-histogram-usability-for-prometheus-and-grafana-bc7e5df0e350) -per each group of points with the same timestamp. Useful for visualizing big number of time series via a heatmap. -See [this article](https://medium.com/@valyala/improving-histogram-usability-for-prometheus-and-grafana-bc7e5df0e350) for more details. - -See also [histogram_over_time](#histogram_over_time) and [histogram_quantile](#histogram_quantile). - -#### limitk - -`limitk(k, q) by (group_labels)` is [aggregate function](#aggregate-functions), which returns up to `k` time series per each `group_labels` -out of time series returned by `q`. The returned set of time series remain the same across calls. - -See also [limit_offset](#limit_offset). - -#### mad - -`mad(q) by (group_labels)` is [aggregate function](#aggregate-functions), which returns the [Median absolute deviation](https://en.wikipedia.org/wiki/Median_absolute_deviation) -per each `group_labels` for all the time series returned by `q`. The aggregate is calculated individually per each group of points with the same timestamp. - -See also [range_mad](#range_mad), [mad_over_time](#mad_over_time), [outliers_mad](#outliers_mad) and [stddev](#stddev). - -#### max - -`max(q) by (group_labels)` is [aggregate function](#aggregate-functions), which returns the maximum value per each `group_labels` -for all the time series returned by `q`. The aggregate is calculated individually per each group of points with the same timestamp. - -This function is supported by PromQL. - -#### median - -`median(q) by (group_labels)` is [aggregate function](#aggregate-functions), which returns the median value per each `group_labels` -for all the time series returned by `q`. The aggregate is calculated individually per each group of points with the same timestamp. - -#### min - -`min(q) by (group_labels)` is [aggregate function](#aggregate-functions), which returns the minimum value per each `group_labels` -for all the time series returned by `q`. The aggregate is calculated individually per each group of points with the same timestamp. - -This function is supported by PromQL. - -#### mode - -`mode(q) by (group_labels)` is [aggregate function](#aggregate-functions), which returns [mode](https://en.wikipedia.org/wiki/Mode_(statistics)) -per each `group_labels` for all the time series returned by `q`. The aggregate is calculated individually per each group of points with the same timestamp. - -#### outliers_iqr - -`outliers_iqr(q)` is [aggregate function](#aggregate-functions), which returns time series from `q` with at least a single point -outside e.g. [Interquartile range outlier bounds](https://en.wikipedia.org/wiki/Interquartile_range) `[q25-1.5*iqr .. q75+1.5*iqr]` -comparing to other time series at the given point, where: -- `iqr` is an [Interquartile range](https://en.wikipedia.org/wiki/Interquartile_range) calculated independently per each point on the graph across `q` series. -- `q25` and `q75` are 25th and 75th [percentiles](https://en.wikipedia.org/wiki/Percentile) calculated independently per each point on the graph across `q` series. - -The `outliers_iqr()` is useful for detecting anomalous series in the group of series. For example, `outliers_iqr(temperature) by (country)` returns -per-country series with anomalous outlier values comparing to the rest of per-country series. - -See also [outliers_mad](#outliers_mad), [outliersk](#outliersk) and [outlier_iqr_over_time](#outlier_iqr_over_time). - -#### outliers_mad - -`outliers_mad(tolerance, q)` is [aggregate function](#aggregate-functions), which returns time series from `q` with at least -a single point outside [Median absolute deviation](https://en.wikipedia.org/wiki/Median_absolute_deviation) (aka MAD) multiplied by `tolerance`. -E.g. it returns time series with at least a single point below `median(q) - mad(q)` or a single point above `median(q) + mad(q)`. - -See also [outliers_iqr](#outliers_iqr), [outliersk](#outliersk) and [mad](#mad). - -#### outliersk - -`outliersk(k, q)` is [aggregate function](#aggregate-functions), which returns up to `k` time series with the biggest standard deviation (aka outliers) -out of time series returned by `q`. - -See also [outliers_iqr](#outliers_iqr) and [outliers_mad](#outliers_mad). - -#### quantile - -`quantile(phi, q) by (group_labels)` is [aggregate function](#aggregate-functions), which calculates `phi`-quantile per each `group_labels` -for all the time series returned by `q`. `phi` must be in the range `[0...1]`. -The aggregate is calculated individually per each group of points with the same timestamp. - -This function is supported by PromQL. - -See also [quantiles](#quantiles) and [histogram_quantile](#histogram_quantile). - -#### quantiles - -`quantiles("phiLabel", phi1, ..., phiN, q)` is [aggregate function](#aggregate-functions), which calculates `phi*`-quantiles for all the time series -returned by `q` and return them in time series with `{phiLabel="phi*"}` label. `phi*` must be in the range `[0...1]`. -The aggregate is calculated individually per each group of points with the same timestamp. - -See also [quantile](#quantile). - -#### share - -`share(q) by (group_labels)` is [aggregate function](#aggregate-functions), which returns shares in the range `[0..1]` -for every non-negative points returned by `q` per each timestamp, so the sum of shares per each `group_labels` equals 1. - -This function is useful for normalizing [histogram bucket](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#histogram) shares -into `[0..1]` range: - -```metricsql -share( - sum( - rate(http_request_duration_seconds_bucket[5m]) - ) by (le, vmrange) -) -``` - -See also [range_normalize](#range_normalize). - -#### stddev - -`stddev(q) by (group_labels)` is [aggregate function](#aggregate-functions), which calculates standard deviation per each `group_labels` -for all the time series returned by `q`. The aggregate is calculated individually per each group of points with the same timestamp. - -This function is supported by PromQL. - -#### stdvar - -`stdvar(q) by (group_labels)` is [aggregate function](#aggregate-functions), which calculates standard variance per each `group_labels` -for all the time series returned by `q`. The aggregate is calculated individually per each group of points with the same timestamp. - -This function is supported by PromQL. - -#### sum - -`sum(q) by (group_labels)` is [aggregate function](#aggregate-functions), which returns the sum per each `group_labels` -for all the time series returned by `q`. The aggregate is calculated individually per each group of points with the same timestamp. - -This function is supported by PromQL. - -#### sum2 - -`sum2(q) by (group_labels)` is [aggregate function](#aggregate-functions), which calculates the sum of squares per each `group_labels` -for all the time series returned by `q`. The aggregate is calculated individually per each group of points with the same timestamp. - -#### topk - -`topk(k, q)` is [aggregate function](#aggregate-functions), which returns up to `k` points with the biggest values across all the time series returned by `q`. -The aggregate is calculated individually per each group of points with the same timestamp. - -This function is supported by PromQL. - -See also [bottomk](#bottomk), [topk_max](#topk_max) and [topk_last](#topk_last). - -#### topk_avg - -`topk_avg(k, q, "other_label=other_value")` is [aggregate function](#aggregate-functions), which returns up to `k` time series from `q` with the biggest averages. -If an optional `other_label=other_value` arg is set, then the sum of the remaining time series is returned with the given label. -For example, `topk_avg(3, sum(process_resident_memory_bytes) by (job), "job=other")` would return up to 3 time series with the biggest averages -plus a time series with `{job="other"}` label with the sum of the remaining series if any. - -See also [bottomk_avg](#bottomk_avg). - -#### topk_last - -`topk_last(k, q, "other_label=other_value")` is [aggregate function](#aggregate-functions), which returns up to `k` time series from `q` with the biggest last values. -If an optional `other_label=other_value` arg is set, then the sum of the remaining time series is returned with the given label. -For example, `topk_max(3, sum(process_resident_memory_bytes) by (job), "job=other")` would return up to 3 time series with the biggest maximums -plus a time series with `{job="other"}` label with the sum of the remaining series if any. - -See also [bottomk_last](#bottomk_last). - -#### topk_max - -`topk_max(k, q, "other_label=other_value")` is [aggregate function](#aggregate-functions), which returns up to `k` time series from `q` with the biggest maximums. -If an optional `other_label=other_value` arg is set, then the sum of the remaining time series is returned with the given label. -For example, `topk_max(3, sum(process_resident_memory_bytes) by (job), "job=other")` would return up to 3 time series with the biggest maximums -plus a time series with `{job="other"}` label with the sum of the remaining series if any. - -See also [bottomk_max](#bottomk_max). - -#### topk_median - -`topk_median(k, q, "other_label=other_value")` is [aggregate function](#aggregate-functions), which returns up to `k` time series from `q` with the biggest medians. -If an optional `other_label=other_value` arg is set, then the sum of the remaining time series is returned with the given label. -For example, `topk_median(3, sum(process_resident_memory_bytes) by (job), "job=other")` would return up to 3 time series with the biggest medians -plus a time series with `{job="other"}` label with the sum of the remaining series if any. - -See also [bottomk_median](#bottomk_median). - -#### topk_min - -`topk_min(k, q, "other_label=other_value")` is [aggregate function](#aggregate-functions), which returns up to `k` time series from `q` with the biggest minimums. -If an optional `other_label=other_value` arg is set, then the sum of the remaining time series is returned with the given label. -For example, `topk_min(3, sum(process_resident_memory_bytes) by (job), "job=other")` would return up to 3 time series with the biggest minimums -plus a time series with `{job="other"}` label with the sum of the remaining series if any. - -See also [bottomk_min](#bottomk_min). - -#### zscore - -`zscore(q) by (group_labels)` is [aggregate function](#aggregate-functions), which returns [z-score](https://en.wikipedia.org/wiki/Standard_score) values -per each `group_labels` for all the time series returned by `q`. The aggregate is calculated individually per each group of points with the same timestamp. -This function is useful for detecting anomalies in the group of related time series. - -See also [zscore_over_time](#zscore_over_time), [range_trim_zscore](#range_trim_zscore) and [outliers_iqr](#outliers_iqr). - -## Subqueries - -MetricsQL supports and extends PromQL subqueries. See [this article](https://valyala.medium.com/prometheus-subqueries-in-victoriametrics-9b1492b720b3) for details. -Any [rollup function](#rollup-functions) for something other than [series selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering) form a subquery. -Nested rollup functions can be implicit thanks to the [implicit query conversions](#implicit-query-conversions). -For example, `delta(sum(m))` is implicitly converted to `delta(sum(default_rollup(m))[1i:1i])`, so it becomes a subquery, -since it contains [default_rollup](#default_rollup) nested into [delta](#delta). -This behavior can be disabled or logged via `-search.disableImplicitConversion` and `-search.logImplicitConversion` command-line flags -starting from [`v1.101.0` release](https://docs.victoriametrics.com/victoriametrics/changelog/). - -VictoriaMetrics performs subqueries in the following way: - -* It calculates the inner rollup function using the `step` value from the outer rollup function. - For example, for expression `max_over_time(rate(http_requests_total[5m])[1h:30s])` the inner function `rate(http_requests_total[5m])` - is calculated with `step=30s`. The resulting data points are aligned by the `step`. -* It calculates the outer rollup function over the results of the inner rollup function using the `step` value - passed by Grafana to [/api/v1/query_range](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#range-query). - -## Implicit query conversions - -VictoriaMetrics performs the following implicit conversions for incoming queries before starting the calculations: - -* If lookbehind window in square brackets is missing inside [rollup function](#rollup-functions), then it is automatically set to the following value: - - To `step` value passed to [/api/v1/query_range](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#range-query) or [/api/v1/query](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#instant-query) - for all the [rollup functions](#rollup-functions) except of [default_rollup](#default_rollup) and [rate](#rate). This value is known as `$__interval` in Grafana or `1i` in MetricsQL. - For example, `avg_over_time(temperature)` is automatically transformed to `avg_over_time(temperature[1i])`. - - To the `max(step, scrape_interval)`, where `scrape_interval` is the interval between [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) - for [default_rollup](#default_rollup) and [rate](#rate) functions. This allows avoiding unexpected gaps on the graph when `step` is smaller than `scrape_interval`. -* All the [series selectors](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering), - which aren't wrapped into [rollup functions](#rollup-functions), are automatically wrapped into [default_rollup](#default_rollup) function. - Examples: - * `foo` is transformed to `default_rollup(foo)` - * `foo + bar` is transformed to `default_rollup(foo) + default_rollup(bar)` - * `count(up)` is transformed to `count(default_rollup(up))`, because [count](#count) isn't a [rollup function](#rollup-functions) - - it is [aggregate function](#aggregate-functions) - * `abs(temperature)` is transformed to `abs(default_rollup(temperature))`, because [abs](#abs) isn't a [rollup function](#rollup-functions) - - it is [transform function](#transform-functions) -* If `step` in square brackets is missing inside [subquery](#subqueries), then `1i` step is automatically added there. - For example, `avg_over_time(rate(http_requests_total[5m])[1h])` is automatically converted to `avg_over_time(rate(http_requests_total[5m])[1h:1i])`. -* If something other than [series selector](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering) - is passed to [rollup function](#rollup-functions), then a [subquery](#subqueries) with `1i` lookbehind window and `1i` step is automatically formed. - For example, `rate(sum(up))` is automatically converted to `rate((sum(default_rollup(up)))[1i:1i])`. - This behavior can be disabled or logged via `-search.disableImplicitConversion` and `-search.logImplicitConversion` command-line flags - starting from [`v1.102.0-rc2` release](https://docs.victoriametrics.com/victoriametrics/changelog/changelog_2024/#v11020-rc2). diff --git a/app/vlselect/vmui/assets/index-721xTF8u.js b/app/vlselect/vmui/assets/index-721xTF8u.js deleted file mode 100644 index 211fe5240a..0000000000 --- a/app/vlselect/vmui/assets/index-721xTF8u.js +++ /dev/null @@ -1,208 +0,0 @@ -var zi=Object.defineProperty;var Hi=(t,n,r)=>n in t?zi(t,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[n]=r;var we=(t,n,r)=>Hi(t,typeof n!="symbol"?n+"":n,r);import{d as U,t as Vi,a as qi,u as Ui,r as Bi,q as Fr,g as st,K as yt,h as Et,T as M,b as e,x as $e,N as Yo,c as I,A as q,y as A,e as N,k as V,f as W,i as qn,j as ht,$ as pt,M as zr,D as Un,I as ji,l as oe,F as Hr,O as Vr,m as ln,n as Bt,o as jt,_ as Qi,L as Bn,H as qr,R as Ur,p as fe,s as jn,v as Yi,w as Gi,z as Wi,B as Ji}from"./vendor-V4vnRsM-.js";(function(){const n=document.createElement("link").relList;if(n&&n.supports&&n.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))a(o);new MutationObserver(o=>{for(const s of o)if(s.type==="childList")for(const i of s.addedNodes)i.tagName==="LINK"&&i.rel==="modulepreload"&&a(i)}).observe(document,{childList:!0,subtree:!0});function r(o){const s={};return o.integrity&&(s.integrity=o.integrity),o.referrerPolicy&&(s.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?s.credentials="include":o.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function a(o){if(o.ep)return;o.ep=!0;const s=r(o);fetch(o.href,s)}})();U.extend(Vi);U.extend(qi);U.extend(Ui);U.extend(Bi);var dt=(t=>(t.victoriametrics="victoriametrics",t.victorialogs="victorialogs",t.vmanomaly="vmanomaly",t))(dt||{});const Qt="victorialogs",Ki=Qt==="victorialogs",Zi=Qt==="vmanomaly",Z={home:"/",metrics:"/metrics",dashboards:"/dashboards",cardinality:"/cardinality",topQueries:"/top-queries",trace:"/trace",withTemplate:"/expand-with-exprs",relabel:"/relabeling",logs:"/logs",activeQueries:"/active-queries",queryAnalyzer:"/query-analyzer",icons:"/icons",anomaly:"/anomaly",query:"/query",rawQuery:"/raw-query",downsamplingDebug:"/downsampling-filters-debug",retentionDebug:"/retention-filters-debug"},Kt={header:{tenant:!0,stepControl:!1,timeSelector:!1,executionControls:!1}},gt={[Z.home]:{title:"Query",...Kt},[Z.rawQuery]:{title:"Raw query",...Kt},[Z.metrics]:{title:"Explore Prometheus metrics",header:{tenant:!0,stepControl:!0,timeSelector:!0}},[Z.cardinality]:{title:"Explore cardinality",header:{tenant:!0,cardinalityDatePicker:!0}},[Z.topQueries]:{title:"Top queries",header:{tenant:!0}},[Z.trace]:{title:"Trace analyzer",header:{}},[Z.queryAnalyzer]:{title:"Query analyzer",header:{}},[Z.dashboards]:{title:"Dashboards",...Kt},[Z.withTemplate]:{title:"WITH templates",header:{}},[Z.relabel]:{title:"Metric relabel debug",header:{}},[Z.logs]:{title:"Logs Explorer",header:{}},[Z.activeQueries]:{title:"Active Queries",header:{}},[Z.icons]:{title:"Icons",header:{}},[Z.anomaly]:{title:"Anomaly exploration",...Kt},[Z.query]:{title:"Query",...Kt},[Z.downsamplingDebug]:{title:"Downsampling filters debug",header:{}},[Z.retentionDebug]:{title:"Retention filters debug",header:{}}},cn=()=>{var n;const t=((n=document.getElementById("root"))==null?void 0:n.dataset.params)||"{}";try{return JSON.parse(t)}catch(r){return console.error(r),{}}},Ee=()=>!!Object.keys(cn()).length,Go=/(\/select\/)(\d+|\d.+)(\/)(.+)/,Wo=(t,n)=>t.replace(Go,`$1${n}/$4`),dn=t=>{var n;return((n=t.match(Go))==null?void 0:n[2])||""},Le=(t,n)=>{n?window.localStorage.setItem(t,JSON.stringify({value:n})):Br([t]),window.dispatchEvent(new Event("storage"))},Ae=t=>{var r;const n=window.localStorage.getItem(t);if(n!==null)try{return(r=JSON.parse(n))==null?void 0:r.value}catch{return n}},Br=t=>t.forEach(n=>window.localStorage.removeItem(n)),Xi=t=>{const{serverURL:n}=cn(),r=Ae("SERVER_URL"),a=window.location.href.replace(/(\/(select\/)?vmui\/.*|\/#\/.*)/,""),o=`${window.location.origin}${window.location.pathname.replace(/^\/vmui/,"")}`,s=window.location.href.replace(/\/(?:prometheus\/)?(?:graph|vmui)\/.*/,"/prometheus"),i=n||r||s;switch(Qt){case dt.victorialogs:return a;case dt.vmanomaly:return r||o;default:return t?Wo(i,t):i}},In=10,Jo=25,Ko={table:100,chart:20,code:1e3},Pn=[{id:"small",isDefault:!0,height:()=>window.innerHeight*.2},{id:"medium",height:()=>window.innerHeight*.4},{id:"large",height:()=>window.innerHeight*.8}],jr=["min","median","max"],ze=(t,n)=>{const r=window.location.hash.split("?")[1],a=Fr.parse(r,{ignoreQueryPrefix:!0});return st(a,t,n||"")},Zo=()=>{var r;const n=((r=(window.location.hash.split("?")[1]||"").match(/g\d+\.expr/g))==null?void 0:r.length)||1;return new Array(n>In?In:n).fill(1).map((a,o)=>ze(`g${o}.expr`,""))};var ne=(t=>(t.yhat="yhat",t.yhatUpper="yhat_upper",t.yhatLower="yhat_lower",t.anomaly="vmui_anomalies_points",t.training="vmui_training_data",t.actual="actual",t.anomalyScore="anomaly_score",t))(ne||{}),Ne=(t=>(t.table="table",t.chart="chart",t.code="code",t))(Ne||{}),Ce=(t=>(t.emptyServer="Please enter Server URL",t.validServer="Please provide a valid Server URL",t.validQuery="Please enter a valid Query and execute it",t.traceNotFound="Not found the tracing information",t.emptyTitle="Please enter title",t.positiveNumber="Please enter positive number",t.validStep="Please enter a valid step",t.unknownType="Unknown server response format: must have 'errorType'",t))(Ce||{}),Ge=(t=>(t.system="system",t.light="light",t.dark="dark",t))(Ge||{}),Oe=(t=>(t.empty="empty",t.metricsql="metricsql",t.label="label",t.labelValue="labelValue",t))(Oe||{});const tt=t=>getComputedStyle(document.documentElement).getPropertyValue(`--${t}`),Rt=(t,n)=>{document.documentElement.style.setProperty(`--${t}`,n)},Dn=()=>window.matchMedia("(prefers-color-scheme: dark)").matches,el=t=>t===Ge.system&&Dn()||t===Ge.dark,Qr=t=>{let n;try{n=new URL(t)}catch{return!1}return n.protocol==="http:"||n.protocol==="https:"},Xo=t=>t.replace(/\/$/,""),tl=(t,n)=>{if(Array.from(t.entries()).length!==Array.from(n.entries()).length)return!1;for(const[r,a]of t)if(n.get(r)!==a)return!1;return!0},nl=t=>{try{const n=t.match(/\/api\/v1\/[^?]+/);return n?n[0]:null}catch(n){return console.error("Invalid URL:",n),null}},to=ze("g0.tenantID",""),rl={serverUrl:Xo(Xi(to)),tenantId:to,theme:Ae("THEME")||Ge.system,isDarkTheme:null,flags:{},appConfig:{}};function al(t,n){switch(n.type){case"SET_SERVER":return{...t,serverUrl:Xo(n.payload)};case"SET_TENANT_ID":return{...t,tenantId:n.payload};case"SET_THEME":return Le("THEME",n.payload),{...t,theme:n.payload};case"SET_DARK_THEME":return{...t,isDarkTheme:el(t.theme)};case"SET_FLAGS":return{...t,flags:n.payload};case"SET_APP_CONFIG":return{...t,appConfig:n.payload};default:throw new Error}}const Yr=yt({}),se=()=>$e(Yr).state,xt=()=>$e(Yr).dispatch,ol=Object.entries(rl).reduce((t,[n,r])=>({...t,[n]:ze(n)||r}),{}),sl=({children:t})=>{const[n,r]=Et(al,ol),a=M(()=>({state:n,dispatch:r}),[n,r]);return e(Yr.Provider,{value:a,children:t})},kt="YYYY-MM-DD",qe="YYYY-MM-DD HH:mm:ss",On="YYYY-MM-DD HH:mm:ss:SSS (Z)",Gr="YYYY-MM-DD[T]HH:mm:ss",Wr="YYYY-MM-DD_HHmmss",il=["Africa/Abidjan","Africa/Accra","Africa/Addis_Ababa","Africa/Algiers","Africa/Asmera","Africa/Bamako","Africa/Bangui","Africa/Banjul","Africa/Bissau","Africa/Blantyre","Africa/Brazzaville","Africa/Bujumbura","Africa/Cairo","Africa/Casablanca","Africa/Ceuta","Africa/Conakry","Africa/Dakar","Africa/Dar_es_Salaam","Africa/Djibouti","Africa/Douala","Africa/El_Aaiun","Africa/Freetown","Africa/Gaborone","Africa/Harare","Africa/Johannesburg","Africa/Juba","Africa/Kampala","Africa/Khartoum","Africa/Kigali","Africa/Kinshasa","Africa/Lagos","Africa/Libreville","Africa/Lome","Africa/Luanda","Africa/Lubumbashi","Africa/Lusaka","Africa/Malabo","Africa/Maputo","Africa/Maseru","Africa/Mbabane","Africa/Mogadishu","Africa/Monrovia","Africa/Nairobi","Africa/Ndjamena","Africa/Niamey","Africa/Nouakchott","Africa/Ouagadougou","Africa/Porto-Novo","Africa/Sao_Tome","Africa/Tripoli","Africa/Tunis","Africa/Windhoek","America/Adak","America/Anchorage","America/Anguilla","America/Antigua","America/Araguaina","America/Argentina/La_Rioja","America/Argentina/Rio_Gallegos","America/Argentina/Salta","America/Argentina/San_Juan","America/Argentina/San_Luis","America/Argentina/Tucuman","America/Argentina/Ushuaia","America/Aruba","America/Asuncion","America/Bahia","America/Bahia_Banderas","America/Barbados","America/Belem","America/Belize","America/Blanc-Sablon","America/Boa_Vista","America/Bogota","America/Boise","America/Buenos_Aires","America/Cambridge_Bay","America/Campo_Grande","America/Cancun","America/Caracas","America/Catamarca","America/Cayenne","America/Cayman","America/Chicago","America/Chihuahua","America/Coral_Harbour","America/Cordoba","America/Costa_Rica","America/Creston","America/Cuiaba","America/Curacao","America/Danmarkshavn","America/Dawson","America/Dawson_Creek","America/Denver","America/Detroit","America/Dominica","America/Edmonton","America/Eirunepe","America/El_Salvador","America/Fort_Nelson","America/Fortaleza","America/Glace_Bay","America/Godthab","America/Goose_Bay","America/Grand_Turk","America/Grenada","America/Guadeloupe","America/Guatemala","America/Guayaquil","America/Guyana","America/Halifax","America/Havana","America/Hermosillo","America/Indiana/Knox","America/Indiana/Marengo","America/Indiana/Petersburg","America/Indiana/Tell_City","America/Indiana/Vevay","America/Indiana/Vincennes","America/Indiana/Winamac","America/Indianapolis","America/Inuvik","America/Iqaluit","America/Jamaica","America/Jujuy","America/Juneau","America/Kentucky/Monticello","America/Kralendijk","America/La_Paz","America/Lima","America/Los_Angeles","America/Louisville","America/Lower_Princes","America/Maceio","America/Managua","America/Manaus","America/Marigot","America/Martinique","America/Matamoros","America/Mazatlan","America/Mendoza","America/Menominee","America/Merida","America/Metlakatla","America/Mexico_City","America/Miquelon","America/Moncton","America/Monterrey","America/Montevideo","America/Montreal","America/Montserrat","America/Nassau","America/New_York","America/Nipigon","America/Nome","America/Noronha","America/North_Dakota/Beulah","America/North_Dakota/Center","America/North_Dakota/New_Salem","America/Ojinaga","America/Panama","America/Pangnirtung","America/Paramaribo","America/Phoenix","America/Port-au-Prince","America/Port_of_Spain","America/Porto_Velho","America/Puerto_Rico","America/Punta_Arenas","America/Rainy_River","America/Rankin_Inlet","America/Recife","America/Regina","America/Resolute","America/Rio_Branco","America/Santa_Isabel","America/Santarem","America/Santiago","America/Santo_Domingo","America/Sao_Paulo","America/Scoresbysund","America/Sitka","America/St_Barthelemy","America/St_Johns","America/St_Kitts","America/St_Lucia","America/St_Thomas","America/St_Vincent","America/Swift_Current","America/Tegucigalpa","America/Thule","America/Thunder_Bay","America/Tijuana","America/Toronto","America/Tortola","America/Vancouver","America/Whitehorse","America/Winnipeg","America/Yakutat","America/Yellowknife","Antarctica/Casey","Antarctica/Davis","Antarctica/DumontDUrville","Antarctica/Macquarie","Antarctica/Mawson","Antarctica/McMurdo","Antarctica/Palmer","Antarctica/Rothera","Antarctica/Syowa","Antarctica/Troll","Antarctica/Vostok","Arctic/Longyearbyen","Asia/Aden","Asia/Almaty","Asia/Amman","Asia/Anadyr","Asia/Aqtau","Asia/Aqtobe","Asia/Ashgabat","Asia/Atyrau","Asia/Baghdad","Asia/Bahrain","Asia/Baku","Asia/Bangkok","Asia/Barnaul","Asia/Beirut","Asia/Bishkek","Asia/Brunei","Asia/Calcutta","Asia/Chita","Asia/Choibalsan","Asia/Colombo","Asia/Damascus","Asia/Dhaka","Asia/Dili","Asia/Dubai","Asia/Dushanbe","Asia/Famagusta","Asia/Gaza","Asia/Hebron","Asia/Hong_Kong","Asia/Hovd","Asia/Irkutsk","Asia/Jakarta","Asia/Jayapura","Asia/Jerusalem","Asia/Kabul","Asia/Kamchatka","Asia/Karachi","Asia/Katmandu","Asia/Khandyga","Asia/Krasnoyarsk","Asia/Kuala_Lumpur","Asia/Kuching","Asia/Kuwait","Asia/Macau","Asia/Magadan","Asia/Makassar","Asia/Manila","Asia/Muscat","Asia/Nicosia","Asia/Novokuznetsk","Asia/Novosibirsk","Asia/Omsk","Asia/Oral","Asia/Phnom_Penh","Asia/Pontianak","Asia/Pyongyang","Asia/Qatar","Asia/Qostanay","Asia/Qyzylorda","Asia/Rangoon","Asia/Riyadh","Asia/Saigon","Asia/Sakhalin","Asia/Samarkand","Asia/Seoul","Asia/Shanghai","Asia/Singapore","Asia/Srednekolymsk","Asia/Taipei","Asia/Tashkent","Asia/Tbilisi","Asia/Tehran","Asia/Thimphu","Asia/Tokyo","Asia/Tomsk","Asia/Ulaanbaatar","Asia/Urumqi","Asia/Ust-Nera","Asia/Vientiane","Asia/Vladivostok","Asia/Yakutsk","Asia/Yekaterinburg","Asia/Yerevan","Atlantic/Azores","Atlantic/Bermuda","Atlantic/Canary","Atlantic/Cape_Verde","Atlantic/Faeroe","Atlantic/Madeira","Atlantic/Reykjavik","Atlantic/South_Georgia","Atlantic/St_Helena","Atlantic/Stanley","Australia/Adelaide","Australia/Brisbane","Australia/Broken_Hill","Australia/Currie","Australia/Darwin","Australia/Eucla","Australia/Hobart","Australia/Lindeman","Australia/Lord_Howe","Australia/Melbourne","Australia/Perth","Australia/Sydney","Europe/Amsterdam","Europe/Andorra","Europe/Astrakhan","Europe/Athens","Europe/Belgrade","Europe/Berlin","Europe/Bratislava","Europe/Brussels","Europe/Bucharest","Europe/Budapest","Europe/Busingen","Europe/Chisinau","Europe/Copenhagen","Europe/Dublin","Europe/Gibraltar","Europe/Guernsey","Europe/Helsinki","Europe/Isle_of_Man","Europe/Istanbul","Europe/Jersey","Europe/Kaliningrad","Europe/Kiev","Europe/Kirov","Europe/Lisbon","Europe/Ljubljana","Europe/London","Europe/Luxembourg","Europe/Madrid","Europe/Malta","Europe/Mariehamn","Europe/Minsk","Europe/Monaco","Europe/Moscow","Europe/Oslo","Europe/Paris","Europe/Podgorica","Europe/Prague","Europe/Riga","Europe/Rome","Europe/Samara","Europe/San_Marino","Europe/Sarajevo","Europe/Saratov","Europe/Simferopol","Europe/Skopje","Europe/Sofia","Europe/Stockholm","Europe/Tallinn","Europe/Tirane","Europe/Ulyanovsk","Europe/Uzhgorod","Europe/Vaduz","Europe/Vatican","Europe/Vienna","Europe/Vilnius","Europe/Volgograd","Europe/Warsaw","Europe/Zagreb","Europe/Zaporozhye","Europe/Zurich","Indian/Antananarivo","Indian/Chagos","Indian/Christmas","Indian/Cocos","Indian/Comoro","Indian/Kerguelen","Indian/Mahe","Indian/Maldives","Indian/Mauritius","Indian/Mayotte","Indian/Reunion","Pacific/Apia","Pacific/Auckland","Pacific/Bougainville","Pacific/Chatham","Pacific/Easter","Pacific/Efate","Pacific/Enderbury","Pacific/Fakaofo","Pacific/Fiji","Pacific/Funafuti","Pacific/Galapagos","Pacific/Gambier","Pacific/Guadalcanal","Pacific/Guam","Pacific/Honolulu","Pacific/Johnston","Pacific/Kiritimati","Pacific/Kosrae","Pacific/Kwajalein","Pacific/Majuro","Pacific/Marquesas","Pacific/Midway","Pacific/Nauru","Pacific/Niue","Pacific/Norfolk","Pacific/Noumea","Pacific/Pago_Pago","Pacific/Palau","Pacific/Pitcairn","Pacific/Ponape","Pacific/Port_Moresby","Pacific/Rarotonga","Pacific/Saipan","Pacific/Tahiti","Pacific/Tarawa","Pacific/Tongatapu","Pacific/Truk","Pacific/Wake","Pacific/Wallis"],ll=window.innerWidth/4,cl=window.innerWidth/40,no={min:1,max:1578e8},ro=Intl.supportedValuesOf,dl=ro?ro("timeZone"):il,Jr=[{long:"years",short:"y",possible:"year"},{long:"weeks",short:"w",possible:"week"},{long:"days",short:"d",possible:"day"},{long:"hours",short:"h",possible:"hour"},{long:"minutes",short:"m",possible:"min"},{long:"seconds",short:"s",possible:"sec"},{long:"milliseconds",short:"ms",possible:"millisecond"}],ml=Jr.map(t=>t.short),xn=t=>Math.round(t*1e3)/1e3,Kr=t=>Qn(U.duration(t,"seconds").asMilliseconds()),Er=t=>{let n=xn(t);const r=Math.round(t);return t>=100&&(n=r-r%10),t<100&&t>=10&&(n=r-r%5),t<10&&t>=1&&(n=r),t<1&&t>.01&&(n=Math.round(t*40)/40),Kr(n||.001).replace(/\s/g,"")},es=t=>{const n=t.match(/\d+/g),r=t.match(/[a-zA-Z]+/g);if(r&&n&&ml.includes(r[0]))return{[r[0]]:n[0]}},Zr=t=>{const n=Jr.map(s=>s.short).join("|"),r=new RegExp(`\\d+(\\.\\d+)?[${n}]+`,"g"),o=(t.match(r)||[]).reduce((s,i)=>{const l=es(i);return l?{...s,...l}:{...s}},{});return U.duration(o).asSeconds()},ul=[Ne.table,Ne.code],mn=(t,n,r)=>r&&ul.includes(r)?Er(t):Er(t/(n?cl:ll)),Nt=(t,n)=>{const r=(n||U().toDate()).valueOf()/1e3,a=Zr(t);return{start:r-a,end:r,step:mn(a),date:ts(n||U().toDate())}},hl=t=>U(t).utcOffset(0,!0).toDate(),ts=t=>U.tz(t).utc().format(Gr),Ft=t=>U.tz(t).format(Gr),pl=()=>U().utc().format(Gr),Qn=t=>{const n=Math.floor(t%1e3),r=Math.floor(t/1e3%60),a=Math.floor(t/1e3/60%60),o=Math.floor(t/1e3/3600%24),s=Math.floor(t/(1e3*60*60*24)),i=["d","h","m","s","ms"];return[s,o,a,r,n].map((c,d)=>c?`${c}${i[d]}`:"").filter(c=>c).join("")},gl=t=>{const n=t.to.valueOf()-t.from.valueOf();return Qn(n)},We=t=>{const n=U(t*1e3);return n.isValid()?n.toDate():new Date},vl=()=>U().tz().subtract(1,"day").endOf("day").toDate(),fl=()=>U().tz().endOf("day").toDate(),nn=[{title:"Last 5 minutes",duration:"5m",isDefault:Ki},{title:"Last 15 minutes",duration:"15m"},{title:"Last 30 minutes",duration:"30m",isDefault:!1},{title:"Last 1 hour",duration:"1h"},{title:"Last 3 hours",duration:"3h"},{title:"Last 6 hours",duration:"6h"},{title:"Last 12 hours",duration:"12h"},{title:"Last 24 hours",duration:"24h"},{title:"Last 2 days",duration:"2d"},{title:"Last 7 days",duration:"7d"},{title:"Last 30 days",duration:"30d"},{title:"Last 90 days",duration:"90d"},{title:"Last 180 days",duration:"180d"},{title:"Last 1 year",duration:"1y"},{title:"Yesterday",duration:"1d",until:vl},{title:"Today",duration:"1d",until:fl}].map(t=>({id:t.title.replace(/\s/g,"_").toLocaleLowerCase(),until:t.until?t.until:()=>U().tz().toDate(),...t})),Xr=({relativeTimeId:t,defaultDuration:n,defaultEndInput:r})=>{var i;const a=(i=nn.find(l=>l.isDefault))==null?void 0:i.id,o=t||ze("g0.relative_time",a),s=nn.find(l=>l.id===o);return{relativeTimeId:s?o:"none",duration:s?s.duration:n,endInput:s?s.until():r}},en=t=>`UTC${U().tz(t).format("Z")}`,ao=(t="")=>{const n=new RegExp(t,"i");return dl.reduce((r,a)=>{const o=(a.match(/^(.*?)\//)||[])[1]||"unknown",s=en(a),i=s.replace(/UTC|0/,""),l=a.replace(/[/_]/g," "),c={region:a,utc:s,search:`${a} ${s} ${l} ${i}`},d=!t||t&&n.test(c.search);return d&&r[o]?r[o].push(c):d&&(r[o]=[c]),r},{})},ns=t=>{U.tz.setDefault(t)},_l=t=>{try{return U().tz(t),!0}catch{return!1}},rs=()=>{const t=U.tz.guess(),n=_l(t);return{isValid:n,title:n?`Browser Time (${t})`:"Browser timezone (UTC)",region:n?t:"UTC"}},oo=t=>{if(!t)return 0n;const n=U(t).valueOf();if(!t.includes("."))return BigInt(n)*1000000n;const r=t.match(/\.(\d+)Z/);if(!r)return BigInt(n)*1000000n;let a=r[1];a=a.padEnd(9,"0");const o=parseInt(a.slice(3),10);return BigInt(n)*1000000n+BigInt(o)},as=Ae("TIMEZONE")||rs().region;ns(as);const os=()=>{const t=ze("g0.range_input"),{duration:n,endInput:r,relativeTimeId:a}=Xr({defaultDuration:t||"1h",defaultEndInput:hl(ze("g0.end_input",pl())),relativeTimeId:t?ze("g0.relative_time","none"):void 0});return{duration:n,period:Nt(n,r),relativeTime:a}},bl={...os(),timezone:as};function yl(t,n){switch(n.type){case"SET_TIME_STATE":return{...t,...n.payload};case"SET_DURATION":return{...t,duration:n.payload,period:Nt(n.payload,We(t.period.end)),relativeTime:"none"};case"SET_RELATIVE_TIME":return{...t,duration:n.payload.duration,period:Nt(n.payload.duration,n.payload.until),relativeTime:n.payload.id};case"SET_PERIOD":const r=gl(n.payload);return{...t,duration:r,period:Nt(r,n.payload.to),relativeTime:"none"};case"RUN_QUERY":const{duration:a,endInput:o}=Xr({relativeTimeId:t.relativeTime,defaultDuration:t.duration,defaultEndInput:We(t.period.end)});return{...t,period:Nt(a,o)};case"RUN_QUERY_TO_NOW":return{...t,period:Nt(t.duration)};case"SET_TIMEZONE":return ns(n.payload),Le("TIMEZONE",n.payload),t.defaultTimezone&&Le("DISABLED_DEFAULT_TIMEZONE",n.payload!==t.defaultTimezone),{...t,timezone:n.payload};case"SET_DEFAULT_TIMEZONE":return{...t,defaultTimezone:n.payload};default:throw new Error}}const ea=yt({}),ge=()=>$e(ea).state,Be=()=>$e(ea).dispatch,wl=({children:t})=>{const[n,r]=Et(yl,bl),a=M(()=>({state:n,dispatch:r}),[n,r]);return e(ea.Provider,{value:a,children:t})},Yn=t=>{const n=Ae(t);return n?JSON.parse(n):{}},ss=(t,n,r)=>{const a=Yn(t);Le(t,JSON.stringify({...a,[n]:r}))},Zt=(t,n)=>Yn(t)[n]||[],Cl=(t,n)=>{const r=n.map(c=>c.values[c.index]),a=Yn(t),o=a.QUERY_HISTORY||[];o[0]||(o[0]=[]);const s=o[0],i=Jo*In;r.forEach(c=>{!s.includes(c)&&c&&s.unshift(c),s.length>i&&s.pop()});const l={...a,QUERY_HISTORY:[s]};Le(t,JSON.stringify(l))},Nl=(t,n)=>{ss(t,"QUERY_FAVORITES",n)},Sl=(t,n)=>{const r=Yn(t);Le(t,JSON.stringify({...r,[n]:[]}))},is=(t,n)=>{const r=n||{values:[]},a=t===r.values[r.values.length-1],o=!a&&t?[...r.values,t]:r.values;return o.length>Jo&&o.shift(),{index:r.values.length-Number(a),values:o}},kl=()=>{const t=n=>{const r=Ae(n);if(r){const a=JSON.parse(r);ss("METRICS_QUERY_HISTORY",n,a),Br([n])}};t("QUERY_HISTORY"),t("QUERY_FAVORITES")};kl();const Tt={displayResults:50,queryLimit:1e3,cacheLimit:1e3};class Tl{constructor(){we(this,"maxSize");we(this,"map");this.maxSize=Tt.cacheLimit,this.map=new Map}get(n){for(const[r,a]of this.map){const o=JSON.parse(r),s=o.start===n.start&&o.end===n.end,i=o.type===n.type,l=n.value&&o.value&&n.value.includes(o.value),c=o.match===n.match||l,d=a.length=this.maxSize){const a=this.map.keys().next().value;a&&this.map.delete(a)}this.map.set(JSON.stringify(n),r)}}const so=Zo(),Ll={query:so,queryHistory:so.map(t=>({index:0,values:[t]})),autocomplete:Ae("AUTOCOMPLETE")||!1,autocompleteQuick:!1,autocompleteCache:new Tl,metricsQLFunctions:[]};function Al(t,n){switch(n.type){case"SET_QUERY":return{...t,query:n.payload.map(r=>r)};case"SET_QUERY_HISTORY":return Cl(n.payload.key,n.payload.history),{...t,queryHistory:n.payload.history};case"SET_QUERY_HISTORY_BY_INDEX":return t.queryHistory.splice(n.payload.queryNumber,1,n.payload.value),{...t,queryHistory:t.queryHistory};case"TOGGLE_AUTOCOMPLETE":return Le("AUTOCOMPLETE",!t.autocomplete),{...t,autocomplete:!t.autocomplete};case"SET_AUTOCOMPLETE_QUICK":return{...t,autocompleteQuick:n.payload};case"SET_AUTOCOMPLETE_CACHE":return t.autocompleteCache.put(n.payload.key,n.payload.value),{...t};case"SET_METRICSQL_FUNCTIONS":return{...t,metricsQLFunctions:n.payload};default:throw new Error}}const ta=yt({}),xe=()=>$e(ta).state,Mt=()=>$e(ta).dispatch,El=({children:t})=>{const[n,r]=Et(Al,Ll),a=M(()=>({state:n,dispatch:r}),[n,r]);return e(ta.Provider,{value:a,children:t})},ls=()=>e("svg",{viewBox:"0 0 74 24",fill:"currentColor",children:e("path",{d:"M6.12 10.48c.36.28.8.43 1.26.43h.05c.48 0 .96-.19 1.25-.44 1.5-1.28 5.88-5.29 5.88-5.29C15.73 4.1 12.46 3.01 7.43 3h-.06C2.33 3-.93 4.1.24 5.18c0 0 4.37 4 5.88 5.3Zm2.56 2.16c-.36.28-.8.44-1.26.45h-.04c-.46 0-.9-.17-1.26-.45-1.04-.88-4.74-4.22-6.12-5.5v1.94c0 .21.08.5.22.63l.07.06c1.05.96 4.55 4.16 5.83 5.25.36.28.8.43 1.26.44h.04c.49-.02.96-.2 1.26-.44 1.3-1.11 4.94-4.45 5.88-5.31.15-.14.23-.42.23-.63V7.15a454.94 454.94 0 0 1-6.11 5.5Zm-1.26 4.99c.46 0 .9-.16 1.26-.44a454.4 454.4 0 0 0 6.1-5.5v1.94c0 .2-.07.48-.22.62-.94.87-4.57 4.2-5.88 5.3-.3.26-.77.44-1.26.45h-.04c-.46 0-.9-.16-1.26-.44-1.2-1.02-4.38-3.92-5.62-5.06l-.28-.25c-.14-.14-.22-.42-.22-.62v-1.94c1.38 1.26 5.08 4.6 6.12 5.5.36.28.8.43 1.26.44h.04ZM35 5l-5.84 14.46h-2.43L20.89 5h2.16a.9.9 0 0 1 .9.61l3.41 8.82a18.8 18.8 0 0 1 .62 2.02 19.44 19.44 0 0 1 .57-2.02l3.39-8.82c.05-.15.16-.3.31-.42a.9.9 0 0 1 .58-.19H35Zm17.18 0v14.46H49.8v-9.34c0-.37.02-.78.06-1.21l-4.37 8.21c-.21.4-.53.59-.95.59h-.38c-.43 0-.75-.2-.95-.59L38.8 8.88a22.96 22.96 0 0 1 .07 1.24v9.34H36.5V5h2.03l.3.01c.1 0 .17.02.24.05.07.03.13.07.19.13a1 1 0 0 1 .17.24l4.33 8.03a16.97 16.97 0 0 1 .6 1.36 14.34 14.34 0 0 1 .6-1.38l4.28-8.01c.05-.1.1-.18.17-.24.06-.06.12-.1.19-.13a.9.9 0 0 1 .24-.05l.3-.01h2.04Zm8.88 13.73a4.5 4.5 0 0 0 1.82-.35 3.96 3.96 0 0 0 2.22-2.47c.2-.57.3-1.19.3-1.85V5.31h1.02v8.75c0 .78-.12 1.51-.37 2.19a4.88 4.88 0 0 1-2.76 2.95c-.66.29-1.4.43-2.23.43-.82 0-1.57-.14-2.24-.43a5.01 5.01 0 0 1-2.75-2.95 6.37 6.37 0 0 1-.37-2.19V5.31h1.03v8.74c0 .66.1 1.28.3 1.85a3.98 3.98 0 0 0 2.21 2.47c.53.24 1.14.36 1.82.36Zm10.38.73h-1.03V5.31h1.03v14.15Z"})}),cs=()=>e("svg",{viewBox:"0 0 85 38",fill:"currentColor",children:[e("path",{d:"M11.12 10.48c.36.28.8.43 1.26.43h.05c.48 0 .96-.19 1.25-.44 1.5-1.28 5.88-5.29 5.88-5.29 1.17-1.09-2.1-2.17-7.13-2.18h-.06c-5.04 0-8.3 1.1-7.13 2.18 0 0 4.37 4 5.88 5.3Zm2.56 2.16c-.36.28-.8.44-1.26.45h-.04c-.46 0-.9-.17-1.26-.45-1.04-.88-4.74-4.22-6.12-5.5v1.94c0 .21.08.5.22.63l.07.06c1.05.96 4.55 4.16 5.83 5.25.36.28.8.43 1.26.44h.04c.49-.02.96-.2 1.26-.44 1.3-1.11 4.94-4.45 5.88-5.31.15-.14.23-.42.23-.63V7.15a455.13 455.13 0 0 1-6.11 5.5Zm-1.26 4.99c.46 0 .9-.16 1.26-.44 2.05-1.82 4.09-3.65 6.1-5.5v1.94c0 .2-.07.48-.22.62-.94.87-4.57 4.2-5.88 5.3-.3.26-.77.44-1.26.45h-.04c-.46 0-.9-.16-1.26-.44-1.2-1.02-4.38-3.92-5.62-5.06l-.28-.25c-.14-.14-.22-.42-.22-.62v-1.94c1.38 1.26 5.08 4.6 6.12 5.5.36.28.8.43 1.26.44h.04ZM40 5l-5.84 14.46h-2.43L25.89 5h2.16a.9.9 0 0 1 .9.61l3.41 8.82a18.8 18.8 0 0 1 .62 2.02 19.44 19.44 0 0 1 .57-2.02l3.39-8.82c.05-.15.16-.3.31-.42a.9.9 0 0 1 .58-.19H40Zm17.18 0v14.46H54.8v-9.34c0-.37.02-.78.06-1.21l-4.37 8.21c-.21.4-.53.59-.95.59h-.38c-.43 0-.75-.2-.95-.59L43.8 8.88a22.96 22.96 0 0 1 .07 1.24v9.34H41.5V5h2.03l.3.01c.1 0 .17.02.24.05.07.03.13.07.19.13a1 1 0 0 1 .17.24l4.33 8.03a16.97 16.97 0 0 1 .6 1.36 14.34 14.34 0 0 1 .6-1.38l4.28-8.01c.05-.1.1-.18.17-.24.06-.06.12-.1.19-.13a.9.9 0 0 1 .24-.05l.3-.01h2.04Zm8.88 13.73a4.5 4.5 0 0 0 1.82-.35 3.96 3.96 0 0 0 2.22-2.47c.2-.57.3-1.19.3-1.85V5.31h1.02v8.75c0 .78-.12 1.51-.37 2.19a4.88 4.88 0 0 1-2.76 2.95c-.66.29-1.4.43-2.23.43-.82 0-1.57-.14-2.24-.43a5.01 5.01 0 0 1-2.75-2.95 6.37 6.37 0 0 1-.37-2.19V5.31h1.03v8.74c0 .66.1 1.28.3 1.85a3.98 3.98 0 0 0 2.21 2.47c.53.24 1.14.36 1.82.36Zm10.38.73h-1.03V5.31h1.03v14.15ZM1.73 36v-5.17l-.67-.07a.6.6 0 0 1-.21-.1.23.23 0 0 1-.08-.18v-.44h.96v-.59c0-.34.05-.65.14-.92a1.79 1.79 0 0 1 1.08-1.11 2.45 2.45 0 0 1 1.62-.02l-.03.53c0 .1-.06.15-.16.16H4c-.18 0-.35.03-.5.08a.95.95 0 0 0-.39.23c-.1.11-.19.25-.25.43-.05.18-.08.4-.08.65v.56h1.75v.78H2.8V36H1.73Zm6.17-6.17c.45 0 .85.07 1.2.22a2.57 2.57 0 0 1 1.5 1.62c.13.38.2.81.2 1.29s-.07.91-.2 1.3a2.57 2.57 0 0 1-1.49 1.61c-.36.14-.76.21-1.2.21-.45 0-.86-.07-1.22-.21a2.57 2.57 0 0 1-1.5-1.62c-.12-.38-.19-.81-.19-1.3 0-.47.07-.9.2-1.28a2.57 2.57 0 0 1 1.5-1.62c.35-.15.76-.22 1.2-.22Zm0 5.42c.6 0 1.05-.2 1.35-.6.3-.4.44-.97.44-1.69s-.15-1.28-.44-1.69c-.3-.4-.75-.6-1.35-.6-.3 0-.57.05-.8.15-.22.1-.4.26-.56.45-.15.2-.26.44-.33.73-.08.28-.11.6-.11.96 0 .72.15 1.29.44 1.69.3.4.76.6 1.36.6Zm5.26-4.11c.2-.42.43-.74.71-.97.28-.24.62-.36 1.03-.36.13 0 .25.02.36.05.12.02.23.07.32.13l-.08.8c-.02.1-.08.15-.18.15l-.24-.04a1.7 1.7 0 0 0-.88.05c-.15.05-.29.14-.4.25-.12.1-.23.24-.32.4-.1.17-.18.35-.26.56V36h-1.07v-6.08h.61c.12 0 .2.02.24.07.05.04.08.12.1.23l.06.92Zm13.73-3.82L23.39 36h-1.46l-3.5-8.68h1.29a.54.54 0 0 1 .54.37l2.04 5.3a11.31 11.31 0 0 1 .37 1.21 11.65 11.65 0 0 1 .35-1.22l2.03-5.29c.03-.1.1-.18.19-.25.1-.08.21-.12.35-.12h1.3Zm2.2 2.52V36H27.6v-6.16h1.49Zm.2-1.79c0 .13-.02.25-.08.36a1 1 0 0 1-.51.5.96.96 0 0 1-.73 0 1.02 1.02 0 0 1-.5-.5.96.96 0 0 1 0-.73.93.93 0 0 1 .86-.58.9.9 0 0 1 .37.08c.12.05.22.11.3.2a.94.94 0 0 1 .3.67Zm5.72 3.1a.68.68 0 0 1-.13.13c-.04.03-.1.05-.18.05a.42.42 0 0 1-.22-.07 3.95 3.95 0 0 0-.62-.31c-.14-.05-.3-.07-.51-.07-.26 0-.5.04-.69.14-.2.1-.36.23-.49.4-.13.18-.22.4-.29.64-.06.25-.1.53-.1.85 0 .33.04.62.1.88.08.25.18.47.32.64.13.18.29.3.48.4.18.09.4.13.63.13a1.6 1.6 0 0 0 .94-.27l.26-.2a.4.4 0 0 1 .25-.09.3.3 0 0 1 .27.14l.43.54a2.76 2.76 0 0 1-1.77.96c-.22.03-.43.05-.65.05a2.57 2.57 0 0 1-1.96-.83c-.25-.28-.45-.6-.6-1-.14-.4-.21-.85-.21-1.35 0-.45.06-.87.2-1.25a2.61 2.61 0 0 1 1.51-1.67c.37-.16.8-.24 1.28-.24.46 0 .86.07 1.2.22.35.15.66.36.94.64l-.4.54Zm3.43 4.95c-.54 0-.95-.15-1.24-.45-.28-.3-.42-.73-.42-1.26v-3.44h-.63a.29.29 0 0 1-.2-.07c-.06-.06-.09-.13-.09-.24v-.59l.99-.16.31-1.68a.33.33 0 0 1 .12-.18.34.34 0 0 1 .21-.07h.77v1.94h1.64v1.05h-1.64v3.34c0 .2.05.34.14.45.1.1.22.16.39.16a.73.73 0 0 0 .39-.1l.12-.07a.2.2 0 0 1 .11-.03c.05 0 .08.01.11.03l.09.1.44.72c-.21.18-.46.32-.74.4-.28.1-.57.15-.87.15Zm5.09-6.35c.46 0 .87.07 1.24.22a2.7 2.7 0 0 1 1.58 1.63c.14.39.22.83.22 1.31 0 .49-.08.93-.22 1.32-.14.4-.35.73-.62 1-.26.28-.58.49-.96.64-.37.15-.78.22-1.24.22a3.4 3.4 0 0 1-1.25-.22 2.71 2.71 0 0 1-1.59-1.64 3.8 3.8 0 0 1-.21-1.32c0-.48.07-.92.21-1.31a2.75 2.75 0 0 1 1.58-1.63c.38-.15.8-.22 1.26-.22Zm0 5.2c.51 0 .89-.17 1.13-.52.25-.34.38-.84.38-1.5a2.6 2.6 0 0 0-.38-1.53c-.24-.34-.62-.52-1.13-.52-.52 0-.9.18-1.16.53-.25.35-.37.85-.37 1.51s.12 1.17.37 1.51c.25.35.64.52 1.16.52Zm5.56-4.04c.2-.37.42-.65.69-.86.26-.21.57-.32.94-.32.28 0 .5.06.68.19l-.1 1.1a.3.3 0 0 1-.09.16.24.24 0 0 1-.15.04 1.8 1.8 0 0 1-.27-.03 2.01 2.01 0 0 0-.34-.03c-.16 0-.3.03-.44.08a1.1 1.1 0 0 0-.34.2c-.1.1-.2.2-.27.33-.08.13-.15.27-.22.44V36H47.7v-6.16h.87c.15 0 .26.03.31.09.06.05.1.15.13.29l.09.7Zm4.62-1.07V36h-1.49v-6.16h1.49Zm.2-1.79c0 .13-.02.25-.07.36a1 1 0 0 1-.51.5.96.96 0 0 1-.74 0 1.02 1.02 0 0 1-.5-.5.96.96 0 0 1 0-.73.93.93 0 0 1 .86-.58.9.9 0 0 1 .38.08c.11.05.21.11.3.2a.94.94 0 0 1 .28.67Zm4.56 5.32a7.8 7.8 0 0 0-1.08.12c-.29.05-.52.12-.7.2a.92.92 0 0 0-.38.3.64.64 0 0 0-.11.36c0 .26.07.45.23.56.15.11.35.17.6.17.3 0 .57-.06.79-.17.22-.1.44-.28.65-.5v-1.04Zm-3.4-2.67c.71-.65 1.57-.97 2.56-.97.36 0 .68.06.97.18a1.99 1.99 0 0 1 1.16 1.24c.1.3.16.61.16.96V36h-.67a.7.7 0 0 1-.33-.06c-.07-.04-.13-.13-.18-.26l-.13-.44c-.16.14-.3.26-.46.37a2.8 2.8 0 0 1-.97.43 2.77 2.77 0 0 1-1.32-.05 1.62 1.62 0 0 1-.57-.31 1.41 1.41 0 0 1-.38-.53 1.85 1.85 0 0 1-.05-1.18c.05-.16.14-.3.25-.45.12-.14.28-.27.46-.4a3 3 0 0 1 .7-.32 9.19 9.19 0 0 1 2.2-.33v-.36c0-.41-.09-.71-.26-.91-.18-.2-.43-.3-.76-.3a1.84 1.84 0 0 0-1.02.28l-.33.18c-.1.06-.2.09-.32.09-.1 0-.2-.03-.27-.08a.72.72 0 0 1-.17-.2l-.26-.47Zm11.49 4.32V36h-4.88v-8.6h1.16v7.62h3.72Zm3.16-5.2c.44 0 .84.08 1.2.23a2.57 2.57 0 0 1 1.49 1.62c.13.38.2.81.2 1.29s-.07.91-.2 1.3a2.57 2.57 0 0 1-1.49 1.61c-.36.14-.76.21-1.2.21-.45 0-.85-.07-1.21-.21a2.57 2.57 0 0 1-1.5-1.62c-.13-.38-.2-.81-.2-1.3 0-.47.07-.9.2-1.28.14-.39.33-.72.59-1 .25-.26.55-.47.9-.62.37-.15.77-.22 1.22-.22Zm0 5.43c.6 0 1.05-.2 1.34-.6.3-.4.45-.97.45-1.69s-.15-1.28-.45-1.69c-.3-.4-.74-.6-1.34-.6-.3 0-.57.05-.8.15-.22.1-.4.26-.56.45-.15.2-.26.44-.34.73-.07.28-.1.6-.1.96 0 .72.14 1.29.44 1.69.3.4.75.6 1.36.6Zm6.33-2.22c.22 0 .4-.03.57-.09.16-.06.3-.14.41-.25.12-.11.2-.24.26-.39.05-.15.08-.31.08-.5 0-.37-.11-.66-.34-.88-.23-.22-.55-.33-.98-.33-.43 0-.76.1-.99.33-.22.22-.34.51-.34.89 0 .18.03.34.09.5a1.1 1.1 0 0 0 .67.63c.16.06.35.09.57.09Zm1.93 3.3a.51.51 0 0 0-.13-.36.84.84 0 0 0-.34-.22 8.57 8.57 0 0 0-1.73-.2 7.5 7.5 0 0 1-.62-.05c-.23.1-.41.23-.56.4a.8.8 0 0 0-.1.92c.07.12.18.22.32.3.14.1.32.16.54.21a3.5 3.5 0 0 0 1.55 0c.23-.05.42-.12.57-.22.16-.1.29-.21.37-.34a.8.8 0 0 0 .13-.44Zm1.08-6.17v.4c0 .13-.08.21-.25.25l-.69.09c.14.26.2.56.2.88a1.86 1.86 0 0 1-1.36 1.82 3.07 3.07 0 0 1-1.72.04c-.12.08-.22.16-.29.25a.44.44 0 0 0-.1.27c0 .15.06.26.17.33.12.08.28.13.47.16a5 5 0 0 0 .66.06 16.56 16.56 0 0 1 1.5.13c.26.05.48.12.67.22.19.1.34.24.46.41.12.18.18.4.18.69 0 .26-.07.5-.2.75s-.31.46-.56.65c-.24.2-.54.34-.9.46a4.57 4.57 0 0 1-2.36.04c-.33-.09-.6-.2-.82-.36a1.56 1.56 0 0 1-.5-.51c-.1-.2-.16-.4-.16-.6 0-.3.1-.56.28-.77.19-.2.45-.37.77-.5a1.15 1.15 0 0 1-.43-.32.88.88 0 0 1-.15-.54c0-.09.01-.18.04-.27.04-.1.08-.2.15-.28a1.55 1.55 0 0 1 .58-.5c-.3-.16-.53-.39-.7-.66-.17-.28-.25-.6-.25-.97 0-.3.05-.57.16-.8.12-.25.28-.46.48-.63.2-.17.45-.3.73-.4a3 3 0 0 1 2.3.21h1.64Zm4.65.76a.24.24 0 0 1-.23.14.42.42 0 0 1-.2-.07 3.59 3.59 0 0 0-.67-.3 1.8 1.8 0 0 0-1.03 0c-.14.05-.27.11-.37.2a.87.87 0 0 0-.23.27.75.75 0 0 0-.08.35c0 .15.04.28.13.39.1.1.21.19.36.27.15.07.32.14.5.2a13.63 13.63 0 0 1 1.16.4c.2.08.36.18.5.3a1.33 1.33 0 0 1 .5 1.07 2 2 0 0 1-.15.78c-.1.24-.25.44-.45.62-.2.17-.43.3-.72.4a3.1 3.1 0 0 1-2.14-.05 2.97 2.97 0 0 1-.87-.53l.25-.41c.04-.05.07-.1.12-.12a.3.3 0 0 1 .17-.04.4.4 0 0 1 .22.08l.3.19a1.91 1.91 0 0 0 1.03.27c.2 0 .38-.03.54-.08.16-.06.29-.13.4-.22a.96.96 0 0 0 .3-.7c0-.17-.05-.31-.14-.42-.09-.11-.2-.2-.36-.28a2.6 2.6 0 0 0-.5-.2l-.59-.19c-.2-.06-.39-.14-.58-.22a2.14 2.14 0 0 1-.5-.3 1.45 1.45 0 0 1-.36-.46c-.1-.19-.14-.41-.14-.67a1.6 1.6 0 0 1 .57-1.23c.18-.16.4-.3.68-.39.26-.1.57-.14.91-.14a2.84 2.84 0 0 1 1.9.7l-.23.4Z"}),e("defs",{children:e("path",{d:"M0 0h85v38H0z"})})]}),ds=()=>e("svg",{viewBox:"0 0 85 38",fill:"currentColor",children:e("path",{d:"M11.118 10.476c.36.28.801.433 1.257.436h.052c.48-.007.961-.192 1.25-.444 1.509-1.279 5.88-5.287 5.88-5.287 1.168-1.087-2.093-2.174-7.13-2.181h-.06c-5.036.007-8.298 1.094-7.13 2.181 0 0 4.372 4.008 5.88 5.295zm2.559 2.166c-.359.283-.801.439-1.258.444h-.044a2.071 2.071 0 0 1-1.257-.444C10.082 11.755 6.384 8.42 5 7.148v1.93c0 .215.081.496.222.629l.07.064c1.045.955 4.546 4.154 5.825 5.245.358.283.8.438 1.257.444h.044c.489-.015.962-.2 1.258-.444 1.309-1.11 4.948-4.444 5.887-5.31.148-.132.222-.413.222-.628v-1.93a455.127 455.127 0 0 1-6.11 5.494zm-1.258 4.984a2.071 2.071 0 0 0 1.258-.436c2.053-1.815 4.09-3.65 6.11-5.502v1.938c0 .207-.075.488-.223.621-.94.873-4.578 4.2-5.887 5.31-.296.25-.77.436-1.258.443h-.044a2.071 2.071 0 0 1-1.257-.436c-1.204-1.027-4.376-3.928-5.616-5.062l-.28-.255c-.14-.133-.221-.414-.221-.621v-1.938c1.383 1.265 5.081 4.607 6.117 5.495.358.282.8.438 1.257.443h.044zM40 5l-5.84 14.46h-2.43L25.89 5h2.16c.233 0 .423.057.57.17.146.113.256.26.33.44l3.41 8.82c.113.287.22.603.32.95.106.34.206.697.3 1.07.08-.373.166-.73.26-1.07a8.84 8.84 0 0 1 .31-.95l3.39-8.82a.959.959 0 0 1 .31-.42.906.906 0 0 1 .58-.19H40zm17.176 0v14.46h-2.37v-9.34c0-.373.02-.777.06-1.21l-4.37 8.21c-.206.393-.523.59-.95.59h-.38c-.426 0-.743-.197-.95-.59l-4.42-8.24c.02.22.037.437.05.65.014.213.02.41.02.59v9.34h-2.37V5h2.03c.12 0 .224.003.31.01a.778.778 0 0 1 .23.05c.074.027.137.07.19.13.06.06.117.14.17.24l4.33 8.03c.114.213.217.433.31.66.1.227.197.46.29.7.094-.247.19-.483.29-.71.1-.233.207-.457.32-.67l4.27-8.01c.054-.1.11-.18.17-.24a.57.57 0 0 1 .19-.13.903.903 0 0 1 .24-.05c.087-.007.19-.01.31-.01h2.03zm8.887 13.73c.68 0 1.286-.117 1.82-.35.54-.24.996-.57 1.37-.99a4.28 4.28 0 0 0 .85-1.48c.2-.573.3-1.19.3-1.85V5.31h1.02v8.75c0 .78-.124 1.51-.37 2.19a5.248 5.248 0 0 1-1.07 1.77c-.46.5-1.024.893-1.69 1.18-.66.287-1.404.43-2.23.43-.827 0-1.574-.143-2.24-.43a5.012 5.012 0 0 1-1.69-1.18 5.33 5.33 0 0 1-1.06-1.77 6.373 6.373 0 0 1-.37-2.19V5.31h1.03v8.74c0 .66.096 1.277.29 1.85.2.567.483 1.06.85 1.48.373.42.826.75 1.36.99.54.24 1.15.36 1.83.36zm10.38.73h-1.03V5.31h1.03v14.15zM4.242 35v-5.166l-.672-.078a.595.595 0 0 1-.21-.09.23.23 0 0 1-.078-.186v-.438h.96v-.588c0-.348.048-.656.144-.924.1-.272.24-.5.42-.684a1.79 1.79 0 0 1 .66-.426c.256-.096.544-.144.864-.144.272 0 .522.04.75.12l-.024.534c-.008.096-.062.148-.162.156a4.947 4.947 0 0 1-.39.012c-.184 0-.352.024-.504.072a.949.949 0 0 0-.384.234c-.108.108-.192.25-.252.426a2.184 2.184 0 0 0-.084.654v.558h1.752v.774H5.316V35H4.242zM10.416 28.826a3.1 3.1 0 0 1 1.2.222c.356.148.66.358.912.63s.444.602.576.99c.136.384.204.814.204 1.29 0 .48-.068.912-.204 1.296a2.735 2.735 0 0 1-.576.984 2.572 2.572 0 0 1-.912.63 3.175 3.175 0 0 1-1.2.216c-.448 0-.852-.072-1.212-.216a2.572 2.572 0 0 1-.912-.63 2.805 2.805 0 0 1-.582-.984 3.972 3.972 0 0 1-.198-1.296c0-.476.066-.906.198-1.29.136-.388.33-.718.582-.99.252-.272.556-.482.912-.63.36-.148.764-.222 1.212-.222zm0 5.424c.6 0 1.048-.2 1.344-.6.296-.404.444-.966.444-1.686 0-.724-.148-1.288-.444-1.692-.296-.404-.744-.606-1.344-.606-.304 0-.57.052-.798.156a1.507 1.507 0 0 0-.564.45c-.148.196-.26.438-.336.726a3.941 3.941 0 0 0-.108.966c0 .72.148 1.282.444 1.686.3.4.754.6 1.362.6zM15.677 30.14c.192-.416.428-.74.708-.972.28-.236.622-.354 1.026-.354.128 0 .25.014.366.042.12.028.226.072.318.132l-.078.798c-.024.1-.084.15-.18.15-.056 0-.138-.012-.246-.036a1.694 1.694 0 0 0-.366-.036c-.192 0-.364.028-.516.084-.148.056-.282.14-.402.252a1.782 1.782 0 0 0-.318.408c-.092.16-.176.344-.252.552V35h-1.074v-6.078h.612c.116 0 .196.022.24.066.044.044.074.12.09.228l.072.924zM26.761 28.922 24.283 35h-.96l-2.478-6.078h.87a.33.33 0 0 1 .33.222l1.542 3.912c.048.148.09.292.126.432.036.14.07.28.102.42.032-.14.066-.28.102-.42.036-.14.08-.284.132-.432l1.56-3.912a.33.33 0 0 1 .12-.156.311.311 0 0 1 .198-.066h.834zM27.74 35v-6.078h.643c.152 0 .246.074.282.222l.078.624c.224-.276.476-.502.756-.678.28-.176.604-.264.972-.264.408 0 .738.114.99.342.256.228.44.536.552.924.088-.22.2-.41.336-.57a1.987 1.987 0 0 1 1.014-.624c.196-.048.394-.072.594-.072.32 0 .604.052.852.156.252.1.464.248.636.444.176.196.31.438.402.726.092.284.138.61.138.978V35H34.91v-3.87c0-.476-.104-.836-.312-1.08-.208-.248-.508-.372-.9-.372-.176 0-.344.032-.504.096-.156.06-.294.15-.414.27-.12.12-.216.272-.288.456-.068.18-.102.39-.102.63V35h-1.074v-3.87c0-.488-.098-.852-.294-1.092-.196-.24-.482-.36-.858-.36-.264 0-.508.072-.732.216a2.38 2.38 0 0 0-.618.576V35H27.74zM40.746 32.372c-.428.02-.788.058-1.08.114-.292.052-.526.12-.702.204a.923.923 0 0 0-.378.294.639.639 0 0 0-.114.366c0 .26.076.446.228.558.156.112.358.168.606.168.304 0 .566-.054.786-.162.224-.112.442-.28.654-.504v-1.038zm-3.396-2.67c.708-.648 1.56-.972 2.556-.972.36 0 .682.06.966.18.284.116.524.28.72.492.196.208.344.458.444.75.104.292.156.612.156.96V35h-.672a.708.708 0 0 1-.324-.06c-.076-.044-.136-.13-.18-.258l-.132-.444c-.156.14-.308.264-.456.372a2.804 2.804 0 0 1-.462.264c-.16.072-.332.126-.516.162-.18.04-.38.06-.6.06-.26 0-.5-.034-.72-.102a1.618 1.618 0 0 1-.57-.318 1.414 1.414 0 0 1-.372-.522 1.852 1.852 0 0 1-.132-.726 1.419 1.419 0 0 1 .33-.906c.12-.14.274-.272.462-.396s.418-.232.69-.324c.276-.092.596-.166.96-.222.364-.06.78-.096 1.248-.108v-.36c0-.412-.088-.716-.264-.912-.176-.2-.43-.3-.762-.3-.24 0-.44.028-.6.084-.156.056-.294.12-.414.192l-.33.186a.631.631 0 0 1-.324.084.439.439 0 0 1-.264-.078.716.716 0 0 1-.174-.192l-.264-.474zM44.974 29.6c.124-.124.254-.238.39-.342a2.395 2.395 0 0 1 .936-.444c.176-.044.368-.066.576-.066.336 0 .634.058.894.174.26.112.476.272.648.48.176.204.308.45.396.738.092.284.138.598.138.942V35H47.47v-3.918c0-.376-.086-.666-.258-.87-.172-.208-.434-.312-.786-.312-.256 0-.496.058-.72.174a2.58 2.58 0 0 0-.636.474V35h-1.482v-6.156h.906c.192 0 .318.09.378.27l.102.486zM53.085 28.748c.456 0 .87.074 1.242.222a2.692 2.692 0 0 1 1.578 1.626c.144.392.216.83.216 1.314 0 .488-.072.928-.216 1.32-.144.392-.35.726-.618 1.002a2.653 2.653 0 0 1-.96.636 3.333 3.333 0 0 1-1.242.222c-.46 0-.878-.074-1.254-.222a2.712 2.712 0 0 1-.966-.636 2.922 2.922 0 0 1-.618-1.002 3.807 3.807 0 0 1-.216-1.32c0-.484.072-.922.216-1.314.148-.392.354-.724.618-.996.268-.272.59-.482.966-.63a3.397 3.397 0 0 1 1.254-.222zm0 5.202c.512 0 .89-.172 1.134-.516.248-.344.372-.848.372-1.512s-.124-1.17-.372-1.518c-.244-.348-.622-.522-1.134-.522-.52 0-.906.176-1.158.528-.248.348-.372.852-.372 1.512s.124 1.164.372 1.512c.252.344.638.516 1.158.516zM57.252 35v-6.156h.906c.192 0 .318.09.378.27l.096.456c.108-.12.22-.23.336-.33a2.017 2.017 0 0 1 1.32-.492c.388 0 .706.106.954.318.252.208.44.486.564.834a1.93 1.93 0 0 1 .834-.882c.172-.092.354-.16.546-.204.196-.044.392-.066.588-.066.34 0 .642.052.906.156.264.104.486.256.666.456.18.2.316.444.408.732.096.288.144.618.144.99V35h-1.482v-3.918c0-.392-.086-.686-.258-.882-.172-.2-.424-.3-.756-.3-.152 0-.294.026-.426.078a1.026 1.026 0 0 0-.342.228 1.019 1.019 0 0 0-.228.366 1.435 1.435 0 0 0-.084.51V35h-1.488v-3.918c0-.412-.084-.712-.252-.9-.164-.188-.406-.282-.726-.282-.216 0-.418.054-.606.162a1.979 1.979 0 0 0-.516.432V35h-1.482zM70.558 32.372c-.428.02-.788.058-1.08.114-.292.052-.526.12-.702.204a.923.923 0 0 0-.378.294.639.639 0 0 0-.114.366c0 .26.076.446.228.558.156.112.358.168.606.168.304 0 .566-.054.786-.162.224-.112.442-.28.654-.504v-1.038zm-3.396-2.67c.708-.648 1.56-.972 2.556-.972.36 0 .682.06.966.18.284.116.524.28.72.492.196.208.344.458.444.75.104.292.156.612.156.96V35h-.672a.708.708 0 0 1-.324-.06c-.076-.044-.136-.13-.18-.258l-.132-.444c-.156.14-.308.264-.456.372a2.804 2.804 0 0 1-.462.264c-.16.072-.332.126-.516.162-.18.04-.38.06-.6.06-.26 0-.5-.034-.72-.102a1.618 1.618 0 0 1-.57-.318 1.414 1.414 0 0 1-.372-.522 1.852 1.852 0 0 1-.132-.726 1.419 1.419 0 0 1 .33-.906c.12-.14.274-.272.462-.396s.418-.232.69-.324c.276-.092.596-.166.96-.222.364-.06.78-.096 1.248-.108v-.36c0-.412-.088-.716-.264-.912-.176-.2-.43-.3-.762-.3-.24 0-.44.028-.6.084-.156.056-.294.12-.414.192l-.33.186a.631.631 0 0 1-.324.084.439.439 0 0 1-.264-.078.716.716 0 0 1-.174-.192l-.264-.474zM74.9 26.084V35h-1.482v-8.916H74.9zM81.969 28.844l-3.354 7.848a.538.538 0 0 1-.174.234c-.068.056-.174.084-.318.084h-1.104l1.152-2.472-2.49-5.694h1.302c.116 0 .206.028.27.084.068.056.118.12.15.192l1.308 3.192c.044.108.08.216.108.324.032.108.062.218.09.33a32.3 32.3 0 0 1 .108-.33c.036-.112.076-.222.12-.33l1.236-3.186a.437.437 0 0 1 .408-.276h1.188z"})}),ms=()=>e("svg",{viewBox:"0 0 15 17",fill:"currentColor",children:e("path",{d:"M6.11767 7.47586C6.47736 7.75563 6.91931 7.90898 7.37503 7.91213H7.42681C7.90756 7.90474 8.38832 7.71987 8.67677 7.46846C10.1856 6.18921 14.5568 2.18138 14.5568 2.18138C15.7254 1.09438 12.4637 0.00739 7.42681 0H7.36764C2.3308 0.00739 -0.930935 1.09438 0.237669 2.18138C0.237669 2.18138 4.60884 6.18921 6.11767 7.47586ZM8.67677 9.64243C8.31803 9.92483 7.87599 10.0808 7.41941 10.0861H7.37503C6.91845 10.0808 6.47641 9.92483 6.11767 9.64243C5.0822 8.75513 1.38409 5.42018 0.000989555 4.14832V6.07829C0.000989555 6.29273 0.0823481 6.57372 0.222877 6.70682L0.293316 6.7712L0.293344 6.77122C1.33784 7.72579 4.83903 10.9255 6.11767 12.0161C6.47641 12.2985 6.91845 12.4545 7.37503 12.4597H7.41941C7.90756 12.4449 8.38092 12.2601 8.67677 12.0161C9.9859 10.9069 13.6249 7.57198 14.5642 6.70682C14.7121 6.57372 14.7861 6.29273 14.7861 6.07829V4.14832C12.7662 5.99804 10.7297 7.82949 8.67677 9.64243ZM7.41941 14.6263C7.87513 14.6232 8.31708 14.4698 8.67677 14.19C10.7298 12.3746 12.7663 10.5407 14.7861 8.68853V10.6259C14.7861 10.8329 14.7121 11.1139 14.5642 11.247C13.6249 12.1196 9.9859 15.4471 8.67677 16.5563C8.38092 16.8077 7.90756 16.9926 7.41941 17H7.37503C6.91931 16.9968 6.47736 16.8435 6.11767 16.5637C4.91427 15.5373 1.74219 12.6364 0.502294 11.5025C0.393358 11.4029 0.299337 11.3169 0.222877 11.247C0.0823481 11.1139 0.000989555 10.8329 0.000989555 10.6259V8.68853C1.38409 9.95303 5.0822 13.2953 6.11767 14.1827C6.47641 14.4651 6.91845 14.6211 7.37503 14.6263H7.41941Z"})}),Ze=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"})}),Ue=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"})}),ct=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M12 5V2L8 6l4 4V7c3.31 0 6 2.69 6 6 0 2.97-2.17 5.43-5 5.91v2.02c3.95-.49 7-3.85 7-7.93 0-4.42-3.58-8-8-8zm-6 8c0-1.65.67-3.15 1.76-4.24L6.34 7.34C4.9 8.79 4 10.79 4 13c0 4.08 3.05 7.44 7 7.93v-2.02c-2.83-.48-5-2.94-5-5.91z"})}),mt=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"})}),un=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M11 7h2v2h-2zm0 4h2v6h-2zm1-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8"})}),na=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"})}),ra=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"})}),us=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"})}),Gn=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z"})}),be=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M7.41 8.59 12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z"})}),Je=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"m7 10 5 5 5-5z"})}),rn=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:[e("path",{d:"M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"}),e("path",{d:"M12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z"})]}),Rn=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M20 3h-1V1h-2v2H7V1H5v2H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 18H4V8h16v13z"})}),hs=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"m22 5.72-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM7.88 3.39 6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM12.5 8H11v6l4.75 2.85.75-1.23-4-2.37V8zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"})}),ps=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M20 5H4c-1.1 0-1.99.9-1.99 2L2 17c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-9 3h2v2h-2V8zm0 3h2v2h-2v-2zM8 8h2v2H8V8zm0 3h2v2H8v-2zm-1 2H5v-2h2v2zm0-3H5V8h2v2zm9 7H8v-2h8v2zm0-4h-2v-2h2v2zm0-3h-2V8h2v2zm3 3h-2v-2h2v2zm0-3h-2V8h2v2z"})}),nt=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M8 5v14l11-7z"})}),hn=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"m10 16.5 6-4.5-6-4.5v9zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"})}),aa=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"m3.5 18.49 6-6.01 4 4L22 6.92l-1.41-1.41-7.09 7.97-4-4L2 16.99z"})}),pn=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M10 10.02h5V21h-5zM17 21h3c1.1 0 2-.9 2-2v-9h-5v11zm3-18H5c-1.1 0-2 .9-2 2v3h19V5c0-1.1-.9-2-2-2zM3 19c0 1.1.9 2 2 2h3V10H3v9z"})}),It=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M9.4 16.6 4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0 4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"})}),gn=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"})}),oa=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"})}),gs=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M19 13H5v-2h14v2z"})}),Wn=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M8.9999 14.7854L18.8928 4.8925C19.0803 4.70497 19.3347 4.59961 19.5999 4.59961C19.8651 4.59961 20.1195 4.70497 20.307 4.8925L21.707 6.2925C22.0975 6.68303 22.0975 7.31619 21.707 7.70672L9.70701 19.7067C9.31648 20.0972 8.68332 20.0972 8.2928 19.7067L2.6928 14.1067C2.50526 13.9192 2.3999 13.6648 2.3999 13.3996C2.3999 13.1344 2.50526 12.88 2.6928 12.6925L4.0928 11.2925C4.48332 10.902 5.11648 10.902 5.50701 11.2925L8.9999 14.7854Z"})}),Vt=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"})}),sa=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78 3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z"})}),vs=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M19 9l1.25-2.75L23 5l-2.75-1.25L19 1l-1.25 2.75L15 5l2.75 1.25L19 9zm-7.5.5L9 4 6.5 9.5 1 12l5.5 2.5L9 20l2.5-5.5L17 12l-5.5-2.5zM19 15l-1.25 2.75L15 19l2.75 1.25L19 23l1.25-2.75L23 19l-2.75-1.25L19 15z"})}),Xe=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"})}),ia=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M20 9H4v2h16V9zM4 15h16v-2H4v2z"})}),$n=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M23 8c0 1.1-.9 2-2 2-.18 0-.35-.02-.51-.07l-3.56 3.55c.05.16.07.34.07.52 0 1.1-.9 2-2 2s-2-.9-2-2c0-.18.02-.36.07-.52l-2.55-2.55c-.16.05-.34.07-.52.07s-.36-.02-.52-.07l-4.55 4.56c.05.16.07.33.07.51 0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2c.18 0 .35.02.51.07l4.56-4.55C8.02 9.36 8 9.18 8 9c0-1.1.9-2 2-2s2 .9 2 2c0 .18-.02.36-.07.52l2.55 2.55c.16-.05.34-.07.52-.07s.36.02.52.07l3.55-3.56C19.02 8.35 19 8.18 19 8c0-1.1.9-2 2-2s2 .9 2 2z"})}),ut=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:[e("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M21 5C19.89 4.65 18.67 4.5 17.5 4.5C15.55 4.5 13.45 4.9 12 6C10.55 4.9 8.45 4.5 6.5 4.5C5.33 4.5 4.11 4.65 3 5C2.25 5.25 1.6 5.55 1 6V20.6C1 20.85 1.25 21.1 1.5 21.1C1.6 21.1 1.65 21.1 1.75 21.05C3.15 20.3 4.85 20 6.5 20C8.2 20 10.65 20.65 12 21.5C13.35 20.65 15.8 20 17.5 20C19.15 20 20.85 20.3 22.25 21.05C22.35 21.1 22.4 21.1 22.5 21.1C22.75 21.1 23 20.85 23 20.6V6C22.4 5.55 21.75 5.25 21 5ZM21 18.5C19.9 18.15 18.7 18 17.5 18C15.8 18 13.35 18.65 12 19.5C10.65 18.65 8.2 18 6.5 18C5.3 18 4.1 18.15 3 18.5V7C4.1 6.65 5.3 6.5 6.5 6.5C8.2 6.5 10.65 7.15 12 8C13.35 7.15 15.8 6.5 17.5 6.5C18.7 6.5 19.9 6.65 21 7V18.5Z"}),e("path",{d:"M17.5 10.5C18.38 10.5 19.23 10.59 20 10.76V9.24C19.21 9.09 18.36 9 17.5 9C15.8 9 14.26 9.29 13 9.83V11.49C14.13 10.85 15.7 10.5 17.5 10.5ZM13 12.49V14.15C14.13 13.51 15.7 13.16 17.5 13.16C18.38 13.16 19.23 13.25 20 13.42V11.9C19.21 11.75 18.36 11.66 17.5 11.66C15.8 11.66 14.26 11.96 13 12.49ZM17.5 14.33C15.8 14.33 14.26 14.62 13 15.16V16.82C14.13 16.18 15.7 15.83 17.5 15.83C18.38 15.83 19.23 15.92 20 16.09V14.57C19.21 14.41 18.36 14.33 17.5 14.33Z"}),e("path",{d:"M6.5 10.5C5.62 10.5 4.77 10.59 4 10.76V9.24C4.79 9.09 5.64 9 6.5 9C8.2 9 9.74 9.29 11 9.83V11.49C9.87 10.85 8.3 10.5 6.5 10.5ZM11 12.49V14.15C9.87 13.51 8.3 13.16 6.5 13.16C5.62 13.16 4.77 13.25 4 13.42V11.9C4.79 11.75 5.64 11.66 6.5 11.66C8.2 11.66 9.74 11.96 11 12.49ZM6.5 14.33C8.2 14.33 9.74 14.62 11 15.16V16.82C9.87 16.18 8.3 15.83 6.5 15.83C5.62 15.83 4.77 15.92 4 16.09V14.57C4.79 14.41 5.64 14.33 6.5 14.33Z"})]}),fs=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M12 2C6.49 2 2 6.49 2 12s4.49 10 10 10 10-4.49 10-10S17.51 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm3-8c0 1.66-1.34 3-3 3s-3-1.34-3-3 1.34-3 3-3 3 1.34 3 3z"})}),la=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM12 6C9.79 6 8 7.79 8 10H10C10 8.9 10.9 8 12 8C13.1 8 14 8.9 14 10C14 10.8792 13.4202 11.3236 12.7704 11.8217C11.9421 12.4566 11 13.1787 11 15H13C13 13.9046 13.711 13.2833 14.4408 12.6455C15.21 11.9733 16 11.2829 16 10C16 7.79 14.21 6 12 6ZM13 16V18H11V16H13Z"})}),Lt=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M4 20h16c1.1 0 2-.9 2-2s-.9-2-2-2H4c-1.1 0-2 .9-2 2s.9 2 2 2zm0-3h2v2H4v-2zM2 6c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2s-.9-2-2-2H4c-1.1 0-2 .9-2 2zm4 1H4V5h2v2zm-2 7h16c1.1 0 2-.9 2-2s-.9-2-2-2H4c-1.1 0-2 .9-2 2s.9 2 2 2zm0-3h2v2H4v-2z"})}),ca=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"})}),_s=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M3 17v2h6v-2H3zM3 5v2h10V5H3zm10 16v-2h8v-2h-8v-2h-2v6h2zM7 9v2H3v2h4v2h2V9H7zm14 4v-2H11v2h10zm-6-4h2V7h4V5h-4V3h-2v6z"})}),vn=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M7 20h4c0 1.1-.9 2-2 2s-2-.9-2-2zm-2-1h8v-2H5v2zm11.5-9.5c0 3.82-2.66 5.86-3.77 6.5H5.27c-1.11-.64-3.77-2.68-3.77-6.5C1.5 5.36 4.86 2 9 2s7.5 3.36 7.5 7.5zm4.87-2.13L20 8l1.37.63L22 10l.63-1.37L24 8l-1.37-.63L22 6l-.63 1.37zM19 6l.94-2.06L22 3l-2.06-.94L19 0l-.94 2.06L16 3l2.06.94L19 6z"})}),bs=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M3 14h4v-4H3v4zm0 5h4v-4H3v4zM3 9h4V5H3v4zm5 5h13v-4H8v4zm0 5h13v-4H8v4zM8 5v4h13V5H8z"})}),ys=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"m22 9.24-7.19-.62L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21 12 17.27 18.18 21l-1.63-7.03L22 9.24zM12 15.4l-3.76 2.27 1-4.28-3.32-2.88 4.38-.38L12 6.1l1.71 4.04 4.38.38-3.32 2.88 1 4.28L12 15.4z"})}),ws=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M12 17.27 18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"})}),Fn=()=>e("svg",{viewBox:"0 0 16 16",fill:tt("color-error"),children:e("path",{d:"M13.5095 4L8.50952 1H7.50952L2.50952 4L2.01953 4.85999V10.86L2.50952 11.71L7.50952 14.71H8.50952L13.5095 11.71L13.9995 10.86V4.85999L13.5095 4ZM7.50952 13.5601L3.00952 10.86V5.69995L7.50952 8.15002V13.5601ZM3.26953 4.69995L8.00952 1.85999L12.7495 4.69995L8.00952 7.29004L3.26953 4.69995ZM13.0095 10.86L8.50952 13.5601V8.15002L13.0095 5.69995V10.86Z"})}),an=()=>e("svg",{viewBox:"0 0 16 16",fill:tt("color-primary"),children:e("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M2 5H4V4H1.5L1 4.5V12.5L1.5 13H4V12H2V5ZM14.5 4H12V5H14V12H12V13H14.5L15 12.5V4.5L14.5 4ZM11.76 6.56995L12 7V9.51001L11.7 9.95996L7.19995 11.96H6.73999L4.23999 10.46L4 10.03V7.53003L4.30005 7.06995L8.80005 5.06995H9.26001L11.76 6.56995ZM5 9.70996L6.5 10.61V9.28003L5 8.38V9.70996ZM5.57996 7.56006L7.03003 8.43005L10.42 6.93005L8.96997 6.06006L5.57996 7.56006ZM7.53003 10.73L11.03 9.17004V7.77002L7.53003 9.31995V10.73Z"})}),da=()=>e("svg",{viewBox:"0 0 16 16",fill:tt("color-warning"),children:e("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M14 2H8L7 3V6H8V3H14V8H10V9H14L15 8V3L14 2ZM9 6H13V7H9.41L9 6.59V6ZM7 7H2L1 8V13L2 14H8L9 13V8L8 7H7ZM8 13H2V8H8V9V13ZM3 9H7V10H3V9ZM3 11H7V12H3V11ZM9 4H13V5H9V4Z"})}),zn=()=>e("svg",{viewBox:"0 0 16 16",fill:tt("color-primary"),children:e("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M7 3L8 2H14L15 3V8L14 9H10V8H14V3H8V6H7V3ZM9 9V8L8 7H7H2L1 8V13L2 14H8L9 13V9ZM8 8V9V13H2V8H7H8ZM9.41421 7L9 6.58579V6H13V7H9.41421ZM9 4H13V5H9V4ZM7 10H3V11H7V10Z"})}),fn=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"})}),ma=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M12 5.83 15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15z"})}),ua=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M7.41 18.59 8.83 20 12 16.83 15.17 20l1.41-1.41L12 14zm9.18-13.18L15.17 4 12 7.17 8.83 4 7.41 5.41 12 10z"})}),Cs=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14"})}),ha=()=>e("svg",{viewBox:"0 0 24 24",children:e("path",{fill:"currentColor",d:"M12,4a8,8,0,0,1,7.89,6.7A1.53,1.53,0,0,0,21.38,12h0a1.5,1.5,0,0,0,1.48-1.75,11,11,0,0,0-21.72,0A1.5,1.5,0,0,0,2.62,12h0a1.53,1.53,0,0,0,1.49-1.3A8,8,0,0,1,12,4Z",children:e("animateTransform",{attributeName:"transform",dur:"0.75s",repeatCount:"indefinite",type:"rotate",values:"0 12 12;360 12 12"})})}),Ns=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4zM18 14H6v-2h12zm0-3H6V9h12zm0-3H6V6h12z"})}),pa=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M4.25 5.61C6.27 8.2 10 13 10 13v6c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-6s3.72-4.8 5.74-7.39c.51-.66.04-1.61-.79-1.61H5.04c-.83 0-1.3.95-.79 1.61"})}),ga=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M19.79 5.61C20.3 4.95 19.83 4 19 4H6.83l7.97 7.97zM2.81 2.81 1.39 4.22 10 13v6c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-2.17l5.78 5.78 1.41-1.41z"})}),xl=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3z"})}),Ml=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M19 4H5c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.89-2-2-2m0 14H5V8h14z"})}),Ss=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M6 19h4V5H6v14zm8-14v14h4V5h-4z"})}),ks=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M8 12l4-4 4 4m-4-4v12",strokeWidth:"2",stroke:"currentColor",fill:"none"})}),Ts=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:[e("path",{d:"M4 3 L4 15 L1.5 15 L5.5 21 L9.5 15 L7 15 L7 3 Z"}),e("path",{d:"M13 21 L13 9 L10.5 9 L14.5 3 L18.5 9 L16 9 L16 21 Z"})]}),Ls=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M10.5 3 L10.5 15 L8 15 L12 21 L16 15 L13.5 15 L13.5 3 Z"})}),As=()=>e("svg",{viewBox:"0 0 24 24",fill:"currentColor",children:e("path",{d:"M10.5 21 L10.5 9 L8 9 L12 3 L16 9 L13.5 9 L13.5 21 Z"})}),Il=Object.freeze(Object.defineProperty({__proto__:null,AlarmIcon:hs,ArrowDownIcon:be,ArrowDropDownIcon:Je,CalendarIcon:Rn,ChartIcon:aa,ClockIcon:rn,CloseIcon:Ue,CodeIcon:It,CollapseIcon:ua,CommentIcon:Ns,CopyIcon:Xe,DeleteIcon:gn,DoneIcon:Wn,DownloadIcon:fn,DragIcon:ia,ErrorIcon:ra,ExpandIcon:ma,FilterIcon:pa,FilterOffIcon:ga,FunctionIcon:an,InfoIcon:mt,InfoOutlinedIcon:un,IssueIcon:fs,KeyboardIcon:ps,LabelIcon:da,ListIcon:bs,LogoAnomalyIcon:ds,LogoIcon:ls,LogoLogsIcon:cs,LogoShortIcon:ms,MetricIcon:Fn,MinusIcon:gs,ModalIcon:Ml,MoreIcon:ca,OpenNewIcon:xl,PauseIcon:Ss,PlayCircleOutlineIcon:hn,PlayIcon:nt,PlusIcon:oa,Prettify:vs,QuestionIcon:la,RefreshIcon:Gn,RestartIcon:ct,ScrollToTopIcon:ks,SearchIcon:Cs,SettingsIcon:Ze,SortArrowDownIcon:Ls,SortArrowUpIcon:As,SortIcon:Ts,SpinnerIcon:ha,StarBorderIcon:ys,StarIcon:ws,StorageIcon:Lt,SuccessIcon:us,TableIcon:pn,TimelineIcon:$n,TipIcon:vn,TuneIcon:_s,ValueIcon:zn,VisibilityIcon:Vt,VisibilityOffIcon:sa,WarningIcon:na,WikiIcon:ut},Symbol.toStringTag,{value:"Module"})),Pl=({to:t,isNavLink:n,children:r,...a})=>n?e(Yo,{to:t,...a,children:r}):e("div",{...a,children:r}),Dl=({activeItem:t,item:n,color:r=tt("color-primary"),activeNavRef:a,onChange:o,isNavLink:s})=>{const i=l=>()=>{o&&o(l)};return e(Pl,{className:I({"vm-tabs-item":!0,"vm-tabs-item_active":t===n.value,[n.className||""]:n.className}),isNavLink:s,to:n.value,style:{color:r},onClick:i(n.value),ref:t===n.value?a:void 0,children:[n.icon&&e("div",{className:I({"vm-tabs-item__icon":!0,"vm-tabs-item__icon_single":!n.label}),children:n.icon}),n.label]})};function me(t,n,r,a){const o=q(n);A(()=>{o.current=n},[n]),A(()=>{const s=(r==null?void 0:r.current)??window;if(!(s&&s.addEventListener))return;const i=l=>o.current(l);return s.addEventListener(t,i,a),()=>{s.removeEventListener(t,i,a)}},[t,r,a])}const Pt=()=>{const[t,n]=N({width:0,height:0}),r=()=>{n({width:window.innerWidth,height:window.innerHeight})};return me("resize",r),A(r,[]),t},Yt=({activeItem:t,items:n,color:r=tt("color-primary"),onChange:a,indicatorPlacement:o="bottom",isNavLink:s})=>{const i=Pt(),l=q(null),[c,d]=N({left:0,width:0,bottom:0});return A(()=>{var m;if(((m=l.current)==null?void 0:m.base)instanceof HTMLElement){const{offsetLeft:u,offsetWidth:h,offsetHeight:p}=l.current.base;d({left:u,width:h,bottom:o==="top"?p-2:0})}},[i,t,l,n]),e("div",{className:"vm-tabs",children:[n.map(m=>e(Dl,{activeItem:t,item:m,onChange:a,color:r,activeNavRef:l,isNavLink:s},m.value)),e("div",{className:"vm-tabs__indicator",style:{...c,borderColor:r}})]})},zt=[{value:Ne.chart,icon:e(aa,{}),label:"Graph",prometheusCode:0},{value:Ne.code,icon:e(It,{}),label:"JSON",prometheusCode:3},{value:Ne.table,icon:e(pn,{}),label:"Table",prometheusCode:1}],Es=({tabFilter:t})=>{const{displayType:n}=je(),r=Gt(),a=s=>{r({type:"SET_DISPLAY_TYPE",payload:s??n})},o=zt.filter(t??(()=>!0));return e(Yt,{activeItem:n,items:o,onChange:a})},xs=()=>{const t=ze("g0.tab",0),n=zt.find(r=>r.prometheusCode===+t||r.value===t);return(n==null?void 0:n.value)||Ne.chart},io=Ae("SERIES_LIMITS"),Ol={displayType:xs(),nocache:!1,isTracingEnabled:!1,seriesLimits:io?JSON.parse(io):Ko,tableCompact:Ae("TABLE_COMPACT")||!1,reduceMemUsage:!1};function Rl(t,n){switch(n.type){case"SET_DISPLAY_TYPE":return{...t,displayType:n.payload};case"SET_SERIES_LIMITS":return Le("SERIES_LIMITS",JSON.stringify(n.payload)),{...t,seriesLimits:n.payload};case"TOGGLE_QUERY_TRACING":return{...t,isTracingEnabled:!t.isTracingEnabled};case"TOGGLE_NO_CACHE":return{...t,nocache:!t.nocache};case"TOGGLE_TABLE_COMPACT":return Le("TABLE_COMPACT",!t.tableCompact),{...t,tableCompact:!t.tableCompact};case"TOGGLE_REDUCE_MEM_USAGE":return Le("TABLE_COMPACT",!t.reduceMemUsage),{...t,reduceMemUsage:!t.reduceMemUsage};default:throw new Error}}const va=yt({}),je=()=>$e(va).state,Gt=()=>$e(va).dispatch,$l=({children:t})=>{const[n,r]=Et(Rl,Ol),a=M(()=>({state:n,dispatch:r}),[n,r]);return e(va.Provider,{value:a,children:t})},Fl={customStep:ze("g0.step_input",""),yaxis:{limits:{enable:!1,range:{1:[0,0]}}},isHistogram:!1,isEmptyHistogram:!1,spanGaps:!1,openSettings:!1};function zl(t,n){switch(n.type){case"TOGGLE_ENABLE_YAXIS_LIMITS":return{...t,yaxis:{...t.yaxis,limits:{...t.yaxis.limits,enable:!t.yaxis.limits.enable}}};case"SET_CUSTOM_STEP":return{...t,customStep:n.payload};case"SET_YAXIS_LIMITS":return{...t,yaxis:{...t.yaxis,limits:{...t.yaxis.limits,range:n.payload}}};case"SET_IS_HISTOGRAM":return{...t,isHistogram:n.payload};case"SET_IS_EMPTY_HISTOGRAM":return{...t,isEmptyHistogram:n.payload};case"SET_SPAN_GAPS":return{...t,spanGaps:n.payload};case"SET_OPEN_SETTINGS":return{...t,openSettings:n.payload};default:throw new Error}}const fa=yt({}),He=()=>$e(fa).state,vt=()=>$e(fa).dispatch,Hl=({children:t})=>{const[n,r]=Et(zl,Fl),a=M(()=>({state:n,dispatch:r}),[n,r]);return e(fa.Provider,{value:a,children:t})},Vl={dashboardsSettings:[],dashboardsLoading:!1,dashboardsError:""};function ql(t,n){switch(n.type){case"SET_DASHBOARDS_SETTINGS":return{...t,dashboardsSettings:n.payload};case"SET_DASHBOARDS_LOADING":return{...t,dashboardsLoading:n.payload};case"SET_DASHBOARDS_ERROR":return{...t,dashboardsError:n.payload};default:throw new Error}}const _a=yt({}),Ms=()=>$e(_a).state,Ul=()=>$e(_a).dispatch,Bl=({children:t})=>{const[n,r]=Et(ql,Vl),a=M(()=>({state:n,dispatch:r}),[n,r]);return e(_a.Provider,{value:a,children:t})},jl={markdownParsing:Ae("LOGS_MARKDOWN")==="true",ansiParsing:Ae("LOGS_ANSI")==="true",autocompleteCache:new Map};function Ql(t,n){switch(n.type){case"SET_MARKDOWN_PARSING":return Le("LOGS_MARKDOWN",`${n.payload}`),{...t,markdownParsing:n.payload};case"SET_ANSI_PARSING":return Le("LOGS_ANSI",`${n.payload}`),{...t,ansiParsing:n.payload};case"SET_AUTOCOMPLETE_CACHE":{if(t.autocompleteCache.size>=Tt.cacheLimit){const r=t.autocompleteCache.keys().next().value;r&&t.autocompleteCache.delete(r)}return t.autocompleteCache.set(n.payload.key,n.payload.value),{...t,autocompleteCache:t.autocompleteCache}}default:throw new Error}}const ba=yt({}),ya=()=>$e(ba).state,Is=()=>$e(ba).dispatch,Yl=({children:t})=>{const[n,r]=Et(Ql,jl),a=M(()=>({state:n,dispatch:r}),[n,r]);return e(ba.Provider,{value:a,children:t})},Ps={windows:"Windows",mac:"Mac OS",linux:"Linux"},Gl=()=>Object.values(Ps).find(t=>navigator.userAgent.indexOf(t)>=0)||"unknown",Jn=()=>Gl()===Ps.mac,Wl=()=>["Android","webOS","iPhone","iPad","iPod","BlackBerry","Windows Phone"].map(r=>navigator.userAgent.match(new RegExp(r,"i"))).some(r=>r);function J(){const t=Pt(),n=()=>{const o=Wl(),s=window.innerWidth<500;return o||s},[r,a]=N(n());return A(()=>{a(n())},[t]),{isMobile:r}}const Jl={success:e(us,{}),error:e(ra,{}),warning:e(na,{}),info:e(mt,{})},le=({variant:t,children:n})=>{const{isDarkTheme:r}=se(),{isMobile:a}=J();return e("div",{className:I({"vm-alert":!0,[`vm-alert_${t}`]:t,"vm-alert_dark":r,"vm-alert_mobile":a}),children:[e("div",{className:"vm-alert__icon",children:Jl[t||"info"]}),e("div",{className:"vm-alert__content",children:n})]})},Ds=yt({showInfoMessage:()=>{}}),Kl=()=>$e(Ds),Zl=({children:t})=>{const{isMobile:n}=J(),[r,a]=N({text:"",type:"info"}),[o,s]=N(!1),[i,l]=N(null);A(()=>{if(!i)return;a({...i,key:Date.now()}),s(!0);const d=setTimeout(c,i.timeout||4e3);return()=>clearTimeout(d)},[i]);const c=()=>{l(null),s(!1)};return e(Ds.Provider,{value:{showInfoMessage:l},children:[o&&e("div",{className:I({"vm-snackbar":!0,"vm-snackbar_mobile":n}),children:e(le,{variant:r.type,children:e("div",{className:"vm-snackbar-content",children:[e("span",{children:r.text}),e("div",{className:"vm-snackbar-content__close",onClick:c,children:e(Ue,{})})]})})}),t]})},Xl=(...t)=>t.reduce((n,r)=>({children:a})=>e(n,{children:e(r,{children:a})}),({children:n})=>e(V,{children:n})),ec=[sl,wl,El,$l,Hl,Zl,Bl,Yl],wa=Xl(...ec);var on=(t=>(t[t.internalLink=0]="internalLink",t[t.externalLink=1]="externalLink",t))(on||{});const tc=(t,n)=>({label:"Alerts",value:!!dn(t)?`${t}/vmalert`:t.replace(/\/prometheus$/,"/vmalert"),type:1,hide:!n}),nc=t=>[{value:Z.trace},{value:Z.queryAnalyzer},{value:Z.withTemplate},{value:Z.relabel},{value:Z.downsamplingDebug,hide:!t},{value:Z.retentionDebug,hide:!t}],rc=()=>[{value:Z.metrics},{value:Z.cardinality},{value:Z.topQueries},{value:Z.activeQueries}],ac=({serverUrl:t,isEnterpriseLicense:n,showPredefinedDashboards:r,showAlertLink:a})=>[{value:Z.home},{value:Z.rawQuery},{label:"Explore",submenu:rc()},{label:"Tools",submenu:nc(n)},{value:Z.dashboards,hide:!r},tc(t,a)],oc=()=>[{label:gt[Z.logs].title,value:Z.home}],sc=()=>[{label:gt[Z.anomaly].title,value:Z.home}],xr=({activeMenu:t,label:n,value:r,type:a,color:o})=>a===on.externalLink?e("a",{className:I({"vm-header-nav-item":!0,"vm-header-nav-item_active":t===r}),style:{color:o},href:r,target:"_blank",rel:"noreferrer",children:n}):e(Yo,{className:I({"vm-header-nav-item":!0,"vm-header-nav-item_active":t===r}),style:{color:o},to:r,children:n}),_n=(t,n,r)=>{const a=W(o=>{const s=t==null?void 0:t.current,i=o.target,l=(r==null?void 0:r.current)&&r.current.contains(i);!s||s.contains((o==null?void 0:o.target)||null)||l||n(o)},[t,n]);me("mouseup",a),me("touchstart",a)},D=({variant:t="contained",color:n="primary",size:r="medium",ariaLabel:a,children:o,endIcon:s,startIcon:i,fullWidth:l=!1,className:c,disabled:d,onClick:m,onMouseDown:u,"data-id":h})=>{const p=I({"vm-button":!0,[`vm-button_${t}_${n}`]:!0,[`vm-button_${r}`]:r,"vm-button_icon_only":(i||s)&&!o,"vm-button_full-width":l,"vm-button_with-icons":i||s,[c||""]:c});return e("button",{className:p,disabled:d,"aria-label":a,onClick:m,onMouseDown:u,"data-id":h,children:[i,o,s]})},Ie=({children:t,buttonRef:n,placement:r="bottom-left",placementPosition:a,open:o=!1,onClose:s,offset:i={top:6,left:0},clickOutside:l=!0,fullWidth:c,title:d,disabledFullScreen:m,variant:u})=>{const{isMobile:h}=J(),p=qn(),v=ht(),[b,f]=N({width:0,height:0}),[g,_]=N(!1),y=q(null);A(()=>(_(o),!o&&s&&s(),o&&h&&!m&&(document.body.style.overflow="hidden"),()=>{document.body.style.overflow="auto"}),[o]),A(()=>{var L,x;f({width:((L=y==null?void 0:y.current)==null?void 0:L.clientWidth)||0,height:((x=y==null?void 0:y.current)==null?void 0:x.clientHeight)||0}),_(!1)},[y]);const S=M(()=>{const L=n.current;if(!L||!g)return{};const x=L.getBoundingClientRect(),E={top:0,left:0,width:"auto"},P=r==="bottom-right"||r==="top-right",F=r==null?void 0:r.includes("top"),O=(i==null?void 0:i.top)||0,H=(i==null?void 0:i.left)||0;if(E.left=E.left=x.left+H,E.top=x.height+x.top+O,P&&(E.left=x.right-b.width),F&&(E.top=x.top-b.height-O),r==="fixed"&&a)return E.top=Math.max(a.top+i.top,0),E.left=Math.max(a.left+i.left,0),E;const{innerWidth:z,innerHeight:Y}=window,G=E.top+b.height>Y,K=E.top<0,re=E.left+b.width>z,Q=E.left<0;return G&&(E.top=x.top-b.height-O),K&&(E.top=x.height+x.top+O),re&&(E.left=x.right-b.width-H),Q&&(E.left=x.left+H),c&&(E.width=`${x.width}px`),E.top<0&&(E.top=0),E.left<0&&(E.left=0),E},[n,r,g,t,c]),T=L=>{L.stopPropagation(),s()},w=()=>{_(!1),s()},C=()=>{l&&w()};A(()=>{if(!y.current||!g||h&&!m)return;const{right:L,width:x}=y.current.getBoundingClientRect();if(L>window.innerWidth){const E=window.innerWidth-x;y.current.style.left=`${E}px`}},[g,y,a]);const k=W(()=>{g&&h&&!m&&(p(v,{replace:!0}),s())},[g,h,m,v,s]);return me("scroll",w),me("popstate",k),_n(y,C,n),e(V,{children:(g||!b.width)&&pt(e("div",{className:I({"vm-popper":!0,[`vm-popper_${u}`]:u,"vm-popper_mobile":h&&!m,"vm-popper_open":(h||Object.keys(S).length)&&g}),ref:y,style:h&&!m?{}:S,children:[(d||h&&!m)&&e("div",{className:"vm-popper-header",children:[e("p",{className:"vm-popper-header__title",children:d}),e(D,{variant:"text",color:u==="dark"?"white":"primary",size:"small",onClick:T,ariaLabel:"close",children:e(Ue,{})})]}),t]}),document.body)})},ae=t=>{const[n,r]=N(!!t),a=W(()=>r(!0),[]),o=W(()=>r(!1),[]),s=W(()=>r(i=>!i),[]);return{value:n,setValue:r,setTrue:a,setFalse:o,toggle:s}},ic=({activeMenu:t,label:n,color:r,background:a,submenu:o,direction:s})=>{const{pathname:i}=ht(),[l,c]=N(null),d=q(null),{value:m,setFalse:u,setTrue:h}=ae(!1),p=()=>{h(),l&&clearTimeout(l)},v=()=>{l&&clearTimeout(l);const f=setTimeout(u,300);c(f)},b=()=>{l&&clearTimeout(l)};return A(()=>{u()},[i]),s==="column"?e(V,{children:o.map(f=>e(xr,{activeMenu:t,value:f.value||"",label:f.label||"",type:f.type||on.internalLink},f.value))}):e("div",{className:I({"vm-header-nav-item":!0,"vm-header-nav-item_sub":!0,"vm-header-nav-item_open":m,"vm-header-nav-item_active":o.find(f=>f.value===t)}),style:{color:r},onMouseEnter:p,onMouseLeave:v,ref:d,children:[n,e(Je,{}),e(Ie,{open:m,placement:"bottom-left",offset:{top:12,left:0},onClose:u,buttonRef:d,children:e("div",{className:"vm-header-nav-item-submenu",style:{background:a},onMouseLeave:v,onMouseEnter:b,children:o.map(f=>e(xr,{activeMenu:t,value:f.value||"",label:f.label||"",color:r,type:f.type||on.internalLink},f.value))})})]})},lc=t=>{try{return t.replace(/^\/+/,"").replace(/-/g," ").trim().replace(/^\w/,n=>n.toUpperCase())}catch{return t}},Os=t=>t.filter(n=>!n.hide).map(n=>{var a;const r={...n};return r.value&&!r.label&&(r.label=((a=gt[r.value])==null?void 0:a.title)||lc(r.value)),r.submenu&&r.submenu.length>0&&(r.submenu=Os(r.submenu)),r}),cc=()=>{var m;const t=Ee(),{dashboardsSettings:n}=Ms(),{serverUrl:r,flags:a,appConfig:o}=se(),s=((m=o.license)==null?void 0:m.type)==="enterprise",i=!!a["vmalert.proxyURL"],l=!!(!t&&n.length),c=M(()=>({serverUrl:r,isEnterpriseLicense:s,showAlertLink:i,showPredefinedDashboards:l}),[r,s,i,l]),d=M(()=>{switch(Qt){case dt.victorialogs:return oc();case dt.vmanomaly:return sc();default:return ac(c)}},[c]);return Os(d)},Rs=({color:t,background:n,direction:r})=>{const{pathname:a}=ht(),[o,s]=N(a),i=cc();return A(()=>{s(a)},[a]),e("nav",{className:I({"vm-header-nav":!0,[`vm-header-nav_${r}`]:r}),children:i.map(l=>l.submenu?e(ic,{activeMenu:o,label:l.label||"",submenu:l.submenu,color:t,background:n,direction:r},l.label):e(xr,{activeMenu:o,value:l.value||"",label:l.label||"",color:t,type:l.type||on.internalLink},l.value))})},Me=({title:t,children:n,onClose:r,className:a,isOpen:o=!0})=>{const{isMobile:s}=J(),i=qn(),l=ht(),c=W(h=>{o&&h.key==="Escape"&&r()},[o]),d=h=>{h.stopPropagation()},m=W(()=>{o&&(i(l,{replace:!0}),r())},[o,l,r]);return A(()=>{if(o)return document.body.style.overflow="hidden",()=>{document.body.style.overflow="auto"}},[o]),me("popstate",m),me("keyup",c),pt(e("div",{className:I({"vm-modal":!0,"vm-modal_mobile":s,[`${a}`]:a}),onMouseDown:r,children:e("div",{className:"vm-modal-content",onMouseDown:d,children:[e("div",{className:"vm-modal-content-header",children:[t&&e("div",{className:"vm-modal-content-header__title",children:t}),e("div",{className:"vm-modal-header__close",children:e(D,{variant:"text",size:"small",onClick:r,ariaLabel:"close",children:e(Ue,{})})})]}),e("div",{className:"vm-modal-content-body",tabIndex:0,children:n})]})}),document.body)},j=({children:t,title:n,open:r,placement:a="bottom-center",offset:o={top:6,left:0}})=>{const{isMobile:s}=J(),[i,l]=N(!1),[c,d]=N({width:0,height:0}),m=q(null),u=q(null),h=()=>l(!1);A(()=>{if(!(!u.current||!i))return d({width:u.current.clientWidth,height:u.current.clientHeight}),window.addEventListener("scroll",h),()=>{window.removeEventListener("scroll",h)}},[i,n]);const p=M(()=>{var H;const f=(H=m==null?void 0:m.current)==null?void 0:H.base;if(!f||!i)return{};const g=f.getBoundingClientRect(),_={top:0,left:0},y=a==="bottom-right"||a==="top-right",S=a==="bottom-left"||a==="top-left",T=a==null?void 0:a.includes("top"),w=(o==null?void 0:o.top)||0,C=(o==null?void 0:o.left)||0;_.left=g.left-(c.width-g.width)/2+C,_.top=g.height+g.top+w,y&&(_.left=g.right-c.width),S&&(_.left=g.left+C),T&&(_.top=g.top-c.height-w);const{innerWidth:k,innerHeight:L}=window,x=20,E=_.top+c.height+x>L,P=_.top-x<0,F=_.left+c.width+x>k,O=_.left-x<0;return E&&(_.top=g.top-c.height-w),P&&(_.top=g.height+g.top+w),F&&(_.left=g.right-c.width-C),O&&(_.left=g.left+C),_.top<0&&(_.top=20),_.left<0&&(_.left=20),_},[m,a,i,c]),v=()=>{typeof r!="boolean"&&l(!0)},b=()=>{l(!1)};return A(()=>{typeof r=="boolean"&&l(r)},[r]),A(()=>{var g;const f=(g=m==null?void 0:m.current)==null?void 0:g.base;if(f)return f.addEventListener("mouseenter",v),f.addEventListener("mouseleave",b),()=>{f.removeEventListener("mouseenter",v),f.removeEventListener("mouseleave",b)}},[m]),e(V,{children:[e(V,{ref:m,children:t}),!s&&i&&pt(e("div",{className:"vm-tooltip",ref:u,style:p,children:n}),document.body)]})},Mn=e("code",{children:Jn()?"Cmd":"Ctrl"}),dc=[{title:"Zoom in",description:e(V,{children:["To zoom in, hold down the ",Mn," + ",e("code",{children:"scroll up"}),", or press the ",e("code",{children:"+"}),". Also, you can zoom in on a range on the graph by holding down your mouse button and selecting the range."]})},{title:"Zoom out",description:e(V,{children:["To zoom out, hold down the ",Mn," + ",e("code",{children:"scroll down"}),", or press the ",e("code",{children:"-"}),"."]})},{title:"Move horizontal axis",description:e(V,{children:["To move the graph, hold down the ",Mn," + ",e("code",{children:"drag"})," the graph to the right or left."]})},{title:"Fixing a tooltip",description:e(V,{children:["To fix the tooltip, ",e("code",{children:"click"})," mouse when it's open. Then, you can drag the fixed tooltip by ",e("code",{children:"clicking"})," and ",e("code",{children:"dragging"})," on the ",e(ia,{})," icon."]})},{title:"Set a custom range for the vertical axis",description:e(V,{children:["To set a custom range for the vertical axis, click on the ",e(Ze,{})," icon located in the upper right corner of the graph, activate the toggle, and set the values."]})}],mc=[{title:"Show/hide a legend item",description:e(V,{children:[e("code",{children:"click"})," on a legend item to isolate it on the graph.",Mn," + ",e("code",{children:"click"})," on a legend item to remove it from the graph. To revert to the previous state, click again."]})},{title:"Copy label key-value pairs",description:e(V,{children:[e("code",{children:"click"})," on a label key-value pair to save it to the clipboard."]})},{title:"Collapse/Expand the legend group",description:e(V,{children:[e("code",{children:"click"})," on the group name (e.g. ",e("b",{children:'Query 1: {__name__!=""}'}),") to collapse or expand the legend."]})}],uc=dc.concat(mc),Ca=()=>{const{value:t,setFalse:n,setTrue:r}=ae(!1);return e(V,{children:[e(j,{title:"Show tips on working with the graph",children:e(D,{variant:"text",color:"gray",startIcon:e(vn,{}),onClick:r,ariaLabel:"open the tips"})}),t&&e(Me,{title:"Tips on working with the graph and the legend",onClose:n,children:e("div",{className:"fc-graph-tips",children:uc.map(({title:a,description:o})=>e("div",{className:"fc-graph-tips-item",children:[e("h4",{className:"fc-graph-tips-item__action",children:a}),e("p",{className:"fc-graph-tips-item__description",children:o})]},a))})})]})},Ct=e("code",{children:Jn()?"Cmd":"Ctrl"}),$s=e(V,{children:[e("code",{children:Jn()?"Option":"Ctrl"})," + ",e("code",{children:"Space"})]}),hc=[{title:"Query",list:[{keys:e("code",{children:"Enter"}),description:"Run"},{keys:e(V,{children:[e("code",{children:"Shift"})," + ",e("code",{children:"Enter"})]}),description:"Multi-line queries"},{keys:e(V,{children:[Ct," + ",e("code",{children:"Arrow Up"})]}),description:"Previous command from the Query history"},{keys:e(V,{children:[Ct," + ",e("code",{children:"Arrow Down"})]}),description:"Next command from the Query history"},{keys:e(V,{children:[Ct," + ",e("code",{children:"click"})," by ",e(Vt,{})]}),description:"Toggle multiple queries"},{keys:$s,description:"Show quick autocomplete tips"}]},{title:"Graph",readMore:e(Ca,{}),list:[{keys:e(V,{children:[Ct," + ",e("code",{children:"scroll Up"})," or ",e("code",{children:"+"})]}),description:"Zoom in"},{keys:e(V,{children:[Ct," + ",e("code",{children:"scroll Down"})," or ",e("code",{children:"-"})]}),description:"Zoom out"},{keys:e(V,{children:[Ct," + ",e("code",{children:"drag"})]}),description:"Move the graph left/right"},{keys:e(V,{children:e("code",{children:"click"})}),description:"Select the series in the legend"},{keys:e(V,{children:[Ct," + ",e("code",{children:"click"})]}),description:"Toggle multiple series in the legend"}]}],pr="Shortcut keys",Mr=Jn(),pc=Mr?"Cmd + /":"F1",Fs=({showTitle:t})=>{const n=Ee(),{value:r,setTrue:a,setFalse:o}=ae(!1),s=W(i=>{const l=Mr&&i.key==="/"&&i.metaKey,c=!Mr&&i.key==="F1"&&!i.metaKey;(l||c)&&a()},[a]);return me("keydown",s),e(V,{children:[e(j,{open:t===!0?!1:void 0,title:`${pr} (${pc})`,placement:"bottom-center",children:e(D,{className:n?"":"vm-header-button",variant:"contained",color:"primary",startIcon:e(ps,{}),onClick:a,ariaLabel:pr,children:t&&pr})}),r&&e(Me,{title:"Shortcut keys",onClose:o,children:e("div",{className:"vm-shortcuts",children:hc.map(i=>e("div",{className:"vm-shortcuts-section",children:[i.readMore&&e("div",{className:"vm-shortcuts-section__read-more",children:i.readMore}),e("h3",{className:"vm-shortcuts-section__title",children:i.title}),e("div",{className:"vm-shortcuts-section-list",children:i.list.map((l,c)=>e("div",{className:"vm-shortcuts-section-list-item",children:[e("div",{className:"vm-shortcuts-section-list-item__key",children:l.keys}),e("p",{className:"vm-shortcuts-section-list-item__description",children:l.description})]},`${i.title}_${c}`))})]},i.title))})})]})},gc=({open:t})=>e("button",{className:I({"vm-menu-burger":!0,"vm-menu-burger_opened":t}),"aria-label":"menu",children:e("span",{})}),vc=({background:t,color:n})=>{const{pathname:r}=ht(),{isMobile:a}=J(),o=q(null),{value:s,toggle:i,setFalse:l}=ae(!1);return A(l,[r]),_n(o,l),e("div",{className:"vm-header-sidebar",ref:o,children:[e("div",{className:I({"vm-header-sidebar-button":!0,"vm-header-sidebar-button_open":s}),onClick:i,children:e(gc,{open:s})}),e("div",{className:I({"vm-header-sidebar-menu":!0,"vm-header-sidebar-menu_open":s}),children:[e("div",{children:e(Rs,{color:n,background:t,direction:"column"})}),e("div",{className:"vm-header-sidebar-menu-settings",children:!a&&!1})]})]})},fc=t=>`${t.replace(/^(.+)(\/select.+)/,"$1")}/admin/tenants`,_c=()=>{const{useTenantID:t}=cn(),n=Ee(),{serverUrl:r}=se(),[a,o]=N(!1),[s,i]=N(),[l,c]=N([]),d=M(()=>fc(r),[r]),m=M(()=>!!dn(r),[r]),u=n?!t:!m;return A(()=>{if(u)return;(async()=>{o(!0);try{const p=await fetch(d),v=await p.json(),b=v.data||[];c(b.sort((f,g)=>f.localeCompare(g))),p.ok?i(void 0):i(`${v.errorType}\r -${v==null?void 0:v.error}`)}catch(p){p instanceof Error&&i(`${p.name}: ${p.message}`)}o(!1)})().catch(console.error)},[d]),{accountIds:l,isLoading:a,error:s}},bc=({controlsComponent:t,isMobile:n,...r})=>{const a=Ee(),{pathname:o}=ht(),{accountIds:s}=_c(),{value:i,toggle:l,setFalse:c}=ae(!1),d=M(()=>(gt[o]||{}).header||{},[o]),m=e(t,{...r,isMobile:n,accountIds:s,headerSetup:d});return n?e(V,{children:[e("div",{children:e(D,{className:I({"vm-header-button":!a}),startIcon:e(ca,{}),onClick:l,ariaLabel:"controls"})}),e(Me,{title:"Controls",onClose:c,isOpen:i,className:I({"vm-header-controls-modal":!0,"vm-header-controls-modal_open":i}),children:m})]}):m},lo=()=>{switch(Qt){case dt.victorialogs:return e(cs,{});case dt.vmanomaly:return e(ds,{});default:return e(ls,{})}},Na=({controlsComponent:t})=>{const{isMobile:n}=J(),r=Pt(),a=M(()=>window.innerWidth<1e3,[r]),{isDarkTheme:o}=se(),s=Ee(),i=M(()=>tt(o?"color-background-block":"color-primary"),[o]),{background:l,color:c}=M(()=>{const{headerStyles:{background:u=s?"#FFF":i,color:h=s?i:"#FFF"}={}}=cn();return{background:u,color:h}},[i]),d=qn(),m=()=>{d({pathname:Z.home}),window.location.reload()};return e("header",{className:I({"vm-header":!0,"vm-header_app":s,"vm-header_dark":o,"vm-header_sidebar":a,"vm-header_mobile":n}),style:{background:l,color:c},children:[a?e(vc,{background:l,color:c}):e(V,{children:[!s&&e("div",{className:"vm-header-logo",onClick:m,style:{color:c},children:e(lo,{})}),e(Rs,{color:c,background:l})]}),a&&e("div",{className:I({"vm-header-logo":!0,"vm-header-logo_mobile":!0}),onClick:m,style:{color:c},children:e(lo,{})}),e(bc,{controlsComponent:t,displaySidebar:a,isMobile:n})]})},zs={href:"https://github.com/VictoriaMetrics/VictoriaMetrics/issues/new/choose",Icon:fs,title:"Create an issue"},yc=[{href:"https://docs.victoriametrics.com/victoriametrics/metricsql/",Icon:It,title:"MetricsQL"},{href:"https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#vmui",Icon:ut,title:"Documentation"},zs],wc=[{href:"https://docs.victoriametrics.com/victorialogs/logsql/",Icon:It,title:"LogsQL"},{href:"https://docs.victoriametrics.com/victorialogs/",Icon:ut,title:"Documentation"},zs],Sa=zr(({links:t=yc})=>{const n=`2019-${new Date().getFullYear()}`;return e("footer",{className:"vm-footer",children:[e("a",{className:"vm-link vm-footer__website",target:"_blank",href:"https://victoriametrics.com/",rel:"me noreferrer",children:[e(ms,{}),"victoriametrics.com"]}),t.map(({href:r,Icon:a,title:o})=>e("a",{className:"vm-link vm-footer__link",target:"_blank",href:r,rel:"help noreferrer",children:[e(a,{}),o]},`${r}-${o}`)),e("div",{className:"vm-footer__copyright",children:["© ",n," VictoriaMetrics"]})]})}),Cc=()=>{const t=Ee(),{serverUrl:n}=se(),r=Ul(),[a,o]=N(!1),[s,i]=N(""),[l,c]=N([]),d=async()=>{};return A(()=>{t||(c([]),d())},[n]),A(()=>{r({type:"SET_DASHBOARDS_SETTINGS",payload:l})},[l]),A(()=>{r({type:"SET_DASHBOARDS_LOADING",payload:a})},[a]),A(()=>{r({type:"SET_DASHBOARDS_ERROR",payload:s})},[s]),{dashboardsSettings:l,isLoading:a,error:s}},Nc=({error:t,warning:n,info:r})=>{const a=q(null),[o,s]=N(!1),[i,l]=N(!1),d=`${M(()=>t?"ERROR: ":n?"WARNING: ":"",[t,n])}${t||n||r}`,m=()=>{const h=a.current;if(h){const{offsetWidth:p,scrollWidth:v,offsetHeight:b,scrollHeight:f}=h,g=p+1{o&&(l(!0),s(!1))};return A(()=>{l(!1),m()},[a,d]),me("resize",m),!t&&!n&&!r?null:e("span",{className:I({"vm-text-field__error":!0,"vm-text-field__warning":n&&!t,"vm-text-field__helper-text":!n&&!t,"vm-text-field__error_overflowed":o,"vm-text-field__error_full":i}),"data-show":!!d,ref:a,onClick:u,children:d})},ce=({label:t,value:n,type:r="text",error:a="",warning:o="",helperText:s="",placeholder:i,endIcon:l,startIcon:c,disabled:d=!1,autofocus:m=!1,inputmode:u="text",caretPosition:h,onChange:p,onEnter:v,onKeyDown:b,onFocus:f,onBlur:g,onChangeCaret:_})=>{const{isDarkTheme:y}=se(),{isMobile:S}=J(),T=q(null),w=q(null),C=M(()=>r==="textarea"?w:T,[r]),k=I({"vm-text-field__input":!0,"vm-text-field__input_error":a,"vm-text-field__input_warning":!a&&o,"vm-text-field__input_icon-start":c,"vm-text-field__input_disabled":d,"vm-text-field__input_textarea":r==="textarea"}),L=Y=>{if(!_)return;const{selectionStart:G,selectionEnd:K}=Y;_&&_([G||0,K||0])},x=Y=>{L(Y.currentTarget)},E=Y=>{b&&b(Y);const{key:G,ctrlKey:K,metaKey:re}=Y,Q=G==="Enter";(r!=="textarea"?Q:Q&&(re||K))&&v&&(Y.preventDefault(),v())},P=Y=>{L(Y.currentTarget)},F=Y=>{d||(p&&p(Y.currentTarget.value),L(Y.currentTarget))},O=()=>{f&&f()},H=()=>{g&&g()},z=Y=>{try{C.current&&C.current.setSelectionRange(Y[0],Y[1])}catch(G){return G}};return A(()=>{var Y;!m||S||(Y=C==null?void 0:C.current)!=null&&Y.focus&&C.current.focus()},[C,m]),A(()=>{h&&z(h)},[h]),e("label",{className:I({"vm-text-field":!0,"vm-text-field_textarea":r==="textarea","vm-text-field_dark":y}),"data-replicated-value":n,children:[c&&e("div",{className:"vm-text-field__icon-start",children:c}),l&&e("div",{className:"vm-text-field__icon-end",children:l}),r==="textarea"?e("textarea",{className:k,disabled:d,ref:w,value:n,rows:1,inputMode:u,placeholder:i,autoCapitalize:"none",onInput:F,onKeyDown:E,onKeyUp:P,onFocus:O,onBlur:H,onMouseUp:x}):e("input",{className:k,disabled:d,ref:T,value:n,type:r,placeholder:i,inputMode:u,autoCapitalize:"none",onInput:F,onKeyDown:E,onKeyUp:P,onFocus:O,onBlur:H,onMouseUp:x}),t&&e("span",{className:"vm-text-field__label",children:t}),e(Nc,{error:a,warning:o,info:s})]})},Hs=({accountIds:t})=>{const n=Ee(),{isMobile:r}=J(),{tenantId:a,serverUrl:o}=se(),s=xt(),i=Be(),[l,c]=N(""),d=q(null),{value:m,toggle:u,setFalse:h}=ae(!1),p=M(()=>{if(!l)return t;try{const f=new RegExp(l,"i");return t.filter(_=>f.test(_)).sort((_,y)=>{var S,T;return(((S=_.match(f))==null?void 0:S.index)||0)-(((T=y.match(f))==null?void 0:T.index)||0)})}catch{return[]}},[l,t]),v=M(()=>t.length>1,[t]),b=f=>()=>{const g=f;if(s({type:"SET_TENANT_ID",payload:g}),o){const _=Wo(o,g);if(_===o)return;s({type:"SET_SERVER",payload:_}),i({type:"RUN_QUERY"})}h()};return A(()=>{const f=dn(o);a&&a!==f?b(a)():b(f)()},[o]),v?e("div",{className:"vm-tenant-input",children:[e(j,{title:"Define Tenant ID if you need request to another storage",children:e("div",{ref:d,children:r?e("div",{className:"vm-mobile-option",onClick:u,children:[e("span",{className:"vm-mobile-option__icon",children:e(Lt,{})}),e("div",{className:"vm-mobile-option-text",children:[e("span",{className:"vm-mobile-option-text__label",children:"Tenant ID"}),e("span",{className:"vm-mobile-option-text__value",children:a})]}),e("span",{className:"vm-mobile-option__arrow",children:e(be,{})})]}):e(D,{className:n?"":"vm-header-button",variant:"contained",color:"primary",fullWidth:!0,startIcon:e(Lt,{}),endIcon:e("div",{className:I({"vm-execution-controls-buttons__arrow":!0,"vm-execution-controls-buttons__arrow_open":m}),children:e(be,{})}),onClick:u,children:a})})}),e(Ie,{open:m,placement:"bottom-right",onClose:h,buttonRef:d,title:r?"Define Tenant ID":void 0,children:e("div",{className:I({"vm-list vm-tenant-input-list":!0,"vm-list vm-tenant-input-list_mobile":r}),children:[e("div",{className:"vm-tenant-input-list__search",children:e(ce,{autofocus:!0,label:"Search",value:l,onChange:c,type:"search"})}),p.map(f=>e("div",{className:I({"vm-list-item":!0,"vm-list-item_mobile":r,"vm-list-item_active":f===a}),onClick:b(f),children:f},f))]})})]}):null};function qt(t){const n=q();return A(()=>{n.current=t},[t]),n.current}const Te=({text:t,href:n,children:r,colored:a=!0,underlined:o=!1,withIcon:s=!1})=>e("a",{href:n,className:I({"vm-link":!0,"vm-link_colored":a,"vm-link_underlined":o,"vm-link_with-icon":s}),target:"_blank",rel:"noreferrer",children:t||r}),Vs=()=>{const t=Ee(),{isMobile:n}=J(),{customStep:r,isHistogram:a}=He(),{period:{step:o,end:s,start:i}}=ge(),l=vt(),{displayType:c}=je(),d=qt(s-i),m=M(()=>mn(s-i,a,c),[s,i,a,c]),u=qt(m),[h,p]=N(r||m),[v,b]=N(""),f=r===m,{value:g,toggle:_,setFalse:y}=ae(!1),S=q(null),T=E=>{const P=E||h||m||"1s",O=(P.match(/[a-zA-Z]+/g)||[]).length?P:`${P}s`;l({type:"SET_CUSTOM_STEP",payload:O}),p(O),b("")},w=()=>{T(),y()},C=()=>{document.activeElement instanceof HTMLInputElement&&document.activeElement.select()},k=()=>{T(),w()},L=E=>{const P=E.match(/[-+]?([0-9]*\.[0-9]+|[0-9]+)/g)||[],F=E.match(/[a-zA-Z]+/g)||[],O=P.length&&P.every(Y=>parseFloat(Y)>0),H=F.every(Y=>Jr.find(G=>G.short===Y)),z=O&&H;p(E),b(z?"":Ce.validStep)},x=()=>{const E=m||"1s";L(E),T(E)};return A(()=>{r&&T(r)},[r]),A(()=>{!r&&m&&T(m)},[m]),A(()=>{s-i===d||!d||r!==u||m&&T(m)},[d,m]),A(()=>{(o===r||o===m)&&T(m)},[a,c]),e("div",{className:"vm-step-control",ref:S,children:[n?e("div",{className:"vm-mobile-option",onClick:_,children:[e("span",{className:"vm-mobile-option__icon",children:e($n,{})}),e("div",{className:"vm-mobile-option-text",children:[e("span",{className:"vm-mobile-option-text__label",children:"Step"}),e("span",{className:"vm-mobile-option-text__value",children:h})]}),e("span",{className:"vm-mobile-option__arrow",children:e(be,{})})]}):e(D,{className:t?"":"vm-header-button",variant:"contained",color:"primary",startIcon:e($n,{}),onClick:_,children:["Step: ",f?`auto (${h})`:h]}),e(Ie,{open:g,placement:"bottom-right",onClose:w,buttonRef:S,title:n?"Query resolution step width":void 0,children:e("div",{className:I({"vm-step-control-popper":!0,"vm-step-control-popper_mobile":n}),children:[e(ce,{autofocus:!0,label:"Step value",value:h,error:v,onChange:L,onEnter:k,onFocus:C,onBlur:T,endIcon:e(j,{title:`Reset to auto step (${m})`,children:e(D,{size:"small",variant:"text",color:"primary",startIcon:e(ct,{}),onClick:x,ariaLabel:"reset step"})})}),e("div",{className:"vm-step-control-popper-info",children:[e("p",{children:[e("code",{children:"step"})," - the ",e(Te,{href:"https://prometheus.io/docs/prometheus/latest/querying/basics/#time-durations",text:"interval"})," between datapoints, which must be returned from the range query. The ",e("code",{children:"query"})," is executed at ",e("code",{children:"start"}),", ",e("code",{children:"start+step"}),", ",e("code",{children:"start+2*step"}),", …, ",e("code",{children:"end"})," timestamps."]}),e("p",{children:["Read more about ",e(Te,{href:"https://docs.victoriametrics.com/victoriametrics/keyconcepts/#range-query",text:"Range"})," and ",e(Te,{href:"https://docs.victoriametrics.com/victoriametrics/keyconcepts/#instant-query",text:"Instant"})," queries."]})]})]})})]})},Sc=({relativeTime:t,setDuration:n})=>{const{isMobile:r}=J(),a=o=>()=>{n(o)};return e("div",{className:I({"vm-time-duration":!0,"vm-time-duration_mobile":r}),children:nn.map(({id:o,duration:s,until:i,title:l})=>e("div",{className:I({"vm-list-item":!0,"vm-list-item_mobile":r,"vm-list-item_active":o===t}),onClick:a({duration:s,until:i(),id:o}),children:l||s},o))})},kc=({viewDate:t,showArrowNav:n,onChangeViewDate:r,toggleDisplayYears:a})=>{const o=()=>{r(t.subtract(1,"month"))},s=()=>{r(t.add(1,"month"))};return e("div",{className:"vm-calendar-header",children:[e("div",{className:"vm-calendar-header-left",onClick:a,children:[e("span",{className:"vm-calendar-header-left__date",children:t.format("MMMM YYYY")}),e("div",{className:"vm-calendar-header-left__select-year",children:e(Je,{})})]}),n&&e("div",{className:"vm-calendar-header-right",children:[e("div",{className:"vm-calendar-header-right__prev",onClick:o,children:e(be,{})}),e("div",{className:"vm-calendar-header-right__next",onClick:s,children:e(be,{})})]})]})},Tc=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],Lc=({viewDate:t,selectDate:n,onChangeSelectDate:r})=>{const a="YYYY-MM-DD",o=U.tz(),s=U(t.format(a)),i=M(()=>{const c=new Array(42).fill(null),d=s.startOf("month"),u=s.endOf("month").diff(d,"day")+1,h=new Array(u).fill(d).map((v,b)=>v.add(b,"day")),p=d.day();return c.splice(p,u,...h),c},[s]),l=c=>()=>{c&&r(c)};return e("div",{className:"vm-calendar-body",children:[Tc.map(c=>e(j,{title:c,children:e("div",{className:"vm-calendar-body-cell vm-calendar-body-cell_weekday",children:c[0]})},c)),i.map((c,d)=>e("div",{className:I({"vm-calendar-body-cell":!0,"vm-calendar-body-cell_day":!0,"vm-calendar-body-cell_day_empty":!c,"vm-calendar-body-cell_day_active":(c&&c.format(a))===n.format(a),"vm-calendar-body-cell_day_today":(c&&c.format(a))===o.format(a)}),onClick:l(c),children:c&&c.format("D")},c?c.format(a):d))]})},Ac=({viewDate:t,onChangeViewDate:n})=>{const r=U().format("YYYY"),a=M(()=>t.format("YYYY"),[t]),o=M(()=>{const c=U().subtract(18/2,"year");return new Array(18).fill(c).map((d,m)=>d.add(m,"year"))},[t]);A(()=>{const i=document.getElementById(`vm-calendar-year-${a}`);i&&i.scrollIntoView({block:"center"})},[]);const s=i=>()=>{n(i)};return e("div",{className:"vm-calendar-years",children:o.map(i=>e("div",{className:I({"vm-calendar-years__year":!0,"vm-calendar-years__year_selected":i.format("YYYY")===a,"vm-calendar-years__year_today":i.format("YYYY")===r}),id:`vm-calendar-year-${i.format("YYYY")}`,onClick:s(i),children:i.format("YYYY")},i.format("YYYY")))})},Ec=({viewDate:t,selectDate:n,onChangeViewDate:r})=>{const a=U().format("MM"),o=M(()=>n.format("MM"),[n]),s=M(()=>new Array(12).fill("").map((l,c)=>U(t).month(c)),[t]);A(()=>{const l=document.getElementById(`vm-calendar-year-${o}`);l&&l.scrollIntoView({block:"center"})},[]);const i=l=>()=>{r(l)};return e("div",{className:"vm-calendar-years",children:s.map(l=>e("div",{className:I({"vm-calendar-years__year":!0,"vm-calendar-years__year_selected":l.format("MM")===o,"vm-calendar-years__year_today":l.format("MM")===a}),id:`vm-calendar-year-${l.format("MM")}`,onClick:i(l),children:l.format("MMMM")},l.format("MM")))})},xc=({date:t,format:n=qe,onChange:r})=>{const[a,o]=N(0),[s,i]=N(U.tz(t)),[l,c]=N(U.tz(t)),d=U.tz(),m=d.format(kt)===s.format(kt),{isMobile:u}=J(),h=()=>{o(f=>f===2?0:2)},p=f=>{i(f),o(g=>g===2?1:0)},v=f=>{c(f)},b=()=>{i(d)};return A(()=>{l.format()!==U.tz(t).format()&&r(l.format(n))},[l]),A(()=>{const f=U.tz(t);i(f),c(f)},[t]),e("div",{className:I({"vm-calendar":!0,"vm-calendar_mobile":u}),children:[e(kc,{viewDate:s,onChangeViewDate:p,toggleDisplayYears:h,showArrowNav:a===0}),a===0&&e(Lc,{viewDate:s,selectDate:l,onChangeSelectDate:v}),a===2&&e(Ac,{viewDate:s,onChangeViewDate:p}),a===1&&e(Ec,{selectDate:l,viewDate:s,onChangeViewDate:p}),!m&&a===0&&e("div",{className:"vm-calendar-footer",children:e(D,{variant:"text",size:"small",onClick:b,children:"show today"})})]})},qs=Un(({date:t,targetRef:n,format:r=qe,onChange:a,label:o},s)=>{const i=M(()=>U(t).isValid()?U.tz(t):U().tz(),[t]),{isMobile:l}=J(),{value:c,toggle:d,setFalse:m}=ae(!1),u=p=>{a(p),m()},h=p=>{(p.key==="Escape"||p.key==="Enter")&&m()};return me("click",d,n),me("keyup",h),e(V,{children:e(Ie,{open:c,buttonRef:n,placement:"bottom-right",onClose:m,title:l?o:void 0,children:e("div",{ref:s,children:e(xc,{date:i,format:r,onChange:u})})})})}),co=t=>U(t).isValid()?U.tz(t).format(qe):t,mo=({value:t="",label:n,pickerLabel:r,pickerRef:a,onChange:o,onEnter:s})=>{const i=q(null),[l,c]=N(null),[d,m]=N(co(t)),[u,h]=N(!1),[p,v]=N(!1),b=U(d).isValid()?"":"Invalid date format",f=S=>{m(S.currentTarget.value)},g=()=>{o(d)},_=S=>{S.key==="Enter"&&(o(d),v(!0))},y=S=>{m(S),h(!0)};return A(()=>{const S=co(t);S!==d&&m(S),p&&(s(),v(!1))},[t]),A(()=>{u&&l&&(l.focus(),l.setSelectionRange(11,11),h(!1))},[u]),e("div",{className:I({"vm-date-time-input":!0,"vm-date-time-input_error":b}),children:[e("label",{children:n}),e(ji,{tabIndex:1,inputRef:c,mask:"9999-99-99 99:99:99",placeholder:"YYYY-MM-DD HH:mm:ss",value:d,autoCapitalize:"none",inputMode:"numeric",maskChar:null,onChange:f,onBlur:g,onKeyUp:_}),b&&e("span",{className:"vm-date-time-input__error-text",children:b}),e("div",{className:"vm-date-time-input__icon",ref:i,children:e(D,{variant:"text",color:"gray",size:"small",startIcon:e(Rn,{}),ariaLabel:"calendar"})}),e(qs,{label:r,ref:a,date:d,onChange:y,targetRef:i})]})},ka=()=>{const{isMobile:t}=J(),{isDarkTheme:n}=se(),r=q(null),a=Pt(),o=M(()=>a.width>1120,[a]),[s,i]=N(),[l,c]=N(),{period:{end:d,start:m},relativeTime:u,timezone:h,duration:p}=ge(),v=Be(),b=Ee(),f=qt(h),{value:g,toggle:_,setFalse:y}=ae(!1),S=M(()=>({region:h,utc:en(h)}),[h]);A(()=>{i(Ft(We(d)))},[h,d]),A(()=>{c(Ft(We(m)))},[h,m]);const T=({duration:O,until:H,id:z})=>{v({type:"SET_RELATIVE_TIME",payload:{duration:O,until:H,id:z}}),y()},w=M(()=>{const O=U.tz(We(m)).format(qe),H=U.tz(We(d)).format(qe);return{start:O,end:H}},[m,d,h]),C=M(()=>u&&u!=="none"?u.replace(/_/g," "):`${w.start} - ${w.end}`,[u,w]),k=q(null),L=q(null),x=q(null),E=()=>{l&&s&&v({type:"SET_PERIOD",payload:{from:U.tz(l).toDate(),to:U.tz(s).toDate()}}),y()},P=()=>v({type:"RUN_QUERY_TO_NOW"}),F=()=>{i(Ft(We(d))),c(Ft(We(m))),y()};return A(()=>{const O=Xr({relativeTimeId:u,defaultDuration:p,defaultEndInput:We(d)});f&&h!==f&&T({id:O.relativeTimeId,duration:O.duration,until:O.endInput})},[h,f]),_n(r,O=>{var G,K;if(t)return;const H=O.target,z=(k==null?void 0:k.current)&&((G=k==null?void 0:k.current)==null?void 0:G.contains(H)),Y=(L==null?void 0:L.current)&&((K=L==null?void 0:L.current)==null?void 0:K.contains(H));z||Y||y()}),e(V,{children:[e("div",{ref:x,children:t?e("div",{className:"vm-mobile-option",onClick:_,children:[e("span",{className:"vm-mobile-option__icon",children:e(rn,{})}),e("div",{className:"vm-mobile-option-text",children:[e("span",{className:"vm-mobile-option-text__label",children:"Time range"}),e("span",{className:"vm-mobile-option-text__value",children:C})]}),e("span",{className:"vm-mobile-option__arrow",children:e(be,{})})]}):e(j,{title:o?"Time range controls":C,children:e(D,{className:b?"":"vm-header-button",variant:"contained",color:"primary",startIcon:e(rn,{}),onClick:_,ariaLabel:"time range controls",children:o&&e("span",{children:C})})})}),e(Ie,{open:g,buttonRef:x,placement:"bottom-right",onClose:y,clickOutside:!1,title:t?"Time range controls":"",children:e("div",{className:I({"vm-time-selector":!0,"vm-time-selector_mobile":t}),ref:r,children:[e("div",{className:"vm-time-selector-left",children:[e("div",{className:I({"vm-time-selector-left-inputs":!0,"vm-time-selector-left-inputs_dark":n}),children:[e(mo,{value:l,label:"From:",pickerLabel:"Date From",pickerRef:k,onChange:c,onEnter:E}),e(mo,{value:s,label:"To:",pickerLabel:"Date To",pickerRef:L,onChange:i,onEnter:E})]}),e("div",{className:"vm-time-selector-left-timezone",children:[e("div",{className:"vm-time-selector-left-timezone__title",children:S.region}),e("div",{className:"vm-time-selector-left-timezone__utc",children:S.utc})]}),e(D,{variant:"text",startIcon:e(hs,{}),onClick:P,children:"switch to now"}),e("div",{className:"vm-time-selector-left__controls",children:[e(D,{color:"error",variant:"outlined",onClick:F,children:"Cancel"}),e(D,{color:"primary",onClick:E,children:"Apply"})]})]}),e(Sc,{relativeTime:u||"",setDuration:T})]})})]})},rt=()=>{const t=qn(),[n,r]=oe();return{setSearchParamsFromKeys:W(o=>{const s=!!Array.from(n.values()).length;let i=!1;Object.entries(o).forEach(([l,c])=>{n.get(l)!==`${c}`&&(n.set(l,`${c}`),i=!0)}),i&&(s?r(n):t(`?${n.toString()}`,{replace:!0}))},[n,t])}},Us=()=>{const{isMobile:t}=J(),n=Ee(),r=q(null),[a]=oe(),{setSearchParamsFromKeys:o}=rt(),s=a.get("date")||U().tz().format(kt),i=M(()=>U.tz(s).format(kt),[s]),l=c=>{o({date:c})};return A(()=>{l(s)},[]),e("div",{children:[e("div",{ref:r,children:t?e("div",{className:"vm-mobile-option",children:[e("span",{className:"vm-mobile-option__icon",children:e(Rn,{})}),e("div",{className:"vm-mobile-option-text",children:[e("span",{className:"vm-mobile-option-text__label",children:"Date control"}),e("span",{className:"vm-mobile-option-text__value",children:i})]}),e("span",{className:"vm-mobile-option__arrow",children:e(be,{})})]}):e(j,{title:"Date control",children:e(D,{className:n?"":"vm-header-button",variant:"contained",color:"primary",startIcon:e(Rn,{}),children:i})})}),e(qs,{label:"Date control",date:s||"",format:kt,onChange:l,targetRef:r})]})},gr=[{seconds:0,title:"Off"},{seconds:1,title:"1s"},{seconds:2,title:"2s"},{seconds:5,title:"5s"},{seconds:10,title:"10s"},{seconds:30,title:"30s"},{seconds:60,title:"1m"},{seconds:300,title:"5m"},{seconds:900,title:"15m"},{seconds:1800,title:"30m"},{seconds:3600,title:"1h"},{seconds:7200,title:"2h"}],Ta=()=>{const{isMobile:t}=J(),n=Be(),r=Ee(),[a,o]=N(!1),[s,i]=N(gr[0]),{value:l,toggle:c,setFalse:d}=ae(!1),m=q(null),u=v=>{(a&&!v.seconds||!a&&v.seconds)&&o(b=>!b),i(v),d()},h=()=>{n({type:"RUN_QUERY"})};A(()=>{const v=s.seconds;let b;return a?b=setInterval(()=>{n({type:"RUN_QUERY"})},v*1e3):i(gr[0]),()=>{b&&clearInterval(b)}},[s,a]);const p=v=>()=>{u(v)};return e(V,{children:[e("div",{className:"vm-execution-controls",children:e("div",{className:I({"vm-execution-controls-buttons":!0,"vm-execution-controls-buttons_mobile":t,"vm-header-button":!r}),children:[!t&&e(j,{title:"Refresh dashboard",children:e(D,{variant:"contained",color:"primary",onClick:h,startIcon:e(Gn,{}),ariaLabel:"refresh dashboard"})}),t?e("div",{className:"vm-mobile-option",onClick:c,children:[e("span",{className:"vm-mobile-option__icon",children:e(ct,{})}),e("div",{className:"vm-mobile-option-text",children:[e("span",{className:"vm-mobile-option-text__label",children:"Auto-refresh"}),e("span",{className:"vm-mobile-option-text__value",children:s.title})]}),e("span",{className:"vm-mobile-option__arrow",children:e(be,{})})]}):e(j,{title:"Auto-refresh control",children:e("div",{ref:m,children:e(D,{variant:"contained",color:"primary",fullWidth:!0,endIcon:e("div",{className:I({"vm-execution-controls-buttons__arrow":!0,"vm-execution-controls-buttons__arrow_open":l}),children:e(be,{})}),onClick:c,children:s.title})})})]})}),e(Ie,{open:l,placement:"bottom-right",onClose:d,buttonRef:m,title:t?"Auto-refresh duration":void 0,children:e("div",{className:I({"vm-execution-controls-list":!0,"vm-execution-controls-list_mobile":t}),children:gr.map(v=>e("div",{className:I({"vm-list-item":!0,"vm-list-item_mobile":t,"vm-list-item_active":v.seconds===s.seconds}),onClick:p(v),children:v.title},v.seconds))})})]})},uo={enable:"Enable to save the modified server URL to local storage, preventing reset upon page refresh.",disable:"Disable to stop saving the server URL to local storage, reverting to the default URL on page refresh."},Mc=Un(({onClose:t},n)=>{const{serverUrl:r}=se(),a=xt(),{value:o,toggle:s}=ae(!!Ae("SERVER_URL")),[i,l]=N(r),[c,d]=N(""),m=h=>{l(h||""),d("")},u=W(()=>{const h=dn(i);h!==""&&a({type:"SET_TENANT_ID",payload:h}),a({type:"SET_SERVER",payload:i}),t()},[i]);return A(()=>{r||d(Ce.emptyServer),Qr(r)||d(Ce.validServer)},[r]),A(()=>{o?Le("SERVER_URL",i):Br(["SERVER_URL"])},[o]),A(()=>{o&&Le("SERVER_URL",i)},[i]),A(()=>{r!==i&&l(r)},[r]),Hr(n,()=>({handleApply:u}),[u]),e("div",{children:[e("div",{className:"vm-server-configurator__title",children:"Server URL"}),e("div",{className:"vm-server-configurator-url",children:[e(ce,{autofocus:!0,value:i,error:c,onChange:m,onEnter:u,inputmode:"url"}),e(j,{title:o?uo.disable:uo.enable,children:e(D,{className:"vm-server-configurator-url__button",variant:"text",color:o?"primary":"gray",onClick:s,startIcon:e(Lt,{})})})]})]})}),Ic=[{label:"Graph",type:Ne.chart},{label:"JSON",type:Ne.code},{label:"Table",type:Ne.table}],Pc=Un(({onClose:t},n)=>{const{isMobile:r}=J(),{seriesLimits:a}=je(),o=Gt(),[s,i]=N(a),[l,c]=N({table:"",chart:"",code:""}),d=()=>{i(Ko)},m=h=>p=>{const v=p||"";c(b=>({...b,[h]:+v<0?Ce.positiveNumber:""})),i({...s,[h]:v||1/0})},u=W(()=>{o({type:"SET_SERIES_LIMITS",payload:s}),t()},[s]);return Hr(n,()=>({handleApply:u}),[u]),e("div",{className:"vm-limits-configurator",children:[e("div",{className:"vm-server-configurator__title",children:["Series limits by tabs",e(j,{title:"Set to 0 to disable the limit",children:e(D,{variant:"text",color:"primary",size:"small",startIcon:e(mt,{})})}),e("div",{className:"vm-limits-configurator-title__reset",children:e(D,{variant:"text",color:"primary",size:"small",startIcon:e(ct,{}),onClick:d,children:"Reset limits"})})]}),e("div",{className:I({"vm-limits-configurator__inputs":!0,"vm-limits-configurator__inputs_mobile":r}),children:Ic.map(h=>e("div",{children:e(ce,{label:h.label,value:s[h.type],error:l[h.type],onChange:m(h.type),onEnter:u,type:"number"})},h.type))})]})}),Kn=({defaultExpanded:t=!1,onChange:n,title:r,children:a})=>{const[o,s]=N(t),i=()=>{const l=window.getSelection();l&&l.toString()||s(c=>{const d=!c;return n&&n(d),d})};return A(()=>{s(t)},[t]),e(V,{children:[e("header",{className:`vm-accordion-header ${o&&"vm-accordion-header_open"}`,onClick:i,children:[r,e("div",{className:`vm-accordion-header__arrow ${o&&"vm-accordion-header__arrow_open"}`,children:e(be,{})})]}),o&&e("section",{className:"vm-accordion-section",children:a},"content")]})},Dc="Browser timezone is not recognized, supported, or could not be determined.",Oc=()=>e(j,{title:Dc,children:e(na,{})}),Cn=rs(),Rc=Un((t,n)=>{const{isMobile:r}=J(),a=ao(),{timezone:o,defaultTimezone:s}=ge(),i=Be(),[l,c]=N(o),[d,m]=N(""),u=q(null),{value:h,toggle:p,setFalse:v}=ae(!1),b=M(()=>[{title:`Default time (${s})`,region:s,utc:s?en(s):"UTC"},{title:Cn.title,region:Cn.region,utc:en(Cn.region),isInvalid:!Cn.isValid},{title:"UTC (Coordinated Universal Time)",region:"UTC",utc:"UTC"}].filter(w=>w.region),[s]),f=M(()=>{if(!d)return a;try{return ao(d)}catch{return{}}},[d,a]),g=M(()=>Object.keys(f),[f]),_=M(()=>({region:l,utc:en(l)}),[l]),y=w=>{m(w)},S=w=>{c(w.region),m(""),v()},T=w=>()=>{S(w)};return A(()=>{c(o)},[o]),Hr(n,()=>({handleApply:()=>{i({type:"SET_TIMEZONE",payload:l})}}),[l]),e("div",{className:"vm-timezones",children:[e("div",{className:"vm-server-configurator__title",children:"Time zone"}),e("div",{className:"vm-timezones-item vm-timezones-item_selected",onClick:p,ref:u,children:[e("div",{className:"vm-timezones-item__title",children:_.region}),e("div",{className:"vm-timezones-item__utc",children:_.utc}),e("div",{className:I({"vm-timezones-item__icon":!0,"vm-timezones-item__icon_open":h}),children:e(Je,{})})]}),e(Ie,{open:h,buttonRef:u,placement:"bottom-left",onClose:v,fullWidth:!0,title:r?"Time zone":void 0,children:e("div",{className:I({"vm-timezones-list":!0,"vm-timezones-list_mobile":r}),children:[e("div",{className:"vm-timezones-list-header",children:[e("div",{className:"vm-timezones-list-header__search",children:e(ce,{autofocus:!0,label:"Search",value:d,onChange:y})}),b.map((w,C)=>w&&e("div",{className:"vm-timezones-item vm-timezones-list-group-options__item",onClick:T(w),children:[e("div",{className:"vm-timezones-item__title",children:[w.title,w.isInvalid&&e(Oc,{})]}),e("div",{className:"vm-timezones-item__utc",children:w.utc})]},`${C}_${w.region}`))]}),g.map(w=>e("div",{className:"vm-timezones-list-group",children:e(Kn,{defaultExpanded:!0,title:e("div",{className:"vm-timezones-list-group__title",children:w}),children:e("div",{className:"vm-timezones-list-group-options",children:f[w]&&f[w].map(C=>e("div",{className:"vm-timezones-item vm-timezones-list-group-options__item",onClick:T(C),children:[e("div",{className:"vm-timezones-item__title",children:C.region}),e("div",{className:"vm-timezones-item__utc",children:C.utc})]},C.search))})})},w))]})})]})}),$c=({options:t,value:n,label:r,onChange:a})=>{const o=q(null),[s,i]=N({width:"0px",left:"0px",borderRadius:"0px"}),l=c=>()=>{a(c)};return A(()=>{if(!o.current){i({width:"0px",left:"0px",borderRadius:"0px"});return}const c=t.findIndex(p=>p.value===n),{width:d}=o.current.getBoundingClientRect();let m=d,u=c*m,h="0";c===0&&(h="16px 0 0 16px"),c===t.length-1&&(h="10px",u-=1,h="0 16px 16px 0"),c!==0&&c!==t.length-1&&(m+=1,u-=1),i({width:`${m}px`,left:`${u}px`,borderRadius:h})},[o,n,t]),e("div",{className:"vm-toggles",children:[r&&e("label",{className:"vm-toggles__label",children:r}),e("div",{className:"vm-toggles-group",style:{gridTemplateColumns:`repeat(${t.length}, 1fr)`},children:[s.borderRadius&&e("div",{className:"vm-toggles-group__highlight",style:s}),t.map((c,d)=>e("div",{className:I({"vm-toggles-group-item":!0,"vm-toggles-group-item_first":d===0,"vm-toggles-group-item_active":c.value===n,"vm-toggles-group-item_icon":c.icon&&c.title}),onClick:l(c.value),ref:c.value===n?o:null,children:[c.icon,c.title]},c.value))]})]})},Fc=Object.values(Ge).map(t=>({title:t,value:t})),zc=()=>{const{isMobile:t}=J(),n=xt(),{theme:r}=se(),a=o=>{n({type:"SET_THEME",payload:o})};return e("div",{className:I({"vm-theme-control":!0,"vm-theme-control_mobile":t}),children:[e("div",{className:"vm-server-configurator__title",children:"Theme preferences"}),e("div",{className:"vm-theme-control__toggle",children:e($c,{options:Fc,value:r,onChange:a})},`${t}`)]})},vr="Settings",La=()=>{const{isMobile:t}=J(),n=Ee(),r=q(null),a=q(null),o=q(null),{value:s,setTrue:i,setFalse:l}=ae(!1),c=()=>{r.current&&r.current.handleApply(),a.current&&a.current.handleApply(),o.current&&o.current.handleApply(),l()},d=[{show:!n&&!1,component:e(Mc,{ref:r,onClose:l})},{show:!1,component:e(Pc,{ref:a,onClose:l})},{show:!0,component:e(Rc,{ref:o})},{show:!n,component:e(zc,{})}].filter(m=>m.show);return e(V,{children:[t?e("div",{className:"vm-mobile-option",onClick:i,children:[e("span",{className:"vm-mobile-option__icon",children:e(Ze,{})}),e("div",{className:"vm-mobile-option-text",children:e("span",{className:"vm-mobile-option-text__label",children:vr})}),e("span",{className:"vm-mobile-option__arrow",children:e(be,{})})]}):e(j,{title:vr,children:e(D,{className:I({"vm-header-button":!n}),variant:"contained",color:"primary",startIcon:e(Ze,{}),onClick:i,ariaLabel:"settings"})}),s&&e(Me,{title:vr,onClose:l,children:e("div",{className:I({"vm-server-configurator":!0,"vm-server-configurator_mobile":t}),children:[d.map((m,u)=>e("div",{className:"vm-server-configurator__input",children:m.component},u)),e("div",{className:"vm-server-configurator-footer",children:[e(D,{color:"error",variant:"outlined",onClick:l,children:"Cancel"}),e(D,{color:"primary",variant:"contained",onClick:c,children:"Apply"})]})]})})]})},Hc=({displaySidebar:t,isMobile:n,headerSetup:r,accountIds:a})=>e("div",{className:I({"vm-header-controls":!0,"vm-header-controls_mobile":n}),children:[(r==null?void 0:r.tenant)&&e(Hs,{accountIds:a||[]}),(r==null?void 0:r.stepControl)&&e(Vs,{}),(r==null?void 0:r.timeSelector)&&e(ka,{}),(r==null?void 0:r.cardinalityDatePicker)&&e(Us,{}),(r==null?void 0:r.executionControls)&&e(Ta,{}),e(La,{}),!t&&e(Fs,{})]});Ae("DISABLED_DEFAULT_TIMEZONE");const Aa=()=>{const{serverUrl:t}=se();Be();const[n,r]=N(!1),[a,o]=N(""),s=async()=>{};return A(()=>{s()},[t]),{isLoading:n,error:a}},Vc=()=>{const{serverUrl:t}=se();xt();const[n,r]=N(!1),[a,o]=N("");return A(()=>{(async()=>{})()},[t]),{isLoading:n,error:a}},qc=()=>{xt();const[t,n]=N(!1),[r,a]=N("");return A(()=>{(async()=>{})()},[]),{isLoading:t,error:r}},Uc=()=>{const t=Ee(),{isMobile:n}=J(),{pathname:r}=ht(),[a,o]=oe();Cc(),Aa(),qc(),Vc();const s=()=>{var d;const l="vmui",c=(d=gt[r])==null?void 0:d.title;document.title=c?`${c} - ${l}`:l},i=()=>{const{search:l,href:c}=window.location;if(l){const m=Fr.parse(l,{ignoreQueryPrefix:!0});Object.entries(m).forEach(([u,h])=>a.set(u,h)),o(a),window.location.search=""}const d=c.replace(/\/\?#\//,"/#/");d!==c&&window.location.replace(d)};return A(s,[r]),A(i,[]),e("section",{className:"vm-container",children:[e(Na,{controlsComponent:Hc}),e("div",{className:I({"vm-container-body":!0,"vm-container-body_mobile":n,"vm-container-body_app":t}),children:e(Vr,{})}),!t&&e(Sa,{})]})},Bc=`No match! -This query hasn't selected any time series from database. -Either the requested metrics are missing in the database, -or there is a typo in series selector.`,jc=`The shown results are marked as PARTIAL. -The result is marked as partial if one or more vmstorage nodes failed to respond to the query.`,Bs=({value:t,onChange:n,onEnter:r,onArrowUp:a,onArrowDown:o,autocomplete:s,autocompleteEl:i,error:l,stats:c,label:d,disabled:m=!1,includeFunctions:u=!0})=>{const{autocompleteQuick:h}=xe(),{isMobile:p}=J(),[v,b]=N(!1),[f,g]=N([0,0]),[_,y]=N([0,0]),S=q(null),[T,w]=N(!!i),C=q(ln(w,500)).current,k=[{show:(c==null?void 0:c.seriesFetched)==="0"&&!c.resultLength,text:Bc},{show:c==null?void 0:c.isPartial,text:jc}].filter(F=>F.show).map(F=>F.text).join("");c&&(d=`${d} (${c.executionTimeMsec||0}ms)`);const L=(F,O)=>{n(F),y([O,O])},x=F=>{const{key:O,ctrlKey:H,metaKey:z,shiftKey:Y}=F,K=(F.target.value||"").split(` -`).length>1,re=H||z,Q=O==="ArrowUp",ie=O==="ArrowDown",X=O==="Enter";Q&&re&&(F.preventDefault(),a()),ie&&re&&(F.preventDefault(),o()),X&&v&&F.preventDefault(),X&&!Y&&(!K||re)&&!v&&(F.preventDefault(),r())},E=F=>{b(!!F.length)},P=F=>{g(O=>O[0]===F[0]&&O[1]===F[1]?O:F)};return A(()=>{b(!!i&&h)},[h]),A(()=>{w(!1),C(!0)},[f]),e("div",{className:"vm-query-editor",ref:S,children:[e(ce,{value:t,label:d,type:"textarea",autofocus:!p,error:l,warning:k,onKeyDown:x,onChange:n,onChangeCaret:P,disabled:m,inputmode:"search",caretPosition:_}),T&&s&&i&&e(i,{value:t,anchorEl:S,caretPosition:f,hasHelperText:!!(k||l),includeFunctions:u,onSelect:L,onFoundOptions:E})]})},_e=({value:t=!1,disabled:n=!1,label:r,color:a="secondary",fullWidth:o,onChange:s})=>{const i=()=>{n||s(!t)},l=I({"vm-switch":!0,"vm-switch_full-width":o,"vm-switch_disabled":n,"vm-switch_active":t,[`vm-switch_${a}_active`]:t,[`vm-switch_${a}`]:a});return e("div",{className:l,onClick:i,children:[e("div",{className:"vm-switch-track",children:e("div",{className:"vm-switch-track__thumb"})}),r&&e("span",{className:"vm-switch__label",children:r})]})},ho=({isMobile:t,hideButtons:n})=>{const{autocomplete:r}=xe(),a=Mt(),{nocache:o,isTracingEnabled:s,reduceMemUsage:i}=je(),l=Gt(),c=()=>{l({type:"TOGGLE_NO_CACHE"})},d=()=>{l({type:"TOGGLE_REDUCE_MEM_USAGE"})},m=()=>{l({type:"TOGGLE_QUERY_TRACING"})},u=()=>{a({type:"TOGGLE_AUTOCOMPLETE"})},h=()=>{a({type:"SET_AUTOCOMPLETE_QUICK",payload:!0})};return me("keydown",v=>{const{code:b,ctrlKey:f,altKey:g}=v;b==="Space"&&(f||g)&&(v.preventDefault(),h())}),e("div",{className:I({"vm-additional-settings":!0,"vm-additional-settings_mobile":t}),children:[!(n!=null&&n.autocomplete)&&e(j,{title:e(V,{children:["Quick tip: ",$s]}),children:e(_e,{label:"Autocomplete",value:r,onChange:u,fullWidth:t})}),!(n!=null&&n.disableCache)&&e(_e,{label:"Disable cache",value:o,onChange:c,fullWidth:t}),!(n!=null&&n.reduceMemUsage)&&e(_e,{label:"Disable deduplication",value:i,onChange:d,fullWidth:t}),!(n!=null&&n.traceQuery)&&e(_e,{label:"Trace query",value:s,onChange:m,fullWidth:t})]})},Qc=t=>{const{isMobile:n}=J(),r=q(null),{value:a,toggle:o,setFalse:s}=ae(!1);return n?e(V,{children:[e("div",{ref:r,children:e(D,{variant:"outlined",startIcon:e(_s,{}),onClick:o,ariaLabel:"additional the query settings"})}),e(Ie,{open:a,buttonRef:r,placement:"bottom-left",onClose:s,title:"Query settings",children:e(ho,{isMobile:n,...t})})]}):e(ho,{...t})},Zn=(t,n)=>t.length===n.length&&t.every((r,a)=>r===n[a]);function js(t,n){const r=t.reduce((a,o)=>{const s=n.map(i=>`${String(i)}: ${o[i]||"-"}`).join("|");return(a[s]=a[s]||[]).push(o),a},{});return Object.entries(r).map(([a,o])=>({keys:a.split("|"),values:o}))}const Yc=t=>t.length<2?!1:t.every((n,r)=>r===0||n{const{serverUrl:t}=se();return async r=>{try{const a=encodeURIComponent(r),o=`${t}/prettify-query?query=${a}`,s=await fetch(o);if(s.status!=200)return{query:r,error:"Error requesting /prettify-query, status: "+s.status};const i=await s.json();return i.status!="success"?{query:r,error:String(i.msg)}:{query:String(i.query),error:""}}catch(a){return console.error(a),a instanceof Error&&a.name!=="AbortError"?{query:r,error:`${a.name}: ${a.message}`}:{query:r,error:String(a)}}}},Fe=()=>{const{showInfoMessage:t}=Kl();return async(n,r)=>{if(!(navigator!=null&&navigator.clipboard))return t({text:e(Wc,{}),type:"error",timeout:2e4}),!1;try{return await navigator.clipboard.writeText(n),r&&t({text:r,type:"success"}),!0}catch(a){return a instanceof Error&&t({text:`${a.name}: ${a.message}`,type:"error"}),console.warn("Copy failed",a),!1}}},Wc=()=>e("div",{className:"vm-snackbar-details",children:[e("p",{className:"vm-snackbar-details__title",children:"Clipboard not supported"}),window.isSecureContext?e("p",{className:"vm-snackbar-details__msg",children:[e("p",{children:"Common reasons:"}),e("ul",{children:[e("li",{children:"Browser restrictions"}),e("li",{children:"Insecure connection (HTTP)"}),e("li",{children:"Permissions not granted"})]}),e("p",{children:["For detailed information, visit the ",e("a",{className:"vm-link vm-link_underlined vm-link_colored",href:"https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API#security_considerations",target:"_blank",rel:"noopener noreferrer",children:"Clipboard API documentation"})]})]}):e("p",{className:"vm-snackbar-details__msg",children:[e("p",{children:"This page is not running in a secure context (HTTPS)."}),e("p",{children:"Clipboard operations require a secure context."}),e("a",{className:"vm-link vm-link_underlined vm-link_colored",href:"https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts",target:"_blank",rel:"noopener noreferrer",children:"Learn more about secure contexts"})]})]}),Jc=({query:t,favorites:n,onRun:r,onToggleFavorite:a})=>{const o=Fe(),s=M(()=>n.includes(t),[t,n]);return e("div",{className:"vm-query-history-item",children:[e("span",{className:"vm-query-history-item__value",children:t}),e("div",{className:"vm-query-history-item__buttons",children:[e(j,{title:"Execute query",children:e(D,{size:"small",variant:"text",onClick:()=>{r(t)},startIcon:e(hn,{})})}),e(j,{title:"Copy query",children:e(D,{size:"small",variant:"text",onClick:async()=>{await o(t,"Query has been copied")},startIcon:e(Xe,{})})}),e(j,{title:s?"Remove Favorite":"Add to Favorites",children:e(D,{size:"small",variant:"text",color:s?"warning":"primary",onClick:()=>{a(t,s)},startIcon:s?e(ws,{}):e(ys,{})})})]})]})},St={session:"session",storage:"saved",favorite:"favorite"},po=[{label:"Session history",value:St.session},{label:"Saved history",value:St.storage},{label:"Favorite queries",value:St.favorite}],Qs=({handleSelectQuery:t,historyKey:n})=>{const{queryHistory:r}=xe(),{isMobile:a}=J(),{value:o,setTrue:s,setFalse:i}=ae(!1),[l,c]=N(po[0].value),[d,m]=N(Zt(n,"QUERY_HISTORY")),[u,h]=N(Zt(n,"QUERY_FAVORITES")),p=M(()=>r.map(T=>T.values.filter(w=>w).reverse()),[r]),v=M(()=>{switch(l){case St.favorite:return u;case St.storage:return d;default:return p}},[l,u,d,p]),b=v==null?void 0:v.every(T=>!T.length),f=M(()=>{switch(l){case St.favorite:return`Favorites queries are empty. -To see your favorites, mark a query as a favorite.`;default:return`Query history is empty. -To see the history, please make a query.`}},[l]),g=T=>w=>{t(w,T),i()},_=(T,w)=>{h(C=>{const k=C[0]||[];return w?[k.filter(L=>L!==T)]:!w&&!k.includes(T)?[[...k,T]]:C})},y=()=>{m(Zt(n,"QUERY_HISTORY")),h(Zt(n,"QUERY_FAVORITES"))},S=()=>{Sl(n,"QUERY_HISTORY")};return A(()=>{const T=u[0]||[],w=Zt(n,"QUERY_FAVORITES")[0]||[];Zn(T,w)||Nl(n,u)},[u]),me("storage",y),e(V,{children:[e(j,{title:"Show history",children:e(D,{color:"primary",variant:"text",onClick:s,startIcon:e(rn,{}),ariaLabel:"Show history"})}),o&&e(Me,{title:"Query history",onClose:i,children:e("div",{className:I({"vm-query-history":!0,"vm-query-history_mobile":a}),children:[e("div",{className:I({"vm-query-history__tabs":!0,"vm-section-header__tabs":!0,"vm-query-history__tabs_mobile":a}),children:e(Yt,{activeItem:l,items:po,onChange:c})}),e("div",{className:"vm-query-history-list",children:[b&&e("div",{className:"vm-query-history-list__no-data",children:f}),v.map((T,w)=>e("div",{children:[v.length>1&&e("div",{className:I({"vm-query-history-list__group-title":!0,"vm-query-history-list__group-title_first":w===0}),children:["Query ",w+1]}),T.map((C,k)=>e(Jc,{query:C,favorites:u.flat(),onRun:g(w),onToggleFavorite:_},k))]},w)),l===St.storage&&!b&&e("div",{className:"vm-query-history-footer",children:e(D,{color:"error",variant:"outlined",size:"small",startIcon:e(gn,{}),onClick:S,children:"clear history"})})]})]})})]})},Qe=({containerStyles:t,message:n})=>{const{isDarkTheme:r}=se();return e("div",{className:I({"vm-spinner":!0,"vm-spinner_dark":r}),style:t,children:[e("div",{className:"half-circle-spinner",children:[e("div",{className:"circle circle-1"}),e("div",{className:"circle circle-2"})]}),n&&e("div",{className:"vm-spinner__message",children:n})]})},Kc=()=>{const{serverUrl:t}=se(),{isMobile:n}=J(),{value:r,setTrue:a,setFalse:o}=ae(!1),{query:s}=xe(),{period:i}=ge(),[l,c]=N(!1),[d,m]=N(""),[u,h]=N(""),[p,v]=N(""),b=async()=>{c(!0);try{const g=encodeURIComponent(s[0]||""),_=encodeURIComponent(i.step||mn(i.end-i.start,!1)),y=`${t}/api/vmanomaly/config.yaml?query=${g}&step=${_}`,S=await fetch(y),T=S.headers.get("Content-Type");if(S.ok)if(T=="application/yaml"){const w=await S.blob(),C=await w.text();m(C),h(URL.createObjectURL(w))}else v("Response Content-Type is not YAML, does `Server URL` point to VMAnomaly server?");else{const w=await S.text();v(` ${S.status} ${S.statusText}: ${w}`)}}catch(g){console.error(g),v(String(g))}c(!1)};return e(V,{children:[e(D,{color:"secondary",variant:"outlined",onClick:()=>(a(),v(""),URL.revokeObjectURL(u),m(""),h(""),b()),children:"Open Config"}),r&&e(Me,{title:"Download config",onClose:o,children:e("div",{className:I({"vm-anomaly-config":!0,"vm-anomaly-config_mobile":n}),children:[l&&e(Qe,{containerStyles:{position:"relative"},message:"Loading config..."}),!l&&p&&e("div",{className:"vm-anomaly-config-error",children:[e("div",{className:"vm-anomaly-config-error__icon",children:e(ra,{})}),e("h3",{className:"vm-anomaly-config-error__title",children:"Cannot download config"}),e("p",{className:"vm-anomaly-config-error__text",children:p})]}),!l&&d&&e(ce,{value:d,label:"config.yaml",type:"textarea",disabled:!0}),e("div",{className:"vm-anomaly-config-footer",children:u&&e("a",{href:u,download:"config.yaml",children:e(D,{variant:"contained",startIcon:e(fn,{}),children:"download"})})})]})})]})},Ea=({value:t,options:n,anchor:r,disabled:a,minLength:o=2,fullWidth:s,selected:i,noOptionsText:l,label:c,disabledFullScreen:d,offset:m,maxDisplayResults:u,loading:h,onSelect:p,onOpenAutocomplete:v,onFoundOptions:b,onChangeWrapperRef:f})=>{var re;const{isMobile:g}=J(),_=q(null),[y,S]=N({index:-1}),[T,w]=N(""),[C,k]=N(0),{value:L,setValue:x,setFalse:E}=ae(!1),P=M(()=>{if(!L)return[];try{const Q=new RegExp(String(t.trim()),"i"),X=n.filter(R=>Q.test(R.value)).sort((R,$)=>{var B,ee;return R.value.toLowerCase()===t.trim().toLowerCase()?-1:$.value.toLowerCase()===t.trim().toLowerCase()?1:(((B=R.value.match(Q))==null?void 0:B.index)||0)-(((ee=$.value.match(Q))==null?void 0:ee.index)||0)});return k(X.length),w(X.length>Number(u==null?void 0:u.limit)&&(u==null?void 0:u.message)||""),u!=null&&u.limit?X.slice(0,u.limit):X}catch{return[]}},[L,n,t]),F=M(()=>{var Q;return P.length===1&&((Q=P[0])==null?void 0:Q.value)===t},[P]),O=M(()=>l&&!P.length,[l,P]),H=Q=>()=>{a||(p(Q.value,Q),i||E())},z=Q=>()=>{S({index:Q,type:0})},Y=()=>{S({index:-1})},G=()=>{if(!_.current||y.type===0)return;const Q=_.current.childNodes[y.index];Q!=null&&Q.scrollIntoView&&Q.scrollIntoView({block:"center"})},K=W(Q=>{const{key:ie,ctrlKey:X,metaKey:R,shiftKey:$}=Q,B=X||R||$,ee=P.length&&!F;if(ie==="ArrowUp"&&!B&&ee&&(Q.preventDefault(),S(({index:te})=>({index:te<=0?0:te-1,type:1}))),ie==="ArrowDown"&&!B&&ee){Q.preventDefault();const te=P.length-1;S(({index:ue})=>({index:ue>=te?te:ue+1,type:1}))}if(ie==="Enter"){const te=P[y.index];te&&p(te.value,te),i||E()}ie==="Escape"&&E()},[y,P,F,E,p,i]);return A(()=>{x(t.length>=o)},[t,n]),me("keydown",K),A(G,[y,P]),A(()=>{S({index:-1})},[P]),A(()=>{v&&v(L)},[L]),A(()=>{b&&b(F?[]:P)},[P,F]),A(()=>{f&&f(_)},[_]),e(Ie,{open:L,buttonRef:r,placement:"bottom-left",onClose:E,fullWidth:s,title:g?c:void 0,disabledFullScreen:d,offset:m,children:[e("div",{className:I({"vm-autocomplete":!0,"vm-autocomplete_mobile":g&&!d}),ref:_,children:[h&&e("div",{className:"vm-autocomplete__loader",children:[e(Gn,{}),e("span",{children:"Loading..."})]}),O&&e("div",{className:"vm-autocomplete__no-options",children:l}),!F&&P.map((Q,ie)=>e("div",{className:I({"vm-list-item":!0,"vm-list-item_mobile":g,"vm-list-item_active":ie===y.index,"vm-list-item_multiselect":i,"vm-list-item_multiselect_selected":i==null?void 0:i.includes(Q.value),"vm-list-item_with-icon":Q.icon}),id:`$autocomplete$${Q.value}`,onClick:H(Q),onMouseEnter:z(ie),onMouseLeave:Y,children:[(i==null?void 0:i.includes(Q.value))&&e(Wn,{}),e(V,{children:Q.icon}),e("span",{children:Q.value})]},`${ie}${Q.value}`))]}),T&&e("div",{className:"vm-autocomplete-message",children:["Shown ",u==null?void 0:u.limit," results out of ",C,". ",T]}),((re=P[y.index])==null?void 0:re.description)&&e("div",{className:"vm-autocomplete-info",children:[e("div",{className:"vm-autocomplete-info__type",children:P[y.index].type}),e("div",{className:"vm-autocomplete-info__description",dangerouslySetInnerHTML:{__html:P[y.index].description||""}})]})]})},Hn=t=>t.replace(/[/\-\\^$*+?.()|[\]{}]/g,"\\$&"),Nn=t=>JSON.stringify(t).slice(1,-1),Ys=t=>{const n=t.match(/["`']/g);return n?n.length%2!==0:!1},Zc={metric:e(Fn,{}),label:e(da,{}),labelValue:e(zn,{})},Xc=({valueByContext:t,metric:n,label:r,context:a})=>{const{serverUrl:o}=se(),{period:{start:s,end:i}}=ge(),{autocompleteCache:l}=xe(),c=Mt(),[d,m]=N(!1),[u,h]=N(t),p=ln(h,500);A(()=>(p(t),p.cancel),[t,p]);const[v,b]=N([]),[f,g]=N([]),[_,y]=N([]),S=q(new AbortController),T=W(k=>{const L=U(s*1e3).startOf("day").valueOf()/1e3,x=U(i*1e3).endOf("day").valueOf()/1e3;return new URLSearchParams({...k||{},limit:`${Tt.queryLimit}`,start:`${L}`,end:`${x}`})},[s,i]),w=(k,L)=>k.map(x=>({value:x,type:`${L}`,icon:Zc[L]})),C=async({value:k,urlSuffix:L,setter:x,type:E,params:P})=>{if(!k&&E==="metric")return;S.current.abort(),S.current=new AbortController;const{signal:F}=S.current,O={type:E,value:k,start:(P==null?void 0:P.get("start"))||"",end:(P==null?void 0:P.get("end"))||"",match:(P==null?void 0:P.get("match[]"))||""};m(!0);try{const H=l.get(O);if(H){x(w(H,E)),m(!1);return}const z=await fetch(`${o}/api/v1/${L}?${P}`,{signal:F});if(z.ok){const{data:Y}=await z.json();x(w(Y,E)),c({type:"SET_AUTOCOMPLETE_CACHE",payload:{key:O,value:Y}})}m(!1)}catch(H){H instanceof Error&&H.name!=="AbortError"&&(c({type:"SET_AUTOCOMPLETE_CACHE",payload:{key:O,value:[]}}),m(!1),console.error(H))}};return A(()=>{const k=a!==Oe.metricsql&&a!==Oe.empty;if(!o||!n||k)return;b([]);const L=Nn(Hn(n));return C({value:u,urlSuffix:"label/__name__/values",setter:b,type:"metric",params:T({"match[]":`{__name__=~".*${L}.*"}`})}),()=>{var x;return(x=S.current)==null?void 0:x.abort()}},[o,u,a,n]),A(()=>{if(!o||a!==Oe.label)return;g([]);const k=Nn(n);return C({value:u,urlSuffix:"labels",setter:g,type:"label",params:T(n?{"match[]":`{__name__="${k}"}`}:void 0)}),()=>{var L;return(L=S.current)==null?void 0:L.abort()}},[o,u,a,n]),A(()=>{if(!o||!r||a!==Oe.labelValue)return;y([]);const k=Nn(n),L=Nn(Hn(u)),x=n?`__name__="${k}"`:"",E=`${r}=~".*${L}.*"`,P=[x,E].filter(Boolean).join(",");return C({value:u,urlSuffix:`label/${r}/values`,setter:y,type:"labelValue",params:T({"match[]":`{${P}}`})}),()=>{var F;return(F=S.current)==null?void 0:F.abort()}},[o,u,a,n,r]),{metrics:v,labels:f,labelValues:_,loading:d}},ed=""+new URL("MetricsQL-Ckl-MH95.md",import.meta.url).href,Gs="h3",td="h4",nd="p",rd="https://docs.victoriametrics.com/victoriametrics/metricsql/",ad="vm-link vm-link_colored",od=t=>{const n=`$1 target="_blank" class="${ad}" $2${rd}#`;return t.replace(/(s.outerHTML??"").join(` -`);return{type:t,value:r,description:od(o),icon:e(an,{})}},ld=t=>{let n="";return Array.from(t).map(r=>{const a=r.tagName.toLowerCase()===Gs;return n=a?r.textContent??"":n,a?null:id(n,r)}).filter(Boolean)},cd=t=>{const{metricsQLFunctions:n}=xe(),r=Mt(),a=o=>{const s=document.createElement("div");s.innerHTML=Bt(o);const i=s.querySelectorAll(`${Gs}, ${td}`);return ld(i)};return A(()=>{if(!t||n.length)return;(async()=>{try{const i=await(await fetch(ed)).text(),l=a(i);r({type:"SET_METRICSQL_FUNCTIONS",payload:l})}catch(s){console.error("Error fetching or processing the MetricsQL.md file:",s)}})()},[]),t?n:[]};function dd(t){const n=/\s(or|and|unless|default|ifnot|if|group_left|group_right)\s|}|\+|\|-|\*|\/|\^/i,r=t.split(n),a=r[r.length-1].trim(),o=/.*\(([^)]*)$/,s=a.match(o);if(s&&s[1]){const i=s[1];if(i.lastIndexOf("{")>i.lastIndexOf("}")){const c=i.match(/([\w_.:]+)\{[^}]*$/);return c?c[0]:a}const l=i.lastIndexOf(",");return l!==-1?i.substring(l+1).trim():i}return a}function md(t){const n=t.match(/([\w_.:]+(?![},]))$/);return n?n[0]:""}function ud(t){const n=/([{(),+\-*/^]|\b(?:or|and|unless|default|ifnot|if|group_left|group_right|by|without|on|ignoring)\b)/i,r=t.split(/\s+/),a=r.length,o=r[a-1],s=r[a-2],i=!o&&Ys(t),l=(!o||r.length>1)&&!n.test(s);return i||l}function hd(t,n="",r=""){const a=t.trim(),o=["}",")"].some(d=>a.endsWith(d)),s=!Ys(a)&&["`","'",'"'].some(d=>a.endsWith(d));if(!a||o||s||ud(a))return Oe.empty;const i=/(?:by|without|on|ignoring)\s*\(\s*[^)]*$|\{[^}]*$/i,l=`(${Hn(n)})?{?.+${Hn(r)}(=|!=|=~|!~)"?([^"]*)$`,c=new RegExp(l,"g");switch(!0){case c.test(a):return Oe.labelValue;case i.test(a):return Oe.label;default:return Oe.metricsql}}const pd=({value:t,anchorEl:n,caretPosition:r,hasHelperText:a,includeFunctions:o,onSelect:s,onFoundOptions:i})=>{const[l,c]=N({top:0,left:0}),d=cd(o),m=M(()=>{if(r[0]!==r[1])return{beforeCursor:t,afterCursor:""};const w=t.substring(0,r[0]),C=t.substring(r[1]);return{beforeCursor:w,afterCursor:C}},[t,r]),u=M(()=>dd(m.beforeCursor),[m]),h=M(()=>{const w=/\w+\((?[^)]+)\)\s+(by|without|on|ignoring)\s*\(\w*/gi,C=[...u.matchAll(w)];if(C.length>0&&C[0].groups&&C[0].groups.metricName)return C[0].groups.metricName;const k=/^\s*\b(?[^{}(),\s]+)(?={|$)/g,L=[...u.matchAll(k)];return L.length>0&&L[0].groups&&L[0].groups.metricName?L[0].groups.metricName:""},[u]),p=M(()=>{const w=/[a-z_:-][\w\-.:/]*\b(?=\s*(=|!=|=~|!~))/g,C=u.match(w);return C?C[C.length-1]:""},[u]),v=M(()=>hd(m.beforeCursor,h,p),[m,h,p]),b=M(()=>md(m.beforeCursor),[m.beforeCursor]),{metrics:f,labels:g,labelValues:_,loading:y}=Xc({valueByContext:b,metric:h,label:p,context:v}),S=M(()=>{switch(v){case Oe.metricsql:return[...f,...d];case Oe.label:return g;case Oe.labelValue:return _;default:return[]}},[v,f,g,_]),T=W(w=>{const C=m.beforeCursor;let k=m.afterCursor;const L=C.lastIndexOf(b,r[0]),x=L+b.length,E=C.substring(0,L),P=C.substring(x);if(v===Oe.labelValue){const O='"';k=k.replace(/^[^\s"|},]*/,"");const H=/(?:=|!=|=~|!~)$/.test(E),z=k.trim()[0]!=='"';w=`${H?O:""}${w}${z?O:""}`}v===Oe.label&&(k=k.replace(/^[^\s=!,{}()"|+\-/*^]*/,"")),v===Oe.metricsql&&(k=k.replace(/^[^\s[\]{}()"|+\-/*^]*/,""));const F=`${E}${w}${P}${k}`;s(F,E.length+w.length)},[m]);return A(()=>{if(!n.current){c({top:0,left:0});return}const w=n.current.querySelector("textarea")||n.current,C=window.getComputedStyle(w),k=`${C.getPropertyValue("font-size")}`,L=`${C.getPropertyValue("font-family")}`,x=parseInt(`${C.getPropertyValue("line-height")}`),E=document.createElement("div");E.style.font=`${k} ${L}`,E.style.padding=C.getPropertyValue("padding"),E.style.lineHeight=`${x}px`,E.style.width=`${w.offsetWidth}px`,E.style.maxWidth=`${w.offsetWidth}px`,E.style.whiteSpace=C.getPropertyValue("white-space"),E.style.overflowWrap=C.getPropertyValue("overflow-wrap");const P=document.createElement("span");E.appendChild(document.createTextNode(m.beforeCursor)),E.appendChild(P),E.appendChild(document.createTextNode(m.afterCursor)),document.body.appendChild(E);const F=E.getBoundingClientRect(),O=P.getBoundingClientRect(),H=O.left-F.left,z=O.bottom-F.bottom-(a?x:0);c({top:z,left:H}),E.remove(),P.remove()},[n,r,a]),e(V,{children:e(Ea,{loading:y,disabledFullScreen:!0,value:b,options:S,anchor:n,minLength:0,offset:l,onSelect:T,onFoundOptions:i,maxDisplayResults:{limit:Tt.displayResults,message:"Please, specify the query more precisely."}})})},xa=({queryErrors:t,setQueryErrors:n,setHideError:r,stats:a,label:o,isLoading:s,includeFunctions:i=!0,onHideQuery:l,onRunQuery:c,abortFetch:d,hideButtons:m})=>{const{isMobile:u}=J(),{query:h,queryHistory:p,autocomplete:v,autocompleteQuick:b}=xe(),f=Mt(),g=Be(),[_,y]=N(h||[]),[S,T]=N([]),[w,C]=N(!1),k=qt(_),L=Gc(),x=()=>{f({type:"SET_QUERY_HISTORY",payload:{key:"METRICS_QUERY_HISTORY",history:_.map((X,R)=>is(X,p[R]))}})},E=()=>{if(s){d&&d();return}x(),f({type:"SET_QUERY",payload:_}),g({type:"RUN_QUERY"}),c()},P=()=>{y(X=>[...X,""])},F=X=>{y(R=>R.filter(($,B)=>B!==X))},O=(X,R)=>{const{ctrlKey:$,metaKey:B}=X;if($||B){const te=_.map((ue,he)=>he).filter(ue=>ue!==R);T(ue=>Zn(te,ue)?[]:te)}else T(te=>te.includes(R)?te.filter(ue=>ue!==R):[...te,R])},H=(X,R)=>{y($=>$.map((B,ee)=>ee===R?X:B))},z=(X,R)=>{H(X,R),C(!0)},Y=(X,R)=>{const{index:$,values:B}=p[R],ee=$+X;ee<0||ee>=B.length||(H(B[ee]||"",R),f({type:"SET_QUERY_HISTORY_BY_INDEX",payload:{value:{values:B,index:ee},queryNumber:R}}))},G=(X,R)=>()=>{Y(X,R)},K=X=>R=>{H(R,X),f({type:"SET_AUTOCOMPLETE_QUICK",payload:!1})},re=X=>()=>{F(X),T(R=>R.includes(X)?R.filter($=>$!==X):R.map($=>$>X?$-1:$))},Q=X=>R=>{O(R,X)},ie=async X=>{const R=await L(_[X]);r(!1),H(R.query,X),n($=>($[X]=R.error,[...$]))};return A(()=>{k&&_.length{l&&l(S)},[S]),A(()=>{w&&(E(),C(!1))},[_,w]),A(()=>{y(h||[])},[h]),e("div",{className:I({"vm-query-configurator":!0,"vm-block":!0,"vm-block_mobile":u}),children:[e("div",{className:"vm-query-configurator-list",children:_.map((X,R)=>e("div",{className:I({"vm-query-configurator-list-row":!0,"vm-query-configurator-list-row_disabled":S.includes(R),"vm-query-configurator-list-row_mobile":u}),children:[e(Bs,{value:_[R],autocomplete:!(m!=null&&m.autocomplete)&&(v||b),autocompleteEl:pd,error:t[R],stats:a[R],onArrowUp:G(-1,R),onArrowDown:G(1,R),onEnter:E,onChange:K(R),label:`${o||"Query"} ${_.length>1?R+1:""}`,disabled:S.includes(R),includeFunctions:i}),l&&e(j,{title:S.includes(R)?"Enable query":"Disable query",children:e("div",{className:"vm-query-configurator-list-row__button",children:e(D,{variant:"text",color:"gray",startIcon:S.includes(R)?e(sa,{}):e(Vt,{}),onClick:Q(R),ariaLabel:"visibility query"})})}),!(m!=null&&m.prettify)&&e(j,{title:"Prettify query",children:e("div",{className:"vm-query-configurator-list-row__button",children:e(D,{variant:"text",color:"gray",startIcon:e(vs,{}),onClick:async()=>await ie(R),className:"prettify",ariaLabel:"prettify the query"})})}),_.length>1&&e(j,{title:"Remove Query",children:e("div",{className:"vm-query-configurator-list-row__button",children:e(D,{variant:"text",color:"error",startIcon:e(gn,{}),onClick:re(R),ariaLabel:"remove query"})})})]},R))}),e("div",{className:"vm-query-configurator-settings",children:[e(Qc,{hideButtons:m}),e("div",{className:"vm-query-configurator-settings__buttons",children:[e(Qs,{handleSelectQuery:z,historyKey:"METRICS_QUERY_HISTORY"}),(m==null?void 0:m.anomalyConfig)&&e(Kc,{}),!(m!=null&&m.addQuery)&&_.length`${t}/api/v1/query_range?query=${encodeURIComponent(n)}&start=${r.start}&end=${r.end}&step=${r.step}${a?"&nocache=1":""}${o?"&trace=1":""}`,vd=(t,n,r,a,o)=>`${t}/api/v1/query?query=${encodeURIComponent(n)}&time=${r.end}&step=${r.step}${a?"&nocache=1":""}${o?"&trace=1":""}`,fd=(t,n,r,a)=>{const o=new URLSearchParams({"match[]":n,start:r.start.toString(),end:r.end.toString()});return a&&o.set("reduce_mem_usage","1"),`${t}/api/v1/export?${o}`};let _d=0;class At{constructor(n,r){we(this,"tracing");we(this,"query");we(this,"tracingChildren");we(this,"originalTracing");we(this,"id");this.tracing=n,this.originalTracing=JSON.parse(JSON.stringify(n)),this.query=r,this.id=_d++;const a=n.children||[];this.tracingChildren=a.map(o=>new At(o,r))}get queryValue(){return this.query}get idValue(){return this.id}get children(){return this.tracingChildren}get message(){return this.tracing.message}get duration(){return this.tracing.duration_msec}get JSON(){return JSON.stringify(this.tracing,null,2)}get originalJSON(){return JSON.stringify(this.originalTracing,null,2)}setTracing(n){this.tracing=n;const r=n.children||[];this.tracingChildren=r.map(a=>new At(a,this.query))}setQuery(n){this.query=n}resetTracing(){this.tracing=this.originalTracing}}const Ir=(t,n,r=!0)=>{const{__name__:a,...o}=t.metric,s=r?`[Query ${t.group}] `:"";if(n)return Ws(t.metric,n);const i=`${s}${a||""}`;if(Object.keys(o).length===0)return i||"value";const l=Object.entries(o).map(([c,d])=>`${c}=${JSON.stringify(d)}`).join(", ");return`${i}{${l}}`},Ws=(t,n)=>n.replace(/\{\{(\w+)}}/g,(r,a)=>t[a]||""),sn=t=>{switch(t){case"NaN":return NaN;case"Inf":case"+Inf":return 1/0;case"-Inf":return-1/0;default:return parseFloat(t)}},Ma=t=>{if(t.length<2)return!1;const n=["le","vmrange"],r=Object.keys(t[0].metric).filter(o=>!n.includes(o));return t.every(o=>{const s=Object.keys(o.metric).filter(i=>!n.includes(i));return r.length===s.length&&s.every(i=>o.metric[i]===t[0].metric[i])})&&t.every(o=>n.some(s=>s in o.metric))},Xn=({predefinedQuery:t,visible:n,display:r,customStep:a,hideQuery:o,showAllSeries:s})=>{const{query:i}=xe(),{period:l}=ge(),{displayType:c,nocache:d,isTracingEnabled:m,seriesLimits:u}=je(),{serverUrl:h}=se(),{isHistogram:p}=He(),[v,b]=N(!1),[f,g]=N(),[_,y]=N(),[S,T]=N(),[w,C]=N(),[k,L]=N([]),[x,E]=N([]),[P,F]=N(),[O,H]=N([]),[z,Y]=N(!1),G=M(()=>{const{end:$,start:B}=l;return mn($-B,p,c)},[l,p,c]),re=W(ln(async({fetchUrl:$,fetchQueue:B,displayType:ee,query:te,stateSeriesLimits:ue,showAllSeries:he,hideQuery:Ye})=>{const ye=new AbortController;H([...B,ye]);try{const Pe=ee===Ne.chart,De=he?1/0:+ue[ee]||1/0;let Ve=De;const pe=[],Dt=[];let at=1,wt=0,Jt=!1;for await(const ft of $){if(Ye==null?void 0:Ye.includes(at-1)){L(_t=>[..._t,""]),E(_t=>[..._t,{}]),at++;continue}const ur=new URL(ft),eo=await fetch(`${ur.origin}${ur.pathname}`,{signal:ye.signal,method:"POST",body:ur.searchParams}),ve=await eo.json();if(eo.ok){if(E(et=>[...et,{...ve==null?void 0:ve.stats,isPartial:ve==null?void 0:ve.isPartial,resultLength:ve.data.result.length}]),L(et=>[...et,""]),ve.trace){const et=new At(ve.trace,te[at-1]);Dt.push(et)}const _t=!!ze("display_mode",null);Jt=!Zi&&Pe&&!_t&&Ma(ve.data.result),Ve=Jt?1/0:De;const hr=Ve-pe.length;ve.data.result.slice(0,hr).forEach(et=>{et.group=at,pe.push(et)}),wt+=ve.data.result.length}else{pe.push({metric:{},values:[],group:at});const _t=ve.errorType||Ce.unknownType,hr=(ve==null?void 0:ve.error)||(ve==null?void 0:ve.message)||"see console for more details",et=[_t,hr].join(`,\r -`);L(Fi=>[...Fi,`${et}`]),console.error(`Fetch query error: ${_t}`,ve)}at++}const Ot=`Showing ${pe.length} series out of ${wt} series due to performance reasons. Please narrow down the query, so it returns less series`;F(wt>Ve?Ot:""),Pe?g(pe):y(pe),T(Dt),Y(ft=>wt?Jt:ft)}catch(Pe){const De=Pe;if(De.name==="AbortError"){b(!1);return}let pe=`Error executing query: ${De.message}. Please check your serverURL settings and confirm server availability.`;De.message==="Unexpected end of JSON input"&&(pe+=` -Additionally, this error can occur if the server response is too large to process. Apply more specific filters to reduce the data volume.`),C(pe)}b(!1)},300),[]),Q=M(()=>{C(""),L([]),E([]);const $=t??i,B=(r||c)===Ne.chart;if(l)if(!h)C(Ce.emptyServer);else if($.every(ee=>!ee.trim()))L($.map(()=>Ce.validQuery));else if(Qr(h)){const ee={...l};return ee.step=a,$.map(te=>B?gd(h,te,ee,d,m):vd(h,te,ee,d,m))}else C(Ce.validServer)},[h,l,c,a,o]),ie=W(()=>{O.map($=>$.abort()),H([]),g([]),y([])},[O]),[X,R]=N([]);return A(()=>{const $=Q===X&&!!t;if(!n||!(Q!=null&&Q.length)||$)return;b(!0),re({fetchUrl:Q,fetchQueue:O,displayType:r||c,query:t??i,stateSeriesLimits:u,showAllSeries:s,hideQuery:o}),R(Q)},[Q,n,u,s]),A(()=>{const $=O.slice(0,-1);$.length&&($.map(B=>B.abort()),H(O.filter(B=>!B.signal.aborted)))},[O]),A(()=>{G===a&&g([])},[z]),{fetchUrl:Q,isLoading:v,graphData:f,liveData:_,error:w,queryErrors:k,setQueryErrors:L,queryStats:x,warning:P,traces:S,isHistogram:z,abortFetch:ie}},er=()=>e("div",{className:"vm-line-loader",children:[e("div",{className:"vm-line-loader__background"}),e("div",{className:"vm-line-loader__line"})]}),Ia=()=>{const{tenantId:t}=se(),{displayType:n}=je(),{query:r}=xe(),{duration:a,relativeTime:o,period:{date:s,step:i}}=ge(),{customStep:l}=He(),[c,d]=oe(),m=xt(),u=Be(),h=vt(),p=Mt(),v=Gt(),[b,f]=N(!1),g=W(()=>{if(b){f(!1);return}const _=new URLSearchParams(c);r.forEach((S,T)=>{var L;const w=`g${T}`;c.get(`${w}.expr`)!==S&&S&&_.set(`${w}.expr`,S),c.get(`${w}.range_input`)!==a&&_.set(`${w}.range_input`,a),c.get(`${w}.end_input`)!==s&&_.set(`${w}.end_input`,s),c.get(`${w}.relative_time`)!==o&&_.set(`${w}.relative_time`,o||"none");const C=c.get(`${w}.step_input`)||i;C&&C!==l&&_.set(`${w}.step_input`,l);const k=`${((L=zt.find(x=>x.value===n))==null?void 0:L.prometheusCode)||0}`;c.get(`${w}.tab`)!==k&&_.set(`${w}.tab`,`${k}`),c.get(`${w}.tenantID`)!==t&&t&&_.set(`${w}.tenantID`,t)});const y=r.length-1;Array.from(_.keys()).forEach(S=>{const T=S.match(/^g(\d+)\./);T&&parseInt(T[1],10)>y&&_.delete(S)}),!(tl(_,c)||!_.size)&&d(_)},[t,n,r,a,o,s,i,l]);A(()=>{const _=setTimeout(g,200);return()=>clearTimeout(_)},[g]),A(()=>{if(!b)return;const _=os(),y=_.duration!==a,S=_.relativeTime!==o,T=_.relativeTime==="none"&&_.period.date!==s;(y||S||T)&&u({type:"SET_TIME_STATE",payload:_});const C=xs();C!==n&&v({type:"SET_DISPLAY_TYPE",payload:C});const k=c.get("g0.tenantID")||"";k!==t&&m({type:"SET_TENANT_ID",payload:k});const L=Zo();Zn(L,r)||(p({type:"SET_QUERY",payload:L}),u({type:"RUN_QUERY"}));const x=setTimeout(()=>{const E=c.get("g0.step_input")||i;E&&E!==l&&h({type:"SET_CUSTOM_STEP",payload:E})},50);return()=>clearTimeout(x)},[c,b]),me("popstate",()=>{f(!0)})},bd=e(Te,{text:"last_over_time",href:"https://docs.victoriametrics.com/victoriametrics/metricsql/#last_over_time",underlined:!0}),yd=e(Te,{text:"instant query",href:"https://docs.victoriametrics.com/victoriametrics/keyconcepts/#instant-query",underlined:!0}),wd=()=>{const{customStep:t}=He();return e("div",{children:[e("p",{children:["This tab shows ",yd," results for the last ",t||"5m"," (defined by the ",e("code",{children:"step"}),") ending at the selected time range."]}),e("p",{children:["Please wrap the query into ",bd," if you need results over arbitrary lookbehind interval."]})]})},Js=({value:t,hideValue:n})=>e("div",{className:"vm-line-progress",children:[e("div",{className:"vm-line-progress-track",children:e("div",{className:"vm-line-progress-track__thumb",style:{width:`${t}%`}})}),!n&&e("span",{children:[t.toFixed(2),"%"]})]}),Ks=({isRoot:t,trace:n,totalMsec:r,isExpandedAll:a})=>{const{isDarkTheme:o}=se(),{isMobile:s}=J(),[i,l]=N({}),c=q(null),[d,m]=N(!1),[u,h]=N(!1),p=Kr(n.duration/1e3)||`${n.duration}ms`;A(()=>{if(!c.current)return;const y=c.current,S=c.current.children[0],{height:T}=S.getBoundingClientRect();m(T>y.clientHeight)},[n]);const v=y=>{y.stopPropagation(),h(S=>!S)},b=n.children&&!!n.children.length,f=n.duration/r*100,g=y=>()=>{b&&l(S=>({...S,[y]:!S[y]}))},_=y=>{var T;const S=[y.idValue];return(T=y==null?void 0:y.children)==null||T.forEach(w=>{S.push(..._(w))}),S};return A(()=>{if(!a){l([]);return}const y=_(n),S={};y.forEach(T=>{S[T]=!0}),l(S)},[a]),e("div",{className:I({"vm-nested-nav":!0,"vm-nested-nav_root":t,"vm-nested-nav_dark":o,"vm-nested-nav_mobile":s}),children:[e("div",{className:I({"vm-nested-nav-header":!0,"vm-nested-nav-header_open":i[n.idValue]}),onClick:g(n.idValue),children:[b&&e("div",{className:I({"vm-nested-nav-header__icon":!0,"vm-nested-nav-header__icon_open":i[n.idValue]}),children:e(be,{})}),e("div",{className:"vm-nested-nav-header__progress",children:e(Js,{value:f})}),e("div",{className:I({"vm-nested-nav-header__message":!0,"vm-nested-nav-header__message_show-full":u}),ref:c,children:[e("span",{className:"vm-nested-nav-header__message_duration",children:p}),": ",e("span",{children:n.message})]}),e("div",{className:"vm-nested-nav-header-bottom",children:(d||u)&&e(D,{variant:"text",size:"small",onClick:v,children:u?"Hide":"Show full query"})})]}),i[n.idValue]&&e("div",{className:"vm-nested-nav__childrens",children:b&&n.children.map(y=>e(Ks,{trace:y,totalMsec:r,isExpandedAll:a},y.duration))})]})},Zs=({editable:t=!1,defaultTile:n="JSON",displayTitle:r=!0,defaultJson:a="",resetValue:o="",onClose:s,onUpload:i})=>{const l=Fe(),{isMobile:c}=J(),[d,m]=N(a),[u,h]=N(n),[p,v]=N(""),[b,f]=N(""),g=M(()=>{try{const C=JSON.parse(d),k=C.trace||C;return k.duration_msec?(new At(k,""),""):Ce.traceNotFound}catch(C){return C instanceof Error?C.message:"Unknown error"}},[d]),_=C=>{h(C)},y=C=>{f(""),m(C)},S=async()=>{await l(d,"Formatted JSON has been copied")},T=()=>{m(o)},w=()=>{f(g),u.trim()||v(Ce.emptyTitle),!(g||p)&&(i(d,u),s())};return e("div",{className:I({"vm-json-form":!0,"vm-json-form_one-field":!r,"vm-json-form_one-field_mobile":!r&&c,"vm-json-form_mobile":c}),children:[r&&e(ce,{value:u,label:"Title",error:p,onEnter:w,onChange:_}),e(ce,{value:d,label:"JSON",type:"textarea",error:b,autofocus:!0,onChange:y,onEnter:w,disabled:!t}),e("div",{className:"vm-json-form-footer",children:[e("div",{className:"vm-json-form-footer__controls",children:[e(D,{variant:"outlined",startIcon:e(Xe,{}),onClick:S,children:"Copy JSON"}),o&&e(D,{variant:"text",startIcon:e(ct,{}),onClick:T,children:"Reset JSON"})]}),e("div",{className:"vm-json-form-footer__controls vm-json-form-footer__controls_right",children:[e(D,{variant:"outlined",color:"error",onClick:s,children:"Cancel"}),e(D,{variant:"contained",onClick:w,children:"apply"})]})]})]})},Xs=(t,n)=>{const r=document.createElement("a"),a=URL.createObjectURL(t);r.setAttribute("href",a),r.setAttribute("download",n),document.body.appendChild(r),r.click(),document.body.removeChild(r),URL.revokeObjectURL(a)},Cd=(t,n)=>{const r=l=>{const c=l.reduce((d,m)=>(Object.keys(m).forEach(u=>{u&&!d[u]&&(d[u]=!0)}),d),{});return Object.keys(c)},a=l=>l.includes(",")||l.includes(` -`)||l.includes('"')?'"'+l.replace(/"/g,'""')+'"':l,s=(l=>{const c=r(l),d=l.map(m=>c.map(u=>m[u]?a(m[u]):"").join(","));return[c.map(a).join(","),...d].join(`\r -`)})(t),i=new Blob([s],{type:"text/csv;charset=utf-8;"});Xs(i,n)},Pa=(t,n)=>{const r=new Blob([t],{type:"application/json"});Xs(r,n)},Da=({traces:t,jsonEditor:n=!1,onDeleteClick:r})=>{const{isMobile:a}=J(),[o,s]=N(null),[i,l]=N([]),c=()=>{s(null)},d=(v,b)=>{if(!(!n||!o))try{o.setTracing(JSON.parse(v)),o.setQuery(b),s(null)}catch(f){console.error(f)}};if(!t.length)return e(le,{variant:"info",children:"Please re-run the query to see results of the tracing"});const m=v=>()=>{r(v)},u=v=>()=>{s(v)},h=v=>()=>{Pa(v.originalJSON,`vmui_trace_${v.queryValue}.json`)},p=v=>()=>{l(b=>b.includes(v.idValue)?b.filter(f=>f!==v.idValue):[...b,v.idValue])};return e(V,{children:[e("div",{className:"vm-tracings-view",children:t.map(v=>e("div",{className:"vm-tracings-view-trace vm-block vm-block_empty-padding",children:[e("div",{className:"vm-tracings-view-trace-header",children:[e("h3",{className:"vm-tracings-view-trace-header-title",children:["Trace for ",e("b",{className:"vm-tracings-view-trace-header-title__query",children:v.queryValue})]}),e(j,{title:i.includes(v.idValue)?"Collapse All":"Expand All",children:e(D,{variant:"text",startIcon:i.includes(v.idValue)?e(ua,{}):e(ma,{}),onClick:p(v),ariaLabel:i.includes(v.idValue)?"Collapse All":"Expand All"})}),e(j,{title:"Save Trace to JSON",children:e(D,{variant:"text",startIcon:e(fn,{}),onClick:h(v),ariaLabel:"Save trace to JSON"})}),e(j,{title:"Open JSON",children:e(D,{variant:"text",startIcon:e(It,{}),onClick:u(v),ariaLabel:"open JSON"})}),e(j,{title:"Remove trace",children:e(D,{variant:"text",color:"error",startIcon:e(gn,{}),onClick:m(v),ariaLabel:"remove trace"})})]}),e("nav",{className:I({"vm-tracings-view-trace__nav":!0,"vm-tracings-view-trace__nav_mobile":a}),children:e(Ks,{isRoot:!0,trace:v,totalMsec:v.duration,isExpandedAll:i.includes(v.idValue)})})]},v.idValue))}),o&&e(Me,{title:o.queryValue,onClose:c,children:e(Zs,{editable:n,displayTitle:n,defaultTile:o.queryValue,defaultJson:o.JSON,resetValue:o.originalJSON,onClose:c,onUpload:d})})]})},Nd=({traces:t,displayType:n})=>{const{isTracingEnabled:r}=je(),[a,o]=N([]),s=i=>{const l=a.filter(c=>c.idValue!==i.idValue);o([...l])};return A(()=>{t&&o([...a,...t])},[t]),A(()=>{o([])},[n]),e(V,{children:r&&e("div",{className:"vm-custom-panel__trace",children:e(Da,{traces:a,onDeleteClick:s})})})},tr=({warning:t,query:n,onChange:r})=>{const{isMobile:a}=J(),{value:o,setTrue:s,setFalse:i}=ae(!1);return A(i,[n]),A(()=>{r(o)},[o]),e(le,{variant:"warning",children:e("div",{className:I({"vm-custom-panel__warning":!0,"vm-custom-panel__warning_mobile":a}),children:[e("p",{children:t}),e(D,{color:"warning",variant:"outlined",onClick:s,children:"Show all"})]})})},nr=t=>{let n=t.length,r=-1/0;for(;n--;){const a=t[n];Number.isFinite(a)&&a>r&&(r=a)}return Number.isFinite(r)?r:null},Oa=t=>{let n=t.length,r=1/0;for(;n--;){const a=t[n];Number.isFinite(a)&&a{let n=t[0],r=1;for(let a=1;a{let n=t.length;const r=[];for(;n--;){const a=t[n];Number.isFinite(a)&&r.push(a)}return r.sort(),r[r.length>>1]},Td=t=>{let n=t.length;for(;n--;){const r=t[n];if(Number.isFinite(r))return r}},Ld=t=>t>=1e9?(t/1e9).toFixed(1).replace(/\.0$/,"")+"B":t>=1e6?(t/1e6).toFixed(1).replace(/\.0$/,"")+"M":t>=1e3?(t/1e3).toFixed(1).replace(/\.0$/,"")+"K":t.toString(),Ad=(t,n,r="")=>{const a=n[0],o=n[n.length-1];return r?n.map(s=>`${bt(s,a,o)} ${r}`):n.map(s=>bt(s,a,o))},bt=(t,n,r)=>{if(t==null)return"";r=r||0,n=n||0;const a=Math.abs(r-n);if(isNaN(a)||a==0)return Math.abs(t)>=1e3?t.toLocaleString("en-US"):t.toString();let o=3+Math.floor(1+Math.log10(Math.max(Math.abs(n),Math.abs(r)))-Math.log10(a));return(isNaN(o)||o>20)&&(o=20),t.toLocaleString("en-US",{minimumSignificantDigits:1,maximumSignificantDigits:o})},Ed=(t,n)=>{const r=document.createElement("span");r.innerText=t,r.style.cssText=`position: absolute; z-index: -1; pointer-events: none; opacity: 0; font: ${n}`,document.body.appendChild(r);const a=r.offsetWidth;return r.remove(),a},xd=(t,n)=>{if(n!=null&&n.hasAlias&&(n!=null&&n.label))return n.label;const r=(t==null?void 0:t.metric)||{},o=Object.keys(r).filter(i=>i!="__name__").map(i=>`${i}=${JSON.stringify(r[i])}`);let s=r.__name__||"";return o.length>0&&(s+="{"+o.join(",")+"}"),s},Md=[[3600*24*365,"{YYYY}",null,null,null,null,null,null,1],[3600*24*28,"{MMM}",` -{YYYY}`,null,null,null,null,null,1],[3600*24,"{MM}-{DD}",` -{YYYY}`,null,null,null,null,null,1],[3600,"{HH}:{mm}",` -{YYYY}-{MM}-{DD}`,null,` -{MM}-{DD}`,null,null,null,1],[60,"{HH}:{mm}",` -{YYYY}-{MM}-{DD}`,null,` -{MM}-{DD}`,null,null,null,1],[1,"{HH}:{mm}:{ss}",` -{YYYY}-{MM}-{DD}`,null,` -{MM}-{DD} {HH}:{mm}`,null,null,null,1],[.001,":{ss}.{fff}",` -{YYYY}-{MM}-{DD} {HH}:{mm}`,null,` -{MM}-{DD} {HH}:{mm}`,null,` -{HH}:{mm}`,null,1]],Ra=(t,n)=>Array.from(new Set(t.map(r=>r.scale))).map(r=>{const a="10px Arial",o=tt("color-text"),s={scale:r,show:!0,size:ei,stroke:o,font:a,values:(i,l)=>Ad(i,l,n)};return r?!(Number(r)%2)&&r!=="y"?{...s,side:1}:s:{space:80,values:Md,stroke:o,font:a}}),Id=(t,n,r)=>{const a=Zr(n)||1,o=Array.from(new Set(t)).sort((d,m)=>d-m);let s=r.start;const i=xn(r.end+a);let l=0;const c=[];for(;s<=i;){for(;l=o.length||o[l]>s)&&c.push(s)}for(;c.length<2;)c.push(s),s=xn(s+a);return c},rr=(t,n)=>{if(t==null||n==null)return[-1,1];const a=.02*(Math.abs(n-t)||Math.abs(t)||1);return[t-a,n+a]},Pd=(t,n)=>{const r={},a=Object.values(t).flat(),o="1",s=Oa(a)||0,i=nr(a)||1;return r[o]=n?rr(s,i):[s,i],r},ei=(t,n,r,a)=>{var l;const o=t.axes[r];if(a>1)return o._size||60;let s=6+(((l=o==null?void 0:o.ticks)==null?void 0:l.size)||0)+(o.gap||0);const i=(n??[]).reduce((c,d)=>(d==null?void 0:d.length)>c.length?d:c,"");return i!=""&&(s+=Ed(i,"10px Arial")),Math.ceil(s)},go=["#e54040","#32a9dc","#2ee329","#7126a1","#e38f0f","#3d811a","#ffea00","#2d2d2d","#da42a6","#a44e0c"],ti=t=>{if(t.length!=7)return"0, 0, 0";const n=parseInt(t.slice(1,3),16),r=parseInt(t.slice(3,5),16),a=parseInt(t.slice(5,7),16);return`${n}, ${r}, ${a}`},Ht={[ne.yhatUpper]:"#7126a1",[ne.yhatLower]:"#7126a1",[ne.yhat]:"#da42a6",[ne.anomaly]:"#da4242",[ne.anomalyScore]:"#7126a1",[ne.actual]:"#203ea9",[ne.training]:`rgba(${ti("#203ea9")}, 0.2)`},vo=t=>{let a=1,o=0,s=1;if(t.length>0)for(let l=0;lo&&(o=t[l].charCodeAt(0)),s=parseInt(String(16777215/o)),a=(a+t[l].charCodeAt(0)*s*49979693)%16777215;let i=(a*t.length%16777215).toString(16);return i=i.padEnd(6,i),`#${i}`},Dd=t=>{let n=t.replace("#","").trim();if(n.length===3&&(n=n[0]+n[0]+n[1]+n[1]+n[2]+n[2]),n.length!==6)throw new Error("Invalid HEX color.");const r=parseInt(n.slice(0,2),16),a=parseInt(n.slice(2,4),16),o=parseInt(n.slice(4,6),16);return(r*299+a*587+o*114)/1e3>=128?"#000000":"#FFFFFF"},Od=(t,n,r)=>{const a=[];for(let o=0;oMath.round(d)).join(", "))}return a.map(o=>`rgb(${o})`)},$a=Od([246,226,219],[127,39,4],16),Rd=(t,n)=>{const r=t.data[n][2],a=$a,o=0;let s=1/0,i=-1/0;for(let m=0;mo&&(s=Math.min(s,r[m]),i=Math.max(i,r[m]));const l=i-s,c=a.length,d=Array(r.length);for(let m=0;m(t,n)=>{const r=Math.round(devicePixelRatio);jt.orient(t,n,(a,o,s,i,l,c,d,m,u,h,p,v,b,f)=>{const[g,_,y]=t.data[n],S=g.length,T=Rd(t,n),w=$a??[...Array.from(new Set(T))],C=w.map(()=>new Path2D),k=S-_.lastIndexOf(_[0]),L=S/k,x=_[1]-_[0],E=g[k]-g[0],P=c(E,i,h,m)-c(0,i,h,m)-r,F=d(x,l,p,u)-d(0,l,p,u)+r,O=_.slice(0,k).map(z=>Math.round(d(z,l,p,u)-F/2)),H=Array.from({length:L},(z,Y)=>Math.round(c(g[Y*k],i,h,m)-P));for(let z=0;z0&&g[z]>=(i.min||-1/0)&&g[z]<=(i.max||1/0)&&_[z]>=(l.min||-1/0)&&_[z]<=(l.max||1/0)){const Y=H[~~(z/k)],G=O[z%k],K=C[T[z]];f(K,Y,G,P,F)}t.ctx.save(),t.ctx.rect(t.bbox.left,t.bbox.top,t.bbox.width,t.bbox.height),t.ctx.clip(),C.forEach((z,Y)=>{t.ctx.fillStyle=w[Y],t.ctx.fill(z)}),t.ctx.restore()})},Fd=t=>{var s,i;if(!t.every(l=>l.metric.le))return t;const n=t.sort((l,c)=>parseFloat(l.metric.le)-parseFloat(c.metric.le)),r=((s=t[0])==null?void 0:s.group)||1;let a={metric:{le:""},values:[]};const o=[];for(const l of n){const c=[a.metric.le,l.metric.le].filter(m=>m).join("..."),d=[];for(const[m,u]of l.values){const h=((i=a.values.find(v=>v[0]===m))==null?void 0:i[1])||0,p=+u-+h;d.push([m,`${p}`])}o.push({metric:{vmrange:c},values:d,group:r}),a=l}return o},fo=t=>{const n=(t.metric.vmrange||t.metric.le||"").split("...");return sn(n[n.length-1])},zd=(t,n)=>fo(t)-fo(n),Hd=(t,n)=>{if(!n)return t;const r=t.sort(zd),a=Fd(r),o={};return a.forEach(i=>i.values.forEach(([l,c])=>{const d=Number(c),m=isNaN(d)?0:d,u=o[l]||0;o[l]=u+m})),a.map(i=>{const l=i.values.map(([c,d])=>{const m=o[c];return[c,`${Math.round(+d/m*100)}`]});return{...i,values:l}}).filter(i=>!i.values.every(l=>l[1]==="0"))},Vd=t=>{Object.keys(t.hooks).forEach(n=>{t.hooks[n]=[]})},Pr=t=>{const n=["__name__","for"];return Object.entries(t).filter(([r])=>!n.includes(r)).map(([r,a])=>`${r}: ${a}`).join(",")},ni=t=>{const n=(t==null?void 0:t.__name__)||"",r=new RegExp(`(${Object.values(ne).join("|")})$`),a=n.match(r),o=a&&a[0];return{value:/(?:^|[^a-zA-Z0-9_])y(?:$|[^a-zA-Z0-9_])/.test(n)?ne.actual:o,group:Pr(t)}},qd=(t,n,r,a)=>{const o={},s=a?0:Math.min(t.length,go.length);for(let i=0;i{const c=a?ni(t[l].metric):null,d=r[i.group-1],m=a?(c==null?void 0:c.group)||"":Ir(i,d);return{label:m,hasAlias:!!d,dash:jd(c),width:Qd(c),stroke:Wd({metricInfo:c,label:m,isAnomalyUI:a,colorState:o}),points:Yd(c),spanGaps:!1,forecast:c==null?void 0:c.value,forecastGroup:c==null?void 0:c.group,freeFormFields:i.metric,show:!ri(m,n),scale:"1",...Ud(i)}}},Ud=t=>{const n=t.values.map(i=>sn(i[1])),{min:r,max:a,median:o,last:s}={min:Oa(n),max:nr(n),median:kd(n),last:Td(n)};return{median:o,statsFormatted:{min:bt(r,r,a),max:bt(a,r,a),median:bt(o,r,a),last:bt(s,r,a)}}},_o=(t,n)=>({group:n,label:t.label||"",color:t.stroke,checked:t.show||!1,freeFormFields:t.freeFormFields,statsFormatted:t.statsFormatted,median:t.median,hasAlias:t.hasAlias||!1}),Bd=({hideSeries:t,legend:n,metaKey:r,series:a,isAnomalyView:o})=>{const{label:s}=n,i=ri(s,t),l=a.map(c=>c.label||"");return o?l.filter(c=>c!==s):r?i?t.filter(c=>c!==s):[...t,s]:t.length?i?[...l.filter(c=>c!==s)]:[]:[...l.filter(c=>c!==s)]},ri=(t,n)=>n.includes(`${t}`),Fa=t=>{for(let n=t.series.length-1;n>=0;n--)n&&t.delSeries(n)},ai=(t,n,r=!1)=>{n.forEach((a,o)=>{a.label&&(a.spanGaps=r),o&&t.addSeries(a)})},jd=t=>{const n=(t==null?void 0:t.value)===ne.yhatLower,r=(t==null?void 0:t.value)===ne.yhatUpper,a=(t==null?void 0:t.value)===ne.yhat;return n||r?[10,5]:a?[10,2]:[]},Qd=t=>{const n=(t==null?void 0:t.value)===ne.yhatLower,r=(t==null?void 0:t.value)===ne.yhatUpper,a=(t==null?void 0:t.value)===ne.yhat,o=(t==null?void 0:t.value)===ne.anomaly;return r||n?.7:a?1:o?0:1.4},Yd=t=>(t==null?void 0:t.value)===ne.anomaly?{size:8,width:4,space:0}:{size:4,width:0,show:!0,filter:Gd},Gd=(t,n)=>{const r=t.data[n],a=[];for(let o=0;o{const o=a[n]||vo(n),s=(t==null?void 0:t.value)===ne.anomaly;return r&&s?Ht[ne.anomaly]:r&&!s&&!(t!=null&&t.value)?Ht[ne.actual]:t!=null&&t.value?t!=null&&t.value?Ht[t==null?void 0:t.value]:o:a[n]||vo(n)},oi=({width:t=400,height:n=500})=>({width:t,height:n,series:[],tzDate:r=>U(Ft(We(r))).local().toDate(),legend:{show:!1},cursor:{drag:{x:!0,y:!1},focus:{prox:30},points:{size:5.6,width:1.4},bind:{click:()=>null,dblclick:()=>null}}}),za=t=>{Fa(t),Vd(t),t.setData([])},si=({min:t,max:n})=>[t,n],ii=(t,n=0,r=1,a,o)=>o.limits.enable?o.limits.range[a]:rr(n,r),Jd=(t,n)=>{const r={x:{range:()=>si(n)}},a=Object.keys(t.limits.range);return(a.length?a:["1"]).forEach(o=>{r[o]={range:(s,i=0,l=1)=>ii(s,i,l,o,t)}}),r},Ha=t=>n=>{const r=n.posToVal(n.select.left,"x"),a=n.posToVal(n.select.left+n.select.width,"x");t({min:r,max:a})},li=(t,n)=>{if(t.delBand(),n.length<2)return;const r=n.map((i,l)=>({...i,index:l})),a=r.filter(i=>i.forecast===ne.yhatUpper),o=r.filter(i=>i.forecast===ne.yhatLower),s=a.map(i=>{const l=o.find(c=>c.forecastGroup===i.forecastGroup);return l?{series:[i.index,l.index],fill:Kd(ne.yhatUpper)}:null}).filter(i=>i!==null);s.length&&s.forEach(i=>{t.addBand(i)})};function Kd(t){return`rgba(${ti(Ht[t])}, 0.05)`}const Zd=t=>t instanceof MouseEvent,bo=t=>Zd(t)?t.clientX:t.touches[0].clientX,Xd=({dragSpeed:t=.85,setPanning:n,setPlotScale:r})=>{const a=q({leftStart:0,xUnitsPerPx:0,scXMin:0,scXMax:0}),o=l=>{l.preventDefault();const c=bo(l),{leftStart:d,xUnitsPerPx:m,scXMin:u,scXMax:h}=a.current,p=m*((c-d)*t);r({min:u-p,max:h-p})},s=()=>{n(!1),document.removeEventListener("mousemove",o),document.removeEventListener("mouseup",s),document.removeEventListener("touchmove",o),document.removeEventListener("touchend",s)},i=()=>{document.addEventListener("mousemove",o),document.addEventListener("mouseup",s),document.addEventListener("touchmove",o),document.addEventListener("touchend",s)};return({e:l,u:c})=>{l.preventDefault(),n(!0),a.current={leftStart:bo(l),xUnitsPerPx:c.posToVal(1,"x")-c.posToVal(0,"x"),scXMin:c.scales.x.min||0,scXMax:c.scales.x.max||0},i()}},em=t=>{const{ctrlKey:n,metaKey:r,button:a}=t;return a===0&&(n||r)},fr=.9,Va=t=>{const[n,r]=N(!1),a=Xd({dragSpeed:fr,setPanning:r,setPlotScale:t});return{onReadyChart:s=>{const i=c=>{const d=c instanceof MouseEvent&&em(c),m=window.TouchEvent&&c instanceof TouchEvent&&c.touches.length>1;(d||m)&&a({u:s,e:c})},l=c=>{if(!c.ctrlKey&&!c.metaKey)return;c.preventDefault();const{width:d}=s.over.getBoundingClientRect(),m=s.cursor.left&&s.cursor.left>0?s.cursor.left:0,u=s.posToVal(m,"x"),h=(s.scales.x.max||0)-(s.scales.x.min||0),p=c.deltaY<0?h*fr:h/fr,v=u-m/d*p,b=v+p;s.batch(()=>t({min:v,max:b}))};s.over.addEventListener("mousedown",i),s.over.addEventListener("touchstart",i),s.over.addEventListener("wheel",l)},isPanning:n}},yo=t=>{const n=t[0].clientX-t[1].clientX,r=t[0].clientY-t[1].clientY;return Math.sqrt(n*n+r*r)},qa=({uPlotInst:t,xRange:n,setPlotScale:r})=>{const[a,o]=N(0),s=W(c=>{const{target:d,ctrlKey:m,metaKey:u,key:h}=c,p=d instanceof HTMLInputElement||d instanceof HTMLTextAreaElement;if(!t||p)return;const v=h==="+"||h==="=";if((h==="-"||v)&&!(m||u)){c.preventDefault();const g=(n.max-n.min)/10*(v?1:-1);r({min:n.min+g,max:n.max-g})}},[t,n]),i=c=>{c.touches.length===2&&(c.preventDefault(),o(yo(c.touches)))},l=W(c=>{if(!t||c.touches.length!==2)return;c.preventDefault();const d=yo(c.touches),m=a-d,u=t.scales.x.max||n.max,h=t.scales.x.min||n.min,p=u-h,v=m>0?-1:1,b=p/50*v;t.batch(()=>r({min:h+b,max:u-b}))},[t,a,n]);return me("keydown",s),me("touchmove",l),me("touchstart",i),null},Ua=({period:t,setPeriod:n})=>{const[r,a]=N({min:t.start,max:t.end}),o=({min:s,max:i})=>{const l=(i-s)*1e3;lno.max||n({from:U(s*1e3).toDate(),to:U(i*1e3).toDate()})};return A(()=>{a({min:t.start,max:t.end})},[t]),{xRange:r,setPlotScale:o}},tm=({u:t,metrics:n,series:r,unit:a,isAnomalyView:o})=>{const[s,i]=N(!1),[l,c]=N({seriesIdx:-1,dataIdx:-1}),[d,m]=N([]),u=()=>{m([]),c({seriesIdx:-1,dataIdx:-1})},h=g=>{const _=g.cursor.idx??-1;c(y=>({...y,dataIdx:_}))},p=(g,_)=>{const y=_??-1;c(S=>({...S,seriesIdx:y}))},v=W(()=>{const{seriesIdx:g,dataIdx:_}=l,y=n[g-1],S=r[g],T=new Set(n.map(P=>P.group)),w=(y==null?void 0:y.group)||0,C=st(t,["data",g,_],0),k=st(t,["scales","1","min"],0),L=st(t,["scales","1","max"],1),x=st(t,["data",0,_],0),E={top:t?t.valToPos(C||0,(S==null?void 0:S.scale)||"1"):0,left:t?t.valToPos(x,"x"):0};return{unit:a,point:E,u:t,id:`${g}_${_}`,title:T.size>1&&!o?`Query ${w}`:"",dates:[x?U(x*1e3).tz().format(On):"-"],value:bt(C,k,L),info:xd(y,S),statsFormatted:S==null?void 0:S.statsFormatted,marker:`${S==null?void 0:S.stroke}`}},[t,l,n,r,a,o]),b=W(()=>{if(!s)return;const g=v();d.find(_=>_.id===g.id)||m(_=>[..._,g])},[v,d,s]),f=g=>{m(_=>_.filter(y=>y.id!==g))};return A(()=>{i(l.dataIdx!==-1&&l.seriesIdx!==-1)},[l]),me("click",b),{showTooltip:s,stickyTooltips:d,handleUnStick:f,getTooltipProps:v,seriesFocus:p,setCursor:h,resetTooltips:u}},wo=({u:t,id:n,title:r,dates:a,value:o,point:s,unit:i="",info:l,statsFormatted:c,isSticky:d,marker:m,onClose:u})=>{const h=q(null),[p,v]=N({top:-999,left:-999}),[b,f]=N(!1),[g,_]=N(!1),y=()=>{u&&u(n)},S=k=>{_(!0),f(!0);const{clientX:L,clientY:x}=k;v({top:x,left:L})},T=W(k=>{if(!b)return;const{clientX:L,clientY:x}=k;v({top:x,left:L})},[b]),w=()=>{f(!1)};return A(()=>{if(!h.current||!t)return;const{top:k,left:L}=s,x={left:parseFloat(t.over.style.left),top:parseFloat(t.over.style.top)},{width:E,height:P}=t.over.getBoundingClientRect(),{width:F,height:O}=h.current.getBoundingClientRect(),H=10,z=L+F>=E?F+2*H:0,Y=k+O>=P?O+2*H:0,G={top:k+x.top+H-Y,left:L+x.left+H-z};G.left<0&&(G.left=20),G.top<0&&(G.top=20),v(G)},[t,o,s,h]),me("mousemove",T),me("mouseup",w),t?pt(e("div",{className:I({"vm-chart-tooltip":!0,"vm-chart-tooltip_sticky":d,"vm-chart-tooltip_moved":g}),ref:h,style:p,children:[e("div",{className:"vm-chart-tooltip-header",children:[r&&e("div",{className:"vm-chart-tooltip-header__title",children:r}),e("div",{className:"vm-chart-tooltip-header__date",children:a.map((k,L)=>e("span",{children:k},L))}),d&&e(V,{children:[e(D,{className:"vm-chart-tooltip-header__drag",variant:"text",size:"small",startIcon:e(ia,{}),onMouseDown:S,ariaLabel:"drag the tooltip"}),e(D,{className:"vm-chart-tooltip-header__close",variant:"text",size:"small",startIcon:e(Ue,{}),onClick:y,ariaLabel:"close the tooltip"})]})]}),e("div",{className:"vm-chart-tooltip-data",children:[m&&e("span",{className:"vm-chart-tooltip-data__marker",style:{background:m}}),e("p",{className:"vm-chart-tooltip-data__value",children:[e("b",{children:o}),i]})]}),c&&e("table",{className:"vm-chart-tooltip-stats",children:jr.map((k,L)=>e("div",{className:"vm-chart-tooltip-stats-row",children:[e("span",{className:"vm-chart-tooltip-stats-row__key",children:[k,":"]}),e("span",{className:"vm-chart-tooltip-stats-row__value",children:c[k]})]},L))}),l&&e("p",{className:"vm-chart-tooltip__info",children:l})]}),t.root):null},ci=({showTooltip:t,tooltipProps:n,stickyTooltips:r,handleUnStick:a})=>e(V,{children:[t&&n&&e(wo,{...n}),r.map(o=>Qi(wo,{...o,isSticky:!0,key:o.id,onClose:a}))]}),nm=({data:t,series:n,metrics:r=[],period:a,yaxis:o,unit:s,setPeriod:i,layoutSize:l,height:c,isAnomalyView:d,spanGaps:m=!1})=>{const{isDarkTheme:u}=se(),h=q(null),[p,v]=N(),{xRange:b,setPlotScale:f}=Ua({period:a,setPeriod:i}),{onReadyChart:g,isPanning:_}=Va(f);qa({uPlotInst:p,xRange:b,setPlotScale:f});const{showTooltip:y,stickyTooltips:S,handleUnStick:T,getTooltipProps:w,seriesFocus:C,setCursor:k,resetTooltips:L}=tm({u:p,metrics:r,series:n,unit:s,isAnomalyView:d}),x={...oi({width:l.width,height:c}),series:n,axes:Ra([{},{scale:"1"}],s),scales:Jd(o,b),hooks:{ready:[g],setSeries:[C],setCursor:[k],setSelect:[Ha(f)],destroy:[za]},bands:[]};return A(()=>{if(L(),!h.current)return;p&&p.destroy();const E=new jt(x,t,h.current);return v(E),E.destroy},[h,u]),A(()=>{p&&(p.setData(t),p.redraw())},[t]),A(()=>{p&&(Fa(p),ai(p,n,m),li(p,n),p.redraw())},[n,m]),A(()=>{p&&(Object.keys(o.limits.range).forEach(E=>{p.scales[E]&&(p.scales[E].range=(P,F=0,O=1)=>ii(P,F,O,E,o))}),p.redraw())},[o]),A(()=>{p&&(p.scales.x.range=()=>si(b),p.redraw())},[b]),A(()=>{p&&(p.setSize({width:l.width||400,height:c||500}),p.redraw())},[c,l]),e("div",{className:I({"vm-line-chart":!0,"vm-line-chart_panning":_}),style:{minWidth:`${l.width||400}px`,minHeight:`${c||500}px`},children:[e("div",{className:"vm-line-chart__u-plot",ref:h}),e(ci,{showTooltip:y,tooltipProps:w(),stickyTooltips:S,handleUnStick:T})]})};var Wt=(t=>(t.view="legend_view",t.hideDuplicates="legend_hide_duplicates",t.hideStats="legend_hide_stats",t.format="legend_format",t.group="legend_group",t))(Wt||{}),Dr=(t=>(t.table="table",t.lines="lines",t))(Dr||{});const Sn=Wt.view,di=()=>{const[t,n]=oe(),r=t.get(Sn),[a,o]=N(r||"lines"),s=i=>{i==="table"?t.set(Sn,i):t.delete(Sn),o(i),n(t)};return A(()=>{const i=t.get(Sn);i!==a&&o(i)},[t]),{view:a,isLinesView:a==="lines",isTableView:a==="table",onChange:s}},rm=t=>Object.keys(t.freeFormFields).filter(r=>r!=="__name__").map(r=>{const a=`${r}=${JSON.stringify(t.freeFormFields[r])}`;return{id:`${t.label}.${a}`,freeField:a,key:r}}),kn=Wt.hideStats,Ba=()=>{const[t,n]=oe(),r=t.get(kn)==="true",[a,o]=N(r),s=i=>{i?t.set(kn,"true"):t.delete(kn),o(i),n(t)};return A(()=>{const i=t.get(kn)==="true";i!==a&&o(i)},[t]),{hideStats:a,onChange:s}},Tn=Wt.format,mi=()=>{const[t,n]=oe(),r=t.get(Tn)||"",[a,o]=N(r),s=l=>{o(l)},i=()=>{a?t.set(Tn,a):t.delete(Tn),n(t)};return A(()=>{const l=t.get(Tn);l!==a&&o(l||"")},[t]),{format:a,onChange:s,onApply:i}},am=({legend:t,onChange:n,duplicateFields:r,isAnomalyView:a})=>{const o=Fe(),{hideStats:s}=Ba(),{format:i}=mi(),l=Ws(t.freeFormFields,i),c=M(()=>{const p=rm(t);return r!=null&&r.length?p.filter(v=>!r.includes(v.key)):p},[t,r]),d=t.statsFormatted,m=Object.values(d).some(p=>p),u=p=>v=>{n&&n(p,v.ctrlKey||v.metaKey)},h=p=>async v=>{v.stopPropagation(),await o(p,`${p} has been copied`)};return e("div",{className:I({"vm-legend-item":!0,"vm-legend-row":!0,"vm-legend-item_hide":!t.checked}),onClick:u(t),children:[!a&&e("div",{className:"vm-legend-item__marker",style:{backgroundColor:t.color}}),e("div",{className:"vm-legend-item-info",children:e("span",{className:"vm-legend-item-info__label",children:[t.hasAlias&&t.label,!t.hasAlias&&i&&l,!t.hasAlias&&!i&&e(V,{children:[t.freeFormFields.__name__,!!c.length&&e(V,{children:" {"}),c.map((p,v)=>e("span",{className:"vm-legend-item-info__free-fields",onClick:h(p.freeField),title:"copy to clipboard",children:[p.freeField,v+1e("div",{className:"vm-legend-item-stats-row",children:[e("span",{className:"vm-legend-item-stats-row__key",children:[p,":"]}),e("span",{className:"vm-legend-item-stats-row__value",children:d[p]})]},v))})]})},om=({labels:t,isAnomalyView:n,duplicateFields:r,onChange:a})=>e("div",{className:"vm-legend-item-container",children:t.map(o=>e(am,{legend:o,isAnomalyView:n,duplicateFields:r,onChange:a},o.label))}),sm=jr.map(t=>({key:`statsFormatted.${t}`,title:t})),im=({labels:t,duplicateFields:n,onChange:r})=>{const{hideStats:a}=Ba(),o=a?[]:sm,i=M(()=>{const c=[...new Set(t.flatMap(d=>Object.keys(d.freeFormFields)))].map(d=>({key:`freeFormFields.${d}`,title:d}));return n!=null&&n.length?c.filter(d=>!n.includes(d.title)):c},[t,n]).concat(o),l=c=>d=>{r&&r(c,d.ctrlKey||d.metaKey)};return e("div",{className:"vm-legend-table__wrapper",children:e("table",{className:"vm-legend-table",children:[e("thead",{className:"vm-legend-table-thead",children:e("tr",{className:"vm-legend-table-row vm-legend-table_thead",children:[e("th",{className:"vm-legend-table-col vm-legend-table-col_marker vm-legend-table-col_thead"}),i.map(c=>e("th",{className:"vm-legend-table-col vm-legend-table-col_thead",children:c.title},c.key))]})}),e("tbody",{className:"vm-legend-table-tbody",children:t.map(c=>e("tr",{className:I({"vm-legend-table-row":!0,"vm-legend-table-row_tbody":!0,"vm-legend-table-row_exclude":!c.checked}),onClick:l(c),children:[e("td",{className:"vm-legend-table-col vm-legend-table-col_marker",children:e("div",{className:"vm-legend-item__marker",style:{backgroundColor:c.color}})}),i.map(d=>e("td",{className:"vm-legend-table-col",children:e("span",{className:"vm-legend-table-col__content",children:st(c,d.key)})},`${d.key}_${c.label}`))]},c.label))})]})})},Ln=Wt.hideDuplicates,ui=t=>{const[n,r]=oe(),a=n.get(Ln)==="true",[o,s]=N(a),i=c=>{c?n.set(Ln,"true"):n.delete(Ln),s(c),r(n)};A(()=>{const c=n.get(Ln)==="true";c!==o&&s(c)},[n]);const l=M(()=>!o||!(t!=null&&t.length)||(t==null?void 0:t.length)<2?[]:[...new Set(t.flatMap(d=>Object.keys(d.freeFormFields||{})))].filter(d=>{var u;const m=(u=t.find(h=>h.freeFormFields[d]))==null?void 0:u.freeFormFields[d];return t.every(h=>h.freeFormFields[d]===m)}),[t,o]);return{hideDuplicates:o,onChange:i,duplicateFields:l}},lm=50,hi=100,pi=5,Ut="Ungrouped",Re="_stream",tn="_msg",$t=`${qe}.SSS`,ke={GROUP_BY:"groupBy",DISPLAY_FIELDS:"displayFields",NO_WRAP_LINES:"noWrapLines",COMPACT_GROUP_HEADER:"compactGroupHeader",DATE_FORMAT:"dateFormat",ROWS_PER_PAGE:"rows_per_page"},An=Wt.group,ja=()=>{const[t,n]=oe(),r=t.get(An)||"",[a,o]=N(r),s=i=>{i&&i!==Ut?t.set(An,i):t.delete(An),o(i),n(t)};return A(()=>{const i=t.get(An);i!==a&&o(i||"")},[t]),{groupByLabel:a,onChange:s}},cm=({labels:t,group:n,isAnomalyView:r,onChange:a})=>{const{isTableView:o}=di(),{groupByLabel:s}=ja(),i=Fe(),{duplicateFields:l}=ui(t),c=M(()=>t.sort((u,h)=>(h.median||0)-(u.median||0)),[t]),d=u=>async h=>{h.stopPropagation(),await i(u,`${u} has been copied`)},m=o?im:om;return e("div",{className:"vm-legend-group",children:e(Kn,{defaultExpanded:!0,title:e("div",{className:"vm-legend-group-header",children:[e("div",{className:"vm-legend-group-header-title",children:["Group by",s?"":" query",": ",e("b",{children:n})]}),!!l.length&&e("div",{className:"vm-legend-group-header-labels",children:["common labels: {",l.map(u=>e("div",{onClick:d(`${u}="${t[0].freeFormFields[u]}"`),className:"vm-legend-group-header-labels__item",children:`${u}="${t[0].freeFormFields[u]}"`},u)),"}"]})]}),children:e(m,{labels:c,isAnomalyView:r,duplicateFields:l,onChange:a})})},n)},dm=({labels:t,query:n,groupByLabel:r})=>M(()=>mm(t,n,r),[t,n,r]),mm=(t,n,r)=>{const a=new Map;for(const o of t){const s=r?`${r}="${o.freeFormFields[r]??""}"`:`${n[o.group-1]}`;a.has(s)||a.set(s,{group:String(s),items:[]});const i=a.get(s);i.items.some(c=>c.label===o.label)||i.items.push(o)}return Array.from(a.values())},um=({values:t,onRemoveItem:n})=>{const{isMobile:r}=J(),a=o=>s=>{n(o),s.stopPropagation()};return r?e("span",{className:"vm-select-input-content__counter",children:["selected ",t.length]}):e(V,{children:t.map(o=>e("div",{className:"vm-select-input-content__selected",children:[e("span",{children:o}),e("div",{onClick:a(o),children:e(Ue,{})})]},o))})},it=({value:t,list:n,label:r,placeholder:a,noOptionsText:o,clearable:s=!1,searchable:i=!1,autofocus:l,disabled:c,onChange:d})=>{const{isDarkTheme:m}=se(),{isMobile:u}=J(),[h,p]=N(""),v=q(null),[b,f]=N(null),[g,_]=N(!1),y=q(null),S=Array.isArray(t),T=Array.isArray(t)?t:void 0,w=u&&S&&!!(T!=null&&T.length),C=M(()=>g?h:Array.isArray(t)?"":t,[t,h,g,S]),k=M(()=>g?h||"(.+)":"",[h,g]),L=()=>{y.current&&y.current.blur()},x=()=>{_(!1),L()},E=()=>{c||_(!0)},P=()=>{n.includes(h)&&d(h)},F=G=>{G.target instanceof HTMLInputElement||c||_(K=>!K)},O=G=>{p(""),d(G),S||x(),S&&y.current&&y.current.focus()},H=G=>{p(G.target.value)},z=G=>K=>{O(G),K.stopPropagation()},Y=G=>{y.current!==G.target&&_(!1)};return A(()=>{p(""),g&&y.current&&y.current.focus(),g||L()},[g,y]),A(()=>{!l||!y.current||u||y.current.focus()},[l,y]),me("keyup",Y),_n(v,x,b),e("div",{className:I({"vm-select":!0,"vm-select_dark":m,"vm-select_disabled":c}),children:[e("div",{className:"vm-select-input",onClick:F,ref:v,children:[e("div",{className:"vm-select-input-content",children:[!!(T!=null&&T.length)&&e(um,{values:T,onRemoveItem:O}),!w&&e("input",{value:C,type:"text",placeholder:a,onInput:H,onFocus:E,onBlur:P,ref:y,readOnly:u||!i})]}),r&&e("span",{className:"vm-text-field__label",children:r}),s&&t&&e("div",{className:"vm-select-input__icon",onClick:z(""),children:e(Ue,{})}),e("div",{className:I({"vm-select-input__icon":!0,"vm-select-input__icon_open":g}),children:e(Je,{})})]}),e(Ea,{label:r,value:k,options:n.map(G=>({value:G})),anchor:v,selected:T,minLength:1,fullWidth:!0,noOptionsText:o,onSelect:O,onOpenAutocomplete:_,onChangeWrapperRef:f})]})},gi=({data:t,isCompact:n})=>{const{isTableView:r,onChange:a}=di(),{hideDuplicates:o,onChange:s}=ui(),{hideStats:i,onChange:l}=Ba(),{format:c,onChange:d,onApply:m}=mi(),{groupByLabel:u,onChange:h}=ja(),p=vt(),v=M(()=>{if(!t||!t.length)return[];const y=t.flatMap(S=>Object.keys(S.metric));return Array.from(new Set(y))},[t]),b=y=>{const S=y?Dr.table:Dr.lines;a(S)},f=()=>{p({type:"SET_OPEN_SETTINGS",payload:!0})},g=[{label:"Table View",value:r,onChange:b,info:"If enabled, the legend will be displayed in a table format."},{label:"Hide Common Labels",value:o,onChange:s,info:"If enabled, hides labels that are the same for all series."},{label:"Hide Statistics",value:i,onChange:l,info:"If enabled, hides the display of min, median, and max values."}],_=n?j:V;return e("div",{className:I({"vm-legend-configs":!0,"vm-legend-configs_compact":n}),children:[g.map(({label:y,value:S,onChange:T,info:w})=>e(_,{title:w,children:e("div",{className:"vm-legend-configs-item vm-legend-configs-item_switch",children:[e("span",{className:"vm-legend-configs-item__label",children:y}),e(_e,{label:`${n?y:S?"Enabled":"Disabled"}`,value:S,onChange:T}),e("span",{className:"vm-legend-configs-item__info",children:w})]})},y)),n&&e(D,{size:"small",variant:"text",startIcon:e(Ze,{}),onClick:f,children:"Settings"}),!n&&e(V,{children:[e("div",{className:"vm-legend-configs-item",children:[e(ce,{label:"Custom Legend Format",placeholder:"{{label_name}}",value:c,onChange:d,onBlur:m,onEnter:m}),e("span",{className:"vm-legend-configs-item__info vm-legend-configs-item__info_input",children:"Customize legend labels with text and {{label_name}} placeholders."})]}),e("div",{className:"vm-legend-configs-item",children:[e(it,{label:"Group Legend By",value:u,list:[Ut,...v],placeholder:Ut,onChange:h,searchable:!0}),e("span",{className:"vm-legend-configs-item__info",children:"Choose a label to group the legend. By default, legends are grouped by query."})]})]})]})},hm=({labels:t,query:n,isAnomalyView:r,isPredefinedPanel:a,onChange:o})=>{const{groupByLabel:s}=ja(),i=dm({labels:t,query:n,groupByLabel:s});return e("div",{className:"vm-legend",children:[!a&&e(gi,{isCompact:!0}),e("div",{children:i.map(({group:l,items:c})=>e(cm,{labels:c,group:l,isAnomalyView:r,onChange:o},l))})]})},pm=({min:t,max:n,legendValue:r})=>{const[a,o]=N(0),[s,i]=N(""),[l,c]=N(""),[d,m]=N(""),u=M(()=>parseFloat(String((r==null?void 0:r.value)||0).replace("%","")),[r]);return A(()=>{o(u?(u-t)/(n-t)*100:0),i(u?`${u}%`:""),c(`${t}%`),m(`${n}%`)},[u,t,n]),e("div",{className:"vm-legend-heatmap__wrapper",children:e("div",{className:"vm-legend-heatmap",children:[e("div",{className:"vm-legend-heatmap-gradient",style:{background:`linear-gradient(to right, ${$a.join(", ")})`},children:!!u&&e("div",{className:"vm-legend-heatmap-gradient__value",style:{left:`${a}%`},children:e("span",{children:s})})}),e("div",{className:"vm-legend-heatmap__value",children:l}),e("div",{className:"vm-legend-heatmap__value",children:d})]})})},gm=({u:t,metrics:n,unit:r})=>{const[a,o]=N({left:0,top:0}),[s,i]=N([]),l=()=>{i([]),o({left:0,top:0})},c=h=>{const p=h.cursor.left||0,v=h.cursor.top||0;o({left:p,top:v})},d=W(()=>{var x;const{left:h,top:p}=a,v=st(t,["data",1,0],[])||[],b=t?t.posToVal(h,"x"):0,f=t?t.posToVal(p,"y"):0,g=v.findIndex((E,P)=>b>=E&&bE[0]===_)||[],w=v[g],C=U(w*1e3).tz().format(On),k=U(S*1e3).tz().format(On),L=((x=y==null?void 0:y.metric)==null?void 0:x.vmrange)||"";return{unit:r,point:a,u:t,id:`${L}_${C}`,dates:[C,k],value:`${T}%`,info:L,show:+T>0}},[t,a,n,r]),m=W(()=>{const h=d();h.show&&(s.find(p=>p.id===h.id)||i(p=>[...p,h]))},[d,s]),u=h=>{i(p=>p.filter(v=>v.id!==h))};return me("click",m),{stickyTooltips:s,handleUnStick:u,getTooltipProps:d,setCursor:c,resetTooltips:l}},vm=({data:t,metrics:n=[],period:r,unit:a,setPeriod:o,layoutSize:s,height:i,onChangeLegend:l})=>{const{isDarkTheme:c}=se(),d=q(null),[m,u]=N(),{xRange:h,setPlotScale:p}=Ua({period:r,setPeriod:o}),{onReadyChart:v,isPanning:b}=Va(p);qa({uPlotInst:m,xRange:h,setPlotScale:p});const{stickyTooltips:f,handleUnStick:g,getTooltipProps:_,setCursor:y,resetTooltips:S}=gm({u:m,metrics:n,unit:a}),T=M(()=>_(),[_]),w=()=>{const k=Ra([{}],a);return[...k,{scale:"y",stroke:k[0].stroke,font:k[0].font,size:ei,splits:n.map((L,x)=>x),values:n.map(L=>L.metric.vmrange)}]},C={...oi({width:s.width,height:i}),mode:2,series:[{},{paths:$d(),facets:[{scale:"x",auto:!0,sorted:1},{scale:"y",auto:!0}]}],axes:w(),scales:{x:{time:!0},y:{log:2,time:!1,range:(k,L,x)=>[L-1,x+1]}},hooks:{ready:[v],setCursor:[y],setSelect:[Ha(p)],destroy:[za]}};return A(()=>{S();const k=t[0]===null&&Array.isArray(t[1]);if(!d.current||!k)return;const L=new jt(C,t,d.current);return u(L),L.destroy},[d,t,c]),A(()=>{m&&(m.setSize({width:s.width||400,height:i||500}),m.redraw())},[i,s]),A(()=>{l(T)},[T]),e("div",{className:I({"vm-line-chart":!0,"vm-line-chart_panning":b}),style:{minWidth:`${s.width||400}px`,minHeight:`${i||500}px`},children:[e("div",{className:"vm-line-chart__u-plot",ref:d}),e(ci,{showTooltip:!!T.show,tooltipProps:T,stickyTooltips:f,handleUnStick:g})]})},vi=()=>{const[t,n]=N(null),[r,a]=N({width:0,height:0}),o=W(()=>{a({width:(t==null?void 0:t.offsetWidth)||0,height:(t==null?void 0:t.offsetHeight)||0})},[t==null?void 0:t.offsetHeight,t==null?void 0:t.offsetWidth]);return me("resize",o),A(o,[t==null?void 0:t.offsetHeight,t==null?void 0:t.offsetWidth]),[n,r]},fm={[ne.yhat]:"yhat",[ne.yhatLower]:"yhat_upper - yhat_lower",[ne.yhatUpper]:"yhat_upper - yhat_lower",[ne.anomaly]:"anomalies",[ne.training]:"training data",[ne.actual]:"y"},_m=({series:t})=>{const n=M(()=>{const r=t.reduce((o,s)=>{const i=Object.prototype.hasOwnProperty.call(s,"forecast"),l=s.forecast!==ne.yhatUpper,c=!o.find(d=>d.forecast===s.forecast);return i&&c&&l&&o.push(s),o},[]),a={...r[0],forecast:ne.training,color:Ht[ne.training]};return r.splice(1,0,a),r.map(o=>({...o,color:typeof o.stroke=="string"?o.stroke:Ht[o.forecast||ne.actual]}))},[t]);return e(V,{children:e("div",{className:"vm-legend-anomaly",children:n.filter(r=>r.forecast!==ne.training).map((r,a)=>{var o;return e("div",{className:"vm-legend-anomaly-item",children:[e("svg",{children:r.forecast===ne.anomaly?e("circle",{cx:"15",cy:"7",r:"4",fill:r.color,stroke:r.color,strokeWidth:"1.4"}):e("line",{x1:"0",y1:"7",x2:"30",y2:"7",stroke:r.color,strokeWidth:r.width||1,strokeDasharray:(o=r.dash)==null?void 0:o.join(",")})}),e("div",{className:"vm-legend-anomaly-item__title",children:fm[r.forecast||ne.actual]})]},`${a}_${r.forecast}`)})})})},ar=({data:t=[],period:n,customStep:r,query:a,yaxis:o,unit:s,showLegend:i=!0,setYaxisLimits:l,setPeriod:c,alias:d=[],fullWidth:m=!0,height:u,isHistogram:h,isAnomalyView:p,isPredefinedPanel:v,spanGaps:b})=>{var X;const f=vt(),{isMobile:g}=J(),{timezone:_}=ge(),y=M(()=>r||n.step||"1s",[n.step,r]),S=M(()=>Hd(t,h),[h,t]),[T,w]=N([[]]),[C,k]=N([]),[L,x]=N([]),[E,P]=N([]),[F,O]=N(null),H=M(()=>qd(S,E,d,p),[S,E,d,p]),z=R=>{const $=Pd(R,!h);l($)},Y=(R,$)=>{P(Bd({hideSeries:E,legend:R,metaKey:$,series:C,isAnomalyView:p}))},G=R=>{const $=R.slice(1,R.length),B=[],ee=[];$.forEach((ue,he)=>{ue.forEach((Ye,ye)=>{const Pe=ye*$.length+he;ee[Pe]=Ye})}),R[0].forEach(ue=>{const he=new Array($.length).fill(ue);B.push(...he)});const te=new Array(B.length).fill(0).map((ue,he)=>he%$.length);return[null,[B,te,ee]]},K=R=>p?js(R,["group","label"]).map(B=>{const ee=B.values[0];return{...ee,freeFormFields:{...ee.freeFormFields,__name__:""}}}):R;A(()=>{const R=[],$={},B=[],ee=[{}];S==null||S.forEach((ye,Pe)=>{const De=H(ye,Pe);ee.push(De),B.push(_o(De,ye.group));const Ve=$[ye.group]||[];for(const pe of ye.values)R.push(pe[0]),Ve.push(sn(pe[1]));$[ye.group]=Ve});const te=Id(R,y,n),ue=S.map(ye=>{const Pe=[],De=ye.values,Ve=De.length;let pe=0;for(const Ot of te){for(;peOt!==null),at=Math.abs(Sd(Dt)),wt=rr(Oa(Dt),nr(Dt)),Jt=Math.abs(wt[1]-wt[0]);return at>Jt*1e10&&!p?Pe.map(()=>at):Pe});ue.unshift(te),z($);const he=h?G(ue):ue;w(he),k(ee);const Ye=K(B);x(Ye),p&&P(Ye.map(ye=>ye.label||"").slice(1))},[S,_,h,y]),A(()=>{const R=[],$=[{}];S==null||S.forEach((B,ee)=>{const te=H(B,ee);$.push(te),R.push(_o(te,B.group))}),k($),x(K(R))},[E]);const[re,Q]=vi(),ie=((X=T[0])==null?void 0:X.length)>0;return A(()=>{const $=(()=>{var B;if(!h||!S[1])return!1;try{return(((B=T==null?void 0:T[1])==null?void 0:B[2])||[]).every(te=>te===null)}catch{return!1}})();f({type:"SET_IS_EMPTY_HISTOGRAM",payload:$})},[T,h]),e("div",{className:I({"vm-graph-view":!0,"vm-graph-view_full-width":m,"vm-graph-view_full-width_mobile":m&&g}),ref:re,children:[!h&&ie&&e(nm,{data:T,series:C,metrics:S,period:n,yaxis:o,unit:s,setPeriod:c,layoutSize:Q,height:u,isAnomalyView:p,spanGaps:b}),h&&e(vm,{data:T,metrics:S,period:n,unit:s,setPeriod:c,layoutSize:Q,height:u,onChangeLegend:O}),p&&i&&e(_m,{series:C}),!h&&i&&e(hm,{labels:L,query:a,isAnomalyView:p,onChange:Y,isPredefinedPanel:v}),h&&i&&e(pm,{min:o.limits.range[1][0]||0,max:o.limits.range[1][1]||0,legendValue:F})]})},bm=({yaxis:t,setYaxisLimits:n,toggleEnableLimits:r})=>{const{isMobile:a}=J(),o=M(()=>Object.keys(t.limits.range),[t.limits.range]),i=W(ln((c,d,m)=>{const u=t.limits.range;u[d][m]=+c,!(u[d][0]===u[d][1]||u[d][0]>u[d][1])&&n(u)},500),[t.limits.range]),l=(c,d)=>m=>{i(m,c,d)};return e("div",{className:I({"vm-axes-limits":!0,"vm-axes-limits_mobile":a}),children:[e("div",{className:"vm-graph-settings-row",children:[e("span",{className:"vm-graph-settings-row__label",children:"Fixed Y-axis limits"}),e(_e,{value:t.limits.enable,onChange:r,label:t.limits.enable?"Enabled":"Disabled",fullWidth:a})]}),e("span",{className:"vm-legend-configs-item__info",children:"Enables manual setting of min and max values for the y-axis."}),t.limits.enable&&e("div",{className:"vm-axes-limits-list",children:o.map(c=>e("div",{className:"vm-axes-limits-list__inputs",children:[e(ce,{label:`Min ${c}`,type:"number",disabled:!t.limits.enable,value:t.limits.range[c][0],onChange:l(c,0)}),e(ce,{label:`Max ${c}`,type:"number",disabled:!t.limits.enable,value:t.limits.range[c][1],onChange:l(c,1)})]},c))})]})},ym=({spanGaps:t,onChange:n})=>{const{isMobile:r}=J();return e("div",{className:"vm-graph-settings-row",children:[e("span",{className:"vm-graph-settings-row__label",children:"Connect null values"}),e(_e,{value:t,onChange:n,label:t?"Enabled":"Disabled",fullWidth:r}),e("span",{className:"vm-legend-configs-item__info",children:"Connects data points by skipping null values instead of creating gaps."})]})},fi=()=>{const[t,n]=oe(),r=Be();return{handleChange:(o,s)=>{o?t.delete("display_mode"):t.set("display_mode","lines"),n(t),r({type:"RUN_QUERY"}),s&&s()}}},wm=({onChange:t})=>{const{isMobile:n}=J(),{handleChange:r}=fi(),[a]=oe(),o=!a.get("display_mode");return e("div",{className:"vm-graph-settings-row",children:[e("span",{className:"vm-graph-settings-row__label",children:"Histogram mode"}),e(_e,{value:o,onChange:i=>{r(i,t)},label:o?"Enabled":"Disabled",fullWidth:n})]})},Co="Graph & Legend Settings",Qa=({data:t,yaxis:n,setYaxisLimits:r,toggleEnableLimits:a,spanGaps:o})=>{const{openSettings:s}=He(),i=vt(),l=q(null),c=q(null),d=Ma(t),{value:m,setTrue:u,setFalse:h}=ae(!1);return A(()=>{s&&(u(),i({type:"SET_OPEN_SETTINGS",payload:!1}))},[s]),e("div",{className:"vm-graph-settings",children:[e(j,{title:Co,children:e("div",{ref:c,children:e(D,{variant:"text",startIcon:e(Ze,{}),onClick:u,ariaLabel:"settings"})})}),m&&e(Me,{onClose:h,title:Co,className:"vm-graph-settings-modal",children:e("div",{className:"vm-graph-settings-body",ref:l,children:[e("div",{className:"vm-graph-settings-body-section",children:[e("h3",{className:"vm-graph-settings-body-section__title",children:"Graph Options"}),e("div",{className:"vm-graph-settings-body-section-content",children:[e(bm,{yaxis:n,setYaxisLimits:r,toggleEnableLimits:a}),e(ym,{spanGaps:o.value,onChange:o.onChange}),d&&e(wm,{onChange:h})]})]}),e("div",{className:"vm-graph-settings-body-section",children:[e("h3",{className:"vm-graph-settings-body-section__title",children:"Legend Options"}),e("div",{className:"vm-graph-settings-body-section-content",children:e(gi,{data:t})})]})]})})]})},_i=({isHistogram:t,graphData:n,controlsRef:r,isAnomalyView:a})=>{const{isMobile:o}=J(),{customStep:s,yaxis:i,spanGaps:l}=He(),{period:c}=ge(),{query:d}=xe(),m=Be(),u=vt(),h=g=>{u({type:"SET_YAXIS_LIMITS",payload:g})},p=()=>{u({type:"TOGGLE_ENABLE_YAXIS_LIMITS"})},v=g=>{u({type:"SET_SPAN_GAPS",payload:g})},b=({from:g,to:_})=>{m({type:"SET_PERIOD",payload:{from:g,to:_}})},f=e("div",{className:"vm-custom-panel-body-header__graph-controls",children:[e(Ca,{}),e(Qa,{data:n,yaxis:i,isHistogram:t,setYaxisLimits:h,toggleEnableLimits:p,spanGaps:{value:l,onChange:v}})]});return e(V,{children:[r.current&&pt(f,r.current),e(ar,{data:n,period:c,customStep:s,query:d,yaxis:i,setYaxisLimits:h,setPeriod:b,height:o?window.innerHeight*.5:500,isHistogram:t,isAnomalyView:a,spanGaps:l})]})},or=({data:t})=>{const n=Fe(),r=M(()=>JSON.stringify(t,null,2),[t]);return e("div",{className:"vm-json-view",children:[e("div",{className:"vm-json-view__copy",children:e(D,{variant:"outlined",onClick:async()=>{await n(r,"Formatted JSON has been copied")},children:"Copy JSON"})}),e("pre",{className:"vm-json-view__code",children:e("code",{children:r})})]})},Ya=t=>{const n={};return t.forEach(r=>Object.entries(r.metric).forEach(a=>n[a[0]]?n[a[0]].options.add(a[1]):n[a[0]]={options:new Set([a[1]])})),Object.entries(n).map(r=>({key:r[0],variations:r[1].options.size})).sort((r,a)=>r.variations-a.variations)},No=(t,n)=>M(()=>n?Ya(t).filter(a=>n.includes(a.key)):[],[t,n]),bi=({data:t,displayColumns:n})=>{const r=Fe(),{isMobile:a}=J(),{tableCompact:o}=je(),s=q(null),[i,l]=N(""),[c,d]=N("asc"),m=o?No([{group:0,metric:{Data:"Data"}}],["Data"]):No(t,n),u=y=>{const{__name__:S,...T}=y;return!S&&!Object.keys(T).length?"":S?`${S} ${JSON.stringify(T)}`:`${JSON.stringify(T)}`},p=new Set(t==null?void 0:t.map(y=>y.group)).size>1,v=M(()=>{const y=t==null?void 0:t.map(w=>({metadata:m.map(C=>o?Ir(w,"",p):w.metric[C.key]||"-"),value:w.value?w.value[1]:"-",values:w.values?w.values.map(([C,k])=>`${k} @${C}`):[],copyValue:u(w.metric)})),S=i==="Value",T=m.findIndex(w=>w.key===i);return!S&&T===-1?y:y.sort((w,C)=>{const k=S?Number(w.value):w.metadata[T],L=S?Number(C.value):C.metadata[T];return(c==="asc"?kL)?-1:1})},[m,t,i,c,o]),b=M(()=>v.some(y=>y.copyValue),[v]),f=y=>{d(S=>S==="asc"&&i===y?"desc":"asc"),l(y)},g=y=>()=>{f(y)},_=y=>async()=>{await r(y,"Row has been copied")};return v.length?e("div",{className:I({"vm-table-view":!0,"vm-table-view_mobile":a}),children:e("table",{className:"vm-table",ref:s,children:[e("thead",{className:"vm-table-header",children:e("tr",{className:"vm-table__row vm-table__row_header",children:[m.map((y,S)=>e("td",{className:"vm-table-cell vm-table-cell_header vm-table-cell_sort",onClick:g(y.key),children:e("div",{className:"vm-table-cell__content",children:[y.key,e("div",{className:I({"vm-table__sort-icon":!0,"vm-table__sort-icon_active":i===y.key,"vm-table__sort-icon_desc":c==="desc"&&i===y.key}),children:e(Je,{})})]})},S)),e("td",{className:"vm-table-cell vm-table-cell_header vm-table-cell_right vm-table-cell_sort",onClick:g("Value"),children:e("div",{className:"vm-table-cell__content",children:[e("div",{className:I({"vm-table__sort-icon":!0,"vm-table__sort-icon_active":i==="Value","vm-table__sort-icon_desc":c==="desc"}),children:e(Je,{})}),"Value"]})}),b&&e("td",{className:"vm-table-cell vm-table-cell_header"})]})}),e("tbody",{className:"vm-table-body",children:v.map((y,S)=>e("tr",{className:"vm-table__row",children:[y.metadata.map((T,w)=>e("td",{className:I({"vm-table-cell vm-table-cell_no-wrap":!0,"vm-table-cell_gray":v[S-1]&&v[S-1].metadata[w]===T}),children:T},w)),e("td",{className:"vm-table-cell vm-table-cell_right vm-table-cell_no-wrap",children:y.values.length?y.values.map(T=>e("p",{children:T},T)):y.value}),b&&e("td",{className:"vm-table-cell vm-table-cell_right",children:y.copyValue&&e("div",{className:"vm-table-cell__content",children:e(j,{title:"Copy row",children:e(D,{variant:"text",color:"gray",size:"small",startIcon:e(Xe,{}),onClick:_(y.copyValue),ariaLabel:"copy row"})})})})]},S))})]})}):e(le,{variant:"warning",children:"No data to show"})},Or=({checked:t=!1,disabled:n=!1,label:r,color:a="secondary",onChange:o})=>{const s=()=>{n||o(!t)},i=I({"vm-checkbox":!0,"vm-checkbox_disabled":n,"vm-checkbox_active":t,[`vm-checkbox_${a}_active`]:t,[`vm-checkbox_${a}`]:a});return e("div",{className:i,onClick:s,children:[e("div",{className:"vm-checkbox-track",children:e("div",{className:"vm-checkbox-track__thumb",children:e(Wn,{})})}),r&&e("span",{className:"vm-checkbox__label",children:r})]})},_r="Table settings",Ga=({columns:t,selectedColumns:n=[],tableCompact:r,onChangeColumns:a,toggleTableCompact:o})=>{const[s,i]=oe(),l=q(null),{value:c,toggle:d,setFalse:m}=ae(!1),[u,h]=N(""),[p,v]=N(-1),b=M(()=>n.filter(k=>!t.includes(k)),[t,n]),f=M(()=>{const k=b.concat(t);return(u?k.filter(x=>x.includes(u)):k).sort((x,E)=>x.localeCompare(E))},[t,b,u]),g=M(()=>f.every(k=>n.includes(k)),[n,f]),_=k=>{a(k);const L=new URLSearchParams(s.toString());k.length===t.length?L.delete("columns"):L.set("columns",k.map(encodeURIComponent).join(",")),i(L)},y=k=>{const L=n.includes(k)?n.filter(x=>x!==k):[...n,k];_(L)},S=()=>{_(g?n.filter(k=>!f.includes(k)):f)},T=k=>()=>{y(k)},w=()=>{v(-1)},C=k=>{const L=k.key==="ArrowUp",x=k.key==="ArrowDown",E=k.key==="Enter";(x||L||E)&&k.preventDefault(),x?v(P=>P+1>f.length-1?P:P+1):L?v(P=>P-1<0?P:P-1):E&&y(f[p])};return A(()=>{Zn(t,n)||s.has("columns")||a(t)},[t]),A(()=>{if(!s.has("columns"))return;const x=(s.get("columns")||"").split(",").map(decodeURIComponent).filter(Boolean);a(x)},[]),e("div",{className:"vm-table-settings",children:[e(j,{title:_r,children:e("div",{ref:l,children:e(D,{variant:"text",startIcon:e(Ze,{}),onClick:d,ariaLabel:_r})})}),c&&e(Me,{title:_r,className:"vm-table-settings-modal",onClose:m,children:[e("div",{className:"vm-table-settings-modal-section",children:[e("div",{className:"vm-table-settings-modal-section__title",children:"Customize columns"}),e("div",{className:"vm-table-settings-modal-columns",children:[e("div",{className:"vm-table-settings-modal-columns__search",children:e(ce,{placeholder:"Search columns",startIcon:e(Cs,{}),value:u,onChange:h,onBlur:w,onKeyDown:C,type:"search"})}),e("div",{className:"vm-table-settings-modal-columns-list",children:[!!f.length&&e("div",{className:"vm-table-settings-modal-columns-list__item vm-table-settings-modal-columns-list__item_all",children:e(Or,{checked:g,onChange:S,label:g?"Uncheck all":"Check all",disabled:r})}),!f.length&&e("div",{className:"vm-table-settings-modal-columns-no-found",children:e("p",{className:"vm-table-settings-modal-columns-no-found__info",children:"No columns found."})}),f.map((k,L)=>e("div",{className:I({"vm-table-settings-modal-columns-list__item":!0,"vm-table-settings-modal-columns-list__item_focus":L===p,"vm-table-settings-modal-columns-list__item_custom":b.includes(k)}),children:e(Or,{checked:n.includes(k),onChange:T(k),label:k,disabled:r})},k))]})]})]}),o&&r!==void 0&&e("div",{className:"vm-table-settings-modal-section",children:[e("div",{className:"vm-table-settings-modal-section__title",children:"Table view"}),e("div",{className:"vm-table-settings-modal-columns-list__item",children:e(_e,{label:"Compact view",value:r,onChange:o})})]})]})]})},Cm=({liveData:t,controlsRef:n})=>{const{tableCompact:r}=je(),a=Gt(),[o,s]=N(),i=M(()=>Ya(t||[]).map(d=>d.key),[t]),c=e(Ga,{columns:i,selectedColumns:o,onChangeColumns:s,tableCompact:r,toggleTableCompact:()=>{a({type:"TOGGLE_TABLE_COMPACT"})}});return e(V,{children:[n.current&&pt(c,n.current),e(bi,{data:t,displayColumns:o})]})},yi=({graphData:t,liveData:n,isHistogram:r,displayType:a,controlsRef:o})=>a===Ne.code&&n?e(or,{data:n}):a===Ne.table&&n?e(Cm,{liveData:n,controlsRef:o}):a===Ne.chart&&t?e(_i,{graphData:t,isHistogram:r,controlsRef:o}):null,Nm=e(V,{children:[e("p",{children:"Filename - specify the name for your report file."}),e("p",{children:["Default format: ",e("code",{children:["vmui_report_$",Wr,".json"]}),"."]}),e("p",{children:"This name will be used when saving your report on your device."})]}),Sm=e(V,{children:[e("p",{children:["Title - specify the title that will be displayed on the ",e(Bn,{to:Z.queryAnalyzer,target:"_blank",rel:"noreferrer",className:"vm-link vm-link_underlined",children:gt[Z.queryAnalyzer].title})," page."]}),e("p",{children:"This helps identify your report in the interface."})]}),km=e(V,{children:[e("p",{children:"Comment (optional) - add a comment to your report."}),e("p",{children:"This can be any additional information that will be useful when reviewing the report later."})]}),Tm=e(V,{children:[e("p",{children:"Query trace - enable this option to include a query trace in your report."}),e("p",{children:"This will assist in analyzing and diagnosing the query processing."})]}),Lm=e(V,{children:[e("p",{children:"Generate Report - click this button to generate and save your report. "}),e("p",{children:["After creation, the report can be downloaded and examined on the ",e(Bn,{to:Z.queryAnalyzer,target:"_blank",rel:"noreferrer",className:"vm-link vm-link_underlined",children:gt[Z.queryAnalyzer].title})," page."]})]}),Am=[Nm,Sm,km,Tm,Lm],wi=t=>{try{return JSON.parse(t)}catch{return null}},Em=[{title:"Write",value:!1},{title:"Preview",value:!0}],xm=({value:t,onChange:n})=>{const{value:r,setTrue:a,setFalse:o}=ae(!1);return e("div",{className:"vm-markdown-editor",children:[e("div",{className:"vm-markdown-editor-header",children:[e("div",{className:"vm-markdown-editor-header-tabs",children:Em.map(({title:s,value:i})=>e("div",{className:I({"vm-markdown-editor-header-tabs__tab":!0,"vm-markdown-editor-header-tabs__tab_active":r===i}),onClick:i?a:o,children:s},s))}),e("span",{className:"vm-markdown-editor-header__info",children:"Markdown is supported"})]}),r?e("div",{className:"vm-markdown-editor-preview vm-markdown",dangerouslySetInnerHTML:{__html:Bt(t)}}):e(ce,{type:"textarea",value:t,onChange:n})]})};var Ci=(t=>(t[t.QUERY_DATA=0]="QUERY_DATA",t[t.RAW_DATA=1]="RAW_DATA",t))(Ci||{});const Mm=t=>{switch(t){case 1:return"Raw report";default:return"Report"}},Im=t=>{const n=U().utc().format(Wr);return`vmui_${t.toLowerCase().replace(/ /g,"_")}_${n}`},Ni=({fetchUrl:t,reportType:n=0})=>{const{query:r}=xe(),a=Mm(n),o=Im(a),[s,i]=N(a),[l,c]=N(o),[d,m]=N(""),[u,h]=N(n===0),[p,v]=N(),[b,f]=N(!1),g=q(null),_=q(null),y=q(null),S=q(null),T=q(null),w=[_,g,y,S,T],[C,k]=N(0),{value:L,toggle:x,setFalse:E}=ae(!1),{value:P,toggle:F,setFalse:O}=ae(!1),H=W(()=>{if(t)try{return t.map((R,$)=>{const B=new URL(R);return u?B.searchParams.set("trace","1"):B.searchParams.delete("trace"),{id:$,url:B}})}catch(R){v(String(R))}},[t,u]),z=W(R=>{const $=JSON.stringify(R,null,2);Pa($,`${l||o}.json`),E()},[l]),Y=({id:R,url:$,comment:B,title:ee})=>({id:R,title:ee||a,comment:B,endpoint:nl($.pathname)||"",params:Object.fromEntries($.searchParams)}),G=async(R,$)=>{const B=[],ee=await R.text();return R.ok?ee.split(` -`).filter(ue=>ue).forEach(ue=>{const he=wi(ue);he&&B.push({metric:he.metric,values:he.values.map((Ye,ye)=>[he.timestamps[ye]/1e3,Ye])})}):v(String(ee)),{data:{result:B,resultType:"matrix"},vmui:Y($)}},K=async(R,$)=>{const B=await R.json();if(R.ok)return B.vmui=Y($),B;{const ee=B.errorType?`${B.errorType}\r -`:"";v(`${ee}${(B==null?void 0:B.error)||(B==null?void 0:B.message)||"unknown error"}`)}},re=async(R,$)=>{switch(n){case 1:return await G(R,$);default:return await K(R,$)}},Q=W(async()=>{const R=H();if(!R){v($=>$||Ce.validQuery);return}v(""),f(!0);try{const $=[];for await(const B of R){if(!B)continue;const{url:ee,id:te}=B,ue=await fetch(ee),he=await re(ue,{id:te,url:ee,comment:d,title:s});$.push(he)}$.length&&z($)}catch($){$ instanceof Error&&$.name!=="AbortError"&&v(`${$.name}: ${$.message}`)}finally{f(!1)}},[H,d,z,r,s]),ie=R=>()=>{const $=B=>{var te;const ee=B+R;return(te=w[ee])!=null&&te.current?ee:$(ee)};k($)};return A(()=>{v(""),c(o),m("")},[L]),A(()=>{k(0)},[P]),e(V,{children:[e(j,{title:"Export query",children:e(D,{variant:"text",startIcon:e(fn,{}),onClick:x,ariaLabel:"export query"})}),L&&e(Me,{title:"Export query",onClose:E,isOpen:L,children:e("div",{className:"vm-download-report",children:[e("div",{className:"vm-download-report-settings",children:[e("div",{ref:_,children:[e("div",{className:"vm-download-report-settings__title",children:"Filename"}),e(ce,{value:l,onChange:c})]}),e("div",{ref:g,children:[e("div",{className:"vm-download-report-settings__title",children:"Report title"}),e(ce,{value:s,onChange:i})]}),e("div",{ref:y,children:[e("div",{className:"vm-download-report-settings__title",children:"Comment"}),e(xm,{value:d,onChange:m})]}),n===0&&e(V,{children:[e("div",{ref:S,children:e(Or,{checked:u,onChange:h,label:"Include query trace"})}),e(le,{variant:"info",children:["If confused with the query results, try viewing the raw samples for selected series in ",e(()=>e(Bn,{className:"vm-link vm-link_underlined vm-link_colored",to:Z.rawQuery,children:"Raw Query"}),{})," tab."]})]})]}),p&&e(le,{variant:"error",children:p}),e("div",{className:"vm-download-report__buttons",children:[e(D,{variant:"text",onClick:F,children:"Help"}),e("div",{ref:T,children:e(D,{onClick:Q,disabled:b,children:b?"Loading data...":"Generate Report"})})]}),e(Ie,{open:P,buttonRef:w[C],placement:"top-left",variant:"dark",onClose:O,children:e("div",{className:"vm-download-report-helper",children:[e("div",{className:"vm-download-report-helper__description",children:Am[C]}),e("div",{className:"vm-download-report-helper__buttons",children:[C!==0&&e(D,{onClick:ie(-1),size:"small",color:"white",children:"Prev"}),e(D,{onClick:C===w.length-1?O:ie(1),size:"small",color:"white",variant:"text",children:C===w.length-1?"Close":"Next"})]})]})})]})})]})},Si=()=>{const{isEmptyHistogram:t}=He(),{handleChange:n}=fi();return t?e(le,{variant:"warning",children:e("div",{className:"vm-warning-heatmap-to-line",children:[e("p",{className:"vm-warning-heatmap-to-line__text",children:'The expression cannot be displayed as a heatmap. To make the graph work, disable the heatmap in the "Graph settings" or modify the expression.'}),e(D,{size:"small",color:"primary",variant:"text",onClick:()=>n(!1),children:"Switch to line chart"})]})}):null},ki=()=>{Ia();const{isMobile:t}=J(),{displayType:n}=je(),{query:r}=xe(),{customStep:a}=He(),o=vt(),[s,i]=N([]),[l,c]=N(!r[0]),[d,m]=N(!1),u=q(null),{fetchUrl:h,isLoading:p,liveData:v,graphData:b,error:f,queryErrors:g,setQueryErrors:_,queryStats:y,warning:S,traces:T,isHistogram:w,abortFetch:C}=Xn({visible:!0,customStep:a,hideQuery:s,showAllSeries:d}),k=!(v!=null&&v.length)&&n!==Ne.chart,L=!l&&f,x=P=>{i(P)},E=()=>{c(!1)};return A(()=>{o({type:"SET_IS_HISTOGRAM",payload:w})},[b]),e("div",{className:I({"vm-custom-panel":!0,"vm-custom-panel_mobile":t}),children:[e(xa,{queryErrors:l?[]:g,setQueryErrors:_,setHideError:c,stats:y,isLoading:p,onHideQuery:x,onRunQuery:E,abortFetch:C,hideButtons:{reduceMemUsage:!0}}),e(Nd,{traces:T,displayType:n}),L&&e(le,{variant:"error",children:f}),k&&e(le,{variant:"info",children:e(wd,{})}),e(Si,{}),S&&e(tr,{warning:S,query:r,onChange:m}),e("div",{className:I({"vm-custom-panel-body":!0,"vm-custom-panel-body_mobile":t,"vm-block":!0,"vm-block_mobile":t}),children:[p&&e(er,{}),e("div",{className:"vm-custom-panel-body-header",ref:u,children:[e("div",{className:"vm-custom-panel-body-header__tabs",children:e(Es,{})}),(b||v)&&e(Ni,{fetchUrl:h})]}),e(yi,{graphData:b,liveData:v,isHistogram:w,displayType:n,controlsRef:u})]})]})},Pm=({title:t,description:n,unit:r,expr:a,showLegend:o,filename:s,alias:i})=>{const{isMobile:l}=J(),{period:c}=ge(),{customStep:d}=He(),m=Be(),u=q(null),[h,p]=N(!1),[v,b]=N(!1),[f,g]=N({limits:{enable:!1,range:{1:[0,0]}}}),_=M(()=>Array.isArray(a)&&a.every(E=>E),[a]),{isLoading:y,graphData:S,error:T,warning:w}=Xn({predefinedQuery:_?a:[],display:Ne.chart,visible:h,customStep:d}),C=E=>{const P={...f};P.limits.range=E,g(P)},k=()=>{const E={...f};E.limits.enable=!E.limits.enable,g(E)},L=({from:E,to:P})=>{m({type:"SET_PERIOD",payload:{from:E,to:P}})};return A(()=>{const E=new IntersectionObserver(P=>{P.forEach(F=>p(F.isIntersecting))},{threshold:.1});return u.current&&E.observe(u.current),()=>{u.current&&E.unobserve(u.current)}},[u]),_?e("div",{className:"vm-predefined-panel",ref:u,children:[e("div",{className:"vm-predefined-panel-header",children:[e(j,{title:e(()=>e("div",{className:"vm-predefined-panel-header__description vm-default-styles",children:[n&&e(V,{children:[e("div",{children:[e("span",{children:"Description:"}),e("div",{dangerouslySetInnerHTML:{__html:Bt(n)}})]}),e("hr",{})]}),e("div",{children:[e("span",{children:"Queries:"}),e("div",{children:a.map((E,P)=>e("div",{children:E},`${P}_${E}`))})]})]}),{}),children:e("div",{className:"vm-predefined-panel-header__info",children:e(mt,{})})}),e("h3",{className:"vm-predefined-panel-header__title",children:t||""}),e(Qa,{data:S||[],yaxis:f,setYaxisLimits:C,toggleEnableLimits:k,spanGaps:{value:v,onChange:b}})]}),e("div",{className:"vm-predefined-panel-body",children:[y&&e(Qe,{}),T&&e(le,{variant:"error",children:T}),w&&e(le,{variant:"warning",children:w}),S&&e(ar,{isPredefinedPanel:!0,data:S,period:c,customStep:d,query:a,yaxis:f,unit:r,alias:i,showLegend:o,setYaxisLimits:C,setPeriod:L,fullWidth:!1,height:l?window.innerHeight*.5:500,spanGaps:v})]})]}):e(le,{variant:"error",children:[e("code",{children:'"expr"'})," not found. Check the configuration file ",e("b",{children:s}),"."]})},Dm=({index:t,title:n,panels:r,filename:a})=>{const o=Pt(),s=M(()=>o.width/12,[o]),[i,l]=N(!t),[c,d]=N([]);A(()=>{d(r&&r.map(_=>_.width||12))},[r]);const[m,u]=N({start:0,target:0,enable:!1}),h=W(_=>{if(!m.enable)return;const{start:y}=m,S=Math.ceil((y-_.clientX)/s);if(Math.abs(S)>=12)return;const T=c.map((w,C)=>w-(C===m.target?S:0));d(T)},[m,s]),p=(_,y)=>{u({start:_.clientX,target:y,enable:!0})},v=W(()=>{u({...m,enable:!1})},[m]),b=_=>l(_),f=_=>y=>{p(y,_)};return me("mousemove",h),me("mouseup",v),e("div",{className:"vm-predefined-dashboard",children:e(Kn,{defaultExpanded:i,onChange:b,title:e(()=>e("div",{className:I({"vm-predefined-dashboard-header":!0,"vm-predefined-dashboard-header_open":i}),children:[(n||a)&&e("span",{className:"vm-predefined-dashboard-header__title",children:n||`${t+1}. ${a}`}),r&&e("span",{className:"vm-predefined-dashboard-header__count",children:["(",r.length," panels)"]})]}),{}),children:e("div",{className:"vm-predefined-dashboard-panels",children:Array.isArray(r)&&r.length?r.map((_,y)=>e("div",{className:"vm-predefined-dashboard-panels-panel vm-block vm-block_empty-padding",style:{gridColumn:`span ${c[y]}`},children:[e(Pm,{title:_.title,description:_.description,unit:_.unit,expr:_.expr,alias:_.alias,filename:a,showLegend:_.showLegend}),e("button",{className:"vm-predefined-dashboard-panels-panel__resizer",onMouseDown:f(y),"aria-label":"resize the panel"})]},y)):e("div",{className:"vm-predefined-dashboard-panels-panel__alert",children:e(le,{variant:"error",children:[e("code",{children:'"panels"'})," not found. Check the configuration file ",e("b",{children:a}),"."]})})})})})};function Om(t,n){return Object.fromEntries(Object.entries(t).filter(n))}function Ti(t){return Om(t,n=>!!n[1]||typeof n[1]=="number")}function Rm(t){return Object.keys(t).length===0}const $m=()=>{const{duration:t,relativeTime:n,period:{date:r}}=ge(),{customStep:a}=He(),{setSearchParamsFromKeys:o}=rt(),s=()=>{const i=Ti({"g0.range_input":t,"g0.end_input":r,"g0.step_input":a,"g0.relative_time":n});o(i)};A(s,[t,n,r,a]),A(s,[])},Fm=()=>{$m();const{isMobile:t}=J(),{dashboardsSettings:n,dashboardsLoading:r,dashboardsError:a}=Ms(),[o,s]=N(0),i=M(()=>n.map((p,v)=>({label:p.title||"",value:v})),[n]),l=M(()=>n[o]||{},[n,o]),c=M(()=>l==null?void 0:l.rows,[l]),d=M(()=>l.title||l.filename||"",[l]),m=M(()=>Array.isArray(c)&&!!c.length,[c]),u=p=>{s(p)},h=p=>()=>{u(p)};return e("div",{className:"vm-predefined-panels",children:[r&&e(Qe,{}),!n.length&&a&&e(le,{variant:"error",children:a}),!n.length&&e(le,{variant:"info",children:"Dashboards not found"}),i.length>1&&e("div",{className:I({"vm-predefined-panels-tabs":!0,"vm-predefined-panels-tabs_mobile":t}),children:i.map(p=>e("div",{className:I({"vm-predefined-panels-tabs__tab":!0,"vm-predefined-panels-tabs__tab_active":p.value==o}),onClick:h(p.value),children:p.label},p.value))}),e("div",{className:"vm-predefined-panels__dashboards",children:[m&&c.map((p,v)=>e(Dm,{index:v,filename:d,title:p.title,panels:p.panels},`${o}_${v}`)),!!n.length&&!m&&e(le,{variant:"error",children:[e("code",{children:'"rows"'})," not found. Check the configuration file ",e("b",{children:d}),"."]})]})]})},br=(t,n)=>{const r=n.match?"&match[]="+encodeURIComponent(n.match):"",a=n.focusLabel?"&focusLabel="+encodeURIComponent(n.focusLabel):"";return`${t}/api/v1/status/tsdb?topN=${n.topN}&date=${n.date}${r}${a}`},zm=(t,n)=>{const r=new URLSearchParams(Object.entries(n).filter(([a,o])=>o!=null)).toString();return`${t}/api/v1/status/metric_names_stats?${r}`},bn={id:"action",label:"",modifiers:["action"]},yn={id:"diff",label:"1d",info:"Shows the absolute difference compared to the previous day.",sortable:!0,modifiers:["compact"]},wn={id:"diffPercent",label:"1d %",info:"Shows the percentage difference compared to the previous day.",sortable:!0,modifiers:["compact"]},sr={id:"value",label:"Number of series",sortable:!0,modifiers:["compact"]},Hm=[{id:"name",label:"Metric name",sortable:!0},sr,{id:"requestsCount",label:"Requests count",sortable:!0,modifiers:["compact"],info:"The number of times this metric was queried since stats collection began."},{id:"lastRequestTimestamp",label:"Last request",sortable:!0,modifiers:["compact"],info:"The last time this metric was used in a query since stats collection began."},yn,wn,{id:"percentage",label:"Share in total",info:"Shows the share of a metric to the total number of series"},bn],Vm=[{id:"name",label:"Label name",sortable:!0},sr,yn,wn,{id:"percentage",label:"Share in total",info:"Shows the share of the label to the total number of series"},bn],qm=[{id:"name",label:"Label value",sortable:!0},sr,yn,wn,{id:"percentage",label:"Share in total"},bn],Um=[{id:"name",label:"Label=value pair",sortable:!0},sr,yn,wn,{id:"percentage",label:"Share in total",info:"Shows the share of the label value pair to the total number of series"},bn],Bm=[{id:"name",label:"Label name",sortable:!0},{id:"value",label:"Number of unique values",sortable:!0,modifiers:["compact"]},yn,wn,bn];class jm{constructor(){we(this,"tsdbStatus");we(this,"metricNameStats");we(this,"tabsNames");we(this,"isPrometheus");this.tsdbStatus=this.defaultTSDBStatus,this.metricNameStats=this.defaultMetricNameStats,this.tabsNames=["table","graph"],this.isPrometheus=!1,this.getDefaultState=this.getDefaultState.bind(this)}set tsdbStatusData(n){this.isPrometheus=!!(n!=null&&n.headStats),this.tsdbStatus=n}set metricNameStatsData(n){this.metricNameStats=n}get tsdbStatusData(){return this.tsdbStatus}get metricNameStatsData(){return this.metricNameStats}get defaultTSDBStatus(){return{totalSeries:0,totalSeriesPrev:0,totalSeriesByAll:0,totalLabelValuePairs:0,seriesCountByMetricName:[],seriesCountByLabelName:[],seriesCountByFocusLabelValue:[],seriesCountByLabelValuePair:[],labelValueCountByLabelName:[]}}get defaultMetricNameStats(){return{statsCollectedSince:0,statsCollectedRecordsTotal:0,trackerMemoryMaxSizeBytes:0,trackerCurrentMemoryUsageBytes:0}}get isPrometheusData(){return this.isPrometheus}keys(n,r){const a=n&&/__name__=".+"/.test(n),o=n&&/{.+=".+"}/g.test(n),s=n&&/__name__=".+", .+!=""/g.test(n);let i=[];return r||s?i=i.concat("seriesCountByFocusLabelValue"):a?i=i.concat("labelValueCountByLabelName"):o?i=i.concat("seriesCountByMetricName","seriesCountByLabelName"):i=i.concat("seriesCountByMetricName","seriesCountByLabelName","seriesCountByLabelValuePair","labelValueCountByLabelName"),i}getDefaultState(n,r){return this.keys(n,r).reduce((a,o)=>({...a,tabs:{...a.tabs,[o]:this.tabsNames},containerRefs:{...a.containerRefs,[o]:q(null)}}),{tabs:{},containerRefs:{}})}sectionsTitles(n){return{seriesCountByMetricName:"Metric names with the highest number of series",seriesCountByLabelName:"Labels with the highest number of series",seriesCountByFocusLabelValue:`Values for "${n}" label with the highest number of series`,seriesCountByLabelValuePair:"Label=value pairs with the highest number of series",labelValueCountByLabelName:"Labels with the highest number of unique values"}}get sectionsTips(){return{seriesCountByMetricName:` -

- This table returns a list of metrics with the highest cardinality. - The cardinality of a metric is the number of time series associated with that metric, - where each time series is defined as a unique combination of key-value label pairs. -

-

- When looking to reduce the number of active series in your data source, - you can start by inspecting individual metrics with high cardinality - (i.e. that have lots of active time series associated with them), - since that single metric contributes a large fraction of the series that make up your total series count. -

`,seriesCountByLabelName:` -

- This table returns a list of the labels with the highest number of series. -

-

- Use this table to identify labels that are storing dimensions with high cardinality - (many different label values). -

-

- It is recommended to choose labels such that they have a finite set of values, - since every unique combination of key-value label pairs creates a new time series - and therefore can dramatically increase the number of time series in your system. -

`,seriesCountByFocusLabelValue:` -

- This table returns a list of unique label values per selected label. -

-

- Use this table to identify label values that are storing per each selected series. -

`,labelValueCountByLabelName:` -

- This table returns a list of labels with the highest number of the unique values. -

- `,seriesCountByLabelValuePair:` -

- This table returns a list of the label values pairs with the highest number of series. -

-

- Use this table to identify unique label values pairs. This helps to identify same labels - is applied to count timeseries in your system, since every unique combination of key-value label pairs - creates a new time series and therefore can dramatically increase the number of time series in your system -

`}}get tablesHeaders(){return{seriesCountByMetricName:Hm,seriesCountByLabelName:Vm,seriesCountByFocusLabelValue:qm,seriesCountByLabelValuePair:Um,labelValueCountByLabelName:Bm}}totalSeries(n,r=!1){return n==="labelValueCountByLabelName"?-1:r?this.tsdbStatus.totalSeriesPrev:this.tsdbStatus.totalSeries}}const Qm=()=>{const t=new jm,[n]=oe(),r=n.get("match"),a=n.get("focusLabel"),o=+(n.get("topN")||10),s=n.get("date")||U().tz().format(kt),i=qt(s),l=q(),{serverUrl:c}=se(),[d,m]=N(!1),[u,h]=N(),[p,v]=N(t.defaultTSDBStatus),[b,f]=N(t.defaultMetricNameStats),[g,_]=N(!1),y=async C=>{const k=await fetch(C),L=await k.json();if(k.ok)return L;console.error(`Error fetching ${C}:`,L);const x=L.errorType||Ce.unknownType,E=(L==null?void 0:L.error)||(L==null?void 0:L.message)||"see console for more details",P=[x,E].join(`\r -`);throw new Error(P)},S=(C,k)=>{Object.keys(C).forEach(L=>{const x=L,E=C[x],P=k[x];Array.isArray(E)&&Array.isArray(P)&&E.forEach(F=>{var Y;const O=(Y=P.find(G=>G.name===F.name))==null?void 0:Y.value,H=O?F.value-O:0,z=O?H/O*100:0;F.diff=H,F.diffPercent=z,F.valuePrev=O||0})})},T=async C=>{var E,P,F,O,H,z,Y,G,K,re;if(!c)return;h(""),m(!0),v(t.defaultTSDBStatus);const k={...C,date:C.date,topN:0,match:"",focusLabel:""},L={...C,date:U(C.date).subtract(1,"day").format(kt)},x=[br(c,C),br(c,L)];i!==s&&(C.match||C.focusLabel)&&x.push(br(c,k));try{const[Q,ie,X]=await Promise.all(x.map(y)),R={...ie.data},{data:$}=X||l.current||Q;l.current={data:$};const B={...Q.data,totalSeries:((E=Q.data)==null?void 0:E.totalSeries)||((F=(P=Q.data)==null?void 0:P.headStats)==null?void 0:F.numSeries)||0,totalLabelValuePairs:((O=Q.data)==null?void 0:O.totalLabelValuePairs)||((z=(H=Q.data)==null?void 0:H.headStats)==null?void 0:z.numLabelValuePairs)||0,seriesCountByLabelName:((Y=Q.data)==null?void 0:Y.seriesCountByLabelName)||[],seriesCountByFocusLabelValue:((G=Q.data)==null?void 0:G.seriesCountByFocusLabelValue)||[],totalSeriesByAll:($==null?void 0:$.totalSeries)||((K=$==null?void 0:$.headStats)==null?void 0:K.numSeries)||p.totalSeriesByAll||0,totalSeriesPrev:(R==null?void 0:R.totalSeries)||((re=R==null?void 0:R.headStats)==null?void 0:re.numSeries)||0},ee=r==null?void 0:r.replace(/[{}"]/g,"");B.seriesCountByLabelValuePair=B.seriesCountByLabelValuePair.filter(te=>te.name!==ee),S(B,R),v(B),m(!1)}catch(Q){m(!1),Q instanceof Error&&h(`${Q.name}: ${Q.message}`)}},w=async()=>{if(!c)return;h(""),m(!0);const C=zm(c,{limit:1});try{const k=await y(C);f(k),m(!1)}catch(k){m(!1),f(t.defaultMetricNameStats),console.error(k)}};return A(()=>{T({topN:o,match:r,date:s,focusLabel:a})},[c,r,a,o,s]),A(()=>{w()},[c]),A(()=>{u&&(v(t.defaultTSDBStatus),m(!1))},[u]),A(()=>{const C=dn(c);_(!!C)},[c]),t.tsdbStatusData=p,t.metricNameStatsData=b,{isLoading:d,appConfigurator:t,error:u,isCluster:g}},Ym={seriesCountByMetricName:({query:t})=>yr("__name__",t),seriesCountByLabelName:({query:t})=>`{${t}!=""}`,seriesCountByFocusLabelValue:({query:t,focusLabel:n})=>yr(n,t),seriesCountByLabelValuePair:({query:t})=>{const n=t.split("="),r=n[0],a=n.slice(1).join("=");return yr(r,a)},labelValueCountByLabelName:({query:t,match:n})=>n===""?`{${t}!=""}`:`${n.replace("}","")}, ${t}!=""}`},yr=(t,n)=>t?"{"+t+"="+JSON.stringify(n)+"}":"",Gm=({metricNameStats:t})=>{const{statsCollectedSince:n,statsCollectedRecordsTotal:r=0,trackerMemoryMaxSizeBytes:a=0,trackerCurrentMemoryUsageBytes:o=0}=t,s=n?U.unix(n).format(qe):" - ",i=a?`${(o/a*100).toFixed(2)}%`:" - ",l=r.toLocaleString("en-US");return e("div",{className:"vm-cardinality-totals-card",children:[e("h4",{className:"vm-cardinality-totals-card__title",children:[e(j,{placement:"bottom-left",title:e("div",{className:"vm-cardinality-totals-card__tooltip",children:n?e(V,{children:[e("p",{children:["Total entries in cache since ",s]}),e("p",{children:["Cache utilization: ",i]})]}):e(V,{children:[e("p",{children:"Metric names tracker is likely disabled."}),e("p",{children:"No data available. See documentation for enabling the metric names tracker."})]})}),children:e("div",{className:"vm-cardinality-totals-card__info-icon",children:e(un,{})})}),"Total metric names"]}),e("span",{className:"vm-cardinality-totals-card__value",children:l}),e("span",{className:"vm-cardinality-totals-card__link",children:e(Te,{href:"https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#track-ingested-metrics-usage",children:"Docs ↗"})})]})},Wm=({totalSeries:t=0,totalSeriesPrev:n=0,totalSeriesAll:r=0,seriesCountByMetricName:a=[],metricNameStats:o,isPrometheus:s})=>{var b;const{isMobile:i}=J(),[l]=oe(),c=l.get("match"),d=l.get("focusLabel"),m=/__name__/.test(c||""),u=((b=a[0])==null?void 0:b.value)/r*100,h=t-n,p=Math.abs(h)/n*100,v=[{title:"Total series",value:t.toLocaleString("en-US"),dynamic:!t||!n||s?"":`${p.toFixed(2)}%`,display:!d,info:`The total number of unique time series for a selected day. - A time series is uniquely identified by its name plus a set of its labels. - For example, temperature{city="NY",country="US"} and temperature{city="SF",country="US"} - are two distinct series, since they differ by the "city" label.`},{title:"Percentage from total",value:isNaN(u)?"-":`${u.toFixed(2)}%`,display:m,info:"The share of these series in the total number of time series."}].filter(f=>f.display);return v.length?e("div",{className:I({"vm-cardinality-totals":!0,"vm-cardinality-totals_mobile":i}),children:[v.map(({title:f,value:g,info:_,dynamic:y})=>e("div",{className:"vm-cardinality-totals-card",children:[e("h4",{className:"vm-cardinality-totals-card__title",children:[_&&e(j,{title:e("p",{className:"vm-cardinality-totals-card__tooltip",children:_}),children:e("div",{className:"vm-cardinality-totals-card__info-icon",children:e(un,{})})}),f]}),e("span",{className:"vm-cardinality-totals-card__value",children:g}),!!y&&e(j,{title:`in relation to the previous day: ${n.toLocaleString("en-US")}`,placement:"bottom-left",children:e("span",{className:I({"vm-dynamic-number":!0,"vm-dynamic-number_positive vm-dynamic-number_down":h<0,"vm-dynamic-number_negative vm-dynamic-number_up":h>0}),children:y})})]},f)),e(Gm,{metricNameStats:o})]}):null},Se=(t,n)=>{const[r]=oe(),a=r.get(n)?r.get(n):t,[o,s]=N(a);return A(()=>{a!==o&&s(a)},[a]),[o,s]},Jm=({isPrometheus:t,isCluster:n,...r})=>{const{isMobile:a}=J(),[o]=oe(),{setSearchParamsFromKeys:s}=rt(),i=o.get("tips")||"",[l,c]=Se("","match"),[d,m]=Se("","focusLabel"),[u,h]=Se(10,"topN"),p=M(()=>u<0?"Number must be bigger than zero":"",[u]),v=_=>{const y=+_;h(isNaN(y)?0:y)},b=()=>{s({match:l,topN:u,focusLabel:d})},f=()=>{s({match:"",focusLabel:""})},g=()=>{const _=o.get("tips")||"";s({tips:_?"":"true"})};return A(()=>{const _=o.get("match"),y=+(o.get("topN")||10),S=o.get("focusLabel");_!==l&&c(_||""),y!==u&&h(y),S!==d&&m(S||"")},[o]),e("div",{className:I({"vm-cardinality-configurator":!0,"vm-cardinality-configurator_mobile":a,"vm-block":!0,"vm-block_mobile":a}),children:[e("div",{className:"vm-cardinality-configurator-controls",children:[e("div",{className:"vm-cardinality-configurator-controls__query",children:e(ce,{label:"Time series selector",type:"string",value:l,onChange:c,onEnter:b})}),e("div",{className:"vm-cardinality-configurator-controls__item",children:e(ce,{label:"Focus label",type:"text",value:d||"",onChange:m,onEnter:b,endIcon:e(j,{title:e("div",{children:e("p",{children:"To identify values with the highest number of series for the selected label."})}),children:e(la,{})})})}),e("div",{className:"vm-cardinality-configurator-controls__item vm-cardinality-configurator-controls__item_limit",children:e(ce,{label:"Limit entries",type:"number",value:t?10:u,error:p,disabled:t,helperText:t?"not available for Prometheus":"",onChange:v,onEnter:b})})]}),e("div",{className:"vm-cardinality-configurator-bottom",children:[e(Wm,{isPrometheus:t,isCluster:n,...r}),n&&e("div",{className:"vm-cardinality-configurator-bottom-helpful",children:e(Te,{href:"https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#cardinality-explorer-statistic-inaccuracy",withIcon:!0,children:[e(ut,{}),"Statistic inaccuracy explanation"]})}),e("div",{className:"vm-cardinality-configurator-bottom-helpful",children:e(Te,{href:"https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#cardinality-explorer",withIcon:!0,children:[e(ut,{}),"Documentation"]})}),e("div",{className:"vm-cardinality-configurator-bottom__execute",children:[e(j,{title:i?"Hide tips":"Show tips",children:e(D,{variant:"text",color:i?"warning":"gray",startIcon:e(vn,{}),onClick:g,ariaLabel:"visibility tips"})}),e(D,{variant:"text",startIcon:e(ct,{}),onClick:f,children:"Reset"}),e(D,{startIcon:e(nt,{}),onClick:b,children:"Execute Query"})]})]})]})};function Km(t){const{order:n,orderBy:r,onRequestSort:a,headerCells:o}=t,s=i=>l=>{a(l,i)};return e("thead",{className:"vm-table-header vm-cardinality-panel-table__header",children:e("tr",{className:"vm-table__row vm-table__row_header",children:o.map(i=>e("th",{className:I({"vm-table-cell vm-table-cell_header":!0,"vm-table-cell_sort":i.sortable,"vm-table-cell_right":i.id==="action"}),onClick:i.sortable?s(i.id):void 0,children:e("div",{className:"vm-table-cell__content",children:[i.info&&e(j,{title:i.info,children:e("div",{className:"vm-metrics-content-header__tip-icon",children:e(un,{})})}),i.label,i.sortable&&e("div",{className:I({"vm-table__sort-icon":!0,"vm-table__sort-icon_active":r===i.id,"vm-table__sort-icon_desc":n==="desc"&&r===i.id}),children:e(Je,{})})]})},i.id))})})}const Zm=["date","timestamp","time"];function So(t,n,r){const a=t[r],o=n[r];if(a==null&&o==null)return 0;if(a==null)return 1;if(o==null)return-1;const s=String(a),i=String(o);if(Zm.includes(String(r))){const u=oo(s),h=oo(i);return hu?1:0}const c=Number(s),d=Number(i);return!isNaN(c)&&!isNaN(d)?d-c:is?1:0}function Wa(t,n){return t==="desc"?(r,a)=>So(r,a,n):(r,a)=>-So(r,a,n)}function Ja(t,n){const r=t.map((a,o)=>[a,o]);return r.sort((a,o)=>{const s=n(a[0],o[0]);return s!==0?s:a[1]-o[1]}),r.map(a=>a[0])}const Xm=({rows:t,headerCells:n,defaultSortColumn:r,tableCells:a})=>{const[o,s]=N("desc"),[i,l]=N(r),c=(m,u)=>{s(i===u&&o==="asc"?"desc":"asc"),l(u)},d=Ja(t,Wa(o,i));return e("table",{className:"vm-table vm-cardinality-panel-table",children:[e(Km,{order:o,orderBy:i,onRequestSort:c,rowCount:t.length,headerCells:n}),e("tbody",{className:"vm-table-header",children:d.map(m=>e("tr",{className:"vm-table__row",children:a(m)},m.name))})]})},eu=({row:t,tableHeaderCells:n,totalSeries:r,totalSeriesPrev:a,onActionClick:o})=>{const s=r>0?t.value/r*100:-1,i=a>0?t.valuePrev/a*100:-1,l=[s,i].some(x=>x===-1),c=t.value.toLocaleString("en-US"),d=t.valuePrev.toLocaleString("en-US"),m=Math.abs(t.diff).toLocaleString("en-US"),u=s-i,h=l?"":`${Math.abs(u).toFixed(2)}%`,p=`${Math.abs(t.diffPercent).toFixed(2)}%`,v=t.requestsCount===0,f=t.requestsCount==null?"n/a":t.requestsCount.toLocaleString("en-US"),g=t.lastRequestTimestamp===0,_=t.lastRequestTimestamp==null,y=!g&&!_,S=g?"never":"n/a",T=y?U().diff(t.lastRequestTimestamp*1e3,"seconds"):0,w=y?U.unix(t.lastRequestTimestamp).format(qe):"-",C=y?U.duration(-T,"seconds").humanize(!0):S,k=()=>{o(t.name)},L=x=>{switch(x.id){case"name":return e("span",{className:"vm-link vm-link_colored",onClick:k,children:t.name});case"value":return c;case"requestsCount":return e("div",{className:I({"vm-dynamic-number":!0,"vm-dynamic-number_negative":v}),children:f});case"lastRequestTimestamp":return e(j,{title:`${w}`,children:e("span",{className:I({"vm-dynamic-number":!0,"vm-dynamic-number_negative":g||T>=30*86400,"vm-dynamic-number_warning":T>=7*86400&&T<30*86400}),children:C})});case"diff":return e(j,{title:`in relation to the previous day: ${d}`,children:e("span",{className:I({"vm-dynamic-number":!0,"vm-dynamic-number_positive vm-dynamic-number_down":t.diff<0,"vm-dynamic-number_negative vm-dynamic-number_up":t.diff>0}),children:m})});case"diffPercent":return e(j,{title:`in relation to the previous day: ${d}`,children:e("div",{className:I({"vm-dynamic-number":!0,"vm-dynamic-number_positive vm-dynamic-number_down":t.diff<0,"vm-dynamic-number_negative vm-dynamic-number_up":t.diff>0}),children:p})});case"percentage":return e("div",{className:"vm-cardinality-panel-table__progress",children:[e(Js,{value:s,hideValue:!0}),e("span",{className:"vm-dynamic-number vm-dynamic-number_static",children:[s.toFixed(2),"%"]}),e(j,{title:"in relation to the previous day",children:e("span",{className:I({"vm-dynamic-number":!0,"vm-dynamic-number_no-change":u===0,"vm-dynamic-number_positive vm-dynamic-number_down":u<0,"vm-dynamic-number_negative vm-dynamic-number_up":u>0}),children:h})})]});case"action":return e("div",{className:"vm-table-cell__content",children:e(j,{title:e("span",{children:["Filter by ",e("code",{children:["`",t.name,"`"]})]}),children:e(D,{variant:"text",size:"small",onClick:k,startIcon:e(hn,{})})})});default:return st(t,x.id,"")}};return e(V,{children:n.map(x=>{var E;return e("td",{className:I("vm-table-cell",...((E=x.modifiers)==null?void 0:E.map(P=>`vm-table-cell_${P}`))??[]),children:L(x)},x.id)})})},tu=({data:t})=>{const[n,r]=N([]),[a,o]=N([0,0]),s=i=>{const l=i.map(u=>u.value),c=Math.ceil(l[0]||1),d=10,m=c/(d-1);return new Array(d+1).fill(c+m).map((u,h)=>Math.round(u-m*h))};return A(()=>{const i=t.sort((c,d)=>d.value-c.value),l=s(i);o(l),r(i.map(c=>({...c,percentage:c.value/l[0]*100})))},[t]),e("div",{className:"vm-simple-bar-chart",children:[e("div",{className:"vm-simple-bar-chart-y-axis",children:a.map(i=>e("div",{className:"vm-simple-bar-chart-y-axis__tick",children:i},i))}),e("div",{className:"vm-simple-bar-chart-data",children:n.map(({name:i,value:l,percentage:c})=>e(j,{title:`${i}: ${l}`,placement:"top-center",children:e("div",{className:"vm-simple-bar-chart-data-item",style:{maxHeight:`${c||0}%`}})},`${i}_${l}`))})]})},nu=({rows:t,tabs:n=[],chartContainer:r,totalSeries:a,totalSeriesPrev:o,onActionClick:s,sectionTitle:i,tip:l,tableHeaderCells:c,isPrometheus:d})=>{const{isMobile:m}=J(),[u,h]=N("table"),p=d&&!t.length,v=f=>e(eu,{row:f,tableHeaderCells:c,totalSeries:a,totalSeriesPrev:o,onActionClick:s}),b=M(()=>n.map((f,g)=>({value:f,label:f,icon:g===0?e(pn,{}):e(aa,{})})),[n]);return e("div",{className:I({"vm-metrics-content":!0,"vm-metrics-content_mobile":m,"vm-block":!0,"vm-block_mobile":m}),children:[e("div",{className:"vm-metrics-content-header vm-section-header",children:[e("h5",{className:I({"vm-metrics-content-header__title":!0,"vm-section-header__title":!0,"vm-section-header__title_mobile":m}),children:[!m&&l&&e(j,{title:e("p",{dangerouslySetInnerHTML:{__html:l},className:"vm-metrics-content-header__tip"}),children:e("div",{className:"vm-metrics-content-header__tip-icon",children:e(un,{})})}),i]}),e("div",{className:"vm-section-header__tabs",children:e(Yt,{activeItem:u,items:b,onChange:h})})]}),p&&e("div",{className:"vm-metrics-content-prom-data",children:[e("div",{className:"vm-metrics-content-prom-data__icon",children:e(mt,{})}),e("h3",{className:"vm-metrics-content-prom-data__title",children:"Prometheus Data Limitation"}),e("p",{className:"vm-metrics-content-prom-data__text",children:["Due to missing data from your Prometheus source, some tables may appear empty.",e("br",{}),"This does not indicate an issue with your system or our tool."]})]}),!p&&u==="table"&&e("div",{ref:r,className:I({"vm-metrics-content__table":!0,"vm-metrics-content__table_mobile":m}),children:e(Xm,{rows:t,headerCells:c,defaultSortColumn:"value",tableCells:v})}),!p&&u==="graph"&&e("div",{className:"vm-metrics-content__chart",children:e(tu,{data:t.map(({name:f,value:g})=>({name:f,value:g}))})})]})},ir=({title:t,children:n})=>e("div",{className:"vm-cardinality-tip",children:[e("div",{className:"vm-cardinality-tip-header",children:[e("div",{className:"vm-cardinality-tip-header__tip-icon",children:e(vn,{})}),e("h4",{className:"vm-cardinality-tip-header__title",children:t||"Tips"})]}),e("p",{className:"vm-cardinality-tip__description",children:n})]}),ru=()=>e(ir,{title:"Metrics with a high number of series",children:e("ul",{children:[e("li",{children:["Identify and eliminate labels with frequently changed values to reduce their ",e(Te,{href:"https://docs.victoriametrics.com/victoriametrics/faq/#what-is-high-cardinality",children:"cardinality"})," and ",e(Te,{href:"https://docs.victoriametrics.com/victoriametrics/faq/#what-is-high-churn-rate",children:"high churn rate"})]}),e("li",{children:["Find unused time series and ",e(Te,{href:"https://docs.victoriametrics.com/victoriametrics/relabeling/",children:"drop entire metrics"})]}),e("li",{children:["Aggregate time series before they got ingested into the database via ",e(Te,{href:"https://docs.victoriametrics.com/victoriametrics/stream-aggregation/",children:"streaming aggregation"})]})]})}),au=()=>e(ir,{title:"Labels with a high number of unique values",children:e("ul",{children:[e("li",{children:"Decrease the number of unique label values to reduce cardinality"}),e("li",{children:["Drop the label entirely via ",e(Te,{href:"https://docs.victoriametrics.com/victoriametrics/relabeling/",children:"relabeling"})]}),e("li",{children:"For volatile label values (such as URL path, user session, etc.) consider printing them to the log file instead of adding to time series"})]})}),ou=()=>e(ir,{title:"Dashboard of a single metric",children:[e("p",{children:"This dashboard helps to understand the cardinality of a single metric."}),e("p",{children:"Each time series is a unique combination of key-value label pairs. Therefore a label key with many values can create a lot of time series for a particular metric. If you’re trying to decrease the cardinality of a metric, start by looking at the labels with the highest number of values."}),e("p",{children:"Use the series selector at the top of the page to apply additional filters."})]}),su=()=>e(ir,{title:"Dashboard of a label",children:[e("p",{children:"This dashboard helps you understand the count of time series per label."}),e("p",{children:"Use the selector at the top of the page to pick a label name you’d like to inspect. For the selected label name, you’ll see the label values that have the highest number of series associated with them. So if you’ve chosen `instance` as your label name, you may see that `657` time series have value “host-1” attached to them and `580` time series have value `host-2` attached to them."}),e("p",{children:"This can be helpful in allowing you to determine where the bulk of your time series are coming from. If the label “instance=host-1” was applied to 657 series and the label “instance=host-2” was only applied to 580 series, you’d know, for example, that host-01 was responsible for sending the majority of the time series."})]}),iu=`Please wait while cardinality stats is calculated. - This may take some time if the db contains big number of time series.`,lu=()=>{const{isMobile:t}=J(),[n]=oe(),{setSearchParamsFromKeys:r}=rt(),a=n.get("tips")||"",o=n.get("match")||"",s=n.get("focusLabel")||"",{isLoading:i,appConfigurator:l,error:c,isCluster:d}=Qm(),{tsdbStatusData:m,metricNameStatsData:u,getDefaultState:h,tablesHeaders:p,sectionsTips:v}=l,b=h(o,s),f=g=>_=>{const S={match:Ym[g]({query:_,focusLabel:s,match:o})};(g==="labelValueCountByLabelName"||g=="seriesCountByLabelName")&&(S.focusLabel=_),g=="seriesCountByFocusLabelValue"&&(S.focusLabel=""),r(S)};return e("div",{className:I({"vm-cardinality-panel":!0,"vm-cardinality-panel_mobile":t}),children:[i&&e(Qe,{message:iu}),e(Jm,{isPrometheus:l.isPrometheusData,totalSeries:m.totalSeries,totalSeriesPrev:m.totalSeriesPrev,totalSeriesAll:m.totalSeriesByAll,totalLabelValuePairs:m.totalLabelValuePairs,seriesCountByMetricName:m.seriesCountByMetricName,metricNameStats:u,isCluster:d}),a&&e("div",{className:"vm-cardinality-panel-tips",children:[!o&&!s&&e(ru,{}),o&&!s&&e(ou,{}),!o&&!s&&e(au,{}),s&&e(su,{})]}),c&&e(le,{variant:"error",children:c}),l.keys(o,s).map(g=>e(nu,{sectionTitle:l.sectionsTitles(s)[g],tip:v[g],rows:m[g],onActionClick:f(g),tabs:b.tabs[g],chartContainer:b.containerRefs[g],totalSeriesPrev:l.totalSeries(g,!0),totalSeries:l.totalSeries(g),tableHeaderCells:p[g],isPrometheus:l.isPrometheusData},g))]})},cu=(t,n,r)=>`${t}/api/v1/status/top_queries?topN=${n||""}&maxLifetime=${r||""}`,du=(t,n)=>{var i;const{query:r,timeRangeSeconds:a}=t,o=[`g0.expr=${encodeURIComponent(r)}`],s=(i=nn.find(l=>l.duration===n))==null?void 0:i.id;return s&&o.push(`g0.relative_time=${s}`),a&&o.push(`g0.range_input=${n}`),`${Z.home}?${o.join("&")}`},mu=t=>(["topByAvgDuration","topByCount","topBySumDuration"].forEach(r=>{const a=t[r];Array.isArray(a)&&a.forEach(o=>{const s=Qn(o.timeRangeSeconds*1e3);o.url=du(o,s),o.timeRange=s})}),t),uu=({topN:t,maxLifetime:n})=>{const{serverUrl:r}=se(),{setSearchParamsFromKeys:a}=rt(),[o,s]=N(null),[i,l]=N(!1),[c,d]=N(),m=M(()=>cu(r,t,n),[r,t,n]);return{data:o,error:c,loading:i,fetch:async()=>{l(!0),a({topN:t,maxLifetime:n});try{const h=await fetch(m),p=await h.json();s(h.ok?mu(p):null),d(String(p.error||""))}catch(h){h instanceof Error&&h.name!=="AbortError"&&d(`${h.name}: ${h.message}`)}l(!1)}}},hu=({rows:t,columns:n,defaultOrderBy:r})=>{const a=Fe(),[o,s]=N(r||"count"),[i,l]=N("desc"),c=M(()=>Ja(t,Wa(i,o)),[t,o,i]),d=h=>{l(p=>p==="asc"&&o===h?"desc":"asc"),s(h)},m=h=>()=>{d(h)},u=({query:h})=>async()=>{await a(h,"Query has been copied")};return e("table",{className:"vm-table",children:[e("thead",{className:"vm-table-header",children:e("tr",{className:"vm-table__row vm-table__row_header",children:[n.map(h=>e("th",{className:"vm-table-cell vm-table-cell_header vm-table-cell_sort",onClick:m(h.sortBy||h.key),children:e("div",{className:"vm-table-cell__content",children:[h.title||h.key,e("div",{className:I({"vm-table__sort-icon":!0,"vm-table__sort-icon_active":o===h.key,"vm-table__sort-icon_desc":i==="desc"&&o===h.key}),children:e(Je,{})})]})},h.key)),e("th",{className:"vm-table-cell vm-table-cell_header"})," "]})}),e("tbody",{className:"vm-table-body",children:c.map((h,p)=>e("tr",{className:"vm-table__row",children:[n.map(v=>e("td",{className:"vm-table-cell",children:h[v.key]||"-"},v.key)),e("td",{className:"vm-table-cell vm-table-cell_no-padding",children:e("div",{className:"vm-top-queries-panels__table-actions",children:[h.url&&e(j,{title:"Execute query",children:e(Bn,{to:h.url,target:"_blank",rel:"noreferrer","aria-disabled":!0,children:e(D,{variant:"text",size:"small",startIcon:e(hn,{}),ariaLabel:"execute query"})})}),e(j,{title:"Copy query",children:e(D,{variant:"text",size:"small",startIcon:e(Xe,{}),onClick:u(h),ariaLabel:"copy query"})})]})})]},p))})]})},pu=["table","JSON"].map((t,n)=>({value:String(n),label:t,icon:n===0?e(pn,{}):e(It,{})})),wr=({rows:t,title:n,columns:r,defaultOrderBy:a})=>{const{isMobile:o}=J(),[s,i]=N(0),l=c=>{i(+c)};return e("div",{className:I({"vm-top-queries-panel":!0,"vm-block":!0,"vm-block_mobile":o}),children:[e("div",{className:I({"vm-top-queries-panel-header":!0,"vm-section-header":!0,"vm-top-queries-panel-header_mobile":o}),children:[e("h5",{className:I({"vm-section-header__title":!0,"vm-section-header__title_mobile":o}),children:n}),e("div",{className:"vm-section-header__tabs",children:e(Yt,{activeItem:String(s),items:pu,onChange:l})})]}),e("div",{className:I({"vm-top-queries-panel__table":!0,"vm-top-queries-panel__table_mobile":o}),children:[s===0&&e(hu,{rows:t,columns:r,defaultOrderBy:a}),s===1&&e(or,{data:t})]})]})},gu="30ms, 15s, 3d4h, 1y2w",vu=()=>{const{isMobile:t}=J(),[n,r]=Se(10,"topN"),[a,o]=Se("10m","maxLifetime"),{data:s,error:i,loading:l,fetch:c}=uu({topN:n,maxLifetime:a}),d=M(()=>{const _=a.trim().split(" ").reduce((S,T)=>{const w=es(T);return w?{...S,...w}:{...S}},{});return!!U.duration(_).asMilliseconds()},[a]),m=M(()=>!!n&&n<1,[n]),u=M(()=>m?"Number must be bigger than zero":"",[m]),h=M(()=>d?"":"Invalid duration value",[d]),p=g=>{if(!s)return g;const _=s[g];return typeof _=="number"?bt(_,_,_):_||g},v=g=>{r(+g)},b=g=>{o(g)},f=g=>{g.key==="Enter"&&c()};return A(()=>{s&&(n||r(+s.topN),a||o(s.maxLifetime))},[s]),A(()=>(c(),window.addEventListener("popstate",c),()=>{window.removeEventListener("popstate",c)}),[]),e("div",{className:I({"vm-top-queries":!0,"vm-top-queries_mobile":t}),children:[l&&e(Qe,{containerStyles:{height:"500px"}}),e("div",{className:I({"vm-top-queries-controls":!0,"vm-block":!0,"vm-block_mobile":t}),children:[e("div",{className:"vm-top-queries-controls-fields",children:[e("div",{className:"vm-top-queries-controls-fields__item",children:e(ce,{label:"Max lifetime",value:a,error:h,helperText:`For example ${gu}`,onChange:b,onKeyDown:f})}),e("div",{className:"vm-top-queries-controls-fields__item",children:e(ce,{label:"Number of returned queries",type:"number",value:n||"",error:u,onChange:v,onKeyDown:f})})]}),e("div",{className:I({"vm-top-queries-controls-bottom":!0,"vm-top-queries-controls-bottom_mobile":t}),children:[e("div",{className:"vm-top-queries-controls-bottom__info",children:["VictoriaMetrics tracks the last ",e(j,{title:"search.queryStats.lastQueriesCount",children:e("b",{children:p("search.queryStats.lastQueriesCount")})})," queries with durations at least ",e(j,{title:"search.queryStats.minQueryDuration",children:e("b",{children:p("search.queryStats.minQueryDuration")})})]}),e("div",{className:"vm-top-queries-controls-bottom__button",children:e(D,{startIcon:e(nt,{}),onClick:c,children:"Execute"})})]})]}),i&&e(le,{variant:"error",children:i}),s&&e(V,{children:e("div",{className:"vm-top-queries-panels",children:[e(wr,{rows:s.topBySumDuration,title:"Queries with most summary time to execute",columns:[{key:"query"},{key:"sumDurationSeconds",title:"sum duration, sec"},{key:"timeRange",sortBy:"timeRangeSeconds",title:"query time interval"},{key:"count"}],defaultOrderBy:"sumDurationSeconds"}),e(wr,{rows:s.topByAvgDuration,title:"Most heavy queries",columns:[{key:"query"},{key:"avgDurationSeconds",title:"avg duration, sec"},{key:"timeRange",sortBy:"timeRangeSeconds",title:"query time interval"},{key:"count"}],defaultOrderBy:"avgDurationSeconds"}),e(wr,{rows:s.topByCount,title:"Most frequently executed queries",columns:[{key:"query"},{key:"timeRange",sortBy:"timeRangeSeconds",title:"query time interval"},{key:"count"}]})]})})]})},Cr={"color-primary":"#589DF6","color-secondary":"#316eca","color-error":"#e5534b","color-warning":"#c69026","color-info":"#539bf5","color-success":"#57ab5a","color-background-body":"#22272e","color-background-block":"#2d333b","color-background-tooltip":"rgba(22, 22, 22, 0.8)","color-text":"#cdd9e5","color-text-secondary":"#768390","color-text-disabled":"#636e7b","box-shadow":"rgba(0, 0, 0, 0.16) 1px 2px 6px","box-shadow-popper":"rgba(0, 0, 0, 0.2) 0px 2px 8px 0px","border-divider":"1px solid rgba(99, 110, 123, 0.5)","color-hover-black":"rgba(0, 0, 0, 0.2)","color-log-hits-bar-0":"rgba(255, 255, 255, 0.18)","color-log-hits-bar-1":"#FFB74D","color-log-hits-bar-2":"#81C784","color-log-hits-bar-3":"#64B5F6","color-log-hits-bar-4":"#E57373","color-log-hits-bar-5":"#8a62f0"},Nr={"color-primary":"#3F51B5","color-secondary":"#E91E63","color-error":"#FD080E","color-warning":"#FF8308","color-info":"#03A9F4","color-success":"#4CAF50","color-background-body":"#FEFEFF","color-background-block":"#FFFFFF","color-background-tooltip":"rgba(80,80,80,0.9)","color-text":"#110f0f","color-text-secondary":"#706F6F","color-text-disabled":"#A09F9F","box-shadow":"rgba(0, 0, 0, 0.08) 1px 2px 6px","box-shadow-popper":"rgba(0, 0, 0, 0.1) 0px 2px 8px 0px","border-divider":"1px solid rgba(0, 0, 0, 0.15)","color-hover-black":"rgba(0, 0, 0, 0.06)","color-log-hits-bar-0":"rgba(0, 0, 0, 0.18)","color-log-hits-bar-1":"#FFB74D","color-log-hits-bar-2":"#81C784","color-log-hits-bar-3":"#64B5F6","color-log-hits-bar-4":"#E57373","color-log-hits-bar-5":"#8a62f0"},fu=()=>{const[t,n]=N(Dn()),r=a=>{n(a.matches)};return A(()=>{const a=window.matchMedia("(prefers-color-scheme: dark)");return a.addEventListener("change",r),()=>a.removeEventListener("change",r)},[]),t},Sr=["primary","secondary","error","warning","info","success"],Ka=({onLoaded:t})=>{const n=Ee(),{palette:r={}}=cn(),{theme:a}=se(),o=fu(),s=xt(),i=Pt(),[l,c]=N({[Ge.dark]:Cr,[Ge.light]:Nr,[Ge.system]:Dn()?Cr:Nr}),d=()=>{const{innerWidth:v,innerHeight:b}=window,{clientWidth:f,clientHeight:g}=document.documentElement;Rt("scrollbar-width",`${v-f}px`),Rt("scrollbar-height",`${b-g}px`),Rt("vh",`${b*.01}px`)},m=()=>{Sr.forEach((v,b)=>{const f=tt(`color-${v}`),g=Dd(f);Rt(`${v}-text`,g),b===Sr.length-1&&(s({type:"SET_DARK_THEME"}),t(!0))})},u=()=>{Sr.forEach(v=>{const b=r[v];b&&Rt(`color-${v}`,b)}),m()},h=()=>{const v=Ae("THEME")||Ge.system,b=l[v];Object.entries(b).forEach(([f,g])=>{Rt(f,g)}),m(),n&&u()},p=()=>{const v=Dn()?Cr:Nr;if(l[Ge.system]===v){h();return}c(b=>({...b,[Ge.system]:v}))};return A(()=>{d(),h()},[l]),A(d,[i]),A(p,[a,o]),A(()=>{n&&s({type:"SET_THEME",payload:Ge.light})},[]),null},Li=()=>{const[t,n]=N([]),[r,a]=N(!1),o=q(document.body),s=d=>{const m=Array.from(d||[]);n(m)},i=d=>{d.preventDefault(),d.stopPropagation(),d.type==="dragenter"||d.type==="dragover"?a(!0):d.type==="dragleave"&&a(!1)},l=d=>{var m;d.preventDefault(),d.stopPropagation(),a(!1),(m=d==null?void 0:d.dataTransfer)!=null&&m.files&&d.dataTransfer.files[0]&&s(d.dataTransfer.files)},c=d=>{var h;const m=(h=d.clipboardData)==null?void 0:h.items;if(!m)return;const u=Array.from(m).filter(p=>p.type==="application/json").map(p=>p.getAsFile()).filter(p=>p!==null);n(u)};return me("dragenter",i,o),me("dragleave",i,o),me("dragover",i,o),me("drop",l,o),me("paste",c,o),{files:t,dragging:r}},Vn=({onOpenModal:t,onChange:n})=>e("div",{className:"vm-upload-json-buttons",children:[e(D,{variant:"outlined",onClick:t,children:"Paste JSON"}),e("div",{className:"vm-upload-json-buttons__upload",children:[e(D,{children:"Upload Files"}),e("input",{id:"json",name:"json",type:"file",accept:"application/json",multiple:!0,title:" ",onChange:n})]})]}),_u=()=>{const[t,n]=N([]),[r,a]=N([]),o=M(()=>!!t.length,[t]),{value:s,setTrue:i,setFalse:l}=ae(!1),c=(g,_="")=>{a(y=>[{filename:_,text:`: ${g.message}`},...y])},d=(g,_)=>{try{const y=JSON.parse(g),S=y.trace||y;if(!S.duration_msec){c(new Error(Ce.traceNotFound),_);return}const T=new At(S,_);n(w=>[T,...w])}catch(y){y instanceof Error&&c(y,_)}},m=g=>{g.map(_=>{const y=new FileReader,S=(_==null?void 0:_.name)||"";y.onload=T=>{var C;const w=String((C=T.target)==null?void 0:C.result);d(w,S)},y.readAsText(_)})},u=g=>{if(!g.target)return;const _=g.target;a([]);const y=Array.from(_.files||[]);m(y),_.value=""},h=g=>{const _=t.filter(y=>y.idValue!==g.idValue);n([..._])},p=g=>{a(_=>_.filter((y,S)=>S!==g))},v=g=>()=>{p(g)},{files:b,dragging:f}=Li();return A(()=>{m(b)},[b]),e("div",{className:"vm-trace-page",children:[e("div",{className:"vm-trace-page-header",children:[e("div",{className:"vm-trace-page-header-errors",children:r.map((g,_)=>e("div",{className:"vm-trace-page-header-errors-item",children:[e(le,{variant:"error",children:[e("b",{className:"vm-trace-page-header-errors-item__filename",children:g.filename}),e("span",{children:g.text})]}),e(D,{className:"vm-trace-page-header-errors-item__close",startIcon:e(Ue,{}),variant:"text",color:"error",onClick:v(_)})]},`${g}_${_}`))}),e("div",{children:o&&e(Vn,{onOpenModal:i,onChange:u})})]}),o&&e("div",{children:e(Da,{jsonEditor:!0,traces:t,onDeleteClick:h})}),!o&&e("div",{className:"vm-trace-page-preview",children:[e("p",{className:"vm-trace-page-preview__text",children:["Please, upload file with JSON response content.",` -`,"The file must contain tracing information in JSON format.",` -`,"In order to use tracing please refer to the doc: ",e("a",{className:"vm-link vm-link_colored",href:"https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#query-tracing",target:"_blank",rel:"help noreferrer",children:"https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#query-tracing"}),` -`,"Tracing graph will be displayed after file upload.",` -`,"Attach files by dragging & dropping, selecting or pasting them."]}),e(Vn,{onOpenModal:i,onChange:u})]}),s&&e(Me,{title:"Paste JSON",onClose:l,children:e(Zs,{editable:!0,displayTitle:!0,defaultTile:`JSON ${t.length+1}`,onClose:l,onUpload:d})}),f&&e("div",{className:"vm-trace-page__dropzone"})]})},bu=({job:t,instance:n,metrics:r,size:a})=>{const{duration:o,relativeTime:s,period:{date:i}}=ge(),{customStep:l}=He(),{setSearchParamsFromKeys:c}=rt(),d=()=>{const m=Ti({"g0.range_input":o,"g0.end_input":i,"g0.step_input":l,"g0.relative_time":s,size:a,job:t,instance:n,metrics:r});c(m)};A(d,[o,s,i,l,t,n,r,a]),A(d,[])},yu=(t,n)=>`${t}/api/v1/label/job/values?start=${n.start}&end=${n.end}`,wu=(t,n,r)=>{const a=`{job=${JSON.stringify(r)}}`;return`${t}/api/v1/label/instance/values?match[]=${encodeURIComponent(a)}&start=${n.start}&end=${n.end}`},Cu=(t,n,r,a)=>{const s=`{${Object.entries({job:r,instance:a}).filter(i=>i[1]).map(([i,l])=>`${i}=${JSON.stringify(l)}`).join(",")}}`;return`${t}/api/v1/label/__name__/values?match[]=${encodeURIComponent(s)}&start=${n.start}&end=${n.end}`},Nu=()=>{const{serverUrl:t}=se(),{period:n}=ge(),[r,a]=N([]),[o,s]=N(!1),[i,l]=N(),c=M(()=>yu(t,n),[t,n]);return A(()=>{(async()=>{s(!0);try{const m=await fetch(c),u=await m.json(),h=u.data||[];a(h.sort((p,v)=>p.localeCompare(v))),m.ok?l(void 0):l(`${u.errorType}\r -${u==null?void 0:u.error}`)}catch(m){m instanceof Error&&l(`${m.name}: ${m.message}`)}s(!1)})().catch(console.error)},[c]),{jobs:r,isLoading:o,error:i}},Su=t=>{const{serverUrl:n}=se(),{period:r}=ge(),[a,o]=N([]),[s,i]=N(!1),[l,c]=N(),d=M(()=>wu(n,r,t),[n,r,t]);return A(()=>{if(!t)return;(async()=>{i(!0);try{const u=await fetch(d),h=await u.json(),p=h.data||[];o(p.sort((v,b)=>v.localeCompare(b))),u.ok?c(void 0):c(`${h.errorType}\r -${h==null?void 0:h.error}`)}catch(u){u instanceof Error&&c(`${u.name}: ${u.message}`)}i(!1)})().catch(console.error)},[d]),{instances:a,isLoading:s,error:l}},ku=(t,n)=>{const{serverUrl:r}=se(),{period:a}=ge(),[o,s]=N([]),[i,l]=N(!1),[c,d]=N(),m=M(()=>Cu(r,a,t,n),[r,a,t,n]);return A(()=>{if(!t)return;(async()=>{l(!0);try{const h=await fetch(m),p=await h.json(),v=p.data||[];s(v.sort((b,f)=>b.localeCompare(f))),h.ok?d(void 0):d(`${p.errorType}\r -${p==null?void 0:p.error}`)}catch(h){h instanceof Error&&d(`${h.name}: ${h.message}`)}l(!1)})().catch(console.error)},[m]),{names:o,isLoading:i,error:c}},Tu=({name:t,job:n,instance:r,rateEnabled:a,isBucket:o,height:s})=>{const{isMobile:i}=J(),{customStep:l,yaxis:c}=He(),{period:d}=ge(),m=vt(),u=Be(),h=mn(d.end-d.start),p=Zr(l),v=Qn(p*10*1e3),[b,f]=N(!1),[g,_]=N(!1),y=b&&l===h?v:l,S=M(()=>{const F=Object.entries({job:n,instance:r}).filter(z=>z[1]).map(([z,Y])=>`${z}=${JSON.stringify(Y)}`);F.push(`__name__=${JSON.stringify(t)}`),t=="node_cpu_seconds_total"&&F.push('mode!="idle"');const O=`{${F.join(",")}}`;return o?`sum(rate(${O})) by (vmrange, le)`:` -with (q = ${a?`rollup_rate(${O})`:`rollup(${O})`}) ( - alias(min(label_match(q, "rollup", "min")), "min"), - alias(max(label_match(q, "rollup", "max")), "max"), - alias(avg(label_match(q, "rollup", "avg")), "avg"), -)`},[t,n,r,a,o]),{isLoading:T,graphData:w,error:C,queryErrors:k,warning:L,isHistogram:x}=Xn({predefinedQuery:[S],visible:!0,customStep:y,showAllSeries:g}),E=F=>{m({type:"SET_YAXIS_LIMITS",payload:F})},P=({from:F,to:O})=>{u({type:"SET_PERIOD",payload:{from:F,to:O}})};return A(()=>{f(x)},[x]),e("div",{className:I({"vm-explore-metrics-graph":!0,"vm-explore-metrics-graph_mobile":i}),children:[T&&e(Qe,{}),C&&e(le,{variant:"error",children:C}),k[0]&&e(le,{variant:"error",children:k[0]}),L&&e(tr,{warning:L,query:[S],onChange:_}),w&&d&&e(ar,{data:w,period:d,customStep:y,query:[S],yaxis:c,setYaxisLimits:E,setPeriod:P,showLegend:!1,height:s,isHistogram:x})]})},Lu=({name:t,index:n,length:r,isBucket:a,rateEnabled:o,onChangeRate:s,onRemoveItem:i,onChangeOrder:l})=>{const{isMobile:c}=J(),{value:d,setTrue:m,setFalse:u}=ae(!1),h=()=>{i(t)},p=()=>{l(t,n,n+1)},v=()=>{l(t,n,n-1)};return c?e("div",{className:"vm-explore-metrics-item-header vm-explore-metrics-item-header_mobile",children:[e("div",{className:"vm-explore-metrics-item-header__name",children:t}),e(D,{variant:"text",size:"small",startIcon:e(ca,{}),onClick:m,ariaLabel:"open panel settings"}),d&&e(Me,{title:t,onClose:u,children:e("div",{className:"vm-explore-metrics-item-header-modal",children:[e("div",{className:"vm-explore-metrics-item-header-modal-order",children:[e(D,{startIcon:e(gs,{}),variant:"outlined",onClick:v,disabled:n===0,ariaLabel:"move graph up"}),e("p",{children:["position:",e("span",{className:"vm-explore-metrics-item-header-modal-order__index",children:["#",n+1]})]}),e(D,{endIcon:e(oa,{}),variant:"outlined",onClick:p,disabled:n===r-1,ariaLabel:"move graph down"})]}),!a&&e("div",{className:"vm-explore-metrics-item-header-modal__rate",children:[e(_e,{label:e("span",{children:["enable ",e("code",{children:"rate()"})]}),value:o,onChange:s,fullWidth:!0}),e("p",{children:"calculates the average per-second speed of metrics change"})]}),e(D,{startIcon:e(Ue,{}),color:"error",variant:"outlined",onClick:h,fullWidth:!0,children:"Remove graph"})]})})]}):e("div",{className:"vm-explore-metrics-item-header",children:[e("div",{className:"vm-explore-metrics-item-header-order",children:[e(j,{title:"move graph up",children:e(D,{className:"vm-explore-metrics-item-header-order__up",startIcon:e(be,{}),variant:"text",color:"gray",size:"small",onClick:v,ariaLabel:"move graph up"})}),e("div",{className:"vm-explore-metrics-item-header__index",children:["#",n+1]}),e(j,{title:"move graph down",children:e(D,{className:"vm-explore-metrics-item-header-order__down",startIcon:e(be,{}),variant:"text",color:"gray",size:"small",onClick:p,ariaLabel:"move graph down"})})]}),e("div",{className:"vm-explore-metrics-item-header__name",children:t}),!a&&e("div",{className:"vm-explore-metrics-item-header__rate",children:e(j,{title:"calculates the average per-second speed of metric's change",children:e(_e,{label:e("span",{children:["enable ",e("code",{children:"rate()"})]}),value:o,onChange:s})})}),e("div",{className:"vm-explore-metrics-item-header__close",children:e(j,{title:"close graph",children:e(D,{startIcon:e(Ue,{}),variant:"text",color:"gray",size:"small",onClick:h,ariaLabel:"close graph"})})})]})},Au=({name:t,job:n,instance:r,index:a,length:o,size:s,onRemoveItem:i,onChangeOrder:l})=>{const c=M(()=>/_sum?|_total?|_count?/.test(t),[t]),d=M(()=>/_bucket?/.test(t),[t]),[m,u]=N(c),h=Pt(),p=M(s.height,[s,h]);return A(()=>{u(c)},[n]),e("div",{className:"vm-explore-metrics-item vm-block vm-block_empty-padding",children:[e(Lu,{name:t,index:a,length:o,isBucket:d,rateEnabled:m,size:s.id,onChangeRate:u,onRemoveItem:i,onChangeOrder:l}),e(Tu,{name:t,job:n,instance:r,rateEnabled:m,isBucket:d,height:p},`${t}_${n}_${r}_${m}`)]})},Eu=Pn.map(t=>t.id),xu=({jobs:t,instances:n,names:r,job:a,instance:o,size:s,selectedMetrics:i,onChangeJob:l,onChangeInstance:c,onToggleMetric:d,onChangeSize:m})=>{const u=M(()=>a?"":"No instances. Please select job",[a]),h=M(()=>a?"":"No metric names. Please select job",[a]),{isMobile:p}=J(),{value:v,toggle:b,setFalse:f}=ae(Ae("EXPLORE_METRICS_TIPS")!=="false");return A(()=>{Le("EXPLORE_METRICS_TIPS",`${v}`)},[v]),e(V,{children:[e("div",{className:I({"vm-explore-metrics-header":!0,"vm-explore-metrics-header_mobile":p,"vm-block":!0,"vm-block_mobile":p}),children:[e("div",{className:"vm-explore-metrics-header__job",children:e(it,{value:a,list:t,label:"Job",placeholder:"Please select job",onChange:l,autofocus:!a&&!!t.length&&!p,searchable:!0})}),e("div",{className:"vm-explore-metrics-header__instance",children:e(it,{value:o,list:n,label:"Instance",placeholder:"Please select instance",onChange:c,noOptionsText:u,clearable:!0,searchable:!0})}),e("div",{className:"vm-explore-metrics-header__size",children:[e(it,{label:"Size graphs",value:s,list:Eu,onChange:m}),e(j,{title:`${v?"Hide":"Show"} tip`,children:e(D,{variant:"text",color:v?"warning":"gray",startIcon:e(vn,{}),onClick:b,ariaLabel:"visibility tips"})})]}),e("div",{className:"vm-explore-metrics-header-metrics",children:e(it,{label:"Metrics",value:i,list:r,placeholder:"Search metric name",onChange:d,noOptionsText:h,clearable:!0,searchable:!0})})]}),v&&e(le,{variant:"warning",children:e("div",{className:"vm-explore-metrics-header-description",children:[e("p",{children:["Please note: this page is solely designed for exploring Prometheus metrics. Prometheus metrics always contain ",e("code",{children:"job"})," and ",e("code",{children:"instance"})," labels (see ",e("a",{className:"vm-link vm-link_colored",href:"https://prometheus.io/docs/concepts/jobs_instances/",children:"these docs"}),"), and this page relies on them as filters. ",e("br",{}),"Please use this page for Prometheus metrics only, in accordance with their naming conventions."]}),e(D,{variant:"text",size:"small",startIcon:e(Ue,{}),onClick:f,ariaLabel:"close tips"})]})})]})},Mu=ze("job",""),Iu=ze("instance",""),ko=ze("metrics",""),To=ze("size",""),Pu=Pn.find(t=>To?t.id===To:t.isDefault)||Pn[0],Du=()=>{const[t,n]=N(Mu),[r,a]=N(Iu),[o,s]=N(ko?ko.split("&"):[]),[i,l]=N(Pu);bu({job:t,instance:r,metrics:o.join("&"),size:i.id});const{jobs:c,isLoading:d,error:m}=Nu(),{instances:u,isLoading:h,error:p}=Su(t),{names:v,isLoading:b,error:f}=ku(t,r),g=M(()=>d||h||b,[d,h,b]),_=M(()=>m||p||f,[m,p,f]),y=w=>{s(w?C=>C.includes(w)?C.filter(k=>k!==w):[...C,w]:[])},S=w=>{const C=Pn.find(k=>k.id===w);C&&l(C)},T=(w,C,k)=>{const L=k>o.length-1;k<0||L||s(E=>{const P=[...E],[F]=P.splice(C,1);return P.splice(k,0,F),P})};return A(()=>{r&&u.length&&!u.includes(r)&&a("")},[u,r]),e("div",{className:"vm-explore-metrics",children:[e(xu,{jobs:c,instances:u,names:v,job:t,size:i.id,instance:r,selectedMetrics:o,onChangeJob:n,onChangeSize:S,onChangeInstance:a,onToggleMetric:y}),g&&e(Qe,{}),_&&e(le,{variant:"error",children:_}),!t&&e(le,{variant:"info",children:"Please select job to see list of metric names."}),t&&!o.length&&e(le,{variant:"info",children:"Please select metric names to see the graphs."}),e("div",{className:"vm-explore-metrics-body",children:o.map((w,C)=>e(Au,{name:w,job:t,instance:r,index:C,length:o.length,size:i,onRemoveItem:y,onChangeOrder:T},w))})]})},Ou=()=>{const t=Fe(),n=r=>async()=>{await t(`<${r}/>`,`<${r}/> has been copied`)};return e("div",{className:"vm-preview-icons",children:Object.entries(Il).map(([r,a])=>e("div",{className:"vm-preview-icons-item",onClick:n(r),children:[e("div",{className:"vm-preview-icons-item__svg",children:a()}),e("div",{className:"vm-preview-icons-item__name",children:`<${r}/>`})]},r))})},ot=({code:t})=>{const n=Fe(),[r,a]=N("Copy"),o=async()=>{await n(t),a("Copied")};return A(()=>{let s=null;return r==="Copied"&&(s=setTimeout(()=>a("Copy"),1e3)),()=>{s&&clearTimeout(s)}},[r]),e("code",{className:"vm-code-example",children:[t,e("div",{className:"vm-code-example__copy",children:e(j,{title:r,children:e(D,{size:"small",variant:"text",onClick:o,startIcon:e(Xe,{}),ariaLabel:"close"})})})]})},Ru=()=>e("a",{className:"vm-link vm-link_colored",href:"https://docs.victoriametrics.com/victoriametrics/metricsql/",target:"_blank",rel:"help noreferrer",children:"MetricsQL"}),Lo=()=>e("a",{className:"vm-link vm-link_colored",href:"https://grafana.com/grafana/dashboards/1860",target:"_blank",rel:"help noreferrer",children:"Node Exporter Full"}),$u=()=>e("section",{className:"vm-with-template-tutorial",children:[e("h2",{className:"vm-with-template-tutorial__title",children:["Tutorial for WITH expressions in ",e(Ru,{})]}),e("div",{className:"vm-with-template-tutorial-section",children:[e("p",{className:"vm-with-template-tutorial-section__text",children:["Let's look at the following real query from ",e(Lo,{})," dashboard:"]}),e(ot,{code:`( - ( - node_memory_MemTotal_bytes{instance=~"$node:$port", job=~"$job"} - - - node_memory_MemFree_bytes{instance=~"$node:$port", job=~"$job"} - ) - / - node_memory_MemTotal_bytes{instance=~"$node:$port", job=~"$job"} -) * 100`}),e("p",{className:"vm-with-template-tutorial-section__text",children:"It is clear the query calculates the percentage of used memory for the given $node, $port and $job. Isn't it? :)"})]}),e("div",{className:"vm-with-template-tutorial-section",children:[e("p",{className:"vm-with-template-tutorial-section__text",children:"What's wrong with this query? Copy-pasted label filters for distinct timeseries which makes it easy to mistype these filters during modification. Let's simplify the query with WITH expressions:"}),e(ot,{code:`WITH ( - commonFilters = {instance=~"$node:$port",job=~"$job"} -) -( - node_memory_MemTotal_bytes{commonFilters} - - - node_memory_MemFree_bytes{commonFilters} -) - / -node_memory_MemTotal_bytes{commonFilters} * 100`})]}),e("div",{className:"vm-with-template-tutorial-section",children:[e("p",{className:"vm-with-template-tutorial-section__text",children:["Now label filters are located in a single place instead of three distinct places. The query mentions node_memory_MemTotal_bytes metric twice and ","{commonFilters}"," three times. WITH expressions may improve this:"]}),e(ot,{code:`WITH ( - my_resource_utilization(free, limit, filters) = (limit{filters} - free{filters}) / limit{filters} * 100 -) -my_resource_utilization( - node_memory_MemFree_bytes, - node_memory_MemTotal_bytes, - {instance=~"$node:$port",job=~"$job"}, -)`}),e("p",{className:"vm-with-template-tutorial-section__text",children:"Now the template function my_resource_utilization() may be used for monitoring arbitrary resources - memory, CPU, network, storage, you name it."})]}),e("div",{className:"vm-with-template-tutorial-section",children:[e("p",{className:"vm-with-template-tutorial-section__text",children:["Let's take another nice query from ",e(Lo,{})," dashboard:"]}),e(ot,{code:`( - ( - ( - count( - count(node_cpu_seconds_total{instance=~"$node:$port",job=~"$job"}) by (cpu) - ) - ) - - - avg( - sum by (mode) (rate(node_cpu_seconds_total{mode='idle',instance=~"$node:$port",job=~"$job"}[5m])) - ) - ) - * - 100 -) - / -count( - count(node_cpu_seconds_total{instance=~"$node:$port",job=~"$job"}) by (cpu) -)`}),e("p",{className:"vm-with-template-tutorial-section__text",children:"Do you understand what does this mess do? Is it manageable? :) WITH expressions are happy to help in a few iterations."})]}),e("div",{className:"vm-with-template-tutorial-section",children:[e("p",{className:"vm-with-template-tutorial-section__text",children:"1. Extract common filters used in multiple places into a commonFilters variable:"}),e(ot,{code:`WITH ( - commonFilters = {instance=~"$node:$port",job=~"$job"} -) -( - ( - ( - count( - count(node_cpu_seconds_total{commonFilters}) by (cpu) - ) - ) - - - avg( - sum by (mode) (rate(node_cpu_seconds_total{mode='idle',commonFilters}[5m])) - ) - ) - * - 100 -) - / -count( - count(node_cpu_seconds_total{commonFilters}) by (cpu) -)`})]}),e("div",{className:"vm-with-template-tutorial-section",children:[e("p",{className:"vm-with-template-tutorial-section__text",children:'2. Extract "count(count(...) by (cpu))" into cpuCount variable:'}),e(ot,{code:`WITH ( - commonFilters = {instance=~"$node:$port",job=~"$job"}, - cpuCount = count(count(node_cpu_seconds_total{commonFilters}) by (cpu)) -) -( - ( - cpuCount - - - avg( - sum by (mode) (rate(node_cpu_seconds_total{mode='idle',commonFilters}[5m])) - ) - ) - * - 100 -) / cpuCount`})]}),e("div",{className:"vm-with-template-tutorial-section",children:[e("p",{className:"vm-with-template-tutorial-section__text",children:"3. Extract rate(...) part into cpuIdle variable, since it is clear now that this part calculates the number of idle CPUs:"}),e(ot,{code:`WITH ( - commonFilters = {instance=~"$node:$port",job=~"$job"}, - cpuCount = count(count(node_cpu_seconds_total{commonFilters}) by (cpu)), - cpuIdle = sum(rate(node_cpu_seconds_total{mode='idle',commonFilters}[5m])) -) -((cpuCount - cpuIdle) * 100) / cpuCount`})]}),e("div",{className:"vm-with-template-tutorial-section",children:[e("p",{className:"vm-with-template-tutorial-section__text",children:["4. Put node_cpu_seconds_total","{commonFilters}"," into its own variable with the name cpuSeconds:"]}),e(ot,{code:`WITH ( - cpuSeconds = node_cpu_seconds_total{instance=~"$node:$port",job=~"$job"}, - cpuCount = count(count(cpuSeconds) by (cpu)), - cpuIdle = sum(rate(cpuSeconds{mode='idle'}[5m])) -) -((cpuCount - cpuIdle) * 100) / cpuCount`}),e("p",{className:"vm-with-template-tutorial-section__text",children:"Now the query became more clear comparing to the initial query."})]}),e("div",{className:"vm-with-template-tutorial-section",children:[e("p",{className:"vm-with-template-tutorial-section__text",children:"WITH expressions may be nested and may be put anywhere. Try expanding the following query:"}),e(ot,{code:`WITH ( - f(a, b) = WITH ( - f1(x) = b-x, - f2(x) = x+x - ) f1(a)*f2(b) -) f(foo, with(x=bar) x)`})]})]}),Fu=(t,n)=>`${t}/expand-with-exprs?query=${encodeURIComponent(n)}&format=json`,zu=()=>{const{serverUrl:t}=se(),[n,r]=oe(),[a,o]=N(""),[s,i]=N(!1),[l,c]=N();return{data:a,error:l,loading:s,expand:async m=>{n.set("expr",m),r(n);const u=Fu(t,m);i(!0);try{const p=await(await fetch(u)).json();o((p==null?void 0:p.expr)||""),c(String(p.error||""))}catch(h){h instanceof Error&&h.name!=="AbortError"&&c(`${h.name}: ${h.message}`)}i(!1)}}},Hu=()=>{const[t]=oe(),{data:n,loading:r,error:a,expand:o}=zu(),[s,i]=N(t.get("expr")||""),l=d=>{i(d)},c=()=>{o(s)};return A(()=>{s&&o(s)},[]),e("section",{className:"vm-with-template",children:[r&&e(Qe,{}),e("div",{className:"vm-with-template-body vm-block",children:[e("div",{className:"vm-with-template-body__expr",children:e(ce,{type:"textarea",label:"MetricsQL query with optional WITH expressions",value:s,error:a,autofocus:!0,onEnter:c,onChange:l})}),e("div",{className:"vm-with-template-body__result",children:e(ce,{type:"textarea",label:"MetricsQL query after expanding WITH expressions and applying other optimizations",value:n,disabled:!0})}),e("div",{className:"vm-with-template-body-top",children:e(D,{variant:"contained",onClick:c,startIcon:e(nt,{}),children:"Expand"})})]}),e("div",{className:"vm-block",children:e($u,{})})]})},Vu=(t,n,r)=>{const a=["format=json",`relabel_configs=${encodeURIComponent(n)}`,`metric=${encodeURIComponent(r)}`];return`${t}/metric-relabel-debug?${a.join("&")}`},qu=()=>{const{serverUrl:t}=se(),[n,r]=N(null),[a,o]=N(!1),[s,i]=N();return{data:n,error:s,loading:a,fetchData:async(c,d)=>{const m=Vu(t,c,d);o(!0);try{const h=await(await fetch(m)).json();r(h.error?null:h),i(String(h.error||""))}catch(u){u instanceof Error&&u.name!=="AbortError"&&i(`${u.name}: ${u.message}`)}o(!1)}}},Uu={config:`- if: '{bar_label=~"b.*"}' - source_labels: [foo_label, bar_label] - separator: "_" - target_label: foobar -- action: labeldrop - regex: "foo_.*" -- target_label: job - replacement: "my-application-2"`,labels:'{__name__="my_metric", bar_label="bar", foo_label="foo", job="my-application", instance="192.168.0.1"}'},Bu=()=>{const[t,n]=oe(),{data:r,loading:a,error:o,fetchData:s}=qu(),[i,l]=Se("","config"),[c,d]=Se("","labels"),m=v=>{l(v||"")},u=v=>{d(v||"")},h=W(()=>{s(i,c),t.set("config",i),t.set("labels",c),n(t)},[i,c]),p=()=>{const{config:v,labels:b}=Uu;l(v),d(b),s(v,b),t.set("config",v),t.set("labels",b),n(t)};return A(()=>{const v=t.get("config")||"",b=t.get("labels")||"";(b||v)&&(s(v,b),l(v),d(b))},[]),e("section",{className:"vm-relabeling",children:[a&&e(Qe,{}),e("div",{className:"vm-relabeling-header vm-block",children:[e("div",{className:"vm-relabeling-header-configs",children:e(ce,{type:"textarea",label:"Relabel configs",value:i,autofocus:!0,onChange:m,onEnter:h})}),e("div",{className:"vm-relabeling-header__labels",children:e(ce,{type:"textarea",label:"Labels",value:c,onChange:u,onEnter:h})}),e("div",{className:"vm-relabeling-header-bottom",children:[e("a",{className:"vm-link vm-link_with-icon",target:"_blank",href:"https://docs.victoriametrics.com/victoriametrics/relabeling/",rel:"help noreferrer",children:[e(mt,{}),"Relabeling cookbook"]}),e("a",{className:"vm-link vm-link_with-icon",target:"_blank",href:"https://docs.victoriametrics.com/victoriametrics/relabeling/",rel:"help noreferrer",children:[e(ut,{}),"Documentation"]}),e(D,{variant:"text",onClick:p,children:"Try example"}),e(D,{variant:"contained",onClick:h,startIcon:e(nt,{}),children:"Submit"})]})]}),o&&e(le,{variant:"error",children:o}),r&&e("div",{className:"vm-relabeling-steps vm-block",children:[r.originalLabels&&e("div",{className:"vm-relabeling-steps-item",children:e("div",{className:"vm-relabeling-steps-item__row",children:[e("span",{children:"Original labels:"}),e("code",{dangerouslySetInnerHTML:{__html:r.originalLabels}})]})}),r.steps.map((v,b)=>{var f,g;return e("div",{className:"vm-relabeling-steps-item",children:[e("div",{className:"vm-relabeling-steps-item__row",children:[e("span",{children:"Step:"}),b+1]}),e("div",{className:"vm-relabeling-steps-item__row",children:[e("span",{children:"Relabeling Rule:"}),e("code",{children:e("pre",{children:v.rule})})]}),e("div",{className:"vm-relabeling-steps-item__row",children:[e("span",{children:"Input Labels:"}),e("code",{children:e("pre",{dangerouslySetInnerHTML:{__html:((f=v.errors)==null?void 0:f.inLabels)||v.inLabels}})})]}),e("div",{className:"vm-relabeling-steps-item__row",children:[e("span",{children:"Output labels:"}),e("code",{children:e("pre",{dangerouslySetInnerHTML:{__html:((g=v.errors)==null?void 0:g.outLabels)||v.outLabels}})})]})]},b)}),r.resultingLabels&&e("div",{className:"vm-relabeling-steps-item",children:e("div",{className:"vm-relabeling-steps-item__row",children:[e("span",{children:"Resulting labels:"}),e("code",{dangerouslySetInnerHTML:{__html:r.resultingLabels}})]})})]})]})},ju=t=>`${t}/api/v1/status/active_queries`,Qu=()=>{const{serverUrl:t}=se(),[n,r]=N([]),[a,o]=N(U().format(On)),[s,i]=N(!1),[l,c]=N(),d=M(()=>ju(t),[t]),m=async()=>{i(!0);try{const u=await fetch(d),h=await u.json();r(h.data),o(U().format("HH:mm:ss:SSS")),u.ok?c(void 0):c(`${h.errorType}\r -${h==null?void 0:h.error}`)}catch(u){u instanceof Error&&c(`${u.name}: ${u.message}`)}i(!1)};return A(()=>{m().catch(console.error)},[d]),{data:n,lastUpdated:a,isLoading:s,error:l,fetchData:m}},Ai=({rows:t,columns:n,defaultOrderBy:r,defaultOrderDir:a,copyToClipboard:o,paginationOffset:s})=>{const i=Fe(),[l,c]=N(r),[d,m]=N(a||"desc"),[u,h]=N(null),p=M(()=>{const{startIndex:f,endIndex:g}=s;return Ja(t,Wa(d,l)).slice(f,g)},[t,l,d,s]),v=f=>()=>{m(g=>g==="asc"&&l===f?"desc":"asc"),c(f)},b=(f,g)=>async()=>{if(u!==g)try{await i(String(f)),h(g)}catch(_){console.error(_)}};return A(()=>{if(u===null)return;const f=setTimeout(()=>h(null),2e3);return()=>clearTimeout(f)},[u]),e("table",{className:"vm-table",children:[e("thead",{className:"vm-table-header",children:e("tr",{className:"vm-table__row vm-table__row_header",children:[n.map(f=>e("th",{className:"vm-table-cell vm-table-cell_header vm-table-cell_sort",onClick:v(f.key),children:e("div",{className:"vm-table-cell__content",children:[e("div",{children:String(f.title||f.key)}),e("div",{className:I({"vm-table__sort-icon":!0,"vm-table__sort-icon_active":l===f.key,"vm-table__sort-icon_desc":d==="desc"&&l===f.key}),children:e(Je,{})})]})},String(f.key))),o&&e("th",{className:"vm-table-cell vm-table-cell_header"})]})}),e("tbody",{className:"vm-table-body",children:p.map((f,g)=>e("tr",{className:"vm-table__row",children:[n.map(_=>e("td",{className:I({"vm-table-cell":!0,[`${_.className}`]:_.className}),children:f[_.key]||"-"},String(_.key))),o&&e("td",{className:"vm-table-cell vm-table-cell_right",children:f[o]&&e("div",{className:"vm-table-cell__content",children:e(j,{title:u===g?"Copied":"Copy row",children:e(D,{variant:"text",color:u===g?"success":"gray",size:"small",startIcon:u===g?e(Wn,{}):e(Xe,{}),onClick:b(f[o],g),ariaLabel:"copy row"})})})})]},g))})]})},Yu=()=>{const{isMobile:t}=J(),{timezone:n}=ge(),{data:r,lastUpdated:a,isLoading:o,error:s,fetchData:i}=Qu(),l=M(()=>r.map(m=>{const u=U(m.start).tz().format(qe),h=U(m.end).tz().format(qe);return{duration:m.duration,remote_addr:m.remote_addr,query:m.query,args:`${u} to ${h}, step=${Er(m.step)}`,data:JSON.stringify(m,null,2)}}),[r,n]),c=M(()=>{if(!(l!=null&&l.length))return[];const m=Object.keys(l[0]),u={remote_addr:"client address"},h=["data"];return m.filter(p=>!h.includes(p)).map(p=>({key:p,title:u[p]||p}))},[l]),d=async()=>{i().catch(console.error)};return e("div",{className:"vm-active-queries",children:[o&&e(Qe,{}),e("div",{className:"vm-active-queries-header",children:[!l.length&&!s&&e(le,{variant:"info",children:"There are currently no active queries running"}),s&&e(le,{variant:"error",children:s}),e("div",{className:"vm-active-queries-header-controls",children:[e(D,{variant:"contained",onClick:d,startIcon:e(Gn,{}),children:"Update"}),e("div",{className:"vm-active-queries-header__update-msg",children:["Last updated: ",a]})]})]}),!!l.length&&e("div",{className:I({"vm-block":!0,"vm-block_mobile":t}),children:e(Ai,{rows:l,columns:c,defaultOrderBy:"duration",copyToClipboard:"data",paginationOffset:{startIndex:0,endIndex:1/0}})})]})},Gu=({onClose:t,onUpload:n})=>{const{isMobile:r}=J(),[a,o]=N(""),[s,i]=N(""),l=M(()=>{try{return JSON.parse(a),""}catch(m){return m instanceof Error?m.message:"Unknown error"}},[a]),c=m=>{i(""),o(m)},d=()=>{i(l),!l&&(n(a),t())};return e("div",{className:I({"vm-json-form vm-json-form_one-field":!0,"vm-json-form_mobile vm-json-form_one-field_mobile":r}),children:[e(ce,{value:a,label:"JSON",type:"textarea",error:s,autofocus:!0,onChange:c,onEnter:d}),e("div",{className:"vm-json-form-footer",children:e("div",{className:"vm-json-form-footer__controls vm-json-form-footer__controls_right",children:[e(D,{variant:"outlined",color:"error",onClick:t,children:"Cancel"}),e(D,{variant:"contained",onClick:d,children:"apply"})]})})]})},Wu=({data:t,period:n})=>{const{isMobile:r}=J(),[a,o]=oe(),{tableCompact:s}=je(),i=Gt(),[l,c]=N([]),[d,m]=N(),[u,h]=N(),[p,v]=N(!1),[b,f]=N([]),[g,_]=N(),y=M(()=>Ya(u||[]).map(z=>z.key),[u]),S=M(()=>{const z=t.some(G=>G.data.resultType==="matrix");return t.some(G=>G.data.resultType==="vector")&&z?zt:z?zt.filter(G=>G.value==="chart"):zt.filter(G=>G.value!=="chart")},[t]),[T,w]=N(S[0].value),{yaxis:C,spanGaps:k}=He(),L=vt(),x=z=>{L({type:"SET_YAXIS_LIMITS",payload:z})},E=()=>{L({type:"TOGGLE_ENABLE_YAXIS_LIMITS"})},P=z=>{L({type:"SET_SPAN_GAPS",payload:z})},F=z=>{w(z)},O=z=>{c(Y=>Y.filter(G=>G.idValue!==z.idValue))},H=()=>{i({type:"TOGGLE_TABLE_COMPACT"})};return A(()=>{const z=T==="chart"?"matrix":"vector",Y=t.filter(G=>G.data.resultType===z&&G.trace).map(G=>{var K,re;return G.trace?new At(G.trace,((re=(K=G==null?void 0:G.vmui)==null?void 0:K.params)==null?void 0:re.query)||"Query"):null});c(Y.filter(Boolean))},[t,T]),A(()=>{const z=[],Y=[],G=[];t.forEach((K,re)=>{var ie,X;const Q=K.data.result.map(R=>{var $,B;return{...R,group:Number(((B=($=K.vmui)==null?void 0:$.params)==null?void 0:B.id)??re)+1}});K.data.resultType==="matrix"?(Y.push(...Q),z.push(((X=(ie=K.vmui)==null?void 0:ie.params)==null?void 0:X.query)||"Query")):G.push(...Q)}),f(z),m(Y),h(G),a.delete("display_mode"),o(a)},[t]),A(()=>{const z=!a.get("display_mode");v(!!d&&z&&Ma(d))},[d,a]),e("div",{className:I({"vm-query-analyzer-view":!0,"vm-query-analyzer-view_mobile":r}),children:[!!l.length&&e(Da,{traces:l,onDeleteClick:O}),e(Si,{}),e("div",{className:I({"vm-block":!0,"vm-block_mobile":r}),children:[e("div",{className:"vm-custom-panel-body-header",children:[e("div",{className:"vm-custom-panel-body-header__tabs",children:e(Yt,{activeItem:T,items:S,onChange:F})}),e("div",{className:"vm-custom-panel-body-header__graph-controls",children:[T==="chart"&&e(Ca,{}),T==="chart"&&e(Qa,{data:d||[],yaxis:C,isHistogram:p,setYaxisLimits:x,toggleEnableLimits:E,spanGaps:{value:k,onChange:P}}),T==="table"&&e(Ga,{columns:y,selectedColumns:g,onChangeColumns:_,tableCompact:s,toggleTableCompact:H})]})]}),d&&n&&T==="chart"&&e(ar,{data:d,period:n,customStep:n.step||"1s",query:b,yaxis:C,setYaxisLimits:x,setPeriod:()=>null,height:r?window.innerHeight*.5:500,isHistogram:p,spanGaps:k}),u&&T==="code"&&e(or,{data:u}),u&&T==="table"&&e(bi,{data:u,displayColumns:g})]})]})},Ju=({data:t,period:n})=>{var m,u,h,p,v;const r=M(()=>t.filter(b=>b.vmui||b.stats),[t]),a=((u=(m=r.find(b=>{var f;return(f=b==null?void 0:b.vmui)==null?void 0:f.title}))==null?void 0:m.vmui)==null?void 0:u.title)||"Report",o=(p=(h=r.find(b=>{var f;return(f=b==null?void 0:b.vmui)==null?void 0:f.comment}))==null?void 0:h.vmui)==null?void 0:p.comment,s=M(()=>["vmui.endpoint",...new Set(r.flatMap(b=>{var f;return[...Object.keys(((f=b.vmui)==null?void 0:f.params)||[]).map(g=>`vmui.params.${g}`),...Object.keys(b.stats||[]).map(g=>`stats.${g}`),"isPartial"]}))].map(b=>({column:b.split(".").pop(),values:r.map(f=>st(f,b,"-"))})).filter(({values:b})=>b.length&&b.every(f=>f!=="-")),[r]),i=M(()=>{if(!n)return"";const b=U(n.start*1e3).tz().format(qe),f=U(n.end*1e3).tz().format(qe);return`${b} - ${f}`},[n]),{value:l,setTrue:c,setFalse:d}=ae(!1);return e(V,{children:[e("div",{className:"vm-query-analyzer-info-header",children:[e("h1",{className:"vm-query-analyzer-info-header__title",children:a}),i&&e("div",{className:"vm-query-analyzer-info-header__timerange",children:[e(rn,{})," ",i]}),(n==null?void 0:n.step)&&e("div",{className:"vm-query-analyzer-info-header__timerange",children:[e($n,{})," step ",n.step]}),(o||!!s.length)&&e("div",{className:"vm-query-analyzer-info-header__info",children:e(D,{startIcon:e(mt,{}),variant:"outlined",color:"warning",onClick:c,children:["Show stats",o&&" & comments"]})})]}),l&&e(Me,{title:a,onClose:d,children:e("div",{className:"vm-query-analyzer-info__modal",children:[!!s.length&&e("div",{className:"vm-query-analyzer-info-stats",children:[e("div",{className:"vm-query-analyzer-info-comment-header",children:[e(mt,{}),"Stats"]}),e("table",{children:[e("thead",{children:e("tr",{children:s.map(({column:b})=>e("th",{children:b},b))})}),e("tbody",{children:(v=s[0])==null?void 0:v.values.map((b,f)=>e("tr",{children:s.map(({values:g},_)=>e("td",{children:g[f]},_))},f))})]})]}),o&&e("div",{className:"vm-query-analyzer-info-comment",children:[e("div",{className:"vm-query-analyzer-info-comment-header",children:[e(Ns,{}),"Comments"]}),e("div",{className:"vm-query-analyzer-info-comment-body vm-markdown",dangerouslySetInnerHTML:{__html:Bt(o)||o}})]})]})})]})},Ku=t=>{const n=t.slice(1).map((s,i)=>s-t[i]),r={};n.forEach(s=>{const i=s.toString();r[i]=(r[i]||0)+1});let a=0,o=0;for(const s in r)r[s]>o&&(o=r[s],a=Number(s));return a},Zu=()=>{const[t,n]=N([]),[r,a]=N(""),o=M(()=>!!t.length,[t]),{value:s,setTrue:i,setFalse:l}=ae(!1),c=M(()=>{var _,y;if(!t)return;const f=(y=(_=t[0])==null?void 0:_.vmui)==null?void 0:y.params,g={start:+((f==null?void 0:f.start)||0),end:+((f==null?void 0:f.end)||0),step:f==null?void 0:f.step,date:""};if(!f){const T=t.filter(C=>C.data.resultType==="matrix").map(C=>C.data.result).flat().map(C=>{var k;return C.values?(k=C.values)==null?void 0:k.map(L=>L[0]):[0]}).flat(),w=Array.from(new Set(T.filter(Boolean))).sort((C,k)=>C-k);g.start=w[0],g.end=w[w.length-1],g.step=Kr(Ku(w))}return g.date=ts(We(g.end)),g},[t]),d=f=>f.every(g=>{if(typeof g=="object"&&g!==null){const _=g.data;if(typeof _=="object"&&_!==null){const y=_.result,S=_.resultType;return Array.isArray(y)&&typeof S=="string"}}return!1}),m=f=>{try{const g=JSON.parse(f),_=Array.isArray(g)?g:[g];d(_)?n(_):(a("Invalid structure - JSON does not match the expected format"),n([]))}catch(g){g instanceof Error&&(a(`${g.name}: ${g.message}`),n([]))}},u=f=>{f.map(g=>{const _=new FileReader;_.onload=y=>{var T;const S=String((T=y.target)==null?void 0:T.result);m(S)},_.readAsText(g)})},h=f=>{if(!f.target)return;const g=f.target;a("");const _=Array.from(g.files||[]);u(_),g.value=""},p=()=>{a("")},{files:v,dragging:b}=Li();return A(()=>{u(v)},[v]),e("div",{className:"vm-query-analyzer",children:[o&&e("div",{className:"vm-query-analyzer-header",children:[e(Ju,{data:t,period:c}),e(Vn,{onOpenModal:i,onChange:h})]}),o&&e(Wu,{data:t,period:c}),!o&&e("div",{className:"vm-trace-page-preview",children:[e("p",{className:"vm-trace-page-preview__text",children:["Please, upload file with JSON response content.",` -`,"The file must contain query information in JSON format.",` -`,"Graph will be displayed after file upload.",` -`,"Attach files by dragging & dropping, selecting or pasting them."]}),e(Vn,{onOpenModal:i,onChange:h})]}),r&&e("div",{className:"vm-query-analyzer-error",children:[e(le,{variant:"error",children:r}),e(D,{className:"vm-query-analyzer-error__close",startIcon:e(Ue,{}),variant:"text",color:"error",onClick:p})]}),s&&e(Me,{title:"Paste JSON",onClose:l,children:e(Gu,{onClose:l,onUpload:m})}),b&&e("div",{className:"vm-trace-page__dropzone"})]})},Xu=(t,n,r)=>{const a=[`flags=${encodeURIComponent(n)}`,`metrics=${encodeURIComponent(r)}`];return`${t}/downsampling-filters-debug?${a.join("&")}`},eh=()=>{const{serverUrl:t}=se(),[n,r]=oe(),[a,o]=N(new Map),[s,i]=N(!1),[l,c]=N(),[d,m]=N(),[u,h]=N(),p=W(async(v,b)=>{var g,_;if(c(b?"":"metrics are required"),m(v?"":"flags are required"),!b||!v)return;n.set("flags",v),n.set("metrics",b),r(n);const f=Xu(t,v,b);i(!0);try{const S=await(await fetch(f)).json();o(new Map(Object.entries(S.result||{}))),c(((g=S.error)==null?void 0:g.metrics)||""),m(((_=S.error)==null?void 0:_.flags)||""),h("")}catch(y){y instanceof Error&&y.name!=="AbortError"&&h(`${y.name}: ${y.message}`)}i(!1)},[t]);return{data:a,error:u,metricsError:l,flagsError:d,loading:s,applyFilters:p}},Ao={flags:`-downsampling.period={env="dev"}:7d:5m,{env="dev"}:30d:30m --downsampling.period=30d:1m --downsampling.period=60d:5m -`,metrics:`up -up{env="dev"} -up{env="prod"}`},th=()=>{const[t]=oe(),{data:n,loading:r,error:a,metricsError:o,flagsError:s,applyFilters:i}=eh(),[l,c]=N(t.get("metrics")||""),[d,m]=N(t.get("flags")||""),u=W(f=>{c(f)},[c]),h=W(f=>{m(f)},[m]),p=W(()=>{i(d,l)},[i,d,l]),v=W(()=>{const{flags:f,metrics:g}=Ao;m(f),c(g),i(f,g),t.set("flags",f),t.set("metrics",g)},[Ao,m,c,t]);A(()=>{d&&l&&p()},[]);const b=[];for(const[f,g]of n)b.push(e("tr",{className:"vm-table__row",children:[e("td",{className:"vm-table-cell",children:f}),e("td",{className:I({"vm-table-cell":!0,"vm-table-cell_empty":!g}),children:g?g.join(" "):"No matching rules found!"})]}));return e("section",{className:"vm-downsampling-filters",children:[r&&e(Qe,{}),e("div",{className:"vm-downsampling-filters-body vm-block",children:[e("div",{className:"vm-downsampling-filters-body__expr",children:[e("div",{className:"vm-retention-filters-body__title",children:e("p",{children:["Provide a list of flags for downsampling configuration. Note that only ",e("code",{children:"-downsampling.period"})," and ",e("code",{children:"-dedup.minScrapeInterval"})," flags are supported"]})}),e(ce,{type:"textarea",label:"Flags",value:d,error:a||s,autofocus:!0,onEnter:p,onChange:h,placeholder:"-downsampling.period=30d:1m -downsampling.period=7d:5m -dedup.minScrapeInterval=30s"})]}),e("div",{className:"vm-downsampling-filters-body__expr",children:[e("div",{className:"vm-retention-filters-body__title",children:e("p",{children:"Provide a list of metrics to check downsampling configuration."})}),e(ce,{type:"textarea",label:"Metrics",value:l,error:a||o,onEnter:p,onChange:u,placeholder:`up{env="dev"} -up{env="prod"} -`})]}),e("div",{className:"vm-downsampling-filters-body__result",children:e("table",{className:"vm-table",children:[e("thead",{className:"vm-table-header",children:e("tr",{children:[e("th",{className:"vm-table-cell vm-table-cell_header",children:"Metric"}),e("th",{className:"vm-table-cell vm-table-cell_header",children:"Applied downsampling rules"})]})}),e("tbody",{className:"vm-table-body",children:b})]})}),e("div",{className:"vm-downsampling-filters-body-top",children:[e("a",{className:"vm-link vm-link_with-icon",target:"_blank",href:"https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#downsampling",rel:"help noreferrer",children:[e(ut,{}),"Documentation"]}),e(D,{variant:"text",onClick:v,children:"Try example"}),e(D,{variant:"contained",onClick:p,startIcon:e(nt,{}),children:"Apply"})]})]})]})},nh=(t,n,r)=>{const a=[`flags=${encodeURIComponent(n)}`,`metrics=${encodeURIComponent(r)}`];return`${t}/retention-filters-debug?${a.join("&")}`},rh=()=>{const{serverUrl:t}=se(),[n,r]=oe(),[a,o]=N(new Map),[s,i]=N(!1),[l,c]=N(),[d,m]=N(),[u,h]=N(),p=W(async(v,b)=>{var g,_;if(c(b?"":"metrics are required"),m(v?"":"flags are required"),!b||!v)return;n.set("flags",v),n.set("metrics",b),r(n);const f=nh(t,v,b);i(!0);try{const S=await(await fetch(f)).json();o(new Map(Object.entries(S.result||{}))),c(((g=S.error)==null?void 0:g.metrics)||""),m(((_=S.error)==null?void 0:_.flags)||""),h("")}catch(y){y instanceof Error&&y.name!=="AbortError"&&h(`${y.name}: ${y.message}`)}i(!1)},[t]);return{data:a,error:u,metricsError:l,flagsError:d,loading:s,applyFilters:p}},Eo={flags:`-retentionPeriod=1y --retentionFilter={env!="prod"}:2w -`,metrics:`up -up{env="dev"} -up{env="prod"}`},ah=()=>{const[t]=oe(),{data:n,loading:r,error:a,metricsError:o,flagsError:s,applyFilters:i}=rh(),[l,c]=N(t.get("metrics")||""),[d,m]=N(t.get("flags")||""),u=W(f=>{c(f)},[c]),h=W(f=>{m(f)},[m]),p=W(()=>{i(d,l)},[i,d,l]),v=W(()=>{const{flags:f,metrics:g}=Eo;m(f),c(g),i(f,g),t.set("flags",f),t.set("metrics",g)},[Eo,m,c,t]);A(()=>{d&&l&&p()},[]);const b=[];for(const[f,g]of n)b.push(e("tr",{className:"vm-table__row",children:[e("td",{className:"vm-table-cell",children:f}),e("td",{className:"vm-table-cell",children:g})]}));return e("section",{className:"vm-retention-filters",children:[r&&e(Qe,{}),e("div",{className:"vm-retention-filters-body vm-block",children:[e("div",{className:"vm-retention-filters-body__expr",children:[e("div",{className:"vm-retention-filters-body__title",children:e("p",{children:["Provide a list of flags for retention configuration. Note that only ",e("code",{children:"-retentionPeriod"})," and ",e("code",{children:"-retentionFilter"})," flags are supported."]})}),e(ce,{type:"textarea",label:"Flags",value:d,error:a||s,autofocus:!0,onEnter:p,onChange:h,placeholder:'-retentionPeriod=4w -retentionFilter=up{env="dev"}:2w'})]}),e("div",{className:"vm-retention-filters-body__expr",children:[e("div",{className:"vm-retention-filters-body__title",children:e("p",{children:"Provide a list of metrics to check retention configuration."})}),e(ce,{type:"textarea",label:"Metrics",value:l,error:a||o,onEnter:p,onChange:u,placeholder:`up{env="dev"} -up{env="prod"} -`})]}),e("div",{className:"vm-retention-filters-body__result",children:e("table",{className:"vm-table",children:[e("thead",{className:"vm-table-header",children:e("tr",{children:[e("th",{className:"vm-table-cell vm-table-cell_header",children:"Metric"}),e("th",{className:"vm-table-cell vm-table-cell_header",children:"Applied retention"})]})}),e("tbody",{className:"vm-table-body",children:b})]})}),e("div",{className:"vm-retention-filters-body-top",children:[e("a",{className:"vm-link vm-link_with-icon",target:"_blank",href:"https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#retention-filters",rel:"help noreferrer",children:[e(ut,{}),"Documentation"]}),e(D,{variant:"text",onClick:v,children:"Try example"}),e(D,{variant:"contained",onClick:p,startIcon:e(nt,{}),children:"Apply"})]})]})]})},oh=({hideQuery:t,showAllSeries:n})=>{const{query:r}=xe(),{period:a}=ge(),{displayType:o,reduceMemUsage:s,seriesLimits:i}=je(),{serverUrl:l}=se(),[c,d]=N(!1),[m,u]=N(),[h,p]=N(),[v,b]=N([]),[f,g]=N(),_=q(new AbortController),y=M(()=>{if(p(""),b([]),!!a)if(!l)p(Ce.emptyServer);else if(r.every(w=>!w.trim()))b(r.map(()=>Ce.validQuery));else if(Qr(l)){const w={...a};return r.map(C=>fd(l,C,w,s))}else p(Ce.validServer)},[l,a,t,s]),S=W(async({fetchUrl:w,stateSeriesLimits:C,showAllSeries:k})=>{_.current.abort(),_.current=new AbortController;const{signal:L}=_.current;d(!0);try{const x=Math.floor(window.innerWidth/4),E=30*1024*1024,P=[],F=k?1/0:+C[o]||1/0;let O=1,H=0;for await(const Y of w){if(t==null?void 0:t.includes(O-1)){b(ie=>[...ie,""]),O++;continue}const K=await fetch(Y,{signal:L}),re=await K.text();if(new TextEncoder().encode(re).length>E){const ie="Response too large to display (over 30 MiB). Please narrow your query.";p(ie),b(X=>[...X,ie]);continue}if(!K.ok||!K.body)P.push({metric:{},values:[],group:O}),p(re),b(ie=>[...ie,`${re}`]);else{b($=>[...$,""]);const ie=F-P.length,X=re.split(` -`).filter($=>$),R=X.slice(0,ie).sort();for(const $ of R){const B=wi($);if(!B)continue;const{values:ee,timestamps:te}=B,ue=ee.length,he=ue>x,Ye=he?x:ue,ye=he?ue/x:1,Pe=Array.from({length:Ye},(De,Ve)=>{const pe=he?Math.floor(Ve*ye):Ve;return[te[pe]/1e3,ee[pe]]});P.push({group:O,metric:B.metric,values:Pe})}H+=X.length}O++}const z=`Showing ${P.length} series out of ${H} series due to performance reasons. Please narrow down the query, so it returns less series`;g(H>F?z:""),u(P),d(!1)}catch(x){d(!1),x instanceof Error&&x.name!=="AbortError"&&(p(String(x)),console.error(x))}},[o,t]),T=W(()=>{_.current.abort(),u([])},[_]);return A(()=>{if(!(y!=null&&y.length))return;const w=setTimeout(S,400,{fetchUrl:y,stateSeriesLimits:i,showAllSeries:n});return()=>{var C;(C=_.current)==null||C.abort(),clearTimeout(w)}},[y,i,n]),{fetchUrl:y,isLoading:c,data:m,error:h,queryErrors:v,setQueryErrors:b,warning:f,abortFetch:T}},sh=()=>e(Te,{href:"https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples",underlined:!0,children:"raw samples"}),ih=()=>e(Te,{underlined:!0,href:"https://docs.victoriametrics.com/victoriametrics/keyconcepts/#query-data",children:"Query API"}),lh=()=>e(Te,{underlined:!0,href:"https://docs.victoriametrics.com/victoriametrics/keyconcepts/#filtering",children:"time series selector"}),ch=()=>{Ia();const{isMobile:t}=J(),{displayType:n}=je(),{query:r}=xe(),[a,o]=N([]),[s,i]=N(!r[0]),[l,c]=N(!1),[d,m]=N(!0),{data:u,error:h,isLoading:p,warning:v,queryErrors:b,setQueryErrors:f,abortFetch:g,fetchUrl:_}=oh({hideQuery:a,showAllSeries:l}),y=q(null),S=!s&&h,T=k=>{o(k)},w=()=>{i(!1)},C=()=>{m(!1)};return e("div",{className:I({"vm-custom-panel":!0,"vm-custom-panel_mobile":t}),children:[e(xa,{label:"Time series selector",queryErrors:s?[]:b,setQueryErrors:f,setHideError:i,stats:[],isLoading:p,onHideQuery:T,onRunQuery:w,abortFetch:g,hideButtons:{traceQuery:!0,disableCache:!0},includeFunctions:!1}),d&&e(le,{variant:"info",children:e("div",{className:"vm-explore-metrics-header-description",children:[e("ul",{children:[e("li",{children:["This page provides a dedicated view for querying and displaying ",e(sh,{})," from VictoriaMetrics."]}),e("li",{children:["It expects only ",e(lh,{})," as a query argument."]}),e("li",{children:["Deduplication can only be disabled if it was previously enabled on the server (",e("code",{children:"-dedup.minScrapeInterval"}),")."]}),e("li",{children:["Users often assume that the ",e(ih,{})," returns data exactly as stored, but data samples and timestamps may be modified by the API."]})]}),e(D,{variant:"text",size:"small",startIcon:e(Ue,{}),onClick:C,ariaLabel:"close tips"})]})}),S&&e(le,{variant:"error",children:h}),v&&e(tr,{warning:v,query:r,onChange:c}),e("div",{className:I({"vm-custom-panel-body":!0,"vm-custom-panel-body_mobile":t,"vm-block":!0,"vm-block_mobile":t}),children:[p&&e(er,{}),e("div",{className:"vm-custom-panel-body-header",ref:y,children:[e("div",{className:"vm-custom-panel-body-header__tabs",children:e(Es,{tabFilter:k=>k.value!==Ne.table})}),u&&e(Ni,{fetchUrl:_,reportType:Ci.RAW_DATA})]}),e(yi,{graphData:u,liveData:u,isHistogram:!1,displayType:n,controlsRef:y})]})]})},dh=()=>{const[t,n]=N(!1);return e(V,{children:e(qr,{children:e(wa,{children:e(V,{children:[e(Ka,{onLoaded:n}),t&&e(Ur,{children:e(fe,{path:"/",element:e(Uc,{}),children:[e(fe,{path:Z.home,element:e(ki,{})}),e(fe,{path:Z.rawQuery,element:e(ch,{})}),e(fe,{path:Z.metrics,element:e(Du,{})}),e(fe,{path:Z.cardinality,element:e(lu,{})}),e(fe,{path:Z.topQueries,element:e(vu,{})}),e(fe,{path:Z.trace,element:e(_u,{})}),e(fe,{path:Z.queryAnalyzer,element:e(Zu,{})}),e(fe,{path:Z.dashboards,element:e(Fm,{})}),e(fe,{path:Z.withTemplate,element:e(Hu,{})}),e(fe,{path:Z.relabel,element:e(Bu,{})}),e(fe,{path:Z.activeQueries,element:e(Yu,{})}),e(fe,{path:Z.icons,element:e(Ou,{})}),e(fe,{path:Z.downsamplingDebug,element:e(th,{})}),e(fe,{path:Z.retentionDebug,element:e(ah,{})})]})})]})})})})},mh=()=>{const t={0:"#000000",1:"#AA0000",2:"#00AA00",3:"#AA5500",4:"#0000AA",5:"#AA00AA",6:"#00AAAA",7:"#AAAAAA",8:"#555555",9:"#FF5555",10:"#55FF55",11:"#FFFF55",12:"#5555FF",13:"#FF55FF",14:"#55FFFF",15:"#FFFFFF"};for(let n=0;n<6;n++)for(let r=0;r<6;r++)for(let a=0;a<6;a++){const o=16+n*36+r*6+a,s=n>0?n*40+55:0,i=r>0?r*40+55:0,l=a>0?a*40+55:0;t[o]=`rgb(${s},${i},${l})`}for(let n=0;n<24;n++){const r=232+n,a=8+n*10;t[r]=`rgb(${a},${a},${a})`}return t},uh=mh(),Xt=t=>uh[t]||null,hh="(?:\\u0007|\\u001B\\u005C|\\u009C)",ph=[`[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?${hh})`,"(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|"),xo=new RegExp(ph,"g"),gh=(t,n,r)=>{switch(n){case 0:return{color:null,fontWeight:null,fontStyle:null,textDecoration:null,backgroundColor:null};case 30:case 31:case 32:case 33:case 34:case 35:case 36:case 37:return{...t,color:Xt(n-30)};case 90:case 91:case 92:case 93:case 94:case 95:case 96:case 97:return{...t,color:Xt(8+(n-90))};case 38:return r.length>2&&r[1]===5?{...t,color:Xt(r[2])}:t;case 40:case 41:case 42:case 43:case 44:case 45:case 46:case 47:return{...t,backgroundColor:Xt(n-40)};case 100:case 101:case 102:case 103:case 104:case 105:case 106:case 107:return{...t,backgroundColor:Xt(8+(n-100))};case 1:return{...t,fontWeight:"bold"};case 3:return{...t,fontStyle:"italic"};case 4:return{...t,textDecoration:"underline"};case 7:case 27:return{...t,color:t.backgroundColor,backgroundColor:t.color};case 22:return{...t,fontWeight:null};case 23:return{...t,fontStyle:null};case 24:return{...t,textDecoration:null};default:return t}},vh=t=>{var s;let n=0;const r=[];let a={color:null,fontWeight:null,fontStyle:null,textDecoration:null,backgroundColor:null},o;for(;(o=xo.exec(t))!==null;){const i=t.slice(n,o.index);i&&r.push(e("span",{style:{color:a.color||"inherit",fontWeight:a.fontWeight||"inherit",fontStyle:a.fontStyle||"inherit",textDecoration:a.textDecoration||"inherit",backgroundColor:a.backgroundColor||"inherit"},children:i},n));const l=((s=o[0].match(/\d+/g))==null?void 0:s.map(Number))||[];l.forEach(c=>{a=gh(a,c,l)}),n=xo.lastIndex}return n{const a=Fe(),[o,s]=oe(),[i,l]=N(!1),c=o.get(ke.GROUP_BY)||Re,d=o.get(ke.DISPLAY_FIELDS)||"",m=d?d.split(","):[],u=m.includes(t),h=c===t,p=W(async()=>{if(!i)try{await a(`${t}: "${n}"`),l(!0)}catch(f){console.error(f)}},[i,a]),v=()=>{const f=m,g=f.includes(t)?f.filter(_=>_!==t):[...f,t];o.set(ke.DISPLAY_FIELDS,g.join(",")),s(o)},b=()=>{h?o.delete(ke.GROUP_BY):o.set(ke.GROUP_BY,t),s(o)};return A(()=>{if(i===null)return;const f=setTimeout(()=>l(!1),2e3);return()=>clearTimeout(f)},[i]),e("tr",{className:"vm-group-logs-row-fields-item",children:[e("td",{className:"vm-group-logs-row-fields-item-controls",children:e("div",{className:"vm-group-logs-row-fields-item-controls__wrapper",children:[e(j,{title:i?"Copied":"Copy to clipboard",children:e(D,{className:"vm-group-logs-row-fields-item-controls__button",variant:"text",color:"gray",size:"small",startIcon:e(Xe,{}),onClick:p,ariaLabel:"copy to clipboard"})}),e(j,{title:u?"Hide this field":"Show this field instead of the message",children:e(D,{className:"vm-group-logs-row-fields-item-controls__button",variant:"text",color:u?"secondary":"gray",size:"small",startIcon:u?e(Vt,{}):e(Vt,{}),onClick:v,ariaLabel:u?"Hide this field":"Show this field instead of the message"})}),!r&&e(j,{title:h?"Ungroup this field":"Group by this field",children:e(D,{className:"vm-group-logs-row-fields-item-controls__button",variant:"text",color:h?"secondary":"gray",size:"small",startIcon:e(Lt,{}),onClick:b,ariaLabel:h?"Ungroup this field":"Group by this field"})})]})}),e("td",{className:"vm-group-logs-row-fields-item__key",children:t}),e("td",{className:"vm-group-logs-row-fields-item__value",children:n})]})},_h=zr(fh),lr=t=>{const[n,r]=N(!!Ae(t)),a=W(()=>{const s=!!Ae(t);s!==n&&r(s)},[t,n]),o=W(s=>{Le(t,s)},[t]);return me("storage",a),M(()=>[n,o],[n,o])},bh=({log:t,hideGroupButton:n})=>{const r=M(()=>Object.entries(t).sort(([o],[s])=>o.localeCompare(s)),[t]),[a]=lr("LOGS_DISABLED_HOVERS");return e("div",{className:I({"vm-group-logs-row-fields":!0,"vm-group-logs-row-fields_interactive":!a}),children:e("table",{children:e("tbody",{children:r.map(([o,s])=>e(_h,{field:o,value:s,hideGroupButton:n},o))})})})},yh=({log:t,displayFields:n=["_msg"],onItemClick:r,hideGroupButton:a})=>{const{value:o,toggle:s}=ae(!1),[i,l]=N(!1),c=Fe(),[d]=oe(),{markdownParsing:m,ansiParsing:u}=ya(),{timezone:h}=ge(),p=d.get(ke.NO_WRAP_LINES)==="true",v=d.get(ke.DATE_FORMAT)||$t,b=M(()=>t._time?U(t._time).tz().format(v):"",[t._time,h,v]),f=M(()=>!m||!t._msg?"":Bt(t._msg.replace(/```/g,"\n```\n")),[t._msg,m]),g=Object.keys(t).length>0,_=M(()=>{const w=[];return g||w.push("-"),n.some(C=>t[C])?n.filter(C=>t[C]).forEach(C=>{const k=C==="_msg"&&u?vh(t[C]):t[C];w.push(k)}):Object.entries(t).forEach(([C,k])=>{w.push(`${C}: ${k}`)}),w},[t,g,n,u]),[y]=lr("LOGS_DISABLED_HOVERS"),S=()=>{s(),r==null||r(t)},T=W(async w=>{if(w.stopPropagation(),!i)try{await c(JSON.stringify(t,null,2)),l(!0)}catch(C){console.error(C)}},[i,c]);return A(()=>{if(i===null)return;const w=setTimeout(()=>l(!1),2e3);return()=>clearTimeout(w)},[i]),e("div",{className:"vm-group-logs-row",children:[e("div",{className:I({"vm-group-logs-row-content":!0,"vm-group-logs-row-content_interactive":!y}),onClick:S,children:[e(j,{title:i?"Copied":"Copy to clipboard",children:e(D,{className:"vm-group-logs-row-content__copy-row",variant:"text",color:"gray",size:"small",startIcon:e(Xe,{}),onClick:T,ariaLabel:"copy to clipboard"})}),g&&e("div",{className:I({"vm-group-logs-row-content__arrow":!0,"vm-group-logs-row-content__arrow_open":o}),children:e(be,{})}),e("div",{className:I({"vm-group-logs-row-content__time":!0,"vm-group-logs-row-content__time_missing":!b}),children:b||"timestamp missing"}),e("div",{className:I({"vm-group-logs-row-content__msg":!0,"vm-group-logs-row-content__msg_empty-msg":!t._msg,"vm-group-logs-row-content__msg_missing":!_,"vm-group-logs-row-content__msg_single-line":p}),dangerouslySetInnerHTML:f?{__html:f}:void 0,children:_.map((w,C)=>e("span",{className:"vm-group-logs-row-content__sub-msg",children:w},`${w}_${C}`))})]}),g&&o&&e(bh,{hideGroupButton:a,log:t})]})},Ei=zr(yh);var lt=(t=>(t.BAR="Bars",t.LINE="Lines",t.LINE_STEPPED="Stepped lines",t.POINTS="Points",t))(lt||{});const wh=(t,n,r,a)=>{var i,l,c;const o=t.under.clientWidth/hi-1,s=(c=(l=(i=jt)==null?void 0:i.paths)==null?void 0:l.bars)==null?void 0:c.call(l,{size:[.96,o]});return s?s(t,n,r,a):null},Ch=(t,n,r,a)=>{var s,i,l;const o=(l=(i=(s=jt)==null?void 0:s.paths)==null?void 0:i.stepped)==null?void 0:l.call(i,{align:1});return o?o(t,n,r,a):null},Nh=t=>{switch(t){case lt.BAR:return wh;case lt.LINE_STEPPED:return Ch;default:return}},Sh=["color-log-hits-bar-1","color-log-hits-bar-2","color-log-hits-bar-3","color-log-hits-bar-4","color-log-hits-bar-5"],kh={[lt.BAR]:1,[lt.LINE_STEPPED]:2,[lt.LINE]:1.2,[lt.POINTS]:0},Rr="other",xi=t=>t!=null&&t._isOther?Rr:Object.values((t==null?void 0:t.fields)||{}).map(r=>r||'""').join(", "),Th=(t,n=0,r=1)=>{const a=t.series.filter(({scale:s})=>s==="y").map(({max:s})=>s||r),o=nr(a);return rr(0,o||r)},Lh=({data:t,logHits:n,xRange:r,bands:a,containerSize:o,onReadyChart:s,setPlotScale:i,graphOptions:l})=>{const{isDarkTheme:c}=se(),[d,m]=N(-1),u=v=>{const b=v.cursor.idx??-1;m(b)},h=M(()=>{let v=0;return t.map((b,f)=>{if(f===0)return{};const g=n==null?void 0:n[f-1],_=xi(g),y=g==null?void 0:g._isOther,S=y?"color-log-hits-bar-0":Sh[v++],T=tt(S);return{label:_,width:kh[l.graphStyle],spanGaps:!0,show:!0,stroke:T,fill:l.fill&&!y?`${T}80`:l.fill?T:"",paths:Nh(l.graphStyle)}})},[c,t,l]);return{options:{series:h,bands:a,width:o.width||window.innerWidth/2,height:o.height||200,cursor:{points:{width:(v,b,f)=>f/4,size:(v,b)=>{var f,g,_;return(((_=(g=(f=v.series)==null?void 0:f[b])==null?void 0:g.points)==null?void 0:_.size)||1)*1.5},stroke:(v,b)=>{var f;return`${((f=h==null?void 0:h[b])==null?void 0:f.stroke)||"#ffffff"}`},fill:()=>"#ffffff"}},scales:{x:{time:!0,range:()=>[r.min,r.max]},y:{range:Th}},hooks:{drawSeries:[],ready:[s],setCursor:[u],setSelect:[Ha(i)],destroy:[za]},legend:{show:!1},axes:Ra([{},{scale:"y"}]),tzDate:v=>U(Ft(We(v))).local().toDate()},series:h,focusDataIdx:d}},Mi=t=>(/^{.+}$/.test(t)?t.slice(1,-1).split(","):[t]).filter(Boolean),Ii=t=>{const n=U(t.start*1e3),r=U(t.end*1e3),a=r.diff(n,"milliseconds"),o=Math.ceil(a/hi)||1;return{start:n,end:r,step:o}},Pi=(t,n=Re)=>/(.+)?=(".+")/.test(t)?t.replace(/=/,": "):`${n}: "${t}"`,Ah=t=>t.reduce((n,r)=>n+(r.total||0),0),Di=t=>(n,r)=>{if(n.label===Rr)return 1;if(r.label===Rr)return-1;const a=n[t];return r[t]-a},Eh=()=>{const{isMobile:t}=J(),{markdownParsing:n,ansiParsing:r}=ya(),a=Is();return e(V,{children:[e("div",{className:"vm-group-logs-configurator-item",children:[e(_e,{label:"Enable markdown parsing",value:n,onChange:i=>{a({type:"SET_MARKDOWN_PARSING",payload:i}),r&&a({type:"SET_ANSI_PARSING",payload:!1})},fullWidth:t}),e("div",{className:"vm-group-logs-configurator-item__info",children:"Toggle this switch to enable or disable the Markdown formatting for log entries. Enabling this will parse log texts to Markdown."})]}),e("div",{className:"vm-group-logs-configurator-item",children:[e(_e,{label:"Enable ANSI parsing",value:r,onChange:i=>{a({type:"SET_ANSI_PARSING",payload:i}),n&&a({type:"SET_MARKDOWN_PARSING",payload:!1})},fullWidth:t}),e("div",{className:"vm-group-logs-configurator-item__info",children:"Toggle this switch to enable or disable ANSI escape sequence parsing for log entries. Enabling this will interpret ANSI codes to render colored log output."})]})]})},{GROUP_BY:Mo,NO_WRAP_LINES:Io,COMPACT_GROUP_HEADER:Po,DISPLAY_FIELDS:kr,DATE_FORMAT:Tr}=ke,En="Group view settings",xh=({logs:t})=>{const[n,r]=oe(),a=n.get(Mo)||Re,o=n.get(Io)==="true",s=n.get(Po)==="true",i=n.get(kr)||"",l=i?i.split(","):[tn],[c,d]=N(n.get(Tr)||$t),[m,u]=N(""),[h,p]=lr("LOGS_DISABLED_HOVERS"),v=a!==Re,b=l.length!==1||l[0]!==tn,f=c!==$t,g=[v,b,o,s,f].some(Boolean),_=M(()=>{const O=new Set(t.map(H=>Object.keys(H)).flat());return Array.from(O).sort((H,z)=>H.localeCompare(z))},[t]),{value:y,toggle:S,setFalse:T}=ae(!1),w=O=>{n.set(Mo,O),r(n)},C=O=>{const H=l,z=H.includes(O)?H.filter(Y=>Y!==O):[...H,O];n.set(kr,z.join(",")),r(n)},k=()=>{n.delete(kr),r(n)},L=()=>{n.set(Io,String(!o)),r(n)},x=()=>{n.set(Po,String(!s)),r(n)},E=O=>{U(new Date,O,!0).isValid()||u("Invalid date format"),d(O)},P=()=>{c===$t?n.delete(Tr):n.set(Tr,c),r(n),T()};return e(V,{children:[e("div",{className:"vm-group-logs-configurator-button",children:[e(j,{title:g?e("div",{className:"vm-group-logs-configurator__tooltip",children:[e("p",{children:En}),e("hr",{}),e("ul",{children:[v&&e("li",{children:["Group by ",e("code",{children:`"${a}"`})]}),b&&e("li",{children:["Display fields: ",l.length||1]}),o&&e("li",{children:"Single-line text is enabled"}),s&&e("li",{children:"Compact group header is enabled"}),f&&e("li",{children:["Date format: ",e("code",{children:c})]})]})]}):En,children:e(D,{variant:"text",startIcon:e(Ze,{}),onClick:S,ariaLabel:En})}),g&&e("span",{className:"vm-group-logs-configurator-button__marker"})]}),y&&e(Me,{title:En,onClose:P,children:e("div",{className:"vm-group-logs-configurator",children:[e("div",{className:"vm-group-logs-configurator-item",children:[e(it,{value:a,list:[Ut,..._],label:"Group by field",placeholder:"Group by field",onChange:w,searchable:!0}),e(j,{title:"Reset grouping",children:e(D,{variant:"text",color:"primary",startIcon:e(ct,{}),onClick:()=>w(Re)})}),e("span",{className:"vm-group-logs-configurator-item__info",children:["Select a field to group logs by (default: ",e("code",{children:Re}),")."]})]}),e("div",{className:"vm-group-logs-configurator-item",children:[e(it,{value:l,list:_,label:"Display fields",placeholder:"Display fields",onChange:C,searchable:!0}),e(j,{title:"Clear fields",children:e(D,{variant:"text",color:"primary",startIcon:e(ct,{}),onClick:k})}),e("span",{className:"vm-group-logs-configurator-item__info",children:["Select fields to display instead of the message (default: ",e("code",{children:tn}),")."]})]}),e("div",{className:"vm-group-logs-configurator-item",children:[e(ce,{autofocus:!0,label:"Date format",value:c,onChange:E,error:m}),e(j,{title:"Reset format",children:e(D,{variant:"text",color:"primary",startIcon:e(ct,{}),onClick:()=>d($t)})}),e("span",{className:"vm-group-logs-configurator-item__info vm-group-logs-configurator-item__info_input",children:["Set the date format (e.g., ",e("code",{children:"YYYY-MM-DD HH:mm:ss"}),"). Learn more in ",e(Te,{href:"https://day.js.org/docs/en/display/format",children:"this documentation"}),". ",e("br",{}),"Your current date format: ",e("code",{children:U().format(c||$t)})]})]}),e(Eh,{}),e("div",{className:"vm-group-logs-configurator-item",children:[e(_e,{value:o,onChange:L,label:"Single-line message"}),e("span",{className:"vm-group-logs-configurator-item__info",children:"Displays message in a single line and truncates it with an ellipsis if it exceeds the available space."})]}),e("div",{className:"vm-group-logs-configurator-item",children:[e(_e,{value:s,onChange:x,label:"Compact group header"}),e("span",{className:"vm-group-logs-configurator-item__info",children:'Shows group headers in one line with a "+N more" badge for extra fields.'})]}),e("div",{className:"vm-group-logs-configurator-item",children:[e(_e,{value:h,onChange:p,label:"Disable hover effects"}),e("span",{className:"vm-group-logs-configurator-item__info",children:"Disable row highlighting on hover to improve performance with large datasets."})]})]})})]})},Do=({pair:t,isHide:n})=>{const{isDarkTheme:r}=se(),a=Fe(),[o]=oe(),[s,i]=N(null),l=o.get(ke.GROUP_BY)||Re,c=d=>async m=>{m.stopPropagation();const u=Pi(d,l);await a(u)&&i(d)};return A(()=>{if(s===null)return;const d=setTimeout(()=>i(null),2e3);return()=>clearTimeout(d)},[s]),e(j,{title:s===t?"Copied":"Copy to clipboard",placement:"top-center",children:e("div",{className:I({"vm-group-logs-section-keys__pair":!0,"vm-group-logs-section-keys__pair_hide":n,"vm-group-logs-section-keys__pair_dark":r}),onClick:c(t),children:t})})},Mh=({group:t,index:n})=>{const{isDarkTheme:r}=se(),[a]=oe(),o=q(null),s=q(null),{value:i,toggle:l,setFalse:c}=ae(!1),[d,m]=N(0),u=a.get(ke.GROUP_BY)||Re,h=a.get(ke.COMPACT_GROUP_HEADER)==="true",p=t.pairs,v=p.length-d-1,b=g=>{g.stopPropagation(),l()},f=W(()=>{if(!h||!o.current){m(0);return}const g=o.current,_=g.getBoundingClientRect(),S=Array.from(g.querySelectorAll(".vm-group-logs-section-keys__pair:not(.vm-group-logs-section-keys__pair_more)"));let T=0;for(const w of S){const{right:C}=w.getBoundingClientRect();C+220>_.width&&T++}m(T)},[h,o]);return A(f,[t.pairs,h,o]),me("resize",f),e("div",{className:I({"vm-group-logs-section-keys":!0,"vm-group-logs-section-keys_compact":h}),ref:o,children:[e("span",{className:"vm-group-logs-section-keys__title",children:u===Ut?Ut:e(V,{children:[n+1,". Group by ",e("code",{children:u}),":"]})}),p.map((g,_)=>e(Do,{pair:g,isHide:d?_>v:!1},`${t.keysString}_${g}`)),d>0&&e(V,{children:[e("div",{className:I({"vm-group-logs-section-keys__pair":!0,"vm-group-logs-section-keys__pair_more":!0,"vm-group-logs-section-keys__pair_dark":r}),ref:s,onClick:b,children:["+",d," more"]}),e(Ie,{open:i,buttonRef:s,placement:"bottom-left",onClose:c,children:e("div",{className:"vm-group-logs-section-keys vm-group-logs-section-keys_popper",children:p.slice(v+1).map(g=>e(Do,{pair:g},`${t.keysString}_${g}`))})})]}),e("span",{className:"vm-group-logs-section-keys__count",children:[t.total," entries"]})]})},Oi=({currentPage:t,totalItems:n,itemsPerPage:r,onPageChange:a,maxVisiblePages:o=10})=>{const s=Math.ceil(n/r),i=m=>{m<1||m>s||a(m)},l=M(()=>{const m=[];if(s<=o)for(let u=1;u<=s;u++)m.push(u);else{const u=Math.max(1,t-Math.floor(o/2)),h=Math.min(s,u+o-1);u>1&&(m.push(1),u>2&&m.push("..."));for(let p=u;p<=h;p++)m.push(p);h()=>{i(t+m)},d=m=>()=>{typeof m=="number"&&i(m)};return l.length<=1?null:e("div",{className:"vm-pagination",children:[e("button",{className:"vm-pagination__page vm-pagination__arrow vm-pagination__arrow_prev",onClick:c(-1),disabled:t===1,children:e(be,{})}),l.map((m,u)=>e("button",{onClick:d(m),className:I({"vm-pagination__page":!0,"vm-pagination__page_active":t===m,"vm-pagination__page_disabled":m==="..."}),disabled:m==="...",children:m},u)),e("button",{className:"vm-pagination__page vm-pagination__arrow vm-pagination__arrow_next",onClick:c(1),disabled:t===s,children:e(be,{})})]})},Oo=[10,25,50,100,250,500,1e3],Za=({limit:t,allowUnlimited:n,onChange:r,onOpenSelect:a})=>{const{isMobile:o}=J(),s=q(null),i=M(()=>n?[...Oo,0]:Oo,[n]),{value:l,toggle:c,setFalse:d}=ae(!1),m=()=>{c(),l||a==null||a()},u=h=>()=>{r(h),d()};return e(V,{children:[e("div",{className:"vm-select-limits-button",onClick:m,ref:s,children:[e("div",{children:["Rows per page: ",e("b",{children:t||"All"})]}),e(Je,{})]}),e(Ie,{open:l,onClose:d,placement:"bottom-right",buttonRef:s,children:e("div",{className:"vm-select-limits",children:i.map(h=>e("div",{className:I({"vm-list-item":!0,"vm-list-item_mobile":o,"vm-list-item_active":h===t}),onClick:u(h),children:h||"All"},h))})})]})},Ih=(t,n,r)=>M(()=>{if(!r)return t;const a=(n-1)*r,o=a+r;let s=0;const i=[];for(const l of t){const c=l.values.length,d=s,m=s+c;if(m<=a){s=m;continue}if(d>=o)break;const u=Math.max(0,a-d),h=Math.min(c,o-d),p={...l,values:l.values.slice(u,h)};if(i.push(p),s=m,s>=o)break}return i},[t,n,r]),Ph=({title:t,downloadFormatOptions:n,onDownload:r})=>{const{value:a,setTrue:o,setFalse:s}=ae(!1),i=q(null),l=W(()=>{if(a){s();return}n&&n.length>0?o():(r(),s())},[r,s,a,o]),c=W(d=>{const m=d.currentTarget;r(m.textContent??void 0)},[r]);return e(V,{children:[e("div",{ref:i,children:e(j,{title:t,children:e(D,{variant:"text",startIcon:e(fn,{}),onClick:l,ariaLabel:t})})}),n&&n.length>0&&e(Ie,{open:a,onClose:s,buttonRef:i,placement:"bottom-right",children:n.map(d=>e("div",{className:"vm-download-button__format-option",children:e(D,{variant:"text",onClick:c,className:"vm-download-button__format-option-button",children:d})},d))})]})},cr=({getLogs:t})=>{const{fileExtensions:n,getDownloaderByExtension:r}=M(()=>{const o=[{extension:"csv",downloader:Cd},{extension:"json",downloader:(l,c)=>{const d=JSON.stringify(l,null,2);Pa(d,c)}}],s=l=>{var c;return(c=o.find(({extension:d})=>d===l))==null?void 0:c.downloader};return{fileExtensions:o.map(({extension:l})=>l),getDownloaderByExtension:s}},[]),a=W(o=>{if(!o)return;const s=t(),i=r(o);if(i){const l=U().utc().format(Wr);i(s,`vmui_logs_${l}.${o}`)}},[t]);return e(Ph,{title:"Download logs",onDownload:a,downloadFormatOptions:n})},Dh=/(?:^|\|)\s*(?:sort|order)\b/i;function Oh(t){return Dh.test(t)}const Rh=({logs:t,settingsRef:n})=>{const{isMobile:r}=J(),[a,o]=oe(),s=a.get("query")||"",i=Oh(s),[l,c]=N(1),[d,m]=N([]),u=a.get(ke.GROUP_BY)||Re,h=a.get(ke.DISPLAY_FIELDS)||tn,p=M(()=>h.split(","),[h]),v=Number(a.get(ke.ROWS_PER_PAGE)),b=isNaN(v)?0:v,f=M(()=>d.every(Boolean),[d]),g=M(()=>js(t,[u]).map(k=>{var P;const L=((P=k.values[0])==null?void 0:P[u])||"",x=Mi(L),E=i?k.values:k.values.toReversed();return{keys:k.keys,keysString:k.keys.join(""),values:E,pairs:x,total:E.length}}).sort((k,L)=>L.total-k.total),[t,u,i]),_=Ih(g,l,b),y=W(()=>{m(new Array(g.length).fill(!f))},[f,g.length]),S=W(k=>L=>{m(x=>{const E=[...x];return E[k]=L,E})},[]),T=k=>{k?a.set(ke.ROWS_PER_PAGE,String(k)):a.delete(ke.ROWS_PER_PAGE),o(a)},w=k=>{c(k),window.scrollTo({top:0})},C=W(()=>t,[t]);return A(()=>{m(new Array(g.length).fill(!r))},[g]),A(()=>{c(1)},[b]),e(V,{children:[e("div",{className:"vm-group-logs",children:[_.map((k,L)=>e("div",{className:"vm-group-logs-section",children:e(Kn,{defaultExpanded:d[L],onChange:S(L),title:e(Mh,{group:k,index:L}),children:e("div",{className:"vm-group-logs-section-rows",children:k.values.map((x,E)=>e(Ei,{log:x,displayFields:p},`${L}_${E}_${x._time}`))})})},k.keysString)),e(Oi,{currentPage:l,totalItems:t.length,itemsPerPage:b||1/0,onPageChange:w})]}),n.current&&jn.createPortal(e("div",{className:"vm-group-logs-header",children:[e("div",{className:"vm-explore-logs-body-header__log-info",children:["Total groups: ",e("b",{children:g.length})]}),e(Za,{allowUnlimited:!0,limit:b,onChange:T}),e(j,{title:f?"Collapse All":"Expand All",children:e(D,{variant:"text",startIcon:f?e(ua,{}):e(ma,{}),onClick:y,ariaLabel:f?"Collapse All":"Expand All"})}),e(cr,{getLogs:C}),e(xh,{logs:t})]}),n.current)]})},Xa=()=>e("div",{className:"vm-explore-logs-body__empty",children:"No logs found"}),$h=jn.memo(Rh),Fh=({data:t,settingsRef:n})=>t.length?e(V,{children:e($h,{logs:t,settingsRef:n})}):e(Xa,{}),zh=t=>{switch(t){case"_time":return"vm-table-cell_logs-time";default:return"vm-table-cell_logs"}},Hh=[{key:"_vmui_data",title:"Data",className:"vm-table-cell_logs vm-table-cell_pre"}],Vh=({logs:t,displayColumns:n,tableCompact:r,columns:a,rowsPerPage:o})=>{const s=q(null),[i,l]=N(1),c=M(()=>t.map(p=>{const v=JSON.stringify(p,null,2);return{...p,_vmui_data:v}}),[t]),d=M(()=>a.map(p=>({key:p,title:p,className:zh(p)})),[a]),m=M(()=>r?Hh:n!=null&&n.length?d.filter(p=>n.includes(p.key)):[],[d,n,r]),u=M(()=>{const p=(i-1)*o,v=p+o;return{startIndex:p,endIndex:v}},[i,o]),h=p=>{if(l(p),s.current){const v=s.current.getBoundingClientRect().top+window.scrollY-50;window.scrollTo({top:v})}};return A(()=>{l(1)},[t,o]),e(V,{children:[e("div",{ref:s,children:e(Ai,{rows:c,columns:m,defaultOrderBy:"_time",defaultOrderDir:"desc",copyToClipboard:"_vmui_data",paginationOffset:u})}),e(Oi,{currentPage:i,totalItems:c.length,itemsPerPage:o,onPageChange:h})]})},qh=jn.memo(Vh),Uh=({data:t,settingsRef:n})=>{const{setSearchParamsFromKeys:r}=rt(),[a,o]=N([]),[s,i]=Se(100,"rows_per_page"),l=M(()=>{const u=new Set;for(const h of t)for(const p in h)u.add(p);return Array.from(u).sort((h,p)=>h.localeCompare(p))},[t]),c=u=>{i(u),r({rows_per_page:u})},d=W(()=>t,[t]),m=()=>n.current?pt(e("div",{className:"vm-table-view__settings",children:[e(Za,{limit:s,onChange:c}),e("div",{className:"vm-table-view__settings-buttons",children:[t.length>0&&e(cr,{getLogs:d}),e(Ga,{columns:l,selectedColumns:a,onChangeColumns:o})]})]}),n.current):null;return t.length?e(V,{children:[m(),e(qh,{logs:t,displayColumns:a,tableCompact:!1,columns:l,rowsPerPage:Number(s)})]}):e(Xa,{})},Lr="JSON settings",Ro=["asc","desc"],Bh=({fields:t,sortQueryParamName:n,fieldSortQueryParamName:r})=>{const[a,o]=oe(),s=q(null),[i,l]=N(null),{value:c,toggle:d,setFalse:m}=ae(!1),[u,h]=N(null),[p,v]=N(null);A(()=>{const w=a.get(n),C=L=>Ro.includes(L);if(w){const[L,x]=w.split(":").map(decodeURIComponent);L&&C(x)&&(h(L),v(x))}const k=a.get(r);(k==="asc"||k==="desc")&&l(k)},[a,n,r,h,v,l]);const b=W((w,C)=>{const k=new URLSearchParams(a.toString());!w||!C?k.delete(n):k.set(n,`${w}:${C||""}`),o(k)},[a,n]),f=w=>{const C=p||"asc";h(w),v(C),b(w,C)},g=()=>{h(null),v(null),b(null,null)},_=W(()=>{let w=null;i===null?w="asc":i==="asc"&&(w="desc"),l(w);const C=new URLSearchParams(a.toString());w?C.set(r,encodeURIComponent(w)):C.delete(r),o(C)},[i,a,r]),y=w=>{const C=u||t[0];h(C),v(w),b(C,w)},S=M(()=>({default:{title:"Set field sort order. Click to sort in ascending order",icon:e(Ts,{})},asc:{title:"Fields sorted ascending. Click to sort in descending order",icon:e(Ls,{})},desc:{title:"Fields sorted descending. Click to reset sort",icon:e(As,{})}}),[]),T=M(()=>{const{title:w,icon:C}=S[i??"default"];return e(j,{title:w,children:e(D,{variant:"text",startIcon:C,onClick:_,ariaLabel:w})})},[i,d,_,S]);return e("div",{className:"vm-json-settings",children:[T,e(j,{title:Lr,children:e("div",{ref:s,children:e(D,{variant:"text",startIcon:e(Ze,{}),onClick:d,ariaLabel:Lr})})}),c&&e(Me,{title:Lr,className:"vm-json-settings-modal",onClose:m,children:e("div",{className:"vm-json-settings-modal-section",children:e("div",{className:"vm-json-settings-modal-section__sort-settings-container",children:[e(it,{value:u||"",onChange:f,list:t,label:"Select field"}),e(it,{value:p||"",onChange:y,list:Ro,label:"Sort direction"}),(u||p)&&e(D,{variant:"outlined",color:"error",onClick:g,children:"Reset sort"})]})})})]})},jh=jn.memo(or),$o="json_sort",Fo="json_field_sort",Qh=({data:t,settingsRef:n})=>{const r=W(()=>t,[t]),[a]=oe(),o=a.get($o),s=a.get(Fo),[i,l]=M(()=>{const[h,p]=(o==null?void 0:o.split(":").map(decodeURIComponent))||[];return[h,p]},[o]),c=M(()=>{const h=new Set(t.flatMap(Object.keys));return Array.from(h)},[t]),d=M(()=>{if(!s)return t;const h=c.toSorted((p,v)=>s==="asc"?p.localeCompare(v):v.localeCompare(p));return t.map(p=>h.reduce((v,b)=>(p[b]&&(v[b]=p[b]),v),{}))},[c,s,t]),m=M(()=>!i||!l?d:Yi(d,[i],[l]),[d,i,l]),u=()=>n.current?pt(t.length>0&&e("div",{className:"vm-json-view__settings-container",children:[e(cr,{getLogs:r}),e(Bh,{fields:c,sortQueryParamName:$o,fieldSortQueryParamName:Fo})]}),n.current):null;return t.length?e(V,{children:[u(),e(jh,{data:m})]}):e(Xa,{})},dr=()=>{const[t]=oe();return M(()=>({AccountID:t.get("accountID")||"0",ProjectID:t.get("projectID")||"0"}),[t])};class Yh{constructor(n=200,r=10,a=6,o=2){we(this,"threshold");we(this,"windowSize");we(this,"minHighCount");we(this,"minNormalCount");we(this,"window");we(this,"state");this.threshold=n,this.windowSize=r,this.minHighCount=a,this.minNormalCount=o,this.window=[],this.state="normal"}update(n){this.window.push(n),this.window.length>this.windowSize&&this.window.shift();const r=this.window.filter(a=>a>this.threshold).length;return this.state==="normal"?r>=this.minHighCount&&(this.state="high"):this.state==="high"&&rasync o=>{let s=Date.now();const i=setInterval(()=>{if(Date.now()-s>zo){clearInterval(i),a();return}},zo);try{for(;;){const{done:l,value:c}=await o.read();if(l)break;s=Date.now();const d=new TextDecoder().decode(c),m=(t.current+d).split(` -`);t.current=m.pop()||"",n.current=[...n.current,...m]}}catch(l){l instanceof Error&&l.name!=="AbortError"&&(console.error("Stream processing error:",l),a())}finally{clearInterval(i)}},Jh=(t,n)=>t.map(r=>{try{const a=r&&JSON.parse(r);return a._log_id=n.current++,a}catch(a){return console.error(`Failed to parse "${r}" to JSON -`,a),null}}).filter(Boolean),Kh=({lines:t,limit:n,counterRef:r,setIsLimitedLogsPerUpdate:a,setLogs:o,bufferLinesRef:s,logFlowAnalyzerRef:i})=>{var m;const l=((m=i==null?void 0:i.current)==null?void 0:m.update(t.length))==="high",c=l&&t.length>Gh?t.slice(-200):t,d=Jh(c,r);a(l),o(u=>{const h=[...u,...d];return h.length>n?h.slice(-n):h}),s.current=[]},Zh=(t,n)=>{const{serverUrl:r}=se(),[a,o]=N([]),{value:s,setTrue:i,setFalse:l}=ae(!1),c=dr(),[d,m]=N(),[u,h]=N(!1),p=q(0n),v=q(new AbortController),b=q(null),f=q(null),g=q(""),_=q([]),y=q(new Yh),S=W(()=>{b.current&&(b.current.cancel(),b.current=null),f.current&&clearInterval(f.current),g.current&&(g.current=""),v.current.abort()},[]),T=W(async()=>{S(),v.current=new AbortController;const{signal:C}=v.current;m(void 0);try{const k=await fetch(`${r}/select/logsql/tail`,{signal:C,method:"POST",headers:{...c},body:new URLSearchParams({query:t.trim()})});if(!k.ok||!k.body){const E=await k.text();return m(E),o([]),!1}const L=k.body.getReader();return b.current=L,Wh(g,_,m,T)(L),!0}catch(k){return k instanceof Error&&k.name!=="AbortError"&&(m(String(k)),console.error(k),o([])),!1}},[t,S]);A(()=>{if(s){const k=setInterval(()=>{_.current.length>n&&(_.current=_.current.slice(-n))},Ho);return()=>{clearInterval(k)}}const C=setInterval(()=>{const k=_.current;Kh({lines:k,limit:n,counterRef:p,setIsLimitedLogsPerUpdate:h,setLogs:o,bufferLinesRef:_,logFlowAnalyzerRef:y})},Ho);return()=>clearInterval(C)},[n,s,u]);const w=W(()=>{o([])},[]);return{logs:a,isPaused:s,error:d,startLiveTailing:T,stopLiveTailing:S,pauseLiveTailing:i,resumeLiveTailing:l,clearLogs:w,isLimitedLogsPerUpdate:u}},Xh=({settingsRef:t,rowsPerPage:n,handleSetRowsPerPage:r,logs:a,isPaused:o,handleResumeLiveTailing:s,pauseLiveTailing:i,clearLogs:l,isRawJsonView:c,onRawJsonViewChange:d})=>{const m=q(null),{value:u,setFalse:h,setTrue:p}=ae(!1),v=W(()=>a.map(({_log_id:b,...f})=>f),[a]);return t.current?pt(e("div",{className:"vm-live-tailing-view__settings",children:[e(Za,{limit:n,onChange:r,onOpenSelect:i}),e("div",{className:"vm-live-tailing-view__settings-buttons",children:[a.length>0&&e(cr,{getLogs:v}),o?e(j,{title:"Resume live tailing",children:e(D,{variant:"text",color:"primary",onClick:s,startIcon:e(hn,{}),ariaLabel:"Resume live tailing"})}):e(j,{title:"Pause live tailing",children:e(D,{variant:"text",color:"primary",onClick:i,startIcon:e(Ss,{}),ariaLabel:"Pause live tailing"})}),e(j,{title:"Clear logs",children:e(D,{variant:"text",color:"secondary",onClick:l,startIcon:e(gn,{}),ariaLabel:"Clear logs"})}),e(j,{title:"Settings",children:e(D,{ref:m,variant:"text",color:"secondary",onClick:p,startIcon:e(Ze,{}),ariaLabel:"Settings"})}),u&&e(Me,{onClose:h,title:"Live tailing settings",children:e("div",{className:"vm-live-tailing-view__settings-modal",children:e("div",{className:"vm-live-tailing-view__settings-modal-item",children:[e(_e,{label:"Raw JSON View",value:c,onChange:d}),e("span",{className:"vm-group-logs-configurator-item__info",children:"When this option is enabled, logs will be displayed in raw JSON format. This improves performance and uses less CPU and memory."})]})})})]})]}),t.current):null},ep=({className:t})=>{const[n,r]=N(!1),a=()=>{const s=window.pageYOffset||document.documentElement.scrollTop,i=window.innerHeight;r(s>i)},o=W(()=>{window.scrollTo({top:0,behavior:"smooth"})},[]);return A(()=>(window.addEventListener("scroll",a),a(),()=>{window.removeEventListener("scroll",a)}),[]),e("div",{className:I({"vm-scroll-to-top-button":!0,"vm-scroll-to-top-button_visible":n},t),children:e(j,{title:"Scroll to top",children:e(D,{variant:"contained",color:"primary",onClick:o,ariaLabel:"Scroll to top",startIcon:e(ks,{})})})})},tp=100,np=()=>window.scrollTo({top:document.documentElement.scrollHeight,behavior:"smooth"}),Vo=Gi(np,200),rp=({settingsRef:t})=>{const n=q(null),[r,a]=N(!0),[o]=oe(),{setSearchParamsFromKeys:s}=rt(),[i,l]=Se(100,"rows_per_page"),[c,d]=Se("*","query"),[m,u]=lr("RAW_JSON_LIVE_VIEW"),{logs:h,isPaused:p,error:v,startLiveTailing:b,stopLiveTailing:f,pauseLiveTailing:g,resumeLiveTailing:_,clearLogs:y,isLimitedLogsPerUpdate:S}=Zh(c,i),T=o.get(ke.DISPLAY_FIELDS)||tn,w=M(()=>T.split(","),[T]),C=W(()=>{Vo(),_()},[_]),k=W(L=>{s({rows_per_page:L})},[l,s]);return A(()=>(b(),()=>f()),[b,f]),A(()=>{if(!n.current)return;let x=[];const E=()=>{const{scrollTop:P,scrollHeight:F,clientHeight:O}=document.documentElement,H=Math.abs(F-P-O)document.removeEventListener("scroll",E)},[p,g,_]),A(()=>{r&&!p&&Vo()},[h,r]),A(()=>{C()},[i]),v?e("div",{className:"vm-live-tailing-view__error",children:v}):e(V,{children:[e(Xh,{settingsRef:t,rowsPerPage:i,handleSetRowsPerPage:k,logs:h,isPaused:p,handleResumeLiveTailing:C,pauseLiveTailing:g,clearLogs:y,isRawJsonView:m,onRawJsonViewChange:u}),e(ep,{}),e("div",{ref:n,className:"vm-live-tailing-view__container",children:h.length===0?e("div",{className:"vm-live-tailing-view__empty",children:"Waiting for logs..."}):e("div",{className:"vm-live-tailing-view__logs",children:h.map(({_log_id:L,...x},E)=>m?e("pre",{className:"vm-live-tailing-view__log-row",onMouseDown:g,children:JSON.stringify(x)},E):e(Ei,{log:x,onItemClick:g,hideGroupButton:!0,displayFields:w},L))})}),S&&e(le,{variant:"warning",children:"Too many logs per second detected. Large volumes of log data are difficult to process and may impact performance. We recommend adding filters to your query for better analysis and system performance."})]})},qo=[{label:"Group",value:"group",icon:e(bs,{}),Component:Fh},{label:"Table",value:"table",icon:e(pn,{}),Component:Uh},{label:"JSON",value:"json",icon:e(It,{}),Component:Qh},{label:"Live",value:"liveTailing",icon:e(nt,{}),Component:rp}],ap=({data:t,isLoading:n})=>{var d;const{isMobile:r}=J(),{setSearchParamsFromKeys:a}=rt(),[o,s]=Se("group","view"),i=q(null),l=m=>{s(m),a({view:m})},c=(d=qo.find(m=>m.value===o))==null?void 0:d.Component;return e("div",{className:I({"vm-explore-logs-body":!0,"vm-block":!0,"vm-block_mobile":r}),children:[n&&e(er,{}),e("div",{className:I({"vm-explore-logs-body-header":!0,"vm-section-header":!0,"vm-explore-logs-body-header_mobile":r}),children:[e("div",{className:I({"vm-section-header__tabs":!0,"vm-explore-logs-body-header__tabs_mobile":r}),children:[e(Yt,{activeItem:String(o),items:qo,onChange:l}),o!=="liveTailing"&&e("div",{className:"vm-explore-logs-body-header__log-info",children:["Total logs returned: ",e("b",{children:t.length})]})]}),e("div",{className:"vm-explore-logs-body-header__settings",ref:i})]}),e("div",{className:I({"vm-explore-logs-body__table":!0,"vm-explore-logs-body__table_mobile":r}),children:c&&e(c,{data:t,settingsRef:i})})]})},op=t=>`${t}/select/logsql/query`,sp=t=>`${t}/select/logsql/hits`,ip=(t,n,r)=>{const a=dr(),[o,s]=N([]),[i,l]=N({}),[c,d]=N(),m=q(new AbortController),u=M(()=>op(t),[t]),h=(v,b,f,g)=>({signal:g,method:"POST",headers:{...a,Accept:"application/stream+json"},body:new URLSearchParams({query:v.trim(),limit:`${f}`,start:U(b.start*1e3).tz().toISOString(),end:U(b.end*1e3).tz().toISOString()})}),p=W(async v=>{m.current.abort(),m.current=new AbortController;const{signal:b}=m.current,f=Date.now();l(g=>({...g,[f]:!0})),d(void 0);try{const g=h(n,v,r,b),_=await fetch(u,g),y=await _.text();if(!_.ok||!_.body)return d(y),s([]),!1;const S=y.split(` -`,r).map(lp).filter(T=>T);return s(S),!0}catch(g){return g instanceof Error&&g.name!=="AbortError"&&(d(String(g)),console.error(g),s([])),!1}finally{l(g=>{const{[f]:_,...y}=g;return y})}},[u,n,r,a]);return A(()=>()=>{m.current.abort()},[]),{logs:o,isLoading:Object.values(i).some(v=>v),error:c,fetchLogs:p,abortController:m.current}},lp=t=>{try{return t&&JSON.parse(t)}catch(n){return console.error(`Failed to parse "${t}" to JSON -`,n),null}};var Ke=(t=>(t.Filter="Filter",t.Pipe="Pipe",t.Operator="Operator",t.FilterOrPipe="FilterOrPipe",t))(Ke||{}),de=(t=>(t.FilterName="FilterName",t.FilterUnknown="FilterUnknown",t.FilterValue="FilterValue",t.PipeName="Pipes",t.PipeValue="PipeValue",t.Unknown="Unknown",t.FilterOrPipeName="FilterOrPipeName",t))(de||{});const cp="https://docs.victoriametrics.com/victorialogs/logsql",dp="vm-link vm-link_colored",mp=t=>{const n=`$1 target="_blank" class="${dp}" $2`,r=`$1 $2${cp}#`;return t.replace(/(copy copies log fields.'},{value:"delete",description:'delete deletes log fields.'},{value:"drop_empty_fields",description:'drop_empty_fields drops log fields with empty values.'},{value:"extract",description:'extract extracts the specified text into the given log fields.'},{value:"extract_regexp",description:'extract_regexp extracts the specified text into the given log fields via RE2 regular expressions.'},{value:"field_names",description:'field_names returns all the names of log fields.'},{value:"field_values",description:'field_values returns all the values for the given log field.'},{value:"fields",description:'fields selects the given set of log fields.'},{value:"filter",description:'filter applies additional filters to results.'},{value:"format",description:'format formats output field from input log fields.'},{value:"limit",description:'limit limits the number selected logs.'},{value:"math",description:'math performs mathematical calculations over log fields.'},{value:"offset",description:'offset skips the given number of selected logs.'},{value:"pack_json",description:'pack_json packs log fields into JSON object.'},{value:"pack_logfmt",description:'pack_logfmt packs log fields into logfmt message.'},{value:"rename",description:'rename renames log fields.'},{value:"replace",description:'replace replaces substrings in the specified log fields.'},{value:"replace_regexp",description:'replace_regexp updates log fields with regular expressions.'},{value:"sort",description:'sort sorts logs by the given fields.'},{value:"stats",description:'stats calculates various stats over the selected logs.'},{value:"stream_context",description:`stream_context allows selecting surrounding logs in front and after the matching logs -per each log stream.`},{value:"top",description:'top returns top N field sets with the maximum number of matching logs.'},{value:"uniq",description:'uniq returns unique log entries.'},{value:"unpack_json",description:'unpack_json unpacks JSON messages from log fields.'},{value:"unpack_logfmt",description:'unpack_logfmt unpacks logfmt messages from log fields.'},{value:"unpack_syslog",description:'unpack_syslog unpacks syslog messages from log fields.'},{value:"unroll",description:'unroll unrolls JSON arrays from log fields.'}].map(t=>({...t,type:de.PipeName,icon:e(an,{}),description:mp(t.description)})),up=["AND","OR","NOT"],hp=$r.map(t=>t.value),pp=t=>{var v,b;const n=t,r=[];let a="",o,s=!1;const i=["'",'"',"`"];let l=!1,c="";const d=["(","[","{"],m=[")","]","}"],u=[...d,...m];let h=0,p=0;for(let f=0;f{const s=t.trim();if(!s)return;const i=up.includes(s.toUpperCase()),l=[Ke.Pipe,Ke.FilterOrPipe],c=a.length>0&&l.includes(a[a.length-1].type),d=()=>c?Ke.FilterOrPipe:n?Ke.Pipe:i?Ke.Operator:Ke.Filter;a.push({id:a.length,value:s,position:r,type:d(),separator:o})},gp=(t,n)=>{const r=t.value.substring(0,n),a=t.value.substring(n),o={valueBeforeCursor:r,valueAfterCursor:a,valueContext:t.value,contextType:de.Unknown};return fp(t,r,a,o),o.valueContext=o.valueContext.replace(/^["']|["']$/g,""),o},Ri=t=>hp.some(n=>t.startsWith(n)),vp=(t,n)=>!t.includes(":")&&!n.includes(":"),$i=(t,n)=>{const[r,...a]=t.split(":");n.contextType=de.FilterValue,n.filterName=r;const s=["=","-","!","~","<",">","<=",">="].find(i=>i===a[0]);s?(n.valueContext=a.slice(1).join(":"),n.operator=`:${s}`):(n.valueContext=a.join(":"),n.operator=":")},fp=(t,n,r,a)=>{switch(t.type){case Ke.Filter:_p(n,r,a);break;case Ke.Pipe:a.contextType=Ri(t.value)?de.PipeValue:de.PipeName;break;case Ke.FilterOrPipe:bp(t.value,n,a);break}},_p=(t,n,r)=>{vp(t,n)?r.contextType=de.FilterUnknown:t.includes(":")?$i(t,r):r.contextType=de.FilterName},bp=(t,n,r)=>{Ri(t)?r.contextType=de.PipeValue:n.includes(":")?$i(n,r):r.contextType=de.FilterOrPipeName},yp=t=>{if(t.includes("=")){const[n,r]=t.split("=");if(r)return`_stream:${n}=~${r}.*"}`}return"*"},Uo=(t,n)=>{const r=t.lastIndexOf(n);return r!==-1?t.slice(0,r):""},wp=t=>{let n="";return t.valueContext.includes(":")?n=Uo(t.valueContext,":"):t.valueContext.includes("-")&&(n=Uo(t.valueContext,"-")),n?`${t.filterName}:${n}`:"*"},Cp=t=>{let n="";return!t.filterName||!t.query||["_msg","_stream_id"].includes(t.filterName)?n="*":t.filterName==="_stream"?n=yp(t.valueContext):t.filterName==="_time"?n=wp(t):n=`${t.filterName}:${t.valueContext}*`,t.queryBeforeIncompleteFilter?`${t.queryBeforeIncompleteFilter}${t.separator??" "}${n}`:n},Np={[de.FilterName]:e(Fn,{}),[de.FilterUnknown]:e(Fn,{}),[de.FilterValue]:e(zn,{}),[de.PipeName]:e(an,{}),[de.PipeValue]:e(da,{}),[de.Unknown]:e(zn,{}),[de.FilterOrPipeName]:e(an,{})},Sp=t=>{const{serverUrl:n}=se(),{period:{start:r,end:a}}=ge(),{autocompleteCache:o}=ya(),s=Is(),i=dr(),[l,c]=N(!1),[d,m]=N([]),[u,h]=N([]),p=q(new AbortController),v=W(g=>{const _=U(r*1e3).startOf("day").valueOf()/1e3,y=U(a*1e3).endOf("day").valueOf()/1e3;return new URLSearchParams({...g||{},limit:`${Tt.queryLimit}`,start:`${_}`,end:`${y}`})},[r,a]),b=(g,_)=>g.map(y=>({value:y.value,type:`${_}`,icon:Np[_]})),f=async({urlSuffix:g,setter:_,params:y})=>{p.current.abort(),p.current=new AbortController;const{signal:S}=p.current,T=new URLSearchParams(i).toString(),w=`${g}?${y==null?void 0:y.toString()}&${T}`;c(!0);try{const C=o.get(w);if(C){_(C),c(!1);return}const k=await fetch(`${n}/select/logsql/${g}?${y}`,{signal:S,headers:{...i}});if(k.ok){const L=await k.json(),x=(L==null?void 0:L.values)||[];_(x||[]),s({type:"SET_AUTOCOMPLETE_CACHE",payload:{key:w,value:x}})}c(!1)}catch(C){C instanceof Error&&C.name!=="AbortError"&&(s({type:"SET_AUTOCOMPLETE_CACHE",payload:{key:w,value:[]}}),c(!1),console.error(C))}};return A(()=>{const _=![de.FilterName,de.FilterUnknown,de.FilterOrPipeName].includes((t==null?void 0:t.contextType)||de.Unknown);return!n||_?void 0:(m([]),f({urlSuffix:"field_names",setter:S=>{m(b(S,de.FilterName))},params:v({query:(t==null?void 0:t.queryBeforeIncompleteFilter)||"*"})}),()=>{var S;return(S=p.current)==null?void 0:S.abort()})},[n,t]),A(()=>{const g=(t==null?void 0:t.contextType)!==de.FilterValue;return!n||g||!(t!=null&&t.filterName)?void 0:(h([]),f({urlSuffix:"field_values",setter:y=>{h(b(y,de.FilterValue))},params:v({query:Cp(t),field:t.filterName})}),()=>{var y;return(y=p.current)==null?void 0:y.abort()})},[n,t]),{fieldNames:d,fieldValues:u,loading:l}},kp=({value:t,anchorEl:n,caretPosition:r,hasHelperText:a,onSelect:o,onFoundOptions:s})=>{const[i,l]=N({top:0,left:0}),c=M(()=>{if(r[0]!==r[1])return{valueBeforeCursor:t,valueAfterCursor:""};const _=t.substring(0,r[0]),y=t.substring(r[1]);return{valueBeforeCursor:_,valueAfterCursor:y}},[t,r]),d=M(()=>pp(t),[t]),m=M(()=>{if(r[0]!==r[1])return;const _=d.find(w=>r[0]>=w.position[0]&&r[0]<=w.position[1]);if(!_)return;const y=r[0]-_.position[0],S=d.find(w=>w.id===_.id-1),T=S?t.substring(0,S.position[1]+1):void 0;return{..._,queryBeforeIncompleteFilter:T,query:t,...gp(_,y)}},[d,r]),{fieldNames:u,fieldValues:h,loading:p}=Sp(m),v=M(()=>{switch(m==null?void 0:m.contextType){case de.FilterName:case de.FilterUnknown:return u;case de.FilterValue:return h;case de.PipeName:return $r;case de.FilterOrPipeName:return[...u,...$r];default:return[]}},[m,u,h]),b=(_,y,S)=>y.reduce((T,w)=>{const C=w.id===S?_:w.value,k=w.separator==="|"?" | ":" ";return`${T}${k}${C}`},"").trim(),f=(_,y,S="",T)=>{let w=_;if(T===de.FilterName)w+=":";else if(y===de.FilterValue){const C=S.startsWith("_stream:")?w:`${JSON.stringify(w)}`;w=`${(m==null?void 0:m.filterName)||""}${(m==null?void 0:m.operator)||":"}${C}`}return w},g=W((_,y)=>{const{id:S,contextType:T=de.FilterUnknown,value:w="",position:C=[0,0]}=m||{},k=f(_,T,w,y.type),L=b(k,d,S),x=d.find(F=>F.id===S),E=()=>(x==null?void 0:x.type)===Ke.FilterOrPipe||y.type===de.PipeName?1:0,P=(C[0]||1)+k.length+E();o(L,P)},[m,d]);return A(()=>{if(!n.current){l({top:0,left:0});return}const _=n.current.querySelector("textarea")||n.current,y=window.getComputedStyle(_),S=`${y.getPropertyValue("font-size")}`,T=`${y.getPropertyValue("font-family")}`,w=parseInt(`${y.getPropertyValue("line-height")}`),C=document.createElement("div");C.style.font=`${S} ${T}`,C.style.padding=y.getPropertyValue("padding"),C.style.lineHeight=`${w}px`,C.style.width=`${_.offsetWidth}px`,C.style.maxWidth=`${_.offsetWidth}px`,C.style.whiteSpace=y.getPropertyValue("white-space"),C.style.overflowWrap=y.getPropertyValue("overflow-wrap");const k=document.createElement("span");C.appendChild(document.createTextNode(c.valueBeforeCursor||"")),C.appendChild(k),C.appendChild(document.createTextNode(c.valueAfterCursor||"")),document.body.appendChild(C);const L=C.getBoundingClientRect(),x=k.getBoundingClientRect(),E=x.left-L.left,P=x.bottom-L.bottom-(a?w:0);l({top:P,left:E}),C.remove(),k.remove()},[n,r,a,c]),e(V,{children:e(Ea,{loading:p,disabledFullScreen:!0,value:(m==null?void 0:m.valueContext)||"",options:v,anchor:n,minLength:0,offset:i,onSelect:g,onFoundOptions:s,maxDisplayResults:{limit:Tt.displayResults,message:"Please, specify the query more precisely."}})})},Tp=({query:t,limit:n,error:r,isLoading:a,onChange:o,onChangeLimit:s,onRun:i})=>{const{isMobile:l}=J(),{autocomplete:c,queryHistory:d}=xe(),m=Mt(),[u,h]=N(""),[p,v]=N(n),{value:b,setValue:f}=ae(!1),g=w=>{const C=+w;v(C),isNaN(C)||C<0?h("Number must be bigger than zero"):(h(""),s(C))},_=()=>{m({type:"TOGGLE_AUTOCOMPLETE"})};A(()=>{v(n)},[n]);const y=w=>{const{values:C,index:k}=d[0],L=k+w;L<0||L>=C.length||(o(C[L]||""),m({type:"SET_QUERY_HISTORY_BY_INDEX",payload:{value:{values:C,index:L},queryNumber:0}}))},S=w=>{o(w),f(!0)},T=w=>()=>{y(w)};return A(()=>{b&&(i(),f(!1))},[t,b]),e("div",{className:I({"vm-explore-logs-header":!0,"vm-block":!0,"vm-block_mobile":l}),children:[e("div",{className:"vm-explore-logs-header-top",children:[e(Bs,{value:t,autocomplete:c,autocompleteEl:kp,onArrowUp:T(-1),onArrowDown:T(1),onEnter:i,onChange:o,label:"Log query",error:r}),e(ce,{label:"Limit entries",type:"number",value:p,error:u,onChange:g,onEnter:i})]}),e("div",{className:"vm-explore-logs-header-bottom",children:[e("div",{className:"vm-explore-logs-header-bottom-contols",children:e(_e,{label:"Autocomplete",value:c,onChange:_,fullWidth:l})}),e("div",{className:"vm-explore-logs-header-bottom-helpful",children:[e("a",{className:"vm-link vm-link_with-icon",target:"_blank",href:"https://docs.victoriametrics.com/victorialogs/logsql/",rel:"help noreferrer",children:[e(mt,{}),"Query language docs"]}),e("a",{className:"vm-link vm-link_with-icon",target:"_blank",href:"https://docs.victoriametrics.com/victorialogs/",rel:"help noreferrer",children:[e(ut,{}),"Documentation"]})]}),e("div",{className:"vm-explore-logs-header-bottom-buttons",children:[e(Qs,{handleSelectQuery:S,historyKey:"LOGS_QUERY_HISTORY"}),e("div",{className:"vm-explore-logs-header-bottom-execute",children:e(D,{startIcon:a?e(ha,{}):e(nt,{}),onClick:i,fullWidth:!0,children:e("div",{children:[e("span",{className:"vm-explore-logs-header-bottom-execute__text",children:a?"Cancel Query":"Execute Query"}),e("span",{className:"vm-explore-logs-header-bottom-execute__text_hidden",children:"Execute Query"})]})})})]})]})]})},Lp=({onChange:t})=>{const[n,r]=oe(),a=q(null),{value:o,toggle:s,setFalse:i}=ae(!1),[l,c]=Se(!1,"stacked"),[d,m]=Se("true","fill"),[u,h]=Se(!1,"hide_chart"),p=M(()=>({graphStyle:lt.BAR,stacked:l,fill:d==="true",hideChart:u}),[l,d,u]),v=g=>{m(`${g}`),n.set("fill",`${g}`),r(n)},b=g=>{c(g),g?n.set("stacked","true"):n.delete("stacked"),r(n)},f=()=>{h(g=>{const _=!g;return _?n.set("hide_chart","true"):n.delete("hide_chart"),r(n),_})};return A(()=>{t(p)},[p]),e("div",{className:"vm-bar-hits-options",children:[e(j,{title:u?"Show chart and resume hits updates":"Hide chart and pause hits updates",children:e(D,{variant:"text",color:"primary",startIcon:u?e(sa,{}):e(Vt,{}),onClick:f,ariaLabel:"settings"})}),e("div",{ref:a,children:e(j,{title:"Graph settings",children:e(D,{variant:"text",color:"primary",startIcon:e(Ze,{}),onClick:s,ariaLabel:"settings"})})}),e(Ie,{open:o,placement:"bottom-right",onClose:i,buttonRef:a,title:"Graph settings",children:e("div",{className:"vm-bar-hits-options-settings",children:[e("div",{className:"vm-bar-hits-options-settings-item",children:e(_e,{label:"Stacked",value:l,onChange:b})}),e("div",{className:"vm-bar-hits-options-settings-item",children:e(_e,{label:"Fill",value:d==="true",onChange:v})})]})})]})};function Ap(t,n){const r=[];let a=[];const o=t[0].length,s=Array(o);for(let i=0;is[c]+=+(l??0)));for(let i=1;ic>i&&!n(c)),i]});return a=a.filter(i=>i.series[1]>-1),{data:[t[0]].concat(r),bands:a}}const Bo=t=>U(t*1e3).tz().format(qe),Ep=({data:t,focusDataIdx:n,uPlotInst:r})=>{const a=q(null),o=M(()=>{var p,v;const i=(r==null?void 0:r.series)||[],[l,...c]=t.map(b=>b[n]||0),d=t[0][1]-t[0][0],m=l+d,u=c.map((b,f)=>{var T;const g=i[f+1],_=(T=g==null?void 0:g.stroke)==null?void 0:T.call(g),y=g==null?void 0:g.label,S=g==null?void 0:g.show;return{label:y,stroke:_,value:b,show:S}}).filter(b=>b.value>0&&b.show).sort(Di("value"));return{point:{top:u[0]&&((p=r==null?void 0:r.valToPos)==null?void 0:p.call(r,u[0].value,"y"))||0,left:((v=r==null?void 0:r.valToPos)==null?void 0:v.call(r,l,"x"))||0},values:u,total:u.reduce((b,f)=>b+f.value,0),timestamp:`${Bo(l)} - ${Bo(m)}`}},[n,r,t]),s=M(()=>{if(!r||!o.total||!a.current)return;const{top:i,left:l}=o.point,c={left:parseFloat(r.over.style.left),top:parseFloat(r.over.style.top)},{width:d,height:m}=r.over.getBoundingClientRect(),{width:u,height:h}=a.current.getBoundingClientRect(),p=50,v=l+u>=d?u+2*p:0,b=i+h>=m?h+2*p:0,f={top:i+c.top+p-b,left:l+c.left+p-v};return f.left<0&&(f.left=20),f.top<0&&(f.top=20),f},[o,r,a.current]);return e("div",{className:I({"vm-chart-tooltip":!0,"vm-chart-tooltip_hits":!0,"vm-bar-hits-tooltip":!0,"vm-bar-hits-tooltip_visible":n!==-1&&o.values.length}),ref:a,style:s,children:[e("div",{children:o.values.map((i,l)=>e("div",{className:"vm-chart-tooltip-data",children:[e("span",{className:"vm-chart-tooltip-data__marker",style:{background:i.stroke}}),e("p",{className:"vm-bar-hits-tooltip-item",children:[e("span",{className:"vm-bar-hits-tooltip-item__label",children:i.label}),e("span",{children:i.value.toLocaleString("en-US")})]})]},l))}),o.values.length>1&&e("div",{className:"vm-chart-tooltip-data",children:[e("span",{}),e("p",{className:"vm-bar-hits-tooltip-item",children:[e("span",{className:"vm-bar-hits-tooltip-item__label",children:"Total"}),e("span",{children:o.total.toLocaleString("en-US")})]})]}),e("div",{className:"vm-chart-tooltip-header",children:e("div",{className:"vm-chart-tooltip-header__title vm-bar-hits-tooltip__date",children:o.timestamp})})]})},xp=({legend:t})=>{const n=t.total.toLocaleString("en-US"),r=Math.round(t.total/t.totalHits*100);return e("div",{className:"vm-legend-hits-menu-section",children:e("div",{className:"vm-legend-hits-menu-row",children:e("div",{className:"vm-legend-hits-menu-row__title",children:["Total: ",n," (",r,"%)"]})})})},mr=({title:t,handler:n,iconStart:r,iconEnd:a,className:o,submenu:s})=>{const i=q(null),l=q(null),c=q(null),[d,m]=N(!1),[u,h]=N(!1),[p,v]=N(!1),b=!!(s!=null&&s.length),f=()=>{h(S=>!S)},g=()=>{h(!1)},_=()=>{n&&n(),b&&f()};A(()=>{l.current&&m(l.current.scrollWidth>l.current.clientWidth)},[t,l]),A(()=>{requestAnimationFrame(()=>{if(!u||!c.current){v(!1);return}const{left:S,width:T}=c.current.getBoundingClientRect();v(S+T>window.innerWidth)})},[c,u]),_n(i,g);const y=e("div",{ref:l,className:"vm-legend-hits-menu-row__title",children:t});return e("div",{ref:i,className:I({"vm-legend-hits-menu-row":!0,"vm-legend-hits-menu-row_interactive":!!n||b,[`${o}`]:o}),onClick:_,children:[r&&e("div",{className:"vm-legend-hits-menu-row__icon",children:r}),d?e(j,{title:t,children:y}):y,a&&!b&&e("div",{className:"vm-legend-hits-menu-row__icon",children:a}),b&&e("div",{className:"vm-legend-hits-menu-row__icon vm-legend-hits-menu-row__icon_drop",children:e(Je,{})}),u&&s&&e("div",{ref:c,className:I({"vm-legend-hits-menu":!0,"vm-legend-hits-menu_submenu":!0,"vm-legend-hits-menu_submenu_left":p}),children:e("div",{className:"vm-legend-hits-menu-section",children:s.map(({icon:S,title:T,handler:w})=>e(mr,{iconStart:S,title:T,handler:w},T))})})]})},Mp=({legend:t,onApplyFilter:n,onClose:r})=>{const a=Fe(),o=()=>{n(`${Re}: ${t.label}`),r()},s=()=>{n(`(NOT ${Re}: ${t.label})`),r()},i=async()=>{await a(t.label,`${t.label} has been copied`),r()},l=[{title:`Copy ${Re} name`,icon:e(Xe,{}),handler:i},{title:`Add ${Re} to filter`,icon:e(pa,{}),handler:o},{title:`Exclude ${Re} to filter`,icon:e(ga,{}),handler:s}];return e("div",{className:"vm-legend-hits-menu-section",children:l.map(({icon:c,title:d,handler:m})=>e(mr,{iconStart:c,title:d,handler:m},d))})},Ip=({fields:t,onApplyFilter:n,onClose:r})=>{const a=Fe(),o=d=>async()=>{await a(d,`${d} has been copied`),r()},s=d=>()=>{n(d),r()},i=d=>()=>{n(`-${d}`),r()},l=d=>[{title:"Copy",icon:e(Xe,{}),handler:o(d)},{title:"Add to filter",icon:e(pa,{}),handler:s(d)},{title:"Exclude to filter",icon:e(ga,{}),handler:i(d)}],c=M(()=>t.map(d=>{const m=Pi(d);return{title:m,submenu:l(m)}}),[t]);return e("div",{className:"vm-legend-hits-menu-section",children:c==null?void 0:c.map(d=>e(mr,{...d},d.title))})},Pp=`aggregated results for fields not in the top ${pi}`,Dp=({legend:t,fields:n,onApplyFilter:r,onClose:a})=>e("div",{className:"vm-legend-hits-menu",children:[e("div",{className:"vm-legend-hits-menu-section",children:e(mr,{className:"vm-legend-hits-menu-row_info",title:t.isOther?Pp:t.label})}),!t.isOther&&e(Mp,{legend:t,onApplyFilter:r,onClose:a}),!t.isOther&&e(Ip,{fields:n,onApplyFilter:r,onClose:a}),e(xp,{legend:t})]}),Op=({legend:t,series:n,onRedrawGraph:r,onApplyFilter:a})=>{const{value:o,setTrue:s,setFalse:i}=ae(!1),l=q(null),[c,d]=N(null),m=M(()=>n.find(f=>f.label===t.label),[n]),u=M(()=>Mi(t.label),[t.label]),h=u.join(", "),p=Ld(t.total),v=f=>{if(m){if(f.metaKey||f.ctrlKey)m.show=!m.show;else{const g=n.every(_=>_===m||!_.show);n.forEach(_=>{_.show=g||_===m})}r()}},b=f=>{f.preventDefault(),d({top:f.clientY,left:f.clientX}),s()};return e("div",{ref:l,className:I({"vm-bar-hits-legend-item":!0,"vm-bar-hits-legend-item_other":t.isOther,"vm-bar-hits-legend-item_hide":!(m!=null&&m.show)}),onClick:v,onContextMenu:b,children:[e("div",{className:"vm-bar-hits-legend-item__marker",style:{backgroundColor:`${t.stroke}`}}),e("div",{className:"vm-bar-hits-legend-item__label",children:h}),e("span",{className:"vm-bar-hits-legend-item__total",children:["(",p,")"]}),e(Ie,{placement:"fixed",open:o,buttonRef:l,placementPosition:c,onClose:i,children:e(Dp,{legend:t,fields:u,onApplyFilter:a,onClose:i})})]})},Rp=({uPlotInst:t,legendDetails:n,onApplyFilter:r})=>{var c;const[a,o]=N([]),s=((c=n[0])==null?void 0:c.totalHits)||0,i=()=>t.series.filter(d=>d.scale!=="x"),l=()=>{t.redraw()};return A(()=>{t.hooks.draw||(t.hooks.draw=[]),t.hooks.draw.push(()=>{o(i())})},[t]),e("div",{className:"vm-bar-hits-legend",children:[n.map(d=>e(Op,{legend:d,series:a,onRedrawGraph:l,onApplyFilter:r},d.label)),e("div",{className:"vm-bar-hits-legend-info",children:[e("div",{children:["Total hits: ",e("b",{children:s.toLocaleString("en-US")})]}),e("div",{children:[e("code",{children:"L-Click"})," toggles visibility. ",e("code",{children:"R-Click"})," opens menu."]})]})]})},$p=({graphOptions:t,logHits:n,data:r,period:a,setPeriod:o,onApplyFilter:s})=>{const[i,l]=vi(),c=q(null),[d,m]=N(),{xRange:u,setPlotScale:h}=Ua({period:a,setPeriod:o}),{onReadyChart:p,isPanning:v}=Va(h);qa({uPlotInst:d,xRange:u,setPlotScale:h});const{data:b,bands:f}=M(()=>t.stacked?Ap(r,()=>!1):{data:r,bands:[]},[t,r]),{options:g,series:_,focusDataIdx:y}=Lh({data:b,logHits:n,bands:f,xRange:u,containerSize:l,onReadyChart:p,setPlotScale:h,graphOptions:t}),S=W((w,C)=>w.map(k=>{var E;const L=xi(k);return{label:L,isOther:k._isOther,fields:k.fields,total:k.total||0,totalHits:C,stroke:(E=_.find(P=>P.label===L))==null?void 0:E.stroke}}).sort(Di("total")),[_]),T=M(()=>{const w=Ah(n);return S(n,w)},[n,S]);return A(()=>{if(!d)return;const w=new Map(d.series.map(k=>[k.label,k])),C=_.map(k=>{const L=w.get(k.label);return L?{...k,show:L.show}:k});Fa(d),ai(d,C,!0),li(d,C),d.redraw()},[_,d]),A(()=>{d&&(d.delBand(),f.forEach(w=>{d.addBand(w)}),d.redraw())},[f]),A(()=>{if(!c.current)return;const w=new jt(g,b,c.current);return m(w),()=>w.destroy()},[c.current]),A(()=>{d&&(d.scales.x.range=()=>[u.min,u.max],d.redraw())},[u]),A(()=>{d&&(d.setSize(l),d.redraw())},[l]),A(()=>{d&&(d.setData(b),d.redraw())},[b]),e(V,{children:[e("div",{className:I({"vm-bar-hits-chart":!0,"vm-bar-hits-chart_panning":v}),ref:i,children:[e("div",{className:"vm-line-chart__u-plot",ref:c}),e(Ep,{uPlotInst:d,data:r,focusDataIdx:y})]}),d&&e(Rp,{uPlotInst:d,onApplyFilter:s,legendDetails:T})]})},Fp=({logHits:t,data:n,period:r,setPeriod:a,onApplyFilter:o})=>{const[s,i]=N({graphStyle:lt.LINE_STEPPED,stacked:!1,fill:!1,hideChart:!1});return e("div",{className:I({"vm-bar-hits-chart__wrapper":!0,"vm-bar-hits-chart__wrapper_hidden":s.hideChart}),children:[!s.hideChart&&e($p,{logHits:t,data:n,period:r,setPeriod:a,onApplyFilter:o,graphOptions:s}),e(Lp,{onChange:i})]})},zp=({logHits:t,period:n,error:r,isLoading:a,onApplyFilter:o})=>{const{isMobile:s}=J(),i=Be(),[l]=oe(),c=M(()=>l.get("hide_chart"),[l]),d=(v,b)=>v.map(f=>{const g=new Map;return f.timestamps.forEach((_,y)=>{const S=U(_).unix();g.set(S,f.values[y]||null)}),b.map(_=>g.get(_)||null)}),m=W(v=>{const b=[],{start:f,end:g,step:_}=Ii(n),y=Math.ceil(f.diff(v,"milliseconds")/_);let S=v.add(y*_,"milliseconds");S.isBefore(f)&&(S=f.clone());const T=Math.floor(g.diff(S,"milliseconds")/_);for(let w=0;w<=T;w++)b.push(S.add(w*_,"milliseconds").unix());return b},[n]),u=M(()=>{if(!t.length)return[[],[]];const v=m(U(t[0].timestamps[0])),b=d(t,v);return[v,...b]},[t]),h=M(()=>{const v=u.every(g=>g.length===0),b=u[0].length===0,f=u[1].length===0;return c?"Chart hidden. Hits updates paused.":v?`No logs volume available -No volume information available for the current queries and time range.`:b?"No timestamp information available for the current queries and time range.":f?"No value information available for the current queries and time range.":""},[u,c]),p=({from:v,to:b})=>{i({type:"SET_PERIOD",payload:{from:v,to:b}})};return e("section",{className:I({"vm-explore-logs-chart":!0,"vm-block":!0,"vm-block_mobile":s}),children:[a&&e(er,{}),!r&&h&&e("div",{className:"vm-explore-logs-chart__empty",children:e(le,{variant:"info",children:h})}),r&&h&&e("div",{className:"vm-explore-logs-chart__empty",children:e(le,{variant:"error",children:r})}),u&&e(Fp,{logHits:t,data:u,period:n,setPeriod:p,onApplyFilter:o})]})},Hp=(t,n)=>{const r=dr(),[a,o]=N([]),[s,i]=N([]),[l,c]=N(),d=q(new AbortController),m=M(()=>sp(t),[t]),u=(p,v,b)=>{const{start:f,end:g,step:_}=Ii(v);return{signal:b,method:"POST",headers:{...r},body:new URLSearchParams({query:p.trim(),step:`${_}ms`,start:f.toISOString(),end:g.toISOString(),fields_limit:`${pi}`,field:Re})}},h=W(async p=>{d.current.abort(),d.current=new AbortController;const{signal:v}=d.current,b=Date.now();i(f=>({...f,[b]:!0})),c(void 0);try{const f=u(n,p,v),g=await fetch(m,f);if(!g.ok||!g.body){const S=await g.text();c(S),o([]),i(T=>({...T,[b]:!1}));return}const _=await g.json(),y=_==null?void 0:_.hits;y||c("Error: No 'hits' field in response"),o(y.map(Vp).sort(qp))}catch(f){f instanceof Error&&f.name!=="AbortError"&&(c(String(f)),console.error(f),o([]))}i(f=>({...f,[b]:!1}))},[m,n,r]);return A(()=>()=>{d.current.abort()},[]),{logHits:a,isLoading:Object.values(s).some(p=>p),error:l,fetchLogHits:h,abortController:d.current}},Vp=t=>({...t,_isOther:Rm(t.fields)}),qp=(t,n)=>t._isOther!==n._isOther?t._isOther?-1:1:n.total-t.total;function Up(t){const n=q(t);A(()=>{n.current=t},[t]),A(()=>()=>{n.current()},[])}function Bp(t,n=500,r){const a=q(t);a.current=t;const o=M(()=>{const s=ln((...l)=>a.current(...l),n,r),i=(...l)=>{s(...l)};return i.cancel=s.cancel,i.flush=s.flush,i},[n,r]);return Up(()=>{o.cancel()}),o}const jo=Number(Ae("LOGS_LIMIT")),jp=isNaN(jo)?lm:jo,Qp=()=>{const{serverUrl:t}=se(),{queryHistory:n}=xe(),r=Mt(),{duration:a,relativeTime:o,period:s}=ge(),{setSearchParamsFromKeys:i}=rt(),[l]=oe(),c=M(()=>l.get("hide_chart"),[l]),d=qt(c),[m,u]=Se(jp,"limit"),[h,p]=Se("*","query"),v=()=>{const K=is(h,n[0]);r({type:"SET_QUERY_HISTORY",payload:{key:"LOGS_QUERY_HISTORY",history:[K]}})},[b,f]=N(!1),[g,_]=N(s),[y,S]=N(""),{logs:T,isLoading:w,error:C,fetchLogs:k,abortController:L}=ip(t,h,m),{fetchLogHits:x,...E}=Hp(t,h),F=Bp((K,re)=>{k(K).then(Q=>{Q&&re&&x(K)}).catch(()=>{})},300),O=()=>{const K=nn.find(ie=>ie.id===o);if(!K)return s;const{duration:re,until:Q}=K;return Nt(re,Q())},H=()=>{if(!h){S(Ce.validQuery);return}S("");const K=O();_(K),F(K,!c),i({query:h,"g0.range_input":a,"g0.end_input":K.date,"g0.relative_time":o||"none"}),v()},z=K=>{u(K),i({limit:K}),Le("LOGS_LIMIT",`${K}`)},Y=K=>{p(re=>`${K} AND (${re})`),f(!0)},G=()=>{var K,re,Q;w||E.isLoading?((K=L.abort)==null||K.call(L),(Q=(re=E.abortController).abort)==null||Q.call(re)):H()};return A(()=>{h&&H()},[s]),A(()=>{b&&(H(),f(!1))},[h,b]),A(()=>{!c&&d&&x(g)},[c,d,g]),e("div",{className:"vm-explore-logs",children:[e(Tp,{query:h,error:y,limit:m,onChange:p,onChangeLimit:z,onRun:G,isLoading:w||E.isLoading}),C&&e(le,{variant:"error",children:C}),!C&&e(zp,{...E,query:h,period:g,onApplyFilter:Y}),e(ap,{data:T,isLoading:w})]})},Yp=()=>{const t=Ee(),{isMobile:n}=J(),r=Be(),[a,o]=oe(),[s,i]=Se("0","accountID"),[l,c]=Se("0","projectID"),d=`${s}:${l}`,m=q(null),{value:u,toggle:h,setFalse:p}=ae(!1),v=()=>{a.set("accountID",s),a.set("projectID",l),o(a),p(),r({type:"RUN_QUERY"})},b=()=>{i(a.get("accountID")||"0"),c(a.get("projectID")||"0")};return A(()=>{u||b()},[u]),e("div",{className:"vm-tenant-input",children:[e(j,{title:"Define Tenant ID if you need request to another storage",children:e("div",{ref:m,children:n?e("div",{className:"vm-mobile-option",onClick:h,children:[e("span",{className:"vm-mobile-option__icon",children:e(Lt,{})}),e("div",{className:"vm-mobile-option-text",children:[e("span",{className:"vm-mobile-option-text__label",children:"Tenant ID"}),e("span",{className:"vm-mobile-option-text__value",children:d})]}),e("span",{className:"vm-mobile-option__arrow",children:e(be,{})})]}):e(D,{className:t?"":"vm-header-button",variant:"contained",color:"primary",fullWidth:!0,startIcon:e(Lt,{}),endIcon:e("div",{className:I({"vm-execution-controls-buttons__arrow":!0,"vm-execution-controls-buttons__arrow_open":u}),children:e(be,{})}),onClick:h,children:d})})}),e(Ie,{open:u,placement:"bottom-right",onClose:p,buttonRef:m,title:n?"Define Tenant ID":void 0,children:e("div",{className:I({"vm-list vm-tenant-input-list":!0,"vm-list vm-tenant-input-list_mobile":n,"vm-tenant-input-list_inline":!0}),children:[e(ce,{autofocus:!0,label:"accountID",value:s,onChange:i,type:"number"}),e(ce,{autofocus:!0,label:"projectID",value:l,onChange:c,type:"number"}),e("div",{className:"vm-tenant-input-list__buttons",children:[e(j,{title:"Multitenancy in VictoriaLogs documentation",children:e("a",{href:"https://docs.victoriametrics.com/victorialogs/#multitenancy",target:"_blank",rel:"help noreferrer",children:e(D,{variant:"text",color:"gray",startIcon:e(la,{})})})}),e(D,{variant:"contained",color:"primary",onClick:v,children:"Apply"})]})]})})]})},Gp=({isMobile:t})=>e("div",{className:I({"vm-header-controls":!0,"vm-header-controls_mobile":t}),children:[e(Yp,{}),e(ka,{}),e(Ta,{}),e(La,{})]}),Wp=()=>{const t=Ee(),{isMobile:n}=J(),{pathname:r}=ht();return Aa(),A(()=>{var i;const o="vmui for VictoriaLogs",s=(i=gt[Z.logs])==null?void 0:i.title;document.title=`${s} - ${o}`},[r]),e("section",{className:"vm-container",children:[e(Na,{controlsComponent:Gp}),e("div",{className:I({"vm-container-body":!0,"vm-container-body_mobile":n,"vm-container-body_app":t}),children:e(Vr,{})}),!t&&e(Sa,{links:wc})]})},Jp={100:"💯",1234:"🔢",grinning:"😀",smiley:"😃",smile:"😄",grin:"😁",laughing:"😆",satisfied:"😆",sweat_smile:"😅",rofl:"🤣",joy:"😂",slightly_smiling_face:"🙂",upside_down_face:"🙃",melting_face:"🫠",wink:"😉",blush:"😊",innocent:"😇",smiling_face_with_three_hearts:"🥰",heart_eyes:"😍",star_struck:"🤩",kissing_heart:"😘",kissing:"😗",relaxed:"☺️",kissing_closed_eyes:"😚",kissing_smiling_eyes:"😙",smiling_face_with_tear:"🥲",yum:"😋",stuck_out_tongue:"😛",stuck_out_tongue_winking_eye:"😜",zany_face:"🤪",stuck_out_tongue_closed_eyes:"😝",money_mouth_face:"🤑",hugs:"🤗",hand_over_mouth:"🤭",face_with_open_eyes_and_hand_over_mouth:"🫢",face_with_peeking_eye:"🫣",shushing_face:"🤫",thinking:"🤔",saluting_face:"🫡",zipper_mouth_face:"🤐",raised_eyebrow:"🤨",neutral_face:"😐",expressionless:"😑",no_mouth:"😶",dotted_line_face:"🫥",face_in_clouds:"😶‍🌫️",smirk:"😏",unamused:"😒",roll_eyes:"🙄",grimacing:"😬",face_exhaling:"😮‍💨",lying_face:"🤥",shaking_face:"🫨",relieved:"😌",pensive:"😔",sleepy:"😪",drooling_face:"🤤",sleeping:"😴",mask:"😷",face_with_thermometer:"🤒",face_with_head_bandage:"🤕",nauseated_face:"🤢",vomiting_face:"🤮",sneezing_face:"🤧",hot_face:"🥵",cold_face:"🥶",woozy_face:"🥴",dizzy_face:"😵",face_with_spiral_eyes:"😵‍💫",exploding_head:"🤯",cowboy_hat_face:"🤠",partying_face:"🥳",disguised_face:"🥸",sunglasses:"😎",nerd_face:"🤓",monocle_face:"🧐",confused:"😕",face_with_diagonal_mouth:"🫤",worried:"😟",slightly_frowning_face:"🙁",frowning_face:"☹️",open_mouth:"😮",hushed:"😯",astonished:"😲",flushed:"😳",pleading_face:"🥺",face_holding_back_tears:"🥹",frowning:"😦",anguished:"😧",fearful:"😨",cold_sweat:"😰",disappointed_relieved:"😥",cry:"😢",sob:"😭",scream:"😱",confounded:"😖",persevere:"😣",disappointed:"😞",sweat:"😓",weary:"😩",tired_face:"😫",yawning_face:"🥱",triumph:"😤",rage:"😡",pout:"😡",angry:"😠",cursing_face:"🤬",smiling_imp:"😈",imp:"👿",skull:"💀",skull_and_crossbones:"☠️",hankey:"💩",poop:"💩",shit:"💩",clown_face:"🤡",japanese_ogre:"👹",japanese_goblin:"👺",ghost:"👻",alien:"👽",space_invader:"👾",robot:"🤖",smiley_cat:"😺",smile_cat:"😸",joy_cat:"😹",heart_eyes_cat:"😻",smirk_cat:"😼",kissing_cat:"😽",scream_cat:"🙀",crying_cat_face:"😿",pouting_cat:"😾",see_no_evil:"🙈",hear_no_evil:"🙉",speak_no_evil:"🙊",love_letter:"💌",cupid:"💘",gift_heart:"💝",sparkling_heart:"💖",heartpulse:"💗",heartbeat:"💓",revolving_hearts:"💞",two_hearts:"💕",heart_decoration:"💟",heavy_heart_exclamation:"❣️",broken_heart:"💔",heart_on_fire:"❤️‍🔥",mending_heart:"❤️‍🩹",heart:"❤️",pink_heart:"🩷",orange_heart:"🧡",yellow_heart:"💛",green_heart:"💚",blue_heart:"💙",light_blue_heart:"🩵",purple_heart:"💜",brown_heart:"🤎",black_heart:"🖤",grey_heart:"🩶",white_heart:"🤍",kiss:"💋",anger:"💢",boom:"💥",collision:"💥",dizzy:"💫",sweat_drops:"💦",dash:"💨",hole:"🕳️",speech_balloon:"💬",eye_speech_bubble:"👁️‍🗨️",left_speech_bubble:"🗨️",right_anger_bubble:"🗯️",thought_balloon:"💭",zzz:"💤",wave:"👋",raised_back_of_hand:"🤚",raised_hand_with_fingers_splayed:"🖐️",hand:"✋",raised_hand:"✋",vulcan_salute:"🖖",rightwards_hand:"🫱",leftwards_hand:"🫲",palm_down_hand:"🫳",palm_up_hand:"🫴",leftwards_pushing_hand:"🫷",rightwards_pushing_hand:"🫸",ok_hand:"👌",pinched_fingers:"🤌",pinching_hand:"🤏",v:"✌️",crossed_fingers:"🤞",hand_with_index_finger_and_thumb_crossed:"🫰",love_you_gesture:"🤟",metal:"🤘",call_me_hand:"🤙",point_left:"👈",point_right:"👉",point_up_2:"👆",middle_finger:"🖕",fu:"🖕",point_down:"👇",point_up:"☝️",index_pointing_at_the_viewer:"🫵","+1":"👍",thumbsup:"👍","-1":"👎",thumbsdown:"👎",fist_raised:"✊",fist:"✊",fist_oncoming:"👊",facepunch:"👊",punch:"👊",fist_left:"🤛",fist_right:"🤜",clap:"👏",raised_hands:"🙌",heart_hands:"🫶",open_hands:"👐",palms_up_together:"🤲",handshake:"🤝",pray:"🙏",writing_hand:"✍️",nail_care:"💅",selfie:"🤳",muscle:"💪",mechanical_arm:"🦾",mechanical_leg:"🦿",leg:"🦵",foot:"🦶",ear:"👂",ear_with_hearing_aid:"🦻",nose:"👃",brain:"🧠",anatomical_heart:"🫀",lungs:"🫁",tooth:"🦷",bone:"🦴",eyes:"👀",eye:"👁️",tongue:"👅",lips:"👄",biting_lip:"🫦",baby:"👶",child:"🧒",boy:"👦",girl:"👧",adult:"🧑",blond_haired_person:"👱",man:"👨",bearded_person:"🧔",man_beard:"🧔‍♂️",woman_beard:"🧔‍♀️",red_haired_man:"👨‍🦰",curly_haired_man:"👨‍🦱",white_haired_man:"👨‍🦳",bald_man:"👨‍🦲",woman:"👩",red_haired_woman:"👩‍🦰",person_red_hair:"🧑‍🦰",curly_haired_woman:"👩‍🦱",person_curly_hair:"🧑‍🦱",white_haired_woman:"👩‍🦳",person_white_hair:"🧑‍🦳",bald_woman:"👩‍🦲",person_bald:"🧑‍🦲",blond_haired_woman:"👱‍♀️",blonde_woman:"👱‍♀️",blond_haired_man:"👱‍♂️",older_adult:"🧓",older_man:"👴",older_woman:"👵",frowning_person:"🙍",frowning_man:"🙍‍♂️",frowning_woman:"🙍‍♀️",pouting_face:"🙎",pouting_man:"🙎‍♂️",pouting_woman:"🙎‍♀️",no_good:"🙅",no_good_man:"🙅‍♂️",ng_man:"🙅‍♂️",no_good_woman:"🙅‍♀️",ng_woman:"🙅‍♀️",ok_person:"🙆",ok_man:"🙆‍♂️",ok_woman:"🙆‍♀️",tipping_hand_person:"💁",information_desk_person:"💁",tipping_hand_man:"💁‍♂️",sassy_man:"💁‍♂️",tipping_hand_woman:"💁‍♀️",sassy_woman:"💁‍♀️",raising_hand:"🙋",raising_hand_man:"🙋‍♂️",raising_hand_woman:"🙋‍♀️",deaf_person:"🧏",deaf_man:"🧏‍♂️",deaf_woman:"🧏‍♀️",bow:"🙇",bowing_man:"🙇‍♂️",bowing_woman:"🙇‍♀️",facepalm:"🤦",man_facepalming:"🤦‍♂️",woman_facepalming:"🤦‍♀️",shrug:"🤷",man_shrugging:"🤷‍♂️",woman_shrugging:"🤷‍♀️",health_worker:"🧑‍⚕️",man_health_worker:"👨‍⚕️",woman_health_worker:"👩‍⚕️",student:"🧑‍🎓",man_student:"👨‍🎓",woman_student:"👩‍🎓",teacher:"🧑‍🏫",man_teacher:"👨‍🏫",woman_teacher:"👩‍🏫",judge:"🧑‍⚖️",man_judge:"👨‍⚖️",woman_judge:"👩‍⚖️",farmer:"🧑‍🌾",man_farmer:"👨‍🌾",woman_farmer:"👩‍🌾",cook:"🧑‍🍳",man_cook:"👨‍🍳",woman_cook:"👩‍🍳",mechanic:"🧑‍🔧",man_mechanic:"👨‍🔧",woman_mechanic:"👩‍🔧",factory_worker:"🧑‍🏭",man_factory_worker:"👨‍🏭",woman_factory_worker:"👩‍🏭",office_worker:"🧑‍💼",man_office_worker:"👨‍💼",woman_office_worker:"👩‍💼",scientist:"🧑‍🔬",man_scientist:"👨‍🔬",woman_scientist:"👩‍🔬",technologist:"🧑‍💻",man_technologist:"👨‍💻",woman_technologist:"👩‍💻",singer:"🧑‍🎤",man_singer:"👨‍🎤",woman_singer:"👩‍🎤",artist:"🧑‍🎨",man_artist:"👨‍🎨",woman_artist:"👩‍🎨",pilot:"🧑‍✈️",man_pilot:"👨‍✈️",woman_pilot:"👩‍✈️",astronaut:"🧑‍🚀",man_astronaut:"👨‍🚀",woman_astronaut:"👩‍🚀",firefighter:"🧑‍🚒",man_firefighter:"👨‍🚒",woman_firefighter:"👩‍🚒",police_officer:"👮",cop:"👮",policeman:"👮‍♂️",policewoman:"👮‍♀️",detective:"🕵️",male_detective:"🕵️‍♂️",female_detective:"🕵️‍♀️",guard:"💂",guardsman:"💂‍♂️",guardswoman:"💂‍♀️",ninja:"🥷",construction_worker:"👷",construction_worker_man:"👷‍♂️",construction_worker_woman:"👷‍♀️",person_with_crown:"🫅",prince:"🤴",princess:"👸",person_with_turban:"👳",man_with_turban:"👳‍♂️",woman_with_turban:"👳‍♀️",man_with_gua_pi_mao:"👲",woman_with_headscarf:"🧕",person_in_tuxedo:"🤵",man_in_tuxedo:"🤵‍♂️",woman_in_tuxedo:"🤵‍♀️",person_with_veil:"👰",man_with_veil:"👰‍♂️",woman_with_veil:"👰‍♀️",bride_with_veil:"👰‍♀️",pregnant_woman:"🤰",pregnant_man:"🫃",pregnant_person:"🫄",breast_feeding:"🤱",woman_feeding_baby:"👩‍🍼",man_feeding_baby:"👨‍🍼",person_feeding_baby:"🧑‍🍼",angel:"👼",santa:"🎅",mrs_claus:"🤶",mx_claus:"🧑‍🎄",superhero:"🦸",superhero_man:"🦸‍♂️",superhero_woman:"🦸‍♀️",supervillain:"🦹",supervillain_man:"🦹‍♂️",supervillain_woman:"🦹‍♀️",mage:"🧙",mage_man:"🧙‍♂️",mage_woman:"🧙‍♀️",fairy:"🧚",fairy_man:"🧚‍♂️",fairy_woman:"🧚‍♀️",vampire:"🧛",vampire_man:"🧛‍♂️",vampire_woman:"🧛‍♀️",merperson:"🧜",merman:"🧜‍♂️",mermaid:"🧜‍♀️",elf:"🧝",elf_man:"🧝‍♂️",elf_woman:"🧝‍♀️",genie:"🧞",genie_man:"🧞‍♂️",genie_woman:"🧞‍♀️",zombie:"🧟",zombie_man:"🧟‍♂️",zombie_woman:"🧟‍♀️",troll:"🧌",massage:"💆",massage_man:"💆‍♂️",massage_woman:"💆‍♀️",haircut:"💇",haircut_man:"💇‍♂️",haircut_woman:"💇‍♀️",walking:"🚶",walking_man:"🚶‍♂️",walking_woman:"🚶‍♀️",standing_person:"🧍",standing_man:"🧍‍♂️",standing_woman:"🧍‍♀️",kneeling_person:"🧎",kneeling_man:"🧎‍♂️",kneeling_woman:"🧎‍♀️",person_with_probing_cane:"🧑‍🦯",man_with_probing_cane:"👨‍🦯",woman_with_probing_cane:"👩‍🦯",person_in_motorized_wheelchair:"🧑‍🦼",man_in_motorized_wheelchair:"👨‍🦼",woman_in_motorized_wheelchair:"👩‍🦼",person_in_manual_wheelchair:"🧑‍🦽",man_in_manual_wheelchair:"👨‍🦽",woman_in_manual_wheelchair:"👩‍🦽",runner:"🏃",running:"🏃",running_man:"🏃‍♂️",running_woman:"🏃‍♀️",woman_dancing:"💃",dancer:"💃",man_dancing:"🕺",business_suit_levitating:"🕴️",dancers:"👯",dancing_men:"👯‍♂️",dancing_women:"👯‍♀️",sauna_person:"🧖",sauna_man:"🧖‍♂️",sauna_woman:"🧖‍♀️",climbing:"🧗",climbing_man:"🧗‍♂️",climbing_woman:"🧗‍♀️",person_fencing:"🤺",horse_racing:"🏇",skier:"⛷️",snowboarder:"🏂",golfing:"🏌️",golfing_man:"🏌️‍♂️",golfing_woman:"🏌️‍♀️",surfer:"🏄",surfing_man:"🏄‍♂️",surfing_woman:"🏄‍♀️",rowboat:"🚣",rowing_man:"🚣‍♂️",rowing_woman:"🚣‍♀️",swimmer:"🏊",swimming_man:"🏊‍♂️",swimming_woman:"🏊‍♀️",bouncing_ball_person:"⛹️",bouncing_ball_man:"⛹️‍♂️",basketball_man:"⛹️‍♂️",bouncing_ball_woman:"⛹️‍♀️",basketball_woman:"⛹️‍♀️",weight_lifting:"🏋️",weight_lifting_man:"🏋️‍♂️",weight_lifting_woman:"🏋️‍♀️",bicyclist:"🚴",biking_man:"🚴‍♂️",biking_woman:"🚴‍♀️",mountain_bicyclist:"🚵",mountain_biking_man:"🚵‍♂️",mountain_biking_woman:"🚵‍♀️",cartwheeling:"🤸",man_cartwheeling:"🤸‍♂️",woman_cartwheeling:"🤸‍♀️",wrestling:"🤼",men_wrestling:"🤼‍♂️",women_wrestling:"🤼‍♀️",water_polo:"🤽",man_playing_water_polo:"🤽‍♂️",woman_playing_water_polo:"🤽‍♀️",handball_person:"🤾",man_playing_handball:"🤾‍♂️",woman_playing_handball:"🤾‍♀️",juggling_person:"🤹",man_juggling:"🤹‍♂️",woman_juggling:"🤹‍♀️",lotus_position:"🧘",lotus_position_man:"🧘‍♂️",lotus_position_woman:"🧘‍♀️",bath:"🛀",sleeping_bed:"🛌",people_holding_hands:"🧑‍🤝‍🧑",two_women_holding_hands:"👭",couple:"👫",two_men_holding_hands:"👬",couplekiss:"💏",couplekiss_man_woman:"👩‍❤️‍💋‍👨",couplekiss_man_man:"👨‍❤️‍💋‍👨",couplekiss_woman_woman:"👩‍❤️‍💋‍👩",couple_with_heart:"💑",couple_with_heart_woman_man:"👩‍❤️‍👨",couple_with_heart_man_man:"👨‍❤️‍👨",couple_with_heart_woman_woman:"👩‍❤️‍👩",family:"👪",family_man_woman_boy:"👨‍👩‍👦",family_man_woman_girl:"👨‍👩‍👧",family_man_woman_girl_boy:"👨‍👩‍👧‍👦",family_man_woman_boy_boy:"👨‍👩‍👦‍👦",family_man_woman_girl_girl:"👨‍👩‍👧‍👧",family_man_man_boy:"👨‍👨‍👦",family_man_man_girl:"👨‍👨‍👧",family_man_man_girl_boy:"👨‍👨‍👧‍👦",family_man_man_boy_boy:"👨‍👨‍👦‍👦",family_man_man_girl_girl:"👨‍👨‍👧‍👧",family_woman_woman_boy:"👩‍👩‍👦",family_woman_woman_girl:"👩‍👩‍👧",family_woman_woman_girl_boy:"👩‍👩‍👧‍👦",family_woman_woman_boy_boy:"👩‍👩‍👦‍👦",family_woman_woman_girl_girl:"👩‍👩‍👧‍👧",family_man_boy:"👨‍👦",family_man_boy_boy:"👨‍👦‍👦",family_man_girl:"👨‍👧",family_man_girl_boy:"👨‍👧‍👦",family_man_girl_girl:"👨‍👧‍👧",family_woman_boy:"👩‍👦",family_woman_boy_boy:"👩‍👦‍👦",family_woman_girl:"👩‍👧",family_woman_girl_boy:"👩‍👧‍👦",family_woman_girl_girl:"👩‍👧‍👧",speaking_head:"🗣️",bust_in_silhouette:"👤",busts_in_silhouette:"👥",people_hugging:"🫂",footprints:"👣",monkey_face:"🐵",monkey:"🐒",gorilla:"🦍",orangutan:"🦧",dog:"🐶",dog2:"🐕",guide_dog:"🦮",service_dog:"🐕‍🦺",poodle:"🐩",wolf:"🐺",fox_face:"🦊",raccoon:"🦝",cat:"🐱",cat2:"🐈",black_cat:"🐈‍⬛",lion:"🦁",tiger:"🐯",tiger2:"🐅",leopard:"🐆",horse:"🐴",moose:"🫎",donkey:"🫏",racehorse:"🐎",unicorn:"🦄",zebra:"🦓",deer:"🦌",bison:"🦬",cow:"🐮",ox:"🐂",water_buffalo:"🐃",cow2:"🐄",pig:"🐷",pig2:"🐖",boar:"🐗",pig_nose:"🐽",ram:"🐏",sheep:"🐑",goat:"🐐",dromedary_camel:"🐪",camel:"🐫",llama:"🦙",giraffe:"🦒",elephant:"🐘",mammoth:"🦣",rhinoceros:"🦏",hippopotamus:"🦛",mouse:"🐭",mouse2:"🐁",rat:"🐀",hamster:"🐹",rabbit:"🐰",rabbit2:"🐇",chipmunk:"🐿️",beaver:"🦫",hedgehog:"🦔",bat:"🦇",bear:"🐻",polar_bear:"🐻‍❄️",koala:"🐨",panda_face:"🐼",sloth:"🦥",otter:"🦦",skunk:"🦨",kangaroo:"🦘",badger:"🦡",feet:"🐾",paw_prints:"🐾",turkey:"🦃",chicken:"🐔",rooster:"🐓",hatching_chick:"🐣",baby_chick:"🐤",hatched_chick:"🐥",bird:"🐦",penguin:"🐧",dove:"🕊️",eagle:"🦅",duck:"🦆",swan:"🦢",owl:"🦉",dodo:"🦤",feather:"🪶",flamingo:"🦩",peacock:"🦚",parrot:"🦜",wing:"🪽",black_bird:"🐦‍⬛",goose:"🪿",frog:"🐸",crocodile:"🐊",turtle:"🐢",lizard:"🦎",snake:"🐍",dragon_face:"🐲",dragon:"🐉",sauropod:"🦕","t-rex":"🦖",whale:"🐳",whale2:"🐋",dolphin:"🐬",flipper:"🐬",seal:"🦭",fish:"🐟",tropical_fish:"🐠",blowfish:"🐡",shark:"🦈",octopus:"🐙",shell:"🐚",coral:"🪸",jellyfish:"🪼",snail:"🐌",butterfly:"🦋",bug:"🐛",ant:"🐜",bee:"🐝",honeybee:"🐝",beetle:"🪲",lady_beetle:"🐞",cricket:"🦗",cockroach:"🪳",spider:"🕷️",spider_web:"🕸️",scorpion:"🦂",mosquito:"🦟",fly:"🪰",worm:"🪱",microbe:"🦠",bouquet:"💐",cherry_blossom:"🌸",white_flower:"💮",lotus:"🪷",rosette:"🏵️",rose:"🌹",wilted_flower:"🥀",hibiscus:"🌺",sunflower:"🌻",blossom:"🌼",tulip:"🌷",hyacinth:"🪻",seedling:"🌱",potted_plant:"🪴",evergreen_tree:"🌲",deciduous_tree:"🌳",palm_tree:"🌴",cactus:"🌵",ear_of_rice:"🌾",herb:"🌿",shamrock:"☘️",four_leaf_clover:"🍀",maple_leaf:"🍁",fallen_leaf:"🍂",leaves:"🍃",empty_nest:"🪹",nest_with_eggs:"🪺",mushroom:"🍄",grapes:"🍇",melon:"🍈",watermelon:"🍉",tangerine:"🍊",orange:"🍊",mandarin:"🍊",lemon:"🍋",banana:"🍌",pineapple:"🍍",mango:"🥭",apple:"🍎",green_apple:"🍏",pear:"🍐",peach:"🍑",cherries:"🍒",strawberry:"🍓",blueberries:"🫐",kiwi_fruit:"🥝",tomato:"🍅",olive:"🫒",coconut:"🥥",avocado:"🥑",eggplant:"🍆",potato:"🥔",carrot:"🥕",corn:"🌽",hot_pepper:"🌶️",bell_pepper:"🫑",cucumber:"🥒",leafy_green:"🥬",broccoli:"🥦",garlic:"🧄",onion:"🧅",peanuts:"🥜",beans:"🫘",chestnut:"🌰",ginger_root:"🫚",pea_pod:"🫛",bread:"🍞",croissant:"🥐",baguette_bread:"🥖",flatbread:"🫓",pretzel:"🥨",bagel:"🥯",pancakes:"🥞",waffle:"🧇",cheese:"🧀",meat_on_bone:"🍖",poultry_leg:"🍗",cut_of_meat:"🥩",bacon:"🥓",hamburger:"🍔",fries:"🍟",pizza:"🍕",hotdog:"🌭",sandwich:"🥪",taco:"🌮",burrito:"🌯",tamale:"🫔",stuffed_flatbread:"🥙",falafel:"🧆",egg:"🥚",fried_egg:"🍳",shallow_pan_of_food:"🥘",stew:"🍲",fondue:"🫕",bowl_with_spoon:"🥣",green_salad:"🥗",popcorn:"🍿",butter:"🧈",salt:"🧂",canned_food:"🥫",bento:"🍱",rice_cracker:"🍘",rice_ball:"🍙",rice:"🍚",curry:"🍛",ramen:"🍜",spaghetti:"🍝",sweet_potato:"🍠",oden:"🍢",sushi:"🍣",fried_shrimp:"🍤",fish_cake:"🍥",moon_cake:"🥮",dango:"🍡",dumpling:"🥟",fortune_cookie:"🥠",takeout_box:"🥡",crab:"🦀",lobster:"🦞",shrimp:"🦐",squid:"🦑",oyster:"🦪",icecream:"🍦",shaved_ice:"🍧",ice_cream:"🍨",doughnut:"🍩",cookie:"🍪",birthday:"🎂",cake:"🍰",cupcake:"🧁",pie:"🥧",chocolate_bar:"🍫",candy:"🍬",lollipop:"🍭",custard:"🍮",honey_pot:"🍯",baby_bottle:"🍼",milk_glass:"🥛",coffee:"☕",teapot:"🫖",tea:"🍵",sake:"🍶",champagne:"🍾",wine_glass:"🍷",cocktail:"🍸",tropical_drink:"🍹",beer:"🍺",beers:"🍻",clinking_glasses:"🥂",tumbler_glass:"🥃",pouring_liquid:"🫗",cup_with_straw:"🥤",bubble_tea:"🧋",beverage_box:"🧃",mate:"🧉",ice_cube:"🧊",chopsticks:"🥢",plate_with_cutlery:"🍽️",fork_and_knife:"🍴",spoon:"🥄",hocho:"🔪",knife:"🔪",jar:"🫙",amphora:"🏺",earth_africa:"🌍",earth_americas:"🌎",earth_asia:"🌏",globe_with_meridians:"🌐",world_map:"🗺️",japan:"🗾",compass:"🧭",mountain_snow:"🏔️",mountain:"⛰️",volcano:"🌋",mount_fuji:"🗻",camping:"🏕️",beach_umbrella:"🏖️",desert:"🏜️",desert_island:"🏝️",national_park:"🏞️",stadium:"🏟️",classical_building:"🏛️",building_construction:"🏗️",bricks:"🧱",rock:"🪨",wood:"🪵",hut:"🛖",houses:"🏘️",derelict_house:"🏚️",house:"🏠",house_with_garden:"🏡",office:"🏢",post_office:"🏣",european_post_office:"🏤",hospital:"🏥",bank:"🏦",hotel:"🏨",love_hotel:"🏩",convenience_store:"🏪",school:"🏫",department_store:"🏬",factory:"🏭",japanese_castle:"🏯",european_castle:"🏰",wedding:"💒",tokyo_tower:"🗼",statue_of_liberty:"🗽",church:"⛪",mosque:"🕌",hindu_temple:"🛕",synagogue:"🕍",shinto_shrine:"⛩️",kaaba:"🕋",fountain:"⛲",tent:"⛺",foggy:"🌁",night_with_stars:"🌃",cityscape:"🏙️",sunrise_over_mountains:"🌄",sunrise:"🌅",city_sunset:"🌆",city_sunrise:"🌇",bridge_at_night:"🌉",hotsprings:"♨️",carousel_horse:"🎠",playground_slide:"🛝",ferris_wheel:"🎡",roller_coaster:"🎢",barber:"💈",circus_tent:"🎪",steam_locomotive:"🚂",railway_car:"🚃",bullettrain_side:"🚄",bullettrain_front:"🚅",train2:"🚆",metro:"🚇",light_rail:"🚈",station:"🚉",tram:"🚊",monorail:"🚝",mountain_railway:"🚞",train:"🚋",bus:"🚌",oncoming_bus:"🚍",trolleybus:"🚎",minibus:"🚐",ambulance:"🚑",fire_engine:"🚒",police_car:"🚓",oncoming_police_car:"🚔",taxi:"🚕",oncoming_taxi:"🚖",car:"🚗",red_car:"🚗",oncoming_automobile:"🚘",blue_car:"🚙",pickup_truck:"🛻",truck:"🚚",articulated_lorry:"🚛",tractor:"🚜",racing_car:"🏎️",motorcycle:"🏍️",motor_scooter:"🛵",manual_wheelchair:"🦽",motorized_wheelchair:"🦼",auto_rickshaw:"🛺",bike:"🚲",kick_scooter:"🛴",skateboard:"🛹",roller_skate:"🛼",busstop:"🚏",motorway:"🛣️",railway_track:"🛤️",oil_drum:"🛢️",fuelpump:"⛽",wheel:"🛞",rotating_light:"🚨",traffic_light:"🚥",vertical_traffic_light:"🚦",stop_sign:"🛑",construction:"🚧",anchor:"⚓",ring_buoy:"🛟",boat:"⛵",sailboat:"⛵",canoe:"🛶",speedboat:"🚤",passenger_ship:"🛳️",ferry:"⛴️",motor_boat:"🛥️",ship:"🚢",airplane:"✈️",small_airplane:"🛩️",flight_departure:"🛫",flight_arrival:"🛬",parachute:"🪂",seat:"💺",helicopter:"🚁",suspension_railway:"🚟",mountain_cableway:"🚠",aerial_tramway:"🚡",artificial_satellite:"🛰️",rocket:"🚀",flying_saucer:"🛸",bellhop_bell:"🛎️",luggage:"🧳",hourglass:"⌛",hourglass_flowing_sand:"⏳",watch:"⌚",alarm_clock:"⏰",stopwatch:"⏱️",timer_clock:"⏲️",mantelpiece_clock:"🕰️",clock12:"🕛",clock1230:"🕧",clock1:"🕐",clock130:"🕜",clock2:"🕑",clock230:"🕝",clock3:"🕒",clock330:"🕞",clock4:"🕓",clock430:"🕟",clock5:"🕔",clock530:"🕠",clock6:"🕕",clock630:"🕡",clock7:"🕖",clock730:"🕢",clock8:"🕗",clock830:"🕣",clock9:"🕘",clock930:"🕤",clock10:"🕙",clock1030:"🕥",clock11:"🕚",clock1130:"🕦",new_moon:"🌑",waxing_crescent_moon:"🌒",first_quarter_moon:"🌓",moon:"🌔",waxing_gibbous_moon:"🌔",full_moon:"🌕",waning_gibbous_moon:"🌖",last_quarter_moon:"🌗",waning_crescent_moon:"🌘",crescent_moon:"🌙",new_moon_with_face:"🌚",first_quarter_moon_with_face:"🌛",last_quarter_moon_with_face:"🌜",thermometer:"🌡️",sunny:"☀️",full_moon_with_face:"🌝",sun_with_face:"🌞",ringed_planet:"🪐",star:"⭐",star2:"🌟",stars:"🌠",milky_way:"🌌",cloud:"☁️",partly_sunny:"⛅",cloud_with_lightning_and_rain:"⛈️",sun_behind_small_cloud:"🌤️",sun_behind_large_cloud:"🌥️",sun_behind_rain_cloud:"🌦️",cloud_with_rain:"🌧️",cloud_with_snow:"🌨️",cloud_with_lightning:"🌩️",tornado:"🌪️",fog:"🌫️",wind_face:"🌬️",cyclone:"🌀",rainbow:"🌈",closed_umbrella:"🌂",open_umbrella:"☂️",umbrella:"☔",parasol_on_ground:"⛱️",zap:"⚡",snowflake:"❄️",snowman_with_snow:"☃️",snowman:"⛄",comet:"☄️",fire:"🔥",droplet:"💧",ocean:"🌊",jack_o_lantern:"🎃",christmas_tree:"🎄",fireworks:"🎆",sparkler:"🎇",firecracker:"🧨",sparkles:"✨",balloon:"🎈",tada:"🎉",confetti_ball:"🎊",tanabata_tree:"🎋",bamboo:"🎍",dolls:"🎎",flags:"🎏",wind_chime:"🎐",rice_scene:"🎑",red_envelope:"🧧",ribbon:"🎀",gift:"🎁",reminder_ribbon:"🎗️",tickets:"🎟️",ticket:"🎫",medal_military:"🎖️",trophy:"🏆",medal_sports:"🏅","1st_place_medal":"🥇","2nd_place_medal":"🥈","3rd_place_medal":"🥉",soccer:"⚽",baseball:"⚾",softball:"🥎",basketball:"🏀",volleyball:"🏐",football:"🏈",rugby_football:"🏉",tennis:"🎾",flying_disc:"🥏",bowling:"🎳",cricket_game:"🏏",field_hockey:"🏑",ice_hockey:"🏒",lacrosse:"🥍",ping_pong:"🏓",badminton:"🏸",boxing_glove:"🥊",martial_arts_uniform:"🥋",goal_net:"🥅",golf:"⛳",ice_skate:"⛸️",fishing_pole_and_fish:"🎣",diving_mask:"🤿",running_shirt_with_sash:"🎽",ski:"🎿",sled:"🛷",curling_stone:"🥌",dart:"🎯",yo_yo:"🪀",kite:"🪁",gun:"🔫","8ball":"🎱",crystal_ball:"🔮",magic_wand:"🪄",video_game:"🎮",joystick:"🕹️",slot_machine:"🎰",game_die:"🎲",jigsaw:"🧩",teddy_bear:"🧸",pinata:"🪅",mirror_ball:"🪩",nesting_dolls:"🪆",spades:"♠️",hearts:"♥️",diamonds:"♦️",clubs:"♣️",chess_pawn:"♟️",black_joker:"🃏",mahjong:"🀄",flower_playing_cards:"🎴",performing_arts:"🎭",framed_picture:"🖼️",art:"🎨",thread:"🧵",sewing_needle:"🪡",yarn:"🧶",knot:"🪢",eyeglasses:"👓",dark_sunglasses:"🕶️",goggles:"🥽",lab_coat:"🥼",safety_vest:"🦺",necktie:"👔",shirt:"👕",tshirt:"👕",jeans:"👖",scarf:"🧣",gloves:"🧤",coat:"🧥",socks:"🧦",dress:"👗",kimono:"👘",sari:"🥻",one_piece_swimsuit:"🩱",swim_brief:"🩲",shorts:"🩳",bikini:"👙",womans_clothes:"👚",folding_hand_fan:"🪭",purse:"👛",handbag:"👜",pouch:"👝",shopping:"🛍️",school_satchel:"🎒",thong_sandal:"🩴",mans_shoe:"👞",shoe:"👞",athletic_shoe:"👟",hiking_boot:"🥾",flat_shoe:"🥿",high_heel:"👠",sandal:"👡",ballet_shoes:"🩰",boot:"👢",hair_pick:"🪮",crown:"👑",womans_hat:"👒",tophat:"🎩",mortar_board:"🎓",billed_cap:"🧢",military_helmet:"🪖",rescue_worker_helmet:"⛑️",prayer_beads:"📿",lipstick:"💄",ring:"💍",gem:"💎",mute:"🔇",speaker:"🔈",sound:"🔉",loud_sound:"🔊",loudspeaker:"📢",mega:"📣",postal_horn:"📯",bell:"🔔",no_bell:"🔕",musical_score:"🎼",musical_note:"🎵",notes:"🎶",studio_microphone:"🎙️",level_slider:"🎚️",control_knobs:"🎛️",microphone:"🎤",headphones:"🎧",radio:"📻",saxophone:"🎷",accordion:"🪗",guitar:"🎸",musical_keyboard:"🎹",trumpet:"🎺",violin:"🎻",banjo:"🪕",drum:"🥁",long_drum:"🪘",maracas:"🪇",flute:"🪈",iphone:"📱",calling:"📲",phone:"☎️",telephone:"☎️",telephone_receiver:"📞",pager:"📟",fax:"📠",battery:"🔋",low_battery:"🪫",electric_plug:"🔌",computer:"💻",desktop_computer:"🖥️",printer:"🖨️",keyboard:"⌨️",computer_mouse:"🖱️",trackball:"🖲️",minidisc:"💽",floppy_disk:"💾",cd:"💿",dvd:"📀",abacus:"🧮",movie_camera:"🎥",film_strip:"🎞️",film_projector:"📽️",clapper:"🎬",tv:"📺",camera:"📷",camera_flash:"📸",video_camera:"📹",vhs:"📼",mag:"🔍",mag_right:"🔎",candle:"🕯️",bulb:"💡",flashlight:"🔦",izakaya_lantern:"🏮",lantern:"🏮",diya_lamp:"🪔",notebook_with_decorative_cover:"📔",closed_book:"📕",book:"📖",open_book:"📖",green_book:"📗",blue_book:"📘",orange_book:"📙",books:"📚",notebook:"📓",ledger:"📒",page_with_curl:"📃",scroll:"📜",page_facing_up:"📄",newspaper:"📰",newspaper_roll:"🗞️",bookmark_tabs:"📑",bookmark:"🔖",label:"🏷️",moneybag:"💰",coin:"🪙",yen:"💴",dollar:"💵",euro:"💶",pound:"💷",money_with_wings:"💸",credit_card:"💳",receipt:"🧾",chart:"💹",envelope:"✉️",email:"📧","e-mail":"📧",incoming_envelope:"📨",envelope_with_arrow:"📩",outbox_tray:"📤",inbox_tray:"📥",package:"📦",mailbox:"📫",mailbox_closed:"📪",mailbox_with_mail:"📬",mailbox_with_no_mail:"📭",postbox:"📮",ballot_box:"🗳️",pencil2:"✏️",black_nib:"✒️",fountain_pen:"🖋️",pen:"🖊️",paintbrush:"🖌️",crayon:"🖍️",memo:"📝",pencil:"📝",briefcase:"💼",file_folder:"📁",open_file_folder:"📂",card_index_dividers:"🗂️",date:"📅",calendar:"📆",spiral_notepad:"🗒️",spiral_calendar:"🗓️",card_index:"📇",chart_with_upwards_trend:"📈",chart_with_downwards_trend:"📉",bar_chart:"📊",clipboard:"📋",pushpin:"📌",round_pushpin:"📍",paperclip:"📎",paperclips:"🖇️",straight_ruler:"📏",triangular_ruler:"📐",scissors:"✂️",card_file_box:"🗃️",file_cabinet:"🗄️",wastebasket:"🗑️",lock:"🔒",unlock:"🔓",lock_with_ink_pen:"🔏",closed_lock_with_key:"🔐",key:"🔑",old_key:"🗝️",hammer:"🔨",axe:"🪓",pick:"⛏️",hammer_and_pick:"⚒️",hammer_and_wrench:"🛠️",dagger:"🗡️",crossed_swords:"⚔️",bomb:"💣",boomerang:"🪃",bow_and_arrow:"🏹",shield:"🛡️",carpentry_saw:"🪚",wrench:"🔧",screwdriver:"🪛",nut_and_bolt:"🔩",gear:"⚙️",clamp:"🗜️",balance_scale:"⚖️",probing_cane:"🦯",link:"🔗",chains:"⛓️",hook:"🪝",toolbox:"🧰",magnet:"🧲",ladder:"🪜",alembic:"⚗️",test_tube:"🧪",petri_dish:"🧫",dna:"🧬",microscope:"🔬",telescope:"🔭",satellite:"📡",syringe:"💉",drop_of_blood:"🩸",pill:"💊",adhesive_bandage:"🩹",crutch:"🩼",stethoscope:"🩺",x_ray:"🩻",door:"🚪",elevator:"🛗",mirror:"🪞",window:"🪟",bed:"🛏️",couch_and_lamp:"🛋️",chair:"🪑",toilet:"🚽",plunger:"🪠",shower:"🚿",bathtub:"🛁",mouse_trap:"🪤",razor:"🪒",lotion_bottle:"🧴",safety_pin:"🧷",broom:"🧹",basket:"🧺",roll_of_paper:"🧻",bucket:"🪣",soap:"🧼",bubbles:"🫧",toothbrush:"🪥",sponge:"🧽",fire_extinguisher:"🧯",shopping_cart:"🛒",smoking:"🚬",coffin:"⚰️",headstone:"🪦",funeral_urn:"⚱️",nazar_amulet:"🧿",hamsa:"🪬",moyai:"🗿",placard:"🪧",identification_card:"🪪",atm:"🏧",put_litter_in_its_place:"🚮",potable_water:"🚰",wheelchair:"♿",men:"🚹",women:"🚺",restroom:"🚻",baby_symbol:"🚼",wc:"🚾",passport_control:"🛂",customs:"🛃",baggage_claim:"🛄",left_luggage:"🛅",warning:"⚠️",children_crossing:"🚸",no_entry:"⛔",no_entry_sign:"🚫",no_bicycles:"🚳",no_smoking:"🚭",do_not_litter:"🚯","non-potable_water":"🚱",no_pedestrians:"🚷",no_mobile_phones:"📵",underage:"🔞",radioactive:"☢️",biohazard:"☣️",arrow_up:"⬆️",arrow_upper_right:"↗️",arrow_right:"➡️",arrow_lower_right:"↘️",arrow_down:"⬇️",arrow_lower_left:"↙️",arrow_left:"⬅️",arrow_upper_left:"↖️",arrow_up_down:"↕️",left_right_arrow:"↔️",leftwards_arrow_with_hook:"↩️",arrow_right_hook:"↪️",arrow_heading_up:"⤴️",arrow_heading_down:"⤵️",arrows_clockwise:"🔃",arrows_counterclockwise:"🔄",back:"🔙",end:"🔚",on:"🔛",soon:"🔜",top:"🔝",place_of_worship:"🛐",atom_symbol:"⚛️",om:"🕉️",star_of_david:"✡️",wheel_of_dharma:"☸️",yin_yang:"☯️",latin_cross:"✝️",orthodox_cross:"☦️",star_and_crescent:"☪️",peace_symbol:"☮️",menorah:"🕎",six_pointed_star:"🔯",khanda:"🪯",aries:"♈",taurus:"♉",gemini:"♊",cancer:"♋",leo:"♌",virgo:"♍",libra:"♎",scorpius:"♏",sagittarius:"♐",capricorn:"♑",aquarius:"♒",pisces:"♓",ophiuchus:"⛎",twisted_rightwards_arrows:"🔀",repeat:"🔁",repeat_one:"🔂",arrow_forward:"▶️",fast_forward:"⏩",next_track_button:"⏭️",play_or_pause_button:"⏯️",arrow_backward:"◀️",rewind:"⏪",previous_track_button:"⏮️",arrow_up_small:"🔼",arrow_double_up:"⏫",arrow_down_small:"🔽",arrow_double_down:"⏬",pause_button:"⏸️",stop_button:"⏹️",record_button:"⏺️",eject_button:"⏏️",cinema:"🎦",low_brightness:"🔅",high_brightness:"🔆",signal_strength:"📶",wireless:"🛜",vibration_mode:"📳",mobile_phone_off:"📴",female_sign:"♀️",male_sign:"♂️",transgender_symbol:"⚧️",heavy_multiplication_x:"✖️",heavy_plus_sign:"➕",heavy_minus_sign:"➖",heavy_division_sign:"➗",heavy_equals_sign:"🟰",infinity:"♾️",bangbang:"‼️",interrobang:"⁉️",question:"❓",grey_question:"❔",grey_exclamation:"❕",exclamation:"❗",heavy_exclamation_mark:"❗",wavy_dash:"〰️",currency_exchange:"💱",heavy_dollar_sign:"💲",medical_symbol:"⚕️",recycle:"♻️",fleur_de_lis:"⚜️",trident:"🔱",name_badge:"📛",beginner:"🔰",o:"⭕",white_check_mark:"✅",ballot_box_with_check:"☑️",heavy_check_mark:"✔️",x:"❌",negative_squared_cross_mark:"❎",curly_loop:"➰",loop:"➿",part_alternation_mark:"〽️",eight_spoked_asterisk:"✳️",eight_pointed_black_star:"✴️",sparkle:"❇️",copyright:"©️",registered:"®️",tm:"™️",hash:"#️⃣",asterisk:"*️⃣",zero:"0️⃣",one:"1️⃣",two:"2️⃣",three:"3️⃣",four:"4️⃣",five:"5️⃣",six:"6️⃣",seven:"7️⃣",eight:"8️⃣",nine:"9️⃣",keycap_ten:"🔟",capital_abcd:"🔠",abcd:"🔡",symbols:"🔣",abc:"🔤",a:"🅰️",ab:"🆎",b:"🅱️",cl:"🆑",cool:"🆒",free:"🆓",information_source:"ℹ️",id:"🆔",m:"Ⓜ️",new:"🆕",ng:"🆖",o2:"🅾️",ok:"🆗",parking:"🅿️",sos:"🆘",up:"🆙",vs:"🆚",koko:"🈁",sa:"🈂️",u6708:"🈷️",u6709:"🈶",u6307:"🈯",ideograph_advantage:"🉐",u5272:"🈹",u7121:"🈚",u7981:"🈲",accept:"🉑",u7533:"🈸",u5408:"🈴",u7a7a:"🈳",congratulations:"㊗️",secret:"㊙️",u55b6:"🈺",u6e80:"🈵",red_circle:"🔴",orange_circle:"🟠",yellow_circle:"🟡",green_circle:"🟢",large_blue_circle:"🔵",purple_circle:"🟣",brown_circle:"🟤",black_circle:"⚫",white_circle:"⚪",red_square:"🟥",orange_square:"🟧",yellow_square:"🟨",green_square:"🟩",blue_square:"🟦",purple_square:"🟪",brown_square:"🟫",black_large_square:"⬛",white_large_square:"⬜",black_medium_square:"◼️",white_medium_square:"◻️",black_medium_small_square:"◾",white_medium_small_square:"◽",black_small_square:"▪️",white_small_square:"▫️",large_orange_diamond:"🔶",large_blue_diamond:"🔷",small_orange_diamond:"🔸",small_blue_diamond:"🔹",small_red_triangle:"🔺",small_red_triangle_down:"🔻",diamond_shape_with_a_dot_inside:"💠",radio_button:"🔘",white_square_button:"🔳",black_square_button:"🔲",checkered_flag:"🏁",triangular_flag_on_post:"🚩",crossed_flags:"🎌",black_flag:"🏴",white_flag:"🏳️",rainbow_flag:"🏳️‍🌈",transgender_flag:"🏳️‍⚧️",pirate_flag:"🏴‍☠️",ascension_island:"🇦🇨",andorra:"🇦🇩",united_arab_emirates:"🇦🇪",afghanistan:"🇦🇫",antigua_barbuda:"🇦🇬",anguilla:"🇦🇮",albania:"🇦🇱",armenia:"🇦🇲",angola:"🇦🇴",antarctica:"🇦🇶",argentina:"🇦🇷",american_samoa:"🇦🇸",austria:"🇦🇹",australia:"🇦🇺",aruba:"🇦🇼",aland_islands:"🇦🇽",azerbaijan:"🇦🇿",bosnia_herzegovina:"🇧🇦",barbados:"🇧🇧",bangladesh:"🇧🇩",belgium:"🇧🇪",burkina_faso:"🇧🇫",bulgaria:"🇧🇬",bahrain:"🇧🇭",burundi:"🇧🇮",benin:"🇧🇯",st_barthelemy:"🇧🇱",bermuda:"🇧🇲",brunei:"🇧🇳",bolivia:"🇧🇴",caribbean_netherlands:"🇧🇶",brazil:"🇧🇷",bahamas:"🇧🇸",bhutan:"🇧🇹",bouvet_island:"🇧🇻",botswana:"🇧🇼",belarus:"⬜️🟥⬜",belize:"🇧🇿",canada:"🇨🇦",cocos_islands:"🇨🇨",congo_kinshasa:"🇨🇩",central_african_republic:"🇨🇫",congo_brazzaville:"🇨🇬",switzerland:"🇨🇭",cote_divoire:"🇨🇮",cook_islands:"🇨🇰",chile:"🇨🇱",cameroon:"🇨🇲",cn:"🇨🇳",colombia:"🇨🇴",clipperton_island:"🇨🇵",costa_rica:"🇨🇷",cuba:"🇨🇺",cape_verde:"🇨🇻",curacao:"🇨🇼",christmas_island:"🇨🇽",cyprus:"🇨🇾",czech_republic:"🇨🇿",de:"🇩🇪",diego_garcia:"🇩🇬",djibouti:"🇩🇯",denmark:"🇩🇰",dominica:"🇩🇲",dominican_republic:"🇩🇴",algeria:"🇩🇿",ceuta_melilla:"🇪🇦",ecuador:"🇪🇨",estonia:"🇪🇪",egypt:"🇪🇬",western_sahara:"🇪🇭",eritrea:"🇪🇷",es:"🇪🇸",ethiopia:"🇪🇹",eu:"🇪🇺",european_union:"🇪🇺",finland:"🇫🇮",fiji:"🇫🇯",falkland_islands:"🇫🇰",micronesia:"🇫🇲",faroe_islands:"🇫🇴",fr:"🇫🇷",gabon:"🇬🇦",gb:"🇬🇧",uk:"🇬🇧",grenada:"🇬🇩",georgia:"🇬🇪",french_guiana:"🇬🇫",guernsey:"🇬🇬",ghana:"🇬🇭",gibraltar:"🇬🇮",greenland:"🇬🇱",gambia:"🇬🇲",guinea:"🇬🇳",guadeloupe:"🇬🇵",equatorial_guinea:"🇬🇶",greece:"🇬🇷",south_georgia_south_sandwich_islands:"🇬🇸",guatemala:"🇬🇹",guam:"🇬🇺",guinea_bissau:"🇬🇼",guyana:"🇬🇾",hong_kong:"🇭🇰",heard_mcdonald_islands:"🇭🇲",honduras:"🇭🇳",croatia:"🇭🇷",haiti:"🇭🇹",hungary:"🇭🇺",canary_islands:"🇮🇨",indonesia:"🇮🇩",ireland:"🇮🇪",israel:"🇮🇱",isle_of_man:"🇮🇲",india:"🇮🇳",british_indian_ocean_territory:"🇮🇴",iraq:"🇮🇶",iran:"🇮🇷",iceland:"🇮🇸",it:"🇮🇹",jersey:"🇯🇪",jamaica:"🇯🇲",jordan:"🇯🇴",jp:"🇯🇵",kenya:"🇰🇪",kyrgyzstan:"🇰🇬",cambodia:"🇰🇭",kiribati:"🇰🇮",comoros:"🇰🇲",st_kitts_nevis:"🇰🇳",north_korea:"🇰🇵",kr:"🇰🇷",kuwait:"🇰🇼",cayman_islands:"🇰🇾",kazakhstan:"🇰🇿",laos:"🇱🇦",lebanon:"🇱🇧",st_lucia:"🇱🇨",liechtenstein:"🇱🇮",sri_lanka:"🇱🇰",liberia:"🇱🇷",lesotho:"🇱🇸",lithuania:"🇱🇹",luxembourg:"🇱🇺",latvia:"🇱🇻",libya:"🇱🇾",morocco:"🇲🇦",monaco:"🇲🇨",moldova:"🇲🇩",montenegro:"🇲🇪",st_martin:"🇲🇫",madagascar:"🇲🇬",marshall_islands:"🇲🇭",macedonia:"🇲🇰",mali:"🇲🇱",myanmar:"🇲🇲",mongolia:"🇲🇳",macau:"🇲🇴",northern_mariana_islands:"🇲🇵",martinique:"🇲🇶",mauritania:"🇲🇷",montserrat:"🇲🇸",malta:"🇲🇹",mauritius:"🇲🇺",maldives:"🇲🇻",malawi:"🇲🇼",mexico:"🇲🇽",malaysia:"🇲🇾",mozambique:"🇲🇿",namibia:"🇳🇦",new_caledonia:"🇳🇨",niger:"🇳🇪",norfolk_island:"🇳🇫",nigeria:"🇳🇬",nicaragua:"🇳🇮",netherlands:"🇳🇱",norway:"🇳🇴",nepal:"🇳🇵",nauru:"🇳🇷",niue:"🇳🇺",new_zealand:"🇳🇿",oman:"🇴🇲",panama:"🇵🇦",peru:"🇵🇪",french_polynesia:"🇵🇫",papua_new_guinea:"🇵🇬",philippines:"🇵🇭",pakistan:"🇵🇰",poland:"🇵🇱",st_pierre_miquelon:"🇵🇲",pitcairn_islands:"🇵🇳",puerto_rico:"🇵🇷",palestinian_territories:"🇵🇸",portugal:"🇵🇹",palau:"🇵🇼",paraguay:"🇵🇾",qatar:"🇶🇦",reunion:"🇷🇪",romania:"🇷🇴",serbia:"🇷🇸",ru:"🇷🇺",rwanda:"🇷🇼",saudi_arabia:"🇸🇦",solomon_islands:"🇸🇧",seychelles:"🇸🇨",sudan:"🇸🇩",sweden:"🇸🇪",singapore:"🇸🇬",st_helena:"🇸🇭",slovenia:"🇸🇮",svalbard_jan_mayen:"🇸🇯",slovakia:"🇸🇰",sierra_leone:"🇸🇱",san_marino:"🇸🇲",senegal:"🇸🇳",somalia:"🇸🇴",suriname:"🇸🇷",south_sudan:"🇸🇸",sao_tome_principe:"🇸🇹",el_salvador:"🇸🇻",sint_maarten:"🇸🇽",syria:"🇸🇾",swaziland:"🇸🇿",tristan_da_cunha:"🇹🇦",turks_caicos_islands:"🇹🇨",chad:"🇹🇩",french_southern_territories:"🇹🇫",togo:"🇹🇬",thailand:"🇹🇭",tajikistan:"🇹🇯",tokelau:"🇹🇰",timor_leste:"🇹🇱",turkmenistan:"🇹🇲",tunisia:"🇹🇳",tonga:"🇹🇴",tr:"🇹🇷",trinidad_tobago:"🇹🇹",tuvalu:"🇹🇻",taiwan:"🇹🇼",tanzania:"🇹🇿",ukraine:"🇺🇦",uganda:"🇺🇬",us_outlying_islands:"🇺🇲",united_nations:"🇺🇳",us:"🇺🇸",uruguay:"🇺🇾",uzbekistan:"🇺🇿",vatican_city:"🇻🇦",st_vincent_grenadines:"🇻🇨",venezuela:"🇻🇪",british_virgin_islands:"🇻🇬",us_virgin_islands:"🇻🇮",vietnam:"🇻🇳",vanuatu:"🇻🇺",wallis_futuna:"🇼🇫",samoa:"🇼🇸",kosovo:"🇽🇰",yemen:"🇾🇪",mayotte:"🇾🇹",south_africa:"🇿🇦",zambia:"🇿🇲",zimbabwe:"🇿🇼",england:"🏴󠁧󠁢󠁥󠁮󠁧󠁿",scotland:"🏴󠁧󠁢󠁳󠁣󠁴󠁿",wales:"🏴󠁧󠁢󠁷󠁬󠁳󠁿"};Bt.use(Wi({emojis:Jp,renderer:t=>t.emoji}));const Kp=()=>{const[t,n]=N(!1);return e(V,{children:e(qr,{children:e(wa,{children:e(V,{children:[e(Ka,{onLoaded:n}),t&&e(Ur,{children:e(fe,{path:"/",element:e(Wp,{}),children:e(fe,{path:"/",element:e(Qp,{})})})})]})})})})},Zp=({displaySidebar:t,isMobile:n,headerSetup:r,accountIds:a})=>e("div",{className:I({"vm-header-controls":!0,"vm-header-controls_mobile":n}),children:[(r==null?void 0:r.tenant)&&e(Hs,{accountIds:a||[]}),(r==null?void 0:r.stepControl)&&e(Vs,{}),(r==null?void 0:r.timeSelector)&&e(ka,{}),(r==null?void 0:r.cardinalityDatePicker)&&e(Us,{}),(r==null?void 0:r.executionControls)&&e(Ta,{}),e(La,{}),!t&&e(Fs,{})]}),Xp=()=>{const t=Ee(),{isMobile:n}=J(),{pathname:r}=ht(),[a,o]=oe();Aa();const s=()=>{var d;const l="vmui for vmanomaly",c=(d=gt[r])==null?void 0:d.title;document.title=c?`${c} - ${l}`:l},i=()=>{const{search:l,href:c}=window.location;if(l){const m=Fr.parse(l,{ignoreQueryPrefix:!0});Object.entries(m).forEach(([u,h])=>a.set(u,h)),o(a),window.location.search=""}const d=c.replace(/\/\?#\//,"/#/");d!==c&&window.location.replace(d)};return A(s,[r]),A(i,[]),e("section",{className:"vm-container",children:[e(Na,{controlsComponent:Zp}),e("div",{className:I({"vm-container-body":!0,"vm-container-body_mobile":n,"vm-container-body_app":t}),children:e(Vr,{})}),!t&&e(Sa,{})]})},eg=1,tg=()=>{Ia();const{isMobile:t}=J(),{query:n}=xe(),{customStep:r}=He(),a=q(null),[o]=N([]),[s,i]=N(!n[0]),[l,c]=N(!1),{isLoading:d,graphData:m,error:u,queryErrors:h,setQueryErrors:p,queryStats:v,warning:b}=Xn({visible:!0,customStep:r,hideQuery:o,showAllSeries:l}),f=M(()=>{if(!m)return[];const _=m.map(C=>({...ni(C.metric),...C})),y=_.filter(C=>C.value===ne.actual),S=_.filter(C=>C.value===ne.anomaly),T=y.map(C=>{const k=Pr(C.metric),L=S.find(x=>Pr(x.metric)===k);return{group:1,metric:{...C.metric,__name__:ne.anomaly},values:C.values.filter(([x])=>{if(!L)return!1;const E=L.values.find(([P])=>P===x);return E&&sn(E[1])>eg})}});return _.filter(C=>C.value!==ne.anomaly&&C.value).concat(T)},[m]),g=()=>{i(!1)};return e("div",{className:I({"vm-custom-panel":!0,"vm-custom-panel_mobile":t}),children:[e(xa,{queryErrors:s?[]:h,setQueryErrors:p,setHideError:i,stats:v,onRunQuery:g,hideButtons:{addQuery:!0,prettify:!1,autocomplete:!1,traceQuery:!0,anomalyConfig:!0,reduceMemUsage:!0}}),d&&e(Qe,{}),!s&&u&&e(le,{variant:"error",children:u}),b&&e(tr,{warning:b,query:n,onChange:c}),e("div",{className:I({"vm-custom-panel-body":!0,"vm-custom-panel-body_mobile":t,"vm-block":!0,"vm-block_mobile":t}),children:[e("div",{className:"vm-custom-panel-body-header",ref:a,children:e("div",{})}),f&&e(_i,{graphData:f,isHistogram:!1,controlsRef:a,isAnomalyView:!0})]})]})},ng=()=>{const[t,n]=N(!1);return e(V,{children:e(qr,{children:e(wa,{children:e(V,{children:[e(Ka,{onLoaded:n}),t&&e(Ur,{children:e(fe,{path:"/",element:e(Xp,{}),children:[e(fe,{path:"/",element:e(tg,{})}),e(fe,{path:Z.query,element:e(ki,{})})]})})]})})})})},rg=()=>{switch(Qt){case dt.victorialogs:return e(Kp,{});case dt.vmanomaly:return e(ng,{});default:return e(dh,{})}},Qo=document.getElementById("root");Qo&&Ji(rg(),Qo); diff --git a/app/vlselect/vmui/assets/index-C36SC0pJ.css b/app/vlselect/vmui/assets/index-C36SC0pJ.css deleted file mode 100644 index 25fc137ad2..0000000000 --- a/app/vlselect/vmui/assets/index-C36SC0pJ.css +++ /dev/null @@ -1 +0,0 @@ -@charset "UTF-8";.vm-tabs{position:relative;display:flex;align-items:center;justify-content:center;height:100%;gap:12px;-webkit-user-select:none;user-select:none}.vm-tabs-item{display:flex;align-items:center;justify-content:center;padding:12px 8px;color:inherit;text-decoration:none;text-transform:capitalize;font-size:inherit;font-weight:inherit;opacity:.6;transition:opacity .2s;cursor:pointer}.vm-tabs-item_active{opacity:1}.vm-tabs-item:hover{opacity:.8}.vm-tabs-item__icon{display:grid;width:16px;margin-right:8px}.vm-tabs-item__icon_single{margin-right:0}.vm-tabs__indicator{position:absolute;border-bottom:2px solid;transition:width .2s ease,left .3s cubic-bezier(.28,.84,.42,1)}.vm-alert{position:relative;display:grid;grid-template-columns:20px 1fr;align-items:center;gap:8px;padding:12px;background-color:var(--color-background-block);border-radius:8px;box-shadow:var(--box-shadow);font-size:14px;font-weight:400;color:var(--color-text);line-height:1.5}.vm-alert_mobile{align-items:flex-start;border-radius:0}.vm-alert:after{position:absolute;content:"";top:0;left:0;width:100%;height:100%;border-radius:8px;z-index:1;opacity:.1}.vm-alert_mobile:after{border-radius:0}.vm-alert__icon,.vm-alert__content{position:relative;z-index:2}.vm-alert__icon{display:flex;align-items:center;justify-content:center;align-self:flex-start;min-height:24px}.vm-alert__content{filter:brightness(.6);white-space:pre-line;text-wrap:balance;overflow-wrap:anywhere}.vm-alert_success{color:var(--color-success)}.vm-alert_success:after{background-color:var(--color-success)}.vm-alert_error{color:var(--color-error)}.vm-alert_error:after{background-color:var(--color-error)}.vm-alert_info{color:var(--color-info)}.vm-alert_info:after{background-color:var(--color-info)}.vm-alert_warning{color:var(--color-warning)}.vm-alert_warning:after{background-color:var(--color-warning)}.vm-alert_dark:after{opacity:.1}.vm-alert_dark .vm-alert__content{filter:none}.vm-header{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-start;padding:8px 12px;gap:0 16px;min-height:51px;z-index:99}.vm-header_app{padding:8px 0}@media (max-width: 1000px){.vm-header{position:sticky;top:0;gap:8px;padding:8px}}.vm-header_sidebar{display:grid;grid-template-columns:40px auto 1fr;box-shadow:var(--color-background-body) 0 1px 1px 0}.vm-header_mobile{display:grid;grid-template-columns:33px 1fr 33px;justify-content:space-between}.vm-header_dark .vm-header-button,.vm-header_dark button:before,.vm-header_dark button{background-color:var(--color-background-block)}.vm-header-logo{position:relative;display:flex;align-items:center;justify-content:flex-start;cursor:pointer;width:100%;max-width:75px;min-width:75px;margin-bottom:2px;overflow:hidden}.vm-header-logo svg{max-width:75px;min-width:75px}.vm-header-logo_mobile{max-width:75px;min-width:75px;margin:0 auto}.vm-header-nav{display:flex;align-items:center;justify-content:flex-start;gap:12px}.vm-header-nav_column{flex-direction:column;align-items:stretch;gap:8px}.vm-header-nav_column .vm-header-nav-item{padding:12px 0}.vm-header-nav_column .vm-header-nav-item_sub{justify-content:stretch}.vm-header-nav-item{position:relative;padding:12px 8px;opacity:1;cursor:pointer;transition:opacity .2s ease-in;text-transform:capitalize;font-size:14px;font-weight:400}.vm-header-nav-item_sub{display:grid;grid-template-columns:auto 14px;align-items:center;justify-content:center;gap:4px;cursor:default}.vm-header-nav-item:hover{opacity:.7}.vm-header-nav-item_active{border-bottom:2px solid rgba(17,15,15,.2)}.vm-header-nav-item svg{transform:rotate(0);transition:transform .2s ease-in}.vm-header-nav-item_open svg{transform:rotate(180deg)}.vm-header-nav-item-submenu{display:grid;white-space:nowrap;padding:8px;color:#fff;border-radius:4px;opacity:1;transform-origin:top center}.vm-header-nav-item-submenu-item{cursor:pointer}.vm-popper{position:fixed;background-color:var(--color-background-block);box-shadow:var(--box-shadow-popper);z-index:-99;pointer-events:none;opacity:0;transition:opacity .1s ease-in-out;border-radius:4px}.vm-popper_open{z-index:101;opacity:1;transform-origin:top center;animation:vm-slider .15s cubic-bezier(.28,.84,.42,1.1);pointer-events:auto}.vm-popper_mobile{position:fixed;left:0;right:0;top:0;bottom:0;width:100%;border-radius:0;overflow:auto;animation:none}.vm-popper-header{display:grid;grid-template-columns:1fr 25px;gap:12px;align-items:center;justify-content:space-between;background-color:var(--color-background-block);padding:8px 12px;border-radius:4px 4px 0 0;color:var(--color-text);border-bottom:var(--border-divider);margin-bottom:12px}.vm-popper-header__title{font-size:12px;font-weight:700;-webkit-user-select:none;user-select:none}.vm-popper_dark{background-color:var(--color-background-tooltip);color:#fff}.vm-popper_dark .vm-popper-header{background-color:transparent;color:#fff}@keyframes vm-slider{0%{transform:scaleY(0)}to{transform:scaleY(1)}}.vm-modal{position:fixed;top:0;left:0;right:0;bottom:0;z-index:100;display:flex;align-items:center;justify-content:center;background:#110f0f8c}.vm-modal_mobile{align-items:flex-start;min-height:calc(var(--vh) * 100);max-height:calc(var(--vh) * 100);overflow:auto}.vm-modal_mobile .vm-modal-content{width:100vw;border-radius:0;overflow:visible;min-height:100%;max-height:max-content;grid-template-rows:70px max-content}.vm-modal_mobile .vm-modal-content-header{padding:8px 8px 8px 12px;margin-bottom:12px}.vm-modal_mobile .vm-modal-content-header__title{max-width:80vw}.vm-modal_mobile .vm-modal-content-body{display:grid;align-items:flex-start;min-height:100%;padding:0 12px 12px}.vm-modal-content{background:var(--color-background-block);box-shadow:0 0 24px #110f0f12;border-radius:4px;max-height:calc(var(--vh) * 90);overflow:auto}.vm-modal-content-header{position:sticky;top:0;display:grid;grid-template-columns:1fr auto;gap:8px;align-items:center;justify-content:space-between;background-color:var(--color-background-block);padding:12px;border-radius:4px 4px 0 0;color:var(--color-text);border-bottom:var(--border-divider);margin-bottom:12px;min-height:51px;z-index:3}.vm-modal-content-header__title{font-weight:700;-webkit-user-select:none;user-select:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:50vw}.vm-modal-content-header__close{display:flex;align-items:center;justify-content:center;width:24px;padding:10px;box-sizing:content-box;color:#fff;cursor:pointer}.vm-modal-content-body{padding:0 12px 12px}.vm-shortcuts{min-width:400px}@media (max-width: 500px){.vm-shortcuts{min-width:100%}}.vm-shortcuts-section{position:relative;margin-bottom:12px;padding-bottom:12px;border-bottom:var(--border-divider)}.vm-shortcuts-section__title{font-weight:700;margin-bottom:12px}.vm-shortcuts-section__read-more{position:absolute;top:-8px;right:0}.vm-shortcuts-section-list{display:grid;gap:12px}@media (max-width: 500px){.vm-shortcuts-section-list{gap:12px}}.vm-shortcuts-section-list-item{display:grid;grid-template-columns:210px 1fr;align-items:center;gap:8px}@media (max-width: 500px){.vm-shortcuts-section-list-item{grid-template-columns:1fr}}.vm-shortcuts-section-list-item__key{display:flex;align-items:center;gap:4px}.vm-shortcuts-section-list-item__key svg,.vm-shortcuts-section-list-item__key code{display:inline-block;padding:2px 8px 0;font-size:12px;line-height:2;color:var(--color-text);text-align:center;background-color:var(--color-background-body);background-repeat:repeat-x;border:var(--border-divider);border-radius:4px}.vm-shortcuts-section-list-item__key svg{width:24px;padding:4px;color:var(--color-primary)}.vm-shortcuts-section-list-item__description{font-size:14px}.vm-tooltip{position:fixed;padding:3px 8px;background-color:var(--color-background-tooltip);box-shadow:var(--box-shadow-popper);border-radius:4px;color:#fff;font-size:12px;line-height:150%;white-space:nowrap;z-index:101;opacity:1;transition:opacity .1s ease-in-out;animation:vm-scale .15s cubic-bezier(.28,.84,.42,1);pointer-events:auto}@keyframes vm-scale{0%{transform:scale(0)}to{transform:scale(1)}}.fc-graph-tips{max-width:520px;display:grid;gap:12px}.fc-graph-tips-item{display:grid;gap:8px;line-height:1.3;padding-bottom:12px;border-bottom:var(--border-divider)}.fc-graph-tips-item__action{color:var(--color-text-secondary);font-weight:700}.fc-graph-tips-item__description{display:inline-block;line-height:1.5}.fc-graph-tips-item__description svg,.fc-graph-tips-item__description code{min-height:20px;min-width:20px;display:inline-flex;align-items:center;justify-content:center;padding:0 4px;font-size:12px;color:var(--color-text);background-color:var(--color-background-body);border:var(--border-divider);border-radius:4px;margin:0 2px 2px}.fc-graph-tips-item svg{width:18px;color:var(--color-primary);padding:2px;margin-top:-8px;transform:translateY(8px)}.vm-menu-burger{position:relative;border:none;background:none;width:18px;height:18px;padding:0;outline:none;cursor:pointer;transform-style:preserve-3d}.vm-menu-burger:after{content:"";position:absolute;left:-6px;top:-6px;width:calc(100% + 12px);height:calc(100% + 12px);background-color:#110f0f1a;border-radius:50%;transform:scale(0) translateZ(-2px);transition:transform .14s ease-in-out}.vm-menu-burger:hover:after{transform:scale(1) translateZ(-2px)}.vm-menu-burger span{display:block;top:50%;transform:translateY(-50%);border-top:2px solid #fff;transition:transform .3s ease,border-color .3s ease}.vm-menu-burger span,.vm-menu-burger span:before,.vm-menu-burger span:after{position:absolute;left:0;width:100%;height:2px;border-radius:6px}.vm-menu-burger span:before,.vm-menu-burger span:after{content:"";top:0;background:#fff;animation-duration:.6s;animation-timing-function:cubic-bezier(.645,.045,.355,1);animation-fill-mode:forwards}.vm-menu-burger span:before{animation-name:topLineBurger}.vm-menu-burger span:after{animation-name:bottomLineBurger}.vm-menu-burger_opened span{border-color:transparent}.vm-menu-burger_opened span:before{animation-name:topLineCross}.vm-menu-burger_opened span:after{animation-name:bottomLineCross}@keyframes topLineCross{0%{transform:translateY(-7px)}50%{transform:translateY(0)}to{width:60%;transform:translateY(-2px) translate(30%) rotate(45deg)}}@keyframes bottomLineCross{0%{transform:translateY(3px)}50%{transform:translateY(0)}to{width:60%;transform:translateY(-2px) translate(30%) rotate(-45deg)}}@keyframes topLineBurger{0%{transform:translateY(0) rotate(45deg)}50%{transform:rotate(0)}to{transform:translateY(-7px) rotate(0)}}@keyframes bottomLineBurger{0%{transform:translateY(0) rotate(-45deg)}50%{transform:rotate(0)}to{transform:translateY(3px) rotate(0)}}.vm-header-sidebar{width:24px;height:24px;color:inherit;background-color:inherit}.vm-header-sidebar-button{display:flex;align-items:center;justify-content:center;position:absolute;left:0;top:0;height:51px;width:51px;transition:left .35s cubic-bezier(.28,.84,.42,1)}.vm-header-sidebar-button_open{position:fixed;left:149px;z-index:102}.vm-header-sidebar-menu{position:fixed;top:0;left:0;display:grid;gap:12px;padding:12px;grid-template-rows:1fr auto;width:200px;height:100%;background-color:inherit;z-index:101;transform-origin:left;transform:translate(-100%);transition:transform .3s cubic-bezier(.28,.84,.42,1);box-shadow:var(--box-shadow-popper)}.vm-header-sidebar-menu_open{transform:translate(0)}.vm-header-sidebar-menu__logo{position:relative;display:flex;align-items:center;justify-content:flex-start;cursor:pointer;width:65px}.vm-header-sidebar-menu-settings{display:grid;align-items:center;gap:8px}.vm-header-controls{display:flex;align-items:center;justify-content:flex-end;gap:8px;flex-grow:1}.vm-header-controls_mobile{display:grid;grid-template-columns:1fr;padding:0}.vm-header-controls_mobile .vm-header-button{border:none}.vm-header-controls-modal{transform:scale(0)}.vm-header-controls-modal_open{transform:scale(1)}.vm-container{display:flex;flex-direction:column;min-height:calc(var(--vh) * 100 - var(--scrollbar-height))}.vm-container-body{flex-grow:1;min-height:100%;padding:12px;background-color:var(--color-background-body)}.vm-container-body_mobile{padding:8px 0 0}@media (max-width: 768px){.vm-container-body{padding:8px 0 0}}.vm-container-body_app{padding:8px 0;background-color:transparent}.vm-footer{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;padding:12px;gap:12px;border-top:var(--border-divider);color:var(--color-text-secondary);background:var(--color-background-body)}@media (max-width: 768px){.vm-footer{padding:12px;gap:12px}}.vm-footer__link,.vm-footer__website{display:grid;grid-template-columns:12px auto;align-items:center;justify-content:center;gap:6px}.vm-footer__website{margin-right:12px}@media (max-width: 768px){.vm-footer__website{margin-right:0}}.vm-footer__link{grid-template-columns:14px auto}.vm-footer__copyright{text-align:right;flex-grow:1}@media (max-width: 768px){.vm-footer__copyright{width:100%;font-size:12px;text-align:center}}.vm-tenant-input{position:relative}.vm-tenant-input-list{max-height:300px;overflow:auto;overscroll-behavior:none;border-radius:8px}.vm-tenant-input-list_mobile{max-height:calc(var(--vh) * 100 - 70px)}.vm-tenant-input-list_mobile .vm-tenant-input-list__search{padding:0 12px 8px}.vm-tenant-input-list_inline{display:grid;gap:4px;padding:12px}.vm-tenant-input-list__search{position:sticky;top:0;padding:8px 12px;background-color:var(--color-background-block)}.vm-tenant-input-list__buttons{display:flex;justify-content:space-between;gap:8px}.vm-text-field{position:relative;display:grid;margin:6px 0;width:100%}.vm-text-field_textarea:after{content:attr(data-replicated-value) " ";white-space:pre-wrap;overflow-wrap:break-word;visibility:hidden}.vm-text-field__input,.vm-text-field:after{font-family:monospace;width:100%;padding:8px 12px;border:var(--border-divider);background-color:transparent;font-size:14px;line-height:18px;grid-area:1/1/2/2;overflow:hidden;box-sizing:border-box}.vm-text-field__label,.vm-text-field__error,.vm-text-field__warning,.vm-text-field__helper-text{position:absolute;left:6px;max-width:calc(100% - 12px);padding:0 3px;font-size:12px;line-height:14px;pointer-events:none;-webkit-user-select:none;user-select:none;background-color:var(--color-background-block);z-index:2;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:1;line-clamp:1;-webkit-box-orient:vertical}.vm-text-field__label{top:-8px;color:var(--color-text-secondary)}.vm-text-field__helper-text,.vm-text-field__warning,.vm-text-field__error{position:relative;top:-6px;width:fit-content;overflow-wrap:anywhere;pointer-events:auto;-webkit-user-select:text;user-select:text}.vm-text-field__helper-text_full,.vm-text-field__warning_full,.vm-text-field__error_full{display:block;overflow:visible}.vm-text-field__helper-text_overflowed,.vm-text-field__warning_overflowed,.vm-text-field__error_overflowed{cursor:pointer}.vm-text-field__error{color:var(--color-error)}.vm-text-field__warning{color:var(--color-warning)}.vm-text-field__helper-text{color:var(--color-text-secondary)}.vm-text-field__input{display:block;border-radius:4px;transition:border .2s ease;resize:none;overflow:hidden;background-color:transparent;color:var(--color-text)}.vm-text-field__input:focus{border:1px solid var(--color-primary)}.vm-text-field__input:hover{border:1px solid var(--color-primary)}.vm-text-field__input_error,.vm-text-field__input_error:hover{border-color:var(--color-error)}.vm-text-field__input_error:focus{border-color:var(--color-error)}.vm-text-field__input_warning,.vm-text-field__input_warning:hover{border-color:var(--color-warning)}.vm-text-field__input_warning:focus{border-color:var(--color-warning)}.vm-text-field__input_icon-start{padding-left:31px}.vm-text-field__input:disabled{background-color:inherit;color:inherit}.vm-text-field__input:disabled:hover{border-color:var(--color-text-disabled)}.vm-text-field__icon-start,.vm-text-field__icon-end{display:flex;align-items:center;justify-content:center;max-width:15px;top:0;left:8px;height:36px;position:absolute;color:var(--color-text-secondary)}.vm-text-field__icon-end{left:auto;right:8px}.vm-text-field__controls-info{position:absolute;bottom:8px;right:12px;color:var(--color-text-secondary);font-size:12px;opacity:.8}.vm-step-control{display:inline-flex}.vm-step-control button{text-transform:none}.vm-step-control-popper{display:grid;gap:8px;max-width:300px;overflow:auto;padding:12px;font-size:14px}.vm-step-control-popper_mobile{padding:0 12px 8px;max-width:100%;max-height:calc(var(--vh) * 100 - 70px)}.vm-step-control-popper_mobile .vm-step-control-popper-info{font-size:14px}.vm-step-control-popper-info{font-size:12px;line-height:1.8}.vm-step-control-popper-info code{padding:.2em .4em;margin:0;font-size:85%;white-space:break-spaces;background-color:var(--color-hover-black);border-radius:6px}.vm-time-duration{max-height:227px;overflow:auto;font-size:14px}.vm-time-duration_mobile{max-height:100%}.vm-time-selector{display:grid;grid-template-columns:repeat(2,230px);padding:12px 0}.vm-time-selector_mobile{grid-template-columns:1fr;min-width:250px;width:100%;max-height:calc(var(--vh) * 100 - 70px);overflow:auto}.vm-time-selector_mobile .vm-time-selector-left{border-right:none;border-bottom:var(--border-divider);padding-bottom:12px}.vm-time-selector-left{display:flex;flex-direction:column;gap:8px;border-right:var(--border-divider);padding:0 12px}.vm-time-selector-left-inputs{flex-grow:1;display:grid;align-items:flex-start;justify-content:stretch}.vm-time-selector-left-timezone{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:12px;margin-bottom:8px}.vm-time-selector-left-timezone__utc{display:inline-flex;align-items:center;justify-content:center;background-color:var(--color-hover-black);padding:4px;border-radius:4px}.vm-time-selector-left__controls{display:grid;grid-template-columns:repeat(2,1fr);gap:8px}.vm-calendar{display:grid;grid-template-rows:auto 1fr auto;padding:12px;font-size:14px;-webkit-user-select:none;user-select:none;background-color:var(--color-background-block);border-radius:8px}.vm-calendar_mobile{padding:0 12px}.vm-calendar-header{display:grid;grid-template-columns:1fr auto;align-items:center;justify-content:center;gap:12px;padding-bottom:12px;min-height:36px}.vm-calendar-header-left{display:grid;grid-template-columns:auto auto;align-items:center;justify-content:flex-start;gap:8px;cursor:pointer;transition:opacity .2s ease-in-out}.vm-calendar-header-left:hover{opacity:.8}.vm-calendar-header-left__date{font-size:14px;color:var(--color-text);font-weight:700}.vm-calendar-header-left__select-year{display:grid;align-items:center;justify-content:center;width:14px;height:14px}.vm-calendar-header-right{display:grid;grid-template-columns:18px 18px;align-items:center;justify-content:center;gap:8px}.vm-calendar-header-right__prev,.vm-calendar-header-right__next{margin:-8px;padding:8px;cursor:pointer;transition:opacity .2s ease-in-out}.vm-calendar-header-right__prev:hover,.vm-calendar-header-right__next:hover{opacity:.8}.vm-calendar-header-right__prev{transform:rotate(90deg)}.vm-calendar-header-right__next{transform:rotate(-90deg)}.vm-calendar-body{display:grid;grid-template-columns:repeat(7,32px);grid-template-rows:repeat(7,32px);align-items:center;justify-content:center;gap:2px}@media (max-width: 500px){.vm-calendar-body{grid-template-columns:repeat(7,calc((100vw - 24px - 12px) / 7));grid-template-rows:repeat(7,calc((100vw - 24px - 12px) / 7))}}.vm-calendar-body-cell{display:flex;align-items:center;justify-content:center;text-align:center;border-radius:50%;height:100%}.vm-calendar-body-cell_weekday{color:var(--color-text-secondary)}.vm-calendar-body-cell_day{cursor:pointer;transition:color .2s ease,background-color .3s ease-in-out}.vm-calendar-body-cell_day:hover{background-color:var(--color-hover-black)}.vm-calendar-body-cell_day_empty{pointer-events:none}.vm-calendar-body-cell_day_active{background-color:var(--color-primary);color:#fff}.vm-calendar-body-cell_day_active:hover{background-color:var(--color-primary)}.vm-calendar-body-cell_day_today{border:1px solid var(--color-primary)}.vm-calendar-years{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;max-height:400px;overflow:auto}.vm-calendar-years__year{display:flex;align-items:center;justify-content:center;padding:8px 16px;border-radius:8px;cursor:pointer;transition:color .2s ease,background-color .3s ease-in-out}.vm-calendar-years__year:hover{background-color:var(--color-hover-black)}.vm-calendar-years__year_selected{background-color:var(--color-primary);color:#fff}.vm-calendar-years__year_selected:hover{background-color:var(--color-primary)}.vm-calendar-years__year_today{border:1px solid var(--color-primary)}.vm-calendar-footer{display:flex;align-items:center;justify-content:flex-end}.vm-date-time-input{position:relative;display:grid;grid-template-columns:1fr;gap:8px 0;align-items:center;justify-content:center;margin-bottom:12px;cursor:pointer;transition:color .2s ease-in-out,border-bottom-color .3s ease}.vm-date-time-input:hover input{border-bottom-color:var(--color-primary)}.vm-date-time-input label{grid-column:1/3;width:100%;font-size:12px;color:var(--color-text-secondary);-webkit-user-select:none;user-select:none}.vm-date-time-input__icon{position:absolute;bottom:2px;right:0}.vm-date-time-input input{padding:0 0 8px;border-bottom:var(--border-divider);border-top:none;border-left:none;border-right:none;background:transparent;color:var(--color-text)}.vm-date-time-input input:focus{border-bottom-color:var(--color-primary)}.vm-date-time-input_error input{border-color:var(--color-error)}.vm-date-time-input_error input:focus{border-bottom-color:var(--color-error)}.vm-date-time-input__error-text{color:var(--color-error);font-size:12px;position:absolute;left:0;bottom:-12px}.vm-button{display:inline-flex;gap:6px;align-items:center;justify-content:center;padding:6px 14px;font-size:12px;font-weight:400;text-transform:capitalize;color:#fff;background:transparent;border:1px solid transparent;border-radius:6px;cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap;transition:transform .2s,opacity .2s,background-color .2s}.vm-button:focus-visible{outline:2px solid #006fee;outline-offset:2px}.vm-button:active{transform:scale(.97);opacity:.9}.vm-button:disabled{opacity:.3;pointer-events:none}.vm-button_small{padding:4px 10px;line-height:14px}.vm-button_small svg{width:14px}.vm-button_medium{padding:6px 14px;line-height:14px}.vm-button_medium svg{width:16px}.vm-button_large{padding:8px 20px;font-size:16px}.vm-button_large svg{width:18px;line-height:16px}.vm-button_icon_only{aspect-ratio:1}.vm-button_small.vm-button_icon_only{padding:4px}.vm-button_medium.vm-button_icon_only{padding:6px}.vm-button_large.vm-button_icon_only{padding:8px}.vm-button_contained_primary{background-color:var(--color-primary);color:#fff}.vm-button_contained_primary:hover:not(:disabled){opacity:.8}.vm-button_outlined_primary{background-color:transparent;border-color:var(--color-primary);color:var(--color-primary)}.vm-button_outlined_primary:hover:not(:disabled){background-color:var(--color-hover-black);opacity:.8}.vm-button_text_primary{background-color:transparent;color:var(--color-primary)}.vm-button_text_primary:hover:not(:disabled){background-color:var(--color-hover-black)}.vm-button_contained_secondary{background-color:var(--color-secondary);color:#fff}.vm-button_contained_secondary:hover:not(:disabled){opacity:.8}.vm-button_outlined_secondary{background-color:transparent;border-color:var(--color-secondary);color:var(--color-secondary)}.vm-button_outlined_secondary:hover:not(:disabled){background-color:var(--color-hover-black);opacity:.8}.vm-button_text_secondary{background-color:transparent;color:var(--color-secondary)}.vm-button_text_secondary:hover:not(:disabled){background-color:var(--color-hover-black)}.vm-button_contained_success{background-color:var(--color-success);color:#fff}.vm-button_contained_success:hover:not(:disabled){opacity:.8}.vm-button_outlined_success{background-color:transparent;border-color:var(--color-success);color:var(--color-success)}.vm-button_outlined_success:hover:not(:disabled){background-color:var(--color-hover-black);opacity:.8}.vm-button_text_success{background-color:transparent;color:var(--color-success)}.vm-button_text_success:hover:not(:disabled){background-color:var(--color-hover-black)}.vm-button_contained_warning{background-color:var(--color-warning);color:#fff}.vm-button_contained_warning:hover:not(:disabled){opacity:.8}.vm-button_outlined_warning{background-color:transparent;border-color:var(--color-warning);color:var(--color-warning)}.vm-button_outlined_warning:hover:not(:disabled){background-color:var(--color-hover-black);opacity:.8}.vm-button_text_warning{background-color:transparent;color:var(--color-warning)}.vm-button_text_warning:hover:not(:disabled){background-color:var(--color-hover-black)}.vm-button_contained_error{background-color:var(--color-error);color:#fff}.vm-button_contained_error:hover:not(:disabled){opacity:.8}.vm-button_outlined_error{background-color:transparent;border-color:var(--color-error);color:var(--color-error)}.vm-button_outlined_error:hover:not(:disabled){background-color:var(--color-hover-black);opacity:.8}.vm-button_text_error{background-color:transparent;color:var(--color-error)}.vm-button_text_error:hover:not(:disabled){background-color:var(--color-hover-black)}.vm-button_contained_gray{background-color:var(--color-text-secondary);color:#fff}.vm-button_contained_gray:hover:not(:disabled){opacity:.8}.vm-button_outlined_gray{background-color:transparent;border-color:var(--color-text-secondary);color:var(--color-text-secondary)}.vm-button_outlined_gray:hover:not(:disabled){background-color:var(--color-hover-black);opacity:.8}.vm-button_text_gray{background-color:transparent;color:var(--color-text-secondary)}.vm-button_text_gray:hover:not(:disabled){background-color:var(--color-hover-black)}.vm-button_contained_white{background-color:#fff;color:#110f0f}.vm-button_contained_white:hover:not(:disabled){opacity:.8}.vm-button_outlined_white{background-color:transparent;border-color:#fff;color:#fff}.vm-button_outlined_white:hover:not(:disabled){background-color:var(--color-hover-black);opacity:.8}.vm-button_text_white{background-color:transparent;color:#fff}.vm-button_text_white:hover:not(:disabled){background-color:var(--color-hover-black)}.vm-execution-controls-buttons{display:flex;justify-content:space-between;border-radius:7px;min-width:107px}.vm-execution-controls-buttons_mobile{flex-direction:column;gap:12px}.vm-execution-controls-buttons__arrow{display:flex;align-items:center;justify-content:center;transform:rotate(0);transition:transform .2s ease-in-out}.vm-execution-controls-buttons__arrow_open{transform:rotate(180deg)}.vm-execution-controls-list{width:124px;max-height:208px;overflow:auto;padding:8px 0;font-size:14px}.vm-execution-controls-list_mobile{width:100%;max-height:calc(var(--vh) * 100 - 70px);padding:0}.vm-server-configurator{display:flex;flex-direction:column;align-items:center;gap:16px;width:600px;padding-bottom:12px}.vm-server-configurator_mobile{grid-auto-rows:min-content;align-items:flex-start;height:100%;width:100%}@media (max-width: 768px){.vm-server-configurator{width:100%}}.vm-server-configurator__input{width:100%}.vm-server-configurator__input_flex{display:flex;align-items:flex-start;gap:12px}.vm-server-configurator__title{grid-column:auto/span 2;display:flex;align-items:center;justify-content:flex-start;font-size:14px;font-weight:700;margin-bottom:12px}.vm-server-configurator__info{padding-top:8px;font-size:12px;color:var(--color-text-secondary);line-height:130%}.vm-server-configurator-url{display:flex;align-items:flex-start;gap:8px}.vm-server-configurator-url__button{margin-top:8px}.vm-server-configurator-footer{display:flex;align-items:center;justify-content:flex-end;gap:8px;width:100%}.vm-server-configurator_mobile .vm-server-configurator-footer{display:grid;grid-template-columns:1fr 1fr}.vm-limits-configurator-title__reset{display:flex;align-items:center;justify-content:flex-end;flex-grow:1}.vm-limits-configurator__inputs{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px}.vm-limits-configurator__inputs_mobile{gap:8px}.vm-accordion-header{position:relative;font-size:inherit;cursor:pointer;display:grid;align-items:center}.vm-accordion-header__arrow{display:flex;align-items:center;justify-content:center;position:absolute;right:14px;top:auto;transform:rotate(0);transition:transform .2s ease-in-out}.vm-accordion-header__arrow_open{transform:rotate(180deg)}.vm-accordion-header__arrow svg{width:14px;height:auto}.accordion-section{overflow:hidden}.vm-timezones-item{display:flex;align-items:center;justify-content:space-between;gap:8px;cursor:pointer}.vm-timezones-item_selected{border:var(--border-divider);padding:8px 12px;border-radius:4px}.vm-timezones-item__title{display:flex;align-items:center;gap:8px;text-transform:capitalize}.vm-timezones-item__title svg{width:14px;color:var(--color-warning)}.vm-timezones-item__utc{display:inline-flex;align-items:center;justify-content:center;background-color:var(--color-hover-black);padding:4px;border-radius:4px}.vm-timezones-item__icon{display:inline-flex;align-items:center;justify-content:flex-end;margin:0 0 0 auto;transition:transform .2s ease-in}.vm-timezones-item__icon svg{width:14px}.vm-timezones-item__icon_open{transform:rotate(180deg)}.vm-timezones-list{max-height:300px;background-color:var(--color-background-block);border-radius:8px;overflow:auto}.vm-timezones-list_mobile{max-height:calc(var(--vh) * 100 - 70px)}.vm-timezones-list_mobile .vm-timezones-list-header__search{padding:0 12px}.vm-timezones-list-header{position:sticky;top:0;background-color:var(--color-background-block);z-index:2;border-bottom:var(--border-divider)}.vm-timezones-list-header__search{padding:8px}.vm-timezones-list-group{padding:8px 0;border-bottom:var(--border-divider)}.vm-timezones-list-group:last-child{border-bottom:none}.vm-timezones-list-group__title{font-weight:700;color:var(--color-text-secondary);padding:8px 12px}.vm-timezones-list-group-options{display:grid;align-items:flex-start}.vm-timezones-list-group-options__item{padding:8px 12px;transition:background-color .2s ease}.vm-timezones-list-group-options__item:hover{background-color:#110f0f1a}.vm-theme-control__toggle{display:inline-flex;min-width:300px;text-transform:capitalize}.vm-theme-control_mobile .vm-theme-control__toggle{display:flex;min-width:100%}.vm-toggles{position:relative;display:grid;gap:3px;width:100%}.vm-toggles__label{padding:0 12px;color:var(--color-text-secondary);font-size:12px;line-height:1}.vm-toggles-group{position:relative;display:grid;width:100%;align-items:center;justify-content:center;overflow:hidden}.vm-toggles-group-item{position:relative;display:grid;align-items:center;justify-content:center;padding:8px;border-right:var(--border-divider);border-top:var(--border-divider);border-bottom:var(--border-divider);font-size:12px;color:var(--color-text-secondary);font-weight:700;cursor:pointer;text-align:center;transition:color .15s ease-in;z-index:2;-webkit-user-select:none;user-select:none}.vm-toggles-group-item_first{border-radius:16px 0 0 16px;border-left:var(--border-divider)}.vm-toggles-group-item:last-child{border-radius:0 16px 16px 0;border-left:none}.vm-toggles-group-item_icon{grid-template-columns:14px auto;gap:4px}.vm-toggles-group-item:hover{color:var(--color-primary)}.vm-toggles-group-item_active{color:var(--color-primary);border-color:transparent}.vm-toggles-group-item_active:hover{background-color:transparent}.vm-toggles-group__highlight{position:absolute;top:0;height:100%;background-color:rgba(var(--color-primary),.08);border:1px solid var(--color-primary);transition:left .2s cubic-bezier(.28,.84,.42,1),border-radius .2s linear;z-index:1}.vm-query-editor{position:relative}.vm-query-editor .marker-detection{position:absolute;top:0;left:0;pointer-events:none;z-index:-9999;visibility:hidden}.vm-additional-settings{display:inline-flex;align-items:center;justify-content:flex-start;flex-wrap:wrap;gap:12px}.vm-additional-settings__input{flex-basis:160px;margin-bottom:-6px}.vm-additional-settings_mobile{display:grid;grid-template-columns:1fr;align-items:flex-start;padding:0 12px;gap:12px;width:100%}.vm-switch{font-size:12px;display:flex;align-items:center;justify-content:flex-start;cursor:pointer;-webkit-user-select:none;user-select:none}.vm-switch_full-width{justify-content:space-between;flex-direction:row-reverse}.vm-switch_full-width .vm-switch__label{margin-left:0}.vm-switch_disabled{opacity:.6;cursor:default}.vm-switch_secondary_active .vm-switch-track{background-color:var(--color-secondary)}.vm-switch_primary_active .vm-switch-track{background-color:var(--color-primary)}.vm-switch_active .vm-switch-track__thumb{left:20px}.vm-switch:hover .vm-switch-track{opacity:.8}.vm-switch-track{position:relative;background-color:#110f0f66;display:flex;align-items:center;justify-content:flex-start;border-radius:17px;padding:3px;width:34px;height:17px;transition:background-color .2s ease,opacity .3s ease-out}.vm-switch-track__thumb{position:absolute;top:auto;left:3px;min-width:11px;min-height:11px;background-color:var(--color-background-block);border-radius:50%;transition:right .2s ease-out,left .2s ease-out;transform-style:preserve-3d}.vm-switch__label{white-space:nowrap;font-size:inherit;margin-left:8px;transition:color .2s ease;color:var(--color-text-secondary)}.vm-switch_active .vm-switch__label{color:var(--color-text)}.vm-query-configurator{display:grid;gap:12px}.vm-query-configurator-list{display:grid}.vm-query-configurator-list-row{display:grid;grid-template-columns:1fr auto auto auto;align-items:center;gap:8px}.vm-query-configurator-list-row_mobile{gap:4px}.vm-query-configurator-list-row_disabled{filter:grayscale(100%);opacity:.5}.vm-query-configurator-list-row__button{display:grid;align-items:start;width:36px;min-height:36px}.vm-query-configurator-settings{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px}.vm-query-configurator-settings__buttons{flex-grow:1;display:grid;grid-template-columns:repeat(3,auto);gap:8px;justify-content:flex-end}.vm-query-history{max-width:80vw;min-width:500px}.vm-query-history_mobile{max-width:100vw;min-width:100vw}.vm-query-history__tabs{margin:-12px -12px 0;padding:0 8px;border-bottom:var(--border-divider)}.vm-query-history__tabs_mobile{margin:-12px -12px 0}.vm-query-history-list{display:grid;align-items:flex-start}.vm-query-history-list__group-title{font-weight:700;margin:0 -12px;padding:12px 12px 8px}.vm-query-history-list__group-title_first{padding-top:12px}.vm-query-history-list__no-data{display:flex;align-items:center;justify-content:center;padding:16px 12px;color:var(--color-text-secondary);text-align:center;line-height:18px;white-space:pre-line}.vm-query-history-item{display:grid;grid-template-columns:1fr auto;gap:8px;align-items:center;margin:0 -12px;padding:8px 12px;border-bottom:var(--border-divider)}.vm-query-history-item__value{white-space:pre-wrap;overflow-wrap:anywhere;font-family:monospace}.vm-query-history-item__buttons{display:flex}.vm-query-history-footer{display:flex;justify-content:flex-end;padding-top:12px}.vm-spinner{position:fixed;top:0;bottom:0;left:0;right:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background-color:#ffffff80;pointer-events:none;z-index:99;animation:vm-fade 2s cubic-bezier(.28,.84,.42,1.1)}.vm-spinner_dark{background-color:#110f0f33}.vm-spinner__message{margin-top:12px;white-space:pre-line;text-align:center;line-height:1.3;font-size:16px;color:rgba(var(--color-text),.9)}.half-circle-spinner,.half-circle-spinner *{box-sizing:border-box}.half-circle-spinner{width:60px;height:60px;border-radius:100%;position:relative}.half-circle-spinner .circle{content:"";position:absolute;width:100%;height:100%;border-radius:100%;border:6px solid transparent}.half-circle-spinner .circle.circle-1{border-top-color:var(--color-primary);animation:half-circle-spinner-animation 1s infinite}.half-circle-spinner .circle.circle-2{border-bottom-color:var(--color-primary);animation:half-circle-spinner-animation 1s infinite alternate}@keyframes half-circle-spinner-animation{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes vm-fade{0%{opacity:0}to{opacity:1}}.vm-anomaly-config{display:grid;grid-template-rows:calc(var(--vh) * 70 - 78px - 36px) auto;gap:12px;min-width:400px;max-width:80vw;min-height:300px}.vm-anomaly-config_mobile{width:100%;max-width:none;min-height:100%;grid-template-rows:calc(var(--vh) * 100 - 78px - 36px) auto}.vm-anomaly-config textarea{overflow:auto;width:100%;height:100%;max-height:900px}.vm-anomaly-config-error{display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;gap:8px;text-align:center}.vm-anomaly-config-error__icon{display:flex;align-items:center;justify-content:center;width:30px;height:30px;margin-bottom:8px;color:var(--color-error)}.vm-anomaly-config-error__title{font-size:16px;font-weight:700}.vm-anomaly-config-error__text{max-width:700px;line-height:1.3}.vm-anomaly-config-footer{display:flex;align-items:center;justify-content:flex-end;gap:8px}.vm-autocomplete{position:relative;max-height:300px;overflow:auto;overscroll-behavior:none}.vm-autocomplete_mobile{max-height:calc(var(--vh) * 100 - 70px)}.vm-autocomplete__no-options{padding:12px;text-align:center;color:var(--color-text-disabled)}.vm-autocomplete__loader{display:grid;grid-template-columns:14px auto;align-items:center;justify-content:center;gap:8px;padding:12px;color:var(--color-text-secondary);z-index:2;pointer-events:none}.vm-autocomplete__loader svg{animation:half-circle-spinner-animation 1s infinite linear,vm-fade .5s ease-in}.vm-autocomplete-info,.vm-autocomplete-message{padding:12px;background-color:var(--color-background-block);border-top:var(--border-divider)}.vm-autocomplete-message{position:relative;color:var(--color-warning);font-size:12px}.vm-autocomplete-message:after{content:"";position:absolute;top:0;left:0;width:100%;height:100%;background:var(--color-warning);opacity:.1}.vm-autocomplete-info{min-width:450px;max-width:500px;overflow-wrap:anywhere}.vm-autocomplete-info__type{color:var(--color-text-secondary);margin-bottom:8px}.vm-autocomplete-info__description{line-height:130%}.vm-autocomplete-info__description p{margin:12px 0}.vm-autocomplete-info__description p:last-child{margin:0}.vm-line-loader{position:absolute;top:0;left:0;right:0;height:2px;z-index:2;overflow:hidden}.vm-line-loader__background{position:absolute;left:0;right:0;top:0;bottom:0;background-color:var(--color-text);opacity:.1}.vm-line-loader__line{position:absolute;width:10%;height:100%;background-color:var(--color-primary);animation:slide 2s infinite linear;opacity:.8}@keyframes slide{0%{left:0}to{left:100%}}.vm-custom-panel{display:grid;grid-template-columns:100%;align-items:flex-start;gap:12px;height:100%}.vm-custom-panel_mobile{gap:8px}.vm-custom-panel__warning{display:grid;grid-template-columns:1fr auto;align-items:center;justify-content:space-between;gap:8px}.vm-custom-panel__warning_mobile{grid-template-columns:1fr}.vm-custom-panel-body{position:relative}.vm-custom-panel-body-header{position:relative;display:flex;align-items:center;justify-content:space-between;font-size:12px;margin:-12px -12px 12px;padding:0 12px;border-bottom:var(--border-divider);z-index:1}.vm-custom-panel-body-header__tabs{display:flex;justify-content:flex-start;flex-grow:1}.vm-custom-panel-body-header__graph-controls{display:flex;align-items:center;gap:8px;margin:5px 10px}.vm-custom-panel-body_mobile .vm-custom-panel-body-header{margin:-12px -12px 12px;padding:0 12px}.vm-tracings-view{display:grid;gap:12px}.vm-tracings-view-trace-header{display:flex;align-items:center;justify-content:space-between;border-bottom:var(--border-divider);padding:8px 8px 8px 12px}.vm-tracings-view-trace-header-title{flex-grow:1;font-size:16px;margin-right:8px}.vm-tracings-view-trace-header-title__query{font-weight:700}.vm-tracings-view-trace-header__expand-icon{display:flex;align-items:center;justify-content:center;width:20px;transition:transform .2s ease-in-out;transform:rotate(-90deg);color:var(--color-text-secondary)}.vm-tracings-view-trace-header__expand-icon_open{transform:rotate(0)}.vm-tracings-view-trace__nav{padding:12px 12px 12px 0}.vm-tracings-view-trace__nav_mobile{padding:8px 8px 8px 0}.vm-line-progress{display:grid;grid-template-columns:1fr auto;align-items:center;justify-content:center;gap:8px;color:var(--color-text-secondary)}.vm-line-progress-track{width:100%;height:12px;background-color:var(--color-hover-black);border-radius:4px}.vm-line-progress-track__thumb{height:100%;background-color:#1a90ff;border-radius:4px}.vm-nested-nav{position:relative;margin-left:16px;border-radius:4px}.vm-nested-nav_dark .vm-nested-nav-header{background-color:var(--color-background-body)}.vm-nested-nav_dark .vm-nested-nav-header:after,.vm-nested-nav_dark .vm-nested-nav-header:before{background-color:var(--color-background-body)}.vm-nested-nav_dark .vm-nested-nav-header:hover{box-shadow:#ffffff14 0 0 0 1px}.vm-nested-nav_mobile{margin-left:8px}.vm-nested-nav_root>.vm-nested-nav-header:before,.vm-nested-nav_root>.vm-nested-nav-header:after{display:none}.vm-nested-nav-header{position:relative;display:grid;grid-template-columns:auto 1fr;gap:8px;padding:8px;border-radius:4px;transition:box-shadow .2s ease-in-out;cursor:pointer;background-color:#c9e3f666;margin-bottom:8px;z-index:2}.vm-nested-nav-header:after{content:"";position:absolute;top:calc(50% - 1px);height:2px;width:12px;background-color:#c9e3f6;left:-12px}.vm-nested-nav-header:before{content:"";position:absolute;bottom:50%;left:-12px;height:calc(50% + 8px);width:2px;background-color:#c9e3f6}.vm-nested-nav-header:hover{box-shadow:#110f0f14 0 0 0 1px}.vm-nested-nav-header__icon{display:flex;align-items:center;justify-content:center;width:20px;transition:transform .2s ease-in-out;transform:rotate(-90deg);color:var(--color-text-secondary)}.vm-nested-nav-header__icon_open{transform:rotate(0)}.vm-nested-nav-header__progress{grid-column:2}.vm-nested-nav-header__message{position:relative;grid-column:2;line-height:130%;overflow:hidden;text-overflow:ellipsis;display:-moz-box;-moz-box-orient:vertical;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;line-clamp:3}.vm-nested-nav-header__message_show-full{display:block;overflow:visible}.vm-nested-nav-header__message_duration{color:var(--color-text-secondary)}.vm-nested-nav-header-bottom{display:grid;grid-template-columns:1fr auto;align-items:center;grid-column:2}.vm-nested-nav__childrens>.vm-nested-nav:not(:last-child):before{content:"";position:absolute;top:0;left:-12px;height:calc(100% + 32px);width:2px;background-color:#c9e3f6}.vm-nested-nav__childrens>.vm-nested-nav_dark:not(:last-child):before{background-color:var(--color-background-body)}.vm-nested-nav__childrens>.vm-nested-nav:last-child{margin-bottom:32px}.vm-line-chart{pointer-events:auto}.vm-line-chart_panning{pointer-events:none}.vm-line-chart__u-plot{position:relative}.vm-chart-tooltip{position:absolute;display:grid;gap:12px;width:370px;padding:12px;border-radius:8px;background:var(--color-background-tooltip);color:#fff;font-size:12px;font-weight:400;line-height:150%;word-wrap:break-word;font-family:monospace;z-index:98;-webkit-user-select:text;user-select:text;pointer-events:none}.vm-chart-tooltip_hits{white-space:pre-wrap;word-break:break-all;width:auto;max-width:33.3333333333vw}.vm-chart-tooltip_hits .vm-chart-tooltip-data{display:grid;grid-template-columns:14px 1fr}.vm-chart-tooltip_sticky{pointer-events:auto;z-index:99}.vm-chart-tooltip_moved{position:fixed;margin-top:-24.5px;margin-left:-316.5px}.vm-chart-tooltip-header{display:grid;grid-template-columns:1fr 25px 25px;gap:8px;align-items:center;justify-content:center;min-height:25px}.vm-chart-tooltip-header__title{grid-row:1}.vm-chart-tooltip-header__close{grid-row:1;grid-column:3;color:#fff}.vm-chart-tooltip-header__drag{grid-row:1;grid-column:2;color:#fff;cursor:move}.vm-chart-tooltip-header__date{grid-column:1;display:grid;gap:2px}.vm-chart-tooltip-data{display:flex;align-items:center;justify-content:flex-start;gap:8px}.vm-chart-tooltip-data_margin-bottom{margin-bottom:12px}.vm-chart-tooltip-data_margin-top{margin-top:12px}.vm-chart-tooltip-data__marker{min-width:14px;max-width:14px;width:14px;height:14px;border:1px solid rgba(255,255,255,.5)}.vm-chart-tooltip-data__marker_tranparent{opacity:0}.vm-chart-tooltip-data__value{line-height:1;font-size:14px}.vm-chart-tooltip-stats{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-start;gap:8px 12px}.vm-chart-tooltip-stats-row{display:grid;align-items:center;justify-content:flex-start}.vm-chart-tooltip-stats-row:not(:last-child){padding-right:8px}.vm-chart-tooltip-stats-row__key{line-height:1;margin-right:4px}.vm-chart-tooltip-stats-row__value{font-weight:700}.vm-chart-tooltip__info{word-break:break-all;white-space:pre-wrap}.vm-legend{position:relative;display:flex;flex-direction:column;cursor:default;width:100%}.vm-legend-group{min-width:23%;width:100%;margin:0 12px 12px 0}.vm-legend-group-header{display:grid;align-items:center;gap:8px;margin-bottom:1px;border-bottom:var(--border-divider);font-size:12px;padding:8px}.vm-legend-group-header-title{display:flex;align-items:center;gap:8px;color:var(--color-text-secondary)}.vm-legend-group-header-title b{color:var(--color-text)}.vm-legend-group-header-labels{display:flex;flex-wrap:wrap;gap:8px;color:var(--color-text-secondary)}.vm-legend-group-header-labels__item{color:var(--color-text);cursor:pointer}.vm-legend-group-header-labels__item:hover{text-decoration:underline}.vm-legend-group-header-labels__item:not(:last-child):after{content:","}.vm-legend-item{display:grid;grid-template-columns:auto auto;grid-gap:8px;align-items:start;justify-content:start;padding:8px;background-color:var(--color-background-block);cursor:pointer;transition:.2s ease;font-size:12px}.vm-legend-item:hover{background-color:#0000001a}.vm-legend-item_hide{text-decoration:line-through;opacity:.2}.vm-legend-item__marker{position:relative;width:14px;height:14px;box-sizing:border-box;transition:.2s ease;border-radius:2px}.vm-legend-item-info{font-weight:400;word-break:break-all}.vm-legend-item-info__label{margin-right:2px}.vm-legend-item-info__free-fields{padding:2px;cursor:pointer}.vm-legend-item-info__free-fields:hover{text-decoration:underline}.vm-legend-item-stats{grid-column:2;display:flex;align-items:center;gap:8px}.vm-legend-item-stats-row{display:flex;align-items:center;justify-content:flex-start}.vm-legend-item-stats-row:not(:last-child){padding-right:12px}.vm-legend-item-stats-row__key{line-height:1;color:var(--color-text-secondary);margin-right:4px}.vm-legend-table{table-layout:auto;max-width:100%;font-size:12px}.vm-legend-table__wrapper{width:100%;max-height:50vh;overflow:auto}.vm-legend-table-row_tbody{cursor:pointer;transition:.3s ease}.vm-legend-table-row_tbody:hover{background-color:#0000001a}.vm-legend-table-row_exclude{text-decoration:line-through;opacity:.2}.vm-legend-table-col{vertical-align:middle;text-align:left;padding:6px;overflow-wrap:anywhere}.vm-legend-table-col_thead{position:sticky;top:0;left:26px;font-weight:700;z-index:2;white-space:nowrap;background:var(--color-background-block)}.vm-legend-table-col_marker{position:sticky;left:0;width:26px;padding:0 6px}.vm-legend-table-col_marker:not(th){z-index:1}.vm-legend-table-col__content{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vm-select-input{position:relative;display:flex;align-items:center;padding:8px 0 8px 12px;cursor:pointer;border:var(--border-divider);border-radius:4px;min-height:40px}.vm-select-input-content{display:flex;align-items:center;justify-content:flex-start;flex-wrap:wrap;gap:8px;flex-grow:1}.vm-select-input-content_mobile{flex-wrap:nowrap}.vm-select-input-content__counter{font-size:14px;line-height:14px}.vm-select-input-content__selected{display:inline-flex;align-items:center;justify-content:center;background-color:var(--color-hover-black);padding:2px 2px 2px 8px;border-radius:4px;font-size:12px;line-height:14px;max-width:100%}.vm-select-input-content__selected span{width:100%;overflow:hidden;text-overflow:ellipsis}.vm-select-input-content__selected svg{width:20px;display:flex;align-items:center;justify-content:center;margin-left:10px;background-color:transparent;border-radius:4px;transition:background-color .2s ease-in-out;padding:4px}.vm-select-input-content__selected svg:hover{background-color:#110f0f1a}.vm-select-input input{display:inline-block;position:relative;border-radius:4px;font-size:14px;line-height:18px;height:18px;padding:0;border:none;z-index:2;min-width:100px;flex-grow:1;background-color:transparent;color:var(--color-text)}.vm-select-input input:placeholder-shown{width:auto}.vm-select-input__icon{display:inline-flex;align-items:center;justify-content:flex-end;color:var(--color-text-secondary);border-right:var(--border-divider);transition:transform .2s ease-in,opacity .2s ease-in;cursor:pointer;padding:0 8px}.vm-select-input__icon:last-child{border:none}.vm-select-input__icon svg{width:14px}.vm-select-input__icon_open{transform:rotate(180deg)}.vm-select-input__icon:hover{opacity:.7}.vm-select-options{display:grid;gap:8px;max-width:300px;max-height:208px;overflow:auto;padding:12px;font-size:14px}.vm-select-options_mobile{padding:0 12px 8px;max-width:100%;max-height:calc(var(--vh) * 100 - 70px)}.vm-select_disabled *{cursor:not-allowed}.vm-select_disabled .vm-select-input-content input{color:var(--color-text-disabled)}.vm-legend-configs{display:grid;gap:16px}.vm-legend-configs_compact{display:flex;justify-content:flex-end;flex-wrap:wrap;gap:12px;padding:12px}.vm-legend-configs_compact .vm-legend-configs-item_switch{display:flex}.vm-legend-configs_compact .vm-legend-configs-item__label,.vm-legend-configs_compact .vm-legend-configs-item__info{display:none}.vm-legend-configs-item{display:grid;align-items:center;justify-content:stretch;margin-top:6px}.vm-legend-configs-item_switch{grid-template-columns:1fr 100px;margin-top:0}.vm-legend-configs-item__info{margin-top:6px;font-size:12px;color:var(--color-text-secondary);line-height:130%}.vm-legend-configs-item__info_input{margin-top:0}.vm-legend-heatmap{display:inline-grid;grid-template-columns:auto auto;align-items:center;justify-content:space-between;gap:4px}.vm-legend-heatmap__wrapper{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap}.vm-legend-heatmap__value{color:var(--color-text);font-size:12px}.vm-legend-heatmap__value:last-child{text-align:right}.vm-legend-heatmap-gradient{display:flex;align-items:center;justify-content:center;position:relative;grid-column:1/-1;height:12px;width:200px}.vm-legend-heatmap-gradient__value{display:flex;align-items:center;justify-content:center;position:absolute;top:-2px;border-radius:50%;border:2px solid var(--color-text);width:16px;height:16px;transform:translate(-8px);transition:left .1s ease}.vm-legend-heatmap-gradient__value span{position:absolute;top:18px;left:auto;padding:4px 8px;color:var(--color-text);font-size:12px;background-color:var(--color-background-block);box-shadow:var(--box-shadow)}.vm-legend-heatmap__labels{word-break:break-all}.vm-graph-view{width:100%}.vm-graph-view_full-width{width:calc(100vw - 48px - var(--scrollbar-width))}@media (max-width: 768px){.vm-graph-view_full-width{width:calc(100vw - 24px - var(--scrollbar-width))}}.vm-graph-view_full-width_mobile{width:calc(100vw - 24px - var(--scrollbar-width))}.vm-legend-anomaly{position:relative;display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:32px;cursor:default}.vm-legend-anomaly-item{display:flex;align-items:center;justify-content:center;gap:8px}.vm-legend-anomaly-item svg{width:30px;height:14px}.vm-axes-limits{display:grid;align-items:center}.vm-axes-limits_mobile{width:100%;max-width:100%;gap:12px}.vm-axes-limits_mobile .vm-axes-limits-list__inputs{grid-template-columns:repeat(2,1fr)}.vm-axes-limits-list{display:grid;align-items:center;gap:12px}.vm-axes-limits-list__inputs{display:grid;grid-template-columns:repeat(2,auto);gap:8px;margin-top:12px}.vm-graph-settings{display:flex;align-items:center;gap:8px}.vm-graph-settings-modal .vm-modal-content-body{padding:0}.vm-graph-settings-modal .vm-modal-content-header{margin-bottom:0}.vm-graph-settings-body{display:grid;min-width:300px}.vm-graph-settings-body-section{border-bottom:var(--border-divider)}.vm-graph-settings-body-section:last-child{border-bottom:none;padding-bottom:16px}.vm-graph-settings-body-section__title{padding:12px;font-weight:700;background:var(--color-hover-black)}.vm-graph-settings-body-section-content{display:grid;gap:16px;padding:16px}.vm-graph-settings-row{display:grid;align-items:center;justify-content:stretch;grid-template-columns:1fr 100px}.vm-json-view__copy{position:sticky;top:0;display:flex;justify-content:flex-end;z-index:2}.vm-json-view__code{transform:translateY(-32px);font-size:14px;line-height:1.4;white-space:pre-wrap}.vm-table-view{margin-top:-12px;max-width:100%;overflow:auto}.vm-table-view_mobile{margin-top:-12px}.vm-table-view table{margin-top:0}.vm-table-settings-modal .vm-modal-content-body{min-width:clamp(300px,600px,90vw);padding:0}.vm-table-settings-modal-section{padding-block:12px;border-top:var(--border-divider)}.vm-table-settings-modal-section:first-child{padding-top:0;border-top:none}.vm-table-settings-modal-section__title{padding-inline:12px;font-size:14px;font-weight:700;margin-bottom:12px}.vm-table-settings-modal-columns__search{padding-inline:12px}.vm-table-settings-modal-columns-list{display:flex;flex-direction:column;max-height:250px;min-height:250px;overflow:auto;margin-bottom:12px}@media (max-width: 500px){.vm-table-settings-modal-columns-list{width:100vw}}.vm-table-settings-modal-columns-list__item{width:100%;font-size:14px;border-radius:4px}.vm-table-settings-modal-columns-list__item>div{padding:8px 12px}.vm-table-settings-modal-columns-list__item_all{font-weight:700}.vm-table-settings-modal-columns-list__item:hover,.vm-table-settings-modal-columns-list__item_focus{background-color:var(--color-hover-black)}.vm-table-settings-modal-columns-list__item_custom .vm-checkbox__label:after{width:100%;content:"(custom column, will be removed if unchecked)";padding:0 8px;text-align:right;font-style:italic;color:var(--color-text-secondary)}.vm-table-settings-modal-columns-no-found{display:flex;flex-direction:column;min-width:100%;min-height:250px;align-items:center;justify-content:center;gap:12px}.vm-table-settings-modal-columns-no-found__info{text-align:center;font-style:italic;color:var(--color-text-secondary)}.vm-checkbox{display:flex;align-items:center;justify-content:flex-start;cursor:pointer;-webkit-user-select:none;user-select:none}.vm-checkbox_disabled{opacity:.6;cursor:default}.vm-checkbox_secondary_active .vm-checkbox-track{background-color:var(--color-secondary)}.vm-checkbox_secondary .vm-checkbox-track{border:1px solid var(--color-secondary)}.vm-checkbox_primary_active .vm-checkbox-track{background-color:var(--color-primary)}.vm-checkbox_primary .vm-checkbox-track{border:1px solid var(--color-primary)}.vm-checkbox_active .vm-checkbox-track__thumb{transform:scale(1)}.vm-checkbox:hover .vm-checkbox-track{opacity:.8}.vm-checkbox-track{position:relative;background-color:transparent;display:flex;align-items:center;justify-content:center;border-radius:4px;padding:2px;width:16px;height:16px;transition:background-color .2s ease,opacity .3s ease-out}.vm-checkbox-track__thumb{display:grid;align-items:center;justify-content:center;width:12px;height:12px;color:#fff;transform:scale(0);transition:transform .1s ease-in-out}.vm-checkbox__label{white-space:nowrap;font-size:inherit;color:inherit;margin-left:8px;transition:color .2s ease}.vm-download-report{display:grid;gap:16px;padding-top:4px;width:700px;max-width:100%}.vm-download-report-settings{display:grid;gap:16px}.vm-download-report-settings__title{display:flex;align-items:center;margin-right:12px;font-size:14px;font-weight:600;white-space:nowrap}.vm-download-report__buttons{display:flex;align-items:center;justify-content:flex-end;gap:12px}.vm-download-report-helper{display:grid;gap:8px;padding:12px}.vm-download-report-helper__description{max-width:400px;white-space:pre-line;line-height:1.3}.vm-download-report-helper__description p{margin-bottom:4px}.vm-download-report-helper__buttons{display:flex;align-items:center;justify-content:flex-end;gap:8px}.vm-markdown-editor{margin-top:6px;padding:0 6px;border-radius:4px;border:var(--border-divider);overflow:hidden}.vm-markdown-editor-header{display:flex;align-items:center;background-color:var(--color-hover-black);padding-right:12px;border-bottom:var(--border-divider);margin:-1px -7px 6px}.vm-markdown-editor-header-tabs{display:flex}.vm-markdown-editor-header-tabs__tab{display:flex;align-items:center;justify-content:center;margin-bottom:-1px;padding:8px 16px;min-height:40px;color:var(--color-text-secondary);transition:color .3s;cursor:pointer}.vm-markdown-editor-header-tabs__tab:hover{color:var(--color-text)}.vm-markdown-editor-header-tabs__tab_active{position:relative;color:var(--color-text);background-color:var(--color-background-body);border-top-right-radius:4px;border-top-left-radius:4px;z-index:1}.vm-markdown-editor-header-tabs__tab_active:first-child{border-right:var(--border-divider)}.vm-markdown-editor-header-tabs__tab_active:last-child{border-right:var(--border-divider);border-left:var(--border-divider)}.vm-markdown-editor-header__info{margin-left:auto;margin-right:0;color:var(--color-text-secondary);font-size:12px;font-weight:500}.vm-markdown-editor-preview{padding:8px;margin-bottom:6px}.vm-markdown-editor-preview,.vm-markdown-editor textarea{min-height:200px;resize:vertical}.vm-warning-heatmap-to-line{display:flex;align-items:center;justify-content:space-between}.vm-predefined-panel-header{display:grid;grid-template-columns:auto 1fr auto;align-items:center;justify-content:flex-start;gap:8px;padding:8px 16px;border-bottom:var(--border-divider)}.vm-predefined-panel-header__description{white-space:pre-wrap;line-height:1.3}.vm-predefined-panel-header__description ul,.vm-predefined-panel-header__description ol{list-style-position:inside}.vm-predefined-panel-header__description a{color:#c9e3f6;text-decoration:underline}.vm-predefined-panel-header__info{display:flex;align-items:center;justify-content:center;width:18px;color:var(--color-primary)}.vm-predefined-panel-body{padding:8px 16px;min-height:500px}@media (max-width: 500px){.vm-predefined-panel-body{padding:0}}.vm-predefined-dashboard{background-color:transparent}.vm-predefined-dashboard-header{position:relative;display:grid;align-items:center;justify-content:space-between;grid-template-columns:1fr auto;padding:12px;border-radius:4px;font-weight:700;transform-style:preserve-3d;overflow:hidden;line-height:1;box-shadow:var(--box-shadow);transition:box-shadow .2s ease-in-out}.vm-predefined-dashboard-header_open{border-radius:4px 4px 0 0;box-shadow:none}.vm-predefined-dashboard-header__title{font-size:14px}.vm-predefined-dashboard-header__count{grid-column:2;font-size:12px;margin-right:26px}.vm-predefined-dashboard-panels{display:grid;grid-template-columns:repeat(12,1fr);gap:12px;padding:0}@media (max-width: 1000px){.vm-predefined-dashboard-panels{grid-template-columns:1fr}}.vm-predefined-dashboard-panels-panel{position:relative;border-radius:8px;overflow:hidden}.vm-predefined-dashboard-panels-panel:hover .vm-predefined-dashboard-panels-panel__resizer{transform:scale(1)}.vm-predefined-dashboard-panels-panel__resizer{position:absolute;bottom:0;right:0;width:20px;height:20px;transform:scale(0);transition:transform .2s ease-in-out;cursor:ew-resize;z-index:1}.vm-predefined-dashboard-panels-panel__resizer:after{content:"";position:absolute;bottom:5px;right:5px;border-bottom:2px solid rgba(17,15,15,.2);border-right:2px solid rgba(17,15,15,.2);width:5px;height:5px}.vm-predefined-dashboard-panels-panel__alert{grid-column:span 12}.vm-predefined-panels{display:grid;gap:12px;align-items:flex-start}@media (max-width: 768px){.vm-predefined-panels{padding:12px 0}}@media (max-width: 500px){.vm-predefined-panels{padding:8px 0}}.vm-predefined-panels-tabs{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-start;font-size:12px;gap:8px;overflow:hidden}@media (max-width: 768px){.vm-predefined-panels-tabs{padding:0 12px}}.vm-predefined-panels-tabs__tab{padding:8px 12px;border-radius:8px;cursor:pointer;transition:background .2s ease-in-out,color .15s ease-in;background:var(--color-background-block);text-transform:uppercase;color:var(--color-text-secondary);text-align:center;border:1px solid rgba(17,15,15,.2)}@media (max-width: 500px){.vm-predefined-panels-tabs__tab{flex-grow:1}}.vm-predefined-panels-tabs__tab:hover{color:var(--color-primary)}.vm-predefined-panels-tabs__tab_active{border-color:var(--color-primary);color:var(--color-primary)}.vm-predefined-panels__dashboards{display:grid;gap:12px}.vm-cardinality-configurator{display:grid;gap:8px}.vm-cardinality-configurator-controls{display:flex;align-items:center;justify-content:flex-start;flex-wrap:wrap;gap:8px 12px}.vm-cardinality-configurator-controls__query{flex-grow:10}.vm-cardinality-configurator-controls__item{flex-grow:2}.vm-cardinality-configurator-controls__item_limit{flex-grow:1}.vm-cardinality-configurator-controls__item svg{color:var(--color-text-disabled)}.vm-cardinality-configurator-bottom{display:flex;align-items:center;justify-content:flex-end;flex-wrap:wrap;gap:12px;width:100%}.vm-cardinality-configurator-bottom-helpful{display:flex;align-items:center;justify-content:flex-end;flex-wrap:wrap;gap:8px 12px}.vm-cardinality-configurator-bottom-helpful a{color:var(--color-text-secondary)}.vm-cardinality-configurator-bottom__execute{display:flex;align-items:center;gap:8px}.vm-cardinality-configurator_mobile .vm-cardinality-configurator-bottom{justify-content:center}.vm-cardinality-configurator_mobile .vm-cardinality-configurator-bottom-helpful{flex-grow:1;justify-content:center}.vm-cardinality-configurator_mobile .vm-cardinality-configurator-bottom__execute{width:100%}.vm-cardinality-configurator_mobile .vm-cardinality-configurator-bottom__execute button:nth-child(3){width:100%}.vm-cardinality-totals{display:inline-flex;flex-wrap:wrap;align-content:flex-start;justify-content:flex-start;gap:16px;flex-grow:1}.vm-cardinality-totals_mobile{gap:12px;justify-content:center}.vm-cardinality-totals-card{display:grid;grid-template-columns:auto 1fr;align-items:flex-end;justify-content:center;gap:8px 4px;padding:8px}.vm-cardinality-totals-card__info-icon{width:15px;display:flex;align-items:center;justify-content:center;color:var(--color-primary)}.vm-cardinality-totals-card__title{display:flex;align-items:center;justify-content:flex-start;gap:4px;grid-column:1/-1;color:var(--color-text)}.vm-cardinality-totals-card__tooltip{max-width:280px;white-space:normal;padding:8px}.vm-cardinality-totals-card__value{font-weight:700;color:var(--color-primary);font-size:18px;line-height:14px;text-align:center}.vm-cardinality-totals-card__link{text-align:right;font-size:12px;margin-left:8px}.vm-metrics-content{border:var(--border-divider)}.vm-metrics-content-header{margin:-12px -12px 0;background-color:var(--color-hover-black)}.vm-metrics-content-header__title{display:flex;align-items:center;justify-content:flex-start}.vm-metrics-content-header__tip{max-width:300px;white-space:normal;padding:8px}.vm-metrics-content-header__tip p{margin-bottom:8px}.vm-metrics-content-header__tip-icon{width:15px;display:flex;align-items:center;justify-content:center;color:var(--color-primary);margin-right:4px}.vm-metrics-content_mobile .vm-metrics-content-header{margin:-12px -12px 0}.vm-metrics-content__table{padding-top:12px;width:calc(100vw - 64px - var(--scrollbar-width));overflow:auto}@media (max-width: 768px){.vm-metrics-content__table{width:calc(100vw - 24px - var(--scrollbar-width))}}.vm-metrics-content__table_mobile{width:calc(100vw - 24px - var(--scrollbar-width))}.vm-metrics-content__table .vm-table-cell_header{white-space:nowrap}.vm-metrics-content__table th,.vm-metrics-content__table td{vertical-align:middle;height:33px}.vm-metrics-content_mobile .vm-metrics-content__table{width:calc(100vw - 24px - var(--scrollbar-width))}.vm-metrics-content__chart{padding-top:12px}.vm-metrics-content-prom-data{display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;gap:8px;margin-top:12px;text-align:center}.vm-metrics-content-prom-data__icon{display:flex;align-items:center;justify-content:center;width:30px;height:30px;margin-bottom:8px;color:var(--color-primary)}.vm-metrics-content-prom-data__title{font-size:16px;font-weight:700}.vm-metrics-content-prom-data__text{max-width:700px;line-height:1.3}.vm-simple-bar-chart{display:grid;grid-template-columns:auto 1fr;height:100%;padding-bottom:6px;overflow:hidden}.vm-simple-bar-chart-y-axis{position:relative;display:grid;transform:translateY(12px)}.vm-simple-bar-chart-y-axis__tick{position:relative;display:flex;align-items:center;justify-content:flex-end;transform-style:preserve-3d;text-align:right;padding-right:8px;font-size:12px;line-height:2;z-index:1}.vm-simple-bar-chart-y-axis__tick:after{content:"";position:absolute;top:auto;left:100%;width:100vw;height:0;border-bottom:var(--border-divider);transform:translateY(-1px) translateZ(-1)}.vm-simple-bar-chart-data{position:relative;display:flex;align-items:flex-end;justify-content:space-between;gap:1%}.vm-simple-bar-chart-data-item{display:flex;align-items:flex-start;justify-content:center;flex-grow:1;width:100%;min-width:1px;height:calc(100% - 48px);background-color:#3b5;transition:background-color .2s ease-in}.vm-simple-bar-chart-data-item:hover{background-color:#7fdc96}.vm-simple-bar-chart-data-item:first-child{background-color:#f79420}.vm-simple-bar-chart-data-item:first-child:hover{background-color:#fabf79}.vm-cardinality-panel{display:grid;align-items:flex-start;gap:16px}.vm-cardinality-panel_mobile,.vm-cardinality-panel_mobile .vm-cardinality-panel-tips{gap:8px}.vm-cardinality-panel-tips{display:inline-flex;flex-wrap:wrap;align-content:flex-start;justify-content:flex-start;gap:12px;flex-grow:1;width:100%}.vm-cardinality-panel-table__header th:first-child{width:60%}.vm-cardinality-panel-table__progress{display:grid;grid-template-columns:minmax(160px,1fr) repeat(2,auto);white-space:nowrap;align-items:center;justify-content:flex-start;gap:8px;font-size:12px}.vm-cardinality-tip{display:grid;grid-template-rows:auto 1fr;background-color:var(--color-background-block);border-radius:8px;box-shadow:var(--box-shadow);overflow:hidden;color:var(--color-text-secondary);flex-grow:1;width:300px}.vm-cardinality-tip-header{position:relative;display:flex;align-items:center;justify-content:center;padding:8px 12px;border-bottom:var(--border-divider);gap:4px}.vm-cardinality-tip-header:after{content:"";position:absolute;top:0;left:0;width:100%;height:100%;background:var(--color-warning);opacity:.1;pointer-events:none}.vm-cardinality-tip-header__tip-icon{width:12px;display:flex;align-items:center;justify-content:center;color:var(--color-warning)}.vm-cardinality-tip-header__title{font-weight:700;text-align:center;color:var(--color-text)}.vm-cardinality-tip-header__tooltip{max-width:280px;white-space:normal;padding:8px;line-height:130%;font-size:14px}.vm-cardinality-tip__description{padding:8px 12px;line-height:130%}.vm-cardinality-tip__description p{margin-bottom:8px}.vm-cardinality-tip__description p:last-child{margin-bottom:0}.vm-cardinality-tip__description ul,.vm-cardinality-tip__description ol{list-style-position:inside}.vm-cardinality-tip__description ul li,.vm-cardinality-tip__description ol li{margin-bottom:4px}.vm-top-queries-panel-header,.vm-top-queries-panel-header_mobile{margin:-12px -12px 0}.vm-top-queries-panel__table{padding-top:12px;width:calc(100vw - 48px - var(--scrollbar-width));overflow:auto}@media (max-width: 768px){.vm-top-queries-panel__table{width:calc(100vw - 24px - var(--scrollbar-width))}}.vm-top-queries-panel__table_mobile{width:calc(100vw - 24px - var(--scrollbar-width))}.vm-top-queries-panel__table .vm-table-cell_header{white-space:nowrap}.vm-top-queries{display:grid;align-items:flex-start;gap:12px}.vm-top-queries_mobile{gap:8px}.vm-top-queries-controls{display:grid;gap:8px}.vm-top-queries-controls-fields{display:flex;align-items:center;flex-wrap:wrap;gap:12px}.vm-top-queries-controls-fields__item{flex-grow:1;min-width:200px}.vm-top-queries-controls-bottom{display:grid;grid-template-columns:1fr auto;align-items:flex-end;justify-content:space-between;gap:12px}.vm-top-queries-controls-bottom_mobile{grid-template-columns:1fr;gap:8px}.vm-top-queries-controls-bottom__button{display:flex;align-items:center;justify-content:flex-end}.vm-top-queries-panels{display:grid;gap:12px}.vm-top-queries-panels__table-actions{display:flex;align-items:center;justify-content:flex-end;gap:8px;height:100%;padding:0 8px}.vm-trace-page{display:flex;flex-direction:column;min-height:100%}@media (max-width: 768px){.vm-trace-page{padding:12px 0}}.vm-trace-page-header{display:grid;grid-template-columns:1fr auto;align-items:start;gap:12px;margin-bottom:12px}@media (max-width: 768px){.vm-trace-page-header{grid-template-columns:1fr;padding:0 12px}}.vm-trace-page-header-errors{display:grid;align-items:flex-start;justify-content:stretch;grid-template-columns:1fr;gap:12px}@media (max-width: 768px){.vm-trace-page-header-errors{grid-row:2}}.vm-trace-page-header-errors-item{position:relative;display:grid;align-items:center;justify-content:stretch}.vm-trace-page-header-errors-item_margin-bottom{margin-bottom:12px}.vm-trace-page-header-errors-item__filename{min-height:20px}.vm-trace-page-header-errors-item__close{position:absolute;top:auto;right:8px;z-index:2}.vm-trace-page-preview{flex-grow:1;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;min-height:calc(var(--vh) * 50 - var(--scrollbar-height))}.vm-trace-page-preview__text{margin-bottom:12px;font-size:14px;white-space:pre-line;text-align:center;line-height:1.8}.vm-trace-page__dropzone{position:fixed;top:0;left:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;box-shadow:inset var(--color-primary) 0 0 10px;opacity:.5;z-index:100;pointer-events:none}.vm-upload-json-buttons{display:grid;grid-template-columns:1fr 1fr;gap:12px;align-items:center;justify-content:center}.vm-upload-json-buttons__upload{position:relative}.vm-explore-metrics{display:grid;align-items:flex-start;gap:12px}@media (max-width: 500px){.vm-explore-metrics{gap:8px}}.vm-explore-metrics-body{display:grid;align-items:flex-start;gap:12px}@media (max-width: 500px){.vm-explore-metrics-body{gap:8px}}.vm-explore-metrics-graph,.vm-explore-metrics-graph_mobile{padding:0 12px 12px}.vm-explore-metrics-graph__warning{display:grid;grid-template-columns:1fr auto;align-items:center;justify-content:space-between}.vm-explore-metrics-item-header{display:grid;grid-template-columns:auto 1fr auto auto;align-items:center;justify-content:flex-start;padding:12px;border-bottom:var(--border-divider);gap:12px}.vm-explore-metrics-item-header_mobile{grid-template-columns:1fr auto;padding:8px 12px}.vm-explore-metrics-item-header__index{color:var(--color-text-secondary);font-size:12px}.vm-explore-metrics-item-header__name{flex-grow:1;font-weight:700;max-width:100%;text-overflow:ellipsis;overflow:hidden;line-height:130%}.vm-explore-metrics-item-header-order{grid-column:1;display:grid;grid-template-columns:auto 20px auto;align-items:center;justify-content:flex-start;text-align:center}.vm-explore-metrics-item-header-order__up{transform:rotate(180deg)}.vm-explore-metrics-item-header__rate{grid-column:3}.vm-explore-metrics-item-header__close{grid-row:1;grid-column:4;display:grid;align-items:center}.vm-explore-metrics-item-header code{padding:.2em .4em;font-size:85%;background-color:var(--color-hover-black);border-radius:6px}.vm-explore-metrics-item-header-modal{display:grid;align-items:flex-start;gap:12px}.vm-explore-metrics-item-header-modal-order{display:flex;align-items:center;justify-content:space-between;gap:12px}.vm-explore-metrics-item-header-modal-order p{display:flex;align-items:center}.vm-explore-metrics-item-header-modal-order__index{margin-left:4px}.vm-explore-metrics-item-header-modal__rate{display:grid;gap:8px}.vm-explore-metrics-item-header-modal__rate p{color:var(--color-text-secondary)}.vm-explore-metrics-item{position:relative}.vm-explore-metrics-header{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-start;gap:12px 18px;max-width:calc(100vw - var(--scrollbar-width))}.vm-explore-metrics-header_mobile{flex-direction:column;align-items:stretch}.vm-explore-metrics-header__job{flex-grow:1;min-width:150px}.vm-explore-metrics-header__instance{flex-grow:2;min-width:150px}.vm-explore-metrics-header__size{flex-grow:1;min-width:150px;display:grid;grid-template-columns:1fr auto;align-items:center;gap:12px}.vm-explore-metrics-header-description{display:grid;grid-template-columns:1fr auto;align-items:flex-start;gap:8px}.vm-explore-metrics-header-description ul{list-style-position:inside}.vm-explore-metrics-header-description button{color:inherit;min-height:29px}.vm-explore-metrics-header-description code{margin:0 3px}.vm-explore-metrics-header-metrics{flex-grow:1;width:100%}.vm-explore-metrics-header__clear-icon{display:flex;align-items:center;justify-content:center;padding:2px;cursor:pointer}.vm-explore-metrics-header__clear-icon:hover{opacity:.7}.vm-preview-icons{display:grid;align-items:flex-start;justify-content:center;grid-template-columns:repeat(auto-fill,100px);gap:12px}.vm-preview-icons-item{display:grid;grid-template-rows:1fr auto;align-items:stretch;justify-content:center;gap:8px;height:100px;padding:12px 8px;border-radius:4px;border:1px solid transparent;cursor:pointer;transition:box-shadow .2s ease-in-out}.vm-preview-icons-item:hover{box-shadow:#00000029 0 1px 4px}.vm-preview-icons-item:active .vm-preview-icons-item__svg{transform:scale(.9)}.vm-preview-icons-item__name{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;text-align:center;font-size:12px;line-height:2}.vm-preview-icons-item__svg{display:flex;align-items:center;justify-content:center;height:100%;transition:transform .1s ease-out}.vm-preview-icons-item__svg svg{width:auto;height:24px}.vm-with-template{display:grid;gap:12px}.vm-with-template-body{display:grid;gap:12px;align-items:flex-start;width:100%}.vm-with-template-body-top{display:flex;gap:8px;align-items:center;justify-content:flex-end}.vm-with-template-body__expr textarea{min-height:200px}.vm-with-template-body__result textarea{min-height:60px}.vm-with-template-body textarea{font-family:monospace;overflow:auto;width:100%;height:100%}.vm-with-template-tutorial{display:grid;gap:16px}.vm-with-template-tutorial__title{font-size:16px;font-weight:700}.vm-with-template-tutorial-section{display:grid;gap:12px}.vm-with-template-tutorial-section__text{font-size:14px;line-height:130%;max-width:720px}.vm-code-example{position:relative;display:block;padding:12px;white-space:pre-wrap;border-radius:4px;background-color:#110f0f0d;overflow:auto}.vm-code-example__copy{position:absolute;right:10px;top:10px}.vm-relabeling{display:grid;gap:12px}.vm-relabeling-header{display:grid;gap:12px;align-items:flex-start;width:100%}.vm-relabeling-header-configs textarea{min-height:200px}.vm-relabeling-header__labels textarea{min-height:60px}.vm-relabeling-header textarea{font-family:monospace;overflow:auto;width:100%;height:100%}.vm-relabeling-header-bottom{display:flex;align-items:center;justify-content:flex-end;gap:12px}.vm-relabeling-header-bottom a{color:var(--color-text-secondary)}.vm-relabeling-steps{display:grid;gap:12px}.vm-relabeling-steps-item{display:grid;gap:12px;padding:0 12px 12px;border-bottom:var(--border-divider)}.vm-relabeling-steps-item:last-child{border-bottom:none;padding-bottom:0}.vm-relabeling-steps-item__row{display:grid;grid-template-columns:100px 1fr}@media (max-width: 500px){.vm-relabeling-steps-item__row{grid-template-columns:1fr;gap:4px}}.vm-relabeling-steps-item__row pre{white-space:pre-wrap}.vm-active-queries-header{display:grid;grid-template-columns:1fr auto;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px}.vm-active-queries-header-controls{grid-column:2;display:grid;gap:8px}.vm-active-queries-header__update-msg{white-space:nowrap;color:var(--color-text-secondary);font-size:12px}.vm-json-form{display:grid;grid-template-rows:auto calc(var(--vh) * 70 - 78px - 36px) auto;gap:12px;width:70vw;max-width:1000px;max-height:900px;overflow:hidden}.vm-json-form_mobile{width:100%;min-height:100%;grid-template-rows:auto calc(var(--vh) * 100 - 200px - 36px) auto}.vm-json-form_one-field{grid-template-rows:calc(var(--vh) * 70 - 78px - 36px) auto}.vm-json-form_one-field_mobile{grid-template-rows:calc(var(--vh) * 100 - 160px - 24px) auto}.vm-json-form textarea{overflow:auto;width:100%;height:100%;max-height:900px}.vm-json-form-footer{display:flex;align-items:center;justify-content:space-between;gap:8px}@media (max-width: 500px){.vm-json-form-footer{flex-direction:column}.vm-json-form-footer button{flex-grow:1}}.vm-json-form-footer__controls{flex-grow:1;display:flex;align-items:center;justify-content:flex-start;gap:8px}@media (max-width: 500px){.vm-json-form-footer__controls{grid-template-columns:repeat(2,1fr);justify-content:center;width:100%}}.vm-json-form-footer__controls_right{display:grid;grid-template-columns:repeat(2,90px);justify-content:flex-end}@media (max-width: 500px){.vm-json-form-footer__controls_right{grid-template-columns:repeat(2,1fr);justify-content:center;width:100%}}.vm-query-analyzer{display:flex;flex-direction:column}@media (max-width: 768px){.vm-query-analyzer{padding:12px 0}}.vm-query-analyzer-header{display:grid;grid-template-columns:1fr auto;gap:12px;margin-bottom:12px}.vm-query-analyzer-error{position:relative;margin:12px 0}.vm-query-analyzer-error__close{position:absolute;top:8px;right:8px;z-index:2}.vm-query-analyzer-view{display:grid;gap:12px;position:relative}.vm-query-analyzer-view-header{position:relative;display:flex;align-items:center;justify-content:space-between;font-size:12px;margin:-12px -12px 12px;padding:0 12px;border-bottom:var(--border-divider);z-index:1}.vm-query-analyzer-view-header__left{display:flex;align-items:center;gap:8px}.vm-query-analyzer-view_mobile .vm-query-analyzer-view-header{margin:-12px -12px 12px;padding:0 12px}.vm-query-analyzer-info-header{display:flex;align-items:center;width:100%;height:100%;gap:8px;font-size:12px;background-color:var(--color-background-body);z-index:1}.vm-query-analyzer-info-header__title{font-size:18px;font-weight:500}.vm-query-analyzer-info-header__timerange{display:flex;align-items:center;gap:4px;border:var(--border-divider);border-radius:4px;padding:4px 8px;font-size:12px}.vm-query-analyzer-info-header__timerange svg{width:13px;color:var(--color-primary)}.vm-query-analyzer-info-header__info{margin-left:auto;margin-right:0}.vm-query-analyzer-info__modal{width:min(800px,90vw)}.vm-query-analyzer-info-comment{position:relative;max-width:800px;border-radius:8px;border:var(--border-divider);font-size:12px}.vm-query-analyzer-info-comment-header{display:grid;grid-template-columns:16px 1fr;align-items:center;gap:8px;padding:8px;border-bottom:var(--border-divider);background-color:var(--color-hover-black);font-weight:500;z-index:1}.vm-query-analyzer-info-comment-header svg{color:var(--color-primary)}.vm-query-analyzer-info-comment-body{padding:8px;max-height:60vh;overflow:auto}.vm-query-analyzer-info-stats{border-radius:8px;border:var(--border-divider);font-size:12px;margin-bottom:12px;overflow:hidden}.vm-query-analyzer-info-stats table{width:100%}.vm-query-analyzer-info-stats td,.vm-query-analyzer-info-stats th{padding:8px;text-align:left}.vm-query-analyzer-info-stats tr{border-bottom:var(--border-divider)}.vm-query-analyzer-info-stats thead th{font-weight:500}.vm-query-analyzer-info-stats tbody tr{transition:background-color .3s}.vm-query-analyzer-info-stats tbody tr:hover{background-color:var(--color-hover-black)}.vm-query-analyzer-info-stats tbody tr:last-child{border-bottom:none}.vm-downsampling-filters{display:grid;gap:12px}.vm-downsampling-filters-body{display:grid;gap:12px;align-items:flex-start;width:100%}.vm-downsampling-filters-body__title{margin-bottom:12px}.vm-downsampling-filters-body-top{display:flex;gap:8px;align-items:center;justify-content:flex-end}.vm-downsampling-filters-body__expr textarea{min-height:200px}.vm-downsampling-filters-body__result textarea{min-height:60px}.vm-downsampling-filters-body code{background-color:var(--color-hover-black);border-radius:6px;font-size:85%;padding:.2em .4em}.vm-downsampling-filters-body textarea{font-family:monospace;overflow:auto;width:100%;height:100%}.vm-retention-filters{display:grid;gap:12px}.vm-retention-filters-body{display:grid;gap:12px;align-items:flex-start;width:100%}.vm-retention-filters-body__title{margin-bottom:12px}.vm-retention-filters-body-top{display:flex;gap:8px;align-items:center;justify-content:flex-end}.vm-retention-filters-body__expr textarea{min-height:200px}.vm-retention-filters-body__result textarea{min-height:60px}.vm-retention-filters-body code{background-color:var(--color-hover-black);border-radius:6px;font-size:85%;padding:.2em .4em}.vm-retention-filters-body textarea{font-family:monospace;overflow:auto;width:100%;height:100%}html,body,#root{font-family:system-ui;font-size:14px;color:var(--color-text);min-height:100%;cursor:default;background-repeat:no-repeat;background-attachment:fixed;margin:0;background-color:var(--color-background-body)}body{overflow:auto}*{font:inherit;cursor:inherit;touch-action:pan-x pan-y;-webkit-tap-highlight-color:transparent}code{font-family:monospace}b{font-weight:700}textarea,input{cursor:text}input::placeholder,textarea::placeholder{-webkit-user-select:none;user-select:none}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.vm-snackbar{position:fixed;left:12px;bottom:12px;z-index:999;animation:vm-slide-snackbar .15s cubic-bezier(.28,.84,.42,1.1)}.vm-snackbar-content{display:grid;grid-template-columns:1fr auto;gap:16px;align-items:flex-start;line-height:24px}.vm-snackbar-content__close{display:flex;align-items:center;justify-content:center;width:24px;height:24px;padding:4px;color:inherit;opacity:.8;border-radius:4px;cursor:pointer}.vm-snackbar-content__close:hover{background-color:var(--color-hover-black)}.vm-snackbar-details{display:grid;grid-template-columns:1fr;gap:0}.vm-snackbar-details__title{font-weight:600;padding-bottom:4px;margin-bottom:4px;border-bottom:1px solid inherit}.vm-snackbar-details__msg{display:grid;line-height:150%;white-space:pre-line;text-wrap:pretty;overflow-wrap:anywhere}.vm-snackbar-details__msg ul,.vm-snackbar-details__msg ol{list-style-position:inside;margin-bottom:8px}.vm-snackbar_mobile{bottom:0;left:0;right:0}@keyframes vm-slide-snackbar{0%{transform:translateY(100%)}to{transform:translateY(0)}}svg{width:100%}*{scrollbar-width:thin;scrollbar-color:var(--color-text-disabled) var(--color-background-block)}*::-webkit-scrollbar{width:12px}*::-webkit-scrollbar-track{background:var(--color-background-block)}*::-webkit-scrollbar-thumb{background-color:var(--color-text-disabled);border-radius:20px;border:3px solid var(--color-background-block)}html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,u,center,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;vertical-align:baseline}h1,h2,h3,h4,h5,h6{font-weight:400}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}q:before,q:after{content:""}table{border-collapse:collapse;border-spacing:0}input::placeholder{opacity:1;transition:opacity .3s ease}input:focus::placeholder{opacity:0;transition:opacity .3s ease}*{outline:none;box-sizing:border-box}button{padding:0;border-radius:0;border:none;background:none}input[type=file]{opacity:0;cursor:pointer;width:100%;height:100%;font-size:0;left:0;top:0;position:absolute}input[type=file]:disabled{cursor:not-allowed}a{color:inherit;text-decoration:inherit}input,textarea{-webkit-text-fill-color:inherit;-moz-appearance:none;appearance:none;-webkit-appearance:none}input:disabled,textarea:disabled{opacity:1!important}input:placeholder-shown,textarea:placeholder-shown{width:100%}input:-webkit-autofill,input:-webkit-autofill:hover,input:-webkit-autofill:focus,input:-webkit-autofill:active{-webkit-box-shadow:0 0 0 0 white inset!important;z-index:2;width:100%}.vm-header-button{border:1px solid rgba(17,15,15,.2)}.vm-list-item{padding:12px;cursor:pointer;background-color:transparent;transition:background-color .2s ease}.vm-list-item_mobile{padding:12px}.vm-list-item:hover,.vm-list-item_active{background-color:var(--color-hover-black)}.vm-list-item_multiselect{display:grid;grid-template-columns:10px 1fr;gap:8px;align-items:center;justify-content:flex-start}.vm-list-item_multiselect svg{animation:vm-scale .15s cubic-bezier(.28,.84,.42,1)}.vm-list-item_multiselect span{grid-column:2}.vm-list-item_multiselect_selected{color:var(--color-primary)}.vm-list-item_with-icon{display:grid;grid-template-columns:14px 1fr;gap:4px;align-items:center;justify-content:flex-start}.vm-mobile-option{display:flex;align-items:center;justify-content:flex-start;gap:8px;padding:6px 0;width:100%;-webkit-user-select:none;user-select:none}.vm-mobile-option__arrow,.vm-mobile-option__icon{display:flex;align-items:center;justify-content:center}.vm-mobile-option__icon{width:22px;height:22px;color:var(--color-primary)}.vm-mobile-option__arrow{width:14px;height:14px;transform:rotate(-90deg);color:var(--color-primary)}.vm-mobile-option-text{display:grid;align-items:center;gap:2px;flex-grow:1}.vm-mobile-option-text__label{font-weight:700}.vm-mobile-option-text__value{color:var(--color-text-secondary);font-size:12px}.vm-block{padding:12px;background-color:var(--color-background-block);border-radius:8px;box-shadow:var(--box-shadow)}.vm-block_mobile{padding:12px;border-radius:0}.vm-block_empty-padding{padding:0}.vm-section-header{display:grid;grid-template-columns:1fr auto;align-items:center;justify-content:center;padding:0 12px;border-bottom:var(--border-divider);border-radius:8px 8px 0 0}.vm-section-header__title{font-size:14px;font-weight:700}.vm-section-header__title_mobile{overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical}.vm-section-header__tabs{display:flex;align-items:center;justify-content:flex-start;font-size:12px}.vm-table{width:100%;border-collapse:separate;border-spacing:0;margin-top:-12px;background-color:var(--color-background-block)}.vm-table__row{background-color:var(--color-background-block);transition:background-color .2s ease}.vm-table__row:hover:not(.vm-table__row_header){background-color:var(--color-hover-black)}.vm-table__row_header{position:relative;z-index:2}.vm-table__row_selected{background-color:#1a90ff0d}.vm-table-cell{padding:4px;border-bottom:var(--border-divider);vertical-align:top;line-height:1.5;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.vm-table-cell__content{display:flex;align-items:center;justify-content:flex-start}.vm-table-cell_sort{cursor:pointer}.vm-table-cell_sort:hover{background-color:var(--color-hover-black)}.vm-table-cell_header{font-weight:700;text-align:left;overflow-wrap:normal}.vm-table-cell_gray{color:var(--color-text);opacity:.4}.vm-table-cell_right{text-align:right}.vm-table-cell_right .vm-table-cell__content{justify-content:flex-end}.vm-table-cell_no-wrap{white-space:nowrap}.vm-table-cell_no-padding{padding:0}.vm-table-cell_pre{white-space:pre-wrap}.vm-table-cell_logs-time{white-space:nowrap;overflow-wrap:normal}.vm-table-cell_logs{font-family:monospace;line-height:1.2;width:100%;overflow-wrap:normal}.vm-table-cell_compact{white-space:nowrap;width:100px}.vm-table-cell_empty{color:var(--color-text-secondary);font-style:italic}.vm-table__sort-icon{display:flex;align-items:center;justify-content:center;width:15px;margin:0 8px;opacity:.4;transition:opacity .2s ease,transform .2s ease-in-out}.vm-table__sort-icon_active{opacity:1}.vm-table__sort-icon_desc{transform:rotate(180deg)}.vm-link{transition:color .2s ease;cursor:pointer}.vm-link_colored{color:var(--color-primary)}.vm-link_underlined{text-decoration:underline}.vm-link_with-icon{display:grid;align-items:center;justify-content:center;gap:6px;grid-template-columns:14px auto}.vm-link:hover{color:var(--color-primary);text-decoration:underline}.vm-dynamic-number{position:relative;display:flex;align-items:center;padding-left:1em;font-size:12px;color:var(--color-text-disabled)}.vm-dynamic-number_static{color:var(--color-text-secondary);padding-left:0}.vm-dynamic-number_positive{color:var(--color-success)}.vm-dynamic-number_negative{color:var(--color-error)}.vm-dynamic-number_warning{color:var(--color-warning)}.vm-dynamic-number:before{position:absolute;top:auto;left:0;width:1em}.vm-dynamic-number_down:before{content:"↓ "}.vm-dynamic-number_up:before{content:"↑ "}.vm-markdown{display:block;line-height:1.5}.vm-markdown pre,.vm-markdown code{font-size:1em;font-family:monospace}.vm-markdown pre{padding:.5em;line-height:1.25;overflow-x:scroll}.vm-markdown a,.vm-markdown a:visited{color:var(--color-primary);text-decoration:underline;cursor:pointer}.vm-markdown body{line-height:1.85}.vm-markdown p{font-size:1em;margin-bottom:1.3em}.vm-markdown h1,.vm-markdown h2,.vm-markdown h3,.vm-markdown h4,.vm-markdown h5,.vm-markdown h6{margin:.5em 0 .25em;font-weight:inherit;line-height:1.42}.vm-markdown h1{font-size:1.8em}.vm-markdown h2{font-size:1.6em}.vm-markdown h3{font-size:1.4em}.vm-markdown h4{font-size:1.2em}.vm-markdown h5{font-size:1em}.vm-markdown h6,.vm-markdown small{font-size:.8em}.vm-markdown img,.vm-markdown canvas,.vm-markdown iframe,.vm-markdown video,.vm-markdown svg,.vm-markdown select,.vm-markdown textarea{max-width:100%}.vm-markdown pre{background-color:var(--color-hover-black)}.vm-markdown blockquote{border-left:3px solid rgba(17,15,15,.2);padding-left:1em;opacity:.7}.vm-markdown ul,.vm-markdown ol{margin:.3em 0;list-style-position:inside}.vm-markdown ul li,.vm-markdown ol li{margin-bottom:.3em}.vm-markdown ul li ul,.vm-markdown ul li ol,.vm-markdown ol li ul,.vm-markdown ol li ol{margin-left:1em}.vm-markdown input[type=checkbox]{display:none}.vm-markdown th,.vm-markdown td{padding:.2em .4em}.vm-markdown hr{border-top:var(--border-divider)}.vm-markdown strong{font-weight:700}.vm-markdown em{font-style:italic}.vm-markdown del{text-decoration:line-through}.vm-markdown code:not(pre code){display:inline;vertical-align:middle;background:var(--color-hover-black);border-radius:4px;border:var(--border-divider);-moz-tab-size:4;tab-size:4;font-variant-ligatures:none;padding:.12em .4em;font-size:.9em;white-space:nowrap}:root{--color-primary: #3F51B5;--color-secondary: #E91E63;--color-error: #FD080E;--color-warning: #FF8308;--color-info: #03A9F4;--color-success: #4CAF50;--color-primary-text: #FFFFFF;--color-secondary-text: #FFFFFF;--color-error-text: #FFFFFF;--color-warning-text: #FFFFFF;--color-info-text: #FFFFFF;--color-success-text: #FFFFFF;--color-background-body: #FEFEFF;--color-background-block: #FFFFFF;--color-background-tooltip: rgba(80,80,80,.9);--color-text: #110f0f;--color-text-secondary: #706F6F;--color-text-disabled: #A09F9F;--box-shadow: rgba(0, 0, 0, .08) 1px 2px 6px;--box-shadow-popper: rgba(0, 0, 0, .1) 0px 2px 8px 0px;--border-divider: 1px solid rgba(0, 0, 0, .15);--color-hover-black: rgba(0, 0, 0, .06)}.vm-explore-logs-body{position:relative}.vm-explore-logs-body-header{background-color:var(--color-background-block);z-index:3;margin:-12px -12px 0;position:sticky;top:0}@media (max-width: 1000px){.vm-explore-logs-body-header{top:51px}}.vm-explore-logs-body-header_mobile{margin:-12px -12px 0;display:block;border-bottom:none}.vm-explore-logs-body-header__settings{display:flex;align-items:center;gap:8px;justify-content:flex-end}.vm-explore-logs-body-header__log-info{flex-grow:1;text-align:right;padding-right:16px;color:var(--color-text-secondary);font-size:12px}.vm-explore-logs-body-header__tabs_mobile{border-bottom:var(--border-divider)}.vm-explore-logs-body__table{padding-top:12px;width:calc(100vw - 48px - var(--scrollbar-width));overflow:auto}@media (max-width: 768px){.vm-explore-logs-body__table{width:calc(100vw - 24px - var(--scrollbar-width))}}.vm-explore-logs-body__table_mobile{width:calc(100vw - 24px - var(--scrollbar-width));padding-top:16px}.vm-explore-logs-body__table .vm-table{min-width:700px}.vm-group-logs{margin-top:-12px}.vm-group-logs-header{display:flex;align-items:center;justify-content:flex-end}.vm-group-logs-header-keys{max-height:300px;overflow:auto}.vm-group-logs-header-keys__search{padding:8px}.vm-group-logs-section{border-bottom:var(--border-divider)}.vm-group-logs-section-keys{position:relative;display:flex;align-items:center;flex-wrap:wrap;gap:8px;padding:8px 120px 8px 0;font-size:var(--font-size-logs, 12px)}.vm-group-logs-section-keys_compact{flex-wrap:nowrap;overflow:hidden}.vm-group-logs-section-keys_popper{display:flex;flex-wrap:nowrap;flex-direction:column;align-items:flex-start;justify-content:flex-start;padding:12px;max-height:400px;overflow:auto}.vm-group-logs-section-keys__title{font-weight:700;white-space:nowrap}.vm-group-logs-section-keys__title code{font-family:monospace}.vm-group-logs-section-keys__title code:before{content:'"'}.vm-group-logs-section-keys__title code:after{content:'"'}.vm-group-logs-section-keys__count{position:absolute;top:auto;right:0;flex-grow:1;text-align:right;font-size:var(--font-size-logs, 12px);color:var(--color-text-secondary);padding-right:48px}.vm-group-logs-section-keys__pair{order:0;padding:6px 12px;background-color:#e9f4fb;color:#1a6399;border-radius:8px;transition:background-color .3s ease-in,transform .1s ease-in,opacity .3s ease-in;white-space:nowrap}.vm-group-logs-section-keys__pair_hide{order:2;visibility:hidden;opacity:0;pointer-events:none}.vm-group-logs-section-keys__pair_more{order:1}.vm-group-logs-section-keys__pair:hover{background-color:#c9e3f6}.vm-group-logs-section-keys__pair:active{transform:scale(.98)}.vm-group-logs-section-keys__pair_dark{color:#76bcff;background-color:var(--color-background-body);opacity:.8}.vm-group-logs-section-keys__pair_dark:hover{background-color:var(--color-background-body);opacity:1}.vm-group-logs-section-rows{font-size:var(--font-size-logs, 12px);font-variant-numeric:tabular-nums;line-height:1.3}.vm-group-logs-row:last-child{margin-bottom:8px}.vm-group-logs-row-content{display:flex;padding:2px 24px 2px 0;cursor:pointer}.vm-group-logs-row-content_interactive{contain:layout;will-change:background-color}.vm-group-logs-row-content__copy-row{position:absolute;top:0;right:0;z-index:1;visibility:hidden}.vm-group-logs-row-content__copy-row.vm-button{padding:2px}.vm-group-logs-row-content_interactive:hover{background-color:var(--color-hover-black)}.vm-group-logs-row-content_interactive:hover .vm-group-logs-row-content__copy-row{visibility:visible}.vm-group-logs-row-content__arrow{display:flex;align-items:center;justify-content:center;width:16px;height:14px;transform:rotate(-90deg);transition:transform .2s ease-out}.vm-group-logs-row-content__arrow_open{transform:rotate(0)}.vm-group-logs-row-content__arrow svg{width:16px}.vm-group-logs-row-content__time{display:flex;align-items:flex-start;justify-content:flex-end;padding:0 12px 0 8px;white-space:nowrap}.vm-group-logs-row-content__time_missing{color:var(--color-text-disabled);font-style:italic;justify-content:center}.vm-group-logs-row-content__msg{font-family:monospace;overflow-wrap:anywhere}.vm-group-logs-row-content__msg_single-line,.vm-group-logs-row-content__msg_empty-msg{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vm-group-logs-row-content__msg_missing{color:var(--color-text-disabled);font-style:italic;text-align:center}.vm-group-logs-row-content__msg p,.vm-group-logs-row-content__msg pre,.vm-group-logs-row-content__msg code{white-space:pre-wrap;word-wrap:break-word;word-break:normal}.vm-group-logs-row-content__msg code:not(pre code),.vm-group-logs-row-content__msg pre{display:inline-block;background:var(--color-hover-black);border:1px solid var(--color-hover-black);border-radius:4px;-moz-tab-size:4;tab-size:4;font-variant-ligatures:none;margin:2px 0}.vm-group-logs-row-content__msg p{font-family:system-ui;line-height:1.4}.vm-group-logs-row-content__msg pre{padding:8px}.vm-group-logs-row-content__msg code{font-size:var(--font-size-logs, 12px);padding:2px 4px}.vm-group-logs-row-content__msg a{color:var(--color-primary);cursor:pointer}.vm-group-logs-row-content__msg a:hover{text-decoration:underline}.vm-group-logs-row-content__msg strong{font-weight:700}.vm-group-logs-row-content__msg em{font-style:italic}.vm-group-logs-row-content__msg blockquote{border-left:4px solid var(--color-hover-black);margin:4px 8px;padding:4px 8px}.vm-group-logs-row-content__msg ul,.vm-group-logs-row-content__msg ol{list-style-position:inside}.vm-group-logs-row-content__sub-msg{padding-right:12px}.vm-group-logs-row-fields{position:relative;padding:8px 0;margin:8px 0 8px 24px;border:var(--border-divider);border-radius:4px;overflow:auto;height:300px;resize:vertical;font-family:monospace;font-size:var(--font-size-logs, 12px);font-variant-numeric:tabular-nums}.vm-group-logs-row-fields_interactive .vm-group-logs-row-fields-item{contain:layout;will-change:background-color}.vm-group-logs-row-fields_interactive .vm-group-logs-row-fields-item:hover{background-color:var(--color-hover-black)}.vm-group-logs-row-fields-item-controls{padding:0 4px}.vm-group-logs-row-fields-item-controls__wrapper{display:flex;align-items:center;justify-content:center}.vm-group-logs-row-fields-item-controls__button.vm-button_small{width:22px;height:22px;min-height:22px}.vm-group-logs-row-fields-item__key,.vm-group-logs-row-fields-item__value{vertical-align:top;line-height:14px;padding:4px}.vm-group-logs-row-fields-item__key{overflow-wrap:break-word;width:max-content}.vm-group-logs-row-fields-item__value{width:100%;word-break:break-all;white-space:pre-wrap}.vm-group-logs-configurator{display:grid;gap:24px;padding:12px 0;max-width:600px}.vm-group-logs-configurator-item{display:grid;grid-template-columns:1fr 31px;align-items:center;justify-content:stretch;gap:0 8px}.vm-group-logs-configurator-item__info{margin-top:8px;grid-column:1/span 2;font-size:12px;color:var(--color-text-secondary);line-height:130%}.vm-group-logs-configurator-item__info_input{margin-top:0}.vm-group-logs-configurator-button{position:relative}.vm-group-logs-configurator-button__marker{position:absolute;top:6px;left:6px;width:5px;height:5px;border-radius:50%;background-color:var(--color-secondary)}.vm-group-logs-configurator__tooltip ul{list-style-position:inside}.vm-pagination{position:sticky;left:0;display:flex;justify-content:center;gap:8px;padding:12px 0;font-size:14px}.vm-pagination_mobile{padding:12px 0}.vm-pagination__page{display:flex;align-items:center;justify-content:center;height:30px;min-width:30px;color:var(--color-text);padding:0 8px;border-radius:4px;transition:background-color .3s;border:1px solid transparent;cursor:pointer}.vm-pagination__page_active{background-color:var(--color-primary);color:var(--color-primary-text);pointer-events:none}.vm-pagination__page_disabled{cursor:default;pointer-events:none;color:var(--color-text-disabled)}.vm-pagination__page:hover{background-color:var(--color-hover-black)}.vm-pagination__arrow svg{max-width:14px;max-height:14px}.vm-pagination__arrow:disabled{color:var(--color-text-disabled);cursor:default;pointer-events:none}.vm-pagination__arrow_prev{transform:rotate(90deg)}.vm-pagination__arrow_next{transform:rotate(-90deg)}.vm-select-limits-button{display:grid;grid-template-columns:auto 18px;align-items:center;justify-content:center;font-size:12px;color:var(--color-text-secondary);cursor:pointer}.vm-select-limits-button:hover{color:var(--color-primary)}.vm-select-limits{display:grid;padding:8px 0}.vm-download-button__format-option{padding:4px}.vm-download-button__format-option:first-child{padding-bottom:0}.vm-download-button__format-option-button{width:100%;justify-content:flex-start}.vm-explore-logs-body__empty{display:flex;align-items:center;justify-content:center;min-height:120px;color:var(--color-text-disabled);text-align:center}.vm-table-view__settings,.vm-table-view__settings-buttons{display:flex;align-items:center;gap:8px}.vm-json-settings{display:flex;flex-direction:row}.vm-json-settings-modal .vm-modal-content-body{min-width:clamp(300px,600px,90vw);padding:0}.vm-json-settings-modal-section{padding-block:12px;border-top:var(--border-divider)}.vm-json-settings-modal-section:first-child{padding-top:0;border-top:none}.vm-json-settings-modal-section__sort-settings-container{display:grid;padding:12px;grid-template-columns:1fr 1fr 80px;gap:12px}@media (max-width: 500px){.vm-json-settings-modal-section__sort-settings-container{grid-template-columns:1fr}}.vm-json-view__settings-container{display:flex;flex-direction:row;align-items:center}.vm-live-tailing-view__settings{display:flex;align-items:center;justify-content:space-between;width:100%}.vm-live-tailing-view__settings-modal{max-width:500px;min-width:300px}.vm-live-tailing-view__settings-modal-item{display:flex;flex-direction:column;gap:8px}.vm-live-tailing-view__settings-modal-item-info{font-size:12px;color:var(--color-text-secondary);line-height:130%}.vm-live-tailing-view__settings-buttons{display:flex;align-items:center}.vm-live-tailing-view__container{width:100%;height:100%;overflow:auto;min-height:calc(100vh - 120px);font-family:monospace;padding-bottom:12px;transition:min-height .3s ease}.vm-live-tailing-view__empty{display:flex;align-items:center;justify-content:center;height:100%;color:var(--color-text-secondary)}.vm-live-tailing-view__error{display:flex;align-items:center;justify-content:center;height:100%;color:var(--color-error)}.vm-live-tailing-view__logs .vm-group-logs-row{animation:highlight-fade 1s ease-out forwards}.vm-live-tailing-view__log-row{margin-top:8px}@keyframes highlight-fade{0%{background-color:#c9e3f6}to{background-color:var(--color-background-block)}}.vm-scroll-to-top-button{position:fixed;bottom:20px;right:20px;z-index:4;opacity:0;visibility:hidden;transition:opacity .3s,visibility .3s}.vm-scroll-to-top-button_visible{opacity:1;visibility:visible}.vm-scroll-to-top-button .vm-button{border-radius:50%;width:40px;height:40px;display:flex;align-items:center;justify-content:center;box-shadow:0 2px 5px #0003}.vm-explore-logs-header{display:grid;align-items:center;gap:12px}.vm-explore-logs-header-top{display:grid;grid-template-columns:8fr 2fr;align-items:flex-start;justify-content:center;gap:12px}.vm-explore-logs-header-bottom{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:12px}@media (max-width: 500px){.vm-explore-logs-header-bottom{display:grid;justify-content:normal}}.vm-explore-logs-header-bottom-contols{display:flex;align-items:center;justify-content:flex-start;flex-grow:1}.vm-explore-logs-header-bottom-buttons{display:grid;grid-template-columns:auto 1fr;gap:8px}.vm-explore-logs-header-bottom-execute{position:relative;display:grid}.vm-explore-logs-header-bottom-execute__text{position:absolute}.vm-explore-logs-header-bottom-execute__text_hidden{position:relative;visibility:hidden}.vm-explore-logs-header-bottom-helpful{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:8px 12px}.vm-explore-logs-header-bottom-helpful a{color:var(--color-text-secondary)}.vm-explore-logs{display:grid;grid-template-rows:auto 1fr;align-items:flex-start;gap:12px}.vm-explore-logs-chart{position:relative;display:flex;align-items:center;justify-content:center;padding:0 0 0 8px!important;width:calc(100vw - 24px)}@media (max-width: 768px){.vm-explore-logs-chart{width:100vw}}.vm-explore-logs-chart__empty{display:flex;align-items:center;justify-content:center;position:absolute;top:0;bottom:0;z-index:2}.vm-bar-hits-chart{position:relative;width:100%;height:200px}.vm-bar-hits-chart__wrapper{display:flex;flex-direction:column;width:100%;height:100%}.vm-bar-hits-chart__wrapper_hidden{min-height:90px}.vm-bar-hits-chart_panning{pointer-events:none}.vm-bar-hits-options{display:flex;align-items:center;position:absolute;top:8px;right:8px;z-index:2}.vm-bar-hits-options-settings{display:grid;align-items:flex-start;min-width:200px;gap:12px;padding-bottom:12px}.vm-bar-hits-options-settings-item{padding:0 12px}.vm-bar-hits-options-settings-item_list{padding:0}.vm-bar-hits-options-settings-item__title{font-size:12px;color:var(--color-text-secondary);padding:0 8px 8px}.vm-bar-hits-options-settings-item:last-child{border-bottom:none}.vm-bar-hits-tooltip{opacity:0;pointer-events:none;gap:8px}.vm-bar-hits-tooltip_visible{opacity:1;pointer-events:auto}.vm-bar-hits-tooltip-item{display:grid;grid-template-columns:1fr auto;align-items:center;gap:12px;max-width:100%}.vm-bar-hits-tooltip-item__label{display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vm-bar-hits-tooltip__date{white-space:nowrap}.vm-bar-hits-legend{display:flex;flex-wrap:wrap;padding:0 8px 8px;color:var(--color-text)}.vm-bar-hits-legend-item{max-width:50%;display:flex;align-items:center;gap:8px;font-size:12px;padding:8px 12px;border-radius:4px;cursor:pointer;transition:.2s}.vm-bar-hits-legend-item:hover{background-color:#0000000d}.vm-bar-hits-legend-item_hide{text-decoration:line-through;opacity:.5}.vm-bar-hits-legend-item__marker{min-width:14px;max-width:14px;height:14px;border:var(--color-background-block)}.vm-bar-hits-legend-item__label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.vm-bar-hits-legend-item__total{color:var(--color-text-secondary);font-style:italic;grid-column:2}.vm-bar-hits-legend-info{flex-grow:1;width:100%;display:flex;align-items:center;justify-content:space-between;padding-top:8px;color:var(--color-text-secondary);font-size:12px}.vm-bar-hits-legend-info code{display:inline-block;padding:4px 8px;font-size:12px;text-align:center;background-color:var(--color-background-body);background-repeat:repeat-x;border:var(--border-divider);border-radius:4px}.vm-legend-hits-menu{min-width:160px;z-index:1}.vm-legend-hits-menu_submenu{position:absolute;top:-8px;background-color:var(--color-background-block);left:calc(100% + 4px);box-shadow:var(--box-shadow-popper);border-radius:4px;animation:vm-submenu-show .15s cubic-bezier(.28,.84,.2,1);transform-origin:top left}.vm-legend-hits-menu_submenu_left{left:auto;right:calc(100% + 4px);transform-origin:top right}.vm-legend-hits-menu-section{border-bottom:var(--border-divider)}.vm-legend-hits-menu-section:last-child{border-bottom:none}.vm-legend-hits-menu-row{position:relative;display:flex;gap:8px;align-items:center;justify-content:flex-start;padding:0 12px;transition:background-color .3s;color:var(--color-text)}.vm-legend-hits-menu-row_interactive{cursor:pointer}.vm-legend-hits-menu-row_interactive:hover{background-color:#0000000d}.vm-legend-hits-menu-row_info{font-size:12px;font-weight:500;padding-block:8px}.vm-legend-hits-menu-row_info .vm-legend-hits-menu-row__icon{color:var(--color-info)}.vm-legend-hits-menu-row__icon{display:flex;align-items:center;justify-content:center;width:14px;height:14px}.vm-legend-hits-menu-row__icon_drop{transform:rotate(-90deg)}.vm-legend-hits-menu-row__title{flex-grow:1;padding:12px 0;position:relative;max-width:400px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.vm-legend-hits-menu-other-list{width:80vw;height:80vh;overflow:auto}.vm-legend-hits-menu-other-list__search{position:sticky;top:0;padding:8px 0;background-color:var(--color-background-block);border-bottom:var(--border-divider);z-index:2}.vm-legend-hits-menu-other-list-row{border-bottom:var(--border-divider)}.vm-legend-hits-menu-other-list-row_header{border-bottom:none;position:sticky;top:65px;background-color:var(--color-background-block);z-index:1;width:100%}.vm-legend-hits-menu-other-list-row_header:after{content:"";position:absolute;bottom:0;left:0;width:100%;height:1px;border-bottom:var(--border-divider)}.vm-legend-hits-menu-other-list-cell{padding:4px 0;text-align:left}.vm-legend-hits-menu-other-list-cell_header{padding:8px;font-weight:500}.vm-legend-hits-menu-other-list-cell_number{padding:8px;text-align:right;font-variant-numeric:tabular-nums}.vm-legend-hits-menu-other-list-cell_fields{width:100%}.vm-legend-hits-menu-other-list-fields{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-start}.vm-legend-hits-menu-other-list-fields__field{padding:4px 8px;border-radius:4px;transition:background-color .3s}.vm-legend-hits-menu-other-list-fields__field:hover{background-color:var(--color-hover-black)}.vm-legend-hits-menu-other-list-fields__field:not(:last-child):after{content:","}.vm-legend-hits-menu-other-list-actions{display:flex;align-items:center;justify-content:center}@keyframes vm-submenu-show{0%{opacity:0}to{opacity:1}} diff --git a/app/vlselect/vmui/assets/vendor-D1GxaB_c.css b/app/vlselect/vmui/assets/vendor-D1GxaB_c.css deleted file mode 100644 index 519078e550..0000000000 --- a/app/vlselect/vmui/assets/vendor-D1GxaB_c.css +++ /dev/null @@ -1 +0,0 @@ -.uplot,.uplot *,.uplot *:before,.uplot *:after{box-sizing:border-box}.uplot{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";line-height:1.5;width:min-content}.u-title{text-align:center;font-size:18px;font-weight:700}.u-wrap{position:relative;-webkit-user-select:none;user-select:none}.u-over,.u-under{position:absolute}.u-under{overflow:hidden}.uplot canvas{display:block;position:relative;width:100%;height:100%}.u-axis{position:absolute}.u-legend{font-size:14px;margin:auto;text-align:center}.u-inline{display:block}.u-inline *{display:inline-block}.u-inline tr{margin-right:16px}.u-legend th{font-weight:600}.u-legend th>*{vertical-align:middle;display:inline-block}.u-legend .u-marker{width:1em;height:1em;margin-right:4px;background-clip:padding-box!important}.u-inline.u-live th:after{content:":";vertical-align:middle}.u-inline:not(.u-live) .u-value{display:none}.u-series>*{padding:4px}.u-series th{cursor:pointer}.u-legend .u-off>*{opacity:.3}.u-select{background:#00000012;position:absolute;pointer-events:none}.u-cursor-x,.u-cursor-y{position:absolute;left:0;top:0;pointer-events:none;will-change:transform}.u-hz .u-cursor-x,.u-vt .u-cursor-y{height:100%;border-right:1px dashed #607D8B}.u-hz .u-cursor-y,.u-vt .u-cursor-x{width:100%;border-bottom:1px dashed #607D8B}.u-cursor-pt{position:absolute;top:0;left:0;border-radius:50%;border:0 solid;pointer-events:none;will-change:transform;background-clip:padding-box!important}.u-axis.u-off,.u-select.u-off,.u-cursor-x.u-off,.u-cursor-y.u-off,.u-cursor-pt.u-off{display:none} diff --git a/app/vlselect/vmui/assets/vendor-V4vnRsM-.js b/app/vlselect/vmui/assets/vendor-V4vnRsM-.js deleted file mode 100644 index 5a37b73051..0000000000 --- a/app/vlselect/vmui/assets/vendor-V4vnRsM-.js +++ /dev/null @@ -1,67 +0,0 @@ -var Sh=Object.defineProperty;var xh=(e,t,n)=>t in e?Sh(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var ot=(e,t,n)=>xh(e,typeof t!="symbol"?t+"":t,n);var ro,Ce,hf,Fr,Vs,df,mf,gf,Za,Ca,Ta,yf,Xi={},_f=[],kh=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,io=Array.isArray;function er(e,t){for(var n in t)e[n]=t[n];return e}function Ja(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function Oe(e,t,n){var r,i,o,l={};for(o in t)o=="key"?r=t[o]:o=="ref"?i=t[o]:l[o]=t[o];if(arguments.length>2&&(l.children=arguments.length>3?ro.call(arguments,2):n),typeof e=="function"&&e.defaultProps!=null)for(o in e.defaultProps)l[o]==null&&(l[o]=e.defaultProps[o]);return Gi(e,l,r,i,null)}function Gi(e,t,n,r,i){var o={type:e,props:t,key:n,ref:r,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:i??++hf,__i:-1,__u:0};return i==null&&Ce.vnode!=null&&Ce.vnode(o),o}function vf(){return{current:null}}function ln(e){return e.children}function Dn(e,t){this.props=e,this.context=t}function si(e,t){if(t==null)return e.__?si(e.__,e.__i+1):null;for(var n;ta&&Fr.sort(mf),e=Fr.shift(),a=Fr.length,e.__d&&(n=void 0,i=(r=(t=e).__v).__e,o=[],l=[],t.__P&&((n=er({},r)).__v=r.__v+1,Ce.vnode&&Ce.vnode(n),Qa(t.__P,n,r,t.__n,t.__P.namespaceURI,32&r.__u?[i]:null,o,i??si(r),!!(32&r.__u),l),n.__v=r.__v,n.__.__k[n.__i]=n,xf(o,n,l),n.__e!=i&&wf(n)));Ho.__r=0}function bf(e,t,n,r,i,o,l,a,u,s,p){var f,d,g,y,S,w,_=r&&r.__k||_f,v=t.length;for(u=$h(n,t,_,u,v),f=0;f0?Gi(l.type,l.props,l.key,l.ref?l.ref:null,l.__v):l).__=e,l.__b=e.__b+1,a=null,(s=l.__i=Eh(l,n,u,f))!=-1&&(f--,(a=n[s])&&(a.__u|=2)),a==null||a.__v==null?(s==-1&&(i>p?d--:iu?d--:d++,l.__u|=4))):e.__k[o]=null;if(f)for(o=0;o(u!=null&&(2&u.__u)==0?1:0))for(i=n-1,o=n+1;i>=0||o=0){if((u=t[i])&&(2&u.__u)==0&&l==u.key&&a==u.type)return i;i--}if(o0?e:io(e)?e.map(kf):er({},e)}function Ph(e,t,n,r,i,o,l,a,u){var s,p,f,d,g,y,S,w=n.props,_=t.props,v=t.type;if(v=="svg"?i="http://www.w3.org/2000/svg":v=="math"?i="http://www.w3.org/1998/Math/MathML":i||(i="http://www.w3.org/1999/xhtml"),o!=null){for(s=0;s2&&(a.children=arguments.length>3?ro.call(arguments,2):n),Gi(e.type,a,r||e.key,i||e.ref,null)}function wn(e){function t(n){var r,i;return this.getChildContext||(r=new Set,(i={})[t.__c]=this,this.getChildContext=function(){return i},this.componentWillUnmount=function(){r=null},this.shouldComponentUpdate=function(o){this.props.value!=o.value&&r.forEach(function(l){l.__e=!0,Ma(l)})},this.sub=function(o){r.add(o);var l=o.componentWillUnmount;o.componentWillUnmount=function(){r&&r.delete(o),l&&l.call(o)}}),n.children}return t.__c="__cC"+yf++,t.__=e,t.Provider=t.__l=(t.Consumer=function(n,r){return n.children(r)}).contextType=t,t}ro=_f.slice,Ce={__e:function(e,t,n,r){for(var i,o,l;t=t.__;)if((i=t.__c)&&!i.__)try{if((o=i.constructor)&&o.getDerivedStateFromError!=null&&(i.setState(o.getDerivedStateFromError(e)),l=i.__d),i.componentDidCatch!=null&&(i.componentDidCatch(e,r||{}),l=i.__d),l)return i.__E=i}catch(a){e=a}throw e}},hf=0,Dn.prototype.setState=function(e,t){var n;n=this.__s!=null&&this.__s!=this.state?this.__s:this.__s=er({},this.state),typeof e=="function"&&(e=e(er({},n),this.props)),e&&er(n,e),e!=null&&this.__v&&(t&&this._sb.push(t),Ma(this))},Dn.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),Ma(this))},Dn.prototype.render=ln,Fr=[],df=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,mf=function(e,t){return e.__v.__b-t.__v.__b},Ho.__r=0,gf=/(PointerCapture)$|Capture$/i,Za=0,Ca=Ys(!1),Ta=Ys(!0),yf=0;var Oh=0;function uv(e,t,n,r,i,o){t||(t={});var l,a,u=t;if("ref"in u)for(a in u={},t)a=="ref"?l=t[a]:u[a]=t[a];var s={type:e,props:u,key:n,ref:l,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:--Oh,__i:-1,__u:0,__source:i,__self:o};if(typeof e=="function"&&(l=e.defaultProps))for(a in l)u[a]===void 0&&(u[a]=l[a]);return Ce.vnode&&Ce.vnode(s),s}var fr,st,xl,Ks,ui=0,Pf=[],mt=Ce,Zs=mt.__b,Js=mt.__r,Qs=mt.diffed,Xs=mt.__c,eu=mt.unmount,tu=mt.__;function Wr(e,t){mt.__h&&mt.__h(st,e,ui||t),ui=0;var n=st.__H||(st.__H={__:[],__h:[]});return e>=n.__.length&&n.__.push({}),n.__[e]}function pr(e){return ui=1,Zo(Rf,e)}function Zo(e,t,n){var r=Wr(fr++,2);if(r.t=e,!r.__c&&(r.__=[n?n(t):Rf(void 0,t),function(a){var u=r.__N?r.__N[0]:r.__[0],s=r.t(u,a);u!==s&&(r.__N=[s,r.__[1]],r.__c.setState({}))}],r.__c=st,!st.__f)){var i=function(a,u,s){if(!r.__c.__H)return!0;var p=r.__c.__H.__.filter(function(d){return!!d.__c});if(p.every(function(d){return!d.__N}))return!o||o.call(this,a,u,s);var f=r.__c.props!==a;return p.forEach(function(d){if(d.__N){var g=d.__[0];d.__=d.__N,d.__N=void 0,g!==d.__[0]&&(f=!0)}}),o&&o.call(this,a,u,s)||f};st.__f=!0;var o=st.shouldComponentUpdate,l=st.componentWillUpdate;st.componentWillUpdate=function(a,u,s){if(this.__e){var p=o;o=void 0,i(a,u,s),o=p}l&&l.call(this,a,u,s)},st.shouldComponentUpdate=i}return r.__N||r.__}function Hr(e,t){var n=Wr(fr++,3);!mt.__s&&rs(n.__H,t)&&(n.__=e,n.u=t,st.__H.__h.push(n))}function $r(e,t){var n=Wr(fr++,4);!mt.__s&&rs(n.__H,t)&&(n.__=e,n.u=t,st.__h.push(n))}function hr(e){return ui=5,sn(function(){return{current:e}},[])}function es(e,t,n){ui=6,$r(function(){if(typeof e=="function"){var r=e(t());return function(){e(null),r&&typeof r=="function"&&r()}}if(e)return e.current=t(),function(){return e.current=null}},n==null?n:n.concat(e))}function sn(e,t){var n=Wr(fr++,7);return rs(n.__H,t)&&(n.__=e(),n.__H=t,n.__h=e),n.__}function mr(e,t){return ui=8,sn(function(){return e},t)}function qe(e){var t=st.context[e.__c],n=Wr(fr++,9);return n.c=e,t?(n.__==null&&(n.__=!0,t.sub(st)),t.props.value):e.__}function ts(e,t){mt.useDebugValue&&mt.useDebugValue(t?t(e):e)}function Ch(e){var t=Wr(fr++,10),n=pr();return t.__=e,st.componentDidCatch||(st.componentDidCatch=function(r,i){t.__&&t.__(r,i),n[1](r)}),[n[0],function(){n[1](void 0)}]}function ns(){var e=Wr(fr++,11);if(!e.__){for(var t=st.__v;t!==null&&!t.__m&&t.__!==null;)t=t.__;var n=t.__m||(t.__m=[0,0]);e.__="P"+n[0]+"-"+n[1]++}return e.__}function Th(){for(var e;e=Pf.shift();)if(e.__P&&e.__H)try{e.__H.__h.forEach(To),e.__H.__h.forEach(Da),e.__H.__h=[]}catch(t){e.__H.__h=[],mt.__e(t,e.__v)}}mt.__b=function(e){st=null,Zs&&Zs(e)},mt.__=function(e,t){e&&t.__k&&t.__k.__m&&(e.__m=t.__k.__m),tu&&tu(e,t)},mt.__r=function(e){Js&&Js(e),fr=0;var t=(st=e.__c).__H;t&&(xl===st?(t.__h=[],st.__h=[],t.__.forEach(function(n){n.__N&&(n.__=n.__N),n.u=n.__N=void 0})):(t.__h.forEach(To),t.__h.forEach(Da),t.__h=[],fr=0)),xl=st},mt.diffed=function(e){Qs&&Qs(e);var t=e.__c;t&&t.__H&&(t.__H.__h.length&&(Pf.push(t)!==1&&Ks===mt.requestAnimationFrame||((Ks=mt.requestAnimationFrame)||Mh)(Th)),t.__H.__.forEach(function(n){n.u&&(n.__H=n.u),n.u=void 0})),xl=st=null},mt.__c=function(e,t){t.some(function(n){try{n.__h.forEach(To),n.__h=n.__h.filter(function(r){return!r.__||Da(r)})}catch(r){t.some(function(i){i.__h&&(i.__h=[])}),t=[],mt.__e(r,n.__v)}}),Xs&&Xs(e,t)},mt.unmount=function(e){eu&&eu(e);var t,n=e.__c;n&&n.__H&&(n.__H.__.forEach(function(r){try{To(r)}catch(i){t=i}}),n.__H=void 0,t&&mt.__e(t,n.__v))};var nu=typeof requestAnimationFrame=="function";function Mh(e){var t,n=function(){clearTimeout(r),nu&&cancelAnimationFrame(t),setTimeout(e)},r=setTimeout(n,100);nu&&(t=requestAnimationFrame(n))}function To(e){var t=st,n=e.__c;typeof n=="function"&&(e.__c=void 0,n()),st=t}function Da(e){var t=st;e.__c=e.__(),st=t}function rs(e,t){return!e||e.length!==t.length||t.some(function(n,r){return n!==e[r]})}function Rf(e,t){return typeof t=="function"?t(e):t}function Af(e,t){for(var n in t)e[n]=t[n];return e}function La(e,t){for(var n in e)if(n!=="__source"&&!(n in t))return!0;for(var r in t)if(r!=="__source"&&e[r]!==t[r])return!0;return!1}function is(e,t){var n=t(),r=pr({t:{__:n,u:t}}),i=r[0].t,o=r[1];return $r(function(){i.__=n,i.u=t,kl(i)&&o({t:i})},[e,n,t]),Hr(function(){return kl(i)&&o({t:i}),e(function(){kl(i)&&o({t:i})})},[e]),n}function kl(e){var t,n,r=e.u,i=e.__;try{var o=r();return!((t=i)===(n=o)&&(t!==0||1/t==1/n)||t!=t&&n!=n)}catch{return!0}}function Jo(e){e()}function os(e){return e}function ls(){return[!1,Jo]}var as=$r;function qo(e,t){this.props=e,this.context=t}function ss(e,t){function n(i){var o=this.props.ref,l=o==i.ref;return!l&&o&&(o.call?o(null):o.current=null),t?!t(this.props,i)||!l:La(this.props,i)}function r(i){return this.shouldComponentUpdate=n,Oe(e,i)}return r.displayName="Memo("+(e.displayName||e.name)+")",r.prototype.isReactComponent=!0,r.__f=!0,r}(qo.prototype=new Dn).isPureReactComponent=!0,qo.prototype.shouldComponentUpdate=function(e,t){return La(this.props,e)||La(this.state,t)};var ru=Ce.__b;Ce.__b=function(e){e.type&&e.type.__f&&e.ref&&(e.props.ref=e.ref,e.ref=null),ru&&ru(e)};var Dh=typeof Symbol<"u"&&Symbol.for&&Symbol.for("react.forward_ref")||3911;function oo(e){function t(n){var r=Af({},n);return delete r.ref,e(r,n.ref||null)}return t.$$typeof=Dh,t.render=t,t.prototype.isReactComponent=t.__f=!0,t.displayName="ForwardRef("+(e.displayName||e.name)+")",t}var iu=function(e,t){return e==null?null:ar(ar(e).map(t))},us={map:iu,forEach:iu,count:function(e){return e?ar(e).length:0},only:function(e){var t=ar(e);if(t.length!==1)throw"Children.only";return t[0]},toArray:ar},Lh=Ce.__e;Ce.__e=function(e,t,n,r){if(e.then){for(var i,o=t;o=o.__;)if((i=o.__c)&&i.__c)return t.__e==null&&(t.__e=n.__e,t.__k=n.__k),i.__c(e,t)}Lh(e,t,n,r)};var ou=Ce.unmount;function Of(e,t,n){return e&&(e.__c&&e.__c.__H&&(e.__c.__H.__.forEach(function(r){typeof r.__c=="function"&&r.__c()}),e.__c.__H=null),(e=Af({},e)).__c!=null&&(e.__c.__P===n&&(e.__c.__P=t),e.__c.__e=!0,e.__c=null),e.__k=e.__k&&e.__k.map(function(r){return Of(r,t,n)})),e}function Cf(e,t,n){return e&&n&&(e.__v=null,e.__k=e.__k&&e.__k.map(function(r){return Cf(r,t,n)}),e.__c&&e.__c.__P===t&&(e.__e&&n.appendChild(e.__e),e.__c.__e=!0,e.__c.__P=n)),e}function Yi(){this.__u=0,this.o=null,this.__b=null}function Tf(e){var t=e.__.__c;return t&&t.__a&&t.__a(e)}function Mf(e){var t,n,r;function i(o){if(t||(t=e()).then(function(l){n=l.default||l},function(l){r=l}),r)throw r;if(!n)throw t;return Oe(n,o)}return i.displayName="Lazy",i.__f=!0,i}function li(){this.i=null,this.l=null}Ce.unmount=function(e){var t=e.__c;t&&t.__R&&t.__R(),t&&32&e.__u&&(e.type=null),ou&&ou(e)},(Yi.prototype=new Dn).__c=function(e,t){var n=t.__c,r=this;r.o==null&&(r.o=[]),r.o.push(n);var i=Tf(r.__v),o=!1,l=function(){o||(o=!0,n.__R=null,i?i(a):a())};n.__R=l;var a=function(){if(!--r.__u){if(r.state.__a){var u=r.state.__a;r.__v.__k[0]=Cf(u,u.__c.__P,u.__c.__O)}var s;for(r.setState({__a:r.__b=null});s=r.o.pop();)s.forceUpdate()}};r.__u++||32&t.__u||r.setState({__a:r.__b=r.__v.__k[0]}),e.then(l,l)},Yi.prototype.componentWillUnmount=function(){this.o=[]},Yi.prototype.render=function(e,t){if(this.__b){if(this.__v.__k){var n=document.createElement("div"),r=this.__v.__k[0].__c;this.__v.__k[0]=Of(this.__b,n,r.__O=r.__P)}this.__b=null}var i=t.__a&&Oe(ln,null,e.fallback);return i&&(i.__u&=-33),[Oe(ln,null,t.__a?null:e.children),i]};var lu=function(e,t,n){if(++n[1]===n[0]&&e.l.delete(t),e.props.revealOrder&&(e.props.revealOrder[0]!=="t"||!e.l.size))for(n=e.i;n;){for(;n.length>3;)n.pop()();if(n[1]>>1,1),t.h.removeChild(r)}}),eo(Oe(Ih,{context:t.context},e.__v),t.v)}function Df(e,t){var n=Oe(Nh,{__v:e,h:t});return n.containerInfo=t,n}(li.prototype=new Dn).__a=function(e){var t=this,n=Tf(t.__v),r=t.l.get(e);return r[0]++,function(i){var o=function(){t.props.revealOrder?(r.push(i),lu(t,e,r)):i()};n?n(o):o()}},li.prototype.render=function(e){this.i=null,this.l=new Map;var t=ar(e.children);e.revealOrder&&e.revealOrder[0]==="b"&&t.reverse();for(var n=t.length;n--;)this.l.set(t[n],this.i=[1,0,this.i]);return e.children},li.prototype.componentDidUpdate=li.prototype.componentDidMount=function(){var e=this;this.l.forEach(function(t,n){lu(e,n,t)})};var Lf=typeof Symbol<"u"&&Symbol.for&&Symbol.for("react.element")||60103,Fh=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|dominant|fill|flood|font|glyph(?!R)|horiz|image(!S)|letter|lighting|marker(?!H|W|U)|overline|paint|pointer|shape|stop|strikethrough|stroke|text(?!L)|transform|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,zh=/^on(Ani|Tra|Tou|BeforeInp|Compo)/,Bh=/[A-Z0-9]/g,Hh=typeof document<"u",qh=function(e){return(typeof Symbol<"u"&&typeof Symbol()=="symbol"?/fil|che|rad/:/fil|che|ra/).test(e)};function If(e,t,n){return t.__k==null&&(t.textContent=""),eo(e,t),typeof n=="function"&&n(),e?e.__c:null}function Nf(e,t,n){return Ef(e,t),typeof n=="function"&&n(),e?e.__c:null}Dn.prototype.isReactComponent={},["componentWillMount","componentWillReceiveProps","componentWillUpdate"].forEach(function(e){Object.defineProperty(Dn.prototype,e,{configurable:!0,get:function(){return this["UNSAFE_"+e]},set:function(t){Object.defineProperty(this,e,{configurable:!0,writable:!0,value:t})}})});var au=Ce.event;function Uh(){}function Wh(){return this.cancelBubble}function jh(){return this.defaultPrevented}Ce.event=function(e){return au&&(e=au(e)),e.persist=Uh,e.isPropagationStopped=Wh,e.isDefaultPrevented=jh,e.nativeEvent=e};var cs,Vh={enumerable:!1,configurable:!0,get:function(){return this.class}},su=Ce.vnode;Ce.vnode=function(e){typeof e.type=="string"&&function(t){var n=t.props,r=t.type,i={},o=r.indexOf("-")===-1;for(var l in n){var a=n[l];if(!(l==="value"&&"defaultValue"in n&&a==null||Hh&&l==="children"&&r==="noscript"||l==="class"||l==="className")){var u=l.toLowerCase();l==="defaultValue"&&"value"in n&&n.value==null?l="value":l==="download"&&a===!0?a="":u==="translate"&&a==="no"?a=!1:u[0]==="o"&&u[1]==="n"?u==="ondoubleclick"?l="ondblclick":u!=="onchange"||r!=="input"&&r!=="textarea"||qh(n.type)?u==="onfocus"?l="onfocusin":u==="onblur"?l="onfocusout":zh.test(l)&&(l=u):u=l="oninput":o&&Fh.test(l)?l=l.replace(Bh,"-$&").toLowerCase():a===null&&(a=void 0),u==="oninput"&&i[l=u]&&(l="oninputCapture"),i[l]=a}}r=="select"&&i.multiple&&Array.isArray(i.value)&&(i.value=ar(n.children).forEach(function(s){s.props.selected=i.value.indexOf(s.props.value)!=-1})),r=="select"&&i.defaultValue!=null&&(i.value=ar(n.children).forEach(function(s){s.props.selected=i.multiple?i.defaultValue.indexOf(s.props.value)!=-1:i.defaultValue==s.props.value})),n.class&&!n.className?(i.class=n.class,Object.defineProperty(i,"className",Vh)):(n.className&&!n.class||n.class&&n.className)&&(i.class=i.className=n.className),t.props=i}(e),e.$$typeof=Lf,su&&su(e)};var uu=Ce.__r;Ce.__r=function(e){uu&&uu(e),cs=e.__c};var cu=Ce.diffed;Ce.diffed=function(e){cu&&cu(e);var t=e.props,n=e.__e;n!=null&&e.type==="textarea"&&"value"in t&&t.value!==n.value&&(n.value=t.value==null?"":t.value),cs=null};var Ff={ReactCurrentDispatcher:{current:{readContext:function(e){return cs.__n[e.__c].props.value},useCallback:mr,useContext:qe,useDebugValue:ts,useDeferredValue:os,useEffect:Hr,useId:ns,useImperativeHandle:es,useInsertionEffect:as,useLayoutEffect:$r,useMemo:sn,useReducer:Zo,useRef:hr,useState:pr,useSyncExternalStore:is,useTransition:ls}}},Gh="18.3.1";function zf(e){return Oe.bind(null,e)}function di(e){return!!e&&e.$$typeof===Lf}function Bf(e){return di(e)&&e.type===ln}function Hf(e){return!!e&&!!e.displayName&&(typeof e.displayName=="string"||e.displayName instanceof String)&&e.displayName.startsWith("Memo(")}function qf(e){return di(e)?Ah.apply(null,arguments):e}function Uf(e){return!!e.__k&&(eo(null,e),!0)}function Wf(e){return e&&(e.base||e.nodeType===1&&e)||null}var jf=function(e,t){return e(t)},Vf=function(e,t){return e(t)},Gf=ln,Yf=di,Yh={useState:pr,useId:ns,useReducer:Zo,useEffect:Hr,useLayoutEffect:$r,useInsertionEffect:as,useTransition:ls,useDeferredValue:os,useSyncExternalStore:is,startTransition:Jo,useRef:hr,useImperativeHandle:es,useMemo:sn,useCallback:mr,useContext:qe,useDebugValue:ts,version:"18.3.1",Children:us,render:If,hydrate:Nf,unmountComponentAtNode:Uf,createPortal:Df,createElement:Oe,createContext:wn,createFactory:zf,cloneElement:qf,createRef:vf,Fragment:ln,isValidElement:di,isElement:Yf,isFragment:Bf,isMemo:Hf,findDOMNode:Wf,Component:Dn,PureComponent:qo,memo:ss,forwardRef:oo,flushSync:Vf,unstable_batchedUpdates:jf,StrictMode:Gf,Suspense:Yi,SuspenseList:li,lazy:Mf,__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED:Ff};const Kh=Object.freeze(Object.defineProperty({__proto__:null,Children:us,Component:Dn,Fragment:ln,PureComponent:qo,StrictMode:Gf,Suspense:Yi,SuspenseList:li,__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED:Ff,cloneElement:qf,createContext:wn,createElement:Oe,createFactory:zf,createPortal:Df,createRef:vf,default:Yh,findDOMNode:Wf,flushSync:Vf,forwardRef:oo,hydrate:Nf,isElement:Yf,isFragment:Bf,isMemo:Hf,isValidElement:di,lazy:Mf,memo:ss,render:If,startTransition:Jo,unmountComponentAtNode:Uf,unstable_batchedUpdates:jf,useCallback:mr,useContext:qe,useDebugValue:ts,useDeferredValue:os,useEffect:Hr,useErrorBoundary:Ch,useId:ns,useImperativeHandle:es,useInsertionEffect:as,useLayoutEffect:$r,useMemo:sn,useReducer:Zo,useRef:hr,useState:pr,useSyncExternalStore:is,useTransition:ls,version:Gh},Symbol.toStringTag,{value:"Module"}));var Bt=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function In(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function Kf(e){if(Object.prototype.hasOwnProperty.call(e,"__esModule"))return e;var t=e.default;if(typeof t=="function"){var n=function r(){return this instanceof r?Reflect.construct(t,arguments,this.constructor):t.apply(this,arguments)};n.prototype=t.prototype}else n={};return Object.defineProperty(n,"__esModule",{value:!0}),Object.keys(e).forEach(function(r){var i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(n,r,i.get?i:{enumerable:!0,get:function(){return e[r]}})}),n}var Mo={exports:{}},Zh=Mo.exports,fu;function Jh(){return fu||(fu=1,function(e,t){(function(n,r){e.exports=r()})(Zh,function(){var n=1e3,r=6e4,i=36e5,o="millisecond",l="second",a="minute",u="hour",s="day",p="week",f="month",d="quarter",g="year",y="date",S="Invalid Date",w=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,_=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,v={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(j){var B=["th","st","nd","rd"],V=j%100;return"["+j+(B[(V-20)%10]||B[V]||B[0])+"]"}},A=function(j,B,V){var Y=String(j);return!Y||Y.length>=B?j:""+Array(B+1-Y.length).join(V)+j},R={s:A,z:function(j){var B=-j.utcOffset(),V=Math.abs(B),Y=Math.floor(V/60),Z=V%60;return(B<=0?"+":"-")+A(Y,2,"0")+":"+A(Z,2,"0")},m:function j(B,V){if(B.date()1)return j(N[0])}else{var W=B.name;P[W]=B,Z=W}return!Y&&Z&&(D=Z),Z||!Y&&D},z=function(j,B){if(T(j))return j.clone();var V=typeof B=="object"?B:{};return V.date=j,V.args=arguments,new G(V)},I=R;I.l=U,I.i=T,I.w=function(j,B){return z(j,{locale:B.$L,utc:B.$u,x:B.$x,$offset:B.$offset})};var G=function(){function j(V){this.$L=U(V.locale,null,!0),this.parse(V),this.$x=this.$x||V.x||{},this[C]=!0}var B=j.prototype;return B.parse=function(V){this.$d=function(Y){var Z=Y.date,O=Y.utc;if(Z===null)return new Date(NaN);if(I.u(Z))return new Date;if(Z instanceof Date)return new Date(Z);if(typeof Z=="string"&&!/Z$/i.test(Z)){var N=Z.match(w);if(N){var W=N[2]-1||0,L=(N[7]||"0").substring(0,3);return O?new Date(Date.UTC(N[1],W,N[3]||1,N[4]||0,N[5]||0,N[6]||0,L)):new Date(N[1],W,N[3]||1,N[4]||0,N[5]||0,N[6]||0,L)}}return new Date(Z)}(V),this.init()},B.init=function(){var V=this.$d;this.$y=V.getFullYear(),this.$M=V.getMonth(),this.$D=V.getDate(),this.$W=V.getDay(),this.$H=V.getHours(),this.$m=V.getMinutes(),this.$s=V.getSeconds(),this.$ms=V.getMilliseconds()},B.$utils=function(){return I},B.isValid=function(){return this.$d.toString()!==S},B.isSame=function(V,Y){var Z=z(V);return this.startOf(Y)<=Z&&Z<=this.endOf(Y)},B.isAfter=function(V,Y){return z(V)=0&&(S[R]=parseInt(A,10))}var D=S[3],P=D===24?0:D,C=S[0]+"-"+S[1]+"-"+S[2]+" "+P+":"+S[4]+":"+S[5]+":000",T=+d;return(l.utc(C).valueOf()-(T-=T%1e3))/6e4},p=o.prototype;p.tz=function(d,g){d===void 0&&(d=a);var y,S=this.utcOffset(),w=this.toDate(),_=w.toLocaleString("en-US",{timeZone:d}),v=Math.round((w-new Date(_))/1e3/60),A=15*-Math.round(w.getTimezoneOffset()/15)-v;if(!Number(A))y=this.utcOffset(0,g);else if(y=l(_,{locale:this.$L}).$set("millisecond",this.$ms).utcOffset(A,!0),g){var R=y.utcOffset();y=y.add(S-R,"minute")}return y.$x.$timezone=d,y},p.offsetName=function(d){var g=this.$x.$timezone||l.tz.guess(),y=u(this.valueOf(),g,{timeZoneName:d}).find(function(S){return S.type.toLowerCase()==="timezonename"});return y&&y.value};var f=p.startOf;p.startOf=function(d,g){if(!this.$x||!this.$x.$timezone)return f.call(this,d,g);var y=l(this.format("YYYY-MM-DD HH:mm:ss:SSS"),{locale:this.$L});return f.call(y,d,g).tz(this.$x.$timezone,!0)},l.tz=function(d,g,y){var S=y&&g,w=y||g||a,_=s(+l(),w);if(typeof d!="string")return l(d).tz(w);var v=function(P,C,T){var U=P-60*C*1e3,z=s(U,T);if(C===z)return[U,C];var I=s(U-=60*(z-C)*1e3,T);return z===I?[U,z]:[P-60*Math.min(z,I)*1e3,Math.max(z,I)]}(l.utc(d,S).valueOf(),_,w),A=v[0],R=v[1],D=l(A).utcOffset(R);return D.$x.$timezone=w,D},l.tz.guess=function(){return Intl.DateTimeFormat().resolvedOptions().timeZone},l.tz.setDefault=function(d){a=d}}})}(Do)),Do.exports}var td=ed();const fv=In(td);var Lo={exports:{}},nd=Lo.exports,hu;function rd(){return hu||(hu=1,function(e,t){(function(n,r){e.exports=r()})(nd,function(){var n,r,i=1e3,o=6e4,l=36e5,a=864e5,u=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,s=31536e6,p=2628e6,f=/^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/,d={years:s,months:p,days:a,hours:l,minutes:o,seconds:i,milliseconds:1,weeks:6048e5},g=function(P){return P instanceof R},y=function(P,C,T){return new R(P,T,C.$l)},S=function(P){return r.p(P)+"s"},w=function(P){return P<0},_=function(P){return w(P)?Math.ceil(P):Math.floor(P)},v=function(P){return Math.abs(P)},A=function(P,C){return P?w(P)?{negative:!0,format:""+v(P)+C}:{negative:!1,format:""+P+C}:{negative:!1,format:""}},R=function(){function P(T,U,z){var I=this;if(this.$d={},this.$l=z,T===void 0&&(this.$ms=0,this.parseFromMilliseconds()),U)return y(T*d[S(U)],this);if(typeof T=="number")return this.$ms=T,this.parseFromMilliseconds(),this;if(typeof T=="object")return Object.keys(T).forEach(function(j){I.$d[S(j)]=T[j]}),this.calMilliseconds(),this;if(typeof T=="string"){var G=T.match(f);if(G){var J=G.slice(2).map(function(j){return j!=null?Number(j):0});return this.$d.years=J[0],this.$d.months=J[1],this.$d.weeks=J[2],this.$d.days=J[3],this.$d.hours=J[4],this.$d.minutes=J[5],this.$d.seconds=J[6],this.calMilliseconds(),this}}return this}var C=P.prototype;return C.calMilliseconds=function(){var T=this;this.$ms=Object.keys(this.$d).reduce(function(U,z){return U+(T.$d[z]||0)*d[z]},0)},C.parseFromMilliseconds=function(){var T=this.$ms;this.$d.years=_(T/s),T%=s,this.$d.months=_(T/p),T%=p,this.$d.days=_(T/a),T%=a,this.$d.hours=_(T/l),T%=l,this.$d.minutes=_(T/o),T%=o,this.$d.seconds=_(T/i),T%=i,this.$d.milliseconds=T},C.toISOString=function(){var T=A(this.$d.years,"Y"),U=A(this.$d.months,"M"),z=+this.$d.days||0;this.$d.weeks&&(z+=7*this.$d.weeks);var I=A(z,"D"),G=A(this.$d.hours,"H"),J=A(this.$d.minutes,"M"),j=this.$d.seconds||0;this.$d.milliseconds&&(j+=this.$d.milliseconds/1e3,j=Math.round(1e3*j)/1e3);var B=A(j,"S"),V=T.negative||U.negative||I.negative||G.negative||J.negative||B.negative,Y=G.format||J.format||B.format?"T":"",Z=(V?"-":"")+"P"+T.format+U.format+I.format+Y+G.format+J.format+B.format;return Z==="P"||Z==="-P"?"P0D":Z},C.toJSON=function(){return this.toISOString()},C.format=function(T){var U=T||"YYYY-MM-DDTHH:mm:ss",z={Y:this.$d.years,YY:r.s(this.$d.years,2,"0"),YYYY:r.s(this.$d.years,4,"0"),M:this.$d.months,MM:r.s(this.$d.months,2,"0"),D:this.$d.days,DD:r.s(this.$d.days,2,"0"),H:this.$d.hours,HH:r.s(this.$d.hours,2,"0"),m:this.$d.minutes,mm:r.s(this.$d.minutes,2,"0"),s:this.$d.seconds,ss:r.s(this.$d.seconds,2,"0"),SSS:r.s(this.$d.milliseconds,3,"0")};return U.replace(u,function(I,G){return G||String(z[I])})},C.as=function(T){return this.$ms/d[S(T)]},C.get=function(T){var U=this.$ms,z=S(T);return z==="milliseconds"?U%=1e3:U=z==="weeks"?_(U/d[z]):this.$d[z],U||0},C.add=function(T,U,z){var I;return I=U?T*d[S(U)]:g(T)?T.$ms:y(T,this).$ms,y(this.$ms+I*(z?-1:1),this)},C.subtract=function(T,U){return this.add(T,U,!0)},C.locale=function(T){var U=this.clone();return U.$l=T,U},C.clone=function(){return y(this.$ms,this)},C.humanize=function(T){return n().add(this.$ms,"ms").locale(this.$l).fromNow(!T)},C.valueOf=function(){return this.asMilliseconds()},C.milliseconds=function(){return this.get("milliseconds")},C.asMilliseconds=function(){return this.as("milliseconds")},C.seconds=function(){return this.get("seconds")},C.asSeconds=function(){return this.as("seconds")},C.minutes=function(){return this.get("minutes")},C.asMinutes=function(){return this.as("minutes")},C.hours=function(){return this.get("hours")},C.asHours=function(){return this.as("hours")},C.days=function(){return this.get("days")},C.asDays=function(){return this.as("days")},C.weeks=function(){return this.get("weeks")},C.asWeeks=function(){return this.as("weeks")},C.months=function(){return this.get("months")},C.asMonths=function(){return this.as("months")},C.years=function(){return this.get("years")},C.asYears=function(){return this.as("years")},P}(),D=function(P,C,T){return P.add(C.years()*T,"y").add(C.months()*T,"M").add(C.days()*T,"d").add(C.hours()*T,"h").add(C.minutes()*T,"m").add(C.seconds()*T,"s").add(C.milliseconds()*T,"ms")};return function(P,C,T){n=T,r=T().$utils(),T.duration=function(I,G){var J=T.locale();return y(I,{$l:J},G)},T.isDuration=g;var U=C.prototype.add,z=C.prototype.subtract;C.prototype.add=function(I,G){return g(I)?D(this,I,1):U.bind(this)(I,G)},C.prototype.subtract=function(I,G){return g(I)?D(this,I,-1):z.bind(this)(I,G)}}})}(Lo)),Lo.exports}var id=rd();const pv=In(id);var Io={exports:{}},od=Io.exports,du;function ld(){return du||(du=1,function(e,t){(function(n,r){e.exports=r()})(od,function(){return function(n,r,i){n=n||{};var o=r.prototype,l={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"};function a(s,p,f,d){return o.fromToBase(s,p,f,d)}i.en.relativeTime=l,o.fromToBase=function(s,p,f,d,g){for(var y,S,w,_=f.$locale().relativeTime||l,v=n.thresholds||[{l:"s",r:44,d:"second"},{l:"m",r:89},{l:"mm",r:44,d:"minute"},{l:"h",r:89},{l:"hh",r:21,d:"hour"},{l:"d",r:35},{l:"dd",r:25,d:"day"},{l:"M",r:45},{l:"MM",r:10,d:"month"},{l:"y",r:17},{l:"yy",d:"year"}],A=v.length,R=0;R0,P<=D.r||!D.r){P<=1&&R>0&&(D=v[R-1]);var C=_[D.l];g&&(P=g(""+P)),S=typeof C=="string"?C.replace("%d",P):C(P,p,D.l,w);break}}if(p)return S;var T=w?_.future:_.past;return typeof T=="function"?T(S):T.replace("%s",S)},o.to=function(s,p){return a(s,p,this,!0)},o.from=function(s,p){return a(s,p,this)};var u=function(s){return s.$u?i.utc():i()};o.toNow=function(s){return this.to(u(this),s)},o.fromNow=function(s){return this.from(u(this),s)}}})}(Io)),Io.exports}var ad=ld();const hv=In(ad);var No={exports:{}},sd=No.exports,mu;function ud(){return mu||(mu=1,function(e,t){(function(n,r){e.exports=r()})(sd,function(){var n="minute",r=/[+-]\d\d(?::?\d\d)?/g,i=/([+-]|\d\d)/g;return function(o,l,a){var u=l.prototype;a.utc=function(S){var w={date:S,utc:!0,args:arguments};return new l(w)},u.utc=function(S){var w=a(this.toDate(),{locale:this.$L,utc:!0});return S?w.add(this.utcOffset(),n):w},u.local=function(){return a(this.toDate(),{locale:this.$L,utc:!1})};var s=u.parse;u.parse=function(S){S.utc&&(this.$u=!0),this.$utils().u(S.$offset)||(this.$offset=S.$offset),s.call(this,S)};var p=u.init;u.init=function(){if(this.$u){var S=this.$d;this.$y=S.getUTCFullYear(),this.$M=S.getUTCMonth(),this.$D=S.getUTCDate(),this.$W=S.getUTCDay(),this.$H=S.getUTCHours(),this.$m=S.getUTCMinutes(),this.$s=S.getUTCSeconds(),this.$ms=S.getUTCMilliseconds()}else p.call(this)};var f=u.utcOffset;u.utcOffset=function(S,w){var _=this.$utils().u;if(_(S))return this.$u?0:_(this.$offset)?f.call(this):this.$offset;if(typeof S=="string"&&(S=function(D){D===void 0&&(D="");var P=D.match(r);if(!P)return null;var C=(""+P[0]).match(i)||["-",0,0],T=C[0],U=60*+C[1]+ +C[2];return U===0?0:T==="+"?U:-U}(S),S===null))return this;var v=Math.abs(S)<=16?60*S:S,A=this;if(w)return A.$offset=v,A.$u=S===0,A;if(S!==0){var R=this.$u?this.toDate().getTimezoneOffset():-1*this.utcOffset();(A=this.local().add(v+R,n)).$offset=v,A.$x.$localOffset=R}else A=this.utc();return A};var d=u.format;u.format=function(S){var w=S||(this.$u?"YYYY-MM-DDTHH:mm:ss[Z]":"");return d.call(this,w)},u.valueOf=function(){var S=this.$utils().u(this.$offset)?0:this.$offset+(this.$x.$localOffset||this.$d.getTimezoneOffset());return this.$d.valueOf()-6e4*S},u.isUTC=function(){return!!this.$u},u.toISOString=function(){return this.toDate().toISOString()},u.toString=function(){return this.toDate().toUTCString()};var g=u.toDate;u.toDate=function(S){return S==="s"&&this.$offset?a(this.format("YYYY-MM-DD HH:mm:ss:SSS")).toDate():g.call(this)};var y=u.diff;u.diff=function(S,w,_){if(S&&this.$u===S.$u)return y.call(this,S,w,_);var v=this.local(),A=a(S).local();return y.call(v,A,w,_)}}})}(No)),No.exports}var cd=ud();const dv=In(cd);var Ni={},gu;function fd(){if(gu)return Ni;gu=1,Object.defineProperty(Ni,"__esModule",{value:!0}),Ni.parse=l,Ni.serialize=s;const e=/^[\u0021-\u003A\u003C\u003E-\u007E]+$/,t=/^[\u0021-\u003A\u003C-\u007E]*$/,n=/^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i,r=/^[\u0020-\u003A\u003D-\u007E]*$/,i=Object.prototype.toString,o=(()=>{const d=function(){};return d.prototype=Object.create(null),d})();function l(d,g){const y=new o,S=d.length;if(S<2)return y;const w=(g==null?void 0:g.decode)||p;let _=0;do{const v=d.indexOf("=",_);if(v===-1)break;const A=d.indexOf(";",_),R=A===-1?S:A;if(v>R){_=d.lastIndexOf(";",v-1)+1;continue}const D=a(d,_,v),P=u(d,v,D),C=d.slice(D,P);if(y[C]===void 0){let T=a(d,v+1,R),U=u(d,R,T);const z=w(d.slice(T,U));y[C]=z}_=R+1}while(_y;){const S=d.charCodeAt(--g);if(S!==32&&S!==9)return g+1}return y}function s(d,g,y){const S=(y==null?void 0:y.encode)||encodeURIComponent;if(!e.test(d))throw new TypeError(`argument name is invalid: ${d}`);const w=S(g);if(!t.test(w))throw new TypeError(`argument val is invalid: ${g}`);let _=d+"="+w;if(!y)return _;if(y.maxAge!==void 0){if(!Number.isInteger(y.maxAge))throw new TypeError(`option maxAge is invalid: ${y.maxAge}`);_+="; Max-Age="+y.maxAge}if(y.domain){if(!n.test(y.domain))throw new TypeError(`option domain is invalid: ${y.domain}`);_+="; Domain="+y.domain}if(y.path){if(!r.test(y.path))throw new TypeError(`option path is invalid: ${y.path}`);_+="; Path="+y.path}if(y.expires){if(!f(y.expires)||!Number.isFinite(y.expires.valueOf()))throw new TypeError(`option expires is invalid: ${y.expires}`);_+="; Expires="+y.expires.toUTCString()}if(y.httpOnly&&(_+="; HttpOnly"),y.secure&&(_+="; Secure"),y.partitioned&&(_+="; Partitioned"),y.priority)switch(typeof y.priority=="string"?y.priority.toLowerCase():void 0){case"low":_+="; Priority=Low";break;case"medium":_+="; Priority=Medium";break;case"high":_+="; Priority=High";break;default:throw new TypeError(`option priority is invalid: ${y.priority}`)}if(y.sameSite)switch(typeof y.sameSite=="string"?y.sameSite.toLowerCase():y.sameSite){case!0:case"strict":_+="; SameSite=Strict";break;case"lax":_+="; SameSite=Lax";break;case"none":_+="; SameSite=None";break;default:throw new TypeError(`option sameSite is invalid: ${y.sameSite}`)}return _}function p(d){if(d.indexOf("%")===-1)return d;try{return decodeURIComponent(d)}catch{return d}}function f(d){return i.call(d)==="[object Date]"}return Ni}fd();var yu="popstate";function pd(e={}){function t(i,o){let{pathname:l="/",search:a="",hash:u=""}=jr(i.location.hash.substring(1));return!l.startsWith("/")&&!l.startsWith(".")&&(l="/"+l),Ia("",{pathname:l,search:a,hash:u},o.state&&o.state.usr||null,o.state&&o.state.key||"default")}function n(i,o){let l=i.document.querySelector("base"),a="";if(l&&l.getAttribute("href")){let u=i.location.href,s=u.indexOf("#");a=s===-1?u:u.slice(0,s)}return a+"#"+(typeof o=="string"?o:to(o))}function r(i,o){Ln(i.pathname.charAt(0)==="/",`relative pathnames are not supported in hash history.push(${JSON.stringify(o)})`)}return dd(t,n,r,e)}function gt(e,t){if(e===!1||e===null||typeof e>"u")throw new Error(t)}function Ln(e,t){if(!e){typeof console<"u"&&console.warn(t);try{throw new Error(t)}catch{}}}function hd(){return Math.random().toString(36).substring(2,10)}function _u(e,t){return{usr:e.state,key:e.key,idx:t}}function Ia(e,t,n=null,r){return{pathname:typeof e=="string"?e:e.pathname,search:"",hash:"",...typeof t=="string"?jr(t):t,state:n,key:t&&t.key||r||hd()}}function to({pathname:e="/",search:t="",hash:n=""}){return t&&t!=="?"&&(e+=t.charAt(0)==="?"?t:"?"+t),n&&n!=="#"&&(e+=n.charAt(0)==="#"?n:"#"+n),e}function jr(e){let t={};if(e){let n=e.indexOf("#");n>=0&&(t.hash=e.substring(n),e=e.substring(0,n));let r=e.indexOf("?");r>=0&&(t.search=e.substring(r),e=e.substring(0,r)),e&&(t.pathname=e)}return t}function dd(e,t,n,r={}){let{window:i=document.defaultView,v5Compat:o=!1}=r,l=i.history,a="POP",u=null,s=p();s==null&&(s=0,l.replaceState({...l.state,idx:s},""));function p(){return(l.state||{idx:null}).idx}function f(){a="POP";let w=p(),_=w==null?null:w-s;s=w,u&&u({action:a,location:S.location,delta:_})}function d(w,_){a="PUSH";let v=Ia(S.location,w,_);n&&n(v,w),s=p()+1;let A=_u(v,s),R=S.createHref(v);try{l.pushState(A,"",R)}catch(D){if(D instanceof DOMException&&D.name==="DataCloneError")throw D;i.location.assign(R)}o&&u&&u({action:a,location:S.location,delta:1})}function g(w,_){a="REPLACE";let v=Ia(S.location,w,_);n&&n(v,w),s=p();let A=_u(v,s),R=S.createHref(v);l.replaceState(A,"",R),o&&u&&u({action:a,location:S.location,delta:0})}function y(w){return md(w)}let S={get action(){return a},get location(){return e(i,l)},listen(w){if(u)throw new Error("A history only accepts one active listener");return i.addEventListener(yu,f),u=w,()=>{i.removeEventListener(yu,f),u=null}},createHref(w){return t(i,w)},createURL:y,encodeLocation(w){let _=y(w);return{pathname:_.pathname,search:_.search,hash:_.hash}},push:d,replace:g,go(w){return l.go(w)}};return S}function md(e,t=!1){let n="http://localhost";typeof window<"u"&&(n=window.location.origin!=="null"?window.location.origin:window.location.href),gt(n,"No window.location.(origin|href) available to create URL");let r=typeof e=="string"?e:to(e);return r=r.replace(/ $/,"%20"),!t&&r.startsWith("//")&&(r=n+r),new URL(r,n)}function Zf(e,t,n="/"){return gd(e,t,n,!1)}function gd(e,t,n,r){let i=typeof t=="string"?jr(t):t,o=dr(i.pathname||"/",n);if(o==null)return null;let l=Jf(e);yd(l);let a=null;for(let u=0;a==null&&u{let u={relativePath:a===void 0?o.path||"":a,caseSensitive:o.caseSensitive===!0,childrenIndex:l,route:o};u.relativePath.startsWith("/")&&(gt(u.relativePath.startsWith(r),`Absolute route path "${u.relativePath}" nested under path "${r}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),u.relativePath=u.relativePath.slice(r.length));let s=sr([r,u.relativePath]),p=n.concat(u);o.children&&o.children.length>0&&(gt(o.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${s}".`),Jf(o.children,t,p,s)),!(o.path==null&&!o.index)&&t.push({path:s,score:kd(s,o.index),routesMeta:p})};return e.forEach((o,l)=>{var a;if(o.path===""||!((a=o.path)!=null&&a.includes("?")))i(o,l);else for(let u of Qf(o.path))i(o,l,u)}),t}function Qf(e){let t=e.split("/");if(t.length===0)return[];let[n,...r]=t,i=n.endsWith("?"),o=n.replace(/\?$/,"");if(r.length===0)return i?[o,""]:[o];let l=Qf(r.join("/")),a=[];return a.push(...l.map(u=>u===""?o:[o,u].join("/"))),i&&a.push(...l),a.map(u=>e.startsWith("/")&&u===""?"/":u)}function yd(e){e.sort((t,n)=>t.score!==n.score?n.score-t.score:$d(t.routesMeta.map(r=>r.childrenIndex),n.routesMeta.map(r=>r.childrenIndex)))}var _d=/^:[\w-]+$/,vd=3,wd=2,bd=1,Sd=10,xd=-2,vu=e=>e==="*";function kd(e,t){let n=e.split("/"),r=n.length;return n.some(vu)&&(r+=xd),t&&(r+=wd),n.filter(i=>!vu(i)).reduce((i,o)=>i+(_d.test(o)?vd:o===""?bd:Sd),r)}function $d(e,t){return e.length===t.length&&e.slice(0,-1).every((r,i)=>r===t[i])?e[e.length-1]-t[t.length-1]:0}function Ed(e,t,n=!1){let{routesMeta:r}=e,i={},o="/",l=[];for(let a=0;a{if(p==="*"){let y=a[d]||"";l=o.slice(0,o.length-y.length).replace(/(.)\/+$/,"$1")}const g=a[d];return f&&!g?s[p]=void 0:s[p]=(g||"").replace(/%2F/g,"/"),s},{}),pathname:o,pathnameBase:l,pattern:e}}function Pd(e,t=!1,n=!0){Ln(e==="*"||!e.endsWith("*")||e.endsWith("/*"),`Route path "${e}" will be treated as if it were "${e.replace(/\*$/,"/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${e.replace(/\*$/,"/*")}".`);let r=[],i="^"+e.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(l,a,u)=>(r.push({paramName:a,isOptional:u!=null}),u?"/?([^\\/]+)?":"/([^\\/]+)"));return e.endsWith("*")?(r.push({paramName:"*"}),i+=e==="*"||e==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):n?i+="\\/*$":e!==""&&e!=="/"&&(i+="(?:(?=\\/|$))"),[new RegExp(i,t?void 0:"i"),r]}function Rd(e){try{return e.split("/").map(t=>decodeURIComponent(t).replace(/\//g,"%2F")).join("/")}catch(t){return Ln(!1,`The URL path "${e}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${t}).`),e}}function dr(e,t){if(t==="/")return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let n=t.endsWith("/")?t.length-1:t.length,r=e.charAt(n);return r&&r!=="/"?null:e.slice(n)||"/"}function Ad(e,t="/"){let{pathname:n,search:r="",hash:i=""}=typeof e=="string"?jr(e):e;return{pathname:n?n.startsWith("/")?n:Od(n,t):t,search:Md(r),hash:Dd(i)}}function Od(e,t){let n=t.replace(/\/+$/,"").split("/");return e.split("/").forEach(i=>{i===".."?n.length>1&&n.pop():i!=="."&&n.push(i)}),n.length>1?n.join("/"):"/"}function $l(e,t,n,r){return`Cannot include a '${e}' character in a manually specified \`to.${t}\` field [${JSON.stringify(r)}]. Please separate it out to the \`to.${n}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function Cd(e){return e.filter((t,n)=>n===0||t.route.path&&t.route.path.length>0)}function Xf(e){let t=Cd(e);return t.map((n,r)=>r===t.length-1?n.pathname:n.pathnameBase)}function ep(e,t,n,r=!1){let i;typeof e=="string"?i=jr(e):(i={...e},gt(!i.pathname||!i.pathname.includes("?"),$l("?","pathname","search",i)),gt(!i.pathname||!i.pathname.includes("#"),$l("#","pathname","hash",i)),gt(!i.search||!i.search.includes("#"),$l("#","search","hash",i)));let o=e===""||i.pathname==="",l=o?"/":i.pathname,a;if(l==null)a=n;else{let f=t.length-1;if(!r&&l.startsWith("..")){let d=l.split("/");for(;d[0]==="..";)d.shift(),f-=1;i.pathname=d.join("/")}a=f>=0?t[f]:"/"}let u=Ad(i,a),s=l&&l!=="/"&&l.endsWith("/"),p=(o||l===".")&&n.endsWith("/");return!u.pathname.endsWith("/")&&(s||p)&&(u.pathname+="/"),u}var sr=e=>e.join("/").replace(/\/\/+/g,"/"),Td=e=>e.replace(/\/+$/,"").replace(/^\/*/,"/"),Md=e=>!e||e==="?"?"":e.startsWith("?")?e:"?"+e,Dd=e=>!e||e==="#"?"":e.startsWith("#")?e:"#"+e;function Ld(e){return e!=null&&typeof e.status=="number"&&typeof e.statusText=="string"&&typeof e.internal=="boolean"&&"data"in e}var tp=["POST","PUT","PATCH","DELETE"];new Set(tp);var Id=["GET",...tp];new Set(Id);var mi=wn(null);mi.displayName="DataRouter";var Qo=wn(null);Qo.displayName="DataRouterState";var np=wn({isTransitioning:!1});np.displayName="ViewTransition";var Nd=wn(new Map);Nd.displayName="Fetchers";var Fd=wn(null);Fd.displayName="Await";var tr=wn(null);tr.displayName="Navigation";var lo=wn(null);lo.displayName="Location";var nr=wn({outlet:null,matches:[],isDataRoute:!1});nr.displayName="Route";var fs=wn(null);fs.displayName="RouteError";function zd(e,{relative:t}={}){gt(ao(),"useHref() may be used only in the context of a component.");let{basename:n,navigator:r}=qe(tr),{hash:i,pathname:o,search:l}=so(e,{relative:t}),a=o;return n!=="/"&&(a=o==="/"?n:sr([n,o])),r.createHref({pathname:a,search:l,hash:i})}function ao(){return qe(lo)!=null}function Er(){return gt(ao(),"useLocation() may be used only in the context of a component."),qe(lo).location}var rp="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function ip(e){qe(tr).static||$r(e)}function op(){let{isDataRoute:e}=qe(nr);return e?em():Bd()}function Bd(){gt(ao(),"useNavigate() may be used only in the context of a component.");let e=qe(mi),{basename:t,navigator:n}=qe(tr),{matches:r}=qe(nr),{pathname:i}=Er(),o=JSON.stringify(Xf(r)),l=hr(!1);return ip(()=>{l.current=!0}),mr((u,s={})=>{if(Ln(l.current,rp),!l.current)return;if(typeof u=="number"){n.go(u);return}let p=ep(u,JSON.parse(o),i,s.relative==="path");e==null&&t!=="/"&&(p.pathname=p.pathname==="/"?t:sr([t,p.pathname])),(s.replace?n.replace:n.push)(p,s.state,s)},[t,n,o,i,e])}var Hd=wn(null);function qd(e){let t=qe(nr).outlet;return t&&Oe(Hd.Provider,{value:e},t)}function so(e,{relative:t}={}){let{matches:n}=qe(nr),{pathname:r}=Er(),i=JSON.stringify(Xf(n));return sn(()=>ep(e,JSON.parse(i),r,t==="path"),[e,i,r,t])}function Ud(e,t){return lp(e,t)}function lp(e,t,n,r){var v;gt(ao(),"useRoutes() may be used only in the context of a component.");let{navigator:i,static:o}=qe(tr),{matches:l}=qe(nr),a=l[l.length-1],u=a?a.params:{},s=a?a.pathname:"/",p=a?a.pathnameBase:"/",f=a&&a.route;{let A=f&&f.path||"";ap(s,!f||A.endsWith("*")||A.endsWith("*?"),`You rendered descendant (or called \`useRoutes()\`) at "${s}" (under ) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render. - -Please change the parent to .`)}let d=Er(),g;if(t){let A=typeof t=="string"?jr(t):t;gt(p==="/"||((v=A.pathname)==null?void 0:v.startsWith(p)),`When overriding the location using \`\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${p}" but pathname "${A.pathname}" was given in the \`location\` prop.`),g=A}else g=d;let y=g.pathname||"/",S=y;if(p!=="/"){let A=p.replace(/^\//,"").split("/");S="/"+y.replace(/^\//,"").split("/").slice(A.length).join("/")}let w=!o&&n&&n.matches&&n.matches.length>0?n.matches:Zf(e,{pathname:S});Ln(f||w!=null,`No routes matched location "${g.pathname}${g.search}${g.hash}" `),Ln(w==null||w[w.length-1].route.element!==void 0||w[w.length-1].route.Component!==void 0||w[w.length-1].route.lazy!==void 0,`Matched leaf route at location "${g.pathname}${g.search}${g.hash}" does not have an element or Component. This means it will render an with a null value by default resulting in an "empty" page.`);let _=Yd(w&&w.map(A=>Object.assign({},A,{params:Object.assign({},u,A.params),pathname:sr([p,i.encodeLocation?i.encodeLocation(A.pathname).pathname:A.pathname]),pathnameBase:A.pathnameBase==="/"?p:sr([p,i.encodeLocation?i.encodeLocation(A.pathnameBase).pathname:A.pathnameBase])})),l,n,r);return t&&_?Oe(lo.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",...g},navigationType:"POP"}},_):_}function Wd(){let e=Xd(),t=Ld(e)?`${e.status} ${e.statusText}`:e instanceof Error?e.message:JSON.stringify(e),n=e instanceof Error?e.stack:null,r="rgba(200,200,200, 0.5)",i={padding:"0.5rem",backgroundColor:r},o={padding:"2px 4px",backgroundColor:r},l=null;return console.error("Error handled by React Router default ErrorBoundary:",e),l=Oe(ln,null,Oe("p",null,"💿 Hey developer 👋"),Oe("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",Oe("code",{style:o},"ErrorBoundary")," or"," ",Oe("code",{style:o},"errorElement")," prop on your route.")),Oe(ln,null,Oe("h2",null,"Unexpected Application Error!"),Oe("h3",{style:{fontStyle:"italic"}},t),n?Oe("pre",{style:i},n):null,l)}var jd=Oe(Wd,null),Vd=class extends Dn{constructor(e){super(e),this.state={location:e.location,revalidation:e.revalidation,error:e.error}}static getDerivedStateFromError(e){return{error:e}}static getDerivedStateFromProps(e,t){return t.location!==e.location||t.revalidation!=="idle"&&e.revalidation==="idle"?{error:e.error,location:e.location,revalidation:e.revalidation}:{error:e.error!==void 0?e.error:t.error,location:t.location,revalidation:e.revalidation||t.revalidation}}componentDidCatch(e,t){console.error("React Router caught the following error during render",e,t)}render(){return this.state.error!==void 0?Oe(nr.Provider,{value:this.props.routeContext},Oe(fs.Provider,{value:this.state.error,children:this.props.component})):this.props.children}};function Gd({routeContext:e,match:t,children:n}){let r=qe(mi);return r&&r.static&&r.staticContext&&(t.route.errorElement||t.route.ErrorBoundary)&&(r.staticContext._deepestRenderedBoundaryId=t.route.id),Oe(nr.Provider,{value:e},n)}function Yd(e,t=[],n=null,r=null){if(e==null){if(!n)return null;if(n.errors)e=n.matches;else if(t.length===0&&!n.initialized&&n.matches.length>0)e=n.matches;else return null}let i=e,o=n==null?void 0:n.errors;if(o!=null){let u=i.findIndex(s=>s.route.id&&(o==null?void 0:o[s.route.id])!==void 0);gt(u>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(o).join(",")}`),i=i.slice(0,Math.min(i.length,u+1))}let l=!1,a=-1;if(n)for(let u=0;u=0?i=i.slice(0,a+1):i=[i[0]];break}}}return i.reduceRight((u,s,p)=>{let f,d=!1,g=null,y=null;n&&(f=o&&s.route.id?o[s.route.id]:void 0,g=s.route.errorElement||jd,l&&(a<0&&p===0?(ap("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),d=!0,y=null):a===p&&(d=!0,y=s.route.hydrateFallbackElement||null)));let S=t.concat(i.slice(0,p+1)),w=()=>{let _;return f?_=g:d?_=y:s.route.Component?_=Oe(s.route.Component,null):s.route.element?_=s.route.element:_=u,Oe(Gd,{match:s,routeContext:{outlet:u,matches:S,isDataRoute:n!=null},children:_})};return n&&(s.route.ErrorBoundary||s.route.errorElement||p===0)?Oe(Vd,{location:n.location,revalidation:n.revalidation,component:g,error:f,children:w(),routeContext:{outlet:null,matches:S,isDataRoute:!0}}):w()},null)}function ps(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function Kd(e){let t=qe(mi);return gt(t,ps(e)),t}function Zd(e){let t=qe(Qo);return gt(t,ps(e)),t}function Jd(e){let t=qe(nr);return gt(t,ps(e)),t}function hs(e){let t=Jd(e),n=t.matches[t.matches.length-1];return gt(n.route.id,`${e} can only be used on routes that contain a unique "id"`),n.route.id}function Qd(){return hs("useRouteId")}function Xd(){var r;let e=qe(fs),t=Zd("useRouteError"),n=hs("useRouteError");return e!==void 0?e:(r=t.errors)==null?void 0:r[n]}function em(){let{router:e}=Kd("useNavigate"),t=hs("useNavigate"),n=hr(!1);return ip(()=>{n.current=!0}),mr(async(i,o={})=>{Ln(n.current,rp),n.current&&(typeof i=="number"?e.navigate(i):await e.navigate(i,{fromRouteId:t,...o}))},[e,t])}var wu={};function ap(e,t,n){!t&&!wu[e]&&(wu[e]=!0,Ln(!1,n))}ss(tm);function tm({routes:e,future:t,state:n}){return lp(e,void 0,n,t)}function mv(e){return qd(e.context)}function nm(e){gt(!1,"A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .")}function rm({basename:e="/",children:t=null,location:n,navigationType:r="POP",navigator:i,static:o=!1}){gt(!ao(),"You cannot render a inside another . You should never have more than one in your app.");let l=e.replace(/^\/*/,"/"),a=sn(()=>({basename:l,navigator:i,static:o,future:{}}),[l,i,o]);typeof n=="string"&&(n=jr(n));let{pathname:u="/",search:s="",hash:p="",state:f=null,key:d="default"}=n,g=sn(()=>{let y=dr(u,l);return y==null?null:{location:{pathname:y,search:s,hash:p,state:f,key:d},navigationType:r}},[l,u,s,p,f,d,r]);return Ln(g!=null,` is not able to match the URL "${u}${s}${p}" because it does not start with the basename, so the won't render anything.`),g==null?null:Oe(tr.Provider,{value:a},Oe(lo.Provider,{children:t,value:g}))}function gv({children:e,location:t}){return Ud(Na(e),t)}function Na(e,t=[]){let n=[];return us.forEach(e,(r,i)=>{if(!di(r))return;let o=[...t,i];if(r.type===ln){n.push.apply(n,Na(r.props.children,o));return}gt(r.type===nm,`[${typeof r.type=="string"?r.type:r.type.name}] is not a component. All component children of must be a or `),gt(!r.props.index||!r.props.children,"An index route cannot have child routes.");let l={id:r.props.id||o.join("-"),caseSensitive:r.props.caseSensitive,element:r.props.element,Component:r.props.Component,index:r.props.index,path:r.props.path,loader:r.props.loader,action:r.props.action,hydrateFallbackElement:r.props.hydrateFallbackElement,HydrateFallback:r.props.HydrateFallback,errorElement:r.props.errorElement,ErrorBoundary:r.props.ErrorBoundary,hasErrorBoundary:r.props.hasErrorBoundary===!0||r.props.ErrorBoundary!=null||r.props.errorElement!=null,shouldRevalidate:r.props.shouldRevalidate,handle:r.props.handle,lazy:r.props.lazy};r.props.children&&(l.children=Na(r.props.children,o)),n.push(l)}),n}var Fo="get",zo="application/x-www-form-urlencoded";function Xo(e){return e!=null&&typeof e.tagName=="string"}function im(e){return Xo(e)&&e.tagName.toLowerCase()==="button"}function om(e){return Xo(e)&&e.tagName.toLowerCase()==="form"}function lm(e){return Xo(e)&&e.tagName.toLowerCase()==="input"}function am(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function sm(e,t){return e.button===0&&(!t||t==="_self")&&!am(e)}function Fa(e=""){return new URLSearchParams(typeof e=="string"||Array.isArray(e)||e instanceof URLSearchParams?e:Object.keys(e).reduce((t,n)=>{let r=e[n];return t.concat(Array.isArray(r)?r.map(i=>[n,i]):[[n,r]])},[]))}function um(e,t){let n=Fa(e);return t&&t.forEach((r,i)=>{n.has(i)||t.getAll(i).forEach(o=>{n.append(i,o)})}),n}var Po=null;function cm(){if(Po===null)try{new FormData(document.createElement("form"),0),Po=!1}catch{Po=!0}return Po}var fm=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function El(e){return e!=null&&!fm.has(e)?(Ln(!1,`"${e}" is not a valid \`encType\` for \`
\`/\`\` and will default to "${zo}"`),null):e}function pm(e,t){let n,r,i,o,l;if(om(e)){let a=e.getAttribute("action");r=a?dr(a,t):null,n=e.getAttribute("method")||Fo,i=El(e.getAttribute("enctype"))||zo,o=new FormData(e)}else if(im(e)||lm(e)&&(e.type==="submit"||e.type==="image")){let a=e.form;if(a==null)throw new Error('Cannot submit a