agent.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. package trace
  2. import (
  3. "context"
  4. "fmt"
  5. "net/url"
  6. "sync"
  7. "github.com/zeromicro/go-zero/core/lang"
  8. "github.com/zeromicro/go-zero/core/logx"
  9. "go.opentelemetry.io/otel"
  10. "go.opentelemetry.io/otel/exporters/jaeger"
  11. "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
  12. "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
  13. "go.opentelemetry.io/otel/exporters/zipkin"
  14. "go.opentelemetry.io/otel/sdk/resource"
  15. sdktrace "go.opentelemetry.io/otel/sdk/trace"
  16. semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
  17. )
  18. const (
  19. kindJaeger = "jaeger"
  20. kindZipkin = "zipkin"
  21. kindOtlpGrpc = "otlpgrpc"
  22. kindOtlpHttp = "otlphttp"
  23. )
  24. var (
  25. agents = make(map[string]lang.PlaceholderType)
  26. lock sync.Mutex
  27. tp *sdktrace.TracerProvider
  28. )
  29. // StartAgent starts an opentelemetry agent.
  30. func StartAgent(c Config) {
  31. if c.Disabled {
  32. return
  33. }
  34. lock.Lock()
  35. defer lock.Unlock()
  36. _, ok := agents[c.Endpoint]
  37. if ok {
  38. return
  39. }
  40. // if error happens, let later calls run.
  41. if err := startAgent(c); err != nil {
  42. return
  43. }
  44. agents[c.Endpoint] = lang.Placeholder
  45. }
  46. // StopAgent shuts down the span processors in the order they were registered.
  47. func StopAgent() {
  48. _ = tp.Shutdown(context.Background())
  49. }
  50. func createExporter(c Config) (sdktrace.SpanExporter, error) {
  51. // Just support jaeger and zipkin now, more for later
  52. switch c.Batcher {
  53. case kindJaeger:
  54. u, _ := url.Parse(c.Endpoint)
  55. if u.Scheme == "udp" {
  56. return jaeger.New(jaeger.WithAgentEndpoint(jaeger.WithAgentHost(u.Hostname()), jaeger.WithAgentPort(u.Port())))
  57. }
  58. return jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(c.Endpoint)))
  59. case kindZipkin:
  60. return zipkin.New(c.Endpoint)
  61. case kindOtlpGrpc:
  62. // Always treat trace exporter as optional component, so we use nonblock here,
  63. // otherwise this would slow down app start up even set a dial timeout here when
  64. // endpoint can not reach.
  65. // If the connection not dial success, the global otel ErrorHandler will catch error
  66. // when reporting data like other exporters.
  67. opts := []otlptracegrpc.Option{
  68. otlptracegrpc.WithInsecure(),
  69. otlptracegrpc.WithEndpoint(c.Endpoint),
  70. }
  71. if len(c.OtlpHeaders) > 0 {
  72. opts = append(opts, otlptracegrpc.WithHeaders(c.OtlpHeaders))
  73. }
  74. return otlptracegrpc.New(
  75. context.Background(),
  76. opts...,
  77. )
  78. case kindOtlpHttp:
  79. // Not support flexible configuration now.
  80. opts := []otlptracehttp.Option{
  81. otlptracehttp.WithInsecure(),
  82. otlptracehttp.WithEndpoint(c.Endpoint),
  83. }
  84. if len(c.OtlpHeaders) > 0 {
  85. opts = append(opts, otlptracehttp.WithHeaders(c.OtlpHeaders))
  86. }
  87. if len(c.OtlpHttpPath) > 0 {
  88. opts = append(opts, otlptracehttp.WithURLPath(c.OtlpHttpPath))
  89. }
  90. return otlptracehttp.New(
  91. context.Background(),
  92. opts...,
  93. )
  94. default:
  95. return nil, fmt.Errorf("unknown exporter: %s", c.Batcher)
  96. }
  97. }
  98. func startAgent(c Config) error {
  99. opts := []sdktrace.TracerProviderOption{
  100. // Set the sampling rate based on the parent span to 100%
  101. sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(c.Sampler))),
  102. // Record information about this application in a Resource.
  103. sdktrace.WithResource(resource.NewSchemaless(semconv.ServiceNameKey.String(c.Name))),
  104. }
  105. if len(c.Endpoint) > 0 {
  106. exp, err := createExporter(c)
  107. if err != nil {
  108. logx.Error(err)
  109. return err
  110. }
  111. // Always be sure to batch in production.
  112. opts = append(opts, sdktrace.WithBatcher(exp))
  113. }
  114. tp = sdktrace.NewTracerProvider(opts...)
  115. otel.SetTracerProvider(tp)
  116. otel.SetErrorHandler(otel.ErrorHandlerFunc(func(err error) {
  117. logx.Errorf("[otel] error: %v", err)
  118. }))
  119. return nil
  120. }