跳转至

Golang 示例


配置 Datakit Agent

参考配置 Datakit 中的 Pinpoint Agent

配置 Pinpoint Golang Agent

Pinpoint Golang Agent 可以通过包括命令行参数,配置文件,环境变量在内的多种方式进行配置,配置优先级由高到低为:

  • 命令行参数
  • 环境变量
  • 配置文件
  • 配置函数
  • 默认配置

Pinpoint Golang Agent 也支持运行期动态更改配置,所有标记了 dynamic 的配置项参数可以在运行期进行动态配置。

基本参数说明:

以下每个标题为配置文件中的配置项,并且每一个配置项描述中的列表将依次列出对应的命令行参数,环境变量,配置函数,配置值类型以及附加信息。

ConfigFile

: 配置文件支持 JSONYAMLProperties 配置文件。配置文件中的配置项是大小写敏感的

  • --pinpoint-configfile
  • PINPOINT_GO_CONFIGFILE
  • WithConfigFile()
  • string
  • case-sensitive

对于那些以 '.' 分隔的配置字段,它们在配置文件中将以缩进的方式出现。例如:

applicationName: "MyAppName"
collector:
  host: "collector.myhost.com"
sampling:
  type: "percent"
  percentRate: 10
logLevel: "error"

ApplicationName

: ApplicationName 配置应用程序的名字,该项如果没有配置 Agent 将无法启动。

  • --pinpoint-applicationname
  • PINPOINT_GO_APPLICATIONNAME
  • WithAppName()
  • string
  • case-sensitive
  • max-length: 24

ApplicationType

: ApplicationType 配置应用程序的类型

  • --pinpoint-applicationtype
  • PINPOINT_GO_APPLICATIONTYPE
  • WithAppType()
  • int
  • default: 1800 (ServiceTypeGoApp)

AgentId

: AgentId 用于配置 id 来区分不同的 Agent。建议将 hostname 包含进来。如果没有配置或配置错误,Agent 将使用自动生成的 id。

  • --pinpoint-agentid
  • PINPOINT_GO_AGENTID
  • WithAgentId()
  • string
  • case-sensitive
  • max-length: 24

AgentName

: AgentName 配置 Agent 名字。

  • --pinpoint-agentname
  • PINPOINT_GO_AGENTNAME
  • WithAgentName()
  • string
  • case-sensitive
  • max-length: 255

Collector.Host

: Collector.Host 配置 Pinpoint Collector 的主机地址。

  • --pinpoint-collector-host
  • PINPOINT_GO_COLLECTOR_HOST
  • WithCollectorHost()
  • string
  • default: "localhost"
  • case-sensitive

Collector.AgentPort

: Collector.AgentPort 配置 Pinpoint Collector 的 Agent 端口号。

  • --pinpoint-collector-agentport
  • PINPOINT_GO_COLLECTOR_AGENTPORT
  • WithCollectorAgentPort()
  • int
  • default: 9991 (Datakit Pinpoint Agent 中默认端口号为 9991)

Collector.SpanPort

: Collector.SpanPort 配置 Pinpoint Collector 的 Span 端口号。

  • --pinpoint-collector-spanport
  • PINPOINT_GO_COLLECTOR_SPANPORT
  • WithCollectorSpanPort()
  • int
  • default: 9993 (Datakit Pinpoint Agent 中默认端口号为 9991)

Collector.StatPort

: Collector.StatPort 配置 Pinpoint Collector 的 Stat 端口号。

  • --pinpoint-collector-statport
  • PINPOINT_GO_COLLECTOR_STATPORT
  • WithCollectorStatPort()
  • int
  • default: 9992 (Datakit Pinpoint Agent 中默认端口号为 9991)

Sampling.Type

: Sampling.Type 配置采样器类型, "COUNTER" 或者 "PERCENT"。

  • --pinpoint-sampling-type
  • PINPOINT_GO_SAMPLING_TYPE
  • WithSamplingType()
  • string
  • default: "COUNTER"
  • case-insensitive
  • dynamic

Sampling.CounterRate

: Sampling.CounterRate 配置计数采样器采样率。 采样率为 1/rate。 比如,如果 rate 配置为 1 那么采样率为 100%,那么如果 rate 配置为 100 那么采样率为 1%。

  • --pinpoint-sampling-counterrate
  • PINPOINT_GO_SAMPLING_COUNTERRATE
  • WithSamplingCounterRate()
  • int
  • default: 1
  • valid range: 0 ~ 100
  • dynamic

Sampling.PercentRate

: Sampling.PercentRate 配置百分比采样器的采样率。

  • --pinpoint-sampling-percentrate
  • PINPOINT_GO_SAMPLING_PERCENTRATE
  • WithSamplingPercentRate()
  • float
  • default: 100
  • valid range: 0.01 ~ 100
  • dynamic

