| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // Package tracing provides tracing collection filter. |
| package tracing |
| |
| import ( |
| "context" |
| ) |
| |
| import ( |
| "github.com/opentracing/opentracing-go" |
| "github.com/opentracing/opentracing-go/log" |
| ) |
| |
| import ( |
| "dubbo.apache.org/dubbo-go/v3/common/constant" |
| "dubbo.apache.org/dubbo-go/v3/common/extension" |
| "dubbo.apache.org/dubbo-go/v3/filter" |
| "dubbo.apache.org/dubbo-go/v3/protocol" |
| ) |
| |
| // this should be executed before users set their own Tracer |
| func init() { |
| extension.SetFilter(constant.TracingFilterKey, newTracingFilter) |
| opentracing.SetGlobalTracer(opentracing.NoopTracer{}) |
| } |
| |
| var ( |
| errorKey = "ErrorMsg" |
| successKey = "Success" |
| ) |
| |
| // if you wish to using opentracing, please add the this filter into your filter attribute in your configure file. |
| // notice that this could be used in both client-side and server-side. |
| type tracingFilter struct{} |
| |
| func (tf *tracingFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { |
| var ( |
| spanCtx context.Context |
| span opentracing.Span |
| ) |
| operationName := invoker.GetURL().ServiceKey() + "#" + invocation.MethodName() |
| |
| wiredCtx := ctx.Value(constant.TracingRemoteSpanCtx) |
| preSpan := opentracing.SpanFromContext(ctx) |
| |
| if preSpan != nil { |
| // it means that someone already create a span to trace, so we use the span to be the parent span |
| span = opentracing.StartSpan(operationName, opentracing.ChildOf(preSpan.Context())) |
| spanCtx = opentracing.ContextWithSpan(ctx, span) |
| |
| } else if wiredCtx != nil { |
| |
| // it means that there has a remote span, usually from client side. so we use this as the parent |
| span = opentracing.StartSpan(operationName, opentracing.ChildOf(wiredCtx.(opentracing.SpanContext))) |
| spanCtx = opentracing.ContextWithSpan(ctx, span) |
| } else { |
| // it means that there is not any span, so we create a span as the root span. |
| span, spanCtx = opentracing.StartSpanFromContext(ctx, operationName) |
| } |
| |
| defer func() { |
| span.Finish() |
| }() |
| |
| result := invoker.Invoke(spanCtx, invocation) |
| span.SetTag(successKey, result.Error() == nil) |
| if result.Error() != nil { |
| span.LogFields(log.String(errorKey, result.Error().Error())) |
| } |
| return result |
| } |
| |
| func (tf *tracingFilter) OnResponse(ctx context.Context, result protocol.Result, |
| invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { |
| return result |
| } |
| |
| var tracingFilterInstance filter.Filter |
| |
| func newTracingFilter() filter.Filter { |
| if tracingFilterInstance == nil { |
| tracingFilterInstance = &tracingFilter{} |
| } |
| return tracingFilterInstance |
| } |