Skip to content

Commit

Permalink
otelgrpc: Add filter for stats handler
Browse files Browse the repository at this point in the history
  • Loading branch information
Yosuke Matsuda committed Mar 3, 2024
1 parent 0e3482c commit 4a4eb3e
Show file tree
Hide file tree
Showing 7 changed files with 708 additions and 231 deletions.
41 changes: 31 additions & 10 deletions instrumentation/google.golang.org/grpc/otelgrpc/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
package otelgrpc // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"

import (
"google.golang.org/grpc/stats"

"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
Expand All @@ -20,18 +22,24 @@ const (
GRPCStatusCodeKey = attribute.Key("rpc.grpc.status_code")
)

// InterceptorFilter is a predicate used to determine whether a given request in
// interceptor info should be traced. A InterceptorFilter must return true if
// the request should be traced.
type InterceptorFilter func(*InterceptorInfo) bool

// Filter is a predicate used to determine whether a given request in
// interceptor info should be traced. A Filter must return true if
// the request should be traced.
type Filter func(*InterceptorInfo) bool
type Filter func(*stats.RPCTagInfo) bool

// config is a group of options for this instrumentation.
type config struct {
Filter Filter
Propagators propagation.TextMapPropagator
TracerProvider trace.TracerProvider
MeterProvider metric.MeterProvider
SpanStartOptions []trace.SpanStartOption
Filter Filter
InterceptorFilter InterceptorFilter
Propagators propagation.TextMapPropagator
TracerProvider trace.TracerProvider
MeterProvider metric.MeterProvider
SpanStartOptions []trace.SpanStartOption

ReceivedEvent bool
SentEvent bool
Expand Down Expand Up @@ -150,17 +158,30 @@ func (o tracerProviderOption) apply(c *config) {
}

// WithInterceptorFilter returns an Option to use the request filter.
//
// Deprecated: Use stats handlers instead.
func WithInterceptorFilter(f Filter) Option {
func WithInterceptorFilter(f InterceptorFilter) Option {
return interceptorFilterOption{f: f}
}

type interceptorFilterOption struct {
f Filter
f InterceptorFilter
}

func (o interceptorFilterOption) apply(c *config) {
if o.f != nil {
c.InterceptorFilter = o.f
}
}

// WithFilter returns an Option to use the request filter.
func WithFilter(f Filter) Option {
return filterOption{f: f}
}

type filterOption struct {
f Filter
}

func (o filterOption) apply(c *config) {
if o.f != nil {
c.Filter = o.f
}
Expand Down
47 changes: 13 additions & 34 deletions instrumentation/google.golang.org/grpc/otelgrpc/filters/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"path"
"strings"

"google.golang.org/grpc/stats"

"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
)

Expand All @@ -19,20 +21,8 @@ type gRPCPath struct {
// and returns as gRPCPath object that has divided service and method names
// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md
// If name is not FullMethod, returned gRPCPath has empty service field.
func splitFullMethod(i *otelgrpc.InterceptorInfo) gRPCPath {
var name string
switch i.Type {
case otelgrpc.UnaryServer:
name = i.UnaryServerInfo.FullMethod
case otelgrpc.StreamServer:
name = i.StreamServerInfo.FullMethod
case otelgrpc.UnaryClient, otelgrpc.StreamClient:
name = i.Method
default:
name = i.Method
}

s, m := path.Split(name)
func splitFullMethod(i *stats.RPCTagInfo) gRPCPath {
s, m := path.Split(i.FullMethodName)
if s != "" {
s = path.Clean(s)
s = strings.TrimLeft(s, "/")
Expand All @@ -47,7 +37,7 @@ func splitFullMethod(i *otelgrpc.InterceptorInfo) gRPCPath {
// Any takes a list of Filters and returns a Filter that
// returns true if any Filter in the list returns true.
func Any(fs ...otelgrpc.Filter) otelgrpc.Filter {
return func(i *otelgrpc.InterceptorInfo) bool {
return func(i *stats.RPCTagInfo) bool {
for _, f := range fs {
if f(i) {
return true
Expand All @@ -60,7 +50,7 @@ func Any(fs ...otelgrpc.Filter) otelgrpc.Filter {
// All takes a list of Filters and returns a Filter that
// returns true only if all Filters in the list return true.
func All(fs ...otelgrpc.Filter) otelgrpc.Filter {
return func(i *otelgrpc.InterceptorInfo) bool {
return func(i *stats.RPCTagInfo) bool {
for _, f := range fs {
if !f(i) {
return false
Expand All @@ -78,15 +68,15 @@ func None(fs ...otelgrpc.Filter) otelgrpc.Filter {

// Not provides a convenience mechanism for inverting a Filter.
func Not(f otelgrpc.Filter) otelgrpc.Filter {
return func(i *otelgrpc.InterceptorInfo) bool {
return func(i *stats.RPCTagInfo) bool {
return !f(i)
}
}

// MethodName returns a Filter that returns true if the request's
// method name matches the provided string n.
func MethodName(n string) otelgrpc.Filter {
return func(i *otelgrpc.InterceptorInfo) bool {
return func(i *stats.RPCTagInfo) bool {
p := splitFullMethod(i)
return p.method == n
}
Expand All @@ -95,7 +85,7 @@ func MethodName(n string) otelgrpc.Filter {
// MethodPrefix returns a Filter that returns true if the request's
// method starts with the provided string pre.
func MethodPrefix(pre string) otelgrpc.Filter {
return func(i *otelgrpc.InterceptorInfo) bool {
return func(i *stats.RPCTagInfo) bool {
p := splitFullMethod(i)
return strings.HasPrefix(p.method, pre)
}
Expand All @@ -105,26 +95,15 @@ func MethodPrefix(pre string) otelgrpc.Filter {
// full RPC method string, i.e. /package.service/method, starts with
// the provided string n.
func FullMethodName(n string) otelgrpc.Filter {
return func(i *otelgrpc.InterceptorInfo) bool {
var fm string
switch i.Type {
case otelgrpc.UnaryClient, otelgrpc.StreamClient:
fm = i.Method
case otelgrpc.UnaryServer:
fm = i.UnaryServerInfo.FullMethod
case otelgrpc.StreamServer:
fm = i.StreamServerInfo.FullMethod
default:
fm = i.Method
}
return fm == n
return func(i *stats.RPCTagInfo) bool {
return i.FullMethodName == n
}
}

// ServiceName returns a Filter that returns true if the request's
// service name, i.e. package.service, matches s.
func ServiceName(s string) otelgrpc.Filter {
return func(i *otelgrpc.InterceptorInfo) bool {
return func(i *stats.RPCTagInfo) bool {
p := splitFullMethod(i)
return p.service == s
}
Expand All @@ -133,7 +112,7 @@ func ServiceName(s string) otelgrpc.Filter {
// ServicePrefix returns a Filter that returns true if the request's
// service name, i.e. package.service, starts with the provided string pre.
func ServicePrefix(pre string) otelgrpc.Filter {
return func(i *otelgrpc.InterceptorInfo) bool {
return func(i *stats.RPCTagInfo) bool {
p := splitFullMethod(i)
return strings.HasPrefix(p.service, pre)
}
Expand Down
Loading

0 comments on commit 4a4eb3e

Please sign in to comment.