Skip to content

Commit

Permalink
add metrics instrumentation for status updater
Browse files Browse the repository at this point in the history
Signed-off-by: shawnh2 <shawnhxh@outlook.com>
  • Loading branch information
shawnh2 committed May 8, 2024
1 parent 239fdd7 commit 00a217f
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 9 deletions.
2 changes: 1 addition & 1 deletion internal/metrics/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

package metrics

// Options encode changes to the options passed to a Metric at creation time.
// MetricOption encode changes to the options passed to a Metric at creation time.
type MetricOption func(*MetricOptions)

type MetricOptions struct {
Expand Down
20 changes: 20 additions & 0 deletions internal/provider/kubernetes/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright Envoy Gateway Authors
// SPDX-License-Identifier: Apache-2.0
// The full text of the Apache license is available in the LICENSE file at
// the root of the repo.

package kubernetes

import "github.com/envoyproxy/gateway/internal/metrics"

var (
statusUpdateTotal = metrics.NewCounter("status_update_total", "Total number of status updates by object kind.")
statusUpdateFailed = metrics.NewCounter("status_update_failed_total", "Number of status updates that failed by object kind.")
statusUpdateConflict = metrics.NewCounter("status_update_conflict_total", "Number of status update conflicts encountered by object kind.")
statusUpdateNotFound = metrics.NewCounter("status_update_not_found_total", "Number of status update that not found by object kind.")
statusUpdateSuccess = metrics.NewCounter("status_update_success_total", "Number of status updates that succeeded by object kind.")
statusUpdateNoop = metrics.NewCounter("status_update_noop_total", "Number of status updates that are no-ops by object kind. This is a subset of successful status updates.")
statusUpdateDurationSeconds = metrics.NewHistogram("status_update_duration_seconds", "How long a status update takes to finish.", []float64{0.001, 0.01, 0.1, 1, 5, 10})

kindLabel = metrics.NewLabel("kind")
)
48 changes: 40 additions & 8 deletions internal/provider/kubernetes/status_updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package kubernetes

import (
"context"
"time"

"github.com/go-logr/logr"
"github.com/google/go-cmp/cmp"
Expand Down Expand Up @@ -66,31 +67,62 @@ func NewUpdateHandler(log logr.Logger, client client.Client) *UpdateHandler {
}

func (u *UpdateHandler) apply(update Update) {
if err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
obj := update.Resource
var (
statusUpdateErr error

startTime = time.Now()
obj = update.Resource
objKind = obj.GetObjectKind().GroupVersionKind().Kind
)

statusUpdateTotal.With(kindLabel.Value(objKind)).Increment()

defer func() {
updateDuration := time.Since(startTime)
statusUpdateDurationSeconds.With(kindLabel.Value(objKind)).Record(updateDuration.Seconds())

if statusUpdateErr != nil {
statusUpdateFailed.With(kindLabel.Value(objKind)).Increment()
} else {
statusUpdateSuccess.With(kindLabel.Value(objKind)).Increment()
}
}()

if statusUpdateErr = retry.OnError(retry.DefaultBackoff, func(err error) bool {
if kerrors.IsConflict(err) {
statusUpdateConflict.With(kindLabel.Value(objKind)).Increment()
return true
}

if kerrors.IsNotFound(err) {
statusUpdateNotFound.With(kindLabel.Value(objKind)).Increment()
return true
}

return false
}, func() error {
// Get the resource.
if err := u.client.Get(context.Background(), update.NamespacedName, obj); err != nil {
if kerrors.IsNotFound(err) {
return nil
}
return err
}

newObj := update.Mutator.Mutate(obj)

if isStatusEqual(obj, newObj) {
statusUpdateNoop.With(kindLabel.Value(objKind)).Increment()

u.log.WithName(update.NamespacedName.Name).
WithName(update.NamespacedName.Namespace).
Info("status unchanged, bypassing update")

return nil
}

newObj.SetUID(obj.GetUID())

return u.client.Status().Update(context.Background(), newObj)
}); err != nil {
u.log.Error(err, "unable to update status", "name", update.NamespacedName.Name,
}); statusUpdateErr != nil {
u.log.Error(statusUpdateErr, "unable to update status", "name", update.NamespacedName.Name,
"namespace", update.NamespacedName.Namespace)
}
}
Expand Down Expand Up @@ -233,7 +265,7 @@ func isStatusEqual(objA, objB interface{}) bool {
return true
}
}
case gwapiv1a3.BackendTLSPolicy:
case *gwapiv1a3.BackendTLSPolicy:
if b, ok := objB.(*gwapiv1a3.BackendTLSPolicy); ok {
if cmp.Equal(a.Status, b.Status, opts) {
return true
Expand Down

0 comments on commit 00a217f

Please sign in to comment.