赛尔校园公共服务平台 Logo
平台使用
阿里云
百度云
移动云
智算服务
教育生态
登录 →
赛尔校园公共服务平台 Logo
平台使用 阿里云 百度云 移动云 智算服务 教育生态
登录
  1. 首页
  2. 阿里云
  3. 日志服务
  4. 操作指南
  5. 日志应用
  6. 全栈可观测
  7. Trace
  8. 接入Trace数据
  9. 新接入方案
  10. 通过OpenTelemetry接入Golang Trace数据

通过OpenTelemetry接入Golang Trace数据

  • 新接入方案
  • 发布于 2025-04-22
  • 0 次阅读
文档编辑
文档编辑

本文介绍通过OpenTelemetry Golang SDK将Golang应用的Trace数据接入到日志服务的操作步骤。

前提条件

  • 已创建Trace实例。更多信息,请参见创建Trace实例。
  • 已安装Golang 1.13及以上版本的开发环境。

接入流程

  1. 初始化OpenTelemetry Provider。

  2. 判断是否符合半自动接入条件。

    • 如果符合,则您可以使用半自动方式接入Trace数据。

      当半自动方式无法覆盖您的所有场景时,余下场景您需要使用手动方式接入Trace数据。

    • 如果不符合,则您可以使用手动方式接入Trace数据。

步骤1:初始化OpenTelemetry Provider

为简化OpenTelemetry Provider的使用,日志服务提供SLS Provider用于快速构建并上传至日志服务的相关依赖项。

重要

您需要在创建Traces、注册Metrics之前,完成OpenTelemetry Provider的初始化。

