google-cloud-run - 向 Cloud Run 中的内部方法添加跟踪
问题描述
我们想为部署在 Cloud Run 上的服务中使用的方法添加跟踪。
跟踪已提供 Cloud Run 请求:
假设我们有以下 gRPC 方法:
func (s *myServiceService) SyncTable(ctx context.Context, req *pb.SyncTableRequest) (*longrunning.Operation, error) {
//.... some stuff here...
// making a call to the internal method, which has a tracing span
err := dropRequestOnStorage(ctx, ...)
if err != nil {
return nil, err
}
return op, nil
}
这是一个内部方法的示例,我们向其中添加了 Trace span,并由主 gRPC 方法调用:
// dropRequestOnStorage loads the requests on the relevant bucket.
func dropRequestOnStorage(ctx context.Context, filename string, operationID string, req *pb.ExtractDataRequest) error {
// add tracing to this method.
ctx, span := otel.Tracer("").Start(ctx, "dropRequestOnStorage")
defer span.End()
// load json object to storage
reqByte, err := protojson.Marshal(req)
if err != nil {
fmt.Println(err)
}
wc := storageClient.Bucket("my-bucket-with-cool-stuff").Object(filename).NewWriter(ctx)
wc.ContentType = "application/json"
_, err = wc.Write(reqByte)
if err != nil {
fmt.Println(err)
}
wc.Close()
fmt.Println(filename)
return nil
}
查看 Google Cloud Run 的跟踪,我看到了上述方法的跟踪:
尽管context
从主 gRPC 传递到内部方法,但 Tracing 并没有被拉到底层内部。内部方法生成的跟踪不会“接收”主 gRPC 跟踪作为父级。
这是因为 Cloud Run 提供的默认跟踪是由 Cloud Run 内部完成的吗?因此在 gRPC 方法的上下文中不可用?
解决方案
使用 gRPC 拦截器进行跟踪
让它工作的唯一方法是添加 gRPC 拦截器来为每个 gRPC 方法创建跟踪跨度。
package main
import (
"context"
texporter "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"google.golang.org/grpc"
"log"
"net"
"os"
)
func init() {
// Pre-declare err to avoid shadowing.
var err error
// initialising tracing exporter
//exporter, err := stdout.NewExporter(stdout.WithPrettyPrint())
exporter, err := texporter.NewExporter(texporter.WithProjectID("alis-de"))
if err != nil {
log.Fatalf("texporter.NewExporter: %v", err)
}
tp := sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithSyncer(exporter),
)
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
}
func main() {
log.Printf("starting server...")
port := os.Getenv("PORT")
if port == "" {
port = "8080"
log.Printf("Defaulting to port %s", port)
}
listener, err := net.Listen("tcp", ":"+port)
if err != nil {
log.Fatalf("net.Listen: %v", err)
}
// Attaching grpc interceptors to automatically enable tracing at gRCP methods
grpcServer := grpc.NewServer(
grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor()),
grpc.StreamInterceptor(otelgrpc.StreamServerInterceptor()),
)
pb.RegisterOperationsServer(grpcServer, &operationsService{})
if err = grpcServer.Serve(listener); err != nil {
log.Fatal(err)
}
}
跟踪现在拉到控制台:
但是,查看 Traces,现在(不幸的是??)有两个跟踪条目:
- Cloud Run 提供的默认跟踪(没有子跟踪)
- gRPC 拦截器生成的新跟踪(带有反映内部调用方法的子跟踪)
推荐阅读
- php - 无法让 PHP lastInsertId() 使用此设置
- ios - 无法将新创建的可可豆荚添加到私有豆荚规范
- sql - 操作重复值?
- angularjs - 需要帮助解决许多元素的 AngularJS 性能问题
- c# - 如果我有“regio”作为输入,我如何获得“温度”
- keyboard - 如何在颤振上堆叠键盘
- python - Python 3 Flask Rest API 获取多个参数
- javascript - 如何修复Nodejs中的“无法读取未定义的属性推送”错误?
- c++ - 在 SDL_RenderClear() 之前保存屏幕?
- c++ - 一个类可以在同一个命名空间中有一个同名的成员吗?