Files
threshold/internal/daemon/metric/initialize_metrics.go
T

134 lines
4.4 KiB
Go

// Package metric provides functions to initialize the controller specific
// collectors and hooks to measure metrics and update the relevant collectors.
package metric
import (
"net/http"
"strconv"
"strings"
"github.com/prometheus/client_golang/prometheus"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
const (
LabelGrpcService = "grpc_service"
LabelGrpcMethod = "grpc_method"
LabelGrpcCode = "grpc_code"
LabelHttpPath = "path"
LabelHttpMethod = "method"
LabelHttpCode = "code"
invalidPathValue = "invalid"
)
var (
ListGrpcLabels = []string{LabelGrpcService, LabelGrpcMethod, LabelGrpcCode}
ListHttpLabels = []string{LabelHttpPath, LabelHttpMethod, LabelHttpCode}
)
/* The following methods are used to initialize Prometheus histogram vectors for gRPC connections. */
func rangeProtoFiles(m map[string][]string, fd protoreflect.FileDescriptor) bool {
if fd.Services().Len() == 0 {
return true
}
for i := 0; i < fd.Services().Len(); i++ {
s := fd.Services().Get(i)
if s.Methods().Len() == 0 {
continue
}
methods := []string{}
for j := 0; j < s.Methods().Len(); j++ {
methods = append(methods, string(s.Methods().Get(j).Name()))
}
m[string(s.FullName())] = methods
}
return true
}
// appendServicesAndMethods ranges through all registered files in a specified proto package
// and appends service and method names to the provided map m.
// This method is exported for testing purposes.
func appendServicesAndMethods(m map[string][]string, pkg protoreflect.FileDescriptor) {
protoregistry.GlobalFiles.RangeFilesByPackage(
pkg.Package(),
func(fd protoreflect.FileDescriptor) bool { return rangeProtoFiles(m, fd) },
)
}
// InitializeGrpcCollectorsFromPackage registers and zeroes a Prometheus
// histogram, populating all service and method labels by ranging through
// the package containing the provided FileDescriptor.
// Note: inputting a protoreflect.FileDescriptor will populate all services and methods
// found in its package, not just methods associated with that specific FileDescriptor.
func InitializeGrpcCollectorsFromPackage(r prometheus.Registerer, v prometheus.ObserverVec, pkg protoreflect.FileDescriptor, codes []codes.Code) {
if r == nil {
return
}
r.MustRegister(v)
serviceNamesToMethodNames := make(map[string][]string, 0)
appendServicesAndMethods(serviceNamesToMethodNames, pkg)
for serviceName, serviceMethods := range serviceNamesToMethodNames {
for _, sm := range serviceMethods {
for _, c := range codes {
v.With(prometheus.Labels{LabelGrpcService: serviceName, LabelGrpcMethod: sm, LabelGrpcCode: c.String()})
}
}
}
}
// InitializeGrpcCollectorsFromServer registers and zeroes a Prometheus
// histogram, finding all service and method labels from the provided gRPC
// server.
func InitializeGrpcCollectorsFromServer(r prometheus.Registerer, v prometheus.ObserverVec, server *grpc.Server, codes []codes.Code) {
if r == nil {
return
}
r.MustRegister(v)
for serviceName, info := range server.GetServiceInfo() {
for _, mInfo := range info.Methods {
for _, c := range codes {
v.With(prometheus.Labels{LabelGrpcService: serviceName, LabelGrpcMethod: mInfo.Name, LabelGrpcCode: c.String()})
}
}
}
}
/* The following methods are used to initialize Prometheus histogram vectors for http requests. */
// InitializeApiCollectors registers and zeroes a Prometheus
// histogram, populating all path, code, and method labels from the
// provided maps in its parameters.
func InitializeApiCollectors(r prometheus.Registerer, v prometheus.ObserverVec, expectedPathsToMethods map[string][]string, expectedStatusCodesPerMethod map[string][]int) {
if r == nil {
return
}
r.MustRegister(v)
for p, methods := range expectedPathsToMethods {
for _, m := range methods {
for _, sc := range expectedStatusCodesPerMethod[m] {
v.With(prometheus.Labels{LabelHttpPath: p, LabelHttpMethod: strings.ToLower(m), LabelHttpCode: strconv.Itoa(sc)})
}
}
}
// When an invalid path is found, any method is possible, but we expect an error response.
p := invalidPathValue
for m := range expectedStatusCodesPerMethod {
for _, sc := range []int{http.StatusNotFound, http.StatusMethodNotAllowed} {
v.With(prometheus.Labels{LabelHttpPath: p, LabelHttpMethod: strings.ToLower(m), LabelHttpCode: strconv.Itoa(sc)})
}
}
}