From 34e522306de5183fa5b52381e186064bc00f6df7 Mon Sep 17 00:00:00 2001 From: ltp217 <867813857@qq.com> Date: Tue, 17 Oct 2023 20:35:56 +0800 Subject: [PATCH] resolve response is gzip in internalMiddlewareServerTracing (#3055) --- net/ghttp/ghttp_middleware_tracing.go | 28 ++++++++++++ ...tp_z_unit_feature_middleware_basic_test.go | 44 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/net/ghttp/ghttp_middleware_tracing.go b/net/ghttp/ghttp_middleware_tracing.go index 98950fa94..08c71f45e 100644 --- a/net/ghttp/ghttp_middleware_tracing.go +++ b/net/ghttp/ghttp_middleware_tracing.go @@ -7,9 +7,12 @@ package ghttp import ( + "compress/gzip" "context" "fmt" "io" + "net/http" + "strings" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" @@ -110,9 +113,34 @@ func internalMiddlewareServerTracing(r *Request) { } // Response content logging. var resBodyContent = gstr.StrLimit(r.Response.BufferString(), gtrace.MaxContentLogSize(), "...") + if gzipAccepted(r.Response.Header()) { + reader, err := gzip.NewReader(strings.NewReader(r.Response.BufferString())) + if err != nil { + span.SetStatus(codes.Error, fmt.Sprintf(`read gzip response err:%+v`, err)) + } + defer reader.Close() + uncompressed, err := io.ReadAll(reader) + if err != nil { + span.SetStatus(codes.Error, fmt.Sprintf(`get uncompress value err:%+v`, err)) + } + resBodyContent = gstr.StrLimit(string(uncompressed), gtrace.MaxContentLogSize(), "...") + } span.AddEvent(tracingEventHttpResponse, trace.WithAttributes( attribute.String(tracingEventHttpResponseHeaders, gconv.String(httputil.HeaderToMap(r.Response.Header()))), attribute.String(tracingEventHttpResponseBody, resBodyContent), )) } + +// gzipAccepted returns whether the client will accept gzip-encoded content. +func gzipAccepted(header http.Header) bool { + a := header.Get("Content-Encoding") + parts := strings.Split(a, ",") + for _, part := range parts { + part = strings.TrimSpace(part) + if part == "gzip" || strings.HasPrefix(part, "gzip;") { + return true + } + } + return false +} diff --git a/net/ghttp/ghttp_z_unit_feature_middleware_basic_test.go b/net/ghttp/ghttp_z_unit_feature_middleware_basic_test.go index ebbc83d11..ac1985163 100644 --- a/net/ghttp/ghttp_z_unit_feature_middleware_basic_test.go +++ b/net/ghttp/ghttp_z_unit_feature_middleware_basic_test.go @@ -7,8 +7,10 @@ package ghttp_test import ( + "compress/gzip" "fmt" "net/http" + "strings" "testing" "time" @@ -17,6 +19,8 @@ import ( "github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/test/gtest" "github.com/gogf/gf/v2/util/guid" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" ) func Test_BindMiddleware_Basic1(t *testing.T) { @@ -736,3 +740,43 @@ func Test_MiddlewareHandlerResponse(t *testing.T) { t.Assert(rsp.StatusCode, http.StatusInternalServerError) }) } + +func Test_MiddlewareHandlerGzipResponse(t *testing.T) { + tp := testTracerProvider{} + otel.SetTracerProvider(&tp) + s := g.Server(guid.S()) + s.Group("/", func(group *ghttp.RouterGroup) { + group.GET("/default", func(r *ghttp.Request) { + var buffer strings.Builder + gzipWriter := gzip.NewWriter(&buffer) + defer gzipWriter.Close() + _, _ = gzipWriter.Write([]byte("hello")) + // 设置响应头,表明内容使用 gzip 压缩 + r.Response.Header().Set("Content-Encoding", "gzip") + r.Response.Header().Set("Content-Encoding", "gzip") + r.Response.Header().Set("Content-Type", "text/plain") + r.Response.Header().Set("Content-Length", fmt.Sprint(buffer.Len())) + // 写入压缩后的内容 + r.Response.Write(buffer.String()) + }) + }) + s.SetDumpRouterMap(false) + s.Start() + defer s.Shutdown() + time.Sleep(100 * time.Millisecond) + gtest.C(t, func(t *gtest.T) { + client := g.Client() + client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) + rsp, err := client.Get(ctx, "/default") + t.AssertNil(err) + t.Assert(rsp.StatusCode, http.StatusOK) + }) +} + +type testTracerProvider struct{} + +var _ trace.TracerProvider = &testTracerProvider{} + +func (*testTracerProvider) Tracer(_ string, _ ...trace.TracerOption) trace.Tracer { + return trace.NewNoopTracerProvider().Tracer("") +}