http.Client 是 Go 标准库 HTTP 客户端实现, sentry-go也没有这个组件,所以需要自己实现。 我们只需要对 http.Transport 进行包装即可, 完整代码如下
go
package main
import (
"bytes"
"fmt"
"io"
"log"
"net/http"
"time"
"github.com/getsentry/sentry-go"
)
type tracingTransport struct {
http.RoundTripper
}
func NewTracingTransport(roundTripper http.RoundTripper) *tracingTransport {
return &tracingTransport{RoundTripper: roundTripper}
}
func (t *tracingTransport) RoundTrip(req *http.Request) (*http.Response, error) {
operationName := fmt.Sprintf("HTTP %s %s", req.Method, req.URL.String())
span := sentry.StartSpan(req.Context(), operationName)
defer span.Finish()
span.SetTag("url", req.URL.String())
if span.Data == nil {
span.Data = make(map[string]interface{})
}
// reading body from the request body and fill it again
var body []byte
var err error
if req.Body != nil {
body, err = io.ReadAll(req.Body)
if err != nil {
return nil, err
}
}
// Be careful with including sensitive information in the span,
// request body and response may have private user data, which we wouldn't want to expose,
// authorization header also is a good example of sensitive data.
span.Data["body"] = string(body)
req.Body = io.NopCloser(bytes.NewBuffer(body))
// adding sentry header for distributed tracing
req.Header.Add("sentry-trace", span.TraceID.String())
response, err := t.RoundTripper.RoundTrip(req)
span.Data["http_code"] = response.StatusCode
// could additionally add the response to the span data
return response, err
}
func main() {
err := sentry.Init(sentry.ClientOptions{
Debug: true,
Dsn: "https://a5eac4fa3396cbfac8fb4baa6a9c03a3@o4504291071688704.ingest.sentry.io/4506715873804288",
AttachStacktrace: true,
EnableTracing: true,
SampleRate: 1.0,
TracesSampleRate: 1.0,
ProfilesSampleRate: 1.0,
})
if err != nil {
log.Fatalf("sentry.Init: %s", err)
}
defer sentry.Flush(2 * time.Second)
client := &http.Client{
Transport: NewTracingTransport(http.DefaultTransport),
}
res, err := client.Get("http://httpbin.org/get")
if err != nil {
log.Fatalf("client Get: %s", err)
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
log.Fatalf("io.ReadAll: %s", err)
}
fmt.Println(string(body))
}
参考: