cmd/tailscale/cli: support human-readable traffic bytes in status

1. Revert the separator between peer connection info and traffic info to `; `, to avoid breaking someone's script for extracting the bytes not using JSON mode.
2. Prefer SI over IEC, since it seems more commonly used in the context of networking.

Updates: #10671

Signed-off-by: zry98 <dev@zry.io>
pull/10671/head
zry98 5 months ago
parent 48697f86d7
commit da0d025304
No known key found for this signature in database
GPG Key ID: D239A8A2222B2691

@ -56,8 +56,8 @@ https://github.com/tailscale/tailscale/blob/main/ipn/ipnstate/ipnstate.go
fs.BoolVar(&statusArgs.peers, "peers", true, "show status of peers")
fs.StringVar(&statusArgs.listen, "listen", "127.0.0.1:8384", "listen address for web mode; use port 0 for automatic")
fs.BoolVar(&statusArgs.browser, "browser", true, "open a browser in web mode")
fs.BoolVar(&statusArgs.humanReadableIEC, "human", false, "print human-readable bytes in IEC format (in powers of 1024)")
fs.BoolVar(&statusArgs.humanReadableSI, "human-si", false, "print human-readable bytes in SI format (in powers of 1000)")
fs.BoolVar(&statusArgs.humanReadableSI, "human", false, "print human-readable bytes in SI format (in powers of 1000)")
fs.BoolVar(&statusArgs.humanReadableIEC, "human-iec", false, "print human-readable bytes in IEC format (in powers of 1024)")
return fs
})(),
}
@ -70,8 +70,8 @@ var statusArgs struct {
active bool // in CLI mode, filter output to only peers with active sessions
self bool // in CLI mode, show status of local machine
peers bool // in CLI mode, show status of peer machines
humanReadableIEC bool // in CLI mode, print human-readable peer traffic bytes in IEC format
humanReadableSI bool // in CLI mode, print human-readable peer traffic bytes in SI format
humanReadableIEC bool // in CLI mode, print human-readable peer traffic bytes in IEC format
}
func runStatus(ctx context.Context, args []string) error {
@ -197,12 +197,12 @@ func runStatus(ctx context.Context, args []string) error {
}
}
if anyTraffic {
if statusArgs.humanReadableIEC {
f("; tx %s rx %s", humanReadableBytes(ps.TxBytes, false), humanReadableBytes(ps.RxBytes, false))
} else if statusArgs.humanReadableSI {
f("; tx %s rx %s", humanReadableBytes(ps.TxBytes, true), humanReadableBytes(ps.RxBytes, true))
if statusArgs.humanReadableSI {
f(", tx %s rx %s", humanReadableBytes(ps.TxBytes, true), humanReadableBytes(ps.RxBytes, false))
} else if statusArgs.humanReadableIEC {
f(", tx %s rx %s", humanReadableBytes(ps.TxBytes, false), humanReadableBytes(ps.RxBytes, true))
} else {
f("; tx %d rx %d", ps.TxBytes, ps.RxBytes)
f(", tx %d rx %d", ps.TxBytes, ps.RxBytes)
}
}
f("\n")
@ -348,15 +348,15 @@ func firstIPString(v []netip.Addr) string {
}
// humanReadableBytes returns a human-readable string for the given number of bytes.
func humanReadableBytes(b int64, useSI bool) string {
func humanReadableBytes(b int64, useIEC bool) string {
var base float64
var units []string
if useSI {
base = 1000
units = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB"}
} else {
if useIEC {
base = 1024
units = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}
} else {
base = 1000
units = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB"}
}
if b < int64(base) {
return fmt.Sprintf("%d B", b)

@ -1,31 +1,34 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package cli
import "testing"
func TestHumanReadableBytes(t *testing.T) {
type args struct {
b int64
useSI bool
b int64
useIEC bool
}
tests := []struct {
name string
args args
want string
}{
{"IEC_0", args{0, false}, "0 B"},
{"IEC_42", args{42, false}, "42 B"},
{"IEC_1K", args{1024, false}, "1.0 KiB"},
{"IEC_1G", args{1073741824, false}, "1.0 GiB"},
{"IEC_1E", args{1152921504606846976, false}, "1.0 EiB"},
{"SI_0", args{0, true}, "0 B"},
{"SI_42", args{42, true}, "42 B"},
{"SI_1K", args{1000, true}, "1.0 kB"},
{"SI_1G", args{1000000000, true}, "1.0 GB"},
{"SI_1E", args{1000000000000000000, true}, "1.0 EB"},
{"SI_0", args{0, false}, "0 B"},
{"SI_42", args{42, false}, "42 B"},
{"SI_1K", args{1000, false}, "1.0 kB"},
{"SI_1G", args{1000000000, false}, "1.0 GB"},
{"SI_1E", args{1000000000000000000, false}, "1.0 EB"},
{"IEC_0", args{0, true}, "0 B"},
{"IEC_42", args{42, true}, "42 B"},
{"IEC_1K", args{1024, true}, "1.0 KiB"},
{"IEC_1G", args{1073741824, true}, "1.0 GiB"},
{"IEC_1E", args{1152921504606846976, true}, "1.0 EiB"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := humanReadableBytes(tt.args.b, tt.args.useSI); got != tt.want {
if got := humanReadableBytes(tt.args.b, tt.args.useIEC); got != tt.want {
t.Errorf("humanReadableBytes() = %v, want %v", got, tt.want)
}
})

Loading…
Cancel
Save