您可以通过运行代码或配置环境变量完成OpenTelemetry Provider的初始化,详细说明如下:

  • 通过运行代码完成初始化。

    1. 添加依赖项。

      module opentelemetry-golang-sample
      
      go 1.13
      
      require (
          github.com/aliyun-sls/opentelemetry-go-provider-sls v0.10.0
          go.opentelemetry.io/otel v1.16.0
          go.opentelemetry.io/otel/metric v1.16.0
          go.opentelemetry.io/otel/trace v1.16.0
      )
      
    2. 配置初始化代码。

      如下代码中的变量需根据实际情况替换。关于变量的详细说明,请参见变量说明。

      package main
      
      import (
          "github.com/aliyun-sls/opentelemetry-go-provider-sls/provider"
      )
      
      func main() {
      
          slsConfig, err := provider.NewConfig(provider.WithServiceName("${service}"),
              provider.WithServiceNamespace("${service.namespace}"),
              provider.WithServiceVersion("${version}"),
              provider.WithTraceExporterEndpoint("${endpoint}"),
              provider.WithMetricExporterEndpoint("${endpoint}"),
              provider.WithSLSConfig("${project}", "${instance}", "${access-key-id}", "${access-key-secret}"))
          // 使用panic(),表示如果初始化失败则程序直接异常退出,您也可以使用其他错误处理方式。
          if err != nil {
              panic(err)
          }
          if err := provider.Start(slsConfig); err != nil {
              panic(err)
          }
          defer provider.Shutdown(slsConfig)
          
          // 添加业务逻辑代码。
          ...
      }

      表 1. 变量说明

      变量

      说明

      示例

      ${service}

      服务名。根据您的实际场景取值。

      payment

      ${service.namespace}

      服务归属的命名空间。

      order

      ${version}

      服务版本号。建议按照va.b.c格式定义。

      v0.1.2

      ${endpoint}

      日志服务Project的接入地址,格式为${project}.${region-endpoint}:Port,其中:

      • ${project}:日志服务Project名称。

      • ${region-endpoint}:日志服务Project所在地域的访问域名,支持公网和阿里云内网(经典网络、VPC)。更多信息,请参见服务入口。

      • Port:网络端口,固定为10010。

      说明
      • 如果配置为stdout,即provider.WithTraceExporterEndpoint("stdout"),表示将数据打印到标准输出。

      • 如果配置为空值,表示不上传Trace数据到日志服务。

      test-project.cn-hangzhou.log.aliyuncs.com:10010

      ${project}

      日志服务Project名称。

      test-project

      ${instance}

      Trace服务实例ID。更多信息,请参见创建Trace实例。

      test-traces

      ${access-key-id}

      阿里云账号AccessKey ID。

      建议您使用只具备日志服务Project写入权限的RAM用户的AccessKey(包括AccessKey ID和AccessKey Secret)。授予RAM用户向指定Project写入数据权限的具体操作,请参见授权。如何获取AccessKey的具体操作,请参见访问密钥。

      无

      ${access-key-secret}

      阿里云账号AccessKey Secret。

      建议您使用只具备日志服务Project写入权限的RAM用户的AccessKey。

      无

  • 通过配置环境变量完成初始化。

    配置方法

    环境变量

    是否必选

    说明

    默认值

    WithServiceName

    SLS_OTEL_SERVICE_NAME

    是

    服务名。根据您的实际场景取值即可。

    无

    WithServiceNamespace

    SLS_OTEL_SERVICE-NAMESPACE

    否

    服务归属的命名空间。

    order

    WithServiceVersion

    SLS_OTEL_SERVICE_VERSION

    是

    服务版本号。建议按照va.b.c格式定义。

    v0.1.0

    WithSLSConfig

    SLS_OTEL_PROJECT、SLS_OTEL_INSTANCE_ID、SLS_OTEL_ACCESS_KEY_ID、SLS_OTEL_ACCESS_KEY_SECRET

    否

    日志服务资源信息,包括Project名称、Trace实例名称、具备Project只写权限的AccessKey ID和AccessKey Secret。授予RAM用户向指定Project写入数据权限的具体操作,请参见授权。如何获取AccessKey的具体操作,请参见访问密钥。

    无

    WithTraceExporterEndpoint

    SLS_OTEL_TRACE_ENDPOINT

    否

    日志服务Project的接入地址,格式为${project}.${region-endpoint}:Port,其中:

    • ${project}:日志服务Project名称。

    • ${region-endpoint}:日志服务Project所在地域的访问域名,支持内网和公网访问。更多信息,请参见服务入口。

    • Port:网络端口,固定为10010。

    说明
    • 如果配置为stdout,表示将数据打印到标准输出。

    • 如果配置为空值,表示不上传Trace数据到日志服务。

    stdout

    WithTraceExporterInsecure

    SLS_OTEL_TRACE_INSECURE

    否

    是否使用非安全方式传输。

    • true:使用非安全方式传输。

    • false:使用安全方式传输。

    说明

    如果直接传输到日志服务,则必须配置为false。

    false

    WithMetricExporterEndpoint

    SLS_OTEL_METRIC_ENDPOINT

    否

    日志服务Project的接入地址,格式为${project}.${region-endpoint}:Port,其中:

    • ${project}:日志服务Project名称。

    • ${region-endpoint}:日志服务Project所在地域的访问域名,支持内网和公网访问。更多信息,请参见服务入口。

    • Port:网络端口,固定为10010。

    说明
    • 如果配置为stdout,表示将数据打印到标准输出。

    • 如果配置为空值,表示不上传时序数据到日志服务。

    stdout

    WithMetricExporterInsecure

    SLS_OTEL_METRIC_INSECURE

    否

    是否使用非安全方式传输。

    • true:使用非安全方式传输。

    • false:使用安全方式传输。

    说明

    如果直接传输到日志服务,则必须配置为false。

    false

    WithResourceAttributes

    无

    否

    配置附加的Tag信息,例如环境、可用区等信息。

    无

    WithResource

    OTEL_RESOURCE_ATTRIBUTES

    否

    配置附加的Tag信息,例如环境、可用区等信息。配置格式为key1=value1,key2=value2。

    无

    WithMetricReportingPeriod

    SLS_OTEL_METRIC_EXPORT_PERIOD

    否

    Metric输出间隔,建议设置区间为15s~60s。

    30s

    WithErrorHandler

    无

    否

    错误处理函数。在SDK内部出错时,会调用该函数,作用等同于WithErrorHandlerFunc。

    无

    WithErrorHandlerFunc

    无

    否

    错误处理函数。

    无

    无

    SLS_OTEL_ATTRIBUTES_ENV_KEYS

    否

    配置附加的Tag信息,例如环境、可用区等信息。类似于OTEL_RESOURCE_ATTRIBUTES。区别在于SLS_OTEL_ATTRIBUTES_ENV_KEYS定义的Attribute Key,其实际值从对应的环境变量中读取。

    常用于K8s场景中将部分模板值填充到特定的环境变量中。配置格式为env-key-1|env-key-2|env-key-3。

    无

