diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index defe385667..26ed504e1e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -226,24 +226,24 @@ jobs: - name: Install snmp_exporter/generator dependencies run: sudo apt-get update && sudo apt-get -y install libsnmp-dev if: github.repository == 'prometheus/snmp_exporter' + - name: Get golangci-lint version + id: golangci-lint-version + run: echo "version=$(make print-golangci-lint-version)" >> $GITHUB_OUTPUT - name: Lint with stringlabels uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0 with: args: --verbose --build-tags=stringlabels - # Make sure to sync this with Makefile.common and scripts/golangci-lint.yml. - version: v2.2.1 + version: ${{ steps.golangci-lint-version.outputs.version }} - name: Lint with slicelabels uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0 with: args: --verbose --build-tags=slicelabels - # Make sure to sync this with Makefile.common and scripts/golangci-lint.yml. - version: v2.2.1 + version: ${{ steps.golangci-lint-version.outputs.version }} - name: Lint with dedupelabels uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0 with: args: --verbose --build-tags=dedupelabels - # Make sure to sync this with Makefile.common and scripts/golangci-lint.yml. - version: v2.2.1 + version: ${{ steps.golangci-lint-version.outputs.version }} fuzzing: uses: ./.github/workflows/fuzzing.yml if: github.event_name == 'pull_request' diff --git a/.golangci.yml b/.golangci.yml index 09430a1ad1..4632d5a844 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -74,6 +74,9 @@ linters: - linters: - godot source: "^// ===" + - linters: + - staticcheck + text: 'v1\.(Endpoints|EndpointSubset|EndpointPort|EndpointAddress) is deprecated: This API is deprecated in v1.33+' warn-unused: true settings: depguard: diff --git a/Makefile.common b/Makefile.common index 1f4c9025a5..6762d0f830 100644 --- a/Makefile.common +++ b/Makefile.common @@ -61,7 +61,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_ SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v2.2.1 +GOLANGCI_LINT_VERSION ?= v2.4.0 GOLANGCI_FMT_OPTS ?= # golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64. # windows isn't included here because of the path separator being different. @@ -266,6 +266,10 @@ $(GOLANGCI_LINT): | sh -s -- -b $(FIRST_GOPATH)/bin $(GOLANGCI_LINT_VERSION) endif +.PHONY: common-print-golangci-lint-version +common-print-golangci-lint-version: + @echo $(GOLANGCI_LINT_VERSION) + .PHONY: precheck precheck:: diff --git a/RELEASE.md b/RELEASE.md index c30105deff..25f3ad299e 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -16,7 +16,8 @@ Please see [the v2.55 RELEASE.md](https://github.com/prometheus/prometheus/blob/ | v3.4 | 2025-04-29 | Jan-Otto Kröpke (Github: @jkroepke)| | v3.5 LTS | 2025-06-03 | Bryan Boreham (GitHub: @bboreham) | | v3.6 | 2025-08-01 | Ayoub Mrini (Github: @machine424) | -| v3.7 | 2025-09-15 | **volunteer welcome** | +| v3.7 | 2025-09-25 | Arthur Sens and George Krajcsovits (Github: @ArthurSens and @krajorama)| +| v3.8 | 2025-11-06 | **volunteer welcome** | If you are interested in volunteering please create a pull request against the [prometheus/prometheus](https://github.com/prometheus/prometheus) repository and propose yourself for the release series of your choice. diff --git a/cmd/prometheus/main.go b/cmd/prometheus/main.go index 8cbdd762f0..5ccfd0bc7d 100644 --- a/cmd/prometheus/main.go +++ b/cmd/prometheus/main.go @@ -275,6 +275,9 @@ func (c *flagConfig) setFeatureListOptions(logger *slog.Logger) error { case "promql-delayed-name-removal": c.promqlEnableDelayedNameRemoval = true logger.Info("Experimental PromQL delayed name removal enabled.") + case "promql-extended-range-selectors": + parser.EnableExtendedRangeSelectors = true + logger.Info("Experimental PromQL extended range selectors enabled.") case "": continue case "old-ui": @@ -561,7 +564,7 @@ func main() { a.Flag("scrape.discovery-reload-interval", "Interval used by scrape manager to throttle target groups updates."). Hidden().Default("5s").SetValue(&cfg.scrape.DiscoveryReloadInterval) - a.Flag("enable-feature", "Comma separated feature names to enable. Valid options: exemplar-storage, expand-external-labels, memory-snapshot-on-shutdown, promql-per-step-stats, promql-experimental-functions, extra-scrape-metrics, auto-gomaxprocs, native-histograms, created-timestamp-zero-ingestion, concurrent-rule-eval, delayed-compaction, old-ui, otlp-deltatocumulative, promql-duration-expr, use-uncached-io. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details."). + a.Flag("enable-feature", "Comma separated feature names to enable. Valid options: exemplar-storage, expand-external-labels, memory-snapshot-on-shutdown, promql-per-step-stats, promql-experimental-functions, extra-scrape-metrics, auto-gomaxprocs, native-histograms, created-timestamp-zero-ingestion, concurrent-rule-eval, delayed-compaction, old-ui, otlp-deltatocumulative, promql-duration-expr, use-uncached-io, promql-extended-range-selectors. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details."). Default("").StringsVar(&cfg.featureList) a.Flag("agent", "Run Prometheus in 'Agent mode'.").BoolVar(&agentMode) diff --git a/discovery/kubernetes/endpoints.go b/discovery/kubernetes/endpoints.go index 2d25213a12..b221201744 100644 --- a/discovery/kubernetes/endpoints.go +++ b/discovery/kubernetes/endpoints.go @@ -32,6 +32,7 @@ import ( ) // Endpoints discovers new endpoint targets. +// Deprecated: The Endpoints API is deprecated starting in K8s v1.33+. Use EndpointSlice. type Endpoints struct { logger *slog.Logger @@ -47,11 +48,11 @@ type Endpoints struct { endpointsStore cache.Store serviceStore cache.Store - queue *workqueue.Type + queue *workqueue.Typed[string] } // NewEndpoints returns a new endpoints discovery. -// Endpoints API is deprecated in k8s v1.33+, but we should still support it. +// Deprecated: The Endpoints API is deprecated starting in K8s v1.33+. Use NewEndpointSlice. func NewEndpoints(l *slog.Logger, eps cache.SharedIndexInformer, svc, pod, node, namespace cache.SharedInformer, eventCount *prometheus.CounterVec) *Endpoints { if l == nil { l = promslog.NewNopLogger() @@ -79,7 +80,9 @@ func NewEndpoints(l *slog.Logger, eps cache.SharedIndexInformer, svc, pod, node, withNodeMetadata: node != nil, namespaceInf: namespace, withNamespaceMetadata: namespace != nil, - queue: workqueue.NewNamed(RoleEndpoint.String()), + queue: workqueue.NewTypedWithConfig(workqueue.TypedQueueConfig[string]{ + Name: RoleEndpoint.String(), + }), } _, err := e.endpointsInf.AddEventHandler(cache.ResourceEventHandlerFuncs{ @@ -272,12 +275,11 @@ func (e *Endpoints) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { } func (e *Endpoints) process(ctx context.Context, ch chan<- []*targetgroup.Group) bool { - keyObj, quit := e.queue.Get() + key, quit := e.queue.Get() if quit { return false } - defer e.queue.Done(keyObj) - key := keyObj.(string) + defer e.queue.Done(key) namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { diff --git a/discovery/kubernetes/endpointslice.go b/discovery/kubernetes/endpointslice.go index a4b1d942ed..85b579438f 100644 --- a/discovery/kubernetes/endpointslice.go +++ b/discovery/kubernetes/endpointslice.go @@ -50,7 +50,7 @@ type EndpointSlice struct { endpointSliceStore cache.Store serviceStore cache.Store - queue *workqueue.Type + queue *workqueue.Typed[string] } // NewEndpointSlice returns a new endpointslice discovery. @@ -79,7 +79,9 @@ func NewEndpointSlice(l *slog.Logger, eps cache.SharedIndexInformer, svc, pod, n withNodeMetadata: node != nil, namespaceInf: namespace, withNamespaceMetadata: namespace != nil, - queue: workqueue.NewNamed(RoleEndpointSlice.String()), + queue: workqueue.NewTypedWithConfig(workqueue.TypedQueueConfig[string]{ + Name: RoleEndpointSlice.String(), + }), } _, err := e.endpointSliceInf.AddEventHandler(cache.ResourceEventHandlerFuncs{ @@ -236,12 +238,11 @@ func (e *EndpointSlice) Run(ctx context.Context, ch chan<- []*targetgroup.Group) } func (e *EndpointSlice) process(ctx context.Context, ch chan<- []*targetgroup.Group) bool { - keyObj, quit := e.queue.Get() + key, quit := e.queue.Get() if quit { return false } - defer e.queue.Done(keyObj) - key := keyObj.(string) + defer e.queue.Done(key) namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { diff --git a/discovery/kubernetes/ingress.go b/discovery/kubernetes/ingress.go index 7b74d8734d..551453e513 100644 --- a/discovery/kubernetes/ingress.go +++ b/discovery/kubernetes/ingress.go @@ -35,7 +35,7 @@ type Ingress struct { logger *slog.Logger informer cache.SharedIndexInformer store cache.Store - queue *workqueue.Type + queue *workqueue.Typed[string] namespaceInf cache.SharedInformer withNamespaceMetadata bool } @@ -47,10 +47,12 @@ func NewIngress(l *slog.Logger, inf cache.SharedIndexInformer, namespace cache.S ingressDeleteCount := eventCount.WithLabelValues(RoleIngress.String(), MetricLabelRoleDelete) s := &Ingress{ - logger: l, - informer: inf, - store: inf.GetStore(), - queue: workqueue.NewNamed(RoleIngress.String()), + logger: l, + informer: inf, + store: inf.GetStore(), + queue: workqueue.NewTypedWithConfig(workqueue.TypedQueueConfig[string]{ + Name: RoleIngress.String(), + }), namespaceInf: namespace, withNamespaceMetadata: namespace != nil, } @@ -137,12 +139,11 @@ func (i *Ingress) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { } func (i *Ingress) process(ctx context.Context, ch chan<- []*targetgroup.Group) bool { - keyObj, quit := i.queue.Get() + key, quit := i.queue.Get() if quit { return false } - defer i.queue.Done(keyObj) - key := keyObj.(string) + defer i.queue.Done(key) namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { diff --git a/discovery/kubernetes/kubernetes.go b/discovery/kubernetes/kubernetes.go index 7966de52a8..1a6f965ecd 100644 --- a/discovery/kubernetes/kubernetes.go +++ b/discovery/kubernetes/kubernetes.go @@ -387,12 +387,12 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { var informer cache.SharedIndexInformer e := d.client.DiscoveryV1().EndpointSlices(namespace) elw := &cache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) { options.FieldSelector = d.selectors.endpointslice.field options.LabelSelector = d.selectors.endpointslice.label return e.List(ctx, options) }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) { options.FieldSelector = d.selectors.endpointslice.field options.LabelSelector = d.selectors.endpointslice.label return e.Watch(ctx, options) @@ -402,12 +402,12 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { s := d.client.CoreV1().Services(namespace) slw := &cache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) { options.FieldSelector = d.selectors.service.field options.LabelSelector = d.selectors.service.label return s.List(ctx, options) }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) { options.FieldSelector = d.selectors.service.field options.LabelSelector = d.selectors.service.label return s.Watch(ctx, options) @@ -415,12 +415,12 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { } p := d.client.CoreV1().Pods(namespace) plw := &cache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) { options.FieldSelector = d.selectors.pod.field options.LabelSelector = d.selectors.pod.label return p.List(ctx, options) }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) { options.FieldSelector = d.selectors.pod.field options.LabelSelector = d.selectors.pod.label return p.Watch(ctx, options) @@ -454,12 +454,12 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { for _, namespace := range namespaces { e := d.client.CoreV1().Endpoints(namespace) elw := &cache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) { options.FieldSelector = d.selectors.endpoints.field options.LabelSelector = d.selectors.endpoints.label return e.List(ctx, options) }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) { options.FieldSelector = d.selectors.endpoints.field options.LabelSelector = d.selectors.endpoints.label return e.Watch(ctx, options) @@ -467,12 +467,12 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { } s := d.client.CoreV1().Services(namespace) slw := &cache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) { options.FieldSelector = d.selectors.service.field options.LabelSelector = d.selectors.service.label return s.List(ctx, options) }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) { options.FieldSelector = d.selectors.service.field options.LabelSelector = d.selectors.service.label return s.Watch(ctx, options) @@ -480,12 +480,12 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { } p := d.client.CoreV1().Pods(namespace) plw := &cache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) { options.FieldSelector = d.selectors.pod.field options.LabelSelector = d.selectors.pod.label return p.List(ctx, options) }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) { options.FieldSelector = d.selectors.pod.field options.LabelSelector = d.selectors.pod.label return p.Watch(ctx, options) @@ -531,12 +531,12 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { for _, namespace := range namespaces { p := d.client.CoreV1().Pods(namespace) plw := &cache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) { options.FieldSelector = d.selectors.pod.field options.LabelSelector = d.selectors.pod.label return p.List(ctx, options) }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) { options.FieldSelector = d.selectors.pod.field options.LabelSelector = d.selectors.pod.label return p.Watch(ctx, options) @@ -562,12 +562,12 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { for _, namespace := range namespaces { s := d.client.CoreV1().Services(namespace) slw := &cache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) { options.FieldSelector = d.selectors.service.field options.LabelSelector = d.selectors.service.label return s.List(ctx, options) }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) { options.FieldSelector = d.selectors.service.field options.LabelSelector = d.selectors.service.label return s.Watch(ctx, options) @@ -592,12 +592,12 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { for _, namespace := range namespaces { i := d.client.NetworkingV1().Ingresses(namespace) ilw := &cache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) { options.FieldSelector = d.selectors.ingress.field options.LabelSelector = d.selectors.ingress.label return i.List(ctx, options) }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) { options.FieldSelector = d.selectors.ingress.field options.LabelSelector = d.selectors.ingress.label return i.Watch(ctx, options) @@ -666,14 +666,14 @@ func retryOnError(ctx context.Context, interval time.Duration, f func() error) ( } } -func (d *Discovery) newNodeInformer(ctx context.Context) cache.SharedInformer { +func (d *Discovery) newNodeInformer(_ context.Context) cache.SharedInformer { nlw := &cache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) { options.FieldSelector = d.selectors.node.field options.LabelSelector = d.selectors.node.label return d.client.CoreV1().Nodes().List(ctx, options) }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) { options.FieldSelector = d.selectors.node.field options.LabelSelector = d.selectors.node.label return d.client.CoreV1().Nodes().Watch(ctx, options) @@ -682,13 +682,13 @@ func (d *Discovery) newNodeInformer(ctx context.Context) cache.SharedInformer { return d.mustNewSharedInformer(nlw, &apiv1.Node{}, resyncDisabled) } -func (d *Discovery) newNamespaceInformer(ctx context.Context) cache.SharedInformer { +func (d *Discovery) newNamespaceInformer(_ context.Context) cache.SharedInformer { // We don't filter on NamespaceDiscovery. nlw := &cache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) { return d.client.CoreV1().Namespaces().List(ctx, options) }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) { return d.client.CoreV1().Namespaces().Watch(ctx, options) }, } @@ -832,16 +832,16 @@ func (d *Discovery) newIndexedIngressesInformer(ilw *cache.ListWatch) cache.Shar return d.mustNewSharedIndexInformer(ilw, &networkv1.Ingress{}, resyncDisabled, indexers) } -func (d *Discovery) informerWatchErrorHandler(r *cache.Reflector, err error) { +func (d *Discovery) informerWatchErrorHandler(ctx context.Context, r *cache.Reflector, err error) { d.metrics.failuresCount.Inc() - cache.DefaultWatchErrorHandler(r, err) + cache.DefaultWatchErrorHandler(ctx, r, err) } func (d *Discovery) mustNewSharedInformer(lw cache.ListerWatcher, exampleObject runtime.Object, defaultEventHandlerResyncPeriod time.Duration) cache.SharedInformer { informer := cache.NewSharedInformer(lw, exampleObject, defaultEventHandlerResyncPeriod) // Invoking SetWatchErrorHandler should fail only if the informer has been started beforehand. // Such a scenario would suggest an incorrect use of the API, thus the panic. - if err := informer.SetWatchErrorHandler(d.informerWatchErrorHandler); err != nil { + if err := informer.SetWatchErrorHandlerWithContext(d.informerWatchErrorHandler); err != nil { panic(err) } return informer @@ -851,7 +851,7 @@ func (d *Discovery) mustNewSharedIndexInformer(lw cache.ListerWatcher, exampleOb informer := cache.NewSharedIndexInformer(lw, exampleObject, defaultEventHandlerResyncPeriod, indexers) // Invoking SetWatchErrorHandler should fail only if the informer has been started beforehand. // Such a scenario would suggest an incorrect use of the API, thus the panic. - if err := informer.SetWatchErrorHandler(d.informerWatchErrorHandler); err != nil { + if err := informer.SetWatchErrorHandlerWithContext(d.informerWatchErrorHandler); err != nil { panic(err) } return informer diff --git a/discovery/kubernetes/node.go b/discovery/kubernetes/node.go index 8a67abb676..131cdcc9e7 100644 --- a/discovery/kubernetes/node.go +++ b/discovery/kubernetes/node.go @@ -41,7 +41,7 @@ type Node struct { logger *slog.Logger informer cache.SharedInformer store cache.Store - queue *workqueue.Type + queue *workqueue.Typed[string] } // NewNode returns a new node discovery. @@ -58,7 +58,9 @@ func NewNode(l *slog.Logger, inf cache.SharedInformer, eventCount *prometheus.Co logger: l, informer: inf, store: inf.GetStore(), - queue: workqueue.NewNamed(RoleNode.String()), + queue: workqueue.NewTypedWithConfig(workqueue.TypedQueueConfig[string]{ + Name: RoleNode.String(), + }), } _, err := n.informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ @@ -111,12 +113,11 @@ func (n *Node) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { } func (n *Node) process(ctx context.Context, ch chan<- []*targetgroup.Group) bool { - keyObj, quit := n.queue.Get() + key, quit := n.queue.Get() if quit { return false } - defer n.queue.Done(keyObj) - key := keyObj.(string) + defer n.queue.Done(key) _, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { diff --git a/discovery/kubernetes/pod.go b/discovery/kubernetes/pod.go index b58800412b..03089e39d4 100644 --- a/discovery/kubernetes/pod.go +++ b/discovery/kubernetes/pod.go @@ -47,7 +47,7 @@ type Pod struct { withNamespaceMetadata bool store cache.Store logger *slog.Logger - queue *workqueue.Type + queue *workqueue.Typed[string] } // NewPod creates a new pod discovery. @@ -68,7 +68,9 @@ func NewPod(l *slog.Logger, pods cache.SharedIndexInformer, nodes, namespace cac withNamespaceMetadata: namespace != nil, store: pods.GetStore(), logger: l, - queue: workqueue.NewNamed(RolePod.String()), + queue: workqueue.NewTypedWithConfig(workqueue.TypedQueueConfig[string]{ + Name: RolePod.String(), + }), } _, err := p.podInf.AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: func(o any) { @@ -166,12 +168,11 @@ func (p *Pod) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { } func (p *Pod) process(ctx context.Context, ch chan<- []*targetgroup.Group) bool { - keyObj, quit := p.queue.Get() + key, quit := p.queue.Get() if quit { return false } - defer p.queue.Done(keyObj) - key := keyObj.(string) + defer p.queue.Done(key) namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { diff --git a/discovery/kubernetes/service.go b/discovery/kubernetes/service.go index a2e00b1032..d676490d6c 100644 --- a/discovery/kubernetes/service.go +++ b/discovery/kubernetes/service.go @@ -36,7 +36,7 @@ type Service struct { logger *slog.Logger informer cache.SharedIndexInformer store cache.Store - queue *workqueue.Type + queue *workqueue.Typed[string] namespaceInf cache.SharedInformer withNamespaceMetadata bool } @@ -52,10 +52,12 @@ func NewService(l *slog.Logger, inf cache.SharedIndexInformer, namespace cache.S svcDeleteCount := eventCount.WithLabelValues(RoleService.String(), MetricLabelRoleDelete) s := &Service{ - logger: l, - informer: inf, - store: inf.GetStore(), - queue: workqueue.NewNamed(RoleService.String()), + logger: l, + informer: inf, + store: inf.GetStore(), + queue: workqueue.NewTypedWithConfig(workqueue.TypedQueueConfig[string]{ + Name: RoleService.String(), + }), namespaceInf: namespace, withNamespaceMetadata: namespace != nil, } @@ -142,12 +144,11 @@ func (s *Service) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { } func (s *Service) process(ctx context.Context, ch chan<- []*targetgroup.Group) bool { - keyObj, quit := s.queue.Get() + key, quit := s.queue.Get() if quit { return false } - defer s.queue.Done(keyObj) - key := keyObj.(string) + defer s.queue.Done(key) namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { diff --git a/discovery/registry.go b/discovery/registry.go index 03eb9e98c4..33938cef3e 100644 --- a/discovery/registry.go +++ b/discovery/registry.go @@ -42,8 +42,8 @@ var ( configTypesMu sync.Mutex configTypes = make(map[reflect.Type]reflect.Type) - emptyStructType = reflect.TypeOf(struct{}{}) - configsType = reflect.TypeOf(Configs{}) + emptyStructType = reflect.TypeFor[struct{}]() + configsType = reflect.TypeFor[Configs]() ) // RegisterConfig registers the given Config type for YAML marshaling and unmarshaling. @@ -54,7 +54,7 @@ func RegisterConfig(config Config) { func init() { // N.B.: static_configs is the only Config type implemented by default. // All other types are registered at init by their implementing packages. - elemTyp := reflect.TypeOf(&targetgroup.Group{}) + elemTyp := reflect.TypeFor[*targetgroup.Group]() registerConfig(staticConfigsKey, elemTyp, StaticConfig{}) } diff --git a/docs/command-line/prometheus.md b/docs/command-line/prometheus.md index e90a7574ba..51f8a887d8 100644 --- a/docs/command-line/prometheus.md +++ b/docs/command-line/prometheus.md @@ -58,7 +58,7 @@ The Prometheus monitoring server | --query.timeout | Maximum time a query may take before being aborted. Use with server mode only. | `2m` | | --query.max-concurrency | Maximum number of queries executed concurrently. Use with server mode only. | `20` | | --query.max-samples | Maximum number of samples a single query can load into memory. Note that queries will fail if they try to load more samples than this into memory, so this also limits the number of samples a query can return. Use with server mode only. | `50000000` | -| --enable-feature ... | Comma separated feature names to enable. Valid options: exemplar-storage, expand-external-labels, memory-snapshot-on-shutdown, promql-per-step-stats, promql-experimental-functions, extra-scrape-metrics, auto-gomaxprocs, native-histograms, created-timestamp-zero-ingestion, concurrent-rule-eval, delayed-compaction, old-ui, otlp-deltatocumulative, promql-duration-expr, use-uncached-io. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details. | | +| --enable-feature ... | Comma separated feature names to enable. Valid options: exemplar-storage, expand-external-labels, memory-snapshot-on-shutdown, promql-per-step-stats, promql-experimental-functions, extra-scrape-metrics, auto-gomaxprocs, native-histograms, created-timestamp-zero-ingestion, concurrent-rule-eval, delayed-compaction, old-ui, otlp-deltatocumulative, promql-duration-expr, use-uncached-io, promql-extended-range-selectors. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details. | | | --agent | Run Prometheus in 'Agent mode'. | | | --log.level | Only log messages with the given severity or above. One of: [debug, info, warn, error] | `info` | | --log.format | Output format of log messages. One of: [logfmt, json] | `logfmt` | diff --git a/docs/feature_flags.md b/docs/feature_flags.md index 4c390ab92e..c209e59fd7 100644 --- a/docs/feature_flags.md +++ b/docs/feature_flags.md @@ -302,3 +302,42 @@ memory in response to misleading cache growth. This is currently implemented using direct I/O. For more details, see the [proposal](https://github.com/prometheus/proposals/pull/45). + +## Extended Range Selectors + +`--enable-feature=promql-extended-range-selectors` + +Enables experimental `anchored` and `smoothed` modifiers for PromQL range and instant selectors. These modifiers provide more control over how range boundaries are handled in functions like `rate` and `increase`, especially with missing or irregular data. + +Native Histograms are not yet supported by the extended range selectors. + +### `anchored` + +Uses the most recent sample (within the lookback delta) at the beginning of the range, or alternatively the first sample within the range if there is no sample within the lookback delta. The last sample within the range is also used at the end of the range. No extrapolation or interpolation is applied, so this is useful to get the direct difference between sample values. + +Anchored range selector work with: `resets`, `changes`, `rate`, `increase`, and `delta`. + +Example query: +`increase(http_requests_total[5m] anchored)` + +**Note**: When using the anchored modifier with the increase function, the results returned are integers. + +### `smoothed` + +In range selectors, linearly interpolates values at the range boundaries, using the sample values before and after the boundaries for an improved estimation that is robust against irregular scrapes and missing samples. However, it requires a sample after the evaluation interval to work properly, see note below. + +For instant selectors, values are linearly interpolated at the evaluation timestamp using the samples immediately before and after that point. + +Smoothed range selectors work with: `rate`, `increase`, and `delta`. + +Example query: +`rate(http_requests_total[step()] smoothed)` + +> **Note for alerting and recording rules:** +> The `smoothed` modifier requires samples after the evaluation interval, so using it directly in alerting or recording rules will typically *under-estimate* the result, as future samples are not available at evaluation time. +> To use `smoothed` safely in rules, you **must** apply a `query_offset` to the rule group (see [documentation](https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/#rule_group)) to ensure the calculation window is fully in the past and all needed samples are available. +> For critical alerting, set the offset to at least one scrape interval; for less critical or more resilient use cases, consider a larger offset (multiple scrape intervals) to tolerate missed scrapes. + +For more details, see the [design doc](https://github.com/prometheus/proposals/blob/main/proposals/2025-04-04_extended-range-selectors-semantics.md). + +**Note**: Extended Range Selectors are not supported for subqueries. \ No newline at end of file diff --git a/docs/getting_started.md b/docs/getting_started.md index aeba295da8..35f1a88a7d 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -79,7 +79,7 @@ navigating to its metrics endpoint: Let us explore data that Prometheus has collected about itself. To use Prometheus's built-in expression browser, navigate to -http://localhost:9090/graph and choose the "Table" view within the "Graph" tab. +http://localhost:9090/query and choose the "Graph" tab. As you can gather from [localhost:9090/metrics](http://localhost:9090/metrics), one metric that Prometheus exports about itself is named @@ -113,7 +113,7 @@ For more about the expression language, see the ## Using the graphing interface -To graph expressions, navigate to http://localhost:9090/graph and use the "Graph" +To graph expressions, navigate to http://localhost:9090/query and use the "Graph" tab. For example, enter the following expression to graph the per-second rate of chunks diff --git a/docs/querying/api.md b/docs/querying/api.md index 2f3c79cef7..67df15d0a7 100644 --- a/docs/querying/api.md +++ b/docs/querying/api.md @@ -348,7 +348,9 @@ You can URL-encode these parameters directly in the request body by using the `P or dynamic number of series selectors that may breach server-side URL character limits. The `data` section of the query result consists of a list of objects that -contain the label name/value pairs which identify each series. +contain the label name/value pairs which identify each series. Note that the +`start` and `end` times are approximate and the result may contain label values +for series which have no samples in the given interval. The following example returns all series that match either of the selectors `up` or `process_start_time_seconds{job="prometheus"}`: @@ -397,8 +399,9 @@ URL query parameters: series from which to read the label names. Optional. - `limit=`: Maximum number of returned series. Optional. 0 means disabled. - -The `data` section of the JSON response is a list of string label names. +The `data` section of the JSON response is a list of string label names. Note +that the `start` and `end` times are approximate and the result may contain +label names for series which have no samples in the given interval. Here is an example. @@ -451,7 +454,10 @@ URL query parameters: series from which to read the label values. Optional. - `limit=`: Maximum number of returned series. Optional. 0 means disabled. -The `data` section of the JSON response is a list of string label values. +The `data` section of the JSON response is a list of string label values. Note +that the `start` and `end` times are approximate and the result may contain +label values for series which have no samples in the given interval. + This example queries for all label values for the `http_status_code` label: diff --git a/documentation/examples/remote_storage/go.mod b/documentation/examples/remote_storage/go.mod index ba57b0808c..781689a60b 100644 --- a/documentation/examples/remote_storage/go.mod +++ b/documentation/examples/remote_storage/go.mod @@ -113,8 +113,8 @@ require ( google.golang.org/protobuf v1.36.8 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apimachinery v0.32.3 // indirect - k8s.io/client-go v0.32.3 // indirect + k8s.io/apimachinery v0.33.5 // indirect + k8s.io/client-go v0.33.5 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/documentation/examples/remote_storage/go.sum b/documentation/examples/remote_storage/go.sum index b39bcf6ab5..e601aefaae 100644 --- a/documentation/examples/remote_storage/go.sum +++ b/documentation/examples/remote_storage/go.sum @@ -140,16 +140,14 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= +github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -160,8 +158,8 @@ github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3 github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= github.com/gophercloud/gophercloud/v2 v2.7.0 h1:o0m4kgVcPgHlcXiWAjoVxGd8QCmvM5VU+YM71pFbn0E= github.com/gophercloud/gophercloud/v2 v2.7.0/go.mod h1:Ki/ILhYZr/5EPebrPL9Ej+tUg4lqx71/YH2JWVeU+Qk= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= github.com/hashicorp/consul/api v1.32.0 h1:5wp5u780Gri7c4OedGEPzmlUEzi0g2KyiPphSr6zjVg= @@ -471,21 +469,23 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls= -k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k= -k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= -k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU= -k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY= +k8s.io/api v0.33.5 h1:YR+uhYj05jdRpcksv8kjSliW+v9hwXxn6Cv10aR8Juw= +k8s.io/api v0.33.5/go.mod h1:2gzShdwXKT5yPGiqrTrn/U/nLZ7ZyT4WuAj3XGDVgVs= +k8s.io/apimachinery v0.33.5 h1:NiT64hln4TQXeYR18/ES39OrNsjGz8NguxsBgp+6QIo= +k8s.io/apimachinery v0.33.5/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= +k8s.io/client-go v0.33.5 h1:I8BdmQGxInpkMEnJvV6iG7dqzP3JRlpZZlib3OMFc3o= +k8s.io/client-go v0.33.5/go.mod h1:W8PQP4MxbM4ypgagVE65mUUqK1/ByQkSALF9tzuQ6u0= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= -sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= -sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/go.mod b/go.mod index 3dea33d837..b98cef5265 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/envoyproxy/go-control-plane/envoy v1.32.4 github.com/envoyproxy/protoc-gen-validate v1.2.1 github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb - github.com/fsnotify/fsnotify v1.8.0 + github.com/fsnotify/fsnotify v1.9.0 github.com/go-openapi/strfmt v0.23.0 github.com/go-zookeeper/zk v1.0.4 github.com/gogo/protobuf v1.3.2 @@ -93,36 +93,13 @@ require ( google.golang.org/grpc v1.73.0 google.golang.org/protobuf v1.36.8 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.32.3 - k8s.io/apimachinery v0.32.3 - k8s.io/client-go v0.32.3 + k8s.io/api v0.33.5 + k8s.io/apimachinery v0.33.5 + k8s.io/client-go v0.33.5 k8s.io/klog v1.0.0 k8s.io/klog/v2 v2.130.1 ) -require ( - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.0 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.0 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect - github.com/cenkalti/backoff/v5 v5.0.2 // indirect - github.com/containerd/errdefs v1.0.0 // indirect - github.com/containerd/errdefs/pkg v0.3.0 // indirect - github.com/gobwas/glob v0.2.3 // indirect - github.com/hashicorp/go-version v1.7.0 // indirect - github.com/moby/sys/atomicwriter v0.1.0 // indirect - github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect - go.opentelemetry.io/collector/featuregate v1.35.0 // indirect - go.opentelemetry.io/collector/internal/telemetry v0.129.0 // indirect - go.opentelemetry.io/contrib/bridges/otelzap v0.11.0 // indirect - go.opentelemetry.io/otel/log v0.12.2 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect -) - require ( cloud.google.com/go/auth v0.16.2 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect @@ -132,8 +109,19 @@ require ( github.com/Microsoft/go-winio v0.6.1 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v5 v5.0.2 // indirect github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f // indirect + github.com/containerd/errdefs v1.0.0 // indirect + github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -156,15 +144,14 @@ require ( github.com/go-openapi/validate v0.24.0 // indirect github.com/go-resty/resty/v2 v2.16.5 // indirect github.com/go-viper/mapstructure/v2 v2.3.0 // indirect + github.com/gobwas/glob v0.2.3 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/gnostic-models v0.6.9 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect github.com/googleapis/gax-go/v2 v2.14.2 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect github.com/hashicorp/cronexpr v1.1.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -174,6 +161,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/golang-lru v0.6.0 // indirect github.com/hashicorp/serf v0.10.1 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -193,6 +181,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/sys/atomicwriter v0.1.0 // indirect github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -209,6 +198,7 @@ require ( github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/otlptranslator v0.0.2 github.com/prometheus/procfs v0.16.1 // indirect + github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/x448/float16 v0.8.4 // indirect @@ -217,7 +207,11 @@ require ( go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/collector/confmap v1.35.0 // indirect go.opentelemetry.io/collector/confmap/xconfmap v0.129.0 // indirect + go.opentelemetry.io/collector/featuregate v1.35.0 // indirect + go.opentelemetry.io/collector/internal/telemetry v0.129.0 // indirect go.opentelemetry.io/collector/pipeline v0.129.0 // indirect + go.opentelemetry.io/contrib/bridges/otelzap v0.11.0 // indirect + go.opentelemetry.io/otel/log v0.12.2 // indirect go.opentelemetry.io/proto/otlp v1.6.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.41.0 // indirect @@ -231,11 +225,13 @@ require ( gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gotest.tools/v3 v3.0.3 // indirect - k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect + k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) @@ -247,6 +243,3 @@ exclude ( github.com/grpc-ecosystem/grpc-gateway v1.14.7 google.golang.org/api v0.30.0 ) - -// Pin until https://github.com/fsnotify/fsnotify/issues/656 is resolved. -replace github.com/fsnotify/fsnotify v1.8.0 => github.com/fsnotify/fsnotify v1.7.0 diff --git a/go.sum b/go.sum index 6b3cbd5aa7..b21b472ef0 100644 --- a/go.sum +++ b/go.sum @@ -141,8 +141,8 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -198,10 +198,10 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6 github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= +github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -212,8 +212,6 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a h1://KbezygeMJZCSHH+HgUZiTeSoiuFspbMg1ge+eFj18= github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= @@ -226,8 +224,8 @@ github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3 github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= github.com/gophercloud/gophercloud/v2 v2.7.0 h1:o0m4kgVcPgHlcXiWAjoVxGd8QCmvM5VU+YM71pFbn0E= github.com/gophercloud/gophercloud/v2 v2.7.0/go.mod h1:Ki/ILhYZr/5EPebrPL9Ej+tUg4lqx71/YH2JWVeU+Qk= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= @@ -716,23 +714,26 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= -k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls= -k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k= -k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= -k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU= -k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY= +k8s.io/api v0.33.5 h1:YR+uhYj05jdRpcksv8kjSliW+v9hwXxn6Cv10aR8Juw= +k8s.io/api v0.33.5/go.mod h1:2gzShdwXKT5yPGiqrTrn/U/nLZ7ZyT4WuAj3XGDVgVs= +k8s.io/apimachinery v0.33.5 h1:NiT64hln4TQXeYR18/ES39OrNsjGz8NguxsBgp+6QIo= +k8s.io/apimachinery v0.33.5/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= +k8s.io/client-go v0.33.5 h1:I8BdmQGxInpkMEnJvV6iG7dqzP3JRlpZZlib3OMFc3o= +k8s.io/client-go v0.33.5/go.mod h1:W8PQP4MxbM4ypgagVE65mUUqK1/ByQkSALF9tzuQ6u0= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= -sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= -sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= +sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/model/histogram/float_histogram.go b/model/histogram/float_histogram.go index 2b78c6d630..c8c30ec2c8 100644 --- a/model/histogram/float_histogram.go +++ b/model/histogram/float_histogram.go @@ -798,23 +798,24 @@ func (h *FloatHistogram) AllReverseBucketIterator() BucketIterator[float64] { // create false positives here. func (h *FloatHistogram) Validate() error { var nCount, pCount float64 - if h.UsesCustomBuckets() { + switch { + case IsCustomBucketsSchema(h.Schema): if err := checkHistogramCustomBounds(h.CustomValues, h.PositiveSpans, len(h.PositiveBuckets)); err != nil { return fmt.Errorf("custom buckets: %w", err) } if h.ZeroCount != 0 { - return errors.New("custom buckets: must have zero count of 0") + return ErrHistogramCustomBucketsZeroCount } if h.ZeroThreshold != 0 { - return errors.New("custom buckets: must have zero threshold of 0") + return ErrHistogramCustomBucketsZeroThresh } if len(h.NegativeSpans) > 0 { - return errors.New("custom buckets: must not have negative spans") + return ErrHistogramCustomBucketsNegSpans } if len(h.NegativeBuckets) > 0 { - return errors.New("custom buckets: must not have negative buckets") + return ErrHistogramCustomBucketsNegBuckets } - } else { + case IsExponentialSchema(h.Schema): if err := checkHistogramSpans(h.PositiveSpans, len(h.PositiveBuckets)); err != nil { return fmt.Errorf("positive side: %w", err) } @@ -826,8 +827,10 @@ func (h *FloatHistogram) Validate() error { return fmt.Errorf("negative side: %w", err) } if h.CustomValues != nil { - return errors.New("histogram with exponential schema must not have custom bounds") + return ErrHistogramExpSchemaCustomBounds } + default: + return InvalidSchemaError(h.Schema) } err := checkHistogramBuckets(h.PositiveBuckets, &pCount, false) if err != nil { diff --git a/model/histogram/generic.go b/model/histogram/generic.go index 90a94a5600..bc4c69d40c 100644 --- a/model/histogram/generic.go +++ b/model/histogram/generic.go @@ -21,24 +21,41 @@ import ( ) const ( - ExponentialSchemaMax int32 = 8 - ExponentialSchemaMin int32 = -4 - CustomBucketsSchema int32 = -53 + ExponentialSchemaMax int32 = 8 + ExponentialSchemaMaxReserved int32 = 52 + ExponentialSchemaMin int32 = -4 + ExponentialSchemaMinReserved int32 = -9 + CustomBucketsSchema int32 = -53 ) var ( - ErrHistogramCountNotBigEnough = errors.New("histogram's observation count should be at least the number of observations found in the buckets") - ErrHistogramCountMismatch = errors.New("histogram's observation count should equal the number of observations found in the buckets (in absence of NaN)") - ErrHistogramNegativeBucketCount = errors.New("histogram has a bucket whose observation count is negative") - ErrHistogramSpanNegativeOffset = errors.New("histogram has a span whose offset is negative") - ErrHistogramSpansBucketsMismatch = errors.New("histogram spans specify different number of buckets than provided") - ErrHistogramCustomBucketsMismatch = errors.New("histogram custom bounds are too few") - ErrHistogramCustomBucketsInvalid = errors.New("histogram custom bounds must be in strictly increasing order") - ErrHistogramCustomBucketsInfinite = errors.New("histogram custom bounds must be finite") - ErrHistogramsIncompatibleSchema = errors.New("cannot apply this operation on histograms with a mix of exponential and custom bucket schemas") - ErrHistogramsIncompatibleBounds = errors.New("cannot apply this operation on custom buckets histograms with different custom bounds") + ErrHistogramCountNotBigEnough = errors.New("histogram's observation count should be at least the number of observations found in the buckets") + ErrHistogramCountMismatch = errors.New("histogram's observation count should equal the number of observations found in the buckets (in absence of NaN)") + ErrHistogramNegativeBucketCount = errors.New("histogram has a bucket whose observation count is negative") + ErrHistogramSpanNegativeOffset = errors.New("histogram has a span whose offset is negative") + ErrHistogramSpansBucketsMismatch = errors.New("histogram spans specify different number of buckets than provided") + ErrHistogramCustomBucketsMismatch = errors.New("histogram custom bounds are too few") + ErrHistogramCustomBucketsInvalid = errors.New("histogram custom bounds must be in strictly increasing order") + ErrHistogramCustomBucketsInfinite = errors.New("histogram custom bounds must be finite") + ErrHistogramsIncompatibleSchema = errors.New("cannot apply this operation on histograms with a mix of exponential and custom bucket schemas") + ErrHistogramsIncompatibleBounds = errors.New("cannot apply this operation on custom buckets histograms with different custom bounds") + ErrHistogramCustomBucketsZeroCount = errors.New("custom buckets: must have zero count of 0") + ErrHistogramCustomBucketsZeroThresh = errors.New("custom buckets: must have zero threshold of 0") + ErrHistogramCustomBucketsNegSpans = errors.New("custom buckets: must not have negative spans") + ErrHistogramCustomBucketsNegBuckets = errors.New("custom buckets: must not have negative buckets") + ErrHistogramExpSchemaCustomBounds = errors.New("histogram with exponential schema must not have custom bounds") + ErrHistogramsInvalidSchema = fmt.Errorf("histogram has an invalid schema, which must be between %d and %d for exponential buckets, or %d for custom buckets", ExponentialSchemaMin, ExponentialSchemaMax, CustomBucketsSchema) + ErrHistogramsUnknownSchema = fmt.Errorf("histogram has an unknown schema, which must be between %d and %d for exponential buckets, or %d for custom buckets", ExponentialSchemaMinReserved, ExponentialSchemaMaxReserved, CustomBucketsSchema) ) +func InvalidSchemaError(s int32) error { + return fmt.Errorf("%w, got schema %d", ErrHistogramsInvalidSchema, s) +} + +func UnknownSchemaError(s int32) error { + return fmt.Errorf("%w, got schema %d", ErrHistogramsUnknownSchema, s) +} + func IsCustomBucketsSchema(s int32) bool { return s == CustomBucketsSchema } @@ -47,6 +64,20 @@ func IsExponentialSchema(s int32) bool { return s >= ExponentialSchemaMin && s <= ExponentialSchemaMax } +func IsExponentialSchemaReserved(s int32) bool { + return s >= ExponentialSchemaMinReserved && s <= ExponentialSchemaMaxReserved +} + +func IsValidSchema(s int32) bool { + return IsCustomBucketsSchema(s) || IsExponentialSchema(s) +} + +// IsKnownSchema returns bool if we known and accept the schema, but need to +// reduce resolution to the nearest supported schema. +func IsKnownSchema(s int32) bool { + return IsCustomBucketsSchema(s) || IsExponentialSchemaReserved(s) +} + // BucketCount is a type constraint for the count in a bucket, which can be // float64 (for type FloatHistogram) or uint64 (for type Histogram). type BucketCount interface { diff --git a/model/histogram/histogram.go b/model/histogram/histogram.go index cfb63e6341..35c9797155 100644 --- a/model/histogram/histogram.go +++ b/model/histogram/histogram.go @@ -14,7 +14,6 @@ package histogram import ( - "errors" "fmt" "math" "slices" @@ -425,23 +424,24 @@ func resize[T any](items []T, n int) []T { // the total h.Count). func (h *Histogram) Validate() error { var nCount, pCount uint64 - if h.UsesCustomBuckets() { + switch { + case IsCustomBucketsSchema(h.Schema): if err := checkHistogramCustomBounds(h.CustomValues, h.PositiveSpans, len(h.PositiveBuckets)); err != nil { return fmt.Errorf("custom buckets: %w", err) } if h.ZeroCount != 0 { - return errors.New("custom buckets: must have zero count of 0") + return ErrHistogramCustomBucketsZeroCount } if h.ZeroThreshold != 0 { - return errors.New("custom buckets: must have zero threshold of 0") + return ErrHistogramCustomBucketsZeroThresh } if len(h.NegativeSpans) > 0 { - return errors.New("custom buckets: must not have negative spans") + return ErrHistogramCustomBucketsNegSpans } if len(h.NegativeBuckets) > 0 { - return errors.New("custom buckets: must not have negative buckets") + return ErrHistogramCustomBucketsNegBuckets } - } else { + case IsExponentialSchema(h.Schema): if err := checkHistogramSpans(h.PositiveSpans, len(h.PositiveBuckets)); err != nil { return fmt.Errorf("positive side: %w", err) } @@ -453,8 +453,10 @@ func (h *Histogram) Validate() error { return fmt.Errorf("negative side: %w", err) } if h.CustomValues != nil { - return errors.New("histogram with exponential schema must not have custom bounds") + return ErrHistogramExpSchemaCustomBounds } + default: + return InvalidSchemaError(h.Schema) } err := checkHistogramBuckets(h.PositiveBuckets, &pCount, true) if err != nil { diff --git a/model/histogram/histogram_test.go b/model/histogram/histogram_test.go index edc8663c94..52a3392154 100644 --- a/model/histogram/histogram_test.go +++ b/model/histogram/histogram_test.go @@ -1565,6 +1565,18 @@ func TestHistogramValidation(t *testing.T) { CustomValues: []float64{1, 2, 3, 4, 5, 6, 7, 8}, }, }, + "schema too high": { + h: &Histogram{ + Schema: 10, + }, + errMsg: `histogram has an invalid schema, which must be between -4 and 8 for exponential buckets, or -53 for custom buckets, got schema 10`, + }, + "schema too low": { + h: &Histogram{ + Schema: -10, + }, + errMsg: `histogram has an invalid schema, which must be between -4 and 8 for exponential buckets, or -53 for custom buckets, got schema -10`, + }, } for testName, tc := range tests { diff --git a/promql/bench_test.go b/promql/bench_test.go index 92831de346..661faa6556 100644 --- a/promql/bench_test.go +++ b/promql/bench_test.go @@ -117,6 +117,18 @@ func rangeQueryCases() []benchCase { expr: "rate(sparse[1m])", steps: 10000, }, + // Smoothed rate. + { + expr: "rate(a_X[1m] smoothed)", + }, + { + expr: "rate(a_X[1m] smoothed)", + steps: 10000, + }, + { + expr: "rate(sparse[1m] smoothed)", + steps: 10000, + }, // Holt-Winters and long ranges. { expr: "double_exponential_smoothing(a_X[1d], 0.3, 0.3)", @@ -266,6 +278,10 @@ func rangeQueryCases() []benchCase { } func BenchmarkRangeQuery(b *testing.B) { + parser.EnableExtendedRangeSelectors = true + b.Cleanup(func() { + parser.EnableExtendedRangeSelectors = false + }) stor := teststorage.New(b) stor.DisableCompactions() // Don't want auto-compaction disrupting timings. defer stor.Close() diff --git a/promql/engine.go b/promql/engine.go index edafe4fd43..31d910da9a 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -21,6 +21,7 @@ import ( "fmt" "io" "log/slog" + "maps" "math" "reflect" "runtime" @@ -124,6 +125,8 @@ var _ QueryLogger = (*logging.JSONFileLogger)(nil) // QueryLogger is an interface that can be used to log all the queries logged // by the engine. +// logging.JSONFileLogger implements this interface, downstream users may use +// different implementations. type QueryLogger interface { slog.Handler io.Closer @@ -926,13 +929,27 @@ func getTimeRangesForSelector(s *parser.EvalStmt, n *parser.VectorSelector, path // because wo want to exclude samples that are precisely the // lookback delta before the eval time. start -= durationMilliseconds(s.LookbackDelta) - 1 + if n.Smoothed { + end += durationMilliseconds(s.LookbackDelta) + } } else { - // For all matrix queries we want to ensure that we have - // (end-start) + range selected this way we have `range` data - // before the start time. We subtract one from the range to - // exclude samples positioned directly at the lower boundary of - // the range. - start -= durationMilliseconds(evalRange) - 1 + // For matrix queries, adjust the start and end times to ensure the + // correct range of data is selected. For "anchored" selectors, extend + // the start time backwards by the lookback delta plus the evaluation + // range. For "smoothed" selectors, extend both the start and end times + // by the lookback delta, and also extend the start time by the + // evaluation range to cover the smoothing window. For standard range + // queries, extend the start time backwards by the range (minus one + // millisecond) to exclude samples exactly at the lower boundary. + switch { + case n.Anchored: + start -= durationMilliseconds(s.LookbackDelta+evalRange) - 1 + case n.Smoothed: + start -= durationMilliseconds(s.LookbackDelta+evalRange) - 1 + end += durationMilliseconds(s.LookbackDelta) + default: + start -= durationMilliseconds(evalRange) - 1 + } } offsetMilliseconds := durationMilliseconds(n.OriginalOffset) @@ -979,7 +996,6 @@ func (ng *Engine) populateSeries(ctx context.Context, querier storage.Querier, s evalRange = 0 hints.By, hints.Grouping = extractGroupsFromPath(path) n.UnexpandedSeriesSet = querier.Select(ctx, false, hints, n.LabelMatchers...) - case *parser.MatrixSelector: evalRange = n.Range } @@ -1524,6 +1540,76 @@ func (ev *evaluator) rangeEvalAgg(ctx context.Context, aggExpr *parser.Aggregate return result, annos } +// smoothSeries is a helper function that smooths the series by interpolating the values +// based on values before and after the timestamp. +func (ev *evaluator) smoothSeries(series []storage.Series, offset time.Duration) Matrix { + dur := ev.endTimestamp - ev.startTimestamp + + it := storage.NewBuffer(dur + 2*durationMilliseconds(ev.lookbackDelta)) + + offMS := offset.Milliseconds() + start := ev.startTimestamp - offMS + end := ev.endTimestamp - offMS + step := ev.interval + lb := durationMilliseconds(ev.lookbackDelta) + + var chkIter chunkenc.Iterator + mat := make(Matrix, 0, len(series)) + + for _, s := range series { + ss := Series{Metric: s.Labels()} + + chkIter = s.Iterator(chkIter) + it.Reset(chkIter) + + var floats []FPoint + var hists []HPoint + + for ts := start; ts <= end; ts += step { + matrixStart := ts - lb + matrixEnd := ts + lb + + floats, hists = ev.matrixIterSlice(it, matrixStart, matrixEnd, floats, hists) + if len(floats) == 0 && len(hists) == 0 { + continue + } + + if len(hists) > 0 { + // TODO: support native histograms. + ev.errorf("smoothed and anchored modifiers do not work with native histograms") + } + + // Binary search for the first index with T >= ts. + i := sort.Search(len(floats), func(i int) bool { return floats[i].T >= ts }) + + switch { + case i < len(floats) && floats[i].T == ts: + // Exact match. + ss.Floats = append(ss.Floats, floats[i]) + + case i > 0 && i < len(floats): + // Interpolate between prev and next. + // TODO: detect if the sample is a counter, based on __type__ or metadata. + prev, next := floats[i-1], floats[i] + val := interpolate(prev, next, ts, false, false) + ss.Floats = append(ss.Floats, FPoint{F: val, T: ts}) + + case i > 0: + // No next point yet; carry forward previous value. + prev := floats[i-1] + ss.Floats = append(ss.Floats, FPoint{F: prev.F, T: ts}) + + default: + // i == 0 and floats[0].T > ts: there is no previous data yet; skip. + } + } + + mat = append(mat, ss) + } + + return mat +} + // evalSeries generates a Matrix between ev.startTimestamp and ev.endTimestamp (inclusive), each point spaced ev.interval apart, from series given offset. // For every storage.Series iterator in series, the method iterates in ev.interval sized steps from ev.startTimestamp until and including ev.endTimestamp, // collecting every corresponding sample (obtained via ev.vectorSelectorSingle) into a Series. @@ -1784,6 +1870,17 @@ func (ev *evaluator) eval(ctx context.Context, expr parser.Expr) (parser.Value, sel := arg.(*parser.MatrixSelector) selVS := sel.VectorSelector.(*parser.VectorSelector) + switch { + case selVS.Anchored: + if _, ok := AnchoredSafeFunctions[e.Func.Name]; !ok { + ev.errorf("anchored modifier can only be used with: %s - not with %s", strings.Join(slices.Sorted(maps.Keys(AnchoredSafeFunctions)), ", "), e.Func.Name) + } + case selVS.Smoothed: + if _, ok := SmoothedSafeFunctions[e.Func.Name]; !ok { + ev.errorf("smoothed modifier can only be used with: %s - not with %s", strings.Join(slices.Sorted(maps.Keys(SmoothedSafeFunctions)), ", "), e.Func.Name) + } + } + ws, err := checkAndExpandSeriesSet(ctx, sel) warnings.Merge(ws) if err != nil { @@ -1792,7 +1889,17 @@ func (ev *evaluator) eval(ctx context.Context, expr parser.Expr) (parser.Value, mat := make(Matrix, 0, len(selVS.Series)) // Output matrix. offset := durationMilliseconds(selVS.Offset) selRange := durationMilliseconds(sel.Range) - stepRange := min(selRange, ev.interval) + + var stepRange int64 + switch { + case selVS.Anchored: + stepRange = min(selRange+durationMilliseconds(ev.lookbackDelta), ev.interval) + case selVS.Smoothed: + stepRange = min(selRange+durationMilliseconds(2*ev.lookbackDelta), ev.interval) + default: + stepRange = min(selRange, ev.interval) + } + // Reuse objects across steps to save memory allocations. var floats []FPoint var histograms []HPoint @@ -1800,7 +1907,18 @@ func (ev *evaluator) eval(ctx context.Context, expr parser.Expr) (parser.Value, inMatrix := make(Matrix, 1) enh := &EvalNodeHelper{Out: make(Vector, 0, 1), enableDelayedNameRemoval: ev.enableDelayedNameRemoval} // Process all the calls for one time series at a time. - it := storage.NewBuffer(selRange) + // For anchored and smoothed selectors, we need to iterate over a + // larger range than the query range to account for the lookback delta. + // For standard range queries, we iterate over the query range. + bufferRange := selRange + switch { + case selVS.Anchored: + bufferRange += durationMilliseconds(ev.lookbackDelta) + case selVS.Smoothed: + bufferRange += durationMilliseconds(2 * ev.lookbackDelta) + } + + it := storage.NewBuffer(bufferRange) var chkIter chunkenc.Iterator // The last_over_time and first_over_time functions act like @@ -1849,11 +1967,24 @@ func (ev *evaluator) eval(ctx context.Context, expr parser.Expr) (parser.Value, if ts == ev.startTimestamp || selVS.Timestamp == nil { maxt := ts - offset mint := maxt - selRange + switch { + case selVS.Anchored: + mint -= durationMilliseconds(ev.lookbackDelta) + case selVS.Smoothed: + mint -= durationMilliseconds(ev.lookbackDelta) + maxt += durationMilliseconds(ev.lookbackDelta) + } floats, histograms = ev.matrixIterSlice(it, mint, maxt, floats, histograms) } if len(floats)+len(histograms) == 0 { continue } + if selVS.Anchored || selVS.Smoothed { + if len(histograms) > 0 { + // TODO: support native histograms. + ev.errorf("smoothed and anchored modifiers do not work with native histograms") + } + } inMatrix[0].Floats = floats inMatrix[0].Histograms = histograms enh.Ts = ts @@ -2052,6 +2183,10 @@ func (ev *evaluator) eval(ctx context.Context, expr parser.Expr) (parser.Value, if err != nil { ev.error(errWithWarnings{fmt.Errorf("expanding series: %w", err), ws}) } + if e.Smoothed { + mat := ev.smoothSeries(e.Series, e.Offset) + return mat, ws + } mat := ev.evalSeries(ctx, e.Series, e.Offset, false) return mat, ws @@ -2348,10 +2483,23 @@ func (ev *evaluator) matrixSelector(ctx context.Context, node *parser.MatrixSele offset = durationMilliseconds(vs.Offset) maxt = ev.startTimestamp - offset mint = maxt - durationMilliseconds(node.Range) - matrix = make(Matrix, 0, len(vs.Series)) - - it = storage.NewBuffer(durationMilliseconds(node.Range)) + // matrixMint keeps the original mint for smoothed and anchored selectors. + matrixMint = mint + // matrixMaxt keeps the original maxt for smoothed and anchored selectors. + matrixMaxt = maxt + matrix = make(Matrix, 0, len(vs.Series)) + bufferRange = durationMilliseconds(node.Range) ) + switch { + case vs.Anchored: + bufferRange += durationMilliseconds(ev.lookbackDelta) + mint -= durationMilliseconds(ev.lookbackDelta) + case vs.Smoothed: + bufferRange += 2 * durationMilliseconds(ev.lookbackDelta) + mint -= durationMilliseconds(ev.lookbackDelta) + maxt += durationMilliseconds(ev.lookbackDelta) + } + it := storage.NewBuffer(bufferRange) ws, err := checkAndExpandSeriesSet(ctx, node) if err != nil { ev.error(errWithWarnings{fmt.Errorf("expanding series: %w", err), ws}) @@ -2370,6 +2518,18 @@ func (ev *evaluator) matrixSelector(ctx context.Context, node *parser.MatrixSele } ss.Floats, ss.Histograms = ev.matrixIterSlice(it, mint, maxt, nil, nil) + switch { + case vs.Anchored: + if ss.Histograms != nil { + ev.errorf("anchored modifier is not supported with histograms") + } + ss.Floats = extendFloats(ss.Floats, matrixMint, matrixMaxt, false) + case vs.Smoothed: + if ss.Histograms != nil { + ev.errorf("anchored modifier is not supported with histograms") + } + ss.Floats = extendFloats(ss.Floats, matrixMint, matrixMaxt, true) + } totalSize := int64(len(ss.Floats)) + int64(totalHPointSize(ss.Histograms)) ev.samplesStats.IncrementSamplesAtTimestamp(ev.startTimestamp, totalSize) @@ -4035,3 +4195,39 @@ func (ev *evaluator) gatherVector(ts int64, input Matrix, output Vector, bufHelp return output, bufHelpers } + +// extendFloats extends the floats to the given mint and maxt. +// This function is used with matrix selectors that are smoothed or anchored. +func extendFloats(floats []FPoint, mint, maxt int64, smoothed bool) []FPoint { + lastSampleIndex := len(floats) - 1 + + firstSampleIndex := max(0, sort.Search(lastSampleIndex, func(i int) bool { return floats[i].T > mint })-1) + if smoothed { + lastSampleIndex = sort.Search(lastSampleIndex, func(i int) bool { return floats[i].T >= maxt }) + } + + if floats[lastSampleIndex].T <= mint { + return []FPoint{} + } + + // TODO: detect if the sample is a counter, based on __type__ or metadata. + left := pickOrInterpolateLeft(floats, firstSampleIndex, mint, smoothed, false) + right := pickOrInterpolateRight(floats, lastSampleIndex, maxt, smoothed, false) + + // Filter out samples at boundaries or outside the range. + if floats[firstSampleIndex].T <= mint { + firstSampleIndex++ + } + if floats[lastSampleIndex].T >= maxt { + lastSampleIndex-- + } + + // TODO: Preallocate the length of the new list. + out := make([]FPoint, 0) + // Create the new floats list with the boundary samples and the inner samples. + out = append(out, FPoint{T: mint, F: left}) + out = append(out, floats[firstSampleIndex:lastSampleIndex+1]...) + out = append(out, FPoint{T: maxt, F: right}) + + return out +} diff --git a/promql/engine_test.go b/promql/engine_test.go index f70036e3c0..9735d72794 100644 --- a/promql/engine_test.go +++ b/promql/engine_test.go @@ -1513,6 +1513,160 @@ load 10s } } +func TestExtendedRangeSelectors(t *testing.T) { + parser.EnableExtendedRangeSelectors = true + t.Cleanup(func() { + parser.EnableExtendedRangeSelectors = false + }) + + engine := newTestEngine(t) + storage := promqltest.LoadedStorage(t, ` + load 10s + metric 1+1x10 + withreset 1+1x4 1+1x5 + notregular 0 5 100 2 8 + `) + t.Cleanup(func() { storage.Close() }) + + tc := []struct { + query string + t time.Time + expected promql.Matrix + }{ + { + query: "metric[10s] smoothed", + t: time.Unix(10, 0), + expected: promql.Matrix{ + promql.Series{ + Floats: []promql.FPoint{{F: 1, T: 0}, {F: 2, T: 10000}}, + Metric: labels.FromStrings("__name__", "metric"), + }, + }, + }, + { + query: "metric[10s] smoothed", + t: time.Unix(15, 0), + expected: promql.Matrix{ + promql.Series{ + Floats: []promql.FPoint{{F: 1.5, T: 5000}, {F: 2, T: 10000}, {F: 2.5, T: 15000}}, + Metric: labels.FromStrings("__name__", "metric"), + }, + }, + }, + { + query: "metric[10s] smoothed", + t: time.Unix(5, 0), + expected: promql.Matrix{ + promql.Series{ + Floats: []promql.FPoint{{F: 1, T: -5000}, {F: 1, T: 0}, {F: 1.5, T: 5000}}, + Metric: labels.FromStrings("__name__", "metric"), + }, + }, + }, + { + query: "metric[10s] smoothed", + t: time.Unix(105, 0), + expected: promql.Matrix{ + promql.Series{ + Floats: []promql.FPoint{{F: 10.5, T: 95000}, {F: 11, T: 100000}, {F: 11, T: 105000}}, + Metric: labels.FromStrings("__name__", "metric"), + }, + }, + }, + { + query: "withreset[10s] smoothed", + t: time.Unix(45, 0), + expected: promql.Matrix{ + promql.Series{ + Floats: []promql.FPoint{{F: 4.5, T: 35000}, {F: 5, T: 40000}, {F: 3, T: 45000}}, + Metric: labels.FromStrings("__name__", "withreset"), + }, + }, + }, + { + query: "metric[10s] anchored", + t: time.Unix(10, 0), + expected: promql.Matrix{ + promql.Series{ + Floats: []promql.FPoint{{F: 1, T: 0}, {F: 2, T: 10000}}, + Metric: labels.FromStrings("__name__", "metric"), + }, + }, + }, + { + query: "metric[10s] anchored", + t: time.Unix(15, 0), + expected: promql.Matrix{ + promql.Series{ + Floats: []promql.FPoint{{F: 1, T: 5000}, {F: 2, T: 10000}, {F: 2, T: 15000}}, + Metric: labels.FromStrings("__name__", "metric"), + }, + }, + }, + { + query: "metric[10s] anchored", + t: time.Unix(5, 0), + expected: promql.Matrix{ + promql.Series{ + Floats: []promql.FPoint{{F: 1, T: -5000}, {F: 1, T: 0}, {F: 1, T: 5000}}, + Metric: labels.FromStrings("__name__", "metric"), + }, + }, + }, + { + query: "metric[10s] anchored", + t: time.Unix(105, 0), + expected: promql.Matrix{ + promql.Series{ + Floats: []promql.FPoint{{F: 10, T: 95000}, {F: 11, T: 100000}, {F: 11, T: 105000}}, + Metric: labels.FromStrings("__name__", "metric"), + }, + }, + }, + { + query: "withreset[10s] anchored", + t: time.Unix(45, 0), + expected: promql.Matrix{ + promql.Series{ + Floats: []promql.FPoint{{F: 4, T: 35000}, {F: 5, T: 40000}, {F: 5, T: 45000}}, + Metric: labels.FromStrings("__name__", "withreset"), + }, + }, + }, + { + query: "notregular[20s] smoothed", + t: time.Unix(30, 0), + expected: promql.Matrix{ + promql.Series{ + Floats: []promql.FPoint{{F: 5, T: 10000}, {F: 100, T: 20000}, {F: 2, T: 30000}}, + Metric: labels.FromStrings("__name__", "notregular"), + }, + }, + }, + { + query: "notregular[20s] anchored", + t: time.Unix(30, 0), + expected: promql.Matrix{ + promql.Series{ + Floats: []promql.FPoint{{F: 5, T: 10000}, {F: 100, T: 20000}, {F: 2, T: 30000}}, + Metric: labels.FromStrings("__name__", "notregular"), + }, + }, + }, + } + + for _, tc := range tc { + t.Run(tc.query, func(t *testing.T) { + engine = promqltest.NewTestEngine(t, false, 0, 100) + qry, err := engine.NewInstantQuery(context.Background(), storage, nil, tc.query, tc.t) + require.NoError(t, err) + res := qry.Exec(context.Background()) + require.NoError(t, res.Err) + require.Equal(t, tc.expected, res.Value) + }) + } +} + func TestAtModifier(t *testing.T) { engine := newTestEngine(t) storage := promqltest.LoadedStorage(t, ` @@ -3195,89 +3349,6 @@ func TestEngine_Close(t *testing.T) { }) } -func TestInstantQueryWithRangeVectorSelector(t *testing.T) { - engine := newTestEngine(t) - - baseT := timestamp.Time(0) - storage := promqltest.LoadedStorage(t, ` - load 1m - some_metric{env="1"} 0+1x4 - some_metric{env="2"} 0+2x4 - some_metric{env="3"} {{count:0}}+{{count:1}}x4 - some_metric_with_stale_marker 0 1 stale 3 - `) - t.Cleanup(func() { require.NoError(t, storage.Close()) }) - - testCases := map[string]struct { - expr string - expected promql.Matrix - ts time.Time - }{ - "matches series with points in range": { - expr: "some_metric[2m]", - ts: baseT.Add(2 * time.Minute), - expected: promql.Matrix{ - { - Metric: labels.FromStrings("__name__", "some_metric", "env", "1"), - Floats: []promql.FPoint{ - {T: timestamp.FromTime(baseT.Add(time.Minute)), F: 1}, - {T: timestamp.FromTime(baseT.Add(2 * time.Minute)), F: 2}, - }, - }, - { - Metric: labels.FromStrings("__name__", "some_metric", "env", "2"), - Floats: []promql.FPoint{ - {T: timestamp.FromTime(baseT.Add(time.Minute)), F: 2}, - {T: timestamp.FromTime(baseT.Add(2 * time.Minute)), F: 4}, - }, - }, - { - Metric: labels.FromStrings("__name__", "some_metric", "env", "3"), - Histograms: []promql.HPoint{ - {T: timestamp.FromTime(baseT.Add(time.Minute)), H: &histogram.FloatHistogram{Count: 1, CounterResetHint: histogram.NotCounterReset}}, - {T: timestamp.FromTime(baseT.Add(2 * time.Minute)), H: &histogram.FloatHistogram{Count: 2, CounterResetHint: histogram.NotCounterReset}}, - }, - }, - }, - }, - "matches no series": { - expr: "some_nonexistent_metric[1m]", - ts: baseT, - expected: promql.Matrix{}, - }, - "no samples in range": { - expr: "some_metric[1m]", - ts: baseT.Add(20 * time.Minute), - expected: promql.Matrix{}, - }, - "metric with stale marker": { - expr: "some_metric_with_stale_marker[3m]", - ts: baseT.Add(3 * time.Minute), - expected: promql.Matrix{ - { - Metric: labels.FromStrings("__name__", "some_metric_with_stale_marker"), - Floats: []promql.FPoint{ - {T: timestamp.FromTime(baseT.Add(time.Minute)), F: 1}, - {T: timestamp.FromTime(baseT.Add(3 * time.Minute)), F: 3}, - }, - }, - }, - }, - } - - for name, testCase := range testCases { - t.Run(name, func(t *testing.T) { - q, err := engine.NewInstantQuery(context.Background(), storage, nil, testCase.expr, testCase.ts) - require.NoError(t, err) - defer q.Close() - - res := q.Exec(context.Background()) - require.NoError(t, res.Err) - testutil.RequireEqual(t, testCase.expected, res.Value) - }) - } -} - func TestQueryLookbackDelta(t *testing.T) { var ( load = `load 5m diff --git a/promql/functions.go b/promql/functions.go index be1b7da218..6dfe9611f1 100644 --- a/promql/functions.go +++ b/promql/functions.go @@ -65,13 +65,127 @@ func funcTime(_ []Vector, _ Matrix, _ parser.Expressions, enh *EvalNodeHelper) ( }}, nil } +// pickOrInterpolateLeft returns the value at the left boundary of the range. +// If interpolation is needed (when smoothed is true and the first sample is before the range start), +// it returns the interpolated value at the left boundary; otherwise, it returns the first sample's value. +func pickOrInterpolateLeft(floats []FPoint, first int, rangeStart int64, smoothed, isCounter bool) float64 { + if smoothed && floats[first].T < rangeStart { + return interpolate(floats[first], floats[first+1], rangeStart, isCounter, true) + } + return floats[first].F +} + +// pickOrInterpolateRight returns the value at the right boundary of the range. +// If interpolation is needed (when smoothed is true and the last sample is after the range end), +// it returns the interpolated value at the right boundary; otherwise, it returns the last sample's value. +func pickOrInterpolateRight(floats []FPoint, last int, rangeEnd int64, smoothed, isCounter bool) float64 { + if smoothed && last > 0 && floats[last].T > rangeEnd { + return interpolate(floats[last-1], floats[last], rangeEnd, isCounter, false) + } + return floats[last].F +} + +// interpolate performs linear interpolation between two points. +// If isCounter is true and there is a counter reset: +// - on the left edge, it sets the value to 0. +// - on the right edge, it adds the left value to the right value. +// It then calculates the interpolated value at the given timestamp. +func interpolate(p1, p2 FPoint, t int64, isCounter, leftEdge bool) float64 { + y1 := p1.F + y2 := p2.F + if isCounter && y2 < y1 { + if leftEdge { + y1 = 0 + } else { + y2 += y1 + } + } + + return y1 + (y2-y1)*float64(t-p1.T)/float64(p2.T-p1.T) +} + +// correctForCounterResets calculates the correction for counter resets. +// This function is only used for extendedRate functions with smoothed or anchored rates. +func correctForCounterResets(left, right float64, points []FPoint) float64 { + var correction float64 + prev := left + for _, p := range points { + if p.F < prev { + correction += prev + } + prev = p.F + } + if right < prev { + correction += prev + } + return correction +} + +// extendedRate is a utility function for anchored/smoothed rate/increase/delta. +// It calculates the rate (allowing for counter resets if isCounter is true), +// extrapolates if the first/last sample if needed, and returns +// the result as either per-second (if isRate is true) or overall. +func extendedRate(vals Matrix, args parser.Expressions, enh *EvalNodeHelper, isCounter, isRate bool) (Vector, annotations.Annotations) { + var ( + ms = args[0].(*parser.MatrixSelector) + vs = ms.VectorSelector.(*parser.VectorSelector) + samples = vals[0] + f = samples.Floats + lastSampleIndex = len(f) - 1 + rangeStart = enh.Ts - durationMilliseconds(ms.Range+vs.Offset) + rangeEnd = enh.Ts - durationMilliseconds(vs.Offset) + annos annotations.Annotations + smoothed = vs.Smoothed + ) + + firstSampleIndex := max(0, sort.Search(lastSampleIndex, func(i int) bool { return f[i].T > rangeStart })-1) + if smoothed { + lastSampleIndex = sort.Search(lastSampleIndex, func(i int) bool { return f[i].T >= rangeEnd }) + } + + if f[lastSampleIndex].T <= rangeStart { + return enh.Out, annos + } + + left := pickOrInterpolateLeft(f, firstSampleIndex, rangeStart, smoothed, isCounter) + right := pickOrInterpolateRight(f, lastSampleIndex, rangeEnd, smoothed, isCounter) + + resultFloat := right - left + + if isCounter { + // We only need to consider samples exactly within the range + // for counter resets correction, as pickOrInterpolateLeft and + // pickOrInterpolateRight already handle the resets at boundaries. + if f[firstSampleIndex].T <= rangeStart { + firstSampleIndex++ + } + if f[lastSampleIndex].T >= rangeEnd { + lastSampleIndex-- + } + + resultFloat += correctForCounterResets(left, right, f[firstSampleIndex:lastSampleIndex+1]) + } + if isRate { + resultFloat /= ms.Range.Seconds() + } + + return append(enh.Out, Sample{F: resultFloat}), annos +} + // extrapolatedRate is a utility function for rate/increase/delta. // It calculates the rate (allowing for counter resets if isCounter is true), // extrapolates if the first/last sample is close to the boundary, and returns // the result as either per-second (if isRate is true) or overall. +// +// Note: If the vector selector is smoothed or anchored, it will use the +// extendedRate function instead. func extrapolatedRate(vals Matrix, args parser.Expressions, enh *EvalNodeHelper, isCounter, isRate bool) (Vector, annotations.Annotations) { ms := args[0].(*parser.MatrixSelector) vs := ms.VectorSelector.(*parser.VectorSelector) + if vs.Anchored || vs.Smoothed { + return extendedRate(vals, args, enh, isCounter, isRate) + } + var ( samples = vals[0] rangeStart = enh.Ts - durationMilliseconds(ms.Range+vs.Offset) @@ -1548,8 +1662,21 @@ func funcHistogramQuantile(vectorVals []Vector, _ Matrix, args parser.Expression return enh.Out, annos } +// pickFirstSampleIndex returns the index of the last sample before +// or at the range start, or 0 if none exist before the range start. +// If the vector selector is not anchored, it always returns 0. +func pickFirstSampleIndex(floats []FPoint, args parser.Expressions, enh *EvalNodeHelper) int { + ms := args[0].(*parser.MatrixSelector) + vs := ms.VectorSelector.(*parser.VectorSelector) + if !vs.Anchored { + return 0 + } + rangeStart := enh.Ts - durationMilliseconds(ms.Range+vs.Offset) + return max(0, sort.Search(len(floats)-1, func(i int) bool { return floats[i].T > rangeStart })-1) +} + // === resets(Matrix parser.ValueTypeMatrix) (Vector, Annotations) === -func funcResets(_ []Vector, matrixVal Matrix, _ parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) { +func funcResets(_ []Vector, matrixVal Matrix, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) { floats := matrixVal[0].Floats histograms := matrixVal[0].Histograms resets := 0 @@ -1558,7 +1685,8 @@ func funcResets(_ []Vector, matrixVal Matrix, _ parser.Expressions, enh *EvalNod } var prevSample, curSample Sample - for iFloat, iHistogram := 0, 0; iFloat < len(floats) || iHistogram < len(histograms); { + firstSampleIndex := pickFirstSampleIndex(floats, args, enh) + for iFloat, iHistogram := firstSampleIndex, 0; iFloat < len(floats) || iHistogram < len(histograms); { switch { // Process a float sample if no histogram sample remains or its timestamp is earlier. // Process a histogram sample if no float sample remains or its timestamp is earlier. @@ -1571,7 +1699,7 @@ func funcResets(_ []Vector, matrixVal Matrix, _ parser.Expressions, enh *EvalNod iHistogram++ } // Skip the comparison for the first sample, just initialize prevSample. - if iFloat+iHistogram == 1 { + if iFloat+iHistogram == 1+firstSampleIndex { prevSample = curSample continue } @@ -1594,7 +1722,7 @@ func funcResets(_ []Vector, matrixVal Matrix, _ parser.Expressions, enh *EvalNod } // === changes(Matrix parser.ValueTypeMatrix) (Vector, Annotations) === -func funcChanges(_ []Vector, matrixVal Matrix, _ parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) { +func funcChanges(_ []Vector, matrixVal Matrix, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) { floats := matrixVal[0].Floats histograms := matrixVal[0].Histograms changes := 0 @@ -1603,7 +1731,8 @@ func funcChanges(_ []Vector, matrixVal Matrix, _ parser.Expressions, enh *EvalNo } var prevSample, curSample Sample - for iFloat, iHistogram := 0, 0; iFloat < len(floats) || iHistogram < len(histograms); { + firstSampleIndex := pickFirstSampleIndex(floats, args, enh) + for iFloat, iHistogram := firstSampleIndex, 0; iFloat < len(floats) || iHistogram < len(histograms); { switch { // Process a float sample if no histogram sample remains or its timestamp is earlier. // Process a histogram sample if no float sample remains or its timestamp is earlier. @@ -1616,7 +1745,7 @@ func funcChanges(_ []Vector, matrixVal Matrix, _ parser.Expressions, enh *EvalNo iHistogram++ } // Skip the comparison for the first sample, just initialize prevSample. - if iFloat+iHistogram == 1 { + if iFloat+iHistogram == 1+firstSampleIndex { prevSample = curSample continue } @@ -1920,6 +2049,26 @@ var AtModifierUnsafeFunctions = map[string]struct{}{ "timestamp": {}, } +// AnchoredSafeFunctions are the functions that can be used with the anchored +// modifier. Anchored modifier returns matrices with samples outside of the +// boundaries, so not every function can be used with it. +var AnchoredSafeFunctions = map[string]struct{}{ + "resets": {}, + "changes": {}, + "rate": {}, + "increase": {}, + "delta": {}, +} + +// SmoothedSafeFunctions are the functions that can be used with the smoothed +// modifier. Smoothed modifier returns matrices with samples outside of the +// boundaries, so not every function can be used with it. +var SmoothedSafeFunctions = map[string]struct{}{ + "rate": {}, + "increase": {}, + "delta": {}, +} + type vectorByValueHeap Vector func (s vectorByValueHeap) Len() int { diff --git a/promql/functions_internal_test.go b/promql/functions_internal_test.go index 85c6cd7973..658eb7550d 100644 --- a/promql/functions_internal_test.go +++ b/promql/functions_internal_test.go @@ -79,3 +79,24 @@ func TestKahanSumInc(t *testing.T) { }) } } + +func TestInterpolate(t *testing.T) { + tests := []struct { + p1, p2 FPoint + t int64 + isCounter bool + expected float64 + }{ + {FPoint{T: 1, F: 100}, FPoint{T: 2, F: 200}, 1, false, 100}, + {FPoint{T: 0, F: 100}, FPoint{T: 2, F: 200}, 1, false, 150}, + {FPoint{T: 0, F: 200}, FPoint{T: 2, F: 100}, 1, false, 150}, + {FPoint{T: 0, F: 200}, FPoint{T: 2, F: 0}, 1, true, 200}, + {FPoint{T: 0, F: 200}, FPoint{T: 2, F: 100}, 1, true, 250}, + {FPoint{T: 0, F: 500}, FPoint{T: 2, F: 100}, 1, true, 550}, + {FPoint{T: 0, F: 500}, FPoint{T: 10, F: 0}, 1, true, 500}, + } + for _, test := range tests { + result := interpolate(test.p1, test.p2, test.t, test.isCounter, false) + require.Equal(t, test.expected, result) + } +} diff --git a/promql/parser/ast.go b/promql/parser/ast.go index dda25f1f11..67ecb190fe 100644 --- a/promql/parser/ast.go +++ b/promql/parser/ast.go @@ -226,6 +226,11 @@ type VectorSelector struct { // This is the case when VectorSelector is used to represent the info function's second argument. BypassEmptyMatcherCheck bool + // Anchored is true when the VectorSelector is anchored. + Anchored bool + // Smoothed is true when the VectorSelector is smoothed. + Smoothed bool + PosRange posrange.PositionRange } diff --git a/promql/parser/generated_parser.y b/promql/parser/generated_parser.y index bd57070af1..3e2f13d872 100644 --- a/promql/parser/generated_parser.y +++ b/promql/parser/generated_parser.y @@ -141,6 +141,8 @@ GROUP_LEFT GROUP_RIGHT IGNORING OFFSET +SMOOTHED +ANCHORED ON WITHOUT %token keywordsEnd @@ -187,7 +189,7 @@ START_METRIC_SELECTOR %type int %type uint %type number series_value signed_number signed_or_unsigned_number -%type step_invariant_expr aggregate_expr aggregate_modifier bin_modifier binary_expr bool_modifier expr function_call function_call_args function_call_body group_modifiers label_matchers matrix_selector number_duration_literal offset_expr on_or_ignoring paren_expr string_literal subquery_expr unary_expr vector_selector duration_expr paren_duration_expr positive_duration_expr offset_duration_expr +%type step_invariant_expr aggregate_expr aggregate_modifier bin_modifier binary_expr bool_modifier expr function_call function_call_args function_call_body group_modifiers label_matchers matrix_selector number_duration_literal offset_expr anchored_expr smoothed_expr on_or_ignoring paren_expr string_literal subquery_expr unary_expr vector_selector duration_expr paren_duration_expr positive_duration_expr offset_duration_expr %start start @@ -230,6 +232,8 @@ expr : | matrix_selector | number_duration_literal | offset_expr + | anchored_expr + | smoothed_expr | paren_expr | string_literal | subquery_expr @@ -464,6 +468,20 @@ offset_expr: expr OFFSET offset_duration_expr { yylex.(*parser).unexpected("offset", "number, duration, or step()"); $$ = $1 } ; +/* + * Anchored and smoothed modifiers + */ + +anchored_expr: expr ANCHORED + { + yylex.(*parser).setAnchored($1) + } + +smoothed_expr: expr SMOOTHED + { + yylex.(*parser).setSmoothed($1) + } + /* * @ modifiers. */ diff --git a/promql/parser/generated_parser.y.go b/promql/parser/generated_parser.y.go index 77f5cc2e22..df4611892a 100644 --- a/promql/parser/generated_parser.y.go +++ b/promql/parser/generated_parser.y.go @@ -115,26 +115,28 @@ const GROUP_LEFT = 57422 const GROUP_RIGHT = 57423 const IGNORING = 57424 const OFFSET = 57425 -const ON = 57426 -const WITHOUT = 57427 -const keywordsEnd = 57428 -const preprocessorStart = 57429 -const START = 57430 -const END = 57431 -const STEP = 57432 -const preprocessorEnd = 57433 -const counterResetHintsStart = 57434 -const UNKNOWN_COUNTER_RESET = 57435 -const COUNTER_RESET = 57436 -const NOT_COUNTER_RESET = 57437 -const GAUGE_TYPE = 57438 -const counterResetHintsEnd = 57439 -const startSymbolsStart = 57440 -const START_METRIC = 57441 -const START_SERIES_DESCRIPTION = 57442 -const START_EXPRESSION = 57443 -const START_METRIC_SELECTOR = 57444 -const startSymbolsEnd = 57445 +const SMOOTHED = 57426 +const ANCHORED = 57427 +const ON = 57428 +const WITHOUT = 57429 +const keywordsEnd = 57430 +const preprocessorStart = 57431 +const START = 57432 +const END = 57433 +const STEP = 57434 +const preprocessorEnd = 57435 +const counterResetHintsStart = 57436 +const UNKNOWN_COUNTER_RESET = 57437 +const COUNTER_RESET = 57438 +const NOT_COUNTER_RESET = 57439 +const GAUGE_TYPE = 57440 +const counterResetHintsEnd = 57441 +const startSymbolsStart = 57442 +const START_METRIC = 57443 +const START_SERIES_DESCRIPTION = 57444 +const START_EXPRESSION = 57445 +const START_METRIC_SELECTOR = 57446 +const startSymbolsEnd = 57447 var yyToknames = [...]string{ "$end", @@ -220,6 +222,8 @@ var yyToknames = [...]string{ "GROUP_RIGHT", "IGNORING", "OFFSET", + "SMOOTHED", + "ANCHORED", "ON", "WITHOUT", "keywordsEnd", @@ -253,488 +257,490 @@ var yyExca = [...]int16{ 1, -1, -2, 0, -1, 38, - 1, 143, - 10, 143, - 24, 143, + 1, 147, + 10, 147, + 24, 147, -2, 0, - -1, 66, - 2, 186, - 15, 186, - 79, 186, - 85, 186, - -2, 103, - -1, 67, - 2, 187, - 15, 187, - 79, 187, - 85, 187, - -2, 104, -1, 68, - 2, 188, - 15, 188, - 79, 188, - 85, 188, - -2, 106, - -1, 69, - 2, 189, - 15, 189, - 79, 189, - 85, 189, - -2, 107, - -1, 70, 2, 190, 15, 190, 79, 190, - 85, 190, - -2, 108, - -1, 71, + 87, 190, + -2, 107, + -1, 69, 2, 191, 15, 191, 79, 191, - 85, 191, - -2, 113, - -1, 72, + 87, 191, + -2, 108, + -1, 70, 2, 192, 15, 192, 79, 192, - 85, 192, - -2, 115, - -1, 73, + 87, 192, + -2, 110, + -1, 71, 2, 193, 15, 193, 79, 193, - 85, 193, - -2, 117, - -1, 74, + 87, 193, + -2, 111, + -1, 72, 2, 194, 15, 194, 79, 194, - 85, 194, - -2, 118, - -1, 75, + 87, 194, + -2, 112, + -1, 73, 2, 195, 15, 195, 79, 195, - 85, 195, - -2, 119, - -1, 76, + 87, 195, + -2, 117, + -1, 74, 2, 196, 15, 196, 79, 196, - 85, 196, - -2, 120, - -1, 77, + 87, 196, + -2, 119, + -1, 75, 2, 197, 15, 197, 79, 197, - 85, 197, + 87, 197, -2, 121, - -1, 78, + -1, 76, 2, 198, 15, 198, 79, 198, - 85, 198, - -2, 125, - -1, 79, + 87, 198, + -2, 122, + -1, 77, 2, 199, 15, 199, 79, 199, - 85, 199, - -2, 126, - -1, 129, - 41, 262, - 42, 262, - 52, 262, - 53, 262, - 57, 262, - -2, 20, - -1, 239, - 9, 249, - 12, 249, - 13, 249, - 18, 249, - 19, 249, - 25, 249, - 41, 249, - 47, 249, - 48, 249, - 51, 249, - 57, 249, - 62, 249, - 63, 249, - 64, 249, - 65, 249, - 66, 249, - 67, 249, - 68, 249, - 69, 249, - 70, 249, - 71, 249, - 72, 249, - 73, 249, - 74, 249, - 75, 249, - 79, 249, - 83, 249, - 85, 249, - 88, 249, - 89, 249, - 90, 249, + 87, 199, + -2, 123, + -1, 78, + 2, 200, + 15, 200, + 79, 200, + 87, 200, + -2, 124, + -1, 79, + 2, 201, + 15, 201, + 79, 201, + 87, 201, + -2, 125, + -1, 80, + 2, 202, + 15, 202, + 79, 202, + 87, 202, + -2, 129, + -1, 81, + 2, 203, + 15, 203, + 79, 203, + 87, 203, + -2, 130, + -1, 133, + 41, 266, + 42, 266, + 52, 266, + 53, 266, + 57, 266, + -2, 22, + -1, 243, + 9, 253, + 12, 253, + 13, 253, + 18, 253, + 19, 253, + 25, 253, + 41, 253, + 47, 253, + 48, 253, + 51, 253, + 57, 253, + 62, 253, + 63, 253, + 64, 253, + 65, 253, + 66, 253, + 67, 253, + 68, 253, + 69, 253, + 70, 253, + 71, 253, + 72, 253, + 73, 253, + 74, 253, + 75, 253, + 79, 253, + 83, 253, + 87, 253, + 90, 253, + 91, 253, + 92, 253, -2, 0, - -1, 240, - 9, 249, - 12, 249, - 13, 249, - 18, 249, - 19, 249, - 25, 249, - 41, 249, - 47, 249, - 48, 249, - 51, 249, - 57, 249, - 62, 249, - 63, 249, - 64, 249, - 65, 249, - 66, 249, - 67, 249, - 68, 249, - 69, 249, - 70, 249, - 71, 249, - 72, 249, - 73, 249, - 74, 249, - 75, 249, - 79, 249, - 83, 249, - 85, 249, - 88, 249, - 89, 249, - 90, 249, + -1, 244, + 9, 253, + 12, 253, + 13, 253, + 18, 253, + 19, 253, + 25, 253, + 41, 253, + 47, 253, + 48, 253, + 51, 253, + 57, 253, + 62, 253, + 63, 253, + 64, 253, + 65, 253, + 66, 253, + 67, 253, + 68, 253, + 69, 253, + 70, 253, + 71, 253, + 72, 253, + 73, 253, + 74, 253, + 75, 253, + 79, 253, + 83, 253, + 87, 253, + 90, 253, + 91, 253, + 92, 253, -2, 0, } const yyPrivate = 57344 -const yyLast = 1045 +const yyLast = 1052 var yyAct = [...]int16{ - 53, 393, 391, 176, 398, 324, 272, 231, 187, 179, - 45, 338, 89, 135, 215, 87, 118, 122, 339, 64, - 121, 60, 180, 123, 150, 120, 119, 405, 406, 407, - 408, 62, 237, 124, 238, 112, 239, 240, 116, 388, - 387, 358, 315, 208, 184, 356, 145, 377, 117, 115, - 57, 6, 118, 346, 183, 344, 175, 356, 210, 127, - 56, 129, 94, 96, 97, 314, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 185, 108, 109, 111, - 95, 125, 80, 392, 138, 40, 307, 312, 313, 184, - 364, 318, 186, 130, 136, 137, 342, 122, 81, 183, - 365, 306, 309, 123, 110, 363, 319, 91, 174, 173, - 311, 172, 362, 189, 193, 194, 195, 196, 197, 198, - 235, 168, 320, 190, 190, 190, 190, 190, 190, 190, - 171, 192, 169, 211, 191, 191, 191, 191, 191, 191, - 191, 201, 204, 190, 126, 199, 128, 200, 2, 3, - 4, 5, 221, 57, 191, 233, 223, 316, 341, 259, - 227, 112, 216, 56, 217, 131, 113, 116, 234, 264, - 260, 420, 185, 399, 409, 382, 263, 117, 115, 352, - 256, 118, 114, 226, 351, 80, 190, 421, 186, 258, - 419, 191, 260, 418, 381, 265, 266, 191, 146, 350, - 262, 81, 190, 108, 219, 111, 113, 116, 113, 116, - 207, 174, 173, 191, 218, 220, 203, 117, 115, 117, - 115, 118, 114, 118, 114, 217, 137, 310, 261, 202, - 110, 225, 236, 124, 257, 132, 82, 241, 242, 243, - 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, - 254, 255, 340, 317, 224, 36, 336, 337, 7, 376, - 343, 375, 90, 345, 138, 219, 93, 269, 10, 189, - 190, 268, 88, 190, 136, 218, 220, 347, 84, 190, - 222, 191, 134, 374, 191, 91, 267, 91, 373, 372, - 191, 417, 371, 370, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, 165, 354, - 113, 116, 369, 368, 367, 366, 144, 355, 357, 190, - 359, 117, 115, 90, 214, 118, 114, 360, 361, 213, - 191, 349, 385, 88, 51, 8, 37, 184, 57, 38, - 83, 86, 212, 378, 175, 1, 91, 183, 56, 422, - 348, 113, 116, 190, 166, 143, 141, 142, 384, 65, - 386, 140, 117, 115, 191, 50, 118, 114, 390, 185, - 80, 394, 395, 396, 139, 49, 401, 400, 403, 402, - 397, 410, 48, 47, 149, 186, 81, 46, 275, 411, - 412, 190, 44, 353, 413, 379, 174, 173, 285, 147, - 205, 43, 191, 415, 291, 148, 42, 41, 383, 61, - 416, 274, 9, 9, 113, 116, 52, 230, 414, 192, - 190, 321, 423, 92, 228, 117, 115, 270, 85, 118, - 114, 191, 404, 287, 288, 177, 273, 289, 54, 133, - 0, 0, 0, 0, 0, 302, 0, 0, 276, 278, - 280, 281, 282, 290, 292, 295, 296, 297, 298, 299, - 303, 304, 275, 0, 277, 279, 283, 284, 286, 293, - 294, 209, 285, 0, 300, 301, 305, 0, 291, 0, - 0, 188, 271, 0, 0, 274, 0, 0, 57, 0, - 113, 116, 0, 0, 175, 0, 0, 0, 56, 0, - 0, 117, 115, 0, 0, 118, 114, 287, 288, 0, - 0, 289, 0, 0, 0, 0, 0, 0, 0, 302, - 80, 0, 276, 278, 280, 281, 282, 290, 292, 295, - 296, 297, 298, 299, 303, 304, 81, 0, 277, 279, - 283, 284, 286, 293, 294, 0, 174, 173, 300, 301, - 305, 57, 0, 112, 55, 82, 0, 58, 0, 0, - 22, 56, 0, 167, 206, 0, 0, 59, 0, 192, - 57, 0, 0, 0, 0, 0, 175, 0, 0, 0, - 56, 96, 0, 80, 0, 0, 0, 0, 0, 18, - 19, 105, 106, 20, 0, 108, 0, 111, 95, 81, - 0, 0, 80, 0, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, 81, 0, - 0, 13, 110, 0, 380, 24, 0, 30, 174, 173, - 31, 32, 63, 57, 39, 0, 55, 82, 0, 58, - 0, 0, 22, 56, 0, 0, 178, 0, 0, 59, - 0, 170, 0, 184, 0, 0, 0, 0, 113, 116, - 0, 0, 0, 183, 0, 80, 0, 0, 0, 117, - 115, 18, 19, 118, 114, 20, 0, 0, 0, 0, - 0, 81, 0, 0, 0, 185, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 0, 186, 0, 13, 0, 0, 0, 24, 0, 30, - 0, 0, 31, 32, 63, 57, 0, 112, 55, 82, - 0, 58, 0, 0, 22, 56, 0, 0, 0, 0, - 0, 59, 181, 182, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 94, 96, 0, 80, 0, 0, - 0, 0, 0, 18, 19, 105, 106, 20, 308, 108, - 109, 111, 95, 81, 0, 0, 0, 0, 66, 67, + 55, 180, 397, 395, 183, 402, 276, 235, 191, 328, + 91, 45, 342, 139, 66, 219, 89, 241, 17, 84, + 154, 242, 125, 62, 22, 184, 124, 123, 343, 409, + 410, 411, 412, 126, 120, 128, 243, 244, 64, 122, + 392, 127, 391, 362, 121, 119, 149, 319, 122, 192, + 381, 350, 360, 18, 19, 188, 59, 20, 220, 318, + 221, 131, 179, 133, 6, 187, 58, 426, 11, 12, + 14, 15, 16, 21, 23, 25, 26, 27, 28, 29, + 33, 34, 317, 316, 129, 13, 40, 189, 82, 24, + 396, 348, 214, 30, 322, 141, 31, 32, 35, 126, + 223, 360, 134, 190, 83, 369, 315, 127, 239, 323, + 222, 224, 346, 176, 178, 177, 424, 193, 197, 198, + 199, 200, 201, 202, 172, 324, 345, 175, 194, 194, + 194, 194, 194, 194, 194, 423, 173, 215, 422, 196, + 195, 195, 195, 195, 195, 195, 195, 130, 194, 132, + 203, 182, 204, 386, 237, 205, 208, 225, 188, 135, + 195, 227, 320, 2, 3, 4, 5, 268, 187, 171, + 266, 207, 385, 188, 264, 238, 59, 189, 231, 403, + 267, 229, 179, 187, 206, 260, 58, 368, 262, 265, + 189, 194, 425, 190, 269, 270, 264, 195, 311, 150, + 84, 230, 367, 195, 228, 189, 190, 194, 82, 366, + 273, 117, 120, 310, 272, 211, 128, 136, 221, 195, + 218, 190, 121, 119, 83, 217, 122, 118, 141, 271, + 36, 314, 7, 380, 178, 177, 379, 240, 216, 185, + 186, 378, 245, 246, 247, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 344, 223, 174, + 321, 145, 188, 377, 347, 148, 144, 349, 222, 224, + 340, 341, 187, 193, 376, 194, 375, 374, 194, 143, + 373, 351, 95, 10, 194, 59, 116, 195, 372, 371, + 195, 179, 413, 86, 370, 58, 195, 155, 156, 157, + 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 53, 358, 147, 421, 146, 82, 85, 37, + 1, 170, 359, 361, 194, 363, 117, 120, 110, 67, + 115, 364, 365, 83, 117, 120, 195, 121, 119, 52, + 51, 122, 118, 178, 177, 121, 119, 382, 63, 122, + 118, 9, 9, 50, 142, 112, 114, 113, 194, 8, + 49, 153, 388, 38, 140, 390, 356, 48, 196, 47, + 195, 355, 313, 398, 399, 400, 394, 93, 46, 401, + 44, 405, 404, 407, 406, 414, 354, 279, 151, 209, + 43, 152, 389, 42, 415, 416, 194, 289, 357, 417, + 383, 41, 54, 295, 234, 419, 418, 387, 195, 325, + 278, 117, 120, 94, 420, 232, 274, 87, 408, 117, + 120, 181, 121, 119, 427, 194, 122, 118, 277, 56, + 121, 119, 291, 292, 122, 118, 293, 195, 137, 0, + 0, 0, 0, 0, 306, 0, 0, 280, 282, 284, + 285, 286, 294, 296, 299, 300, 301, 302, 303, 307, + 308, 0, 279, 281, 283, 287, 288, 290, 297, 92, + 142, 298, 289, 0, 0, 304, 305, 309, 295, 90, + 140, 0, 275, 213, 0, 278, 92, 226, 138, 59, + 0, 0, 93, 93, 0, 263, 90, 0, 0, 58, + 0, 0, 117, 120, 88, 0, 0, 291, 292, 93, + 0, 293, 0, 121, 119, 0, 0, 122, 118, 306, + 0, 82, 280, 282, 284, 285, 286, 294, 296, 299, + 300, 301, 302, 303, 307, 308, 0, 83, 281, 283, + 287, 288, 290, 297, 0, 0, 298, 178, 177, 0, + 304, 305, 309, 59, 0, 116, 57, 84, 0, 60, + 0, 0, 22, 58, 117, 120, 210, 0, 0, 61, + 0, 0, 261, 0, 0, 121, 119, 0, 0, 122, + 118, 0, 96, 98, 0, 82, 0, 0, 0, 0, + 0, 18, 19, 107, 108, 20, 0, 110, 111, 115, + 97, 83, 0, 0, 0, 0, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 0, 0, 0, 13, 112, 114, 113, 24, 0, 0, + 0, 30, 0, 0, 31, 32, 65, 59, 39, 0, + 57, 84, 0, 60, 0, 0, 22, 58, 0, 0, + 0, 0, 233, 61, 0, 0, 188, 0, 0, 236, + 0, 0, 0, 239, 0, 0, 187, 353, 0, 82, + 0, 0, 0, 0, 59, 18, 19, 0, 0, 20, + 179, 0, 0, 0, 58, 83, 352, 0, 189, 0, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - 78, 79, 17, 82, 0, 13, 110, 0, 22, 24, - 0, 30, 113, 116, 31, 32, 63, 0, 0, 0, - 0, 0, 0, 117, 115, 0, 0, 118, 114, 0, - 0, 0, 229, 0, 0, 0, 184, 18, 19, 232, - 0, 20, 0, 235, 0, 0, 183, 0, 0, 0, - 0, 0, 11, 12, 14, 15, 16, 21, 23, 25, - 26, 27, 28, 29, 33, 34, 17, 36, 185, 13, - 0, 0, 22, 24, 323, 30, 0, 0, 31, 32, - 35, 322, 0, 0, 186, 326, 327, 325, 332, 334, - 331, 333, 328, 329, 330, 335, 0, 0, 0, 0, - 0, 18, 19, 0, 0, 20, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 11, 12, 14, 15, - 16, 21, 23, 25, 26, 27, 28, 29, 33, 34, - 112, 0, 0, 13, 0, 0, 0, 24, 0, 30, - 0, 0, 31, 32, 35, 0, 0, 0, 0, 112, - 0, 0, 0, 0, 0, 0, 0, 94, 96, 97, - 0, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 0, 108, 109, 111, 95, 94, 96, 97, 0, - 98, 99, 100, 0, 102, 103, 104, 105, 106, 107, - 389, 108, 109, 111, 95, 112, 0, 0, 0, 110, - 0, 326, 327, 325, 332, 334, 331, 333, 328, 329, - 330, 335, 0, 0, 0, 0, 0, 0, 110, 0, - 0, 0, 94, 96, 97, 0, 98, 99, 0, 0, - 102, 103, 0, 105, 106, 107, 0, 108, 109, 111, - 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 110, + 78, 79, 80, 81, 190, 384, 82, 13, 0, 0, + 0, 24, 0, 0, 0, 30, 0, 0, 31, 32, + 65, 59, 83, 0, 57, 84, 0, 60, 0, 0, + 22, 58, 178, 177, 0, 0, 0, 61, 0, 117, + 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 121, 119, 0, 82, 122, 118, 0, 196, 0, 18, + 19, 17, 36, 20, 0, 0, 0, 22, 0, 83, + 0, 0, 0, 0, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 0, 0, + 0, 13, 0, 0, 0, 24, 18, 19, 0, 30, + 20, 0, 31, 32, 65, 0, 0, 0, 0, 0, + 0, 11, 12, 14, 15, 16, 21, 23, 25, 26, + 27, 28, 29, 33, 34, 116, 0, 0, 13, 0, + 0, 0, 24, 212, 0, 0, 30, 0, 0, 31, + 32, 35, 0, 0, 116, 0, 0, 0, 0, 0, + 0, 0, 96, 98, 99, 0, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 0, 110, 111, 115, + 97, 96, 98, 99, 0, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 0, 110, 111, 115, 97, + 116, 0, 0, 0, 112, 114, 113, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, + 0, 0, 0, 112, 114, 113, 0, 96, 98, 99, + 0, 100, 101, 102, 0, 104, 105, 106, 107, 108, + 109, 0, 110, 111, 115, 97, 96, 98, 99, 0, + 100, 101, 0, 116, 104, 105, 0, 107, 108, 109, + 0, 110, 111, 115, 97, 312, 0, 0, 0, 112, + 114, 113, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 98, 0, 0, 0, 0, 0, 0, 112, 114, + 113, 107, 108, 0, 0, 110, 0, 115, 97, 117, + 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 121, 119, 0, 0, 122, 118, 0, 0, 327, 0, + 0, 0, 112, 114, 113, 326, 0, 0, 0, 330, + 331, 329, 336, 338, 335, 337, 332, 333, 334, 339, + 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 330, 331, 329, 336, 338, 335, 337, 332, 333, + 334, 339, } var yyPact = [...]int16{ - 49, 248, 834, 834, 624, 770, -1000, -1000, -1000, 242, + 62, 222, 749, 749, 628, 6, -1000, -1000, -1000, 217, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 321, -1000, 264, -1000, - 896, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 125, 18, 218, -1000, -1000, 706, -1000, - 706, 223, -1000, 150, 220, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, 484, -1000, 280, -1000, + 830, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 523, 20, 201, -1000, -1000, + 712, -1000, 712, 187, -1000, 144, 202, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, 262, -1000, -1000, 354, -1000, -1000, 353, 312, - -1000, -1000, 22, -1000, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, - 561, 644, 479, 41, 41, 41, 41, 41, 41, 218, - -62, -1000, 214, 214, 542, -1000, 21, 449, 147, -40, - -1000, 36, 41, 322, -1000, -1000, 160, 221, -1000, -1000, - 260, -1000, 229, -1000, 158, 807, 706, -1000, -50, -44, - -1000, 706, 706, 706, 706, 706, 706, 706, 706, 706, - 706, 706, 706, 706, 706, 706, -1000, -1000, -1000, 144, - 213, 185, 125, -1000, -1000, 41, -1000, 154, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 80, 80, 265, -1000, 125, - -1000, 41, 150, -4, -4, -40, -40, -40, -40, -1000, - -1000, -1000, 460, -1000, -1000, 79, -1000, 896, -1000, -1000, - -1000, 751, -1000, 82, -1000, 85, -1000, -1000, -1000, -1000, - -1000, 63, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 16, - 131, 65, -1000, -1000, -1000, 837, 539, 214, 214, 214, - 214, 147, 147, 703, 703, 703, 961, 915, 703, 703, - 961, 147, 147, 703, 147, 539, -1000, 143, 81, 41, - -40, 33, 41, 449, 31, -1000, -1000, -1000, 329, -1000, - 177, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 468, -1000, -1000, 259, -1000, -1000, + 312, 261, -1000, -1000, 22, -1000, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, 167, -1000, -1000, 149, 47, 276, 276, 276, + 276, 276, 276, 201, -46, -1000, 169, 169, 544, -1000, + 811, 461, 272, -17, -1000, 70, 276, 218, -1000, -1000, + 56, 214, -1000, -1000, 467, -1000, 179, -1000, 176, 647, + 712, -1000, -65, -44, -1000, 712, 712, 712, 712, 712, + 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, + -1000, -1000, -1000, 480, 174, 155, 523, -1000, -1000, 276, + -1000, 152, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 253, + 253, 208, -1000, 523, -1000, 276, 144, -8, -8, -17, + -17, -17, -17, -1000, -1000, -1000, 460, -1000, -1000, 191, + -1000, 830, -1000, -1000, -1000, 948, -1000, 352, -1000, 81, + -1000, -1000, -1000, -1000, -1000, 57, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 21, 136, 68, -1000, -1000, -1000, 991, + 929, 169, 169, 169, 169, 272, 272, 541, 541, 541, + 895, 876, 541, 541, 895, 272, 272, 541, 272, 929, + -1000, 111, 97, 276, -17, 69, 276, 461, 29, -1000, + -1000, -1000, 665, -1000, 364, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 706, 41, -1000, - -1000, -1000, -1000, -1000, -1000, 38, 38, 15, 38, 104, - 104, 88, 83, -1000, -1000, 309, 308, 307, 306, 287, - 286, 283, 282, 277, 255, 253, -1000, -1000, -1000, -1000, - -1000, 25, 41, 373, -1000, 617, -1000, 173, -1000, -1000, - -1000, 386, -1000, 896, 310, -1000, -1000, -1000, 38, -1000, - 14, 13, 953, -1000, -1000, -1000, 26, 35, 35, 35, - 80, 159, 159, 26, 159, 26, -66, -1000, 167, -1000, - 41, -1000, -1000, -1000, -1000, -1000, -1000, 38, 38, -1000, - -1000, -1000, 38, -1000, -1000, -1000, -1000, -1000, -1000, 35, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 41, - 269, -1000, -1000, -1000, 169, -1000, 165, -1000, 328, -1000, - -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 712, 276, -1000, -1000, -1000, -1000, -1000, -1000, 82, + 82, 17, 82, 92, 92, 185, 88, -1000, -1000, 288, + 283, 282, 274, 271, 270, 268, 257, 235, 230, 227, + -1000, -1000, -1000, -1000, -1000, 28, 276, 378, -1000, 698, + -1000, 151, -1000, -1000, -1000, 385, -1000, 830, 370, -1000, + -1000, -1000, 82, -1000, 16, 14, 1013, -1000, -1000, -1000, + 33, 164, 164, 164, 253, 165, 165, 33, 165, 33, + -66, -1000, 285, -1000, 276, -1000, -1000, -1000, -1000, -1000, + -1000, 82, 82, -1000, -1000, -1000, 82, -1000, -1000, -1000, + -1000, -1000, -1000, 164, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 276, 293, -1000, -1000, -1000, 114, -1000, + 170, -1000, 46, -1000, -1000, -1000, -1000, -1000, } var yyPgo = [...]int16{ - 0, 439, 13, 438, 6, 14, 436, 409, 21, 435, - 12, 432, 19, 268, 335, 428, 15, 427, 18, 11, - 424, 423, 7, 421, 5, 4, 418, 2, 1, 9, - 417, 22, 3, 416, 407, 26, 198, 406, 405, 85, - 401, 400, 25, 399, 31, 392, 10, 387, 384, 383, - 382, 375, 365, 334, 0, 359, 8, 354, 345, 336, + 0, 438, 13, 429, 6, 15, 428, 348, 23, 421, + 10, 418, 14, 283, 359, 417, 16, 416, 28, 12, + 415, 413, 7, 409, 9, 5, 406, 3, 2, 4, + 404, 25, 1, 402, 401, 27, 199, 393, 391, 86, + 390, 389, 26, 388, 38, 380, 11, 378, 369, 367, + 361, 360, 353, 340, 339, 312, 0, 329, 8, 321, + 320, 319, } var yyR1 = [...]int8{ - 0, 58, 58, 58, 58, 58, 58, 58, 39, 39, + 0, 60, 60, 60, 60, 60, 60, 60, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 34, 34, 34, 34, 35, 35, 37, 37, 37, + 39, 39, 39, 34, 34, 34, 34, 35, 35, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 36, 38, 38, 48, 48, 43, 43, - 43, 43, 18, 18, 18, 18, 17, 17, 17, 4, - 4, 4, 40, 42, 42, 41, 41, 41, 49, 56, - 47, 47, 33, 33, 33, 9, 9, 45, 51, 51, - 51, 51, 51, 51, 52, 53, 53, 53, 44, 44, - 44, 1, 1, 1, 2, 2, 2, 2, 2, 2, - 2, 14, 14, 7, 7, 7, 7, 7, 7, 7, + 37, 37, 37, 37, 37, 36, 38, 38, 50, 50, + 43, 43, 43, 43, 18, 18, 18, 18, 17, 17, + 17, 4, 4, 4, 40, 42, 42, 41, 41, 41, + 51, 58, 47, 47, 48, 49, 33, 33, 33, 9, + 9, 45, 53, 53, 53, 53, 53, 53, 54, 55, + 55, 55, 44, 44, 44, 1, 1, 1, 2, 2, + 2, 2, 2, 2, 2, 14, 14, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 13, 13, - 13, 13, 15, 15, 15, 16, 16, 16, 16, 16, - 16, 16, 59, 21, 21, 21, 21, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 30, 30, 30, 22, - 22, 22, 22, 23, 23, 23, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 25, 25, 26, - 26, 26, 11, 11, 11, 11, 3, 3, 3, 3, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 13, 13, 13, 13, 15, 15, 15, 16, + 16, 16, 16, 16, 16, 16, 61, 21, 21, 21, + 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 30, 30, 30, 22, 22, 22, 22, 23, 23, 23, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 25, 25, 26, 26, 26, 11, 11, 11, 11, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 8, 8, 5, 5, 5, 5, 46, 46, 29, 29, - 31, 31, 32, 32, 28, 27, 27, 50, 10, 19, - 19, 57, 57, 57, 57, 57, 57, 57, 57, 12, - 12, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 55, + 6, 6, 6, 6, 8, 8, 5, 5, 5, 5, + 46, 46, 29, 29, 31, 31, 32, 32, 28, 27, + 27, 52, 10, 19, 19, 59, 59, 59, 59, 59, + 59, 59, 59, 12, 12, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 57, } var yyR2 = [...]int8{ 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 3, 3, 2, 2, 2, 2, 4, 4, 4, + 1, 1, 1, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 1, 0, 1, 3, 3, 1, 1, - 3, 3, 3, 4, 2, 1, 3, 1, 2, 1, - 1, 1, 2, 3, 2, 3, 1, 2, 3, 1, - 3, 3, 3, 5, 3, 1, 1, 4, 6, 5, - 6, 5, 4, 3, 2, 2, 1, 1, 3, 4, - 2, 3, 1, 2, 3, 3, 1, 3, 3, 2, - 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 4, 4, 4, 4, 4, 1, 0, 1, 3, 3, + 1, 1, 3, 3, 3, 4, 2, 1, 3, 1, + 2, 1, 1, 1, 2, 3, 2, 3, 1, 2, + 3, 1, 3, 3, 2, 2, 3, 5, 3, 1, + 1, 4, 6, 5, 6, 5, 4, 3, 2, 2, + 1, 1, 3, 4, 2, 3, 1, 2, 3, 3, + 1, 3, 3, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 3, 4, - 2, 0, 3, 1, 2, 3, 3, 1, 3, 3, - 2, 1, 2, 0, 3, 2, 1, 1, 3, 1, - 3, 4, 1, 3, 5, 5, 1, 1, 1, 4, - 3, 3, 2, 3, 1, 2, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, - 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3, 4, 2, 0, 3, 1, 2, 3, + 3, 1, 3, 3, 2, 1, 2, 0, 3, 2, + 1, 1, 3, 1, 3, 4, 1, 3, 5, 5, + 1, 1, 1, 4, 3, 3, 2, 3, 1, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 4, 3, 3, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 1, 1, 1, 2, 1, 1, 1, 0, - 1, 1, 2, 3, 4, 6, 7, 4, 1, 1, - 1, 1, 2, 3, 3, 3, 3, 3, 3, 3, - 6, 1, 3, + 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, + 1, 1, 1, 0, 1, 1, 2, 3, 4, 6, + 7, 4, 1, 1, 1, 1, 2, 3, 3, 3, + 3, 3, 3, 3, 6, 1, 3, } var yyChk = [...]int16{ - -1000, -58, 99, 100, 101, 102, 2, 10, -14, -7, + -1000, -60, 101, 102, 103, 104, 2, 10, -14, -7, -13, 62, 63, 79, 64, 65, 66, 12, 47, 48, 51, 67, 18, 68, 83, 69, 70, 71, 72, 73, - 85, 88, 89, 74, 75, 90, 13, -59, -14, 10, - -39, -34, -37, -40, -45, -46, -47, -49, -50, -51, - -52, -53, -33, -54, -3, 12, 19, 9, 15, 25, - -8, -7, -44, 90, -12, -55, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 41, 57, 13, -53, -13, -15, 20, -16, 12, -10, - 2, 25, -21, 2, 41, 59, 42, 43, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 56, 57, - 83, 58, 14, 41, 57, 53, 42, 52, 56, -35, - -42, 2, 79, 85, 15, -42, -39, -54, -39, -54, - -44, 15, 15, -1, 20, -2, 12, -10, 2, 20, - 7, 2, 4, 2, 4, 24, -36, -43, -38, -48, - 78, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -57, 2, -46, -8, - 90, -12, -54, 68, 67, 15, -32, -9, 2, -29, - -31, 88, 89, 19, 9, 41, 57, -56, 2, -54, - -46, -8, 90, -54, -54, -54, -54, -54, -54, -42, - -35, -18, 15, 2, -18, -41, 22, -39, 22, 22, - 22, -54, 20, 7, 2, -5, 2, 4, 54, 44, - 55, -5, 20, -16, 25, 2, 25, 2, -20, 5, - -30, -22, 12, -29, -31, 16, -39, 82, 84, 80, - 81, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -46, 90, -12, 15, - -54, 15, 15, -54, 15, -29, -29, 21, 6, 2, - -17, 22, -4, -6, 25, 2, 62, 78, 63, 79, - 64, 65, 66, 80, 81, 12, 82, 47, 48, 51, - 67, 18, 68, 83, 84, 69, 70, 71, 72, 73, - 88, 89, 59, 74, 75, 90, 22, 7, 7, 20, - -2, 25, 2, 25, 2, 26, 26, -31, 26, 41, - 57, -23, 24, 17, -24, 30, 28, 29, 35, 36, - 37, 33, 31, 34, 32, 38, -18, -18, -19, -18, - -19, 15, 15, -54, 22, -54, 22, -56, 21, 2, - 22, 7, 2, -39, -54, -28, 19, -28, 26, -28, - -22, -22, 24, 17, 2, 17, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 22, -54, 22, - 7, 21, 2, 22, -4, 22, -28, 26, 26, 17, - -24, -27, 57, -28, -32, -32, -32, -29, -25, 14, - -25, -27, -25, -27, -11, 93, 94, 95, 96, 7, - -54, -28, -28, -28, -26, -32, -54, 22, 24, 21, - 2, 22, 21, -32, + 87, 90, 91, 74, 75, 92, 13, -61, -14, 10, + -39, -34, -37, -40, -45, -46, -47, -48, -49, -51, + -52, -53, -54, -55, -33, -56, -3, 12, 19, 9, + 15, 25, -8, -7, -44, 92, -12, -57, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 41, 57, 13, -55, -13, -15, 20, -16, + 12, -10, 2, 25, -21, 2, 41, 59, 42, 43, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 56, 57, 83, 85, 84, 58, 14, 41, 57, 53, + 42, 52, 56, -35, -42, 2, 79, 87, 15, -42, + -39, -56, -39, -56, -44, 15, 15, -1, 20, -2, + 12, -10, 2, 20, 7, 2, 4, 2, 4, 24, + -36, -43, -38, -50, 78, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -59, 2, -46, -8, 92, -12, -56, 68, 67, 15, + -32, -9, 2, -29, -31, 90, 91, 19, 9, 41, + 57, -58, 2, -56, -46, -8, 92, -56, -56, -56, + -56, -56, -56, -42, -35, -18, 15, 2, -18, -41, + 22, -39, 22, 22, 22, -56, 20, 7, 2, -5, + 2, 4, 54, 44, 55, -5, 20, -16, 25, 2, + 25, 2, -20, 5, -30, -22, 12, -29, -31, 16, + -39, 82, 86, 80, 81, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -46, 92, -12, 15, -56, 15, 15, -56, 15, -29, + -29, 21, 6, 2, -17, 22, -4, -6, 25, 2, + 62, 78, 63, 79, 64, 65, 66, 80, 81, 12, + 82, 47, 48, 51, 67, 18, 68, 83, 86, 69, + 70, 71, 72, 73, 90, 91, 59, 74, 75, 92, + 22, 7, 7, 20, -2, 25, 2, 25, 2, 26, + 26, -31, 26, 41, 57, -23, 24, 17, -24, 30, + 28, 29, 35, 36, 37, 33, 31, 34, 32, 38, + -18, -18, -19, -18, -19, 15, 15, -56, 22, -56, + 22, -58, 21, 2, 22, 7, 2, -39, -56, -28, + 19, -28, 26, -28, -22, -22, 24, 17, 2, 17, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 22, -56, 22, 7, 21, 2, 22, -4, 22, + -28, 26, 26, 17, -24, -27, 57, -28, -32, -32, + -32, -29, -25, 14, -25, -27, -25, -27, -11, 95, + 96, 97, 98, 7, -56, -28, -28, -28, -26, -32, + -56, 22, 24, 21, 2, 22, 21, -32, } var yyDef = [...]int16{ - 0, -2, 131, 131, 0, 0, 7, 6, 1, 131, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 124, 125, 126, 127, 0, 2, -2, 3, + 0, -2, 135, 135, 0, 0, 7, 6, 1, 135, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, 131, 0, 2, -2, 3, 4, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 0, 109, 236, 237, 0, 247, - 0, 86, 87, 127, 0, 271, -2, -2, -2, -2, + 17, 18, 19, 20, 21, 22, 0, 113, 240, 241, + 0, 251, 0, 90, 91, 131, 0, 275, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, - 230, 231, 0, 5, 101, 0, 130, 133, 0, 137, - 141, 248, 142, 146, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + -2, -2, 234, 235, 0, 5, 105, 0, 134, 137, + 0, 141, 145, 252, 146, 150, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 0, 74, 75, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 25, 26, 0, 0, 0, 64, + 0, 22, 88, -2, 89, 0, 0, 0, 94, 96, + 0, 100, 104, 132, 0, 138, 0, 144, 0, 149, + 0, 45, 50, 51, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 23, 24, 0, 0, 0, 62, 0, 20, 84, -2, - 85, 0, 0, 0, 90, 92, 0, 96, 100, 128, - 0, 134, 0, 140, 0, 145, 0, 43, 48, 49, - 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 70, 71, 251, 0, - 0, 0, 258, 259, 260, 0, 72, 0, 74, 242, - 243, 75, 76, 238, 239, 0, 0, 0, 83, 69, - 261, 0, 0, 263, 264, 265, 266, 267, 268, 21, - 22, 25, 0, 55, 26, 0, 64, 66, 68, 272, - 269, 0, 88, 0, 93, 0, 99, 232, 233, 234, - 235, 0, 129, 132, 135, 138, 136, 139, 144, 147, - 149, 152, 156, 157, 158, 0, 27, 0, 0, -2, - -2, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 252, 0, 0, 0, - 262, 0, 0, 0, 0, 240, 241, 77, 0, 82, - 0, 54, 57, 59, 60, 61, 200, 201, 202, 203, + 72, 73, 255, 0, 0, 0, 262, 263, 264, 0, + 76, 0, 78, 246, 247, 79, 80, 242, 243, 0, + 0, 0, 87, 71, 265, 0, 0, 267, 268, 269, + 270, 271, 272, 23, 24, 27, 0, 57, 28, 0, + 66, 68, 70, 276, 273, 0, 92, 0, 97, 0, + 103, 236, 237, 238, 239, 0, 133, 136, 139, 142, + 140, 143, 148, 151, 153, 156, 160, 161, 162, 0, + 29, 0, 0, -2, -2, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 256, 0, 0, 0, 266, 0, 0, 0, 0, 244, + 245, 81, 0, 86, 0, 56, 59, 61, 62, 63, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 63, 67, 0, 89, - 91, 94, 98, 95, 97, 0, 0, 0, 0, 0, - 0, 0, 0, 162, 164, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 46, 47, 50, 250, - 51, 0, 0, 0, 253, 0, 73, 0, 79, 81, - 52, 0, 58, 65, 0, 148, 244, 150, 0, 153, - 0, 0, 0, 160, 165, 161, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 254, 0, 257, - 0, 78, 80, 53, 56, 270, 151, 0, 0, 159, - 163, 166, 0, 246, 167, 168, 169, 170, 171, 0, - 172, 173, 174, 175, 176, 182, 183, 184, 185, 0, - 0, 154, 155, 245, 0, 180, 0, 255, 0, 178, - 181, 256, 177, 179, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, + 65, 69, 0, 93, 95, 98, 102, 99, 101, 0, + 0, 0, 0, 0, 0, 0, 0, 166, 168, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 49, 52, 254, 53, 0, 0, 0, 257, 0, + 77, 0, 83, 85, 54, 0, 60, 67, 0, 152, + 248, 154, 0, 157, 0, 0, 0, 164, 169, 165, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 258, 0, 261, 0, 82, 84, 55, 58, 274, + 155, 0, 0, 163, 167, 170, 0, 250, 171, 172, + 173, 174, 175, 0, 176, 177, 178, 179, 180, 186, + 187, 188, 189, 0, 0, 158, 159, 249, 0, 184, + 0, 259, 0, 182, 185, 260, 181, 183, } var yyTok1 = [...]int8{ @@ -752,7 +758,7 @@ var yyTok2 = [...]int8{ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, + 102, 103, 104, 105, } var yyTok3 = [...]int8{ @@ -1119,35 +1125,35 @@ yydefault: { yylex.(*parser).unexpected("", "") } - case 21: + case 23: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = yylex.(*parser).newAggregateExpr(yyDollar[1].item, yyDollar[2].node, yyDollar[3].node, false) } - case 22: + case 24: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = yylex.(*parser).newAggregateExpr(yyDollar[1].item, yyDollar[3].node, yyDollar[2].node, false) } - case 23: + case 25: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.node = yylex.(*parser).newAggregateExpr(yyDollar[1].item, &AggregateExpr{}, yyDollar[2].node, true) } - case 24: + case 26: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("aggregation", "") yyVAL.node = yylex.(*parser).newAggregateExpr(yyDollar[1].item, &AggregateExpr{}, Expressions{}, false) } - case 25: + case 27: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.node = &AggregateExpr{ Grouping: yyDollar[2].strings, } } - case 26: + case 28: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.node = &AggregateExpr{ @@ -1155,16 +1161,6 @@ yydefault: Without: true, } } - case 27: - yyDollar = yyS[yypt-4 : yypt+1] - { - yyVAL.node = yylex.(*parser).newBinaryExpression(yyDollar[1].node, yyDollar[2].item, yyDollar[3].node, yyDollar[4].node) - } - case 28: - yyDollar = yyS[yypt-4 : yypt+1] - { - yyVAL.node = yylex.(*parser).newBinaryExpression(yyDollar[1].node, yyDollar[2].item, yyDollar[3].node, yyDollar[4].node) - } case 29: yyDollar = yyS[yypt-4 : yypt+1] { @@ -1235,14 +1231,24 @@ yydefault: { yyVAL.node = yylex.(*parser).newBinaryExpression(yyDollar[1].node, yyDollar[2].item, yyDollar[3].node, yyDollar[4].node) } + case 43: + yyDollar = yyS[yypt-4 : yypt+1] + { + yyVAL.node = yylex.(*parser).newBinaryExpression(yyDollar[1].node, yyDollar[2].item, yyDollar[3].node, yyDollar[4].node) + } case 44: + yyDollar = yyS[yypt-4 : yypt+1] + { + yyVAL.node = yylex.(*parser).newBinaryExpression(yyDollar[1].node, yyDollar[2].item, yyDollar[3].node, yyDollar[4].node) + } + case 46: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.node = &BinaryExpr{ VectorMatching: &VectorMatching{Card: CardOneToOne}, } } - case 45: + case 47: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.node = &BinaryExpr{ @@ -1250,71 +1256,71 @@ yydefault: ReturnBool: true, } } - case 46: + case 48: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = yyDollar[1].node yyVAL.node.(*BinaryExpr).VectorMatching.MatchingLabels = yyDollar[3].strings } - case 47: + case 49: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = yyDollar[1].node yyVAL.node.(*BinaryExpr).VectorMatching.MatchingLabels = yyDollar[3].strings yyVAL.node.(*BinaryExpr).VectorMatching.On = true } - case 50: + case 52: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = yyDollar[1].node yyVAL.node.(*BinaryExpr).VectorMatching.Card = CardManyToOne yyVAL.node.(*BinaryExpr).VectorMatching.Include = yyDollar[3].strings } - case 51: + case 53: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = yyDollar[1].node yyVAL.node.(*BinaryExpr).VectorMatching.Card = CardOneToMany yyVAL.node.(*BinaryExpr).VectorMatching.Include = yyDollar[3].strings } - case 52: + case 54: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.strings = yyDollar[2].strings } - case 53: + case 55: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.strings = yyDollar[2].strings } - case 54: + case 56: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.strings = []string{} } - case 55: + case 57: yyDollar = yyS[yypt-1 : yypt+1] { yylex.(*parser).unexpected("grouping opts", "\"(\"") yyVAL.strings = nil } - case 56: + case 58: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.strings = append(yyDollar[1].strings, yyDollar[3].item.Val) } - case 57: + case 59: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.strings = []string{yyDollar[1].item.Val} } - case 58: + case 60: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("grouping opts", "\",\" or \")\"") yyVAL.strings = yyDollar[1].strings } - case 59: + case 61: yyDollar = yyS[yypt-1 : yypt+1] { if !model.UTF8Validation.IsValidLabelName(yyDollar[1].item.Val) { @@ -1322,7 +1328,7 @@ yydefault: } yyVAL.item = yyDollar[1].item } - case 60: + case 62: yyDollar = yyS[yypt-1 : yypt+1] { unquoted := yylex.(*parser).unquoteString(yyDollar[1].item.Val) @@ -1333,13 +1339,13 @@ yydefault: yyVAL.item.Pos++ yyVAL.item.Val = unquoted } - case 61: + case 63: yyDollar = yyS[yypt-1 : yypt+1] { yylex.(*parser).unexpected("grouping opts", "label") yyVAL.item = Item{} } - case 62: + case 64: yyDollar = yyS[yypt-2 : yypt+1] { fn, exist := getFunction(yyDollar[1].item.Val, yylex.(*parser).functions) @@ -1358,38 +1364,38 @@ yydefault: }, } } - case 63: + case 65: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = yyDollar[2].node } - case 64: + case 66: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.node = Expressions{} } - case 65: + case 67: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = append(yyDollar[1].node.(Expressions), yyDollar[3].node.(Expr)) } - case 66: + case 68: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.node = Expressions{yyDollar[1].node.(Expr)} } - case 67: + case 69: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).addParseErrf(yyDollar[2].item.PositionRange(), "trailing commas not allowed in function call args") yyVAL.node = yyDollar[1].node } - case 68: + case 70: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = &ParenExpr{Expr: yyDollar[2].node.(Expr), PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[3].item)} } - case 69: + case 71: yyDollar = yyS[yypt-1 : yypt+1] { if numLit, ok := yyDollar[1].node.(*NumberLiteral); ok { @@ -1403,7 +1409,7 @@ yydefault: } yyVAL.node = yyDollar[1].node } - case 70: + case 72: yyDollar = yyS[yypt-3 : yypt+1] { if numLit, ok := yyDollar[3].node.(*NumberLiteral); ok { @@ -1414,31 +1420,41 @@ yydefault: yylex.(*parser).addOffsetExpr(yyDollar[1].node, yyDollar[3].node.(*DurationExpr)) yyVAL.node = yyDollar[1].node } - case 71: + case 73: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).unexpected("offset", "number, duration, or step()") yyVAL.node = yyDollar[1].node } - case 72: + case 74: + yyDollar = yyS[yypt-2 : yypt+1] + { + yylex.(*parser).setAnchored(yyDollar[1].node) + } + case 75: + yyDollar = yyS[yypt-2 : yypt+1] + { + yylex.(*parser).setSmoothed(yyDollar[1].node) + } + case 76: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).setTimestamp(yyDollar[1].node, yyDollar[3].float) yyVAL.node = yyDollar[1].node } - case 73: + case 77: yyDollar = yyS[yypt-5 : yypt+1] { yylex.(*parser).setAtModifierPreprocessor(yyDollar[1].node, yyDollar[3].item) yyVAL.node = yyDollar[1].node } - case 74: + case 78: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).unexpected("@", "timestamp") yyVAL.node = yyDollar[1].node } - case 77: + case 81: yyDollar = yyS[yypt-4 : yypt+1] { var errMsg string @@ -1468,7 +1484,7 @@ yydefault: EndPos: yylex.(*parser).lastClosing, } } - case 78: + case 82: yyDollar = yyS[yypt-6 : yypt+1] { var rangeNl time.Duration @@ -1490,7 +1506,7 @@ yydefault: EndPos: yyDollar[6].item.Pos + 1, } } - case 79: + case 83: yyDollar = yyS[yypt-5 : yypt+1] { var rangeNl time.Duration @@ -1505,31 +1521,31 @@ yydefault: EndPos: yyDollar[5].item.Pos + 1, } } - case 80: + case 84: yyDollar = yyS[yypt-6 : yypt+1] { yylex.(*parser).unexpected("subquery selector", "\"]\"") yyVAL.node = yyDollar[1].node } - case 81: + case 85: yyDollar = yyS[yypt-5 : yypt+1] { yylex.(*parser).unexpected("subquery selector", "number, duration, or step() or \"]\"") yyVAL.node = yyDollar[1].node } - case 82: + case 86: yyDollar = yyS[yypt-4 : yypt+1] { yylex.(*parser).unexpected("subquery or range", "\":\" or \"]\"") yyVAL.node = yyDollar[1].node } - case 83: + case 87: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).unexpected("subquery or range selector", "number, duration, or step()") yyVAL.node = yyDollar[1].node } - case 84: + case 88: yyDollar = yyS[yypt-2 : yypt+1] { if nl, ok := yyDollar[2].node.(*NumberLiteral); ok { @@ -1542,7 +1558,7 @@ yydefault: yyVAL.node = &UnaryExpr{Op: yyDollar[1].item.Typ, Expr: yyDollar[2].node.(Expr), StartPos: yyDollar[1].item.Pos} } } - case 85: + case 89: yyDollar = yyS[yypt-2 : yypt+1] { vs := yyDollar[2].node.(*VectorSelector) @@ -1551,7 +1567,7 @@ yydefault: yylex.(*parser).assembleVectorSelector(vs) yyVAL.node = vs } - case 86: + case 90: yyDollar = yyS[yypt-1 : yypt+1] { vs := &VectorSelector{ @@ -1562,14 +1578,14 @@ yydefault: yylex.(*parser).assembleVectorSelector(vs) yyVAL.node = vs } - case 87: + case 91: yyDollar = yyS[yypt-1 : yypt+1] { vs := yyDollar[1].node.(*VectorSelector) yylex.(*parser).assembleVectorSelector(vs) yyVAL.node = vs } - case 88: + case 92: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = &VectorSelector{ @@ -1577,7 +1593,7 @@ yydefault: PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[3].item), } } - case 89: + case 93: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.node = &VectorSelector{ @@ -1585,7 +1601,7 @@ yydefault: PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[4].item), } } - case 90: + case 94: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.node = &VectorSelector{ @@ -1593,7 +1609,7 @@ yydefault: PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[2].item), } } - case 91: + case 95: yyDollar = yyS[yypt-3 : yypt+1] { if yyDollar[1].matchers != nil { @@ -1602,144 +1618,144 @@ yydefault: yyVAL.matchers = yyDollar[1].matchers } } - case 92: + case 96: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.matchers = []*labels.Matcher{yyDollar[1].matcher} } - case 93: + case 97: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("label matching", "\",\" or \"}\"") yyVAL.matchers = yyDollar[1].matchers } - case 94: + case 98: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.matcher = yylex.(*parser).newLabelMatcher(yyDollar[1].item, yyDollar[2].item, yyDollar[3].item) } - case 95: + case 99: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.matcher = yylex.(*parser).newLabelMatcher(yyDollar[1].item, yyDollar[2].item, yyDollar[3].item) } - case 96: + case 100: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.matcher = yylex.(*parser).newMetricNameMatcher(yyDollar[1].item) } - case 97: + case 101: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).unexpected("label matching", "string") yyVAL.matcher = nil } - case 98: + case 102: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).unexpected("label matching", "string") yyVAL.matcher = nil } - case 99: + case 103: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("label matching", "label matching operator") yyVAL.matcher = nil } - case 100: + case 104: yyDollar = yyS[yypt-1 : yypt+1] { yylex.(*parser).unexpected("label matching", "identifier or \"}\"") yyVAL.matcher = nil } - case 101: + case 105: yyDollar = yyS[yypt-2 : yypt+1] { b := labels.NewBuilder(yyDollar[2].labels) b.Set(labels.MetricName, yyDollar[1].item.Val) yyVAL.labels = b.Labels() } - case 102: + case 106: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.labels = yyDollar[1].labels } - case 128: + case 132: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.labels = labels.New(yyDollar[2].lblList...) } - case 129: + case 133: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.labels = labels.New(yyDollar[2].lblList...) } - case 130: + case 134: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.labels = labels.New() } - case 131: + case 135: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.labels = labels.New() } - case 132: + case 136: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.lblList = append(yyDollar[1].lblList, yyDollar[3].label) } - case 133: + case 137: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.lblList = []labels.Label{yyDollar[1].label} } - case 134: + case 138: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("label set", "\",\" or \"}\"") yyVAL.lblList = yyDollar[1].lblList } - case 135: + case 139: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.label = labels.Label{Name: yyDollar[1].item.Val, Value: yylex.(*parser).unquoteString(yyDollar[3].item.Val)} } - case 136: + case 140: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.label = labels.Label{Name: yyDollar[1].item.Val, Value: yylex.(*parser).unquoteString(yyDollar[3].item.Val)} } - case 137: + case 141: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.label = labels.Label{Name: labels.MetricName, Value: yyDollar[1].item.Val} } - case 138: + case 142: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).unexpected("label set", "string") yyVAL.label = labels.Label{} } - case 139: + case 143: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).unexpected("label set", "string") yyVAL.label = labels.Label{} } - case 140: + case 144: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("label set", "\"=\"") yyVAL.label = labels.Label{} } - case 141: + case 145: yyDollar = yyS[yypt-1 : yypt+1] { yylex.(*parser).unexpected("label set", "identifier or \"}\"") yyVAL.label = labels.Label{} } - case 142: + case 146: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).generatedParserResult = &seriesDescription{ @@ -1747,33 +1763,33 @@ yydefault: values: yyDollar[2].series, } } - case 143: + case 147: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.series = []SequenceValue{} } - case 144: + case 148: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.series = append(yyDollar[1].series, yyDollar[3].series...) } - case 145: + case 149: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.series = yyDollar[1].series } - case 146: + case 150: yyDollar = yyS[yypt-1 : yypt+1] { yylex.(*parser).unexpected("series values", "") yyVAL.series = nil } - case 147: + case 151: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.series = []SequenceValue{{Omitted: true}} } - case 148: + case 152: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.series = []SequenceValue{} @@ -1781,12 +1797,12 @@ yydefault: yyVAL.series = append(yyVAL.series, SequenceValue{Omitted: true}) } } - case 149: + case 153: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.series = []SequenceValue{{Value: yyDollar[1].float}} } - case 150: + case 154: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.series = []SequenceValue{} @@ -1795,7 +1811,7 @@ yydefault: yyVAL.series = append(yyVAL.series, SequenceValue{Value: yyDollar[1].float}) } } - case 151: + case 155: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.series = []SequenceValue{} @@ -1805,12 +1821,12 @@ yydefault: yyDollar[1].float += yyDollar[2].float } } - case 152: + case 156: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.series = []SequenceValue{{Histogram: yyDollar[1].histogram}} } - case 153: + case 157: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.series = []SequenceValue{} @@ -1820,7 +1836,7 @@ yydefault: //$1 += $2 } } - case 154: + case 158: yyDollar = yyS[yypt-5 : yypt+1] { val, err := yylex.(*parser).histogramsIncreaseSeries(yyDollar[1].histogram, yyDollar[3].histogram, yyDollar[5].uint) @@ -1829,7 +1845,7 @@ yydefault: } yyVAL.series = val } - case 155: + case 159: yyDollar = yyS[yypt-5 : yypt+1] { val, err := yylex.(*parser).histogramsDecreaseSeries(yyDollar[1].histogram, yyDollar[3].histogram, yyDollar[5].uint) @@ -1838,7 +1854,7 @@ yydefault: } yyVAL.series = val } - case 156: + case 160: yyDollar = yyS[yypt-1 : yypt+1] { if yyDollar[1].item.Val != "stale" { @@ -1846,130 +1862,130 @@ yydefault: } yyVAL.float = math.Float64frombits(value.StaleNaN) } - case 159: + case 163: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&yyDollar[2].descriptors) } - case 160: + case 164: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&yyDollar[2].descriptors) } - case 161: - yyDollar = yyS[yypt-3 : yypt+1] - { - m := yylex.(*parser).newMap() - yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&m) - } - case 162: - yyDollar = yyS[yypt-2 : yypt+1] - { - m := yylex.(*parser).newMap() - yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&m) - } - case 163: - yyDollar = yyS[yypt-3 : yypt+1] - { - yyVAL.descriptors = *(yylex.(*parser).mergeMaps(&yyDollar[1].descriptors, &yyDollar[3].descriptors)) - } - case 164: - yyDollar = yyS[yypt-1 : yypt+1] - { - yyVAL.descriptors = yyDollar[1].descriptors - } case 165: - yyDollar = yyS[yypt-2 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] { - yylex.(*parser).unexpected("histogram description", "histogram description key, e.g. buckets:[5 10 7]") + m := yylex.(*parser).newMap() + yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&m) } case 166: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-2 : yypt+1] { - yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["schema"] = yyDollar[3].int + m := yylex.(*parser).newMap() + yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&m) } case 167: yyDollar = yyS[yypt-3 : yypt+1] { - yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["sum"] = yyDollar[3].float + yyVAL.descriptors = *(yylex.(*parser).mergeMaps(&yyDollar[1].descriptors, &yyDollar[3].descriptors)) } case 168: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-1 : yypt+1] { - yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["count"] = yyDollar[3].float + yyVAL.descriptors = yyDollar[1].descriptors } case 169: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-2 : yypt+1] { - yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["z_bucket"] = yyDollar[3].float + yylex.(*parser).unexpected("histogram description", "histogram description key, e.g. buckets:[5 10 7]") } case 170: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["z_bucket_w"] = yyDollar[3].float + yyVAL.descriptors["schema"] = yyDollar[3].int } case 171: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["custom_values"] = yyDollar[3].bucket_set + yyVAL.descriptors["sum"] = yyDollar[3].float } case 172: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["buckets"] = yyDollar[3].bucket_set + yyVAL.descriptors["count"] = yyDollar[3].float } case 173: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["offset"] = yyDollar[3].int + yyVAL.descriptors["z_bucket"] = yyDollar[3].float } case 174: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["n_buckets"] = yyDollar[3].bucket_set + yyVAL.descriptors["z_bucket_w"] = yyDollar[3].float } case 175: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["n_offset"] = yyDollar[3].int + yyVAL.descriptors["custom_values"] = yyDollar[3].bucket_set } case 176: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["counter_reset_hint"] = yyDollar[3].item + yyVAL.descriptors["buckets"] = yyDollar[3].bucket_set } case 177: - yyDollar = yyS[yypt-4 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] { - yyVAL.bucket_set = yyDollar[2].bucket_set + yyVAL.descriptors = yylex.(*parser).newMap() + yyVAL.descriptors["offset"] = yyDollar[3].int } case 178: yyDollar = yyS[yypt-3 : yypt+1] { - yyVAL.bucket_set = yyDollar[2].bucket_set + yyVAL.descriptors = yylex.(*parser).newMap() + yyVAL.descriptors["n_buckets"] = yyDollar[3].bucket_set } case 179: yyDollar = yyS[yypt-3 : yypt+1] { - yyVAL.bucket_set = append(yyDollar[1].bucket_set, yyDollar[3].float) + yyVAL.descriptors = yylex.(*parser).newMap() + yyVAL.descriptors["n_offset"] = yyDollar[3].int } case 180: + yyDollar = yyS[yypt-3 : yypt+1] + { + yyVAL.descriptors = yylex.(*parser).newMap() + yyVAL.descriptors["counter_reset_hint"] = yyDollar[3].item + } + case 181: + yyDollar = yyS[yypt-4 : yypt+1] + { + yyVAL.bucket_set = yyDollar[2].bucket_set + } + case 182: + yyDollar = yyS[yypt-3 : yypt+1] + { + yyVAL.bucket_set = yyDollar[2].bucket_set + } + case 183: + yyDollar = yyS[yypt-3 : yypt+1] + { + yyVAL.bucket_set = append(yyDollar[1].bucket_set, yyDollar[3].float) + } + case 184: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.bucket_set = []float64{yyDollar[1].float} } - case 236: + case 240: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.node = &NumberLiteral{ @@ -1977,7 +1993,7 @@ yydefault: PosRange: yyDollar[1].item.PositionRange(), } } - case 237: + case 241: yyDollar = yyS[yypt-1 : yypt+1] { var err error @@ -1992,12 +2008,12 @@ yydefault: Duration: true, } } - case 238: + case 242: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.float = yylex.(*parser).number(yyDollar[1].item.Val) } - case 239: + case 243: yyDollar = yyS[yypt-1 : yypt+1] { var err error @@ -2008,17 +2024,17 @@ yydefault: } yyVAL.float = dur.Seconds() } - case 240: + case 244: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.float = yyDollar[2].float } - case 241: + case 245: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.float = -yyDollar[2].float } - case 244: + case 248: yyDollar = yyS[yypt-1 : yypt+1] { var err error @@ -2027,17 +2043,17 @@ yydefault: yylex.(*parser).addParseErrf(yyDollar[1].item.PositionRange(), "invalid repetition in series values: %s", err) } } - case 245: + case 249: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.int = -int64(yyDollar[2].uint) } - case 246: + case 250: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.int = int64(yyDollar[1].uint) } - case 247: + case 251: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.node = &StringLiteral{ @@ -2045,7 +2061,7 @@ yydefault: PosRange: yyDollar[1].item.PositionRange(), } } - case 248: + case 252: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.item = Item{ @@ -2054,12 +2070,12 @@ yydefault: Val: yylex.(*parser).unquoteString(yyDollar[1].item.Val), } } - case 249: + case 253: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.strings = nil } - case 251: + case 255: yyDollar = yyS[yypt-1 : yypt+1] { nl := yyDollar[1].node.(*NumberLiteral) @@ -2070,7 +2086,7 @@ yydefault: } yyVAL.node = nl } - case 252: + case 256: yyDollar = yyS[yypt-2 : yypt+1] { nl := yyDollar[2].node.(*NumberLiteral) @@ -2085,7 +2101,7 @@ yydefault: nl.PosRange.Start = yyDollar[1].item.Pos yyVAL.node = nl } - case 253: + case 257: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2094,7 +2110,7 @@ yydefault: EndPos: yyDollar[3].item.PositionRange().End, } } - case 254: + case 258: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2107,7 +2123,7 @@ yydefault: StartPos: yyDollar[1].item.Pos, } } - case 255: + case 259: yyDollar = yyS[yypt-6 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2118,7 +2134,7 @@ yydefault: RHS: yyDollar[5].node.(Expr), } } - case 256: + case 260: yyDollar = yyS[yypt-7 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2134,7 +2150,7 @@ yydefault: }, } } - case 257: + case 261: yyDollar = yyS[yypt-4 : yypt+1] { de := yyDollar[3].node.(*DurationExpr) @@ -2149,7 +2165,7 @@ yydefault: } yyVAL.node = yyDollar[3].node } - case 261: + case 265: yyDollar = yyS[yypt-1 : yypt+1] { nl := yyDollar[1].node.(*NumberLiteral) @@ -2160,7 +2176,7 @@ yydefault: } yyVAL.node = nl } - case 262: + case 266: yyDollar = yyS[yypt-2 : yypt+1] { switch expr := yyDollar[2].node.(type) { @@ -2193,25 +2209,25 @@ yydefault: break } } - case 263: + case 267: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[1].node.(Expr)) yyVAL.node = &DurationExpr{Op: ADD, LHS: yyDollar[1].node.(Expr), RHS: yyDollar[3].node.(Expr)} } - case 264: + case 268: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[1].node.(Expr)) yyVAL.node = &DurationExpr{Op: SUB, LHS: yyDollar[1].node.(Expr), RHS: yyDollar[3].node.(Expr)} } - case 265: + case 269: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[1].node.(Expr)) yyVAL.node = &DurationExpr{Op: MUL, LHS: yyDollar[1].node.(Expr), RHS: yyDollar[3].node.(Expr)} } - case 266: + case 270: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[1].node.(Expr)) @@ -2222,7 +2238,7 @@ yydefault: } yyVAL.node = &DurationExpr{Op: DIV, LHS: yyDollar[1].node.(Expr), RHS: yyDollar[3].node.(Expr)} } - case 267: + case 271: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[1].node.(Expr)) @@ -2233,13 +2249,13 @@ yydefault: } yyVAL.node = &DurationExpr{Op: MOD, LHS: yyDollar[1].node.(Expr), RHS: yyDollar[3].node.(Expr)} } - case 268: + case 272: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[1].node.(Expr)) yyVAL.node = &DurationExpr{Op: POW, LHS: yyDollar[1].node.(Expr), RHS: yyDollar[3].node.(Expr)} } - case 269: + case 273: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2248,7 +2264,7 @@ yydefault: EndPos: yyDollar[3].item.PositionRange().End, } } - case 270: + case 274: yyDollar = yyS[yypt-6 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2259,7 +2275,7 @@ yydefault: RHS: yyDollar[5].node.(Expr), } } - case 272: + case 276: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[2].node.(Expr)) diff --git a/promql/parser/lex.go b/promql/parser/lex.go index 72bb77764a..949bc453e8 100644 --- a/promql/parser/lex.go +++ b/promql/parser/lex.go @@ -129,6 +129,8 @@ var key = map[string]ItemType{ // Keywords. "offset": OFFSET, + "smoothed": SMOOTHED, + "anchored": ANCHORED, "by": BY, "without": WITHOUT, "on": ON, diff --git a/promql/parser/parse.go b/promql/parser/parse.go index 85dc3c899b..3a76ddb44d 100644 --- a/promql/parser/parse.go +++ b/promql/parser/parse.go @@ -42,6 +42,9 @@ var parserPool = sync.Pool{ // ExperimentalDurationExpr is a flag to enable experimental duration expression parsing. var ExperimentalDurationExpr bool +// EnableExtendedRangeSelectors is a flag to enable experimental extended range selectors. +var EnableExtendedRangeSelectors bool + type Parser interface { ParseExpr() (Expr, error) Close() @@ -1021,6 +1024,52 @@ func (p *parser) addOffsetExpr(e Node, expr *DurationExpr) { *endPosp = p.lastClosing } +func (p *parser) setAnchored(e Node) { + if !EnableExtendedRangeSelectors { + p.addParseErrf(e.PositionRange(), "anchored modifier is experimental and not enabled") + return + } + switch s := e.(type) { + case *VectorSelector: + s.Anchored = true + if s.Smoothed { + p.addParseErrf(e.PositionRange(), "anchored and smoothed modifiers cannot be used together") + } + case *MatrixSelector: + s.VectorSelector.(*VectorSelector).Anchored = true + if s.VectorSelector.(*VectorSelector).Smoothed { + p.addParseErrf(e.PositionRange(), "anchored and smoothed modifiers cannot be used together") + } + case *SubqueryExpr: + p.addParseErrf(e.PositionRange(), "anchored modifier is not supported for subqueries") + default: + p.addParseErrf(e.PositionRange(), "anchored modifier not implemented") + } +} + +func (p *parser) setSmoothed(e Node) { + if !EnableExtendedRangeSelectors { + p.addParseErrf(e.PositionRange(), "smoothed modifier is experimental and not enabled") + return + } + switch s := e.(type) { + case *VectorSelector: + s.Smoothed = true + if s.Anchored { + p.addParseErrf(e.PositionRange(), "anchored and smoothed modifiers cannot be used together") + } + case *MatrixSelector: + s.VectorSelector.(*VectorSelector).Smoothed = true + if s.VectorSelector.(*VectorSelector).Anchored { + p.addParseErrf(e.PositionRange(), "anchored and smoothed modifiers cannot be used together") + } + case *SubqueryExpr: + p.addParseErrf(e.PositionRange(), "smoothed modifier is not supported for subqueries") + default: + p.addParseErrf(e.PositionRange(), "smoothed modifier not implemented") + } +} + // setTimestamp is used to set the timestamp from the @ modifier in the generated parser. func (p *parser) setTimestamp(e Node, ts float64) { if math.IsInf(ts, -1) || math.IsInf(ts, 1) || math.IsNaN(ts) || diff --git a/promql/parser/printer.go b/promql/parser/printer.go index 34448ab8c0..6bfc8d41e9 100644 --- a/promql/parser/printer.go +++ b/promql/parser/printer.go @@ -263,11 +263,18 @@ func (node *MatrixSelector) String() string { vecSelector.Timestamp = nil vecSelector.StartOrEnd = 0 + extendedAttribute := "" + switch { + case vecSelector.Anchored: + extendedAttribute = " anchored" + case vecSelector.Smoothed: + extendedAttribute = " smoothed" + } rangeStr := model.Duration(node.Range).String() if node.RangeExpr != nil { rangeStr = node.RangeExpr.String() } - str := fmt.Sprintf("%s[%s]%s%s", vecSelector.String(), rangeStr, at, offset) + str := fmt.Sprintf("%s[%s]%s%s%s", vecSelector.String(), rangeStr, extendedAttribute, at, offset) vecSelector.OriginalOffset, vecSelector.OriginalOffsetExpr, vecSelector.Timestamp, vecSelector.StartOrEnd = offsetVal, offsetExprVal, atVal, preproc @@ -380,6 +387,12 @@ func (node *VectorSelector) String() string { b.WriteString(" @ end()") } switch { + case node.Anchored: + b.WriteString(" anchored") + case node.Smoothed: + b.WriteString(" smoothed") + } + switch { case node.OriginalOffsetExpr != nil: b.WriteString(" offset ") node.OriginalOffsetExpr.writeTo(b) diff --git a/promql/promql_test.go b/promql/promql_test.go index 175b0a0d68..92d933f1ee 100644 --- a/promql/promql_test.go +++ b/promql/promql_test.go @@ -48,6 +48,11 @@ func TestConcurrentRangeQueries(t *testing.T) { } // Enable experimental functions testing parser.EnableExperimentalFunctions = true + parser.EnableExtendedRangeSelectors = true + t.Cleanup(func() { + parser.EnableExperimentalFunctions = false + parser.EnableExtendedRangeSelectors = false + }) engine := promqltest.NewTestEngineWithOpts(t, opts) const interval = 10000 // 10s interval. diff --git a/promql/promqltest/README.md b/promql/promqltest/README.md index 84a0e69f3a..d26c01c6f1 100644 --- a/promql/promqltest/README.md +++ b/promql/promqltest/README.md @@ -106,8 +106,44 @@ eval range from to step * `` and `` specify the time range of the range query, and use the same syntax as `