summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill Hawkins <[email protected]>2023-07-19 10:45:53 -0400
committerWill Hawkins <[email protected]>2023-07-19 10:45:53 -0400
commit4a3b5c9ab262a6c029c04a6d1e7f6fe038ee9e63 (patch)
tree2648458225ee1c37e2e5f6743b2aab77ff3bcc63
parentcca033fe0d7389bfa647afa47a47de2a3f6af47d (diff)
[Feature] Add extended-stats for uploads
Now that tests are run in sequence, it seems like a good idea to support extended statistics in both directions. Fixes #58 h/t @moeller0 Signed-off-by: Will Hawkins <[email protected]>
-rw-r--r--lgc/download.go1
-rw-r--r--lgc/upload.go160
-rw-r--r--networkQuality.go21
3 files changed, 170 insertions, 12 deletions
diff --git a/lgc/download.go b/lgc/download.go
index c13a1b1..3ce4389 100644
--- a/lgc/download.go
+++ b/lgc/download.go
@@ -39,7 +39,6 @@ type LoadGeneratingConnectionDownload struct {
ConnectToAddr string
URL string
downloadStartTime time.Time
- lastDownloaded uint64
client *http.Client
debug debug.DebugLevel
InsecureSkipVerify bool
diff --git a/lgc/upload.go b/lgc/upload.go
index e4518b8..32dd86a 100644
--- a/lgc/upload.go
+++ b/lgc/upload.go
@@ -20,12 +20,14 @@ import (
"fmt"
"io"
"net/http"
+ "net/http/httptrace"
"sync"
"sync/atomic"
"time"
"github.com/network-quality/goresponsiveness/debug"
"github.com/network-quality/goresponsiveness/stats"
+ "github.com/network-quality/goresponsiveness/traceable"
"github.com/network-quality/goresponsiveness/utilities"
)
@@ -37,12 +39,13 @@ type LoadGeneratingConnectionUpload struct {
URL string
ConnectToAddr string
uploadStartTime time.Time
- lastUploaded uint64
client *http.Client
debug debug.DebugLevel
InsecureSkipVerify bool
KeyLogger io.Writer
clientId uint64
+ tracer *httptrace.ClientTrace
+ stats stats.TraceStats
status LgcStatus
statusLock *sync.Mutex
statusWaiter *sync.Cond
@@ -67,6 +70,154 @@ func (lgu *LoadGeneratingConnectionUpload) WaitUntilStarted(ctxt context.Context
return utilities.WaitWithContext(ctxt, &conditional, lgu.statusLock, lgu.statusWaiter)
}
+func (lgu *LoadGeneratingConnectionUpload) SetDnsStartTimeInfo(
+ now time.Time,
+ dnsStartInfo httptrace.DNSStartInfo,
+) {
+ lgu.stats.DnsStartTime = now
+ lgu.stats.DnsStart = dnsStartInfo
+ if debug.IsDebug(lgu.debug) {
+ fmt.Printf(
+ "DNS Start for %v: %v\n",
+ lgu.ClientId(),
+ dnsStartInfo,
+ )
+ }
+}
+
+func (lgu *LoadGeneratingConnectionUpload) SetDnsDoneTimeInfo(
+ now time.Time,
+ dnsDoneInfo httptrace.DNSDoneInfo,
+) {
+ lgu.stats.DnsDoneTime = now
+ lgu.stats.DnsDone = dnsDoneInfo
+ if debug.IsDebug(lgu.debug) {
+ fmt.Printf(
+ "DNS Done for %v: %v\n",
+ lgu.ClientId(),
+ lgu.stats.DnsDone,
+ )
+ }
+}
+
+func (lgu *LoadGeneratingConnectionUpload) SetConnectStartTime(
+ now time.Time,
+) {
+ lgu.stats.ConnectStartTime = now
+ if debug.IsDebug(lgu.debug) {
+ fmt.Printf(
+ "TCP Start for %v at %v\n",
+ lgu.ClientId(),
+ lgu.stats.ConnectStartTime,
+ )
+ }
+}
+
+func (lgu *LoadGeneratingConnectionUpload) SetConnectDoneTimeError(
+ now time.Time,
+ err error,
+) {
+ lgu.stats.ConnectDoneTime = now
+ lgu.stats.ConnectDoneError = err
+ if debug.IsDebug(lgu.debug) {
+ fmt.Printf(
+ "TCP Done for %v (with error %v) @ %v\n",
+ lgu.ClientId(),
+ lgu.stats.ConnectDoneError,
+ lgu.stats.ConnectDoneTime,
+ )
+ }
+}
+
+func (lgu *LoadGeneratingConnectionUpload) SetGetConnTime(now time.Time) {
+ lgu.stats.GetConnectionStartTime = now
+ if debug.IsDebug(lgu.debug) {
+ fmt.Printf(
+ "Started getting connection for %v @ %v\n",
+ lgu.ClientId(),
+ lgu.stats.GetConnectionStartTime,
+ )
+ }
+}
+
+func (lgu *LoadGeneratingConnectionUpload) SetGotConnTimeInfo(
+ now time.Time,
+ gotConnInfo httptrace.GotConnInfo,
+) {
+ if gotConnInfo.Reused {
+ fmt.Printf("Unexpectedly reusing a connection!\n")
+ panic(!gotConnInfo.Reused)
+ }
+ lgu.stats.GetConnectionDoneTime = now
+ lgu.stats.ConnInfo = gotConnInfo
+ if debug.IsDebug(lgu.debug) {
+ fmt.Printf(
+ "Got connection for %v at %v with info %v\n",
+ lgu.ClientId(),
+ lgu.stats.GetConnectionDoneTime,
+ lgu.stats.ConnInfo,
+ )
+ }
+}
+
+func (lgu *LoadGeneratingConnectionUpload) SetTLSHandshakeStartTime(
+ now time.Time,
+) {
+ lgu.stats.TLSStartTime = utilities.Some(now)
+ if debug.IsDebug(lgu.debug) {
+ fmt.Printf(
+ "Started TLS Handshake for %v @ %v\n",
+ lgu.ClientId(),
+ lgu.stats.TLSStartTime,
+ )
+ }
+}
+
+func (lgu *LoadGeneratingConnectionUpload) SetTLSHandshakeDoneTimeState(
+ now time.Time,
+ connectionState tls.ConnectionState,
+) {
+ lgu.stats.TLSDoneTime = utilities.Some(now)
+ lgu.stats.TLSConnInfo = connectionState
+ if debug.IsDebug(lgu.debug) {
+ fmt.Printf(
+ "Completed TLS handshake for %v at %v with info %v\n",
+ lgu.ClientId(),
+ lgu.stats.TLSDoneTime,
+ lgu.stats.TLSConnInfo,
+ )
+ }
+}
+
+func (lgu *LoadGeneratingConnectionUpload) SetHttpWroteRequestTimeInfo(
+ now time.Time,
+ info httptrace.WroteRequestInfo,
+) {
+ lgu.stats.HttpWroteRequestTime = now
+ lgu.stats.HttpInfo = info
+ if debug.IsDebug(lgu.debug) {
+ fmt.Printf(
+ "(lgu) Http finished writing request for %v at %v with info %v\n",
+ lgu.ClientId(),
+ lgu.stats.HttpWroteRequestTime,
+ lgu.stats.HttpInfo,
+ )
+ }
+}
+
+func (lgu *LoadGeneratingConnectionUpload) SetHttpResponseReadyTime(
+ now time.Time,
+) {
+ lgu.stats.HttpResponseReadyTime = now
+ if debug.IsDebug(lgu.debug) {
+ fmt.Printf(
+ "Got the first byte of HTTP response headers for %v at %v\n",
+ lgu.ClientId(),
+ lgu.stats.HttpResponseReadyTime,
+ )
+ }
+}
+
func (lgu *LoadGeneratingConnectionUpload) ClientId() uint64 {
return lgu.clientId
}
@@ -124,7 +275,8 @@ func (lgu *LoadGeneratingConnectionUpload) doUpload(ctx context.Context) error {
var request *http.Request = nil
var err error
- if request, err = http.NewRequest(
+ if request, err = http.NewRequestWithContext(
+ httptrace.WithClientTrace(ctx, lgu.tracer),
"POST",
lgu.URL,
s,
@@ -195,6 +347,7 @@ func (lgu *LoadGeneratingConnectionUpload) Start(
utilities.OverrideHostTransport(transport, lgu.ConnectToAddr)
lgu.client = &http.Client{Transport: transport}
+ lgu.tracer = traceable.GenerateHttpTimingTracer(lgu, lgu.debug)
if debug.IsDebug(lgu.debug) {
fmt.Printf("Started a load-generating upload (id: %v).\n", lgu.clientId)
@@ -205,6 +358,5 @@ func (lgu *LoadGeneratingConnectionUpload) Start(
}
func (lgu *LoadGeneratingConnectionUpload) Stats() *stats.TraceStats {
- // Get all your stats from the download side of the LGC.
- return nil
+ return &lgu.stats
}
diff --git a/networkQuality.go b/networkQuality.go
index ed9dcfa..1e6590b 100644
--- a/networkQuality.go
+++ b/networkQuality.go
@@ -432,8 +432,7 @@ func main() {
downloadDirection.Lgcc = lgc.NewLoadGeneratingConnectionCollection()
uploadDirection.Lgcc = lgc.NewLoadGeneratingConnectionCollection()
- // We do not do tracing on upload connections so there are no extended stats for those connections!
- uploadDirection.ExtendedStatsEligible = false
+ uploadDirection.ExtendedStatsEligible = true
downloadDirection.ExtendedStatsEligible = true
generateSelfProbeConfiguration := func() probe.ProbeConfiguration {
@@ -956,24 +955,32 @@ func main() {
direction.Lgcc.Lock.Lock()
defer direction.Lgcc.Lock.Unlock()
- // Note: We do not trace upload connections!
- downloadLgcCount, err := direction.Lgcc.Len()
+ lgcCount, err := direction.Lgcc.Len()
if err != nil {
fmt.Fprintf(
os.Stderr,
- "Warning: Could not calculate the number of download load-generating connections; aborting extended stats preparation.\n",
+ "Warning: Could not calculate the number of %v load-generating connections; aborting extended stats preparation.\n", direction.DirectionLabel,
)
return
}
- for i := 0; i < downloadLgcCount; i++ {
+
+ for i := 0; i < lgcCount; i++ {
// Assume that extended statistics are available -- the check was done explicitly at
// program startup if the calculateExtendedStats flag was set by the user on the command line.
currentLgc, _ := direction.Lgcc.Get(i)
+
+ if currentLgc == nil || (*currentLgc).Stats() == nil {
+ fmt.Fprintf(
+ os.Stderr,
+ "Warning: Could not add extended stats for the connection: The LGC was nil or there were no stats available.\n",
+ )
+ continue
+ }
if err := extendedStats.IncorporateConnectionStats(
(*currentLgc).Stats().ConnInfo.Conn); err != nil {
fmt.Fprintf(
os.Stderr,
- "Warning: Could not add extended stats for the connection: %v\n",
+ "Warning: Could not add extended stats for the connection: %v.\n",
err,
)
}