Support for Prometheus client for opa-pdp 86/140586/2
authorMurali Parthasarathy K <srinivas.yanamadala@techmahindra.com>
Wed, 9 Apr 2025 13:18:36 +0000 (15:18 +0200)
committerMurali Parthasarathy K <srinivas.yanamadala@techmahindra.com>
Wed, 9 Apr 2025 17:23:43 +0000 (19:23 +0200)
Issue-ID: POLICY-5336
Change-Id: I1438ff760b229754a2ba3380ebc51d5df465eebd
Signed-off-by: Srinivas Yanamadala <srinivas.yanamadala@techmahindra.com>
api/register-handlers.go
api/register-handlers_test.go
pkg/metrics/counters.go

index ab71afe..f7ec9d9 100644 (file)
@@ -30,6 +30,9 @@ import (
        "policy-opa-pdp/pkg/log"
        "policy-opa-pdp/pkg/metrics"
        "policy-opa-pdp/pkg/opasdk"
+       "time"
+       "github.com/prometheus/client_golang/prometheus"
+       "github.com/prometheus/client_golang/prometheus/promhttp"
 )
 
 // RegisterHandlers registers the HTTP handlers for the service.
@@ -37,7 +40,7 @@ func RegisterHandlers() {
 
        // Handler for OPA decision making
        opaDecisionHandler := http.HandlerFunc(decision.OpaDecision)
-       http.Handle("/policy/pdpo/v1/decision", basicAuth(opaDecisionHandler))
+       http.Handle("/policy/pdpo/v1/decision", basicAuth(trackDecisionResponseTime(opaDecisionHandler)))
 
        // Handler for kubernetes readiness probe
        readinessProbeHandler := http.HandlerFunc(readinessProbe)
@@ -55,10 +58,32 @@ func RegisterHandlers() {
        http.Handle("/opa/listpolicies", listPoliciesHandler)
 
        dataHandler := http.HandlerFunc(data.DataHandler)
-       http.Handle("/policy/pdpo/v1/data/", basicAuth(dataHandler))
+       http.Handle("/policy/pdpo/v1/data/", basicAuth(trackDataResponseTime(dataHandler)))
 
-       http.Handle("/policy/pdpo/v1/data", basicAuth(dataHandler))
+       http.Handle("/policy/pdpo/v1/data", basicAuth(trackDataResponseTime(dataHandler)))
 
+       //Handler for prometheus
+       http.Handle("/metrics", promhttp.Handler())
+
+}
+
+//Track Decision response time metrics
+func trackDecisionResponseTime(next http.HandlerFunc) http.HandlerFunc {
+       return trackResponseTime(metrics.DecisionResponseTime, next)
+}
+
+//Track Data response time metrics
+func trackDataResponseTime(next http.HandlerFunc) http.HandlerFunc {
+       return trackResponseTime(metrics.DataResponseTime, next)
+}
+
+func trackResponseTime(metricCollector prometheus.Observer, next http.HandlerFunc) http.HandlerFunc {
+       return func(res http.ResponseWriter, req *http.Request) {
+               start := time.Now()
+               next(res, req)
+               duration := time.Since(start).Seconds()
+               metricCollector.Observe(duration)
+       }
 }
 
 // handles authentication
index 3cbd248..2e682a0 100644 (file)
@@ -26,6 +26,8 @@ import (
        "policy-opa-pdp/pkg/decision"
        "policy-opa-pdp/pkg/healthcheck"
        "testing"
+       "time"
+       "github.com/stretchr/testify/assert"
 )
 
 // Mock configuration
@@ -112,3 +114,59 @@ func TestReadinessProbe(t *testing.T) {
                t.Errorf("readinessProbe returned unexpected body: got %v want %v", rr.Body.String(), expected)
        }
 }
+
+
+type mockObserver struct {
+       observedDuration float64
+}
+
+func (m *mockObserver) Observe(duration float64) {
+       m.observedDuration = duration
+}
+
+// Test trackDecisionResponseTime function
+func TestTrackDecisionResponseTime(t *testing.T) {
+       observer := &mockObserver{}
+       handler := trackDecisionResponseTime(func(res http.ResponseWriter, req *http.Request) {
+               time.Sleep(50 * time.Millisecond)
+               res.WriteHeader(http.StatusOK)
+       })
+
+       req := httptest.NewRequest("GET", "/decision", nil)
+       res := httptest.NewRecorder()
+
+       handler(res, req)
+
+       assert.NotNil(t, observer.observedDuration)
+}
+
+// Test trackDataResponseTime function
+func TestTrackDataResponseTime(t *testing.T) {
+       observer := &mockObserver{}
+       handler := trackDataResponseTime(func(res http.ResponseWriter, req *http.Request) {
+               time.Sleep(30 * time.Millisecond)
+               res.WriteHeader(http.StatusOK)
+       })
+
+       req := httptest.NewRequest("GET", "/data", nil)
+       res := httptest.NewRecorder()
+
+       handler(res, req)
+
+       assert.NotNil(t, observer.observedDuration)
+}
+
+// Test trackResponseTime function
+func TestTrackResponseTime(t *testing.T) {
+       observer := &mockObserver{}
+
+       handler := trackResponseTime(observer, func(res http.ResponseWriter, req *http.Request) {
+               time.Sleep(20 * time.Millisecond)
+               res.WriteHeader(http.StatusOK)
+       })
+
+       req := httptest.NewRequest("GET", "/response", nil)
+       res := httptest.NewRecorder()
+       handler(res, req)
+       assert.NotNil(t, observer.observedDuration)
+}
index 09ff4f7..b2b03d8 100644 (file)
 
 package metrics
 
-import "sync"
-
+import (
+        "sync"
+        "github.com/prometheus/client_golang/prometheus"
+)
 // global counter variables
 var TotalErrorCount int64
 var DecisionSuccessCount int64
@@ -32,6 +34,24 @@ var UndeploySuccessCount int64
 var TotalPoliciesCount int64
 var mu sync.Mutex
 
+//Decision and Data counters to be used in prometheus
+var (
+       DecisionResponseTime = prometheus.NewSummary(prometheus.SummaryOpts{
+               Name:    "opa_decision_response_time_seconds",
+               Help:    "Response time of OPA decision handler",
+       })
+       DataResponseTime = prometheus.NewSummary(prometheus.SummaryOpts{
+               Name:    "opa_data_response_time_seconds",
+               Help:    "Response time of OPA data handler",
+       })
+)
+
+//register counters in init
+func init() {
+       prometheus.MustRegister(DecisionResponseTime)
+       prometheus.MustRegister(DataResponseTime)
+}
+
 // Increment counter
 func IncrementTotalErrorCount() {
        mu.Lock()