From: Murali Parthasarathy K Date: Wed, 9 Apr 2025 13:18:36 +0000 (+0200) Subject: Support for Prometheus client for opa-pdp X-Git-Tag: 1.0.5~7 X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=0d2cb30d338b6dbd9add37130189bd16ea243f81;p=policy%2Fopa-pdp.git Support for Prometheus client for opa-pdp Issue-ID: POLICY-5336 Change-Id: I1438ff760b229754a2ba3380ebc51d5df465eebd Signed-off-by: Srinivas Yanamadala --- diff --git a/api/register-handlers.go b/api/register-handlers.go index ab71afe..f7ec9d9 100644 --- a/api/register-handlers.go +++ b/api/register-handlers.go @@ -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 diff --git a/api/register-handlers_test.go b/api/register-handlers_test.go index 3cbd248..2e682a0 100644 --- a/api/register-handlers_test.go +++ b/api/register-handlers_test.go @@ -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) +} diff --git a/pkg/metrics/counters.go b/pkg/metrics/counters.go index 09ff4f7..b2b03d8 100644 --- a/pkg/metrics/counters.go +++ b/pkg/metrics/counters.go @@ -19,8 +19,10 @@ 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()