From da0d025304371930b83705df6179163e02f09fec Mon Sep 17 00:00:00 2001 From: zry98 Date: Sat, 30 Dec 2023 01:23:08 +0100 Subject: [PATCH] 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 --- cmd/tailscale/cli/status.go | 26 +++++++++++++------------- cmd/tailscale/cli/status_test.go | 29 ++++++++++++++++------------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/cmd/tailscale/cli/status.go b/cmd/tailscale/cli/status.go index ebc313f68..a6ba6d29c 100644 --- a/cmd/tailscale/cli/status.go +++ b/cmd/tailscale/cli/status.go @@ -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) diff --git a/cmd/tailscale/cli/status_test.go b/cmd/tailscale/cli/status_test.go index 4526419c3..39caca72d 100644 --- a/cmd/tailscale/cli/status_test.go +++ b/cmd/tailscale/cli/status_test.go @@ -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) } })