From 0eb62105c1709f69c8b0ad2ba53455efdd951e6b Mon Sep 17 00:00:00 2001 From: Dario Faccin <35623244+dariofaccin@users.noreply.github.com> Date: Tue, 8 Oct 2024 12:07:46 +0200 Subject: [PATCH] feat: add PCF metrics counters (#151) * feat: add PCF metrics counters Signed-off-by: Dario Faccin * chore: removed unused metric Signed-off-by: Dario Faccin * chore: address review comments Signed-off-by: Dario Faccin * fix: initialize policy authorization counter Signed-off-by: Dario Faccin --------- Signed-off-by: Dario Faccin --- metrics/telemetry.go | 50 +++++++++++++++++++++++++++++++++ producer/policyauthorization.go | 17 +++++++++++ producer/smpolicy.go | 22 +++++++++++++++ 3 files changed, 89 insertions(+) diff --git a/metrics/telemetry.go b/metrics/telemetry.go index 4168677..68a05ad 100644 --- a/metrics/telemetry.go +++ b/metrics/telemetry.go @@ -11,9 +11,49 @@ import ( "net/http" "github.com/omec-project/pcf/logger" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" ) +// PcfStats captures PCF stats +type PcfStats struct { + pcfSmPolicy *prometheus.CounterVec + pcfPolicyAuthorization *prometheus.CounterVec +} + +var pcfStats *PcfStats + +func initPcfStats() *PcfStats { + return &PcfStats{ + pcfSmPolicy: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pcf_smpolicy", + Help: "Counter of total Session Management policy queries", + }, []string{"query_type", "dnn", "result"}), + pcfPolicyAuthorization: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "pcf_policy_authorization", + Help: "Counter of total policy authorization queries", + }, []string{"query_type", "resource_type", "result"}), + } +} + +func (ps *PcfStats) register() error { + if err := prometheus.Register(ps.pcfSmPolicy); err != nil { + return err + } + if err := prometheus.Register(ps.pcfPolicyAuthorization); err != nil { + return err + } + return nil +} + +func init() { + pcfStats = initPcfStats() + + if err := pcfStats.register(); err != nil { + logger.InitLog.Errorln("PCF Stats register failed") + } +} + // InitMetrics initializes PCF metrics func InitMetrics() { http.Handle("/metrics", promhttp.Handler()) @@ -21,3 +61,13 @@ func InitMetrics() { logger.InitLog.Errorf("Could not open metrics port: %v", err) } } + +// IncrementPcfSmPolicyStats increments number of total Session Management policy queries +func IncrementPcfSmPolicyStats(queryType, dnn, result string) { + pcfStats.pcfSmPolicy.WithLabelValues(queryType, dnn, result).Inc() +} + +// IncrementPcfPolicyAuthorizationStats increments number of total policy authorization queries +func IncrementPcfPolicyAuthorizationStats(queryType, resourceType, result string) { + pcfStats.pcfPolicyAuthorization.WithLabelValues(queryType, resourceType, result).Inc() +} diff --git a/producer/policyauthorization.go b/producer/policyauthorization.go index 19330a3..e026891 100644 --- a/producer/policyauthorization.go +++ b/producer/policyauthorization.go @@ -19,6 +19,7 @@ import ( pcf_context "github.com/omec-project/pcf/context" "github.com/omec-project/pcf/internal/notifyevent" "github.com/omec-project/pcf/logger" + stats "github.com/omec-project/pcf/metrics" "github.com/omec-project/pcf/util" "github.com/omec-project/util/httpwrapper" ) @@ -140,14 +141,17 @@ func HandlePostAppSessionsContext(request *httpwrapper.Request) *httpwrapper.Res headers := http.Header{ "Location": {locationHeader}, } + stats.IncrementPcfPolicyAuthorizationStats("create", "application_sessions", "SUCCESS") return httpwrapper.NewResponse(http.StatusCreated, headers, response) } else if problemDetails != nil { + stats.IncrementPcfPolicyAuthorizationStats("create", "application_sessions", "FAILURE") return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) } problemDetails = &models.ProblemDetails{ Status: http.StatusForbidden, Cause: "UNSPECIFIED", } + stats.IncrementPcfPolicyAuthorizationStats("create", "events_subscription", "FAILURE") return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) } @@ -440,8 +444,10 @@ func HandleDeleteAppSessionContext(request *httpwrapper.Request) *httpwrapper.Re problemDetails := DeleteAppSessionContextProcedure(appSessID, eventsSubscReqData) if problemDetails == nil { + stats.IncrementPcfPolicyAuthorizationStats("delete", "application_sessions", "SUCCESS") return httpwrapper.NewResponse(http.StatusNoContent, nil, nil) } else { + stats.IncrementPcfPolicyAuthorizationStats("delete", "application_sessions", "FAILURE") return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) } } @@ -508,8 +514,10 @@ func HandleGetAppSessionContext(request *httpwrapper.Request) *httpwrapper.Respo problemDetails, response := GetAppSessionContextProcedure(appSessID) if problemDetails == nil { + stats.IncrementPcfPolicyAuthorizationStats("get", "application_sessions", "SUCCESS") return httpwrapper.NewResponse(http.StatusOK, nil, response) } else { + stats.IncrementPcfPolicyAuthorizationStats("get", "application_sessions", "FAILURE") return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) } } @@ -537,8 +545,10 @@ func HandleModAppSessionContext(request *httpwrapper.Request) *httpwrapper.Respo problemDetails, response := ModAppSessionContextProcedure(appSessID, ascUpdateData) if problemDetails == nil { + stats.IncrementPcfPolicyAuthorizationStats("update", "application_sessions", "SUCCESS") return httpwrapper.NewResponse(http.StatusOK, nil, response) } else { + stats.IncrementPcfPolicyAuthorizationStats("update", "application_sessions", "FAILURE") return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) } } @@ -819,8 +829,10 @@ func HandleDeleteEventsSubscContext(request *httpwrapper.Request) *httpwrapper.R problemDetails := DeleteEventsSubscContextProcedure(appSessID) if problemDetails == nil { + stats.IncrementPcfPolicyAuthorizationStats("delete", "events_subscriptions", "SUCCESS") return httpwrapper.NewResponse(http.StatusNoContent, nil, nil) } else { + stats.IncrementPcfPolicyAuthorizationStats("delete", "events_subscriptions", "FAILURE") return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) } } @@ -866,21 +878,26 @@ func HandleUpdateEventsSubscContext(request *httpwrapper.Request) *httpwrapper.R response, locationHeader, status, problemDetails := UpdateEventsSubscContextProcedure(appSessID, EventsSubscReqData) if problemDetails != nil { + stats.IncrementPcfPolicyAuthorizationStats("update", "events_subscriptions", "FAILURE") return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) } else if status == http.StatusCreated { + stats.IncrementPcfPolicyAuthorizationStats("update", "events_subscriptions", "SUCCESS") headers := http.Header{ "Location": {locationHeader}, } return httpwrapper.NewResponse(http.StatusCreated, headers, response) } else if status == http.StatusOK { + stats.IncrementPcfPolicyAuthorizationStats("update", "events_subscriptions", "SUCCESS") return httpwrapper.NewResponse(http.StatusOK, nil, response) } else if status == http.StatusNoContent { + stats.IncrementPcfPolicyAuthorizationStats("update", "events_subscriptions", "SUCCESS") return httpwrapper.NewResponse(http.StatusNoContent, nil, response) } problemDetails = &models.ProblemDetails{ Status: http.StatusForbidden, Cause: "UNSPECIFIED", } + stats.IncrementPcfPolicyAuthorizationStats("update", "events_subscriptions", "FAILURE") return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) } diff --git a/producer/smpolicy.go b/producer/smpolicy.go index 9a266d0..e7b7a45 100644 --- a/producer/smpolicy.go +++ b/producer/smpolicy.go @@ -20,6 +20,7 @@ import ( "github.com/omec-project/openapi/models" pcf_context "github.com/omec-project/pcf/context" "github.com/omec-project/pcf/logger" + stats "github.com/omec-project/pcf/metrics" "github.com/omec-project/pcf/util" "github.com/omec-project/util/httpwrapper" ) @@ -30,11 +31,14 @@ func HandleCreateSmPolicyRequest(request *httpwrapper.Request) *httpwrapper.Resp requestDataType := request.Body.(models.SmPolicyContextData) header, response, problemDetails := createSMPolicyProcedure(requestDataType) if response != nil { + stats.IncrementPcfSmPolicyStats("create", requestDataType.Dnn, "SUCCESS") // status code is based on SPEC, and option headers return httpwrapper.NewResponse(http.StatusCreated, header, response) } else if problemDetails != nil { + stats.IncrementPcfSmPolicyStats("create", requestDataType.Dnn, "FAILURE") return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) } else { + stats.IncrementPcfSmPolicyStats("create", requestDataType.Dnn, "FAILURE") return httpwrapper.NewResponse(http.StatusNotFound, nil, nil) } } @@ -255,11 +259,18 @@ func createSMPolicyProcedure(request models.SmPolicyContextData) ( func HandleDeleteSmPolicyContextRequest(request *httpwrapper.Request) *httpwrapper.Response { logger.SMpolicylog.Infoln("handle DeleteSmPolicyContext") smPolicyID := request.Params["smPolicyId"] + getResponse, getProblemDetails := getSmPolicyContextProcedure(smPolicyID) + smPolicyDnn := "UNKNOWN_DNN" + if getProblemDetails == nil { + smPolicyDnn = getResponse.Context.Dnn + } problemDetails := deleteSmPolicyContextProcedure(smPolicyID) if problemDetails != nil { + stats.IncrementPcfSmPolicyStats("delete", smPolicyDnn, "FAILURE") // status code is based on SPEC, and option headers return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) } else { + stats.IncrementPcfSmPolicyStats("delete", smPolicyDnn, "SUCCESS") return httpwrapper.NewResponse(http.StatusNoContent, nil, nil) } } @@ -303,15 +314,18 @@ func HandleGetSmPolicyContextRequest(request *httpwrapper.Request) *httpwrapper. smPolicyID := request.Params["smPolicyID"] response, problemDetails := getSmPolicyContextProcedure(smPolicyID) if response != nil { + stats.IncrementPcfSmPolicyStats("get", response.Context.Dnn, "SUCCESS") // status code is based on SPEC, and option headers return httpwrapper.NewResponse(http.StatusOK, nil, response) } else if problemDetails != nil { + stats.IncrementPcfSmPolicyStats("get", "UNKNOWN_DNN", "FAILURE") return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) } problemDetails = &models.ProblemDetails{ Status: http.StatusForbidden, Cause: "UNSPECIFIED", } + stats.IncrementPcfSmPolicyStats("get", "UNKNOWN_DNN", "FAILURE") return httpwrapper.NewResponse(http.StatusForbidden, nil, problemDetails) } @@ -340,17 +354,25 @@ func HandleUpdateSmPolicyContextRequest(request *httpwrapper.Request) *httpwrapp logger.SMpolicylog.Infoln("handle UpdateSmPolicyContext") requestDataType := request.Body.(models.SmPolicyUpdateContextData) smPolicyID := request.Params["smPolicyId"] + getResponse, getProblemDetails := getSmPolicyContextProcedure(smPolicyID) + smPolicyDnn := "UNKNOWN_DNN" + if getProblemDetails == nil { + smPolicyDnn = getResponse.Context.Dnn + } response, problemDetails := updateSmPolicyContextProcedure(requestDataType, smPolicyID) if response != nil { + stats.IncrementPcfSmPolicyStats("update", smPolicyDnn, "SUCCESS") // status code is based on SPEC, and option headers return httpwrapper.NewResponse(http.StatusOK, nil, response) } else if problemDetails != nil { + stats.IncrementPcfSmPolicyStats("update", smPolicyDnn, "FAILURE") return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) } problemDetails = &models.ProblemDetails{ Status: http.StatusForbidden, Cause: "UNSPECIFIED", } + stats.IncrementPcfSmPolicyStats("update", smPolicyDnn, "FAILURE") return httpwrapper.NewResponse(http.StatusForbidden, nil, problemDetails) }