knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/observability/metrics/k8s/workqueue.go (about) 1 /* 2 Copyright 2025 The Knative Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package k8s 18 19 import ( 20 "go.opentelemetry.io/otel" 21 "go.opentelemetry.io/otel/attribute" 22 "go.opentelemetry.io/otel/metric" 23 24 "k8s.io/client-go/util/workqueue" 25 26 "knative.dev/pkg/observability/attributekey" 27 ) 28 29 var nameKey = attributekey.String("name") 30 31 type WorkqueueMetricsProvider struct { 32 depth metric.Int64UpDownCounter 33 adds metric.Int64Counter 34 latency metric.Float64Histogram 35 workDuration metric.Float64Histogram 36 unfinishedWork metric.Float64Gauge 37 longestRunning metric.Float64Gauge 38 retries metric.Int64Counter 39 } 40 41 type options struct { 42 meterProvider metric.MeterProvider 43 } 44 45 type Option func(*options) 46 47 func WithMeterProvider(p metric.MeterProvider) Option { 48 return func(o *options) { 49 if p != nil { 50 o.meterProvider = p 51 } 52 } 53 } 54 55 func NewWorkqueueMetricsProvider(opts ...Option) (*WorkqueueMetricsProvider, error) { 56 options := options{ 57 meterProvider: otel.GetMeterProvider(), 58 } 59 var err error 60 61 for _, opt := range opts { 62 opt(&options) 63 } 64 65 meter := options.meterProvider.Meter(scopeName) 66 67 w := &WorkqueueMetricsProvider{} 68 69 w.depth, err = meter.Int64UpDownCounter( 70 "kn.workqueue.depth", 71 metric.WithDescription("Number of current items in the queue"), 72 metric.WithUnit("{item}"), 73 ) 74 if err != nil { 75 return nil, err 76 } 77 78 w.adds, err = meter.Int64Counter( 79 "kn.workqueue.adds", 80 metric.WithDescription("Number of items added to the queue"), 81 metric.WithUnit("{item}"), 82 ) 83 if err != nil { 84 return nil, err 85 } 86 87 w.latency, err = meter.Float64Histogram( 88 "kn.workqueue.queue.duration", 89 metric.WithDescription("How long an item stays in workqueue"), 90 metric.WithUnit("s"), 91 metric.WithExplicitBucketBoundaries(0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10), 92 ) 93 if err != nil { 94 return nil, err 95 } 96 97 w.workDuration, err = meter.Float64Histogram( 98 "kn.workqueue.process.duration", 99 metric.WithUnit("How long in seconds processing an item from workqueue takes"), 100 metric.WithUnit("s"), 101 metric.WithExplicitBucketBoundaries(0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10), 102 ) 103 if err != nil { 104 return nil, err 105 } 106 107 w.unfinishedWork, err = meter.Float64Gauge( 108 "kn.workqueue.unfinished_work", 109 metric.WithUnit("s"), 110 ) 111 if err != nil { 112 return nil, err 113 } 114 115 w.longestRunning, err = meter.Float64Gauge( 116 "kn.workqueue.longest_running_processor", 117 metric.WithUnit("s"), 118 ) 119 if err != nil { 120 return nil, err 121 } 122 123 w.retries, err = meter.Int64Counter( 124 "kn.workqueue.retries", 125 metric.WithDescription("Number of items re-added to the queue"), 126 metric.WithUnit("{item}"), 127 ) 128 if err != nil { 129 return nil, err 130 } 131 132 return w, nil 133 } 134 135 func (p *WorkqueueMetricsProvider) NewDepthMetric(name string) workqueue.GaugeMetric { 136 return &gauge{m: p.depth, attrs: attrs(name)} 137 } 138 139 func (p *WorkqueueMetricsProvider) NewAddsMetric(name string) workqueue.CounterMetric { 140 return &counter{m: p.adds, attrs: attrs(name)} 141 } 142 143 func (p *WorkqueueMetricsProvider) NewLatencyMetric(name string) workqueue.HistogramMetric { 144 return &histogram{m: p.latency, attrs: attrs(name)} 145 } 146 147 func (p *WorkqueueMetricsProvider) NewWorkDurationMetric(name string) workqueue.HistogramMetric { 148 return &histogram{m: p.workDuration, attrs: attrs(name)} 149 } 150 151 func (p *WorkqueueMetricsProvider) NewUnfinishedWorkSecondsMetric(name string) workqueue.SettableGaugeMetric { 152 return &settableGauge{m: p.unfinishedWork, attrs: attrs(name)} 153 } 154 155 func (p *WorkqueueMetricsProvider) NewLongestRunningProcessorSecondsMetric(name string) workqueue.SettableGaugeMetric { 156 return &settableGauge{m: p.longestRunning, attrs: attrs(name)} 157 } 158 159 func (p *WorkqueueMetricsProvider) NewRetriesMetric(name string) workqueue.CounterMetric { 160 return &counter{m: p.retries, attrs: attrs(name)} 161 } 162 163 var _ workqueue.MetricsProvider = (*WorkqueueMetricsProvider)(nil) 164 165 func attrs(name string) attribute.Set { 166 return attribute.NewSet(nameKey.With(name)) 167 }