@@ -18,9 +18,11 @@ import (
18
18
"runtime"
19
19
"strconv"
20
20
"strings"
21
+ "sync"
21
22
"time"
22
23
"unicode/utf8"
23
24
25
+ "golang.org/x/exp/trace"
24
26
"golang.org/x/time/rate"
25
27
26
28
ot "github.com/opentracing/opentracing-go"
@@ -410,6 +412,9 @@ type Proxy struct {
410
412
clientTLS * tls.Config
411
413
hostname string
412
414
onPanicSometimes rate.Sometimes
415
+ flightRecorder * trace.FlightRecorder
416
+ traceOnce sync.Once
417
+ tooLong time.Duration
413
418
}
414
419
415
420
// proxyError is used to wrap errors during proxying and to indicate
@@ -796,6 +801,15 @@ func WithParams(p Params) *Proxy {
796
801
endpointRegistry : p .EndpointRegistry ,
797
802
}
798
803
}
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
+
799
813
return & Proxy {
800
814
routing : p .Routing ,
801
815
registry : p .EndpointRegistry ,
@@ -824,6 +838,32 @@ func WithParams(p Params) *Proxy {
824
838
clientTLS : tr .TLSClientConfig ,
825
839
hostname : hostname ,
826
840
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
+ })
827
867
}
828
868
}
829
869
@@ -969,6 +1009,8 @@ func (p *Proxy) makeBackendRequest(ctx *context, requestContext stdlibcontext.Co
969
1009
ctx .proxySpan .LogKV ("http_roundtrip" , StartEvent )
970
1010
req = injectClientTrace (req , ctx .proxySpan )
971
1011
1012
+ p .writeTraceIfTooSlow (ctx )
1013
+
972
1014
response , err := roundTripper .RoundTrip (req )
973
1015
if endpointMetrics != nil {
974
1016
endpointMetrics .IncRequests (routing.IncRequestsOptions {FailedRoundTrip : err != nil })
@@ -1586,6 +1628,7 @@ func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
1586
1628
func (p * Proxy ) Close () error {
1587
1629
close (p .quit )
1588
1630
p .registry .Close ()
1631
+ p .flightRecorder .Stop ()
1589
1632
return nil
1590
1633
}
1591
1634
0 commit comments