-
Notifications
You must be signed in to change notification settings - Fork 4.5k
stats/opentelemetry: separate out interceptors for tracing and metrics #8063
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
janardhanvissa
wants to merge
62
commits into
grpc:master
Choose a base branch
from
janardhanvissa:refactor-tracing-metrics
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+269
−117
Open
Changes from all commits
Commits
Show all changes
62 commits
Select commit
Hold shift + click to select a range
7ddbe46
replace dial with newclient
janardhankrishna-sai 0486355
Merge branch 'master' of https://github.com/janardhanvissa/grpc-go
janardhankrishna-sai 53fa9cd
Merge branch 'grpc:master' into master
janardhanvissa 4435b8a
Merge branch 'grpc:master' into master
janardhanvissa a413555
Merge branch 'grpc:master' into master
janardhanvissa 4e203c3
Merge branch 'grpc:master' into master
janardhanvissa e9ad552
Merge branch 'grpc:master' into master
janardhanvissa 71804b4
refactor tracing and metrics interceptors separately
janardhankrishna-sai 4b3bd26
adding opentelemetry tracing for client-server
janardhankrishna-sai 69df069
fixing vet issues
janardhankrishna-sai 770f430
reverting newclient changes and fixing vet issues
janardhankrishna-sai b97a3ca
reverting otel trace for client/server changes
janardhankrishna-sai c89f3c9
fixing vet issue
janardhankrishna-sai 3f07e48
renaming receiver name
janardhankrishna-sai 5e8a4a5
unused param fix
janardhankrishna-sai 76e422a
fixing vet issue
janardhankrishna-sai 8fa0b03
refactor client interceptor separately for traces and metrics
janardhankrishna-sai 1f41a49
moving tracing code to client_tracing.go file
janardhankrishna-sai d74c61d
revert previous commit
janardhankrishna-sai 170eef6
adding separate interceptors for traces and metrics of server
janardhankrishna-sai 7f5f539
separating HandleRPC interceptors of traces and metrics
janardhankrishna-sai 50999a0
updating client and server metrics
janardhankrishna-sai 68b8966
removing metrics code from tracingstatshandler and unused parameters
janardhankrishna-sai 8b56f0f
addressing review comments
janardhankrishna-sai ac6080f
addressing review comments
janardhankrishna-sai ed5506c
Merge branch 'master' into refactor-tracing-metrics
janardhanvissa be72377
updating go.sum
janardhankrishna-sai a5ed115
fixing linter issue
janardhankrishna-sai f243b43
addressing review comments for client
janardhankrishna-sai efb738f
addressing review comments for client
janardhankrishna-sai 7b97c65
Merge branch 'master' into refactor-tracing-metrics
janardhanvissa e8b0180
addressing review comments for server
janardhankrishna-sai f70274b
fixing vet issue
janardhankrishna-sai 5e607c5
updating newServerStatsHandler
janardhankrishna-sai a850532
updating var name
janardhankrishna-sai 0f39f8d
moving tracing code to a separate file and adding comments
janardhankrishna-sai 2a914e3
removing unused isMetricsEnabled()
janardhankrishna-sai 05b4278
addressing review comments and updating doc string
janardhankrishna-sai 105efe9
addressing review comments
janardhankrishna-sai 3d78d59
creating helper func for rpcinfo
janardhankrishna-sai 44fce2d
addressing review comments
janardhankrishna-sai e5f50b7
updating logger
janardhankrishna-sai ffcc0fa
Merge branch 'master' into refactor-tracing-metrics
janardhanvissa 67e5b24
update unaryInterceptor
janardhankrishna-sai 8cf7f15
revert doc string
janardhankrishna-sai 7949501
fixing vet issue
janardhankrishna-sai ad22a22
update clientStatsHandler unaryInterceptor
janardhankrishna-sai dd179fb
updating verbosity level and removing redundant code
janardhankrishna-sai 3201805
reverting logger.Info from logger.Error
janardhankrishna-sai a3915ef
Update server_metrics.go
janardhanvissa 1ff5159
addressing review comments
janardhankrishna-sai 4133dd3
updating the comment
janardhankrishna-sai f8e0cac
addressing review comments
janardhankrishna-sai 0b89cf6
fixing vet issue
janardhankrishna-sai 42c08a0
fixing linter issue
janardhankrishna-sai 5bb48b3
addressing review comments
janardhankrishna-sai fb8025d
addressing review comments
janardhankrishna-sai cc39d1a
addressing review comments
janardhankrishna-sai eb8321f
Initializes ri to &rpcInfo{} when it's nil, separating the initializa…
janardhankrishna-sai c858ed2
Merge branch 'master' into refactor-tracing-metrics
janardhanvissa 5c57489
fixing vet issue
janardhankrishna-sai cc12a84
addressing review comments
janardhankrishna-sai File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,24 +18,92 @@ | |
|
||
import ( | ||
"context" | ||
"log" | ||
"strings" | ||
|
||
otelcodes "go.opentelemetry.io/otel/codes" | ||
"go.opentelemetry.io/otel/trace" | ||
"google.golang.org/grpc" | ||
grpccodes "google.golang.org/grpc/codes" | ||
"google.golang.org/grpc/stats" | ||
otelinternaltracing "google.golang.org/grpc/stats/opentelemetry/internal/tracing" | ||
"google.golang.org/grpc/status" | ||
) | ||
|
||
const ( | ||
delayedResolutionEventName = "Delayed name resolution complete" | ||
tracerName = "grpc-go" | ||
) | ||
|
||
type clientTracingHandler struct { | ||
options Options | ||
} | ||
|
||
func (h *clientTracingHandler) initializeTraces() { | ||
if h.options.TraceOptions.TracerProvider == nil { | ||
log.Printf("TracerProvider is not provided in client TraceOptions") | ||
return | ||
} | ||
} | ||
|
||
func (h *clientTracingHandler) unaryInterceptor(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { | ||
ci := getCallInfo(ctx) | ||
purnesh42H marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if ci == nil { | ||
dfawley marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if logger.V(2) { | ||
logger.Info("Creating new CallInfo since its not present in context in clientTracingHandler unaryInterceptor") | ||
} | ||
ci = &callInfo{ | ||
target: cc.CanonicalTarget(), | ||
method: determineMethod(method, opts...), | ||
} | ||
ctx = setCallInfo(ctx, ci) | ||
} | ||
|
||
var span trace.Span | ||
ctx, span = h.createCallTraceSpan(ctx, method) | ||
err := invoker(ctx, method, req, reply, cc, opts...) | ||
h.finishTrace(err, span) | ||
return err | ||
} | ||
|
||
func (h *clientTracingHandler) streamInterceptor(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { | ||
ci := getCallInfo(ctx) | ||
purnesh42H marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if ci == nil { | ||
dfawley marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if logger.V(2) { | ||
logger.Info("Creating new CallInfo since its not present in context in clientTracingHandler streamInterceptor") | ||
} | ||
ci = &callInfo{ | ||
target: cc.CanonicalTarget(), | ||
method: determineMethod(method, opts...), | ||
} | ||
ctx = setCallInfo(ctx, ci) | ||
} | ||
|
||
var span trace.Span | ||
ctx, span = h.createCallTraceSpan(ctx, method) | ||
callback := func(err error) { h.finishTrace(err, span) } | ||
opts = append([]grpc.CallOption{grpc.OnFinish(callback)}, opts...) | ||
return streamer(ctx, desc, cc, method, opts...) | ||
} | ||
|
||
// finishTrace sets the span status based on the RPC result and ends the span. | ||
// It is used to finalize tracing for both unary and streaming calls. | ||
func (h *clientTracingHandler) finishTrace(err error, ts trace.Span) { | ||
s := status.Convert(err) | ||
if s.Code() == grpccodes.OK { | ||
ts.SetStatus(otelcodes.Ok, s.Message()) | ||
} else { | ||
ts.SetStatus(otelcodes.Error, s.Message()) | ||
} | ||
ts.End() | ||
} | ||
|
||
// traceTagRPC populates provided context with a new span using the | ||
// TextMapPropagator supplied in trace options and internal itracing.carrier. | ||
// It creates a new outgoing carrier which serializes information about this | ||
// span into gRPC Metadata, if TextMapPropagator is provided in the trace | ||
// options. if TextMapPropagator is not provided, it returns the context as is. | ||
func (h *clientStatsHandler) traceTagRPC(ctx context.Context, ai *attemptInfo, nameResolutionDelayed bool) (context.Context, *attemptInfo) { | ||
func (h *clientTracingHandler) traceTagRPC(ctx context.Context, ai *attemptInfo, nameResolutionDelayed bool) (context.Context, *attemptInfo) { | ||
// Add a "Delayed name resolution complete" event to the call span | ||
// if there was name resolution delay. In case of multiple retry attempts, | ||
// ensure that event is added only once. | ||
|
@@ -55,13 +123,40 @@ | |
|
||
// createCallTraceSpan creates a call span to put in the provided context using | ||
// provided TraceProvider. If TraceProvider is nil, it returns context as is. | ||
func (h *clientStatsHandler) createCallTraceSpan(ctx context.Context, method string) (context.Context, trace.Span) { | ||
if h.options.TraceOptions.TracerProvider == nil { | ||
logger.Error("TraceProvider is not provided in trace options") | ||
return ctx, nil | ||
} | ||
func (h *clientTracingHandler) createCallTraceSpan(ctx context.Context, method string) (context.Context, trace.Span) { | ||
mn := strings.Replace(removeLeadingSlash(method), "/", ".", -1) | ||
tracer := h.options.TraceOptions.TracerProvider.Tracer(tracerName, trace.WithInstrumentationVersion(grpc.Version)) | ||
ctx, span := tracer.Start(ctx, mn, trace.WithSpanKind(trace.SpanKindClient)) | ||
return ctx, span | ||
} | ||
|
||
// TagConn exists to satisfy stats.Handler for tracing. | ||
func (h *clientTracingHandler) TagConn(ctx context.Context, _ *stats.ConnTagInfo) context.Context { | ||
return ctx | ||
} | ||
|
||
// HandleConn exists to satisfy stats.Handler for tracing. | ||
func (h *clientTracingHandler) HandleConn(context.Context, stats.ConnStats) {} | ||
|
||
// TagRPC implements per RPC attempt context management for traces. | ||
func (h *clientTracingHandler) TagRPC(ctx context.Context, info *stats.RPCTagInfo) context.Context { | ||
ri := getRPCInfo(ctx) | ||
purnesh42H marked this conversation as resolved.
Show resolved
Hide resolved
|
||
var ai *attemptInfo | ||
if ri == nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As above. |
||
ai = &attemptInfo{} | ||
} else { | ||
ai = ri.ai | ||
} | ||
ctx, ai = h.traceTagRPC(ctx, ai, info.NameResolutionDelay) | ||
return setRPCInfo(ctx, &rpcInfo{ai: ai}) | ||
} | ||
|
||
// HandleRPC handles per RPC tracing implementation. | ||
func (h *clientTracingHandler) HandleRPC(ctx context.Context, rs stats.RPCStats) { | ||
ri := getRPCInfo(ctx) | ||
dfawley marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if ri == nil { | ||
purnesh42H marked this conversation as resolved.
Show resolved
Hide resolved
|
||
logger.Error("ctx passed into client side tracing handler trace event handling has no client attempt data present") | ||
return | ||
} | ||
populateSpan(rs, ri.ai) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we doing this? I would expect every unary interceptor start should be for a new call attempt, so there should never be anything in the context already? Am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so, with this refactor, we have 2 stats handler now 1) metrics and 2) traces. The stats handlers are executed in the order in which they are added. So, if metrics handler executes first, we need to make sure that tracing handler doesn't create a new call info rather use the existing one and add the tracing stuff there. Vice-versa is also true if in future we change the order of interceptors. Basically, each interceptor needs to check if call info already exist or not and then add its info to existing one if present otherwise create a new one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, so we are sharing the same data between the two interceptors.
In that case, can we pull it out into one function and call it from all four places?
getOrCreateCallInfo
or something? And a comment indicating that it may already be present if the other interceptor ran first.