mirror of
https://github.com/containrrr/watchtower.git
synced 2025-12-16 07:00:13 +01:00
Add metrics and progress report capabilities for deferred items seperate from other statuses
This commit is contained in:
parent
48bfaef350
commit
3c0441b94c
10 changed files with 84 additions and 43 deletions
|
|
@ -10,19 +10,21 @@ var metrics *Metrics
|
||||||
|
|
||||||
// Metric is the data points of a single scan
|
// Metric is the data points of a single scan
|
||||||
type Metric struct {
|
type Metric struct {
|
||||||
Scanned int
|
Scanned int
|
||||||
Updated int
|
Updated int
|
||||||
Failed int
|
Deferred int
|
||||||
|
Failed int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Metrics is the handler processing all individual scan metrics
|
// Metrics is the handler processing all individual scan metrics
|
||||||
type Metrics struct {
|
type Metrics struct {
|
||||||
channel chan *Metric
|
channel chan *Metric
|
||||||
scanned prometheus.Gauge
|
scanned prometheus.Gauge
|
||||||
updated prometheus.Gauge
|
updated prometheus.Gauge
|
||||||
failed prometheus.Gauge
|
deferred prometheus.Gauge
|
||||||
total prometheus.Counter
|
failed prometheus.Gauge
|
||||||
skipped prometheus.Counter
|
total prometheus.Counter
|
||||||
|
skipped prometheus.Counter
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMetric returns a Metric with the counts taken from the appropriate types.Report fields
|
// NewMetric returns a Metric with the counts taken from the appropriate types.Report fields
|
||||||
|
|
@ -30,8 +32,9 @@ func NewMetric(report types.Report) *Metric {
|
||||||
return &Metric{
|
return &Metric{
|
||||||
Scanned: len(report.Scanned()),
|
Scanned: len(report.Scanned()),
|
||||||
// Note: This is for backwards compatibility. ideally, stale containers should be counted separately
|
// Note: This is for backwards compatibility. ideally, stale containers should be counted separately
|
||||||
Updated: len(report.Updated()) + len(report.Stale()),
|
Updated: len(report.Updated()) + len(report.Stale()),
|
||||||
Failed: len(report.Failed()),
|
Deferred: len(report.Deferred()),
|
||||||
|
Failed: len(report.Failed()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,6 +63,10 @@ func Default() *Metrics {
|
||||||
Name: "watchtower_containers_updated",
|
Name: "watchtower_containers_updated",
|
||||||
Help: "Number of containers updated by watchtower during the last scan",
|
Help: "Number of containers updated by watchtower during the last scan",
|
||||||
}),
|
}),
|
||||||
|
deferred: promauto.NewGauge(prometheus.GaugeOpts{
|
||||||
|
Name: "watchtower_containers_deferred",
|
||||||
|
Help: "Number of containers deferred by watchtower during the last scan",
|
||||||
|
}),
|
||||||
failed: promauto.NewGauge(prometheus.GaugeOpts{
|
failed: promauto.NewGauge(prometheus.GaugeOpts{
|
||||||
Name: "watchtower_containers_failed",
|
Name: "watchtower_containers_failed",
|
||||||
Help: "Number of containers where update failed during the last scan",
|
Help: "Number of containers where update failed during the last scan",
|
||||||
|
|
@ -95,6 +102,7 @@ func (metrics *Metrics) HandleUpdate(channel <-chan *Metric) {
|
||||||
metrics.skipped.Inc()
|
metrics.skipped.Inc()
|
||||||
metrics.scanned.Set(0)
|
metrics.scanned.Set(0)
|
||||||
metrics.updated.Set(0)
|
metrics.updated.Set(0)
|
||||||
|
metrics.deferred.Set(0)
|
||||||
metrics.failed.Set(0)
|
metrics.failed.Set(0)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -102,6 +110,7 @@ func (metrics *Metrics) HandleUpdate(channel <-chan *Metric) {
|
||||||
metrics.total.Inc()
|
metrics.total.Inc()
|
||||||
metrics.scanned.Set(float64(change.Scanned))
|
metrics.scanned.Set(float64(change.Scanned))
|
||||||
metrics.updated.Set(float64(change.Updated))
|
metrics.updated.Set(float64(change.Updated))
|
||||||
|
metrics.deferred.Set(float64(change.Deferred))
|
||||||
metrics.failed.Set(float64(change.Failed))
|
metrics.failed.Set(float64(change.Failed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,13 @@ func (d Data) MarshalJSON() ([]byte, error) {
|
||||||
var report jsonMap
|
var report jsonMap
|
||||||
if d.Report != nil {
|
if d.Report != nil {
|
||||||
report = jsonMap{
|
report = jsonMap{
|
||||||
`scanned`: marshalReports(d.Report.Scanned()),
|
`scanned`: marshalReports(d.Report.Scanned()),
|
||||||
`updated`: marshalReports(d.Report.Updated()),
|
`updated`: marshalReports(d.Report.Updated()),
|
||||||
`failed`: marshalReports(d.Report.Failed()),
|
`deferred`: marshalReports(d.Report.Deferred()),
|
||||||
`skipped`: marshalReports(d.Report.Skipped()),
|
`failed`: marshalReports(d.Report.Failed()),
|
||||||
`stale`: marshalReports(d.Report.Stale()),
|
`skipped`: marshalReports(d.Report.Skipped()),
|
||||||
`fresh`: marshalReports(d.Report.Fresh()),
|
`stale`: marshalReports(d.Report.Stale()),
|
||||||
|
`fresh`: marshalReports(d.Report.Fresh()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ var _ = Describe("JSON template", func() {
|
||||||
],
|
],
|
||||||
"host": "Mock",
|
"host": "Mock",
|
||||||
"report": {
|
"report": {
|
||||||
|
"deferred": [],
|
||||||
"failed": [
|
"failed": [
|
||||||
{
|
{
|
||||||
"currentImageId": "01d210000000",
|
"currentImageId": "01d210000000",
|
||||||
|
|
@ -110,7 +111,7 @@ var _ = Describe("JSON template", func() {
|
||||||
},
|
},
|
||||||
"title": "Watchtower updates on Mock"
|
"title": "Watchtower updates on Mock"
|
||||||
}`
|
}`
|
||||||
data := mockDataFromStates(s.UpdatedState, s.FreshState, s.FailedState, s.SkippedState, s.UpdatedState)
|
data := mockDataFromStates(s.UpdatedState, s.DeferredState, s.FreshState, s.FailedState, s.SkippedState, s.UpdatedState)
|
||||||
Expect(getTemplatedResult(`json.v1`, false, data)).To(MatchJSON(expected))
|
Expect(getTemplatedResult(`json.v1`, false, data)).To(MatchJSON(expected))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,8 @@ func (pb *previewData) addContainer(c containerStatus) {
|
||||||
pb.report.scanned = append(pb.report.scanned, &c)
|
pb.report.scanned = append(pb.report.scanned, &c)
|
||||||
case UpdatedState:
|
case UpdatedState:
|
||||||
pb.report.updated = append(pb.report.updated, &c)
|
pb.report.updated = append(pb.report.updated, &c)
|
||||||
|
case DeferredState:
|
||||||
|
pb.report.deferred = append(pb.report.deferred, &c)
|
||||||
case FailedState:
|
case FailedState:
|
||||||
pb.report.failed = append(pb.report.failed, &c)
|
pb.report.failed = append(pb.report.failed, &c)
|
||||||
case SkippedState:
|
case SkippedState:
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,13 @@ import (
|
||||||
type State string
|
type State string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ScannedState State = "scanned"
|
ScannedState State = "scanned"
|
||||||
UpdatedState State = "updated"
|
UpdatedState State = "updated"
|
||||||
FailedState State = "failed"
|
DeferredState State = "deferred"
|
||||||
SkippedState State = "skipped"
|
FailedState State = "failed"
|
||||||
StaleState State = "stale"
|
SkippedState State = "skipped"
|
||||||
FreshState State = "fresh"
|
StaleState State = "stale"
|
||||||
|
FreshState State = "fresh"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StatesFromString parses a string of state characters and returns a slice of the corresponding report states
|
// StatesFromString parses a string of state characters and returns a slice of the corresponding report states
|
||||||
|
|
@ -27,6 +28,8 @@ func StatesFromString(str string) []State {
|
||||||
states = append(states, ScannedState)
|
states = append(states, ScannedState)
|
||||||
case 'u':
|
case 'u':
|
||||||
states = append(states, UpdatedState)
|
states = append(states, UpdatedState)
|
||||||
|
case 'd':
|
||||||
|
states = append(states, DeferredState)
|
||||||
case 'e':
|
case 'e':
|
||||||
states = append(states, FailedState)
|
states = append(states, FailedState)
|
||||||
case 'k':
|
case 'k':
|
||||||
|
|
@ -43,12 +46,13 @@ func StatesFromString(str string) []State {
|
||||||
}
|
}
|
||||||
|
|
||||||
type report struct {
|
type report struct {
|
||||||
scanned []types.ContainerReport
|
scanned []types.ContainerReport
|
||||||
updated []types.ContainerReport
|
updated []types.ContainerReport
|
||||||
failed []types.ContainerReport
|
deferred []types.ContainerReport
|
||||||
skipped []types.ContainerReport
|
failed []types.ContainerReport
|
||||||
stale []types.ContainerReport
|
skipped []types.ContainerReport
|
||||||
fresh []types.ContainerReport
|
stale []types.ContainerReport
|
||||||
|
fresh []types.ContainerReport
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *report) Scanned() []types.ContainerReport {
|
func (r *report) Scanned() []types.ContainerReport {
|
||||||
|
|
@ -57,6 +61,9 @@ func (r *report) Scanned() []types.ContainerReport {
|
||||||
func (r *report) Updated() []types.ContainerReport {
|
func (r *report) Updated() []types.ContainerReport {
|
||||||
return r.updated
|
return r.updated
|
||||||
}
|
}
|
||||||
|
func (r *report) Deferred() []types.ContainerReport {
|
||||||
|
return r.deferred
|
||||||
|
}
|
||||||
func (r *report) Failed() []types.ContainerReport {
|
func (r *report) Failed() []types.ContainerReport {
|
||||||
return r.failed
|
return r.failed
|
||||||
}
|
}
|
||||||
|
|
@ -87,6 +94,7 @@ func (r *report) All() []types.ContainerReport {
|
||||||
}
|
}
|
||||||
|
|
||||||
appendUnique(r.updated)
|
appendUnique(r.updated)
|
||||||
|
appendUnique(r.deferred)
|
||||||
appendUnique(r.failed)
|
appendUnique(r.failed)
|
||||||
appendUnique(r.skipped)
|
appendUnique(r.skipped)
|
||||||
appendUnique(r.stale)
|
appendUnique(r.stale)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ const (
|
||||||
SkippedState
|
SkippedState
|
||||||
ScannedState
|
ScannedState
|
||||||
UpdatedState
|
UpdatedState
|
||||||
|
DeferredState
|
||||||
FailedState
|
FailedState
|
||||||
FreshState
|
FreshState
|
||||||
StaleState
|
StaleState
|
||||||
|
|
@ -70,6 +71,8 @@ func (u *ContainerStatus) State() string {
|
||||||
return "Scanned"
|
return "Scanned"
|
||||||
case UpdatedState:
|
case UpdatedState:
|
||||||
return "Updated"
|
return "Updated"
|
||||||
|
case DeferredState:
|
||||||
|
return "Deferred"
|
||||||
case FailedState:
|
case FailedState:
|
||||||
return "Failed"
|
return "Failed"
|
||||||
case FreshState:
|
case FreshState:
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,11 @@ func (m Progress) MarkForUpdate(containerID types.ContainerID) {
|
||||||
m[containerID].state = UpdatedState
|
m[containerID].state = UpdatedState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkForUpdate marks the container identified by containerID for deferral
|
||||||
|
func (m Progress) MarkDeferred(containerID types.ContainerID) {
|
||||||
|
m[containerID].state = DeferredState
|
||||||
|
}
|
||||||
|
|
||||||
// Report creates a new Report from a Progress instance
|
// Report creates a new Report from a Progress instance
|
||||||
func (m Progress) Report() types.Report {
|
func (m Progress) Report() types.Report {
|
||||||
return NewReport(m)
|
return NewReport(m)
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type report struct {
|
type report struct {
|
||||||
scanned []types.ContainerReport
|
scanned []types.ContainerReport
|
||||||
updated []types.ContainerReport
|
updated []types.ContainerReport
|
||||||
failed []types.ContainerReport
|
deferred []types.ContainerReport
|
||||||
skipped []types.ContainerReport
|
failed []types.ContainerReport
|
||||||
stale []types.ContainerReport
|
skipped []types.ContainerReport
|
||||||
fresh []types.ContainerReport
|
stale []types.ContainerReport
|
||||||
|
fresh []types.ContainerReport
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *report) Scanned() []types.ContainerReport {
|
func (r *report) Scanned() []types.ContainerReport {
|
||||||
|
|
@ -21,6 +22,9 @@ func (r *report) Scanned() []types.ContainerReport {
|
||||||
func (r *report) Updated() []types.ContainerReport {
|
func (r *report) Updated() []types.ContainerReport {
|
||||||
return r.updated
|
return r.updated
|
||||||
}
|
}
|
||||||
|
func (r *report) Deferred() []types.ContainerReport {
|
||||||
|
return r.deferred
|
||||||
|
}
|
||||||
func (r *report) Failed() []types.ContainerReport {
|
func (r *report) Failed() []types.ContainerReport {
|
||||||
return r.failed
|
return r.failed
|
||||||
}
|
}
|
||||||
|
|
@ -50,6 +54,7 @@ func (r *report) All() []types.ContainerReport {
|
||||||
}
|
}
|
||||||
|
|
||||||
appendUnique(r.updated)
|
appendUnique(r.updated)
|
||||||
|
appendUnique(r.deferred)
|
||||||
appendUnique(r.failed)
|
appendUnique(r.failed)
|
||||||
appendUnique(r.skipped)
|
appendUnique(r.skipped)
|
||||||
appendUnique(r.stale)
|
appendUnique(r.stale)
|
||||||
|
|
@ -64,12 +69,13 @@ func (r *report) All() []types.ContainerReport {
|
||||||
// NewReport creates a types.Report from the supplied Progress
|
// NewReport creates a types.Report from the supplied Progress
|
||||||
func NewReport(progress Progress) types.Report {
|
func NewReport(progress Progress) types.Report {
|
||||||
report := &report{
|
report := &report{
|
||||||
scanned: []types.ContainerReport{},
|
scanned: []types.ContainerReport{},
|
||||||
updated: []types.ContainerReport{},
|
updated: []types.ContainerReport{},
|
||||||
failed: []types.ContainerReport{},
|
deferred: []types.ContainerReport{},
|
||||||
skipped: []types.ContainerReport{},
|
failed: []types.ContainerReport{},
|
||||||
stale: []types.ContainerReport{},
|
skipped: []types.ContainerReport{},
|
||||||
fresh: []types.ContainerReport{},
|
stale: []types.ContainerReport{},
|
||||||
|
fresh: []types.ContainerReport{},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, update := range progress {
|
for _, update := range progress {
|
||||||
|
|
@ -88,9 +94,13 @@ func NewReport(progress Progress) types.Report {
|
||||||
switch update.state {
|
switch update.state {
|
||||||
case UpdatedState:
|
case UpdatedState:
|
||||||
report.updated = append(report.updated, update)
|
report.updated = append(report.updated, update)
|
||||||
|
case DeferredState:
|
||||||
|
report.deferred = append(report.deferred, update)
|
||||||
case FailedState:
|
case FailedState:
|
||||||
report.failed = append(report.failed, update)
|
report.failed = append(report.failed, update)
|
||||||
default:
|
default:
|
||||||
|
// TODO: should this be changed to something lke UnknownState since it shouldn't be possible for a container
|
||||||
|
// to be stale but its state to not be either UpdatedState, DeferredState, or FailedState?
|
||||||
update.state = StaleState
|
update.state = StaleState
|
||||||
report.stale = append(report.stale, update)
|
report.stale = append(report.stale, update)
|
||||||
}
|
}
|
||||||
|
|
@ -98,6 +108,7 @@ func NewReport(progress Progress) types.Report {
|
||||||
|
|
||||||
sort.Sort(sortableContainers(report.scanned))
|
sort.Sort(sortableContainers(report.scanned))
|
||||||
sort.Sort(sortableContainers(report.updated))
|
sort.Sort(sortableContainers(report.updated))
|
||||||
|
sort.Sort(sortableContainers(report.deferred))
|
||||||
sort.Sort(sortableContainers(report.failed))
|
sort.Sort(sortableContainers(report.failed))
|
||||||
sort.Sort(sortableContainers(report.skipped))
|
sort.Sort(sortableContainers(report.skipped))
|
||||||
sort.Sort(sortableContainers(report.stale))
|
sort.Sort(sortableContainers(report.stale))
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ package types
|
||||||
type Report interface {
|
type Report interface {
|
||||||
Scanned() []ContainerReport
|
Scanned() []ContainerReport
|
||||||
Updated() []ContainerReport
|
Updated() []ContainerReport
|
||||||
|
Deferred() []ContainerReport
|
||||||
Failed() []ContainerReport
|
Failed() []ContainerReport
|
||||||
Skipped() []ContainerReport
|
Skipped() []ContainerReport
|
||||||
Stale() []ContainerReport
|
Stale() []ContainerReport
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ func main() {
|
||||||
var states string
|
var states string
|
||||||
var entries string
|
var entries string
|
||||||
|
|
||||||
flag.StringVar(&states, "states", "cccuuueeekkktttfff", "sCanned, Updated, failEd, sKipped, sTale, Fresh")
|
flag.StringVar(&states, "states", "cccuuudddeeekkktttfff", "sCanned, Updated, Deferred, failEd, sKipped, sTale, Fresh")
|
||||||
flag.StringVar(&entries, "entries", "ewwiiidddd", "Fatal,Error,Warn,Info,Debug,Trace")
|
flag.StringVar(&entries, "entries", "ewwiiidddd", "Fatal,Error,Warn,Info,Debug,Trace")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue