Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
507 changes: 507 additions & 0 deletions internal/buildapi/flash.go

Large diffs are not rendered by default.

64 changes: 64 additions & 0 deletions internal/buildapi/flash_metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package buildapi

import (
"fmt"
"time"

"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)

const (
flashMetricsNamespace = "ado"
flashMetricsSubsystem = "flash"
)

var (
// FlashCreatedTotal counts standalone flash operations created via the REST API.
FlashCreatedTotal = prometheus.NewCounter(
prometheus.CounterOpts{
Namespace: flashMetricsNamespace,
Subsystem: flashMetricsSubsystem,
Name: "created_total",
Help: "Total number of flash operations created",
},
)

// FlashRequestDuration tracks flash API request duration by endpoint and status code.
FlashRequestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Namespace: flashMetricsNamespace,
Subsystem: flashMetricsSubsystem,
Name: "request_duration_seconds",
Help: "Flash API request duration in seconds",
Buckets: prometheus.DefBuckets,
},
[]string{"endpoint", "status_code"},
)
)

func init() {
prometheus.MustRegister(
FlashCreatedTotal,
FlashRequestDuration,
)
}

func flashMetricsMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
c.Next()
duration := time.Since(start).Seconds()
endpoint := c.FullPath()
statusCode := fmt.Sprintf("%d", c.Writer.Status())
FlashRequestDuration.WithLabelValues(endpoint, statusCode).Observe(duration)
}
}

func metricsHandler() gin.HandlerFunc {
h := promhttp.Handler()
return func(c *gin.Context) {
h.ServeHTTP(c.Writer, c.Request)
}
}
68 changes: 68 additions & 0 deletions internal/buildapi/flash_metrics_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package buildapi

import (
"net/http"
"net/http/httptest"

"github.com/gin-gonic/gin"
"github.com/go-logr/logr"
. "github.com/onsi/ginkgo/v2" //nolint:revive // Dot import is standard for Ginkgo
. "github.com/onsi/gomega" //nolint:revive // Dot import is standard for Gomega
io_prometheus_client "github.com/prometheus/client_model/go"
)

var _ = Describe("Flash Metrics", func() {
var server *APIServer

BeforeEach(func() {
gin.SetMode(gin.TestMode)
server = NewAPIServer(":0", logr.Discard())
})

Context("metrics endpoint", func() {
It("should expose prometheus metrics at /metrics", func() {
// Ensure at least one observation so the histogram appears
FlashRequestDuration.WithLabelValues("/v1/flash", "200").Observe(0.001)

req, err := http.NewRequest("GET", "/metrics", nil)
Expect(err).NotTo(HaveOccurred())

w := httptest.NewRecorder()
server.router.ServeHTTP(w, req)

Expect(w.Code).To(Equal(http.StatusOK))
body := w.Body.String()
Expect(body).To(ContainSubstring("ado_flash_created_total"))
Expect(body).To(ContainSubstring("ado_flash_request_duration_seconds"))
})
})

Context("FlashCreatedTotal", func() {
It("should increment on flash creation", func() {
m := &io_prometheus_client.Metric{}
Expect(FlashCreatedTotal.Write(m)).To(Succeed())
before := m.GetCounter().GetValue()

FlashCreatedTotal.Inc()

m = &io_prometheus_client.Metric{}
Expect(FlashCreatedTotal.Write(m)).To(Succeed())
after := m.GetCounter().GetValue()
Expect(after - before).To(Equal(float64(1)))
})
})

Context("FlashRequestDuration", func() {
It("should record request duration with endpoint and status labels", func() {
FlashRequestDuration.WithLabelValues("/v1/flash", "200").Observe(0.5)

m := &io_prometheus_client.Metric{}
obs, err := FlashRequestDuration.GetMetricWithLabelValues("/v1/flash", "200")
Expect(err).NotTo(HaveOccurred())
Expect(obs.(interface {
Write(*io_prometheus_client.Metric) error
}).Write(m)).To(Succeed())
Expect(m.GetHistogram().GetSampleCount()).To(BeNumerically(">=", 1))
})
})
})
Loading
Loading