dubbo.apache.org/dubbo-go/v3@v3.1.1/filter/otel/trace/filter.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package trace
    19  
    20  import (
    21  	"context"
    22  )
    23  
    24  import (
    25  	"go.opentelemetry.io/otel"
    26  	"go.opentelemetry.io/otel/baggage"
    27  	"go.opentelemetry.io/otel/codes"
    28  	"go.opentelemetry.io/otel/propagation"
    29  	semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
    30  	"go.opentelemetry.io/otel/trace"
    31  )
    32  
    33  import (
    34  	"dubbo.apache.org/dubbo-go/v3/common/constant"
    35  	"dubbo.apache.org/dubbo-go/v3/common/extension"
    36  	"dubbo.apache.org/dubbo-go/v3/filter"
    37  	"dubbo.apache.org/dubbo-go/v3/protocol"
    38  )
    39  
    40  func init() {
    41  	// TODO: use single filter to simplify filter field in configuration
    42  	extension.SetFilter(constant.OTELServerTraceKey, func() filter.Filter {
    43  		return &otelServerFilter{
    44  			Propagators:    otel.GetTextMapPropagator(),
    45  			TracerProvider: otel.GetTracerProvider(),
    46  		}
    47  	})
    48  	extension.SetFilter(constant.OTELClientTraceKey, func() filter.Filter {
    49  		return &otelClientFilter{
    50  			Propagators:    otel.GetTextMapPropagator(),
    51  			TracerProvider: otel.GetTracerProvider(),
    52  		}
    53  	})
    54  }
    55  
    56  type otelServerFilter struct {
    57  	Propagators    propagation.TextMapPropagator
    58  	TracerProvider trace.TracerProvider
    59  }
    60  
    61  func (f *otelServerFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, protocol protocol.Invocation) protocol.Result {
    62  	return result
    63  }
    64  
    65  func (f *otelServerFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
    66  	attachments := invocation.Attachments()
    67  	bags, spanCtx := Extract(ctx, attachments, f.Propagators)
    68  	ctx = baggage.ContextWithBaggage(ctx, bags)
    69  
    70  	tracer := f.TracerProvider.Tracer(
    71  		constant.OtelPackageName,
    72  		trace.WithInstrumentationVersion(constant.OtelPackageVersion),
    73  	)
    74  
    75  	ctx, span := tracer.Start(
    76  		trace.ContextWithRemoteSpanContext(ctx, spanCtx),
    77  		invocation.ActualMethodName(),
    78  		trace.WithSpanKind(trace.SpanKindServer),
    79  		trace.WithAttributes(
    80  			RPCSystemDubbo,
    81  			semconv.RPCServiceKey.String(invoker.GetURL().ServiceKey()),
    82  			semconv.RPCMethodKey.String(invocation.MethodName()),
    83  		),
    84  	)
    85  	defer span.End()
    86  
    87  	result := invoker.Invoke(ctx, invocation)
    88  
    89  	if result.Error() != nil {
    90  		span.SetStatus(codes.Error, result.Error().Error())
    91  	} else {
    92  		span.SetStatus(codes.Ok, codes.Ok.String())
    93  	}
    94  	return result
    95  }
    96  
    97  type otelClientFilter struct {
    98  	Propagators    propagation.TextMapPropagator
    99  	TracerProvider trace.TracerProvider
   100  }
   101  
   102  func (f *otelClientFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, protocol protocol.Invocation) protocol.Result {
   103  	return result
   104  }
   105  
   106  func (f *otelClientFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
   107  	tracer := f.TracerProvider.Tracer(
   108  		constant.OtelPackageName,
   109  		trace.WithInstrumentationVersion(constant.OtelPackageVersion),
   110  	)
   111  
   112  	var span trace.Span
   113  	ctx, span = tracer.Start(
   114  		ctx,
   115  		invocation.ActualMethodName(),
   116  		trace.WithSpanKind(trace.SpanKindClient),
   117  		trace.WithAttributes(
   118  			RPCSystemDubbo,
   119  			semconv.RPCServiceKey.String(invoker.GetURL().ServiceKey()),
   120  			semconv.RPCMethodKey.String(invocation.MethodName()),
   121  		),
   122  	)
   123  	defer span.End()
   124  
   125  	attachments := invocation.Attachments()
   126  	if attachments == nil {
   127  		attachments = map[string]interface{}{}
   128  	}
   129  	Inject(ctx, attachments, f.Propagators)
   130  	for k, v := range attachments {
   131  		invocation.SetAttachment(k, v)
   132  	}
   133  	result := invoker.Invoke(ctx, invocation)
   134  
   135  	if result.Error() != nil {
   136  		span.SetStatus(codes.Error, result.Error().Error())
   137  	} else {
   138  		span.SetStatus(codes.Ok, codes.Ok.String())
   139  	}
   140  	return result
   141  }