diff --git a/bandwidth.go b/bandwidth.go index a3b9e3c..45505ee 100644 --- a/bandwidth.go +++ b/bandwidth.go @@ -112,6 +112,11 @@ func (b *BPS) Rate() float64 { return float64(total) / b.interval.Seconds() } +// HumanRate returns a human-friendly (e.g. 23.3MB/s) rate. +func (b *BPS) HumanRate() string { + return Bytes(uint64(b.Rate())) + "/s" +} + // Close cleans up and shuts down a BPS. func (b *BPS) Close() { close(b.quit) diff --git a/bandwidth_test.go b/bandwidth_test.go index 0ba189b..836b89f 100644 --- a/bandwidth_test.go +++ b/bandwidth_test.go @@ -76,3 +76,17 @@ func TestAdd(t *testing.T) { } bw.Close() } + +func TestHumanBytes(t *testing.T) { + t.Parallel() + bw, err := New(100*time.Second, 10) + if err != nil { + t.Fatalf("failure to make reasonable BPS: %v", err) + } + bw.Add(1000) + got := bw.HumanRate() + want := "10B/s" + if got != want { + t.Fatalf("did not get right human rate; got %v, want %v", got, want) + } +} diff --git a/bytes.go b/bytes.go new file mode 100644 index 0000000..162fafa --- /dev/null +++ b/bytes.go @@ -0,0 +1,56 @@ +// from https://github.com/dustin/go-humanize/ +// +// Copyright (c) 2005-2008 Dustin Sallings +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// +package bps + +import ( + "fmt" + "math" +) + +func logn(n, b float64) float64 { + return math.Log(n) / math.Log(b) +} + +func humanateBytes(s uint64, base float64, sizes []string) string { + if s < 10 { + return fmt.Sprintf("%dB", s) + } + e := math.Floor(logn(float64(s), base)) + suffix := sizes[int(e)] + val := math.Floor(float64(s)/math.Pow(base, e)*10+0.5) / 10 + f := "%.0f%s" + if val < 10 { + f = "%.1f%s" + } + + return fmt.Sprintf(f, val, suffix) +} + +// Bytes produces a human readable representation of an SI size. +// +// Bytes(82854982) -> 83MB +func Bytes(s uint64) string { + sizes := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB"} + return humanateBytes(s, 1000, sizes) +}