我刚刚开始使用OpenTelemeter,并为此创建了两个(微)服务:Standard和GeoMap.
终端用户向Standard服务发送请求,后者又向GeoMap发送请求以在将结果返回给终端用户之前获取信息.我正在使用GRPC进行所有通信.
我将我的职能作为工具如下:
对于Standard人:
type standardService struct {
pb.UnimplementedStandardServiceServer
}
func (s *standardService) GetStandard(ctx context.Context, in *pb.GetStandardRequest) (*pb.GetStandardResponse, error) {
conn, _:= createClient(ctx, geomapSvcAddr)
defer conn1.Close()
newCtx, span1 := otel.Tracer(name).Start(ctx, "GetStandard")
defer span1.End()
countryInfo, err := pb.NewGeoMapServiceClient(conn).GetCountry(newCtx,
&pb.GetCountryRequest{
Name: in.Name,
})
//...
return &pb.GetStandardResponse{
Standard: standard,
}, nil
}
func createClient(ctx context.Context, svcAddr string) (*grpc.ClientConn, error) {
return grpc.DialContext(ctx, svcAddr,
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()),
)
}
对于GeoMap人:
type geomapService struct {
pb.UnimplementedGeoMapServiceServer
}
func (s *geomapService) GetCountry(ctx context.Context, in *pb.GetCountryRequest) (*pb.GetCountryResponse, error) {
_, span := otel.Tracer(name).Start(ctx, "GetCountry")
defer span.End()
span.SetAttributes(attribute.String("country", in.Name))
span.AddEvent("Retrieving country info")
//...
span.AddEvent("Country info retrieved")
return &pb.GetCountryResponse{
Country: &country,
}, nil
}
这两个服务都被配置为将它们的跨度发送到Jaeger后端,并共享几乎相同的Main函数(注释中指出了微小的差异):
const (
name = "mapedia"
service = "geomap" //or standard
environment = "production"
id = 1
)
func tracerProvider(url string) (*tracesdk.TracerProvider, error) {
// Create the Jaeger exporter
exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(url)))
if err != nil {
return nil, err
}
tp := tracesdk.NewTracerProvider(
// Always be sure to batch in production.
tracesdk.WithBatcher(exp),
// Record information about this application in a Resource.
tracesdk.WithResource(resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName(service),
attribute.String("environment", environment),
attribute.Int64("ID", id),
)),
)
return tp, nil
}
func main() {
tp, err := tracerProvider("http://localhost:14268/api/traces")
if err != nil {
log.Fatal(err)
}
defer func() {
if err := tp.Shutdown(context.Background()); err != nil {
log.Fatal(err)
}
}()
otel.SetTracerProvider(tp)
listener, err := net.Listen("tcp", ":"+port)
if err != nil {
panic(err)
}
s := grpc.NewServer(
grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor()),
)
reflection.Register(s)
pb.RegisterGeoMapServiceServer(s, &geomapService{}) // or pb.RegisterStandardServiceServer(s, &standardService{})
if err := s.Serve(listener); err != nil {
log.Fatalf("Failed to serve: %v", err)
}
}
当我查看由终端用户对Standard服务的请求生成的跟踪时,我可以看到,正如预期的那样,它正在调用其GeoMap服务:
但是,我没有看到我添加到子范围中的任何属性或事件(在检测GeoMap的GetCountry函数时,我添加了一个属性和两个事件).
然而,我注意到,这些属性在另一个单独的跟踪中可用(在Jaeger中的"geomap"服务下可用),其SPAN ID与Standard服务中的子跨距完全无关:
现在,我期望的是只有一个跟踪,并在Standard范围内看到与子范围中的GeoMap相关的所有属性/事件.从这里怎样才能达到预期的效果?