日志服务支持通过 OpenTelemetry SDK 直接写入 Trace 数据到日志服务。本文档以 Go SDK 为例,演示 Golang 应用接入 Trace 服务的操作步骤,适用于业务系统首次使用全链路追踪服务的场景。
go version
检查当前 Go 的版本信息。在微服务、分布式等涉及多个服务交互的架构或系统中,可以使用全链路追踪服务进行服务调用链路分析或架构性能监控。日志服务通过 Trace 服务提供基于 OpenTelemetry 标准协议的分布式链路追踪能力,您可以参考本文档,在业务系统中部署 Trace 服务,在数据源上启用 Trace 事件,采集并发送日志数据到火山引擎日志服务中。
在日志服务控制台中创建一个 Trace 实例,用于配合业务系统采集并发送、管理 Trace 数据。日志服务会同步创建一个日志主题用于存储 Trace 数据。详细操作步骤请参考创建 Trace 实例。
在本地 Go 项目中执行以下命令添加对应依赖。
# 添加otel协议依赖 go get go.opentelemetry.io/otel go get go.opentelemetry.io/otel/trace go get go.opentelemetry.io/otel/bridge/opentracing # 添加otel exporter的依赖(用户需要通过exporter向日志服务发送trace数据) go get go.opentelemetry.io/otel/exporters/otlp/otlptrace # 添加http exporter依赖(如果配置的是日志服务的http端口,需要添加这个依赖) go get go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp # 添加grpc exporter依赖(如果配置的是日志服务的grpc端口,需要添加这个依赖) go get go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc
添加依赖后,您需要通过执行代码完成 OpenTelemetry Provider 的初始化。您需要指定要使用的数据传输协议,以便 OpenTelemetry 将数据从您的应用程序传输到 Trace 实例。在 Tracer 类的构造函数中,可以使用协议参数来指定该协议。
初始化时应配置日志服务接入点和鉴权相关参数,详细信息请参考参数说明。日志服务支持通过以下方式配置鉴权信息:
通过 HTTP 协议方式接入 Trace 服务时,可参考以下示例代码完成 OpenTelemetry Provider 的初始化。日志服务提供两种鉴权参数的配置方式,您可以按需选择对应的示例代码进行接入。详细参数信息请参考参数说明。
通过 OpenTelemetry 协议的 Resource 参数配置鉴权参数:
import ( "context" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" "go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.10.0" ) // 初始化endpoint为日志服务http open telemetry协议端口并且在trace数据的body中添加鉴权信息的TracerProvider func InitTlsOtelTracerWithHttpResource(endPoint string, topicId string, ak string, sk string, region string) *trace.TracerProvider { traceTopicKey := attribute.Key("tls.otel.tracetopic") akKey := attribute.Key("tls.otel.ak") skKey := attribute.Key("tls.otel.sk") regionKey := attribute.Key("tls.otel.region") opts := []otlptracehttp.Option{otlptracehttp.WithEndpoint(endPoint + ":4318")} // endpoint为http 【参数配置】 exporter, _ := otlptrace.New( context.Background(), otlptracehttp.NewClient(opts...), ) tp := trace.NewTracerProvider( trace.WithBatcher(exporter), trace.WithResource(resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceNameKey.String("your_service_name"), // 在otel请求body中添加TLS需要的鉴权字段,参考【参数配置】 traceTopicKey.String(topicId), akKey.String(ak), skKey.String(sk), regionKey.String(region), )), ) return tp }
在 HTTPS 协议的请求头(Header)中配置鉴权参数:
import ( "context" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" "go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.10.0" ) // 初始化endpoint为日志服务http open telemetry协议端口并且在http请求的hader中添加鉴权信息的TracerProvider func InitTlsOtelTracerWithHttpHeader(endPoint string, topicId string, ak string, sk string, region string) *trace.TracerProvider { // 在http header中添加TLS需要的鉴权字段,参考【参数配置】 opts := []otlptracehttp.Option{otlptracehttp.WithEndpoint(endPoint + ":4318"), // endpoint参考【参数配置】 otlptracehttp.WithHeaders(map[string]string{"x-tls-otel-tracetopic": topicId, "x-tls-otel-ak": ak, "x-tls-otel-sk": sk, "x-tls-otel-region": region})} exporter, _ := otlptrace.New( context.Background(), otlptracehttp.NewClient(opts...), ) tp := trace.NewTracerProvider( trace.WithBatcher(exporter), trace.WithResource(resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceNameKey.String("your_service_name"), )), ) return tp }
通过 gRPC 协议方式接入 Trace 服务时,可参考以下示例代码完成 OpenTelemetry Provider 的初始化。日志服务提供两种鉴权参数的配置方式,您可以按需选择对应的示例代码进行接入。详细参数信息请参考参数说明。
通过 OpenTelemetry 协议的 Resource 参数配置鉴权参数:
import ( "context" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.10.0" "google.golang.org/grpc/credentials/insecure" ) // 初始化endpoint为日志服务grpc open telemetry协议端口并且在trace数据的body中添加鉴权信息的TracerProvider func InitTlsOtelTracerWithGrpcResource(endPoint string, topicId string, ak string, sk string, region string) *trace.TracerProvider { exporter, _ := otlptrace.New( context.Background(), otlptracegrpc.NewClient(otlptracegrpc.WithTLSCredentials(insecure.NewCredentials()), otlptracegrpc.WithEndpoint(endPoint+":4317")), // endpoint为grpc 【参数配置】 ) traceTopicKey := attribute.Key("tls.otel.tracetopic") akKey := attribute.Key("tls.otel.ak") skKey := attribute.Key("tls.otel.sk") regionKey := attribute.Key("tls.otel.region") tp := trace.NewTracerProvider( trace.WithBatcher(exporter), trace.WithResource(resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceNameKey.String("your_service_name"), // 在otel请求body中添加TLS需要的鉴权字段,参考【参数配置】 traceTopicKey.String(topicId), akKey.String(ak), skKey.String(sk), regionKey.String(region), )), ) return tp }
在 gRPC 协议的请求头(Header)中配置鉴权参数:
import ( "context" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.10.0" "google.golang.org/grpc/credentials/insecure" ) // 初始化endpoint为日志服务grpc open telemetry协议端口并且在grpc请求的hader中添加鉴权信息的TracerProvider func InitTlsOtelTracerWithGrpcHeader(endPoint string, topicId string, ak string, sk string, region string) *trace.TracerProvider { // 在grpc header中添加TLS需要的鉴权字段,参考【参数配置】 exporter, _ := otlptrace.New( context.Background(), // otlptracegrpc.WithTLSCredentials(insecure.NewCredentials()) 配置tls方式访问 otlptracegrpc.NewClient(otlptracegrpc.WithTLSCredentials(insecure.NewCredentials()), otlptracegrpc.WithEndpoint(endPoint+":4317"), // endpoint为grpc 【参数配置】 otlptracegrpc.WithHeaders(map[string]string{"x-tls-otel-tracetopic": topicId, "x-tls-otel-ak": ak, "x-tls-otel-sk": sk, "x-tls-otel-region": region})), ) tp := trace.NewTracerProvider( trace.WithBatcher(exporter), trace.WithResource(resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceNameKey.String("your_service_name"), )), ) return tp }
初始化 Provider 时,需要在初始化代码中配置接入点和鉴权相关的参数,参数说明如下。
接入点相关参数
endpoint 为日志服务的接入点信息,由服务地址和端口号组成,不同协议类型的端口号不同。接入点格式为 ${tls_endpoint}:端口号
,其中 ${tls_endpoint}
为日志服务的服务地址,获取方式请参考服务地址。
${tls_endpoint}:4318
。例如 https://tls-cn-beijing.ivolces.com:4318
。${tls_endpoint}:4317
,例如 https://tls-cn-beijing.ivolces.com:4317
。鉴权相关参数: 您可以在初始化时通过两种方式配置鉴权信息,即在 gRPC 协议、HTTPS 协议的 Header 中或 OpenTelemetry 协议的 Resource 字段中配置。不同配置方式的参数说明如下。
Header key | Resource key | 示例 | 说明 |
---|---|---|---|
x-tls-otel-tracetopic | tls.otel.tracetopic | 39f0bce1-e37e-4dc5-ab06-801d310b**** | 用于存储 Trace 数据的日志主题 ID。 |
x-tls-otel-ak | tls.otel.ak | AKKTNTA1OTlmOWQ1NTM5DNk5OIWwZGNmMTg0ZWUxNmU**** | 火山引擎主账号或子账号的 Access Key ID。 在火山引擎控制台密钥管理页面,根据页面提示查看并复制 Access Key ID。 |
x-tls-otel-sk | tls.otel.sk | T0RPLS5EUTFZV1JrTmpAKE5EaGCVRGsxTjJVMk5UTTBNV1UzKODJME1U**** | 火山引擎主账号或子账号的 Secret Access Key。 在火山引擎控制台密钥管理页面,根据页面提示查看并复制 Secret Access Key。 |
x-tls-otel-region | tls.otel.region | cn-beijing | Trace 实例所在的地域 ID(Region)。您可以在服务地址中查看指定地域的 ID。 |
参考以下示例代码,通过 tlsOtelTracer 发送 Trace 数据到火山引擎日志服务。详细说明请参考 OpenTelemetry 官方文档。
说明
package main import ( "context" "fmt" "math/rand" "strconv" "time" "github.com/google/uuid" "github.com/opentracing/opentracing-go" "github.com/opentracing/opentracing-go/ext" "go.opentelemetry.io/otel/attribute" otbridge "go.opentelemetry.io/otel/bridge/opentracing" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" "go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.10.0" "google.golang.org/grpc/credentials/insecure" ) func main() { SendTrace(1000) time.Sleep(time.Minute) } func SendTrace(traceCnt int) { endPoint := "tls-cn-beijing.volces.com" // 别的region请更换相关域名,私网请使用私网域名 topicId := "${topicId}" ak := "${AK}" sk := "${SK}" region := "cn-shanghai" // 别的region请更换相关region // 选择不同的方式初始化trace provider httpHeaderProvider := InitTlsOtelTracerWithHttpHeader(endPoint, topicId, ak, sk, region) // httpResourceProvider := InitTlsOtelTracerWithHttpResource(endPoint, topicId, ak, sk, region) // grpcHeaderProvider := InitTlsOtelTracerWithGrpcHeader(endPoint, topicId, ak, sk, region) // grpcResourceProvider := InitTlsOtelTracerWithGrpcResource(endPoint, topicId, ak, sk, region) tracer, _ := otbridge.NewTracerPair(httpHeaderProvider.Tracer("my_trace")) ctx := context.TODO() for i := 0; i < traceCnt; i++ { sendTrace(ctx, tracer) } } func sendTrace(ctx context.Context, tracer *otbridge.BridgeTracer) { var OperationName []string OperationName = append(OperationName, "Operation_1", "Operation_2", "Operation_3", "Operation_4", "Operation_5") i := 0 var last_span opentracing.Span var span opentracing.Span for { uid, _ := uuid.NewUUID() index := strconv.Itoa(i) if i == 0 { span = spanInit(true, ctx, "test.span."+index, tracer, nil) } else { span = spanInit(false, ctx, "test.span"+index, tracer, last_span.Context()) } ext.SpanKindRPCClient.Set(span) ext.PeerService.Set(span, "tls-test-service") // // // #nosec span.LogKV( "event", "soft error", "type", "cache timeout", "waited.millis", 1500) span.SetTag("uuid", uid.String()) span.SetTag("host", "") span.SetBaggageItem("BaggageItem", "TLS test") span.SetOperationName(OperationName[rand.Intn(4)]) span.FinishWithOptions(opentracing.FinishOptions{FinishTime: time.Now()}) last_span = span fmt.Println("successful", i) i++ if i > 100 { break } } } func spanInit(isRoot bool, context context.Context, span_name string, otTracer *otbridge.BridgeTracer, childOfSpanContext opentracing.SpanContext) opentracing.Span { var span opentracing.Span if isRoot { span, _ = opentracing.StartSpanFromContext(context, span_name+".root.span") } else { span = otTracer.StartSpan("TLS test", opentracing.ChildOf(childOfSpanContext)) } return span } // 初始化endpoint为日志服务http open telemetry协议端口并且在http请求的hader中添加鉴权信息的TracerProvider func InitTlsOtelTracerWithHttpHeader(endPoint string, topicId string, ak string, sk string, region string) *trace.TracerProvider { // 在http header中添加TLS需要的鉴权字段,参考【参数配置】 opts := []otlptracehttp.Option{otlptracehttp.WithEndpoint(endPoint + ":4318"), // endpoint参考【参数配置】 otlptracehttp.WithHeaders(map[string]string{"x-tls-otel-tracetopic": topicId, "x-tls-otel-ak": ak, "x-tls-otel-sk": sk, "x-tls-otel-region": region})} exporter, _ := otlptrace.New( context.Background(), otlptracehttp.NewClient(opts...), ) tp := trace.NewTracerProvider( trace.WithBatcher(exporter), trace.WithResource(resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceNameKey.String("your_service_name"), )), ) return tp } // 初始化endpoint为日志服务http open telemetry协议端口并且在trace数据的body中添加鉴权信息的TracerProvider func InitTlsOtelTracerWithHttpResource(endPoint string, topicId string, ak string, sk string, region string) *trace.TracerProvider { traceTopicKey := attribute.Key("tls.otel.tracetopic") akKey := attribute.Key("tls.otel.ak") skKey := attribute.Key("tls.otel.sk") regionKey := attribute.Key("tls.otel.region") opts := []otlptracehttp.Option{otlptracehttp.WithEndpoint(endPoint + ":4318")} // endpoint为http 【参数配置】 exporter, _ := otlptrace.New( context.Background(), otlptracehttp.NewClient(opts...), ) tp := trace.NewTracerProvider( trace.WithBatcher(exporter), trace.WithResource(resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceNameKey.String("your_service_name"), // 在otel请求body中添加TLS需要的鉴权字段,参考【参数配置】 traceTopicKey.String(topicId), akKey.String(ak), skKey.String(sk), regionKey.String(region), )), ) return tp } // 初始化endpoint为日志服务grpc open telemetry协议端口并且在grpc请求的hader中添加鉴权信息的TracerProvider func InitTlsOtelTracerWithGrpcHeader(endPoint string, topicId string, ak string, sk string, region string) *trace.TracerProvider { // 在grpc header中添加TLS需要的鉴权字段,参考【参数配置】 exporter, _ := otlptrace.New( context.Background(), // otlptracegrpc.WithTLSCredentials(insecure.NewCredentials()) 配置tls方式访问 otlptracegrpc.NewClient(otlptracegrpc.WithTLSCredentials(insecure.NewCredentials()), otlptracegrpc.WithEndpoint(endPoint+":4317"), // endpoint为grpc 【参数配置】 otlptracegrpc.WithHeaders(map[string]string{"x-tls-otel-tracetopic": topicId, "x-tls-otel-ak": ak, "x-tls-otel-sk": sk, "x-tls-otel-region": region})), ) tp := trace.NewTracerProvider( trace.WithBatcher(exporter), trace.WithResource(resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceNameKey.String("your_service_name"), )), ) return tp } // 初始化endpoint为日志服务grpc open telemetry协议端口并且在trace数据的body中添加鉴权信息的TracerProvider func InitTlsOtelTracerWithGrpcResource(endPoint string, topicId string, ak string, sk string, region string) *trace.TracerProvider { exporter, _ := otlptrace.New( context.Background(), otlptracegrpc.NewClient(otlptracegrpc.WithTLSCredentials(insecure.NewCredentials()), otlptracegrpc.WithEndpoint(endPoint+":4317")), // endpoint为grpc 【参数配置】 ) traceTopicKey := attribute.Key("tls.otel.tracetopic") akKey := attribute.Key("tls.otel.ak") skKey := attribute.Key("tls.otel.sk") regionKey := attribute.Key("tls.otel.region") tp := trace.NewTracerProvider( trace.WithBatcher(exporter), trace.WithResource(resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceNameKey.String("your_service_name"), // 在otel请求body中添加TLS需要的鉴权字段,参考【参数配置】 traceTopicKey.String(topicId), akKey.String(ak), skKey.String(sk), regionKey.String(region), )), ) return tp }
成功接入 Trace 数据后,您可以通过日志服务的检索分析功能,在线查看采集到的 Trace 数据。如果 Trace 实例对应的日志主题中可检索到您上传的 Trace 数据,表示接入成功。检索 Trace 数据的方式,请参考检索日志。
例如,您可以通过以下 SQL 语法检索指定 TraceID 对应的 Trace 数据详情。
* | select * where TraceID = '877247fa95024d2f3a1234216010****'