refactor(metric): adds filter function to collector init method (#2695)
This commit is contained in:
1 parent
240278cbf1
commit
340cfb0d88
3 files changed
+57
-13
No files matched your search
@@ -33,7 +33,10 @@ var (
|
||||
|
||||
/* The following methods are used to initialize Prometheus histogram vectors for gRPC connections. */
|
||||
|
||||
func rangeProtoFiles(m map[string][]string, fd protoreflect.FileDescriptor) bool {
|
||||
// rangeProtoFiles returns true while there are services with associated methods in the proto package.
|
||||
// It relies on RangeFilesByPackage to range through the package, and it adds them into map m.
|
||||
// Services and methods for which filter() returns true are not added into the map.
|
||||
func rangeProtoFiles(m map[string][]string, fd protoreflect.FileDescriptor, filter func(string, string) bool) bool {
|
||||
if fd.Services().Len() == 0 {
|
||||
return true
|
||||
}
|
||||
@@ -44,11 +47,18 @@ func rangeProtoFiles(m map[string][]string, fd protoreflect.FileDescriptor) bool
|
||||
continue
|
||||
}
|
||||
|
||||
serviceName := string(s.FullName())
|
||||
methods := []string{}
|
||||
for j := 0; j < s.Methods().Len(); j++ {
|
||||
methods = append(methods, string(s.Methods().Get(j).Name()))
|
||||
methodName := string(s.Methods().Get(j).Name())
|
||||
if filter(serviceName, methodName) {
|
||||
continue
|
||||
}
|
||||
methods = append(methods, methodName)
|
||||
}
|
||||
if len(methods) > 0 {
|
||||
m[serviceName] = methods
|
||||
}
|
||||
m[string(s.FullName())] = methods
|
||||
}
|
||||
|
||||
return true
|
||||
@@ -56,27 +66,32 @@ func rangeProtoFiles(m map[string][]string, fd protoreflect.FileDescriptor) bool
|
||||
|
||||
// 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) {
|
||||
func appendServicesAndMethods(m map[string][]string, pkg protoreflect.FileDescriptor, filter func(string, string) bool) {
|
||||
protoregistry.GlobalFiles.RangeFilesByPackage(
|
||||
pkg.Package(),
|
||||
func(fd protoreflect.FileDescriptor) bool { return rangeProtoFiles(m, fd) },
|
||||
func(fd protoreflect.FileDescriptor) bool { return rangeProtoFiles(m, fd, filter) },
|
||||
)
|
||||
}
|
||||
|
||||
// InitializeGrpcCollectorsFromPackage registers and zeroes a Prometheus
|
||||
// histogram, populating all service and method labels by ranging through
|
||||
// the package containing the provided FileDescriptor.
|
||||
// The filter function takes in a service name and method name and skips adding them as labels
|
||||
// upon returning true.
|
||||
// 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) {
|
||||
func InitializeGrpcCollectorsFromPackage(r prometheus.Registerer, v prometheus.ObserverVec,
|
||||
pkgs []protoreflect.FileDescriptor, codes []codes.Code, filter func(string, string) bool,
|
||||
) {
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
r.MustRegister(v)
|
||||
|
||||
serviceNamesToMethodNames := make(map[string][]string, 0)
|
||||
appendServicesAndMethods(serviceNamesToMethodNames, pkg)
|
||||
for _, p := range pkgs {
|
||||
appendServicesAndMethods(serviceNamesToMethodNames, p, filter)
|
||||
}
|
||||
|
||||
for serviceName, serviceMethods := range serviceNamesToMethodNames {
|
||||
for _, sm := range serviceMethods {
|
||||
|
||||
@@ -16,17 +16,35 @@ func Test_AppendServicesAndMethods(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
pkg protoreflect.FileDescriptor
|
||||
filter func(string, string) bool
|
||||
expected map[string][]string
|
||||
}{
|
||||
{
|
||||
name: "basic",
|
||||
pkg: protooptions.File_testing_options_v1_service_proto,
|
||||
filter: func(string, string) bool { return false },
|
||||
expected: map[string][]string{"testing.options.v1.TestService": {"TestMethod"}},
|
||||
},
|
||||
{
|
||||
name: "filter-out",
|
||||
pkg: protooptions.File_testing_options_v1_service_proto,
|
||||
filter: func(_ string, m string) bool {
|
||||
return m == "TestMethod"
|
||||
},
|
||||
expected: map[string][]string{},
|
||||
},
|
||||
{
|
||||
name: "filter-allow",
|
||||
pkg: protooptions.File_testing_options_v1_service_proto,
|
||||
filter: func(_ string, m string) bool {
|
||||
return m != "TestMethod"
|
||||
},
|
||||
expected: map[string][]string{"testing.options.v1.TestService": {"TestMethod"}},
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
m := make(map[string][]string, 0)
|
||||
appendServicesAndMethods(m, tc.pkg)
|
||||
appendServicesAndMethods(m, tc.pkg, tc.filter)
|
||||
assert.Equal(t, tc.expected, m)
|
||||
}
|
||||
}
|
||||
@@ -6,16 +6,25 @@ import (
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/daemon/metric"
|
||||
"github.com/hashicorp/boundary/internal/gen/controller/servers/services"
|
||||
cservices "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
)
|
||||
|
||||
const (
|
||||
clusterClientSubsystem = "cluster_client"
|
||||
)
|
||||
|
||||
// grpcCollectorFilter is currently used to filter the services and methods of the
|
||||
// controller.servers.services package upon running InitializeClusterClientCollectors.
|
||||
var grpcCollectorFilter = noopFilter
|
||||
|
||||
func noopFilter(serviceName string, methodName string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// grpcRequestLatency collects measurements of how long a gRPC
|
||||
// request between a cluster and its clients takes.
|
||||
var grpcRequestLatency prometheus.ObserverVec = prometheus.NewHistogramVec(
|
||||
@@ -37,8 +46,7 @@ type requestRecorder struct {
|
||||
start time.Time
|
||||
}
|
||||
|
||||
// NewRequestRecorder creates a requestRecorder struct which is used to measure gRPC client request latencies.
|
||||
// For testing purposes, this method is exported.
|
||||
// newRequestRecorder creates a requestRecorder struct which is used to measure gRPC client request latencies.
|
||||
func newRequestRecorder(fullMethodName string, reqLatency prometheus.ObserverVec) requestRecorder {
|
||||
service, method := metric.SplitMethodName(fullMethodName)
|
||||
r := requestRecorder{
|
||||
@@ -82,5 +90,8 @@ func InstrumentClusterClient() grpc.UnaryClientInterceptor {
|
||||
// prometheus register and initializes them to 0 for all possible label
|
||||
// combinations.
|
||||
func InitializeClusterClientCollectors(r prometheus.Registerer) {
|
||||
metric.InitializeGrpcCollectorsFromPackage(r, grpcRequestLatency, services.File_controller_servers_services_v1_session_service_proto, expectedGrpcClientCodes)
|
||||
metric.InitializeGrpcCollectorsFromPackage(r, grpcRequestLatency,
|
||||
[]protoreflect.FileDescriptor{
|
||||
cservices.File_controller_servers_services_v1_session_service_proto,
|
||||
}, expectedGrpcClientCodes, grpcCollectorFilter)
|
||||
}
|
||||
Reference in new issue
Block a user