mirror of
https://gitee.com/johng/gf
synced 2026-07-05 21:32:17 +08:00
add tracing configuration switch for whole framework
This commit is contained in:
@ -16,9 +16,11 @@ import (
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/net/gtrace"
|
||||
"golang.org/x/net/proxy"
|
||||
|
||||
"github.com/gogf/gf/v2"
|
||||
@ -43,12 +45,13 @@ type Client struct {
|
||||
}
|
||||
|
||||
var (
|
||||
defaultClientAgent = fmt.Sprintf(`GoFrameHTTPClient %s`, gf.VERSION)
|
||||
host, _ = os.Hostname()
|
||||
defaultClientAgent = fmt.Sprintf(`GClient %s at %s`, gf.VERSION, host)
|
||||
)
|
||||
|
||||
// New creates and returns a new HTTP client object.
|
||||
func New() *Client {
|
||||
client := &Client{
|
||||
c := &Client{
|
||||
Client: http.Client{
|
||||
Transport: &http.Transport{
|
||||
// No validation for https certification of the server in default.
|
||||
@ -61,8 +64,12 @@ func New() *Client {
|
||||
header: make(map[string]string),
|
||||
cookies: make(map[string]string),
|
||||
}
|
||||
client.header["User-Agent"] = defaultClientAgent
|
||||
return client
|
||||
c.header["User-Agent"] = defaultClientAgent
|
||||
// It enables OpenTelemetry for client if tracing feature is enabled.
|
||||
if gtrace.IsEnabled() {
|
||||
c.Use(MiddlewareTracing)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// Clone deeply clones current client and returns a new one.
|
||||
|
||||
@ -7,11 +7,13 @@
|
||||
package gclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptrace"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
@ -27,25 +29,38 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
tracingInstrumentName = "github.com/gogf/gf/v2/net/gclient.Client"
|
||||
tracingAttrHttpAddressRemote = "http.address.remote"
|
||||
tracingAttrHttpAddressLocal = "http.address.local"
|
||||
tracingAttrHttpDnsStart = "http.dns.start"
|
||||
tracingAttrHttpDnsDone = "http.dns.done"
|
||||
tracingAttrHttpConnectStart = "http.connect.start"
|
||||
tracingAttrHttpConnectDone = "http.connect.done"
|
||||
tracingEventHttpRequest = "http.request"
|
||||
tracingEventHttpRequestHeaders = "http.request.headers"
|
||||
tracingEventHttpRequestBaggage = "http.request.baggage"
|
||||
tracingEventHttpRequestBody = "http.request.body"
|
||||
tracingEventHttpResponse = "http.response"
|
||||
tracingEventHttpResponseHeaders = "http.response.headers"
|
||||
tracingEventHttpResponseBody = "http.response.body"
|
||||
tracingInstrumentName = "github.com/gogf/gf/v2/net/gclient.Client"
|
||||
tracingAttrHttpAddressRemote = "http.address.remote"
|
||||
tracingAttrHttpAddressLocal = "http.address.local"
|
||||
tracingAttrHttpDnsStart = "http.dns.start"
|
||||
tracingAttrHttpDnsDone = "http.dns.done"
|
||||
tracingAttrHttpConnectStart = "http.connect.start"
|
||||
tracingAttrHttpConnectDone = "http.connect.done"
|
||||
tracingEventHttpRequest = "http.request"
|
||||
tracingEventHttpRequestHeaders = "http.request.headers"
|
||||
tracingEventHttpRequestBaggage = "http.request.baggage"
|
||||
tracingEventHttpRequestBody = "http.request.body"
|
||||
tracingEventHttpResponse = "http.response"
|
||||
tracingEventHttpResponseHeaders = "http.response.headers"
|
||||
tracingEventHttpResponseBody = "http.response.body"
|
||||
tracingMiddlewareHandled gctx.StrKey = `MiddlewareClientTracingHandled`
|
||||
)
|
||||
|
||||
// MiddlewareTracing is a client middleware that enables tracing feature using standards of OpenTelemetry.
|
||||
func MiddlewareTracing(c *Client, r *http.Request) (response *Response, err error) {
|
||||
tr := otel.GetTracerProvider().Tracer(tracingInstrumentName, trace.WithInstrumentationVersion(gf.VERSION))
|
||||
var (
|
||||
ctx = r.Context()
|
||||
)
|
||||
// Mark this request is handled by server tracing middleware.
|
||||
if ctx.Value(tracingMiddlewareHandled) != nil {
|
||||
return c.Next(r)
|
||||
}
|
||||
|
||||
ctx = context.WithValue(ctx, tracingMiddlewareHandled, 1)
|
||||
tr := otel.GetTracerProvider().Tracer(
|
||||
tracingInstrumentName,
|
||||
trace.WithInstrumentationVersion(gf.VERSION),
|
||||
)
|
||||
ctx, span := tr.Start(r.Context(), r.URL.String(), trace.WithSpanKind(trace.SpanKindClient))
|
||||
defer span.End()
|
||||
|
||||
|
||||
@ -7,10 +7,11 @@
|
||||
package ghttp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
@ -20,38 +21,50 @@ import (
|
||||
"github.com/gogf/gf/v2"
|
||||
"github.com/gogf/gf/v2/internal/httputil"
|
||||
"github.com/gogf/gf/v2/internal/utils"
|
||||
"github.com/gogf/gf/v2/net/gclient"
|
||||
"github.com/gogf/gf/v2/net/gtrace"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
const (
|
||||
tracingInstrumentName = "github.com/gogf/gf/v2/net/ghttp.Server"
|
||||
tracingEventHttpRequest = "http.request"
|
||||
tracingEventHttpRequestHeaders = "http.request.headers"
|
||||
tracingEventHttpRequestBaggage = "http.request.baggage"
|
||||
tracingEventHttpRequestBody = "http.request.body"
|
||||
tracingEventHttpResponse = "http.response"
|
||||
tracingEventHttpResponseHeaders = "http.response.headers"
|
||||
tracingEventHttpResponseBody = "http.response.body"
|
||||
tracingInstrumentName = "github.com/gogf/gf/v2/net/ghttp.Server"
|
||||
tracingEventHttpRequest = "http.request"
|
||||
tracingEventHttpRequestHeaders = "http.request.headers"
|
||||
tracingEventHttpRequestBaggage = "http.request.baggage"
|
||||
tracingEventHttpRequestBody = "http.request.body"
|
||||
tracingEventHttpResponse = "http.response"
|
||||
tracingEventHttpResponseHeaders = "http.response.headers"
|
||||
tracingEventHttpResponseBody = "http.response.body"
|
||||
tracingMiddlewareHandled gctx.StrKey = `MiddlewareServerTracingHandled`
|
||||
)
|
||||
|
||||
// MiddlewareClientTracing is a client middleware that enables tracing feature using standards of OpenTelemetry.
|
||||
func MiddlewareClientTracing(c *gclient.Client, r *http.Request) (*gclient.Response, error) {
|
||||
return gclient.MiddlewareTracing(c, r)
|
||||
}
|
||||
|
||||
// MiddlewareServerTracing is a serer middleware that enables tracing feature using standards of OpenTelemetry.
|
||||
func MiddlewareServerTracing(r *Request) {
|
||||
var (
|
||||
tr = otel.GetTracerProvider().Tracer(tracingInstrumentName, trace.WithInstrumentationVersion(gf.VERSION))
|
||||
ctx, span = tr.Start(
|
||||
otel.GetTextMapPropagator().Extract(r.Context(), propagation.HeaderCarrier(r.Header)),
|
||||
r.URL.String(),
|
||||
trace.WithSpanKind(trace.SpanKindServer),
|
||||
ctx = r.Context()
|
||||
)
|
||||
// Mark this request is handled by server tracing middleware.
|
||||
if ctx.Value(tracingMiddlewareHandled) != nil {
|
||||
r.Middleware.Next()
|
||||
return
|
||||
}
|
||||
|
||||
ctx = context.WithValue(ctx, tracingMiddlewareHandled, 1)
|
||||
var (
|
||||
span trace.Span
|
||||
tr = otel.GetTracerProvider().Tracer(
|
||||
tracingInstrumentName,
|
||||
trace.WithInstrumentationVersion(gf.VERSION),
|
||||
)
|
||||
)
|
||||
ctx, span = tr.Start(
|
||||
otel.GetTextMapPropagator().Extract(
|
||||
ctx,
|
||||
propagation.HeaderCarrier(r.Header),
|
||||
),
|
||||
r.URL.String(),
|
||||
trace.WithSpanKind(trace.SpanKindServer),
|
||||
)
|
||||
defer span.End()
|
||||
|
||||
span.SetAttributes(gtrace.CommonLabels()...)
|
||||
|
||||
@ -16,6 +16,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/net/gtrace"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
@ -115,6 +116,10 @@ func GetServer(name ...interface{}) *Server {
|
||||
}
|
||||
// Record the server to internal server mapping by name.
|
||||
serverMapping.Set(serverName, s)
|
||||
// It enables OpenTelemetry for server if tracing feature is enabled.
|
||||
if gtrace.IsEnabled() {
|
||||
s.Use(MiddlewareServerTracing)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
|
||||
@ -28,14 +28,16 @@ import (
|
||||
const (
|
||||
tracingCommonKeyIpIntranet = `ip.intranet`
|
||||
tracingCommonKeyIpHostname = `hostname`
|
||||
commandEnvKeyForMaxContentLogSize = "gf.gtrace.maxcontentlogsize"
|
||||
commandEnvKeyForTracingInternal = "gf.gtrace.tracinginternal"
|
||||
commandEnvKeyForTraceEnabled = "gf.trace.enabled" // Main switch for tracing feature.
|
||||
commandEnvKeyForMaxContentLogSize = "gf.gtrace.max.content.log.size" // To avoid too big tracing content.
|
||||
commandEnvKeyForTracingInternal = "gf.gtrace.tracing.internal" // For detailed controlling for tracing content.
|
||||
)
|
||||
|
||||
var (
|
||||
intranetIps, _ = gipv4.GetIntranetIpArray()
|
||||
intranetIpStr = strings.Join(intranetIps, ",")
|
||||
hostname, _ = os.Hostname()
|
||||
traceEnabled = false // traceEnabled enables tracing feature for all.
|
||||
tracingInternal = true // tracingInternal enables tracing for internal type spans.
|
||||
tracingMaxContentLogSize = 512 * 1024 // Max log size for request and response body, especially for HTTP/RPC request.
|
||||
// defaultTextMapPropagator is the default propagator for context propagation between peers.
|
||||
@ -46,6 +48,7 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
traceEnabled = gconv.Bool(command.GetOptWithEnv(commandEnvKeyForTraceEnabled, "false"))
|
||||
tracingInternal = gconv.Bool(command.GetOptWithEnv(commandEnvKeyForTracingInternal, "true"))
|
||||
if maxContentLogSize := gconv.Int(command.GetOptWithEnv(commandEnvKeyForMaxContentLogSize)); maxContentLogSize > 0 {
|
||||
tracingMaxContentLogSize = maxContentLogSize
|
||||
@ -53,6 +56,21 @@ func init() {
|
||||
CheckSetDefaultTextMapPropagator()
|
||||
}
|
||||
|
||||
// SetEnabled enables or disables the tracing feature.
|
||||
func SetEnabled(enabled bool) {
|
||||
traceEnabled = enabled
|
||||
}
|
||||
|
||||
// IsEnabled checks and returns if tracing feature is configured enabled.
|
||||
func IsEnabled() bool {
|
||||
return traceEnabled
|
||||
}
|
||||
|
||||
// IsActivated checks given context and returns if tracing feature is actually activated in this context.
|
||||
func IsActivated(ctx context.Context) bool {
|
||||
return GetTraceID(ctx) != ""
|
||||
}
|
||||
|
||||
// IsTracingInternal returns whether tracing spans of internal components.
|
||||
func IsTracingInternal() bool {
|
||||
return tracingInternal
|
||||
@ -73,11 +91,6 @@ func CommonLabels() []attribute.KeyValue {
|
||||
}
|
||||
}
|
||||
|
||||
// IsActivated checks and returns if tracing feature is activated.
|
||||
func IsActivated(ctx context.Context) bool {
|
||||
return GetTraceID(ctx) != ""
|
||||
}
|
||||
|
||||
// CheckSetDefaultTextMapPropagator sets the default TextMapPropagator if it is not set previously.
|
||||
func CheckSetDefaultTextMapPropagator() {
|
||||
p := otel.GetTextMapPropagator()
|
||||
|
||||
Reference in New Issue
Block a user