Skip to content

Commit

Permalink
refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
rbarazzutti committed Jan 2, 2022
1 parent 5917ee0 commit 86aff00
Show file tree
Hide file tree
Showing 6 changed files with 386 additions and 211 deletions.
1 change: 1 addition & 0 deletions app/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ type Config struct {
KeepCookies bool
FollowRedirects bool
Workers int
Tput bool
}

// RuntimeConfig defines the parameters which can be passed to NewPinger and NewWebClient
Expand Down
244 changes: 33 additions & 211 deletions app/httpping.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,22 +82,42 @@ func (httpPingImpl *httpPingImpl) Run() error {

_, _ = fmt.Fprintf(stdout, "HTTP-PING %s %s\n\n", httpPingImpl.pinger.URL(), config.Method)

ch := httpPingImpl.pinger.Ping()
measuresChannel := httpPingImpl.pinger.Ping()

successes := 0
attempts := 0
var latencies []stats.Measure
ticker := time.NewTicker(5 * time.Second)
tickerChan := make(<-chan time.Time)
ticker.Stop()
started := false
tputMeasurer := newTputMeasurer()

var loop = true
loop := true
for loop {
select {
case measure := <-ch:

case _ = <-tickerChan:

m := tputMeasurer.Measure()
httpPingImpl.logger.onTick(m)

case measure := <-measuresChannel:
if measure == nil {
loop = false
} else {
httpPingImpl.logger.onMeasure(measure, attempts)
attempts++
if !measure.IsFailure {
if !started {
if config.Tput {
tputMeasurer.Measure()
tickerChan = (time.NewTicker(5 * time.Second)).C
}
started = true
}
tputMeasurer.Count(measure.TotalTime)

successes++
latencies = append(latencies, measure.TotalTime)
if config.AudibleBell {
Expand All @@ -118,214 +138,16 @@ func (httpPingImpl *httpPingImpl) Run() error {
return nil
}

type logger interface {
onMeasure(httpMeasure *HTTPMeasure, id int)
onClose(attempts int64, success int64, lossRate float64, pingStats *stats.PingStats)
}

type quietLogger struct {
config *Config
stdout io.Writer
pinger Pinger
}

func newQuietLogger(config *Config, stdout io.Writer, pinger Pinger) logger {
return &quietLogger{config: config, stdout: stdout, pinger: pinger}
}

func (quietLogger *quietLogger) onMeasure(_ *HTTPMeasure, _ int) {
}

func (quietLogger *quietLogger) onClose(attempts int64, successes int64, lossRate float64, pingStats *stats.PingStats) {

_, _ = fmt.Fprintf(quietLogger.stdout, "--- %s ping statistics ---\n", quietLogger.pinger.URL())

_, _ = fmt.Fprintf(quietLogger.stdout, "%d requests sent, %d answers received, %.1f%% loss\n", attempts, successes, lossRate)

if successes > 0 {
_, _ = fmt.Fprintf(quietLogger.stdout, "%s\n", pingStats.String())
}
}

type standardLogger struct {
config *Config
stdout io.Writer
pinger Pinger
}

func newStandardLogger(config *Config, stdout io.Writer, pinger Pinger) logger {
return &standardLogger{config: config, stdout: stdout, pinger: pinger}
}

func (standardLogger *standardLogger) onMeasure(measure *HTTPMeasure, id int) {

if measure.IsFailure {
_, _ = fmt.Fprintf(standardLogger.stdout, "%4d: Error: %s\n", id, measure.FailureCause)
return
}
_, _ = fmt.Fprintf(standardLogger.stdout, "%8d: %s, code=%d, size=%d bytes, time=%.1f ms\n", id, measure.RemoteAddr, measure.StatusCode, measure.Bytes, measure.TotalTime.ToFloat(time.Millisecond))

}

func (standardLogger *standardLogger) onClose(attempts int64, successes int64, lossRate float64, pingStats *stats.PingStats) {
_, _ = fmt.Fprintf(standardLogger.stdout, "\n")
_, _ = fmt.Fprintf(standardLogger.stdout, "--- %s ping statistics ---\n", standardLogger.pinger.URL())

_, _ = fmt.Fprintf(standardLogger.stdout, "%d requests sent, %d answers received, %.1f%% loss\n", attempts, successes, lossRate)

if successes > 0 {
_, _ = fmt.Fprintf(standardLogger.stdout, "%s\n", pingStats.String())
}
}

type verboseLogger struct {
config *Config
stdout io.Writer
measureSum *HTTPMeasure
pinger Pinger
}

func newVerboseLogger(config *Config, stdout io.Writer, pinger Pinger) logger {
return &verboseLogger{config: config, stdout: stdout, pinger: pinger,
measureSum: &HTTPMeasure{
DNSResolution: stats.MeasureNotValid,
TCPHandshake: stats.MeasureNotValid,
TLSDuration: stats.MeasureNotValid,
},
}
}

func (verboseLogger *verboseLogger) onMeasure(measure *HTTPMeasure, id int) {

if measure.IsFailure {
_, _ = fmt.Fprintf(verboseLogger.stdout, "%4d: Error: %s\n", id, measure.FailureCause)
return
}

_, _ = fmt.Fprintf(verboseLogger.stdout, "%8d: %s, code=%d, size=%d bytes, time=%.1f ms\n", id, measure.RemoteAddr, measure.StatusCode, measure.Bytes, measure.TotalTime.ToFloat(time.Millisecond))
_, _ = fmt.Fprintf(verboseLogger.stdout, " proto=%s, socket reused=%t, compressed=%t\n", measure.Proto, measure.SocketReused, measure.Compressed)
_, _ = fmt.Fprintf(verboseLogger.stdout, " network i/o: bytes read=%d, bytes written=%d\n", measure.InBytes, measure.OutBytes)

if measure.TLSEnabled {
_, _ = fmt.Fprintf(verboseLogger.stdout, " tls version=%s\n", measure.TLSVersion)
}

verboseLogger.measureSum.TotalTime += measure.TotalTime

verboseLogger.measureSum.ConnEstablishment = verboseLogger.measureSum.ConnEstablishment.SumIfValid(measure.ConnEstablishment)
verboseLogger.measureSum.DNSResolution = verboseLogger.measureSum.DNSResolution.SumIfValid(measure.DNSResolution)
verboseLogger.measureSum.TCPHandshake = verboseLogger.measureSum.TCPHandshake.SumIfValid(measure.TCPHandshake)
verboseLogger.measureSum.TLSDuration = verboseLogger.measureSum.TLSDuration.SumIfValid(measure.TLSDuration)
verboseLogger.measureSum.RequestSending += measure.RequestSending
verboseLogger.measureSum.Wait += measure.Wait
verboseLogger.measureSum.ResponseIngesting += measure.ResponseIngesting

_, _ = fmt.Fprintf(verboseLogger.stdout, "\n")

_, _ = fmt.Fprintf(verboseLogger.stdout, " latency contributions:\n")

verboseLogger.drawMeasure(measure, verboseLogger.stdout)

_, _ = fmt.Fprintf(verboseLogger.stdout, "\n")
}

func (verboseLogger *verboseLogger) onClose(attempts int64, successes int64, lossRate float64, pingStats *stats.PingStats) {
_, _ = fmt.Fprintf(verboseLogger.stdout, "\n")
_, _ = fmt.Fprintf(verboseLogger.stdout, "--- %s ping statistics ---\n", verboseLogger.pinger.URL())

_, _ = fmt.Fprintf(verboseLogger.stdout, "%d requests sent, %d answers received, %.1f%% loss\n", attempts, successes, lossRate)

if successes > 0 {
_, _ = fmt.Fprintf(verboseLogger.stdout, "%s\n", pingStats.String())

verboseLogger.measureSum.TotalTime = verboseLogger.measureSum.TotalTime.Divide(successes)
verboseLogger.measureSum.ConnEstablishment = verboseLogger.measureSum.ConnEstablishment.Divide(successes)
verboseLogger.measureSum.DNSResolution = verboseLogger.measureSum.DNSResolution.Divide(successes)
verboseLogger.measureSum.TCPHandshake = verboseLogger.measureSum.TCPHandshake.Divide(successes)
verboseLogger.measureSum.TLSDuration = verboseLogger.measureSum.TLSDuration.Divide(successes)
verboseLogger.measureSum.RequestSending = verboseLogger.measureSum.RequestSending.Divide(successes)
verboseLogger.measureSum.Wait = verboseLogger.measureSum.Wait.Divide(successes)
verboseLogger.measureSum.ResponseIngesting = verboseLogger.measureSum.ResponseIngesting.Divide(successes)

verboseLogger.measureSum.TLSEnabled = verboseLogger.measureSum.TLSDuration > 0

_, _ = fmt.Fprintf(verboseLogger.stdout, "\naverage latency contributions:\n")

verboseLogger.drawMeasure(verboseLogger.measureSum, verboseLogger.stdout)
}
}

func (verboseLogger *verboseLogger) drawMeasure(measure *HTTPMeasure, stdout io.Writer) {
entries := measureEntry{
label: "request and response",
duration: measure.TotalTime,
children: []*measureEntry{
{label: "connection setup", duration: measure.ConnEstablishment,
children: []*measureEntry{
{label: "DNS resolution", duration: measure.DNSResolution},
{label: "TCP handshake", duration: measure.TCPHandshake},
{label: "TLS handshake", duration: measure.TLSDuration},
}},
{label: "request sending", duration: measure.RequestSending},
{label: "wait", duration: measure.Wait},
{label: "response ingestion", duration: measure.ResponseIngesting},
},
}
if !measure.TLSEnabled {
entries.children[0].children = entries.children[0].children[0:2]
}

l := verboseLogger.makeTreeList(&entries)

for i, e := range l {
pipes := make([]string, e.depth)
for j := 0; j < e.depth; j++ {
if i+1 >= len(l) || l[i+1].depth-1 < j {
pipes[j] = " └─"
} else if j == e.depth-1 {
pipes[j] = " ├─"
} else {
pipes[j] = " │ "
}

}
_, _ = fmt.Fprintf(stdout, " ")
for i := 0; i < e.depth; i++ {
_, _ = fmt.Fprintf(stdout, " %s ", pipes[i])
}

_, _ = fmt.Fprintf(stdout, "%6.1f ms %s\n", e.measureEntry.duration.ToFloat(time.Millisecond), e.measureEntry.label)
func countToString(b int64) string {
const unit = 1000
if b < unit {
return fmt.Sprintf("%d B", b)
}
}

type measureEntry struct {
label string
duration stats.Measure
children []*measureEntry
}

type measureEntryVisit struct {
measureEntry *measureEntry
depth int
}

func (verboseLogger *verboseLogger) makeTreeList(root *measureEntry) []measureEntryVisit {
var list []measureEntryVisit

var visit func(entry *measureEntry, depth int)

visit = func(entry *measureEntry, depth int) {
if entry.duration.IsValid() {
list = append(list, measureEntryVisit{entry, depth})
}

for _, e := range entry.children {
visit(e, depth+1)
}

div, exp := int64(unit), 0
for n := b / unit; n >= unit; n /= unit {
div *= unit
exp++
}

visit(root, 0)

return list
return fmt.Sprintf("%.1f %cB",
float64(b)/float64(div), "kMGTPE"[exp])
}
Loading

0 comments on commit 86aff00

Please sign in to comment.