Span.QueueSize

: Span.QueueSize 配置 Span Queue 的大小。

  • --pinpoint-span-queuesize
  • PINPOINT_GO_SPAN_QUEUESIZE
  • WithSpanQueueSize()
  • type: int
  • default: 1024

Span.MaxCallStackDepth

: Span.MaxCallStackDepth 配置 Span 可探测的调用栈最大深度。

  • --pinpoint-span-maxcallstackdepth
  • PINPOINT_GO_SPAN_MAXCALLSTACKDEPTH
  • WithSpanMaxCallStackDepth()
  • type: int
  • default: 64
  • min: 2
  • ultimate: -1
  • dynamic

Span.MaxCallStackSequence

: Span.MaxCallStackDepth 配置 Span 可探测的调用站最长序列。

  • --pinpoint-span-maxcallstacksequence
  • PINPOINT_GO_SPAN_MAXCALLSTACKSEQUENCE
  • WithSpanMaxCallStackSequence()
  • type: int
  • default: 5000
  • min: 4
  • ultimate: -1
  • dynamic

Stat.CollectInterval

: Stat.CollectInterval 配置统计频率。

  • --pinpoint-stat-collectinterval
  • PINPOINT_GO_STAT_COLLECTINTERVAL
  • WithStatCollectInterval()
  • type: int
  • default: 5000
  • unit: milliseconds

Stat.BatchCount

: Stat.BatchCount 配置批次发送统计数据的个数。

  • --pinpoint-stat-batchcount
  • PINPOINT_GO_STAT_BATCHCOUNT
  • WithStatBatchCount()
  • type: int
  • default: 6

Log.Level

: Log.Level 配置 Agent 日志的层级,trace/debug/info/warn/error 必须配置。

  • --pinpoint-log-level
  • PINPOINT_GO_LOG_LEVEL
  • WithLogLevel()
  • type: string
  • default: "info"
  • case-insensitive
  • dynamic

Log.Output

: Log.Output 配置日志的输出, stderr/stdout/file path。

  • --pinpoint-log-output
  • PINPOINT_GO_LOG_OUTPUT
  • WithLogOutput()
  • type: string
  • default: "stderr"
  • case-insensitive
  • dynamic

Log.MaxSize

: Log.MaxSize 配置日志文件的最大容量。

  • --pinpoint-log-maxsize
  • PINPOINT_GO_LOG_MAXSIZE
  • WithLogMaxSize()
  • type: int
  • default: 10
  • dynamic

手动检测应用程序

对于有虚拟机的程序语言例如:JAVA 可以通过直接向虚拟机中注入检测 Agent 启动自动检测,但是对于需要进行编译后独立运行的编程语言例如 Golang 需要进行手动检测。

Pinpoint Golang Agent 中可以通过两种方式进行手动检测:

Span

: Pinpoint 中 Span 代表着 service 或 application 的顶层程序操作,例如在 HTTP handler 中创建 Span:

func doHandle(w http.ResponseWriter, r *http.Request) {
  tracer = pinpoint.GetAgent().NewSpanTracerWithReader("HTTP Server", r.URL.Path, r.Header)
  defer tracer.EndSpan()

  span := tracer.Span()
  span.SetEndPoint(r.Host)
}

你可以检测单一调用栈的应用并产生一个 Span。 Tracer.EndSpan() 必须被调用以完成这个 Span 并发送到远端的 Collector。 SpanRecorder 和 Annotation 接口可以用来将链路数据记录在 Span 中。

SpanEvent

: Pinpoint 中每一个 SpanEvent 都代表着一个 Span 探测范围内的一次程序操作,例如:访问数据库,调用函数,向另一个服务发起请求等等。你可以通过 Tracer.NewSpanEvent() 上报一个 span,必须调用 Tracer.EndSpanEvent() 来完成一个 span。

func doHandle(w http.ResponseWriter, r *http.Request) {
    tracer := pinpoint.GetAgent().NewSpanTracerWithReader("HTTP Server", r.URL.Path, r.Header)
    defer tracer.EndSpan()

    span := tracer.Span()
    span.SetEndPoint(r.Host)
    defer tracer.NewSpanEvent("doHandle").EndSpanEvent()

    func() {
        defer tracer.NewSpanEvent("func_1").EndSpanEvent()

        func() {
            defer tracer.NewSpanEvent("func_2").EndSpanEvent()
            time.Sleep(100 * time.Millisecond)
        }()
        time.Sleep(1 * time.Second)
    }()
}

分发 Tracing Context

: 如果一次请求来自另一个由 Pinpoint 监测的节点,那么这次数据交换中将包含一个数据交换上下文。大多数此类型的数据来自上一个节点并且被打包在请求消息体内。 Pinpoint 提供了两个函数完成对数据交换上下文的读写。

  • Tracer.Extract(reader DistributedTracingContextReader) // 提取分发的上下文。
  • Tracer.Inject(writer DistributedTracingContextWriter) // 向请求中注入上下文。