步骤2:接入数据

  • (推荐)半自动接入

    OpenTelemetry提供众多基础库的自动埋点方案,如果您的业务依赖于这些基础库,则可以使用这些基础库的自动埋点方案来接入数据。关于基础库的更多信息,请参见Golang自动埋点方案。

    • net、http接入

      如下示例基于go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.37.0版本创建。更多信息,请参见otel-http-example。

      如下代码中的变量需根据实际情况替换。关于变量的详细说明,请参见变量说明。

      package main
      
      import (
          "fmt"
          "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
          "go.opentelemetry.io/otel/attribute"
          "go.opentelemetry.io/otel/metric/global"
          "io"
          "net/http"
          "time"
      
          "github.com/aliyun-sls/opentelemetry-go-provider-sls/provider"
      
          "go.opentelemetry.io/otel/trace"
      )
      
      func main() {
      
          slsConfig, err := provider.NewConfig(provider.WithServiceName("${service}"),
              provider.WithServiceNamespace("${service.namespace}"),
              provider.WithServiceVersion("${version}"),
              provider.WithTraceExporterEndpoint("${endpoint}"),
              provider.WithMetricExporterEndpoint("${endpoint}"),
              provider.WithSLSConfig("${project}", "${instance}", "${access-key-id}", "${access-key-secret}"))
          // 使用panic(),表示如果初始化失败则程序直接异常退出,您也可以使用其他错误处理方式。
          if err != nil {
              panic(err)
          }
          if err := provider.Start(slsConfig); err != nil {
              panic(err)
          }
          defer provider.Shutdown(slsConfig)
      
          // 如果您需要分析应用中的指标数据,可以注册相关的Metric指标。
          labels := []attribute.KeyValue{
              attribute.String("label1", "value1"),
          }
          meter := global.Meter("aliyun.sls")
          sayDavidCount, _ := meter.Int64Counter("say_david_count")
      
          helloHandler := func(w http.ResponseWriter, req *http.Request) {
              if time.Now().Unix()%10 == 0 {
                  _, _ = io.WriteString(w, "Hello, world!\n")
              } else {
                  // 如果您需要记录一些事件,可以获取Context中的Span并添加Event。
                  ctx := req.Context()
                  span := trace.SpanFromContext(ctx)
                  span.AddEvent("say : Hello, I am david", trace.WithAttributes(attribute.KeyValue{
                      Key:   "label-key-1",
                      Value: attribute.StringValue("label-value-1"),
                  }))
      
                  _, _ = io.WriteString(w, "Hello, I am david!\n")
                  sayDavidCount.Add(req.Context(), 1, labels...)
              }
          }
      
          // 使用otel net/http的自动注入方式,只需要使用otelhttp.NewHandler包裹http.Handler。
          otelHandler := otelhttp.NewHandler(http.HandlerFunc(helloHandler), "Hello")
      
          http.Handle("/hello", otelHandler)
          fmt.Println("Now listen port 8080, you can visit 127.0.0.1:8080/hello .")
          err = http.ListenAndServe(":8080", nil)
          if err != nil {
              panic(err)
          }
      }
                                  
    • mux接入

      下述示例基于go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.37.0 版本创建,新版本中接口可能出现一定的改动,最新示例请参见otel-mux-example。

      如下代码中的变量需根据实际情况替换。关于变量的详细说明,请参见变量说明。

      package main
      
      import (
          "context"
          "fmt"
          "go.opentelemetry.io/otel/attribute"
          "go.opentelemetry.io/otel/metric/global"
          "net/http"
      
          "github.com/aliyun-sls/opentelemetry-go-provider-sls/provider"
      
          "github.com/gorilla/mux"
          "go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux"
          "go.opentelemetry.io/otel/trace"
      )
      
      func main() {
      
          slsConfig, err := provider.NewConfig(provider.WithServiceName("${service}"),
              provider.WithServiceNamespace("${service.namespace}"),
              provider.WithServiceVersion("${version}"),
              provider.WithTraceExporterEndpoint("${endpoint}"),
              provider.WithMetricExporterEndpoint("${endpoint}"),
              provider.WithSLSConfig("${project}", "${instance}", "${access-key-id}", "${access-key-secret}"))
          // 使用panic(),表示如果初始化失败则程序直接异常退出,您也可以使用其他错误处理方式。
          if err != nil {
              panic(err)
          }
          if err := provider.Start(slsConfig); err != nil {
              panic(err)
          }
          defer provider.Shutdown(slsConfig)
      
          // 如果您需要分析应用中的指标数据,可以注册相关的Metric指标。
          labels := []attribute.KeyValue{
              attribute.String("label1", "value1"),
          }
          meter := global.Meter("aliyun.sls")
          callUsersCount, _ := meter.Int64Counter("call_users_count")
      
          r := mux.NewRouter()
          r.Use(otelmux.Middleware("my-server"))
          r.HandleFunc("/users/{id:[0-9]+}", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
              vars := mux.Vars(r)
              id := vars["id"]
              callUsersCount.Add(r.Context(), 1, labels...)
              name := getUser(r.Context(), id)
              reply := fmt.Sprintf("user %s (id %s)\n", name, id)
              _, _ = w.Write(([]byte)(reply))
          }))
          http.Handle("/", r)
          fmt.Println("Now listen port 8080, you can visit 127.0.0.1:8080/users/xxx .")
          _ = http.ListenAndServe(":8080", nil)
      }
      
      func getUser(ctx context.Context, id string) string {
          if id == "123" {
              return "otelmux tester"
          }
          // 如果您需要记录一些事件,可以获取Context中的Span并添加Event。
          span := trace.SpanFromContext(ctx)
          span.AddEvent("unknown user id : "+id, trace.WithAttributes(attribute.KeyValue{
              Key:   "label-key-1",
              Value: attribute.StringValue("label-value-1"),
          }))
          return "unknown"
      }
                                  
  • 手动接入

    如下代码中的变量需根据实际情况替换。关于变量的详细说明,请参见变量说明。

    // Copyright The AliyunSLS Authors
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //     http://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    
    package main
    
    import (
        "context"
        "errors"
        "fmt"
        "go.opentelemetry.io/otel/attribute"
        "go.opentelemetry.io/otel/metric/global"
        "go.opentelemetry.io/otel/metric/instrument"
        "math/rand"
        "time"
    
        "github.com/aliyun-sls/opentelemetry-go-provider-sls/provider"
    
        "go.opentelemetry.io/otel"
        "go.opentelemetry.io/otel/codes"
        "go.opentelemetry.io/otel/trace"
    )
    
    func main() {
        slsConfig, err := provider.NewConfig(provider.WithServiceName("payment"),
            provider.WithServiceVersion("v0.1.0"),
            provider.WithTraceExporterEndpoint("stdout"),
            provider.WithMetricExporterEndpoint("stdout"),
            provider.WithSLSConfig("test-project", "test-otel", "access-key-id", "access-key-secret"))
        // 使用panic(),表示如果初始化失败则程序直接异常退出,您也可以使用其他错误处理方式。
        if err != nil {
            panic(err)
        }
        if err := provider.Start(slsConfig); err != nil {
            panic(err)
        }
        defer provider.Shutdown(slsConfig)
    
        mockTrace()
        mockMetrics()
    }
    
    func mockMetrics() {
        // 附加标签信息。
        labels := []attribute.KeyValue{
            attribute.String("label1", "value1"),
        }
    
        meter := global.Meter("ex.com/basic")
    
        meter.Float64ObservableCounter("randval", instrument.WithFloat64Callback(func(ctx context.Context, observer instrument.Float64Observer) error {
            observer.Observe(rand.Float64(), labels...)
            return nil
        }))
    
        temperature, _ := meter.Float64Counter("temperature")
        interrupts, _ := meter.Int64Counter("interrupts")
    
        ctx := context.Background()
    
        for {
            temperature.Add(ctx, 100+10*rand.NormFloat64(), labels...)
            interrupts.Add(ctx, int64(rand.Intn(100)), labels...)
    
            time.Sleep(time.Second * time.Duration(rand.Intn(10)))
        }
    }
    
    func mockTrace() {
    
        tracer := otel.Tracer("ex.com/basic")
    
        ctx0 := context.Background()
    
        ctx1, finish1 := tracer.Start(ctx0, "foo")
        defer finish1.End()
    
        ctx2, finish2 := tracer.Start(ctx1, "bar")
        defer finish2.End()
    
        ctx3, finish3 := tracer.Start(ctx2, "baz")
        defer finish3.End()
    
        ctx := ctx3
        getSpan(ctx)
        addAttribute(ctx)
        addEvent(ctx)
        recordException(ctx)
        createChild(ctx, tracer)
    }
    
    // example of getting the current span
    // 获取当前的Span。
    func getSpan(ctx context.Context) {
        span := trace.SpanFromContext(ctx)
        fmt.Printf("current span: %v\n", span)
    }
    
    // example of adding an attribute to a span
    // 向Span中添加属性值。
    func addAttribute(ctx context.Context) {
        span := trace.SpanFromContext(ctx)
        span.SetAttributes(attribute.KeyValue{
            Key:   "label-key-1",
            Value: attribute.StringValue("label-value-1")})
    }
    
    // example of adding an event to a span
    // 向Span中添加事件。
    func addEvent(ctx context.Context) {
        span := trace.SpanFromContext(ctx)
        span.AddEvent("event1", trace.WithAttributes(
            attribute.String("event-attr1", "event-string1"),
            attribute.Int64("event-attr2", 10)))
    }
    
    // example of recording an exception
    // 记录Span结果以及错误信息。
    func recordException(ctx context.Context) {
        span := trace.SpanFromContext(ctx)
        span.RecordError(errors.New("exception has occurred"))
        span.SetStatus(codes.Error, "internal error")
    }
    
    // example of creating a child span
    // 创建子Span。
    func createChild(ctx context.Context, tracer trace.Tracer) {
        // span := trace.SpanFromContext(ctx)
        _, childSpan := tracer.Start(ctx, "child")
        defer childSpan.End()
        fmt.Printf("child span: %v\n", childSpan)
    }
                        

