tracehandler.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. package handler
  2. import (
  3. "net/http"
  4. "github.com/wuntsong-org/go-zero-plus/core/collection"
  5. "github.com/wuntsong-org/go-zero-plus/core/trace"
  6. "github.com/wuntsong-org/go-zero-plus/rest/internal/response"
  7. "go.opentelemetry.io/otel"
  8. "go.opentelemetry.io/otel/propagation"
  9. semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
  10. oteltrace "go.opentelemetry.io/otel/trace"
  11. )
  12. type (
  13. // TraceOption defines the method to customize an traceOptions.
  14. TraceOption func(options *traceOptions)
  15. // traceOptions is TraceHandler options.
  16. traceOptions struct {
  17. traceIgnorePaths []string
  18. }
  19. )
  20. // TraceHandler return a middleware that process the opentelemetry.
  21. func TraceHandler(serviceName, path string, opts ...TraceOption) func(http.Handler) http.Handler {
  22. var options traceOptions
  23. for _, opt := range opts {
  24. opt(&options)
  25. }
  26. ignorePaths := collection.NewSet()
  27. ignorePaths.AddStr(options.traceIgnorePaths...)
  28. return func(next http.Handler) http.Handler {
  29. tracer := otel.Tracer(trace.TraceName)
  30. propagator := otel.GetTextMapPropagator()
  31. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  32. spanName := path
  33. if len(spanName) == 0 {
  34. spanName = r.URL.Path
  35. }
  36. if ignorePaths.Contains(spanName) {
  37. next.ServeHTTP(w, r)
  38. return
  39. }
  40. ctx := propagator.Extract(r.Context(), propagation.HeaderCarrier(r.Header))
  41. spanCtx, span := tracer.Start(
  42. ctx,
  43. spanName,
  44. oteltrace.WithSpanKind(oteltrace.SpanKindServer),
  45. oteltrace.WithAttributes(semconv.HTTPServerAttributesFromHTTPRequest(
  46. serviceName, spanName, r)...),
  47. )
  48. defer span.End()
  49. // convenient for tracking error messages
  50. propagator.Inject(spanCtx, propagation.HeaderCarrier(w.Header()))
  51. trw := response.NewWithCodeResponseWriter(w)
  52. next.ServeHTTP(trw, r.WithContext(spanCtx))
  53. span.SetAttributes(semconv.HTTPAttributesFromHTTPStatusCode(trw.Code)...)
  54. span.SetStatus(semconv.SpanStatusFromHTTPStatusCodeAndSpanKind(
  55. trw.Code, oteltrace.SpanKindServer))
  56. })
  57. }
  58. }
  59. // WithTraceIgnorePaths specifies the traceIgnorePaths option for TraceHandler.
  60. func WithTraceIgnorePaths(traceIgnorePaths []string) TraceOption {
  61. return func(options *traceOptions) {
  62. options.traceIgnorePaths = append(options.traceIgnorePaths, traceIgnorePaths...)
  63. }
  64. }