This is an automated email from the ASF dual-hosted git repository.

pcongiusti pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-k.git


The following commit(s) were added to refs/heads/main by this push:
     new 39ab1bc19 [chore] improve metrics for integration (#5154)
39ab1bc19 is described below

commit 39ab1bc19d8638ec593a762430c0461dd70ed8c4
Author: LuLo <flex.muscle...@icloud.com>
AuthorDate: Tue Mar 19 16:52:17 2024 +0100

    [chore] improve metrics for integration (#5154)
    
    * [chore] improve metrics for integration
    
    improve metrics for integrations, record a vector with integration_name and 
state
    
    * [chore] add tests
    
    * chore: change test dependency
    
    * solve go.mod conflict
    
    * chore: change test library and fix lint
---
 .../integration/integration_controller.go          |  2 +
 pkg/controller/integration/metrics.go              | 49 +++++++++----
 pkg/controller/integration/metrics_test.go         | 82 ++++++++++++++++++++++
 3 files changed, 121 insertions(+), 12 deletions(-)

diff --git a/pkg/controller/integration/integration_controller.go 
b/pkg/controller/integration/integration_controller.go
index d2b848752..a73179246 100644
--- a/pkg/controller/integration/integration_controller.go
+++ b/pkg/controller/integration/integration_controller.go
@@ -20,6 +20,7 @@ package integration
 import (
        "context"
        "fmt"
+
        "reflect"
        "time"
 
@@ -95,6 +96,7 @@ func integrationUpdateFunc(old *v1.Integration, it 
*v1.Integration) bool {
                timeToFirstReadiness.Observe(duration.Seconds())
        }
 
+       updateIntegrationPhase(it.Name, string(it.Status.Phase))
        // If traits have changed, the reconciliation loop must kick in as
        // traits may have impact
        sameTraits, err := trait.IntegrationsHaveSameTraits(old, it)
diff --git a/pkg/controller/integration/metrics.go 
b/pkg/controller/integration/metrics.go
index 46eb3f2ce..f235a0bc2 100644
--- a/pkg/controller/integration/metrics.go
+++ b/pkg/controller/integration/metrics.go
@@ -18,6 +18,7 @@ limitations under the License.
 package integration
 
 import (
+       "strings"
        "time"
 
        "sigs.k8s.io/controller-runtime/pkg/metrics"
@@ -25,21 +26,45 @@ import (
        "github.com/prometheus/client_golang/prometheus"
 )
 
-var timeToFirstReadiness = prometheus.NewHistogram(
-       prometheus.HistogramOpts{
-               Name: "camel_k_integration_first_readiness_seconds",
-               Help: "Camel K integration time to first readiness",
-               Buckets: []float64{
-                       5 * time.Second.Seconds(),
-                       10 * time.Second.Seconds(),
-                       30 * time.Second.Seconds(),
-                       1 * time.Minute.Seconds(),
-                       2 * time.Minute.Seconds(),
+var (
+       timeToFirstReadiness = prometheus.NewHistogram(
+               prometheus.HistogramOpts{
+                       Name: "camel_k_integration_first_readiness_seconds",
+                       Help: "Camel K integration time to first readiness",
+                       Buckets: []float64{
+                               5 * time.Second.Seconds(),
+                               10 * time.Second.Seconds(),
+                               30 * time.Second.Seconds(),
+                               1 * time.Minute.Seconds(),
+                               2 * time.Minute.Seconds(),
+                       },
                },
-       },
+       )
+
+       integration = prometheus.NewCounterVec(
+               prometheus.CounterOpts{
+                       Name: "camel_k_integration_phase_total",
+                       Help: "Number of integration processed",
+               }, []string{
+                       "phase",
+                       "id",
+               },
+       )
 )
 
 func init() {
        // Register custom metrics with the global prometheus registry
-       metrics.Registry.MustRegister(timeToFirstReadiness)
+       metrics.Registry.MustRegister(timeToFirstReadiness, integration)
+}
+
+func updateIntegrationPhase(iID string, p string) {
+       phase := strings.ReplaceAll(strings.ToLower(p), " ", "_")
+
+       if phase != "" && iID != "" {
+               labels := prometheus.Labels{
+                       "id":    iID,
+                       "phase": phase,
+               }
+               integration.With(labels).Inc()
+       }
 }
diff --git a/pkg/controller/integration/metrics_test.go 
b/pkg/controller/integration/metrics_test.go
new file mode 100644
index 000000000..5fce7b832
--- /dev/null
+++ b/pkg/controller/integration/metrics_test.go
@@ -0,0 +1,82 @@
+package integration
+
+import (
+       "github.com/prometheus/client_golang/prometheus"
+       dto "github.com/prometheus/client_model/go"
+       "github.com/stretchr/testify/assert"
+       "testing"
+)
+
+// getMetricValue returns the sum of the Counter metrics associated with the 
Collector
+// e.g. the metric for a non-vector, or the sum of the metrics for vector 
labels.
+// If the metric is a Histogram then number of samples is used.
+func getMetricValue(col prometheus.Collector) float64 {
+       var total float64
+       collect(col, func(m *dto.Metric) {
+               if h := m.GetHistogram(); h != nil {
+                       total += float64(h.GetSampleCount())
+               } else {
+                       total += m.GetCounter().GetValue()
+               }
+       })
+       return total
+}
+
+// collect calls the function for each metric associated with the Collector
+func collect(col prometheus.Collector, do func(*dto.Metric)) {
+       c := make(chan prometheus.Metric)
+       go func(c chan prometheus.Metric) {
+               col.Collect(c)
+               close(c)
+       }(c)
+       for x := range c { // eg range across distinct label vector values
+               m := dto.Metric{}
+               _ = x.Write(&m)
+               do(&m)
+       }
+}
+
+func Test_updateIntegrationPhase(t *testing.T) {
+       type args struct {
+               iId      string
+               p        string
+               expected float64
+       }
+       tests := []struct {
+               name string
+               args args
+       }{
+               {
+                       name: "test should fail with empty id", args: args{
+                               iId:      "",
+                               p:        "running",
+                               expected: 0,
+                       },
+               },
+               {
+                       name: "test should fail with empty phase", args: args{
+                               iId:      "int-1",
+                               p:        "",
+                               expected: 0,
+                       },
+               },
+               {
+                       name: "test should pass and increase the counter", 
args: args{
+                               iId:      "int-1",
+                               p:        "running",
+                               expected: 1,
+                       },
+               },
+       }
+       for _, tt := range tests {
+               //              integration.Reset()
+               t.Run(tt.name, func(t *testing.T) {
+                       updateIntegrationPhase(tt.args.iId, tt.args.p)
+                       labels := map[string]string{"phase": tt.args.p, "id": 
tt.args.iId}
+                       if i, err := integration.GetMetricWith(labels); err == 
nil {
+                               val := getMetricValue(i)
+                               assert.Equal(t, val, tt.args.expected)
+                       }
+               })
+       }
+}

Reply via email to