diff --git a/src/utils/metrics/reporter.go b/src/utils/metrics/reporter.go index dadd5232..f26a684a 100644 --- a/src/utils/metrics/reporter.go +++ b/src/utils/metrics/reporter.go @@ -21,6 +21,7 @@ type Reporter interface { type ZapReporter struct { logger *zap.Logger groupTargets bool + tracker statsTracker } // NewZapReporter creates a new Reporter using a zap logger. @@ -29,9 +30,10 @@ func NewZapReporter(logger *zap.Logger, groupTargets bool) Reporter { } func (r *ZapReporter) WriteSummary(metrics *Metrics) { - stats, totals := metrics.SumAllStats(r.groupTargets) + stats, totals, statsInterval, totalsInterval := r.tracker.sumStats(metrics, r.groupTargets) - r.logger.Info("stats", zap.Object("total", &totals), zap.Object("targets", stats)) + r.logger.Info("stats", zap.Object("total", &totals), zap.Object("targets", stats), + zap.Object("total_since_last_report", &totalsInterval), zap.Object("targets_since_last_report", statsInterval)) } // ConsoleReporter @@ -39,6 +41,7 @@ func (r *ZapReporter) WriteSummary(metrics *Metrics) { type ConsoleReporter struct { target *bufio.Writer groupTargets bool + tracker statsTracker } // NewConsoleReporter creates a new Reporter which outputs straight to the console @@ -56,33 +59,47 @@ func (r *ConsoleReporter) WriteSummary(metrics *Metrics) { } func (r *ConsoleReporter) writeSummaryTo(metrics *Metrics, writer *tabwriter.Writer) { - stats, totals := metrics.SumAllStats(r.groupTargets) + stats, totals, statsInterval, totalsInterval := r.tracker.sumStats(metrics, r.groupTargets) defer writer.Flush() // Print table's header fmt.Fprintln(writer, "\n --- Traffic stats ---") - fmt.Fprintf(writer, "|\tTarget\t|\tRequests attempted\t|\tRequests sent\t|\tResponses received\t|\tData sent \t|\tData received \t|\n") + fmt.Fprintf(writer, "|\tTarget\t|\tRequests attempted\t|\tRequests sent\t|\tResponses received\t|\tData sent\t|\tData received \t|\n") // Print all table rows for _, tgt := range stats.sortedTargets() { - printStatsRow(writer, tgt, stats[tgt]) + printStatsRow(writer, tgt, stats[tgt], statsInterval[tgt]) } // Print table's footer - fmt.Fprintln(writer, "|\t---\t|\t---\t|\t---\t|\t---\t|\t--- \t|\t--- \t|") - printStatsRow(writer, "Total", totals) + fmt.Fprintln(writer, "|\t---\t|\t---\t|\t---\t|\t---\t|\t---\t|\t--- \t|") + printStatsRow(writer, "Total", totals, totalsInterval) fmt.Fprintln(writer) } -func printStatsRow(writer *tabwriter.Writer, rowName string, stats Stats) { +func printStatsRow(writer *tabwriter.Writer, rowName string, stats Stats, diff Stats) { const BytesInMegabyte = 1024 * 1024 - fmt.Fprintf(writer, "|\t%s\t|\t%d\t|\t%d\t|\t%d\t|\t%.2f MB \t|\t%.2f MB \t|\n", rowName, - stats[RequestsAttemptedStat], - stats[RequestsSentStat], - stats[ResponsesReceivedStat], - float64(stats[BytesSentStat])/BytesInMegabyte, - float64(stats[BytesReceivedStat])/BytesInMegabyte, + fmt.Fprintf(writer, "|\t%s\t|\t%d/%d\t|\t%d/%d\t|\t%d/%d\t|\t%.2f MB/%.2f MB\t|\t%.2f MB/%.2f MB \t|\n", rowName, + diff[RequestsAttemptedStat], stats[RequestsAttemptedStat], + diff[RequestsSentStat], stats[RequestsSentStat], + diff[ResponsesReceivedStat], stats[ResponsesReceivedStat], + float64(diff[BytesSentStat])/BytesInMegabyte, float64(stats[BytesSentStat])/BytesInMegabyte, + float64(diff[BytesReceivedStat])/BytesInMegabyte, float64(stats[BytesReceivedStat])/BytesInMegabyte, ) } + +// statsTracker generalizes tracking stats changes between reports +type statsTracker struct { + lastStats PerTargetStats + lastTotals Stats +} + +func (st *statsTracker) sumStats(metrics *Metrics, groupTargets bool) (stats PerTargetStats, totals Stats, statsInterval PerTargetStats, totalsInterval Stats) { + stats, totals = metrics.SumAllStats(groupTargets) + statsInterval, totalsInterval = stats.Diff(st.lastStats), Diff(totals, st.lastTotals) + st.lastStats, st.lastTotals = stats, totals + + return +} diff --git a/src/utils/metrics/stats.go b/src/utils/metrics/stats.go index 287c2b4d..080819df 100644 --- a/src/utils/metrics/stats.go +++ b/src/utils/metrics/stats.go @@ -36,6 +36,28 @@ func (ts PerTargetStats) sortedTargets() []string { return res } +func Diff(lhs, rhs Stats) Stats { + var res Stats + for i := range res { + res[i] = lhs[i] - rhs[i] + } + + return res +} + +func (ts PerTargetStats) Diff(other PerTargetStats) PerTargetStats { + if other == nil { + return ts + } + + res := make(PerTargetStats) + for k := range ts { + res[k] = Diff(ts[k], other[k]) + } + + return res +} + // MarshalLogObject is required to log PerTargetStats objects to zap func (ts PerTargetStats) MarshalLogObject(enc zapcore.ObjectEncoder) error { for _, tgt := range ts.sortedTargets() {