agent.go 3.1 KB

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