Skip to content

Commit 74b6d67

Browse files
committed
feature: flightrecorder to enable Go trace
Signed-off-by: Sandor Szücs <[email protected]>
1 parent fd0f608 commit 74b6d67

File tree

3 files changed

+46
-1
lines changed

3 files changed

+46
-1
lines changed

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ require (
164164
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
165165
go.uber.org/atomic v1.9.0 // indirect
166166
go.uber.org/automaxprocs v1.5.3 // indirect
167-
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
167+
golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f // indirect
168168
golang.org/x/mod v0.16.0 // indirect
169169
golang.org/x/sys v0.18.0 // indirect
170170
golang.org/x/text v0.14.0 // indirect

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,8 @@ golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL
488488
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
489489
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
490490
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
491+
golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f h1:3CW0unweImhOzd5FmYuRsD4Y4oQFKZIjAnKbjV4WIrw=
492+
golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
491493
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
492494
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
493495
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=

proxy/proxy.go

+43
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ import (
1818
"runtime"
1919
"strconv"
2020
"strings"
21+
"sync"
2122
"time"
2223
"unicode/utf8"
2324

25+
"golang.org/x/exp/trace"
2426
"golang.org/x/time/rate"
2527

2628
ot "github.com/opentracing/opentracing-go"
@@ -410,6 +412,9 @@ type Proxy struct {
410412
clientTLS *tls.Config
411413
hostname string
412414
onPanicSometimes rate.Sometimes
415+
flightRecorder *trace.FlightRecorder
416+
traceOnce sync.Once
417+
tooLong time.Duration
413418
}
414419

415420
// proxyError is used to wrap errors during proxying and to indicate
@@ -796,6 +801,15 @@ func WithParams(p Params) *Proxy {
796801
endpointRegistry: p.EndpointRegistry,
797802
}
798803
}
804+
// TODO(sszuecs): expose an option to start it
805+
fr := trace.NewFlightRecorder()
806+
//fr.SetPeriod(d)
807+
//fr.SetSize(bytes int)
808+
err := fr.Start()
809+
if err != nil {
810+
println("Failed to start FlightRecorder:", err.Error())
811+
}
812+
799813
return &Proxy{
800814
routing: p.Routing,
801815
registry: p.EndpointRegistry,
@@ -824,6 +838,32 @@ func WithParams(p Params) *Proxy {
824838
clientTLS: tr.TLSClientConfig,
825839
hostname: hostname,
826840
onPanicSometimes: rate.Sometimes{First: 3, Interval: 1 * time.Minute},
841+
flightRecorder: fr,
842+
traceOnce: sync.Once{},
843+
tooLong: 250 * time.Millisecond,
844+
}
845+
}
846+
847+
func (p *Proxy) writeTraceIfTooSlow(ctx *context) {
848+
p.log.Infof("write trace if too slow: %s > %s", time.Since(ctx.startServe), p.tooLong)
849+
if time.Since(ctx.startServe) > p.tooLong {
850+
p.log.Info("too slow")
851+
// Do it only once for simplicitly, but you can take more than one.
852+
p.traceOnce.Do(func() {
853+
p.log.Info("write trace because we were too slow")
854+
// Grab the snapshot.
855+
var b bytes.Buffer
856+
_, err := p.flightRecorder.WriteTo(&b)
857+
if err != nil {
858+
p.log.Errorf("Failed to write flightrecorder data: %v", err)
859+
return
860+
}
861+
// Write it to a file.
862+
if err := os.WriteFile("trace.out", b.Bytes(), 0o755); err != nil {
863+
p.log.Errorf("Failed to write trace.out: %v", err)
864+
return
865+
}
866+
})
827867
}
828868
}
829869

@@ -969,6 +1009,8 @@ func (p *Proxy) makeBackendRequest(ctx *context, requestContext stdlibcontext.Co
9691009
ctx.proxySpan.LogKV("http_roundtrip", StartEvent)
9701010
req = injectClientTrace(req, ctx.proxySpan)
9711011

1012+
p.writeTraceIfTooSlow(ctx)
1013+
9721014
response, err := roundTripper.RoundTrip(req)
9731015
if endpointMetrics != nil {
9741016
endpointMetrics.IncRequests(routing.IncRequestsOptions{FailedRoundTrip: err != nil})
@@ -1586,6 +1628,7 @@ func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
15861628
func (p *Proxy) Close() error {
15871629
close(p.quit)
15881630
p.registry.Close()
1631+
p.flightRecorder.Stop()
15891632
return nil
15901633
}
15911634

0 commit comments

Comments
 (0)