@@ -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) {
15861628func (p * Proxy ) Close () error {
15871629 close (p .quit )
15881630 p .registry .Close ()
1631+ p .flightRecorder .Stop ()
15891632 return nil
15901633}
15911634
0 commit comments