package metrics import ( "github.com/prometheus/client_golang/prometheus" ctrl "sigs.k8s.io/controller-runtime" v1patch "edge-infra.dev/pkg/sds/patching/k8s/apis/ienpatch/v1" "edge-infra.dev/pkg/k8s/runtime/controller/metrics" runtimeMetrics "edge-infra.dev/pkg/k8s/runtime/controller/metrics" ) type Metrics = runtimeMetrics.Metrics func PatchingMetrics(mgr ctrl.Manager) Metrics { metrics := runtimeMetrics.New(mgr, "patchctl", runtimeMetrics.WithSuspend(), runtimeMetrics.WithCollectors( PatchctlReadinessMetric, PatchctlDurationMetric, ), ) return metrics } type ReconcileTimeSet map[string]float64 type IControllerMetrics interface { RecordReadiness() recordDuration(controllerReconcileTime float64) RecordMetrics(controllerReconcileTime float64) } type ControllerMetrics struct { patch *v1patch.IENPatch hostname string currentVer string targetVer string } var PatchctlReadinessMetric prometheus.GaugeVec = *prometheus.NewGaugeVec( prometheus.GaugeOpts{ Name: metrics.Name("patch_manager", "reconcile_readiness"), Help: "Metric for patching readiness", }, []string{"hostname", "current_version", "target_version", "status", "message"}) var PatchctlDurationMetric prometheus.HistogramVec = *prometheus.NewHistogramVec( prometheus.HistogramOpts{ Name: metrics.Name("patch_manager", "reconcile_duration_seconds"), Help: "Metric for patch controllers and plugin reconcile duration in seconds", Buckets: prometheus.LinearBuckets(0.0, 0.2, 10), }, []string{"hostname", "current_version", "target_version", "status", "message"}) var lastPatchctlReadinessLabels prometheus.Labels var lastPatchctlDurationLabels prometheus.Labels func CreateNewControllerMetrics(patch *v1patch.IENPatch, hostname, currentVer, targetVer string) *ControllerMetrics { return &ControllerMetrics{ patch: patch, hostname: hostname, currentVer: currentVer, targetVer: targetVer, } } func (m *ControllerMetrics) RecordReadiness() { for _, condition := range m.patch.Status.Conditions { if condition.Type != m.hostname { continue } labels := prometheus.Labels{ "hostname": m.hostname, "target_version": m.targetVer, "current_version": m.currentVer, "status": condition.Reason, "message": condition.Message, } if len(lastPatchctlReadinessLabels) != 0 { PatchctlReadinessMetric.Delete(lastPatchctlReadinessLabels) } if condition.Status == "True" { PatchctlReadinessMetric.With(labels).Set(1) } else { PatchctlReadinessMetric.With(labels).Set(0) } lastPatchctlReadinessLabels = labels break } } func (m *ControllerMetrics) recordDuration(controllerReconcileTime float64) { for _, condition := range m.patch.Status.Conditions { if condition.Type != m.hostname { continue } labels := prometheus.Labels{ "hostname": m.hostname, "target_version": m.targetVer, "current_version": m.currentVer, "status": condition.Reason, "message": condition.Message, } if len(lastPatchctlDurationLabels) != 0 { PatchctlDurationMetric.Delete(lastPatchctlDurationLabels) } PatchctlDurationMetric.With(labels).Observe(controllerReconcileTime) lastPatchctlDurationLabels = labels break } } func (m *ControllerMetrics) RecordMetrics(controllerReconcileTime float64) { m.RecordReadiness() m.recordDuration(controllerReconcileTime) }