ghttp_middleware_tracing.go 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package ghttp
  7. import (
  8. "fmt"
  9. "io/ioutil"
  10. "net/http"
  11. "github.com/gogf/gf"
  12. "github.com/gogf/gf/internal/utils"
  13. "github.com/gogf/gf/net/ghttp/internal/client"
  14. "github.com/gogf/gf/net/ghttp/internal/httputil"
  15. "github.com/gogf/gf/net/gtrace"
  16. "github.com/gogf/gf/text/gstr"
  17. "github.com/gogf/gf/util/gconv"
  18. "go.opentelemetry.io/otel"
  19. "go.opentelemetry.io/otel/attribute"
  20. "go.opentelemetry.io/otel/codes"
  21. "go.opentelemetry.io/otel/propagation"
  22. "go.opentelemetry.io/otel/trace"
  23. )
  24. const (
  25. tracingInstrumentName = "github.com/gogf/gf/net/ghttp.Server"
  26. tracingEventHttpRequest = "http.request"
  27. tracingEventHttpRequestHeaders = "http.request.headers"
  28. tracingEventHttpRequestBaggage = "http.request.baggage"
  29. tracingEventHttpRequestBody = "http.request.body"
  30. tracingEventHttpResponse = "http.response"
  31. tracingEventHttpResponseHeaders = "http.response.headers"
  32. tracingEventHttpResponseBody = "http.response.body"
  33. )
  34. // MiddlewareClientTracing is a client middleware that enables tracing feature using standards of OpenTelemetry.
  35. func MiddlewareClientTracing(c *Client, r *http.Request) (*ClientResponse, error) {
  36. return client.MiddlewareTracing(c, r)
  37. }
  38. // MiddlewareServerTracing is a serer middleware that enables tracing feature using standards of OpenTelemetry.
  39. func MiddlewareServerTracing(r *Request) {
  40. tr := otel.GetTracerProvider().Tracer(tracingInstrumentName, trace.WithInstrumentationVersion(gf.VERSION))
  41. ctx := otel.GetTextMapPropagator().Extract(r.Context(), propagation.HeaderCarrier(r.Header))
  42. ctx, span := tr.Start(ctx, r.URL.String(), trace.WithSpanKind(trace.SpanKindServer))
  43. defer span.End()
  44. span.SetAttributes(gtrace.CommonLabels()...)
  45. // Inject tracing context.
  46. r.SetCtx(ctx)
  47. // Request content logging.
  48. reqBodyContentBytes, _ := ioutil.ReadAll(r.Body)
  49. r.Body = utils.NewReadCloser(reqBodyContentBytes, false)
  50. span.AddEvent(tracingEventHttpRequest, trace.WithAttributes(
  51. attribute.String(tracingEventHttpRequestHeaders, gconv.String(httputil.HeaderToMap(r.Header))),
  52. attribute.String(tracingEventHttpRequestBaggage, gtrace.GetBaggageMap(ctx).String()),
  53. attribute.String(tracingEventHttpRequestBody, gstr.StrLimit(
  54. string(reqBodyContentBytes),
  55. gtrace.MaxContentLogSize(),
  56. "...",
  57. )),
  58. ))
  59. // Continue executing.
  60. r.Middleware.Next()
  61. // Error logging.
  62. if err := r.GetError(); err != nil {
  63. span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))
  64. }
  65. // Response content logging.
  66. var resBodyContent string
  67. resBodyContent = r.Response.BufferString()
  68. resBodyContent = gstr.StrLimit(
  69. r.Response.BufferString(),
  70. gtrace.MaxContentLogSize(),
  71. "...",
  72. )
  73. span.AddEvent(tracingEventHttpResponse, trace.WithAttributes(
  74. attribute.String(tracingEventHttpResponseHeaders, gconv.String(httputil.HeaderToMap(r.Response.Header()))),
  75. attribute.String(tracingEventHttpResponseBody, resBodyContent),
  76. ))
  77. return
  78. }