feat: Add build attempt counter metric
diff --git a/pkg/controller/build/metrics.go b/pkg/controller/build/metrics.go
index b61034c..64286ce 100644
--- a/pkg/controller/build/metrics.go
+++ b/pkg/controller/build/metrics.go
@@ -25,9 +25,18 @@
 	"github.com/prometheus/client_golang/prometheus"
 )
 
-const buildResult = "result"
+const buildResultLabel = "result"
 
 var (
+	buildAttempt = prometheus.NewCounterVec(
+		prometheus.CounterOpts{
+			Name: "camel_k_build_attempt",
+			Help: "Camel K build attempt",
+		},
+		[]string{
+			buildResultLabel,
+		})
+
 	buildDuration = prometheus.NewHistogramVec(
 		prometheus.HistogramOpts{
 			Name: "camel_k_build_duration_seconds",
@@ -42,7 +51,7 @@
 			},
 		},
 		[]string{
-			buildResult,
+			buildResultLabel,
 		},
 	)
 
@@ -63,5 +72,5 @@
 
 func init() {
 	// Register custom metrics with the global prometheus registry
-	metrics.Registry.MustRegister(buildDuration, queueDuration)
+	metrics.Registry.MustRegister(buildAttempt, buildDuration, queueDuration)
 }
diff --git a/pkg/controller/build/monitor_pod.go b/pkg/controller/build/monitor_pod.go
index 23ebbee..15b3f87 100644
--- a/pkg/controller/build/monitor_pod.go
+++ b/pkg/controller/build/monitor_pod.go
@@ -69,6 +69,8 @@
 		build.Status.Phase = v1.BuildPhaseSucceeded
 		duration := metav1.Now().Sub(build.Status.StartedAt.Time)
 		build.Status.Duration = duration.String()
+		// Account for the Build metrics
+		buildAttempt.WithLabelValues(string(build.Status.Phase)).Inc()
 		buildDuration.WithLabelValues(string(build.Status.Phase)).Observe(duration.Seconds())
 		for _, task := range build.Spec.Tasks {
 			if task.Image != nil {
@@ -88,6 +90,8 @@
 		build.Status.Phase = v1.BuildPhaseFailed
 		duration := metav1.Now().Sub(build.Status.StartedAt.Time)
 		build.Status.Duration = duration.String()
+		// Account for the Build metrics
+		buildAttempt.WithLabelValues(string(build.Status.Phase)).Inc()
 		buildDuration.WithLabelValues(string(build.Status.Phase)).Observe(duration.Seconds())
 	}
 
diff --git a/pkg/controller/build/monitor_routine.go b/pkg/controller/build/monitor_routine.go
index 7bdf769..c0ccd65 100644
--- a/pkg/controller/build/monitor_routine.go
+++ b/pkg/controller/build/monitor_routine.go
@@ -53,7 +53,7 @@
 		// and recover the build if it's missing. This can happen when the operator
 		// stops abruptly and restarts or the build status update fails.
 		build.Status.Phase = v1.BuildPhaseFailed
-
+		buildAttempt.WithLabelValues(string(build.Status.Phase)).Inc()
 		return build, nil
 	}
 
diff --git a/pkg/controller/build/recovery.go b/pkg/controller/build/recovery.go
index 0c6cc9c..b8d7bb8 100644
--- a/pkg/controller/build/recovery.go
+++ b/pkg/controller/build/recovery.go
@@ -69,6 +69,7 @@
 
 	if build.Status.Failure.Recovery.Attempt >= build.Status.Failure.Recovery.AttemptMax {
 		build.Status.Phase = v1.BuildPhaseError
+		buildAttempt.WithLabelValues(string(build.Status.Phase)).Inc()
 		return build, nil
 	}
 
diff --git a/pkg/controller/build/schedule_routine.go b/pkg/controller/build/schedule_routine.go
index a48f346..f0e22a0 100644
--- a/pkg/controller/build/schedule_routine.go
+++ b/pkg/controller/build/schedule_routine.go
@@ -128,6 +128,8 @@
 					task.GetName()),
 				Duration: duration.String(),
 			}
+			// Account for the Build metrics
+			buildAttempt.WithLabelValues(string(status.Phase)).Inc()
 			buildDuration.WithLabelValues(string(status.Phase)).Observe(duration.Seconds())
 			_ = action.updateBuildStatus(ctx, build, status)
 			break
@@ -142,6 +144,8 @@
 		if lastTask || taskFailed {
 			duration := metav1.Now().Sub(build.Status.StartedAt.Time)
 			status.Duration = duration.String()
+			// Account for the Build metrics
+			buildAttempt.WithLabelValues(string(status.Phase)).Inc()
 			buildDuration.WithLabelValues(string(status.Phase)).Observe(duration.Seconds())
 		}
 		err := action.updateBuildStatus(ctx, build, status)