后续步骤

  • 查看Trace实例详情

  • 查询和分析Trace数据

相关文章

通过OpenTelemetry接入Java Trace数据 2025-04-22 10:45

本文介绍通过OpenTelemetry Java SDK将Java应用的Trace数据接入到日志服务的操作步骤。 前提条件

通过OpenTelemetry接入Golang Trace数据 2025-04-22 10:45

本文介绍通过OpenTelemetry Golang SDK将Golang应用的Trace数据接入到日志服务的操作步骤。 前提条件

通过OpenTelemetry接入Python Trace数据 2025-04-22 10:45

本文介绍通过OpenTelemetry Python SDK将Python应用的Trace数据接入到日志服务的操作步骤。 前提条件

通过OpenTelemetry接入Node.js Trace数据 2025-04-22 10:45

本文介绍通过opentelemetry-js SDK将Node.js应用的Trace数据接入到日志服务的操作步骤。 前提条件

通过OpenTelemetry接入C# Trace数据 2025-04-22 10:45

本文介绍通过OpenTelemetry .NET SDK将C#应用的Trace数据接入到日志服务的操作步骤。 前提条件

通过OpenTelemetry接入Rust Trace数据 2025-04-22 10:45

本文介绍通过OpenTelemetry Rust SDK将Rust应用的Trace数据接入到日志服务的操作步骤。 前提条件

目录
Copyright © 2025 your company All Rights Reserved. Powered by 赛尔网络.
京ICP备14022346号-15
gongan beian 京公网安备11010802041014号