Browse Source

Merge branch 'main' into sparsehistogram

pull/10870/head
beorn7 2 years ago
parent
commit
095b6c93dd
  1. 2
      Makefile
  2. 75
      Makefile.common
  3. 17
      README.md
  4. 4
      discovery/http/http.go
  5. 8
      discovery/http/http_test.go
  6. 34
      discovery/manager.go
  7. 4
      go.mod
  8. 9
      go.sum
  9. 17
      model/relabel/relabel.go
  10. 2
      model/relabel/relabel_test.go
  11. 2
      tsdb/head_wal.go
  12. 7
      web/api/v1/api.go
  13. 12
      web/api/v1/api_test.go
  14. 236
      web/api/v1/errors_test.go
  15. 12
      web/ui/build_ui.sh
  16. 4
      web/ui/module/codemirror-promql/jest.config.cjs
  17. 33
      web/ui/module/codemirror-promql/package.json
  18. 94
      web/ui/module/codemirror-promql/src/complete/hybrid.test.ts
  19. 4
      web/ui/module/codemirror-promql/src/complete/hybrid.ts
  20. 2
      web/ui/module/codemirror-promql/src/parser/matcher.test.ts
  21. 4
      web/ui/module/codemirror-promql/src/parser/matcher.ts
  22. 2
      web/ui/module/codemirror-promql/src/parser/parser.ts
  23. 2
      web/ui/module/codemirror-promql/src/parser/path-finder.test.ts
  24. 8
      web/ui/module/codemirror-promql/src/parser/path-finder.ts
  25. 2
      web/ui/module/codemirror-promql/src/parser/type.ts
  26. 2
      web/ui/module/codemirror-promql/src/parser/vector.test.ts
  27. 2
      web/ui/module/codemirror-promql/src/parser/vector.ts
  28. 23
      web/ui/module/codemirror-promql/src/promql.ts
  29. 2
      web/ui/module/codemirror-promql/src/test/utils-test.ts
  30. 2
      web/ui/module/codemirror-promql/src/types/function.ts
  31. 2
      web/ui/module/codemirror-promql/src/types/matcher.ts
  32. 10
      web/ui/module/lezer-promql/package.json
  33. 33
      web/ui/module/lezer-promql/src/highlight.js
  34. 2
      web/ui/module/lezer-promql/src/promql.grammar
  35. 9502
      web/ui/package-lock.json
  36. 2
      web/ui/package.json
  37. 32
      web/ui/react-app/package.json
  38. 3
      web/ui/react-app/src/pages/graph/CMTheme.tsx
  39. 36
      web/ui/react-app/src/pages/graph/ExpressionInput.tsx

2
Makefile

@ -45,7 +45,7 @@ ui-install:
.PHONY: ui-build
ui-build:
cd $(UI_PATH) && npm run build
cd $(UI_PATH) && CI="" npm run build
.PHONY: ui-build-module
ui-build-module:

75
Makefile.common