func externalRequest(tracer pinpoint.Tracer) int {
 req, err := http.NewRequest("GET", "http://localhost:9000/async_wrapper", nil)
 client := &http.Client{}

 tracer.NewSpanEvent("externalRequest")
 defer tracer.EndSpanEvent()

 se := tracer.SpanEvent()
 se.SetEndPoint(req.Host)
 se.SetDestination(req.Host)
 se.SetServiceType(pinpoint.ServiceTypeGoHttpClient)
 se.Annotations().AppendString(pinpoint.AnnotationHttpUrl, req.URL.String())
 tracer.Inject(req.Header)

 resp, err := client.Do(req)
 defer resp.Body.Close()

 tracer.SpanEvent().SetError(err)
 return resp.StatusCode
}

函数间调用上下文透传

: 在同一个服务中的不同 API 间和不同进程中进行调用上下文的透传是通过对 context.Context 的操作现的。 Pinpoint Golang Agent 通过向 Context 中注入 Tracer 实现上下文的链接。

  • NewContext() // 注入 Tracer 到 Context 中。
  • FromContext() // 导入一个 Tracer。
func tableCount(w http.ResponseWriter, r *http.Request) {
 tracer := pinpoint.FromContext(r.Context())

 db, err := sql.Open("mysql-pinpoint", "root:p123@tcp(127.0.0.1:3306)/information_schema")
 defer db.Close()

 ctx := pinpoint.NewContext(context.Background(), tracer)
 row := db.QueryRowContext(ctx, "SELECT count(*) from tables")
 var count int
 row.Scan(&count)

 fmt.Println("number of tables in information_schema", count)
}

检测 Goroutine

: Pinpoint Tracer 设计之初是用来检测单一调用栈的应用,所以在不同的线程间共享同一个 Tracer 将引起资源抢占而造成程序崩溃。你可以通过调用 Tracer.NewGoroutineTracer() 创建一个新的 Tracer 来检测 Goroutine。

在线程间传递 Tracer 可以通过以下几种方式:

  • function parameter

    func outGoingRequest(ctx context.Context) {
      client := pphttp.WrapClient(nil)
    
      request, _ := http.NewRequest("GET", "https://github.com/pinpoint-apm/pinpoint-go-agent", nil)
      request = request.WithContext(ctx)
    
      resp, err := client.Do(request)
      if nil != err {
          log.Println(err.Error())
          return
      }
      defer resp.Body.Close()
      log.Println(resp.Body)
    }
    
    func asyncWithTracer(w http.ResponseWriter, r *http.Request) {
        tracer := pinpoint.FromContext(r.Context())
        wg := &sync.WaitGroup{}
        wg.Add(1)
    
        go func(asyncTracer pinpoint.Tracer) {
            defer wg.Done()
    
            defer asyncTracer.EndSpan() // must be called
            defer asyncTracer.NewSpanEvent("asyncWithTracer_goroutine").EndSpanEvent()
    
            ctx := pinpoint.NewContext(context.Background(), asyncTracer)
            outGoingRequest(w, ctx)
        }(tracer.NewGoroutineTracer())
    
        wg.Wait()
    }
    
  • channel

    func asyncWithChan(w http.ResponseWriter, r *http.Request) {
        tracer := pinpoint.FromContext(r.Context())
        wg := &sync.WaitGroup{}
        wg.Add(1)
    
        ch := make(chan pinpoint.Tracer)
    
        go func() {
            defer wg.Done()
    
            asyncTracer := <-ch
            defer asyncTracer.EndSpan() // must be called
            defer asyncTracer.NewSpanEvent("asyncWithChan_goroutine").EndSpanEvent()
    
            ctx := pinpoint.NewContext(context.Background(), asyncTracer)
            outGoingRequest(w, ctx)
        }()
    
        ch <- tracer.NewGoroutineTracer()
        wg.Wait()
    }
    
  • context.Context

    func asyncWithContext(w http.ResponseWriter, r *http.Request) {
        tracer := pinpoint.FromContext(r.Context())
        wg := &sync.WaitGroup{}
        wg.Add(1)
    
        go func(asyncCtx context.Context) {
            defer wg.Done()
    
            asyncTracer := pinpoint.FromContext(asyncCtx)
            defer asyncTracer.EndSpan() // must be called
            defer asyncTracer.NewSpanEvent("asyncWithContext_goroutine").EndSpanEvent()
    
            ctx := pinpoint.NewContext(context.Background(), asyncTracer)
            outGoingRequest(w, ctx)
        }(pinpoint.NewContext(context.Background(), tracer.NewGoroutineTracer()))
    
        wg.Wait()
    }
    

文档评价

文档内容是否对您有帮助? ×