2021-01-25 14:54:38 +08:00
|
|
|
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
|
|
// If a copy of the MIT was not distributed with this file,
|
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
|
|
|
|
|
|
|
package ghttp
|
|
|
|
|
|
|
|
import (
|
2021-01-25 18:43:47 +08:00
|
|
|
"fmt"
|
|
|
|
"github.com/gogf/gf"
|
|
|
|
"github.com/gogf/gf/internal/utils"
|
2021-01-25 14:54:38 +08:00
|
|
|
"github.com/gogf/gf/net/ghttp/internal/client"
|
2021-01-25 18:43:47 +08:00
|
|
|
"github.com/gogf/gf/net/ghttp/internal/httputil"
|
2021-01-27 19:15:14 +08:00
|
|
|
"github.com/gogf/gf/net/gtrace"
|
2021-01-25 18:43:47 +08:00
|
|
|
"go.opentelemetry.io/otel"
|
|
|
|
"go.opentelemetry.io/otel/codes"
|
|
|
|
"go.opentelemetry.io/otel/label"
|
|
|
|
"go.opentelemetry.io/otel/propagation"
|
|
|
|
"go.opentelemetry.io/otel/trace"
|
|
|
|
"io/ioutil"
|
2021-01-25 14:54:38 +08:00
|
|
|
"net/http"
|
|
|
|
)
|
|
|
|
|
2021-01-25 18:43:47 +08:00
|
|
|
const (
|
2021-01-27 20:25:57 +08:00
|
|
|
tracingMaxContentLogSize = 512 * 1024 // Max log size for request and response body.
|
|
|
|
tracingEventHttpRequest = "http.request"
|
|
|
|
tracingEventHttpRequestHeaders = "http.request.headers"
|
|
|
|
tracingEventHttpRequestBody = "http.request.body"
|
|
|
|
tracingEventHttpResponse = "http.response"
|
|
|
|
tracingEventHttpResponseHeaders = "http.response.headers"
|
|
|
|
tracingEventHttpResponseBody = "http.response.body"
|
2021-01-25 18:43:47 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
// MiddlewareClientTracing is a client middleware that enables tracing feature using standards of OpenTelemetry.
|
2021-01-25 14:54:38 +08:00
|
|
|
func MiddlewareClientTracing(c *Client, r *http.Request) (*ClientResponse, error) {
|
|
|
|
return client.MiddlewareTracing(c, r)
|
|
|
|
}
|
2021-01-25 18:43:47 +08:00
|
|
|
|
|
|
|
// MiddlewareServerTracing is a serer middleware that enables tracing feature using standards of OpenTelemetry.
|
|
|
|
func MiddlewareServerTracing(r *Request) {
|
|
|
|
tr := otel.GetTracerProvider().Tracer(
|
|
|
|
"github.com/gogf/gf/net/ghttp.Server",
|
|
|
|
trace.WithInstrumentationVersion(fmt.Sprintf(`%s`, gf.VERSION)),
|
|
|
|
)
|
|
|
|
// Tracing content parsing, start root span.
|
|
|
|
propagator := propagation.NewCompositeTextMapPropagator(
|
|
|
|
propagation.TraceContext{},
|
|
|
|
propagation.Baggage{},
|
|
|
|
)
|
|
|
|
ctx := propagator.Extract(r.Context(), r.Header)
|
2021-01-27 19:50:32 +08:00
|
|
|
ctx, span := tr.Start(ctx, r.URL.String(), trace.WithSpanKind(trace.SpanKindServer))
|
2021-01-25 18:43:47 +08:00
|
|
|
defer span.End()
|
|
|
|
|
2021-01-27 19:15:14 +08:00
|
|
|
span.SetAttributes(gtrace.CommonLabels()...)
|
|
|
|
|
2021-01-25 18:43:47 +08:00
|
|
|
// Inject tracing context.
|
|
|
|
r.SetCtx(ctx)
|
|
|
|
|
|
|
|
// Request content logging.
|
|
|
|
var reqBodyContent string
|
|
|
|
if r.ContentLength <= tracingMaxContentLogSize {
|
|
|
|
reqBodyContentBytes, _ := ioutil.ReadAll(r.Body)
|
|
|
|
r.Body = utils.NewReadCloser(reqBodyContentBytes, false)
|
|
|
|
reqBodyContent = string(reqBodyContentBytes)
|
|
|
|
} else {
|
|
|
|
reqBodyContent = fmt.Sprintf(
|
2021-01-27 19:50:32 +08:00
|
|
|
"[Request Body Too Large For Tracing, Max: %d bytes]",
|
2021-01-25 18:43:47 +08:00
|
|
|
tracingMaxContentLogSize,
|
|
|
|
)
|
|
|
|
}
|
2021-01-27 20:25:57 +08:00
|
|
|
span.AddEvent(tracingEventHttpRequest, trace.WithAttributes(
|
|
|
|
label.Any(tracingEventHttpRequestHeaders, httputil.HeaderToMap(r.Header)),
|
|
|
|
label.String(tracingEventHttpRequestBody, reqBodyContent),
|
2021-01-25 18:43:47 +08:00
|
|
|
))
|
|
|
|
|
|
|
|
// Continue executing.
|
|
|
|
r.Middleware.Next()
|
|
|
|
|
|
|
|
// Error logging.
|
|
|
|
if err := r.GetError(); err != nil {
|
|
|
|
span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))
|
|
|
|
}
|
|
|
|
// Response content logging.
|
|
|
|
var resBodyContent string
|
|
|
|
if r.Response.BufferLength() <= tracingMaxContentLogSize {
|
|
|
|
resBodyContent = r.Response.BufferString()
|
|
|
|
} else {
|
2021-01-27 19:50:32 +08:00
|
|
|
resBodyContent = fmt.Sprintf(
|
|
|
|
"[Response Body Too Large For Tracing, Max: %d bytes]",
|
|
|
|
tracingMaxContentLogSize,
|
|
|
|
)
|
2021-01-25 18:43:47 +08:00
|
|
|
}
|
2021-01-27 20:25:57 +08:00
|
|
|
span.AddEvent(tracingEventHttpResponse, trace.WithAttributes(
|
|
|
|
label.Any(tracingEventHttpResponseHeaders, httputil.HeaderToMap(r.Response.Header())),
|
|
|
|
label.String(tracingEventHttpResponseBody, resBodyContent),
|
2021-01-25 18:43:47 +08:00
|
|
|
))
|
|
|
|
return
|
|
|
|
}
|