Skip to content

Commit

Permalink
Record canary duration and total
Browse files Browse the repository at this point in the history
- add Prometheus metrics canary_duration_seconds and canary_total
  • Loading branch information
stefanprodan committed Oct 29, 2018
1 parent 1b21080 commit 580924e
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 17 deletions.
46 changes: 38 additions & 8 deletions pkg/controller/recorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,35 @@ package controller

import (
"fmt"
"time"

"github.com/prometheus/client_golang/prometheus"
flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1"
)

// CanaryRecorder records the canary analysis as Prometheus metrics
type CanaryRecorder struct {
status *prometheus.GaugeVec
weight *prometheus.GaugeVec
duration *prometheus.HistogramVec
total *prometheus.GaugeVec
status *prometheus.GaugeVec
weight *prometheus.GaugeVec
}

// NewCanaryRecorder creates a new recorder and registers the Prometheus metrics
func NewCanaryRecorder(register bool) CanaryRecorder {
duration := prometheus.NewHistogramVec(prometheus.HistogramOpts{
Subsystem: controllerAgentName,
Name: "canary_duration_seconds",
Help: "Seconds spent performing canary analysis.",
Buckets: prometheus.DefBuckets,
}, []string{"name", "namespace"})

total := prometheus.NewGaugeVec(prometheus.GaugeOpts{
Subsystem: controllerAgentName,
Name: "canary_total",
Help: "Total number of canary object",
}, []string{"namespace"})

// 0 - running, 1 - successful, 2 - failed
status := prometheus.NewGaugeVec(prometheus.GaugeOpts{
Subsystem: controllerAgentName,
Expand All @@ -29,18 +45,32 @@ func NewCanaryRecorder(register bool) CanaryRecorder {
}, []string{"workload", "namespace"})

if register {
prometheus.MustRegister(duration)
prometheus.MustRegister(total)
prometheus.MustRegister(status)
prometheus.MustRegister(weight)
}

return CanaryRecorder{
status: status,
weight: weight,
duration: duration,
total: total,
status: status,
weight: weight,
}
}

// RecordStatus sets the last known canary analysis status
func (cr *CanaryRecorder) RecordStatus(cd *flaggerv1.Canary) {
// SetDuration sets the time spent in seconds performing canary analysis
func (cr *CanaryRecorder) SetDuration(cd *flaggerv1.Canary, duration time.Duration) {
cr.duration.WithLabelValues(cd.Spec.TargetRef.Name, cd.Namespace).Observe(duration.Seconds())
}

// SetTotal sets the total number of canaries per namespace
func (cr *CanaryRecorder) SetTotal(namespace string, total int) {
cr.total.WithLabelValues(namespace).Set(float64(total))
}

// SetStatus sets the last known canary analysis status
func (cr *CanaryRecorder) SetStatus(cd *flaggerv1.Canary) {
status := 1
switch cd.Status.State {
case "running":
Expand All @@ -53,8 +83,8 @@ func (cr *CanaryRecorder) RecordStatus(cd *flaggerv1.Canary) {
cr.status.WithLabelValues(cd.Spec.TargetRef.Name, cd.Namespace).Set(float64(status))
}

// RecordWeight sets the weight values for primary and canary destinations
func (cr *CanaryRecorder) RecordWeight(cd *flaggerv1.Canary, primary int, canary int) {
// SetWeight sets the weight values for primary and canary destinations
func (cr *CanaryRecorder) SetWeight(cd *flaggerv1.Canary, primary int, canary int) {
cr.weight.WithLabelValues(fmt.Sprintf("%s-primary", cd.Spec.TargetRef.Name), cd.Namespace).Set(float64(primary))
cr.weight.WithLabelValues(cd.Spec.TargetRef.Name, cd.Namespace).Set(float64(canary))
}
34 changes: 25 additions & 9 deletions pkg/controller/scheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,28 @@ import (
)

func (c *Controller) scheduleCanaries() {
stats := make(map[string]int)
c.canaries.Range(func(key interface{}, value interface{}) bool {
r := value.(*flaggerv1.Canary)
if r.Spec.TargetRef.Kind == "Deployment" {
go c.advanceCanary(r.Name, r.Namespace)
}

t, ok := stats[r.Namespace]
if !ok {
stats[r.Namespace] = 1
} else {
stats[r.Namespace] = t + 1
}
return true
})
for k, v := range stats {
c.recorder.SetTotal(k, v)
}
}

func (c *Controller) advanceCanary(name string, namespace string) {
begin := time.Now()
// check if the canary exists
cd, err := c.flaggerClient.FlaggerV1alpha1().Canaries(namespace).Get(name, v1.GetOptions{})
if err != nil {
Expand Down Expand Up @@ -58,13 +70,17 @@ func (c *Controller) advanceCanary(name string, namespace string) {
return
}

c.recorder.RecordWeight(cd, primaryRoute.Weight, canaryRoute.Weight)
c.recorder.SetWeight(cd, primaryRoute.Weight, canaryRoute.Weight)

// check if canary analysis should start (canary revision has changes) or continue
if ok := c.checkCanaryStatus(cd, c.deployer); !ok {
return
}

defer func() {
c.recorder.SetDuration(cd, time.Since(begin))
}()

// check if the number of failed checks reached the threshold
if cd.Status.State == "running" && cd.Status.FailedChecks >= cd.Spec.CanaryAnalysis.Threshold {
c.recordEventWarningf(cd, "Rolling back %s.%s failed checks threshold reached %v",
Expand All @@ -78,7 +94,7 @@ func (c *Controller) advanceCanary(name string, namespace string) {
return
}

c.recorder.RecordWeight(cd, primaryRoute.Weight, canaryRoute.Weight)
c.recorder.SetWeight(cd, primaryRoute.Weight, canaryRoute.Weight)
c.recordEventWarningf(cd, "Canary failed! Scaling down %s.%s",
cd.Spec.TargetRef.Name, cd.Namespace)

Expand All @@ -93,7 +109,7 @@ func (c *Controller) advanceCanary(name string, namespace string) {
c.logger.Errorf("%v", err)
return
}
c.recorder.RecordStatus(cd)
c.recorder.SetStatus(cd)
return
}

Expand Down Expand Up @@ -127,7 +143,7 @@ func (c *Controller) advanceCanary(name string, namespace string) {
return
}

c.recorder.RecordWeight(cd, primaryRoute.Weight, canaryRoute.Weight)
c.recorder.SetWeight(cd, primaryRoute.Weight, canaryRoute.Weight)
c.recordEventInfof(cd, "Advance %s.%s canary weight %v", cd.Name, cd.Namespace, canaryRoute.Weight)

// promote canary
Expand All @@ -149,7 +165,7 @@ func (c *Controller) advanceCanary(name string, namespace string) {
return
}

c.recorder.RecordWeight(cd, primaryRoute.Weight, canaryRoute.Weight)
c.recorder.SetWeight(cd, primaryRoute.Weight, canaryRoute.Weight)
c.recordEventInfof(cd, "Promotion completed! Scaling down %s.%s", cd.Spec.TargetRef.Name, cd.Namespace)

// shutdown canary
Expand All @@ -163,13 +179,13 @@ func (c *Controller) advanceCanary(name string, namespace string) {
c.recordEventWarningf(cd, "%v", err)
return
}
c.recorder.RecordStatus(cd)
c.recorder.SetStatus(cd)
}
}

func (c *Controller) checkCanaryStatus(cd *flaggerv1.Canary, deployer CanaryDeployer) bool {
c.recorder.SetStatus(cd)
if cd.Status.State == "running" {
c.recorder.RecordStatus(cd)
return true
}

Expand All @@ -178,7 +194,7 @@ func (c *Controller) checkCanaryStatus(cd *flaggerv1.Canary, deployer CanaryDepl
c.logger.Errorf("%v", err)
return false
}
c.recorder.RecordStatus(cd)
c.recorder.SetStatus(cd)
c.recordEventInfof(cd, "Initialization done! %s.%s", cd.Name, cd.Namespace)
return false
}
Expand All @@ -193,7 +209,7 @@ func (c *Controller) checkCanaryStatus(cd *flaggerv1.Canary, deployer CanaryDepl
c.logger.Errorf("%v", err)
return false
}
c.recorder.RecordStatus(cd)
c.recorder.SetStatus(cd)
return false
}
return false
Expand Down

0 comments on commit 580924e

Please sign in to comment.