grpc 集成 opentelemetry

文章介绍了如何在Go语言的服务端和客户端代码中集成OpenTelemetry和Jaeger,以实现分布式追踪,包括创建TracerProvider、设置资源属性和使用gRPC的拦截器进行OpenTelemetry追踪。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

服务端代码:

package main

import (
   "context"
   "flag"
   "fmt"
   "go.opentelemetry.io/otel"
   "go.opentelemetry.io/otel/attribute"
   "go.opentelemetry.io/otel/exporters/jaeger"
   "go.opentelemetry.io/otel/propagation"
   "go.opentelemetry.io/otel/sdk/resource"
   "go.opentelemetry.io/otel/sdk/trace"
   "google.golang.org/grpc/codes"
   "google.golang.org/grpc/status"
   "log"
   "net"

   pb "GoStart/error/rpc"
   "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
   "google.golang.org/grpc"

   semconv "go.opentelemetry.io/otel/semconv/v1.12.0"
)

const (
   traceName = "mxshop-otel"
)

var tp *trace.TracerProvider

func tracerProvider() error {
   url := "http://127.0.0.1:14268/api/traces"
   jexp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(url)))
   if err != nil {
      panic(err)
   }

   tp = trace.NewTracerProvider(
      trace.WithBatcher(jexp),
      trace.WithResource(
         resource.NewWithAttributes(
            semconv.SchemaURL,
            semconv.ServiceNameKey.String("mxshop-user"),
            attribute.String("environment", "dev"),
            attribute.Int("ID", 1),
         ),
      ),
   )
   otel.SetTracerProvider(tp)
   otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
   return nil
}

var (
   port = flag.Int("port", 50052, "The server port")
)

// server is used to implement helloworld.GreeterServer.
type server struct {
   pb.UnimplementedGreeterServer
}

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
   log.Printf("Received: %v", in.GetName())
   return nil, status.Error(codes.NotFound, "user not found")
   //return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

func main() {
   _ = tracerProvider()
   flag.Parse()
   lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
   if err != nil {
      log.Fatalf("failed to listen: %v", err)
   }
    //添加拦截器(grpc集成OpenTelemetry主要是调用(otelgrpc.UnaryServerInterceptor()) 
   s := grpc.NewServer(grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor()))
   pb.RegisterGreeterServer(s, &server{})
   log.Printf("server listening at %v", lis.Addr())
   if err := s.Serve(lis); err != nil {
      log.Fatalf("failed to serve: %v", err)
   }
}

客户端代码:

package main

import (
   "context"
   "flag"
   "fmt"
   "go.opentelemetry.io/otel"
   "go.opentelemetry.io/otel/attribute"
   "go.opentelemetry.io/otel/exporters/jaeger"
   "go.opentelemetry.io/otel/propagation"
   "go.opentelemetry.io/otel/sdk/resource"
   "go.opentelemetry.io/otel/sdk/trace"
   "log"
   "time"

   pb "GoStart/error/rpc"
   "google.golang.org/grpc"
   "google.golang.org/grpc/credentials/insecure"
   "google.golang.org/grpc/status"

   "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
   semconv "go.opentelemetry.io/otel/semconv/v1.12.0"
)

const (
   traceName = "mxshop-otel"
)

var tp *trace.TracerProvider

func tracerProvider() error {
   url := "http://127.0.0.1:14268/api/traces"
   jexp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(url)))
   if err != nil {
      panic(err)
   }

   tp = trace.NewTracerProvider(
      trace.WithBatcher(jexp),
      trace.WithResource(
         resource.NewWithAttributes(
            semconv.SchemaURL,
            semconv.ServiceNameKey.String("mxshop-user"),
            attribute.String("environment", "dev"),
            attribute.Int("ID", 1),
         ),
      ),
   )
   otel.SetTracerProvider(tp)
   otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
   return nil
}

const (
   defaultName = "world"
)

var (
   addr = flag.String("addr", "localhost:50052", "the address to connect to")
   name = flag.String("name", defaultName, "Name to greet")
)

func main() {
   _ = tracerProvider()

   flag.Parse()
   // Set up a connection to the server.
   conn, err := grpc.Dial(*addr,
      grpc.WithTransportCredentials(insecure.NewCredentials()),
       //添加拦截器(grpc集成OpenTelemetry主要是调用(otelgrpc.UnaryClientInterceptor())                    
      grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()),
   )
   if err != nil {
      log.Fatalf("did not connect: %v", err)
   }
   defer conn.Close()
   c := pb.NewGreeterClient(conn)

   // Contact the server and print out its response.
   ctx, cancel := context.WithTimeout(context.Background(), time.Second)
   defer cancel()
   r, err := c.SayHello(ctx, &pb.HelloRequest{Name: *name})
   if err != nil {
      s, ok := status.FromError(err)
      if !ok {
         log.Fatalf("err is not standard grpc error: %v", err)
      }
      fmt.Println(s.Code())
   }
   log.Printf("Greeting: %s", r.GetMessage())
}
### 集成 OpenTelemetry 和 etcd 的方法 为了实现 OpenTelemetry 与 etcd 的集成,主要目标是在 etcd 客户端和服务端之间传播追踪上下文,并收集分布式跟踪数据。这有助于监控和诊断基于 etcd 构建的应用程序中的性能瓶颈。 #### 使用 OpenTelemetry SDK 初始化 Tracer Provider 首先,在应用程序中初始化 OpenTelemetry 的 `TracerProvider` 并配置导出器用于发送跟踪记录到所选的后端分析工具: ```python from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace.export import BatchSpanProcessor resource = Resource(attributes={ "service.name": "my-etcd-service" }) trace.set_tracer_provider(TracerProvider(resource=resource)) tracer_provider = trace.get_tracer_provider() otlp_exporter = OTLPSpanExporter(endpoint="http://localhost:4317", insecure=True) span_processor = BatchSpanProcessor(otlp_exporter) tracer_provider.add_span_processor(span_processor) ``` #### 创建带有上下文传播功能的 gRPC 中间件 由于 etcd 是通过 gRPC 协议通信的服务,因此需要创建自定义中间件来拦截请求并注入或提取追踪头信息。对于客户端而言,这意味着在发起调用前设置必要的 HTTP 头;而对于服务端,则是从传入请求读取这些头部信息以便继续当前跨度[^2]。 ```python import grpc from opentelemetry.instrumentation.grpc import client_interceptor, GrpcInstrumentorClient from opentelemetry.propagate import inject from opentelemetry.context import attach, detach def create_etcd_client_with_opentelemetry(): instrumentor = GrpcInstrumentorClient() instrumentor.instrument() def open_telemetry_metadata_callback(context, callback): carrier = {} inject(carrier) metadata = list(context.invocation_metadata()) metadata.extend([(key, value) for key, value in carrier.items()]) callback(metadata, None) channel_credentials = grpc.ssl_channel_credentials() interceptors = [client_interceptor(open_telemetry_metadata_callback)] with grpc.secure_channel('etcd-endpoint', credentials=channel_credentials, options=(('grpc.enable_retries', 0),), compression=None, interceptors=tuple(interceptors)) as channel: yield channel ``` 上述代码片段展示了如何利用 Python 版本的 OpenTelemetry 库为 etcd 客户端添加追踪支持。请注意替换 `'etcd-endpoint'` 为实际的目标地址。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值