@ -36,29 +36,6 @@ GO_VERSION ?= $(shell $(GO) version)
GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION))
PRE_GO_111 ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.')
GOVENDOR :=
GO111MODULE :=
ifeq (, $(PRE_GO_111))
ifneq (,$(wildcard go.mod))
# Enforce Go modules support just in case the directory is inside GOPATH (and for Travis CI).
GO111MODULE := on
ifneq (,$(wildcard vendor))
# Always use the local vendor/ directory to satisfy the dependencies.
GOOPTS := $(GOOPTS) -mod=vendor
endif
endif
else
ifneq (,$(wildcard go.mod))
ifneq (,$(wildcard vendor))
$(warning This repository requires Go >= 1.11 because of Go modules)
$(warning Some recipes may not work as expected as the current Go runtime is '$(GO_VERSION_NUMBER)')
endif
else
# This repository isn't using Go modules (yet).
GOVENDOR := $(FIRST_GOPATH)/bin/govendor
endif
endif
PROMU := $(FIRST_GOPATH)/bin/promu
pkgs = ./...
@ -150,11 +127,7 @@ common-check_license:
.PHONY: common-deps
common-deps:
@echo ">> getting dependencies"
ifdef GO111MODULE
GO111MODULE=$(GO111MODULE) $(GO) mod download
else
$(GO) get $(GOOPTS) -t ./...
endif
$(GO) mod download
.PHONY: update-go-deps
update-go-deps:
@ -162,20 +135,17 @@ update-go-deps:
@for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \
$(GO) get -d $$m; \
done
GO111MODULE=$(GO111MODULE) $(GO) mod tidy
ifneq (,$(wildcard vendor))
GO111MODULE=$(GO111MODULE) $(GO) mod vendor
endif
$(GO) mod tidy
.PHONY: common-test-short
common-test-short: $(GOTEST_DIR)
@echo ">> running short tests"
GO111MODULE=$(GO111MODULE) $(GOTEST) -short $(GOOPTS) $(pkgs)
$(GOTEST) -short $(GOOPTS) $(pkgs)
.PHONY: common-test
common-test: $(GOTEST_DIR)
@echo ">> running all tests"
GO111MODULE=$(GO111MODULE) $(GOTEST) $(test-flags) $(GOOPTS) $(pkgs)
$(GOTEST) $(test-flags) $(GOOPTS) $(pkgs)
$(GOTEST_DIR):
@mkdir -p $@
@ -183,25 +153,21 @@ $(GOTEST_DIR):
.PHONY: common-format
common-format:
@echo ">> formatting code"
GO111MODULE=$(GO111MODULE) $(GO) fmt $(pkgs)
$(GO) fmt $(pkgs)
.PHONY: common-vet
common-vet:
@echo ">> vetting code"
GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs)
$(GO) vet $(GOOPTS) $(pkgs)
.PHONY: common-lint
common-lint: $(GOLANGCI_LINT)
ifdef GOLANGCI_LINT
@echo ">> running golangci-lint"
ifdef GO111MODULE
# 'go list' needs to be executed before staticcheck to prepopulate the modules cache.
# Otherwise staticcheck might fail randomly for some reason not yet explained.
GO111MODULE=$(GO111MODULE) $(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null
GO111MODULE=$(GO111MODULE) $(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs)
else
$(GOLANGCI_LINT) run $(pkgs)
endif
$(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null
$(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs)
endif
.PHONY: common-yamllint
@ -218,28 +184,15 @@ endif
common-staticcheck: lint
.PHONY: common-unused
common-unused: $(GOVENDOR)
ifdef GOVENDOR
@echo ">> running check for unused packages"
@$(GOVENDOR) list +unused | grep . && exit 1 || echo 'No unused packages'
else
ifdef GO111MODULE
common-unused:
@echo ">> running check for unused/missing packages in go.mod"
GO111MODULE=$(GO111MODULE) $(GO) mod tidy
ifeq (,$(wildcard vendor))
$(GO) mod tidy
@git diff --exit-code -- go.sum go.mod
else
@echo ">> running check for unused packages in vendor/"
GO111MODULE=$(GO111MODULE) $(GO) mod vendor
@git diff --exit-code -- go.sum go.mod vendor/
endif
endif
endif
.PHONY: common-build
common-build: promu
@echo ">> building binaries"
GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX) $(PROMU_BINARIES)
$(PROMU) build --prefix $(PREFIX) $(PROMU_BINARIES)
.PHONY: common-tarball
common-tarball: promu
@ -295,12 +248,6 @@ $(GOLANGCI_LINT):
| sh -s -- -b $(FIRST_GOPATH)/bin $(GOLANGCI_LINT_VERSION)
endif
ifdef GOVENDOR
.PHONY: $(GOVENDOR)
$(GOVENDOR):
GOOS= GOARCH= $(GO) get -u github.com/kardianos/govendor
endif
.PHONY: precheck
precheck::

17
README.md

@ -63,7 +63,14 @@ To build Prometheus from source code, You need:
* NodeJS [version 16 or greater](https://nodejs.org/).
* npm [version 7 or greater](https://www.npmjs.com/).
You can directly use the `go` tool to download and install the `prometheus`
Start by cloning the repository:
```bash
git clone https://github.com/prometheus/prometheus.git
cd prometheus
```
You can use the `go` tool to build and install the `prometheus`
and `promtool` binaries into your `GOPATH`:
```bash
@ -79,14 +86,10 @@ React UI unless it has been built explicitly using `make assets` or `make build`
An example of the above configuration file can be found [here.](https://github.com/prometheus/prometheus/blob/main/documentation/examples/prometheus.yml)
You can also clone the repository yourself and build using `make build`, which will compile in
the web assets so that Prometheus can be run from anywhere:
You can also build using `make build`, which will compile in the web assets so that
Prometheus can be run from anywhere:
```bash
mkdir -p $GOPATH/src/github.com/prometheus
cd $GOPATH/src/github.com/prometheus
git clone https://github.com/prometheus/prometheus.git
cd prometheus
make build
./prometheus --config.file=your_config.yml
```

4
discovery/http/http.go

@ -136,12 +136,12 @@ func NewDiscovery(conf *SDConfig, logger log.Logger, clientOpts []config.HTTPCli
logger,
"http",
time.Duration(conf.RefreshInterval),
d.refresh,
d.Refresh,
)
return d, nil
}
func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
func (d *Discovery) Refresh(ctx context.Context) ([]*targetgroup.Group, error) {
req, err := http.NewRequest("GET", d.url, nil)
if err != nil {
return nil, err

8
discovery/http/http_test.go

@ -45,7 +45,7 @@ func TestHTTPValidRefresh(t *testing.T) {
require.NoError(t, err)
ctx := context.Background()
tgs, err := d.refresh(ctx)
tgs, err := d.Refresh(ctx)
require.NoError(t, err)
expectedTargets := []*targetgroup.Group{
@ -83,7 +83,7 @@ func TestHTTPInvalidCode(t *testing.T) {
require.NoError(t, err)
ctx := context.Background()
_, err = d.refresh(ctx)
_, err = d.Refresh(ctx)
require.EqualError(t, err, "server returned HTTP status 400 Bad Request")
require.Equal(t, 1.0, getFailureCount())
}
@ -105,7 +105,7 @@ func TestHTTPInvalidFormat(t *testing.T) {
require.NoError(t, err)
ctx := context.Background()
_, err = d.refresh(ctx)
_, err = d.Refresh(ctx)
require.EqualError(t, err, `unsupported content type "text/plain; charset=utf-8"`)
require.Equal(t, 1.0, getFailureCount())
}
@ -423,7 +423,7 @@ func TestSourceDisappeared(t *testing.T) {
ctx := context.Background()
for i, res := range test.responses {
stubResponse = res
tgs, err := d.refresh(ctx)
tgs, err := d.Refresh(ctx)
require.NoError(t, err)
require.Equal(t, test.expectedTargets[i], tgs)
}

34
discovery/manager.go

@ -75,8 +75,8 @@ type poolKey struct {
provider string
}
// provider holds a Discoverer instance, its configuration, cancel func and its subscribers.
type provider struct {
// Provider holds a Discoverer instance, its configuration, cancel func and its subscribers.
type Provider struct {
name string
d Discoverer
config interface{}
@ -92,11 +92,20 @@ type provider struct {
newSubs map[string]struct{}
}
// Discoverer return the Discoverer of the provider
func (p *Provider) Discoverer() Discoverer {
return p.d
}
// IsStarted return true if Discoverer is started.
func (p *provider) IsStarted() bool {
func (p *Provider) IsStarted() bool {
return p.cancel != nil
}
func (p *Provider) Config() interface{} {
return p.config
}
// NewManager is the Discovery Manager constructor.
func NewManager(ctx context.Context, logger log.Logger, options ...func(*Manager)) *Manager {
if logger == nil {
@ -148,7 +157,7 @@ type Manager struct {
targetsMtx sync.Mutex
// providers keeps track of SD providers.
providers []*provider
providers []*Provider
// The sync channel sends the updates as a map where the key is the job value from the scrape config.
syncCh chan map[string][]*targetgroup.Group
@ -163,6 +172,11 @@ type Manager struct {
lastProvider uint
}
// Providers returns the currently configured SD providers.
func (m *Manager) Providers() []*Provider {
return m.providers
}
// Run starts the background processing.
func (m *Manager) Run() error {
go m.sender()
@ -194,7 +208,7 @@ func (m *Manager) ApplyConfig(cfg map[string]Configs) error {
wg sync.WaitGroup
// keep shows if we keep any providers after reload.
keep bool
newProviders []*provider
newProviders []*Provider
)
for _, prov := range m.providers {
// Cancel obsolete providers.
@ -260,7 +274,7 @@ func (m *Manager) ApplyConfig(cfg map[string]Configs) error {
// StartCustomProvider is used for sdtool. Only use this if you know what you're doing.
func (m *Manager) StartCustomProvider(ctx context.Context, name string, worker Discoverer) {
p := &provider{
p := &Provider{
name: name,
d: worker,
subs: map[string]struct{}{
@ -271,7 +285,7 @@ func (m *Manager) StartCustomProvider(ctx context.Context, name string, worker D
m.startProvider(ctx, p)
}
func (m *Manager) startProvider(ctx context.Context, p *provider) {
func (m *Manager) startProvider(ctx context.Context, p *Provider) {
level.Debug(m.logger).Log("msg", "Starting provider", "provider", p.name, "subs", fmt.Sprintf("%v", p.subs))
ctx, cancel := context.WithCancel(ctx)
updates := make(chan []*targetgroup.Group)
@ -283,7 +297,7 @@ func (m *Manager) startProvider(ctx context.Context, p *provider) {
}
// cleaner cleans resources associated with provider.
func (m *Manager) cleaner(p *provider) {
func (m *Manager) cleaner(p *Provider) {
m.targetsMtx.Lock()
p.mu.RLock()
for s := range p.subs {
@ -296,7 +310,7 @@ func (m *Manager) cleaner(p *provider) {
}
}
func (m *Manager) updater(ctx context.Context, p *provider, updates chan []*targetgroup.Group) {
func (m *Manager) updater(ctx context.Context, p *Provider, updates chan []*targetgroup.Group) {
// Ensure targets from this provider are cleaned up.
defer m.cleaner(p)
for {
@ -422,7 +436,7 @@ func (m *Manager) registerProviders(cfgs Configs, setName string) int {
failed++
return
}
m.providers = append(m.providers, &provider{
m.providers = append(m.providers, &Provider{
name: fmt.Sprintf("%s/%d", typ, m.lastProvider),
d: d,
config: cfg,

4
go.mod

@ -47,7 +47,7 @@ require (
github.com/prometheus/exporter-toolkit v0.7.1
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749
github.com/stretchr/testify v1.7.1
github.com/stretchr/testify v1.7.2
github.com/vultr/govultr/v2 v2.17.1
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0
go.opentelemetry.io/otel v1.7.0
@ -74,7 +74,7 @@ require (
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.24.1
k8s.io/apimachinery v0.24.1
k8s.io/client-go v0.24.0
k8s.io/client-go v0.24.1
k8s.io/klog v1.0.0
k8s.io/klog/v2 v2.60.1
)

9
go.sum

@ -817,8 +817,9 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@ -1457,14 +1458,12 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.24.0/go.mod h1:5Jl90IUrJHUJYEMANRURMiVvJ0g7Ax7r3R1bqO8zx8I=
k8s.io/api v0.24.1 h1:BjCMRDcyEYz03joa3K1+rbshwh1Ay6oB53+iUx2H8UY=
k8s.io/api v0.24.1/go.mod h1:JhoOvNiLXKTPQ60zh2g0ewpA+bnEYf5q44Flhquh4vQ=
k8s.io/apimachinery v0.24.0/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM=
k8s.io/apimachinery v0.24.1 h1:ShD4aDxTQKN5zNf8K1RQ2u98ELLdIW7jEnlO9uAMX/I=
k8s.io/apimachinery v0.24.1/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM=
k8s.io/client-go v0.24.0 h1:lbE4aB1gTHvYFSwm6eD3OF14NhFDKCejlnsGYlSJe5U=
k8s.io/client-go v0.24.0/go.mod h1:VFPQET+cAFpYxh6Bq6f4xyMY80G6jKKktU6G0m00VDw=
k8s.io/client-go v0.24.1 h1:w1hNdI9PFrzu3OlovVeTnf4oHDt+FJLd9Ndluvnb42E=
k8s.io/client-go v0.24.1/go.mod h1:f1kIDqcEYmwXS/vTbbhopMUbhKp2JhOeVTfxgaCIlF8=
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 h1:Gii5eqf+GmIEwGNKQYQClCayuJCe2/4fZUvF7VG99sU=
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk=

17
model/relabel/relabel.go

@ -142,17 +142,13 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
// Regexp encapsulates a regexp.Regexp and makes it YAML marshalable.
type Regexp struct {
*regexp.Regexp
original string
}
// NewRegexp creates a new anchored Regexp and returns an error if the
// passed-in regular expression does not compile.
func NewRegexp(s string) (Regexp, error) {
regex, err := regexp.Compile("^(?:" + s + ")$")
return Regexp{
Regexp: regex,
original: s,
}, err
return Regexp{Regexp: regex}, err
}
// MustNewRegexp works like NewRegexp, but panics if the regular expression does not compile.
@ -180,12 +176,19 @@ func (re *Regexp) UnmarshalYAML(unmarshal func(interface{}) error) error {
// MarshalYAML implements the yaml.Marshaler interface.
func (re Regexp) MarshalYAML() (interface{}, error) {
if re.original != "" {
return re.original, nil
if re.String() != "" {
return re.String(), nil
}
return nil, nil
}
// String returns the original string used to compile the regular expression.
func (re Regexp) String() string {
str := re.Regexp.String()
// Trim the anchor `^(?:` prefix and `)$` suffix.
return str[4 : len(str)-2]
}
// Process returns a relabeled copy of the given label set. The relabel configurations
// are applied in order of input.
// If a label set is dropped, nil is returned.

2
model/relabel/relabel_test.go

@ -461,7 +461,7 @@ func TestRelabel(t *testing.T) {
if cfg.Separator == "" {
cfg.Separator = DefaultRelabelConfig.Separator
}
if cfg.Regex.original == "" {
if cfg.Regex.Regexp == nil || cfg.Regex.String() == "" {
cfg.Regex = DefaultRelabelConfig.Regex
}
if cfg.Replacement == "" {

2
tsdb/head_wal.go

@ -537,7 +537,7 @@ func (wp *walSubsetProcessor) waitUntilIdle() {
}
wp.input <- []record.RefSample{}
for len(wp.input) != 0 {
time.Sleep(1 * time.Millisecond)
time.Sleep(10 * time.Microsecond)
select {
case <-wp.output: // Allow output side to drain to avoid deadlock.
default:

7
web/api/v1/api.go

@ -556,7 +556,12 @@ func returnAPIError(err error) *apiError {
return nil
}
switch errors.Cause(err).(type) {
cause := errors.Unwrap(err)
if cause == nil {
cause = err
}
switch cause.(type) {
case promql.ErrQueryCanceled:
return &apiError{errorCanceled, err}
case promql.ErrQueryTimeout:

12
web/api/v1/api_test.go

@ -2949,19 +2949,19 @@ func TestReturnAPIError(t *testing.T) {
err: promql.ErrStorage{Err: errors.New("storage error")},
expected: errorInternal,
}, {
err: errors.Wrap(promql.ErrStorage{Err: errors.New("storage error")}, "wrapped"),
err: fmt.Errorf("wrapped: %w", promql.ErrStorage{Err: errors.New("storage error")}),
expected: errorInternal,
}, {
err: promql.ErrQueryTimeout("timeout error"),
expected: errorTimeout,
}, {
err: errors.Wrap(promql.ErrQueryTimeout("timeout error"), "wrapped"),
err: fmt.Errorf("wrapped: %w", promql.ErrQueryTimeout("timeout error")),
expected: errorTimeout,
}, {
err: promql.ErrQueryCanceled("canceled error"),
expected: errorCanceled,
}, {
err: errors.Wrap(promql.ErrQueryCanceled("canceled error"), "wrapped"),
err: fmt.Errorf("wrapped: %w", promql.ErrQueryCanceled("canceled error")),
expected: errorCanceled,
}, {
err: errors.New("exec error"),
@ -2969,10 +2969,10 @@ func TestReturnAPIError(t *testing.T) {
},
}
for _, c := range cases {
for ix, c := range cases {
actual := returnAPIError(c.err)
require.Error(t, actual)
require.Equal(t, c.expected, actual.typ)
require.Error(t, actual, ix)
require.Equal(t, c.expected, actual.typ, ix)
}
}

236
web/api/v1/errors_test.go

@ -0,0 +1,236 @@
// Copyright 2022 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package v1
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"time"
"github.com/go-kit/log"
"github.com/grafana/regexp"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/route"
"github.com/stretchr/testify/require"
"github.com/prometheus/prometheus/config"
"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/promql"
"github.com/prometheus/prometheus/rules"
"github.com/prometheus/prometheus/scrape"
"github.com/prometheus/prometheus/storage"
)
func TestApiStatusCodes(t *testing.T) {
for name, tc := range map[string]struct {
err error
expectedString string
expectedCode int
}{
"random error": {
err: errors.New("some random error"),
expectedString: "some random error",
expectedCode: http.StatusUnprocessableEntity,
},
"promql.ErrTooManySamples": {
err: promql.ErrTooManySamples("some error"),
expectedString: "too many samples",
expectedCode: http.StatusUnprocessableEntity,
},
"promql.ErrQueryCanceled": {
err: promql.ErrQueryCanceled("some error"),
expectedString: "query was canceled",
expectedCode: http.StatusServiceUnavailable,
},
"promql.ErrQueryTimeout": {
err: promql.ErrQueryTimeout("some error"),
expectedString: "query timed out",
expectedCode: http.StatusServiceUnavailable,
},
"context.DeadlineExceeded": {
err: context.DeadlineExceeded,
expectedString: "context deadline exceeded",
expectedCode: http.StatusUnprocessableEntity,
},
"context.Canceled": {
err: context.Canceled,
expectedString: "context canceled",
expectedCode: http.StatusUnprocessableEntity,
},
} {
for k, q := range map[string]storage.SampleAndChunkQueryable{
"error from queryable": errorTestQueryable{err: tc.err},
"error from querier": errorTestQueryable{q: errorTestQuerier{err: tc.err}},
"error from seriesset": errorTestQueryable{q: errorTestQuerier{s: errorTestSeriesSet{err: tc.err}}},
} {
t.Run(fmt.Sprintf("%s/%s", name, k), func(t *testing.T) {
r := createPrometheusAPI(q)
rec := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/api/v1/query?query=up", nil)
r.ServeHTTP(rec, req)
require.Equal(t, tc.expectedCode, rec.Code)
require.Contains(t, rec.Body.String(), tc.expectedString)
})
}
}
}
func createPrometheusAPI(q storage.SampleAndChunkQueryable) *route.Router {
engine := promql.NewEngine(promql.EngineOpts{
Logger: log.NewNopLogger(),
Reg: nil,
ActiveQueryTracker: nil,
MaxSamples: 100,
Timeout: 5 * time.Second,
})
api := NewAPI(
engine,
q,
nil,
nil,
func(context.Context) TargetRetriever { return &DummyTargetRetriever{} },
func(context.Context) AlertmanagerRetriever { return &DummyAlertmanagerRetriever{} },
func() config.Config { return config.Config{} },
map[string]string{}, // TODO: include configuration flags
GlobalURLOptions{},
func(f http.HandlerFunc) http.HandlerFunc { return f },
nil, // Only needed for admin APIs.
"", // This is for snapshots, which is disabled when admin APIs are disabled. Hence empty.
false, // Disable admin APIs.
log.NewNopLogger(),
func(context.Context) RulesRetriever { return &DummyRulesRetriever{} },
0, 0, 0, // Remote read samples and concurrency limit.
false, // Not an agent.
regexp.MustCompile(".*"),
func() (RuntimeInfo, error) { return RuntimeInfo{}, errors.New("not implemented") },
&PrometheusVersion{},
prometheus.DefaultGatherer,
nil,
nil,
)
promRouter := route.New().WithPrefix("/api/v1")
api.Register(promRouter)
return promRouter
}
type errorTestQueryable struct {
q storage.Querier
err error
}
func (t errorTestQueryable) ChunkQuerier(ctx context.Context, mint, maxt int64) (storage.ChunkQuerier, error) {
return nil, t.err
}
func (t errorTestQueryable) Querier(ctx context.Context, mint, maxt int64) (storage.Querier, error) {
if t.q != nil {
return t.q, nil
}
return nil, t.err
}
type errorTestQuerier struct {
s storage.SeriesSet
err error
}
func (t errorTestQuerier) LabelValues(name string, matchers ...*labels.Matcher) ([]string, storage.Warnings, error) {
return nil, nil, t.err
}
func (t errorTestQuerier) LabelNames(matchers ...*labels.Matcher) ([]string, storage.Warnings, error) {
return nil, nil, t.err
}
func (t errorTestQuerier) Close() error {
return nil
}
func (t errorTestQuerier) Select(sortSeries bool, hints *storage.SelectHints, matchers ...*labels.Matcher) storage.SeriesSet {
if t.s != nil {
return t.s
}
return storage.ErrSeriesSet(t.err)
}
type errorTestSeriesSet struct {
err error
}
func (t errorTestSeriesSet) Next() bool {
return false
}
func (t errorTestSeriesSet) At() storage.Series {
return nil
}
func (t errorTestSeriesSet) Err() error {
return t.err
}
func (t errorTestSeriesSet) Warnings() storage.Warnings {
return nil
}
// DummyTargetRetriever implements github.com/prometheus/prometheus/web/api/v1.targetRetriever.
type DummyTargetRetriever struct{}
// TargetsActive implements targetRetriever.
func (DummyTargetRetriever) TargetsActive() map[string][]*scrape.Target {
return map[string][]*scrape.Target{}
}
// TargetsDropped implements targetRetriever.
func (DummyTargetRetriever) TargetsDropped() map[string][]*scrape.Target {
return map[string][]*scrape.Target{}
}
// DummyAlertmanagerRetriever implements AlertmanagerRetriever.
type DummyAlertmanagerRetriever struct{}
// Alertmanagers implements AlertmanagerRetriever.
func (DummyAlertmanagerRetriever) Alertmanagers() []*url.URL { return nil }
// DroppedAlertmanagers implements AlertmanagerRetriever.
func (DummyAlertmanagerRetriever) DroppedAlertmanagers() []*url.URL { return nil }
// DummyRulesRetriever implements RulesRetriever.
type DummyRulesRetriever struct{}
// RuleGroups implements RulesRetriever.
func (DummyRulesRetriever) RuleGroups() []*rules.Group {
return nil
}
// AlertingRules implements RulesRetriever.
func (DummyRulesRetriever) AlertingRules() []*rules.AlertingRule {
return nil
}

12
web/ui/build_ui.sh

@ -14,28 +14,24 @@
# limitations under the License.
set -e
current=$(pwd)
if ! [[ -w $HOME ]]
then
export npm_config_cache=$(mktemp -d)
fi
buildOrder=(module/lezer-promql module/codemirror-promql)
buildOrder=(lezer-promql codemirror-promql)
function buildModule() {
for module in "${buildOrder[@]}"; do
cd "${module}"
echo "build ${module}"
npm run build
cd "${current}"
npm run build -w "@prometheus-io/${module}"
done
}
function buildReactApp() {
cd react-app
echo "build react-app"
npm run build
cd "${current}"
npm run build -w @prometheus-io/app
rm -rf ./static/react
mv ./react-app/build ./static/react
}

4
web/ui/module/codemirror-promql/jest.config.cjs

@ -12,7 +12,7 @@ module.exports = {
},
},
moduleNameMapper: {
'lezer-promql': '<rootDir>/../../node_modules/lezer-promql/dist/index.es.js'
'lezer-promql': '<rootDir>/../../node_modules/@prometheus-io/lezer-promql/dist/index.cjs'
},
transformIgnorePatterns: ["<rootDir>/../../node_modules/(?!lezer-promql)/"]
transformIgnorePatterns: ["<rootDir>/../../node_modules/(?!@prometheus-io/lezer-promql)/"]
};

33
web/ui/module/codemirror-promql/package.json

@ -1,5 +1,5 @@
{
"name": "codemirror-promql",
"name": "@prometheus-io/codemirror-promql",
"version": "0.19.0",
"description": "a CodeMirror mode for the PromQL language",
"types": "dist/esm/index.d.ts",
@ -29,30 +29,29 @@
},
"homepage": "https://github.com/prometheus/prometheus/blob/main/web/ui/module/codemirror-promql/README.md",
"dependencies": {
"lezer-promql": "0.23.0",
"@prometheus-io/lezer-promql": "0.23.0",
"lru-cache": "^6.0.0"
},
"devDependencies": {
"@codemirror/autocomplete": "^0.19.15",
"@codemirror/highlight": "^0.19.8",
"@codemirror/language": "^0.19.10",
"@codemirror/lint": "^0.19.6",
"@codemirror/state": "^0.19.9",
"@codemirror/view": "^0.19.48",
"@lezer/common": "^0.15.12",
"@lezer/lr": "^0.15.8",
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.0.0",
"@codemirror/lint": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0",
"@lezer/common": "^1.0.0",
"@lezer/lr": "^1.0.0",
"@lezer/highlight": "^1.0.0",
"@types/lru-cache": "^5.1.1",
"isomorphic-fetch": "^3.0.0",
"nock": "^13.2.4"
},
"peerDependencies": {
"@codemirror/autocomplete": "^0.19.15",
"@codemirror/highlight": "^0.19.8",
"@codemirror/language": "^0.19.10",
"@codemirror/lint": "^0.19.6",
"@codemirror/state": "^0.19.9",
"@codemirror/view": "^0.19.48",
"@lezer/common": "^0.15.12"
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.0.0",
"@codemirror/lint": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0",
"@lezer/common": "^1.0.0"
},
"prettier": {
"singleQuote": true,

94
web/ui/module/codemirror-promql/src/complete/hybrid.test.ts

@ -26,7 +26,7 @@ import {
numberTerms,
snippets,
} from './promql.terms';
import { EqlSingle, Neq } from 'lezer-promql';
import { EqlSingle, Neq } from '@prometheus-io/lezer-promql';
import { syntaxTree } from '@codemirror/language';
import { newCompleteStrategy } from './index';
@ -734,7 +734,7 @@ describe('autocomplete promQL test', () => {
options: ([] as Completion[]).concat(functionIdentifierTerms, aggregateOpTerms, numberTerms, snippets),
from: 0,
to: 0,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -745,7 +745,7 @@ describe('autocomplete promQL test', () => {
options: ([] as Completion[]).concat(functionIdentifierTerms, aggregateOpTerms, numberTerms, snippets),
from: 0,
to: 3,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -756,7 +756,7 @@ describe('autocomplete promQL test', () => {
options: ([] as Completion[]).concat(functionIdentifierTerms, aggregateOpTerms, snippets),
from: 4,
to: 4,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -767,7 +767,7 @@ describe('autocomplete promQL test', () => {
options: ([] as Completion[]).concat(functionIdentifierTerms, aggregateOpTerms, snippets),
from: 4,
to: 6,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -778,7 +778,7 @@ describe('autocomplete promQL test', () => {
options: ([] as Completion[]).concat(functionIdentifierTerms, aggregateOpTerms, snippets),
from: 9,
to: 9,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -789,7 +789,7 @@ describe('autocomplete promQL test', () => {
options: ([] as Completion[]).concat(functionIdentifierTerms, aggregateOpTerms, snippets),
from: 25,
to: 33,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -800,7 +800,7 @@ describe('autocomplete promQL test', () => {
options: ([] as Completion[]).concat(functionIdentifierTerms, aggregateOpTerms, binOpModifierTerms, numberTerms, snippets),
from: 14,
to: 19,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -811,7 +811,7 @@ describe('autocomplete promQL test', () => {
options: ([] as Completion[]).concat(functionIdentifierTerms, aggregateOpTerms, binOpModifierTerms, numberTerms, snippets),
from: 40,
to: 41,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -822,7 +822,7 @@ describe('autocomplete promQL test', () => {
options: [],
from: 8,
to: 8,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -833,7 +833,7 @@ describe('autocomplete promQL test', () => {
options: [],
from: 8,
to: 11,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -844,7 +844,7 @@ describe('autocomplete promQL test', () => {
options: [],
from: 18,
to: 23,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -855,7 +855,7 @@ describe('autocomplete promQL test', () => {
options: [],
from: 12,
to: 12,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -866,7 +866,7 @@ describe('autocomplete promQL test', () => {
options: [],
from: 1,
to: 1,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -877,7 +877,7 @@ describe('autocomplete promQL test', () => {
options: [],
from: 12,
to: 15,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -888,7 +888,7 @@ describe('autocomplete promQL test', () => {
options: [],
from: 1,
to: 4,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -899,7 +899,7 @@ describe('autocomplete promQL test', () => {
options: [],
from: 23,
to: 23,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -910,7 +910,7 @@ describe('autocomplete promQL test', () => {
options: [],
from: 12,
to: 12,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -921,7 +921,7 @@ describe('autocomplete promQL test', () => {
options: ([] as Completion[]).concat(aggregateOpModifierTerms, binOpTerms),
from: 6,
to: 7,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -932,7 +932,7 @@ describe('autocomplete promQL test', () => {
options: ([] as Completion[]).concat(aggregateOpModifierTerms, binOpTerms),
from: 19,
to: 21,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -943,7 +943,7 @@ describe('autocomplete promQL test', () => {
options: ([] as Completion[]).concat(aggregateOpModifierTerms, binOpTerms, [{ label: 'offset' }]),
from: 4,
to: 5,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -954,7 +954,7 @@ describe('autocomplete promQL test', () => {
options: binOpTerms,
from: 12,
to: 13,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -965,7 +965,7 @@ describe('autocomplete promQL test', () => {
options: binOpTerms,
from: 12,
to: 13,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -976,7 +976,7 @@ describe('autocomplete promQL test', () => {
options: matchOpTerms,
from: 11,
to: 12,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -987,7 +987,7 @@ describe('autocomplete promQL test', () => {
options: matchOpTerms,
from: 21,
to: 22,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -998,7 +998,7 @@ describe('autocomplete promQL test', () => {
options: durationTerms,
from: 28,
to: 28,
span: undefined,
validFor: undefined,
},
},
{
@ -1009,7 +1009,7 @@ describe('autocomplete promQL test', () => {
options: durationTerms,
from: 46,
to: 46,
span: undefined,
validFor: undefined,
},
},
{
@ -1020,7 +1020,7 @@ describe('autocomplete promQL test', () => {
options: ([] as Completion[]).concat(binOpTerms, [{ label: 'offset' }]),
from: 20,
to: 23,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -1031,7 +1031,7 @@ describe('autocomplete promQL test', () => {
options: ([] as Completion[]).concat(binOpTerms, [{ label: 'offset' }]),
from: 12,
to: 16,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -1042,7 +1042,7 @@ describe('autocomplete promQL test', () => {
options: ([] as Completion[]).concat(binOpTerms, [{ label: 'offset' }]),
from: 34,
to: 37,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -1053,7 +1053,7 @@ describe('autocomplete promQL test', () => {
options: ([] as Completion[]).concat(binOpTerms, [{ label: 'offset' }]),
from: 14,
to: 16,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -1064,7 +1064,7 @@ describe('autocomplete promQL test', () => {
options: ([] as Completion[]).concat(binOpTerms, [{ label: 'offset' }]),
from: 38,
to: 41,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -1075,7 +1075,7 @@ describe('autocomplete promQL test', () => {
options: [],
from: 0,
to: 3,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -1086,7 +1086,7 @@ describe('autocomplete promQL test', () => {
options: [],
from: 0,
to: 12,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -1097,7 +1097,7 @@ describe('autocomplete promQL test', () => {
options: durationTerms,
from: 4,
to: 4,
span: undefined,
validFor: undefined,
},
},
{
@ -1108,7 +1108,7 @@ describe('autocomplete promQL test', () => {
options: durationTerms,
from: 6,
to: 6,
span: undefined,
validFor: undefined,
},
},
{
@ -1119,7 +1119,7 @@ describe('autocomplete promQL test', () => {
options: durationTerms,
from: 26,
to: 26,
span: undefined,
validFor: undefined,
},
},
{
@ -1130,7 +1130,7 @@ describe('autocomplete promQL test', () => {
options: durationTerms,
from: 28,
to: 28,
span: undefined,
validFor: undefined,
},
},
{
@ -1141,7 +1141,7 @@ describe('autocomplete promQL test', () => {
options: durationTerms,
from: 7,
to: 7,
span: undefined,
validFor: undefined,
},
},
{
@ -1152,7 +1152,7 @@ describe('autocomplete promQL test', () => {
options: durationTerms,
from: 9,
to: 9,
span: undefined,
validFor: undefined,
},
},
{
@ -1163,7 +1163,7 @@ describe('autocomplete promQL test', () => {
options: durationTerms,
from: 29,
to: 29,
span: undefined,
validFor: undefined,
},
},
{
@ -1174,7 +1174,7 @@ describe('autocomplete promQL test', () => {
options: durationTerms,
from: 31,
to: 31,
span: undefined,
validFor: undefined,
},
},
{
@ -1185,7 +1185,7 @@ describe('autocomplete promQL test', () => {
options: atModifierTerms,
from: 4,
to: 5,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -1197,7 +1197,7 @@ describe('autocomplete promQL test', () => {
options: ([] as Completion[]).concat(mockedMetricsTerms, functionIdentifierTerms, aggregateOpTerms, numberTerms, snippets),
from: 0,
to: 5,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -1226,7 +1226,7 @@ describe('autocomplete promQL test', () => {
],
from: 20,
to: 20,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -1243,7 +1243,7 @@ describe('autocomplete promQL test', () => {
],
from: 25,
to: 25,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
{
@ -1274,7 +1274,7 @@ describe('autocomplete promQL test', () => {
),
from: 0,
to: 3,
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
},
},
];

4
web/ui/module/codemirror-promql/src/complete/hybrid.ts

@ -58,7 +58,7 @@ import {
SubqueryExpr,
Unless,
VectorSelector,
} from 'lezer-promql';
} from '@prometheus-io/lezer-promql';
import { Completion, CompletionContext, CompletionResult } from '@codemirror/autocomplete';
import { EditorState } from '@codemirror/state';
import { buildLabelMatchers, containsAtLeastOneChild, containsChild, retrieveAllRecursiveNodes, walkBackward, walkThrough } from '../parser';
@ -140,7 +140,7 @@ function arrayToCompletionResult(data: Completion[], from: number, to: number, i
from: from,
to: to,
options: options,
span: span ? /^[a-zA-Z0-9_:]+$/ : undefined,
validFor: span ? /^[a-zA-Z0-9_:]+$/ : undefined,
} as CompletionResult;
}

2
web/ui/module/codemirror-promql/src/parser/matcher.test.ts

@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { EqlRegex, EqlSingle, Neq, NeqRegex } from 'lezer-promql';
import { EqlRegex, EqlSingle, Neq, NeqRegex } from '@prometheus-io/lezer-promql';
import { labelMatchersToString } from './matcher';
import { Matcher } from '../types';

4
web/ui/module/codemirror-promql/src/parser/matcher.ts

@ -12,13 +12,13 @@
// limitations under the License.
import { SyntaxNode } from '@lezer/common';
import { EqlRegex, EqlSingle, LabelName, MatchOp, Neq, NeqRegex, StringLiteral } from 'lezer-promql';
import { EqlRegex, EqlSingle, LabelName, MatchOp, Neq, NeqRegex, StringLiteral } from '@prometheus-io/lezer-promql';
import { EditorState } from '@codemirror/state';
import { Matcher } from '../types';
function createMatcher(labelMatcher: SyntaxNode, state: EditorState): Matcher {
const matcher = new Matcher(0, '', '');
const cursor = labelMatcher.cursor;
const cursor = labelMatcher.cursor();
if (!cursor.next()) {
// weird case, that would mean the labelMatcher doesn't have any child.
return matcher;

2
web/ui/module/codemirror-promql/src/parser/parser.ts

@ -47,7 +47,7 @@ import {
UnaryExpr,
Unless,
VectorSelector,
} from 'lezer-promql';
} from '@prometheus-io/lezer-promql';
import { containsAtLeastOneChild, retrieveAllRecursiveNodes, walkThrough } from './path-finder';
import { getType } from './type';
import { buildLabelMatchers } from './matcher';

2
web/ui/module/codemirror-promql/src/parser/path-finder.test.ts

@ -31,7 +31,7 @@ import {
NumberLiteral,
Sub,
VectorSelector,
} from 'lezer-promql';
} from '@prometheus-io/lezer-promql';
import { createEditorState } from '../test/utils-test';
import { containsAtLeastOneChild, containsChild, retrieveAllRecursiveNodes, walkBackward, walkThrough } from './path-finder';
import { SyntaxNode } from '@lezer/common';

8
web/ui/module/codemirror-promql/src/parser/path-finder.ts

@ -16,7 +16,7 @@ import { SyntaxNode } from '@lezer/common';
// walkBackward will iterate other the tree from the leaf to the root until it founds the given `exit` node.
// It returns null if the exit is not found.
export function walkBackward(node: SyntaxNode, exit: number): SyntaxNode | null {
const cursor = node.cursor;
const cursor = node.cursor();
let cursorIsMoving = true;
while (cursorIsMoving && cursor.type.id !== exit) {
cursorIsMoving = cursor.parent();
@ -29,7 +29,7 @@ export function walkBackward(node: SyntaxNode, exit: number): SyntaxNode | null
// Otherwise if it's not possible to reach the last id/name of the path, it will return `null`
// Note: the way followed during the iteration of the tree to find the given path, is only from the root to the leaf.
export function walkThrough(node: SyntaxNode, ...path: (number | string)[]): SyntaxNode | null {
const cursor = node.cursor;
const cursor = node.cursor();
let i = 0;
let cursorIsMoving = true;
path.unshift(cursor.type.id);
@ -50,7 +50,7 @@ export function walkThrough(node: SyntaxNode, ...path: (number | string)[]): Syn
}
export function containsAtLeastOneChild(node: SyntaxNode, ...child: (number | string)[]): boolean {
const cursor = node.cursor;
const cursor = node.cursor();
if (!cursor.next()) {
// let's try to move directly to the children level and
// return false immediately if the current node doesn't have any child
@ -64,7 +64,7 @@ export function containsAtLeastOneChild(node: SyntaxNode, ...child: (number | st
}
export function containsChild(node: SyntaxNode, ...child: (number | string)[]): boolean {
const cursor = node.cursor;
const cursor = node.cursor();
if (!cursor.next()) {
// let's try to move directly to the children level and
// return false immediately if the current node doesn't have any child

2
web/ui/module/codemirror-promql/src/parser/type.ts

@ -26,7 +26,7 @@ import {
SubqueryExpr,
UnaryExpr,
VectorSelector,
} from 'lezer-promql';
} from '@prometheus-io/lezer-promql';
import { walkThrough } from './path-finder';
import { getFunction, ValueType } from '../types';

2
web/ui/module/codemirror-promql/src/parser/vector.test.ts

@ -14,7 +14,7 @@
import { buildVectorMatching } from './vector';
import { createEditorState } from '../test/utils-test';
import { walkThrough } from './path-finder';
import { BinaryExpr, Expr } from 'lezer-promql';
import { BinaryExpr, Expr } from '@prometheus-io/lezer-promql';
import { syntaxTree } from '@codemirror/language';
import { VectorMatchCardinality } from '../types';

2
web/ui/module/codemirror-promql/src/parser/vector.ts

@ -26,7 +26,7 @@ import {
OnOrIgnoring,
Or,
Unless,
} from 'lezer-promql';
} from '@prometheus-io/lezer-promql';
import { VectorMatchCardinality, VectorMatching } from '../types';
import { containsAtLeastOneChild, retrieveAllRecursiveNodes } from './path-finder';

23
web/ui/module/codemirror-promql/src/promql.ts

@ -11,8 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { parser } from 'lezer-promql';
import { styleTags, tags } from '@codemirror/highlight';
import { parser } from '@prometheus-io/lezer-promql';
import { Extension } from '@codemirror/state';
import { CompleteConfiguration, CompleteStrategy, newCompleteStrategy } from './complete';
import { LintStrategy, newLintStrategy, promQLLinter } from './lint';
@ -28,26 +27,6 @@ export function promQLLanguage(top: LanguageType): LRLanguage {
return LRLanguage.define({
parser: parser.configure({
top: top,
props: [
styleTags({
LineComment: tags.comment,
LabelName: tags.labelName,
StringLiteral: tags.string,
NumberLiteral: tags.number,
Duration: tags.number,
'Abs Absent AbsentOverTime Acos Acosh Asin Asinh Atan Atanh AvgOverTime Ceil Changes Clamp ClampMax ClampMin Cos Cosh CountOverTime DaysInMonth DayOfMonth DayOfWeek DayOfYear Deg Delta Deriv Exp Floor HistogramQuantile HoltWinters Hour Idelta Increase Irate LabelReplace LabelJoin LastOverTime Ln Log10 Log2 MaxOverTime MinOverTime Minute Month Pi PredictLinear PresentOverTime QuantileOverTime Rad Rate Resets Round Scalar Sgn Sin Sinh Sort SortDesc Sqrt StddevOverTime StdvarOverTime SumOverTime Tan Tanh Time Timestamp Vector Year':
tags.function(tags.variableName),
'Avg Bottomk Count Count_values Group Max Min Quantile Stddev Stdvar Sum Topk': tags.operatorKeyword,
'By Without Bool On Ignoring GroupLeft GroupRight Offset Start End': tags.modifier,
'And Unless Or': tags.logicOperator,
'Sub Add Mul Mod Div Atan2 Eql Neq Lte Lss Gte Gtr EqlRegex EqlSingle NeqRegex Pow At': tags.operator,
UnaryOp: tags.arithmeticOperator,
'( )': tags.paren,
'[ ]': tags.squareBracket,
'{ }': tags.brace,
'⚠': tags.invalid,
}),
],
}),
languageData: {
closeBrackets: { brackets: ['(', '[', '{', "'", '"', '`'] },

2
web/ui/module/codemirror-promql/src/test/utils-test.ts

@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { parser } from 'lezer-promql';
import { parser } from '@prometheus-io/lezer-promql';
import { EditorState } from '@codemirror/state';
import { LRLanguage } from '@codemirror/language';
import nock from 'nock';

2
web/ui/module/codemirror-promql/src/types/function.ts

@ -79,7 +79,7 @@ import {
Timestamp,
Vector,
Year,
} from 'lezer-promql';
} from '@prometheus-io/lezer-promql';
export enum ValueType {
none = 'none',

2
web/ui/module/codemirror-promql/src/types/matcher.ts

@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { EqlSingle, Neq } from 'lezer-promql';
import { EqlSingle, Neq } from '@prometheus-io/lezer-promql';
export class Matcher {
type: number;

10
web/ui/module/lezer-promql/package.json

@ -1,5 +1,5 @@
{
"name": "lezer-promql",
"name": "@prometheus-io/lezer-promql",
"version": "0.23.0",
"description": "lezer-based PromQL grammar",
"main": "index.cjs",
@ -30,10 +30,12 @@
"test": "NODE_OPTIONS=--experimental-vm-modules jest"
},
"devDependencies": {
"@lezer/generator": "^0.15.4",
"@lezer/lr": "^0.15.8"
"@lezer/generator": "^1.0.0",
"@lezer/lr": "^1.0.0",
"@lezer/highlight": "^1.0.0"
},
"peerDependencies": {
"@lezer/lr": "^0.15.8"
"@lezer/lr": "^1.0.0",
"@lezer/highlight": "^1.0.0"
}
}

33
web/ui/module/lezer-promql/src/highlight.js

@ -0,0 +1,33 @@
// Copyright 2022 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import {styleTags, tags} from "@lezer/highlight";
export const promQLHighLight = styleTags({
LineComment: tags.comment,
LabelName: tags.labelName,
StringLiteral: tags.string,
NumberLiteral: tags.number,
Duration: tags.number,
'Abs Absent AbsentOverTime Acos Acosh Asin Asinh Atan Atanh AvgOverTime Ceil Changes Clamp ClampMax ClampMin Cos Cosh CountOverTime DaysInMonth DayOfMonth DayOfWeek DayOfYear Deg Delta Deriv Exp Floor HistogramQuantile HoltWinters Hour Idelta Increase Irate LabelReplace LabelJoin LastOverTime Ln Log10 Log2 MaxOverTime MinOverTime Minute Month Pi PredictLinear PresentOverTime QuantileOverTime Rad Rate Resets Round Scalar Sgn Sin Sinh Sort SortDesc Sqrt StddevOverTime StdvarOverTime SumOverTime Tan Tanh Time Timestamp Vector Year':
tags.function(tags.variableName),
'Avg Bottomk Count Count_values Group Max Min Quantile Stddev Stdvar Sum Topk': tags.operatorKeyword,
'By Without Bool On Ignoring GroupLeft GroupRight Offset Start End': tags.modifier,
'And Unless Or': tags.logicOperator,
'Sub Add Mul Mod Div Atan2 Eql Neq Lte Lss Gte Gtr EqlRegex EqlSingle NeqRegex Pow At': tags.operator,
UnaryOp: tags.arithmeticOperator,
'( )': tags.paren,
'[ ]': tags.squareBracket,
'{ }': tags.brace,
'⚠': tags.invalid,
})

2
web/ui/module/lezer-promql/src/promql.grammar

@ -357,6 +357,8 @@ NumberLiteral {
End
}
@external propSource promQLHighLight from "./highlight"
// FunctionIdentifier definitions
Abs { condFn<"abs"> }
Absent { condFn<"absent"> }

9502
web/ui/package-lock.json generated

File diff suppressed because it is too large Load Diff

2
web/ui/package.json

@ -1,5 +1,5 @@
{
"name": "prometheus",
"name": "prometheus-io",
"private": true,
"scripts": {
"build": "bash build_ui.sh --all",

32
web/ui/react-app/package.json

@ -1,28 +1,26 @@
{
"name": "graph",
"name": "@prometheus-io/app",
"version": "0.1.0",
"private": true,
"dependencies": {
"@codemirror/autocomplete": "^0.19.9",
"@codemirror/closebrackets": "^0.19.0",
"@codemirror/commands": "^0.19.5",
"@codemirror/comment": "^0.19.0",
"@codemirror/highlight": "^0.19.6",
"@codemirror/history": "^0.19.2",
"@codemirror/language": "^0.19.7",
"@codemirror/lint": "^0.19.3",
"@codemirror/matchbrackets": "^0.19.3",
"@codemirror/search": "^0.19.3",
"@codemirror/state": "^0.19.6",
"@codemirror/view": "^0.19.27",
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/commands": "^6.0.0",
"@codemirror/language": "^6.0.0",
"@codemirror/lint": "^6.0.0",
"@codemirror/search": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0",
"@forevolve/bootstrap-dark": "^1.0.0",
"@fortawesome/fontawesome-svg-core": "6.1.1",
"@fortawesome/free-solid-svg-icons": "6.1.1",
"@fortawesome/react-fontawesome": "0.1.17",
"@lezer/lr": "^1.0.0",
"@lezer/highlight": "^1.0.0",
"@lezer/common": "^1.0.0",
"@nexucis/fuzzy": "^0.4.0",
"@nexucis/kvsearch": "^0.7.0",
"@prometheus-io/codemirror-promql": "0.19.0",
"bootstrap": "^4.6.1",
"codemirror-promql": "0.19.0",
"css.escape": "^1.5.1",
"downshift": "^6.1.7",
"http-proxy-middleware": "^2.0.6",
@ -89,11 +87,11 @@
"enzyme-to-json/serializer"
],
"transformIgnorePatterns": [
"<rootDir>/../node_modules/(?!codemirror-promql)/",
"<rootDir>/../node_modules/(?!lezer-promql)/"
"<rootDir>/../node_modules/(?!@prometheus-io/codemirror-promql)/",
"<rootDir>/../node_modules/(?!@prometheus-io/lezer-promql)/"
],
"moduleNameMapper": {
"lezer-promql": "<rootDir>/../node_modules/lezer-promql/dist/index.cjs"
"lezer-promql": "<rootDir>/../node_modules/@prometheus-io/lezer-promql/dist/index.cjs"
}
},
"optionalDependencies": {

3
web/ui/react-app/src/pages/graph/CMTheme.tsx

@ -1,5 +1,6 @@
import { HighlightStyle, tags } from '@codemirror/highlight';
import { EditorView } from '@codemirror/view';
import { HighlightStyle } from '@codemirror/language';
import { tags } from '@lezer/highlight';
export const baseTheme = EditorView.theme({
'&.cm-editor': {

36
web/ui/react-app/src/pages/graph/ExpressionInput.tsx

@ -3,15 +3,18 @@ import { Button, InputGroup, InputGroupAddon, InputGroupText } from 'reactstrap'
import { EditorView, highlightSpecialChars, keymap, ViewUpdate, placeholder } from '@codemirror/view';
import { EditorState, Prec, Compartment } from '@codemirror/state';
import { indentOnInput, syntaxTree } from '@codemirror/language';
import { history, historyKeymap } from '@codemirror/history';
import { defaultKeymap, insertNewlineAndIndent } from '@codemirror/commands';
import { bracketMatching } from '@codemirror/matchbrackets';
import { closeBrackets, closeBracketsKeymap } from '@codemirror/closebrackets';
import { bracketMatching, indentOnInput, syntaxHighlighting, syntaxTree } from '@codemirror/language';
import { defaultKeymap, history, historyKeymap, insertNewlineAndIndent } from '@codemirror/commands';
import { highlightSelectionMatches } from '@codemirror/search';
import { commentKeymap } from '@codemirror/comment';
import { lintKeymap } from '@codemirror/lint';
import { autocompletion, completionKeymap, CompletionContext, CompletionResult } from '@codemirror/autocomplete';
import {
autocompletion,
completionKeymap,
CompletionContext,
CompletionResult,
closeBrackets,
closeBracketsKeymap,
} from '@codemirror/autocomplete';
import { baseTheme, lightTheme, darkTheme, promqlHighlighter } from './CMTheme';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
@ -19,8 +22,8 @@ import { faSearch, faSpinner, faGlobeEurope } from '@fortawesome/free-solid-svg-
import MetricsExplorer from './MetricsExplorer';
import { usePathPrefix } from '../../contexts/PathPrefixContext';
import { useTheme } from '../../contexts/ThemeContext';
import { CompleteStrategy, PromQLExtension } from 'codemirror-promql';
import { newCompleteStrategy } from 'codemirror-promql/dist/esm/complete';
import { CompleteStrategy, PromQLExtension } from '@prometheus-io/codemirror-promql';
import { newCompleteStrategy } from '@prometheus-io/codemirror-promql/dist/esm/complete';
const promqlExtension = new PromQLExtension();
@ -67,7 +70,7 @@ export class HistoryCompleteStrategy implements CompleteStrategy {
apply: q,
info: q.length < 80 ? undefined : q,
})),
span: /^[a-zA-Z0-9_:]+$/,
validFor: /^[a-zA-Z0-9_:]+$/,
};
if (res !== null) {
@ -110,7 +113,7 @@ const ExpressionInput: FC<CMExpressionInputProps> = ({
),
});
const dynamicConfig = [
enableHighlighting ? promqlHighlighter : [],
enableHighlighting ? syntaxHighlighting(promqlHighlighter) : [],
promqlExtension.asExtension(),
theme === 'dark' ? darkTheme : lightTheme,
];
@ -136,14 +139,7 @@ const ExpressionInput: FC<CMExpressionInputProps> = ({
autocompletion(),
highlightSelectionMatches(),
EditorView.lineWrapping,
keymap.of([
...closeBracketsKeymap,
...defaultKeymap,
...historyKeymap,
...commentKeymap,
...completionKeymap,
...lintKeymap,
]),
keymap.of([...closeBracketsKeymap, ...defaultKeymap, ...historyKeymap, ...completionKeymap, ...lintKeymap]),
placeholder('Expression (press Shift+Enter for newlines)'),
dynamicConfigCompartment.of(dynamicConfig),
// This keymap is added without precedence so that closing the autocomplete dropdown
@ -157,7 +153,7 @@ const ExpressionInput: FC<CMExpressionInputProps> = ({
},
},
]),
Prec.override(
Prec.highest(
keymap.of([
{
key: 'Enter',

Loading…
Cancel
Save