122 lines
2.3 KiB
Go
122 lines
2.3 KiB
Go
package osimage
|
|
|
|
import (
|
|
"k8s.io/klog/v2"
|
|
"time"
|
|
)
|
|
|
|
type progressState struct {
|
|
lastTime time.Time
|
|
lastPercent int64
|
|
lastBucket int64
|
|
}
|
|
|
|
type ProgressLogger struct {
|
|
minInterval time.Duration
|
|
bucketSize int64
|
|
states map[string]*progressState
|
|
}
|
|
|
|
func NewProgressLogger(minSeconds int, bucketSize int64) *ProgressLogger {
|
|
if minSeconds < 0 {
|
|
minSeconds = 0
|
|
}
|
|
if bucketSize <= 0 {
|
|
bucketSize = 10
|
|
}
|
|
|
|
return &ProgressLogger{
|
|
minInterval: time.Duration(minSeconds) * time.Second,
|
|
bucketSize: bucketSize,
|
|
states: make(map[string]*progressState),
|
|
}
|
|
}
|
|
|
|
func (l *ProgressLogger) state(stage string) *progressState {
|
|
s, ok := l.states[stage]
|
|
if ok {
|
|
return s
|
|
}
|
|
s = &progressState{
|
|
lastPercent: -1,
|
|
lastBucket: -1,
|
|
}
|
|
l.states[stage] = s
|
|
return s
|
|
}
|
|
|
|
func (l *ProgressLogger) Log(p Progress) {
|
|
if p.BytesTotal <= 0 {
|
|
return
|
|
}
|
|
|
|
percent := PercentOf(p.BytesComplete, p.BytesTotal)
|
|
|
|
now := time.Now()
|
|
bucket := percent / l.bucketSize
|
|
s := l.state(p.Stage)
|
|
|
|
// Always log first visible progress
|
|
if s.lastPercent == -1 {
|
|
s.lastPercent = percent
|
|
s.lastBucket = bucket
|
|
s.lastTime = now
|
|
klog.V(4).InfoS(p.Stage, "progress", percent)
|
|
return
|
|
}
|
|
|
|
// Always log completion once
|
|
if percent == 100 && s.lastPercent < 100 {
|
|
s.lastPercent = 100
|
|
s.lastBucket = 100 / l.bucketSize
|
|
s.lastTime = now
|
|
klog.V(4).InfoS(p.Stage, "progress", 100)
|
|
return
|
|
}
|
|
|
|
// Log if we crossed a new milestone bucket
|
|
if bucket > s.lastBucket {
|
|
s.lastPercent = percent
|
|
s.lastBucket = bucket
|
|
s.lastTime = now
|
|
klog.V(4).InfoS(p.Stage, "progress", percent)
|
|
return
|
|
}
|
|
|
|
// Otherwise allow a timed refresh if progress moved
|
|
if now.Sub(s.lastTime) >= l.minInterval && percent > s.lastPercent {
|
|
s.lastPercent = percent
|
|
s.lastTime = now
|
|
klog.V(4).InfoS(p.Stage, "progress", percent)
|
|
}
|
|
}
|
|
|
|
type TimeBasedUpdater struct {
|
|
interval time.Duration
|
|
lastRun time.Time
|
|
}
|
|
|
|
func NewTimeBasedUpdater(seconds int) *TimeBasedUpdater {
|
|
if seconds <= 0 {
|
|
seconds = 15
|
|
}
|
|
return &TimeBasedUpdater{
|
|
interval: time.Duration(seconds) * time.Second,
|
|
}
|
|
}
|
|
|
|
func (u *TimeBasedUpdater) Run(fn func() error) error {
|
|
now := time.Now()
|
|
|
|
if !u.lastRun.IsZero() && now.Sub(u.lastRun) < u.interval {
|
|
return nil
|
|
}
|
|
|
|
if err := fn(); err != nil {
|
|
return err
|
|
}
|
|
|
|
u.lastRun = now
|
|
return nil
|
|
}
|