Files
gf/net/gclient/gclient_tracer_tracing.go
hailaz ee24da4e72 refactor: interface{} to any and reflect.Ptr to reflect.Pointer (#4395)
This pull request standardizes the use of the Go 1.18+ `any` type alias
instead of `interface{}` throughout the codebase. The change improves
code readability and aligns with modern Go best practices. The update
touches many files, including core data structures, code generation
templates, logging utilities, and test data, ensuring consistency across
all usages.

**Type alias migration to `any`:**

* Replaced all instances of `interface{}` with `any` in core data
structures such as `garray` and in generated model structs (e.g.,
`TableUser`, `User1`, `User2`) to modernize type usage.
[[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31)
[[2]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19)
[[3]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18)
[[4]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19)
[[5]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19)
[[6]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19)
* Updated function signatures, method parameters, and return types from
`interface{}` to `any` in various parts of the codebase, including code
generation, service logic, and logging utilities (e.g., `mlog`).
[[1]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55)
[[2]](diffhunk://#diff-2b1953fb78cf3593d8c2c7d911e95b65fd0b847c30ed0b4d167d16fe6d781235L54-R74)
[[3]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73)
[[4]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41)
[[5]](diffhunk://#diff-c5d51d56f487779a2b6207c7ad26c7a20bbadcc846ce094fe60ab4cabff58c51L107-R107)
[[6]](diffhunk://#diff-f96e6a9fdb416eb1804ceaba1fe0ac637bff22c43837f8bb849c2366ce72d4a1L116-R121)
[[7]](diffhunk://#diff-f94c83a1b08ae060d9346f4a6031fc4a7b9a0b894e02d9afaa09018b6598eac0L112-R112)
[[8]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L36-R36)
[[9]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L74-R74)
[[10]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L96-R96)

**Generated code and templates:**

* Adjusted generated files and code generation templates to output `any`
instead of `interface{}` for relevant struct fields and function
signatures, ensuring that new code generation aligns with the updated
convention.
[[1]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19)
[[2]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18)
[[3]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19)
[[4]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19)
[[5]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19)
[[6]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55)
[[7]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73)
[[8]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41)

**Container and utility updates:**

* Refactored the `garray` container implementation and related
constructors/methods to use `[]any` instead of `[]interface{}`, along
with corresponding function signatures.
[[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31)
[[2]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L52-R52)
[[3]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L62-R62)
[[4]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L73-R86)
[[5]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L96-R97)
[[6]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L107-R114)
[[7]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L124-R124)
[[8]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L135-R143)
[[9]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L167-R167)

These changes collectively modernize the codebase and prepare it for
future Go developments by using the idiomatic `any` type.
2025-08-28 16:53:19 +08:00

226 lines
7.4 KiB
Go

// 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 gclient
import (
"context"
"crypto/tls"
"fmt"
"io"
"net/http"
"net/http/httptrace"
"net/textproto"
"strings"
"sync"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
"github.com/gogf/gf/v2/internal/utils"
"github.com/gogf/gf/v2/net/gtrace"
"github.com/gogf/gf/v2/util/gconv"
)
// clientTracerTracing is used for implementing httptrace.ClientTrace.
type clientTracerTracing struct {
context.Context
span trace.Span
request *http.Request
requestBody []byte
headers map[string]any
mtx sync.Mutex
}
// newClientTracerTracing creates and returns object of httptrace.ClientTrace.
func newClientTracerTracing(
ctx context.Context,
span trace.Span,
request *http.Request,
) *httptrace.ClientTrace {
ct := &clientTracerTracing{
Context: ctx,
span: span,
request: request,
headers: make(map[string]any),
}
reqBodyContent, _ := io.ReadAll(ct.request.Body)
ct.requestBody = reqBodyContent
ct.request.Body = utils.NewReadCloser(reqBodyContent, false)
return &httptrace.ClientTrace{
GetConn: ct.GetConn,
GotConn: ct.GotConn,
PutIdleConn: ct.PutIdleConn,
GotFirstResponseByte: ct.GotFirstResponseByte,
Got100Continue: ct.Got100Continue,
Got1xxResponse: ct.Got1xxResponse,
DNSStart: ct.DNSStart,
DNSDone: ct.DNSDone,
ConnectStart: ct.ConnectStart,
ConnectDone: ct.ConnectDone,
TLSHandshakeStart: ct.TLSHandshakeStart,
TLSHandshakeDone: ct.TLSHandshakeDone,
WroteHeaderField: ct.WroteHeaderField,
WroteHeaders: ct.WroteHeaders,
Wait100Continue: ct.Wait100Continue,
WroteRequest: ct.WroteRequest,
}
}
// GetConn is called before a connection is created or
// retrieved from an idle pool. The hostPort is the
// "host:port" of the target or proxy. GetConn is called even
// if there's already an idle cached connection available.
func (ct *clientTracerTracing) GetConn(host string) {}
// GotConn is called after a successful connection is
// obtained. There is no hook for failure to obtain a
// connection; instead, use the error from
// Transport.RoundTrip.
func (ct *clientTracerTracing) GotConn(info httptrace.GotConnInfo) {
remoteAddr := ""
if info.Conn.RemoteAddr() != nil {
remoteAddr = info.Conn.RemoteAddr().String()
}
localAddr := ""
if info.Conn.LocalAddr() != nil {
localAddr = info.Conn.LocalAddr().String()
}
ct.span.SetAttributes(
attribute.String(tracingAttrHttpAddressRemote, remoteAddr),
attribute.String(tracingAttrHttpAddressLocal, localAddr),
)
}
// PutIdleConn is called when the connection is returned to
// the idle pool. If err is nil, the connection was
// successfully returned to the idle pool. If err is non-nil,
// it describes why not. PutIdleConn is not called if
// connection reuse is disabled via Transport.DisableKeepAlives.
// PutIdleConn is called before the caller's Response.Body.Close
// call returns.
// For HTTP/2, this hook is not currently used.
func (ct *clientTracerTracing) PutIdleConn(err error) {
if err != nil {
ct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))
}
}
// GotFirstResponseByte is called when the first byte of the response
// headers is available.
func (ct *clientTracerTracing) GotFirstResponseByte() {}
// Got100Continue is called if the server replies with a "100
// Continue" response.
func (ct *clientTracerTracing) Got100Continue() {}
// Got1xxResponse is called for each 1xx informational response header
// returned before the final non-1xx response. Got1xxResponse is called
// for "100 Continue" responses, even if Got100Continue is also defined.
// If it returns an error, the client request is aborted with that error value.
func (ct *clientTracerTracing) Got1xxResponse(code int, header textproto.MIMEHeader) error {
return nil
}
// DNSStart is called when a DNS lookup begins.
func (ct *clientTracerTracing) DNSStart(info httptrace.DNSStartInfo) {
ct.span.SetAttributes(
attribute.String(tracingAttrHttpDnsStart, info.Host),
)
}
// DNSDone is called when a DNS lookup ends.
func (ct *clientTracerTracing) DNSDone(info httptrace.DNSDoneInfo) {
var buffer strings.Builder
for _, v := range info.Addrs {
if buffer.Len() != 0 {
buffer.WriteString(",")
}
buffer.WriteString(v.String())
}
if info.Err != nil {
ct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, info.Err))
}
ct.span.SetAttributes(
attribute.String(tracingAttrHttpDnsDone, buffer.String()),
)
}
// ConnectStart is called when a new connection's Dial begins.
// If net.Dialer.DualStack (IPv6 "Happy Eyeballs") support is
// enabled, this may be called multiple times.
func (ct *clientTracerTracing) ConnectStart(network, addr string) {
ct.span.SetAttributes(
attribute.String(tracingAttrHttpConnectStart, network+"@"+addr),
)
}
// ConnectDone is called when a new connection's Dial
// completes. The provided err indicates whether the
// connection completed successfully.
// If net.Dialer.DualStack ("Happy Eyeballs") support is
// enabled, this may be called multiple times.
func (ct *clientTracerTracing) ConnectDone(network, addr string, err error) {
if err != nil {
ct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))
}
ct.span.SetAttributes(
attribute.String(tracingAttrHttpConnectDone, network+"@"+addr),
)
}
// TLSHandshakeStart is called when the TLS handshake is started. When
// connecting to an HTTPS site via an HTTP proxy, the handshake happens
// after the CONNECT request is processed by the proxy.
func (ct *clientTracerTracing) TLSHandshakeStart() {}
// TLSHandshakeDone is called after the TLS handshake with either the
// successful handshake's connection state, or a non-nil error on handshake
// failure.
func (ct *clientTracerTracing) TLSHandshakeDone(_ tls.ConnectionState, err error) {
if err != nil {
ct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))
}
}
// WroteHeaderField is called after the Transport has written
// each request header. At the time of this call the values
// might be buffered and not yet written to the network.
func (ct *clientTracerTracing) WroteHeaderField(k string, v []string) {
if len(v) > 1 {
ct.headers[k] = v
} else if len(v) == 1 {
ct.headers[k] = v[0]
}
}
// WroteHeaders is called after the Transport has written
// all request headers.
func (ct *clientTracerTracing) WroteHeaders() {}
// Wait100Continue is called if the Request specified
// "Expect: 100-continue" and the Transport has written the
// request headers but is waiting for "100 Continue" from the
// server before writing the request body.
func (ct *clientTracerTracing) Wait100Continue() {}
// WroteRequest is called with the result of writing the
// request and any body. It may be called multiple times
// in the case of retried requests.
func (ct *clientTracerTracing) WroteRequest(info httptrace.WroteRequestInfo) {
if info.Err != nil {
ct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, info.Err))
}
ct.span.AddEvent(tracingEventHttpRequest, trace.WithAttributes(
attribute.String(tracingEventHttpRequestHeaders, gconv.String(ct.headers)),
attribute.String(tracingEventHttpRequestBaggage, gtrace.GetBaggageMap(ct.Context).String()),
))
}