You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
108 lines
3.0 KiB
Go
108 lines
3.0 KiB
Go
package metrics
|
|
|
|
import (
|
|
"github.com/containrrr/watchtower/pkg/types"
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"github.com/prometheus/client_golang/prometheus/promauto"
|
|
)
|
|
|
|
var metrics *Metrics
|
|
|
|
// Metric is the data points of a single scan
|
|
type Metric struct {
|
|
Scanned int
|
|
Updated int
|
|
Failed int
|
|
}
|
|
|
|
// Metrics is the handler processing all individual scan metrics
|
|
type Metrics struct {
|
|
channel chan *Metric
|
|
scanned prometheus.Gauge
|
|
updated prometheus.Gauge
|
|
failed prometheus.Gauge
|
|
total prometheus.Counter
|
|
skipped prometheus.Counter
|
|
}
|
|
|
|
// NewMetric returns a Metric with the counts taken from the appropriate types.Report fields
|
|
func NewMetric(report types.Report) *Metric {
|
|
return &Metric{
|
|
Scanned: len(report.Scanned()),
|
|
// Note: This is for backwards compatibility. ideally, stale containers should be counted separately
|
|
Updated: len(report.Updated()) + len(report.Stale()),
|
|
Failed: len(report.Failed()),
|
|
}
|
|
}
|
|
|
|
// QueueIsEmpty checks whether any messages are enqueued in the channel
|
|
func (metrics *Metrics) QueueIsEmpty() bool {
|
|
return len(metrics.channel) == 0
|
|
}
|
|
|
|
// Register registers metrics for an executed scan
|
|
func (metrics *Metrics) Register(metric *Metric) {
|
|
metrics.channel <- metric
|
|
}
|
|
|
|
// Default creates a new metrics handler if none exists, otherwise returns the existing one
|
|
func Default() *Metrics {
|
|
if metrics != nil {
|
|
return metrics
|
|
}
|
|
|
|
metrics = &Metrics{
|
|
scanned: promauto.NewGauge(prometheus.GaugeOpts{
|
|
Name: "watchtower_containers_scanned",
|
|
Help: "Number of containers scanned for changes by watchtower during the last scan",
|
|
}),
|
|
updated: promauto.NewGauge(prometheus.GaugeOpts{
|
|
Name: "watchtower_containers_updated",
|
|
Help: "Number of containers updated by watchtower during the last scan",
|
|
}),
|
|
failed: promauto.NewGauge(prometheus.GaugeOpts{
|
|
Name: "watchtower_containers_failed",
|
|
Help: "Number of containers where update failed during the last scan",
|
|
}),
|
|
total: promauto.NewCounter(prometheus.CounterOpts{
|
|
Name: "watchtower_scans_total",
|
|
Help: "Number of scans since the watchtower started",
|
|
}),
|
|
skipped: promauto.NewCounter(prometheus.CounterOpts{
|
|
Name: "watchtower_scans_skipped",
|
|
Help: "Number of skipped scans since watchtower started",
|
|
}),
|
|
channel: make(chan *Metric, 10),
|
|
}
|
|
|
|
go metrics.HandleUpdate(metrics.channel)
|
|
|
|
return metrics
|
|
}
|
|
|
|
// RegisterScan fetches a metric handler and enqueues a metric
|
|
func RegisterScan(metric *Metric) {
|
|
metrics := Default()
|
|
metrics.Register(metric)
|
|
}
|
|
|
|
// HandleUpdate dequeue the metric channel and processes it
|
|
func (metrics *Metrics) HandleUpdate(channel <-chan *Metric) {
|
|
for change := range channel {
|
|
if change == nil {
|
|
// Update was skipped and rescheduled
|
|
metrics.total.Inc()
|
|
metrics.skipped.Inc()
|
|
metrics.scanned.Set(0)
|
|
metrics.updated.Set(0)
|
|
metrics.failed.Set(0)
|
|
continue
|
|
}
|
|
// Update metrics with the new values
|
|
metrics.total.Inc()
|
|
metrics.scanned.Set(float64(change.Scanned))
|
|
metrics.updated.Set(float64(change.Updated))
|
|
metrics.failed.Set(float64(change.Failed))
|
|
}
|
|
}
|