Refactor command line usage functions (#87)

* Created an internal package as an initial framework for refactoring
* Refactored command line usage functions into the new internal package
This commit is contained in:
Boyan Soubachov 2019-07-18 20:30:13 +02:00 committed by Pankaj Garg
parent 90c8f2467c
commit 1c9b13b30e
3 changed files with 207 additions and 196 deletions

210
ethr.go
View file

@ -8,193 +8,17 @@ package main
import (
"flag"
"fmt"
"os"
"runtime"
"strings"
"time"
"github.com/microsoft/ethr/internal/cmd"
)
const defaultLogFileName = "./ethrs.log for server, ./ethrc.log for client"
var gVersion string
func printFlagUsage(flag, info string, helptext ...string) {
fmt.Printf("\t-%s %s\n", flag, info)
for _, help := range helptext {
fmt.Printf("\t\t%s\n", help)
}
}
func printServerUsage() {
printFlagUsage("s", "", "Run in server mode.")
}
func printClientUsage() {
printFlagUsage("c", "<server>", "Run in client mode and connect to <server>.",
"Server is specified using name, FQDN or IP address.")
}
func printExtClientUsage() {
printFlagUsage("c", "<destination>", "Run in external client mode and connect to <destination>.",
"<destination> is specified using host:port format.",
"Example: www.microsoft.com:443 or 10.1.0.4:22 etc.")
}
func printPortUsage() {
printFlagUsage("ports", "<k=v,...>", "Use custom port numbers instead of default ones.",
"A comma separated list of key=value pair is used.",
"Key specifies the protocol, and value specifies base port.",
"Ports used for various tests are calculated from base port.",
"Example: For TCP, Bw: 9999, CPS: 9998, PPS: 9997, Latency: 9996",
"Control is used for control channel communication for ethr.",
"Note: Same configuration must be used on both client & server.",
"Default: 'control=8888,tcp=9999,udp=9999,http=9899,https=9799'")
}
func printExtPortUsage() {
printFlagUsage("ports", "<k=v,...>", "Use custom port numbers instead of default ones.",
"A comma separated list of key=value pair is used.",
"Key specifies the protocol, and value specifies the port.",
"Default: 'tcp=9999,http=9899,https=9799'")
}
func printTestType() {
printFlagUsage("t", "<test>", "Test to run (\"b\", \"c\", \"p\", or \"l\")",
"b: Bandwidth",
"c: Connections/s or Requests/s",
"p: Packets/s",
"l: Latency, Loss & Jitter",
"Default: b - Bandwidth measurement.")
}
func printExtTestType() {
printFlagUsage("t", "<test>", "Test to run (\"b\", \"c\", or \"cl\")",
"b: Bandwidth",
"c: Connections/s or Requests/s",
"cl: TCP connection setup latency",
"Default: cl - TCP connection setup latency.")
}
func printThreadUsage() {
printFlagUsage("n", "<number>", "Number of Parallel Sessions (and Threads).",
"0: Equal to number of CPUs",
"Default: 1")
}
func printDurationUsage() {
printFlagUsage("d", "<duration>",
"Duration for the test (format: <num>[ms | s | m | h]",
"0: Run forever",
"Default: 10s")
}
func printGapUsage() {
printFlagUsage("g", "<gap>",
"Time interval between successive measurements (format: <num>[ms | s | m | h]",
"0: No gap",
"Default: 1s")
}
func printBufLenUsage() {
printFlagUsage("l", "<length>",
"Length of buffer to use (format: <num>[KB | MB | GB])",
"Only valid for Bandwidth tests. Max 1GB.",
"Default: 16KB")
}
func printProtocolUsage() {
printFlagUsage("p", "<protocol>",
"Protocol (\"tcp\", \"udp\", \"http\", \"https\", or \"icmp\")",
"Default: tcp")
}
func printExtProtocolUsage() {
printFlagUsage("p", "<protocol>",
"Protocol (\"tcp\", \"http\", \"https\", or \"icmp\")",
"Default: tcp")
}
func printIterationUsage() {
printFlagUsage("i", "<iterations>",
"Number of round trip iterations for each latency measurement.",
"Default: 1000")
}
func printModeUsage() {
printFlagUsage("m", "<mode>",
"'-m x' MUST be specified for external mode.")
}
func printNoConnStatUsage() {
printFlagUsage("ncs", "",
"No per Connection Stats would be printed if this flag is specified.",
"This is useful to suppress verbose logging when large number of",
"connections are used as specified by -n option for Bandwidth tests.")
}
func printIgnoreCertUsage() {
printFlagUsage("ic", "",
"Ignore Certificate is useful for HTTPS tests, for cases where a",
"middle box like a proxy is not able to supply a valid Ethr cert.")
}
func ethrUsage() {
fmt.Println("\nEthr - A comprehensive network performance measurement tool.")
fmt.Println("Version: " + gVersion)
fmt.Println("It supports 4 modes. Usage of each mode is described below:")
fmt.Println("\nCommon Parameters")
fmt.Println("================================================================================")
printFlagUsage("h", "", "Help")
printFlagUsage("no", "", "Disable logging to file. Logging to file is enabled by default.")
printFlagUsage("o", "<filename>", "Name of log file. By default, following file names are used:",
"Server mode: 'ethrs.log'",
"Client mode: 'ethrc.log'",
"External server mode: 'ethrxs.log'",
"External client mode: 'ethrxc.log'")
printFlagUsage("debug", "", "Enable debug information in logging output.")
printFlagUsage("4", "", "Use only IP v4 version")
printFlagUsage("6", "", "Use only IP v6 version")
fmt.Println("\nMode: Server")
fmt.Println("================================================================================")
printServerUsage()
printFlagUsage("ui", "", "Show output in text UI.")
printPortUsage()
fmt.Println("\nMode: Client")
fmt.Println("================================================================================")
printClientUsage()
printFlagUsage("r", "", "For Bandwidth tests, send data from server to client.")
printDurationUsage()
printThreadUsage()
printNoConnStatUsage()
printBufLenUsage()
printProtocolUsage()
printIgnoreCertUsage()
printPortUsage()
printTestType()
printIterationUsage()
fmt.Println("\nMode: External Server")
fmt.Println("================================================================================")
printModeUsage()
printServerUsage()
printExtPortUsage()
fmt.Println("\nMode: External Client")
fmt.Println("================================================================================")
printModeUsage()
printExtClientUsage()
printDurationUsage()
printThreadUsage()
printNoConnStatUsage()
printBufLenUsage()
printExtProtocolUsage()
printExtTestType()
printGapUsage()
}
func main() {
//
// If version is not set via ldflags, then default to UNKNOWN
@ -211,7 +35,7 @@ func main() {
//
runtime.GOMAXPROCS(1024)
flag.Usage = ethrUsage
flag.Usage = func() { cmd.EthrUsage(gVersion) }
isServer := flag.Bool("s", false, "")
clientDest := flag.String("c", "", "")
testTypePtr := flag.String("t", "", "")
@ -257,13 +81,13 @@ func main() {
case "x":
xMode = true
default:
printUsageError("Invalid value for execution mode (-m).")
cmd.PrintUsageError("Invalid value for execution mode (-m).")
}
mode := ethrModeInv
if *isServer {
if *clientDest != "" {
printUsageError("Invalid arguments, \"-c\" cannot be used with \"-s\".")
cmd.PrintUsageError("Invalid arguments, \"-c\" cannot be used with \"-s\".")
}
if xMode {
mode = ethrModeExtServer
@ -277,11 +101,11 @@ func main() {
mode = ethrModeClient
}
} else {
printUsageError("Invalid arguments, use either \"-s\" or \"-c\".")
cmd.PrintUsageError("Invalid arguments, use either \"-s\" or \"-c\".")
}
if *reverse && mode != ethrModeClient {
printUsageError("Invalid arguments, \"-r\" can only be used in client mode.")
cmd.PrintUsageError("Invalid arguments, \"-r\" can only be used in client mode.")
}
if *use4 && !*use6 {
@ -292,11 +116,11 @@ func main() {
bufLen := unitToNumber(*bufLenStr)
if bufLen == 0 {
printUsageError(fmt.Sprintf("Invalid length specified: %s" + *bufLenStr))
cmd.PrintUsageError(fmt.Sprintf("Invalid length specified: %s" + *bufLenStr))
}
if *rttCount <= 0 {
printUsageError(fmt.Sprintf("Invalid RTT count for latency test: %d", *rttCount))
cmd.PrintUsageError(fmt.Sprintf("Invalid RTT count for latency test: %d", *rttCount))
}
var testType EthrTestType
@ -323,7 +147,7 @@ func main() {
case "cl":
testType = ConnLatency
default:
printUsageError(fmt.Sprintf("Invalid value \"%s\" specified for parameter \"-t\".\n"+
cmd.PrintUsageError(fmt.Sprintf("Invalid value \"%s\" specified for parameter \"-t\".\n"+
"Valid parameters and values are:\n", *testTypePtr))
}
@ -341,7 +165,7 @@ func main() {
case "ICMP":
proto = ICMP
default:
printUsageError(fmt.Sprintf("Invalid value \"%s\" specified for parameter \"-p\".\n"+
cmd.PrintUsageError(fmt.Sprintf("Invalid value \"%s\" specified for parameter \"-p\".\n"+
"Valid parameters and values are:\n", *protocol))
}
@ -400,12 +224,12 @@ func main() {
}
func emitUnsupportedTest(testParam EthrTestParam) {
printUsageError(fmt.Sprintf("\"%s\" test for \"%s\" is not supported.\n",
cmd.PrintUsageError(fmt.Sprintf("\"%s\" test for \"%s\" is not supported.\n",
testToString(testParam.TestID.Type), protoToString(testParam.TestID.Protocol)))
}
func printReverseModeError() {
printUsageError("Reverse mode (-r) is only supported for TCP Bandwidth tests.")
cmd.PrintUsageError("Reverse mode (-r) is only supported for TCP Bandwidth tests.")
}
func validateTestParam(mode ethrMode, testParam EthrTestParam) {
@ -430,7 +254,7 @@ func validateTestParam(mode ethrMode, testParam EthrTestParam) {
}
if testType == Bandwidth {
if testParam.BufferSize > (64 * 1024) {
printUsageError("Maximum supported buffer size for UDP is 64K\n")
cmd.PrintUsageError("Maximum supported buffer size for UDP is 64K\n")
}
}
if testParam.Reverse {
@ -459,9 +283,3 @@ func validateTestParam(mode ethrMode, testParam EthrTestParam) {
}
}
}
func printUsageError(s string) {
fmt.Printf("Error: %s\n", s)
fmt.Printf("Please use \"ethr -h\" for ethr command line arguments.\n")
os.Exit(1)
}

61
internal/cmd/cmd.go Normal file
View file

@ -0,0 +1,61 @@
package cmd
import "fmt"
// EthrUsage prints the command-line usage text
func EthrUsage(gVersion string) {
fmt.Println("\nEthr - A comprehensive network performance measurement tool.")
fmt.Println("Version: " + gVersion)
fmt.Println("It supports 4 modes. Usage of each mode is described below:")
fmt.Println("\nCommon Parameters")
fmt.Println("================================================================================")
PrintFlagUsage("h", "", "Help")
PrintFlagUsage("no", "", "Disable logging to file. Logging to file is enabled by default.")
PrintFlagUsage("o", "<filename>", "Name of log file. By default, following file names are used:",
"Server mode: 'ethrs.log'",
"Client mode: 'ethrc.log'",
"External server mode: 'ethrxs.log'",
"External client mode: 'ethrxc.log'")
PrintFlagUsage("debug", "", "Enable debug information in logging output.")
PrintFlagUsage("4", "", "Use only IP v4 version")
PrintFlagUsage("6", "", "Use only IP v6 version")
fmt.Println("\nMode: Server")
fmt.Println("================================================================================")
PrintServerUsage()
PrintFlagUsage("ui", "", "Show output in text UI.")
PrintPortUsage()
fmt.Println("\nMode: Client")
fmt.Println("================================================================================")
PrintClientUsage()
PrintFlagUsage("r", "", "For Bandwidth tests, send data from server to client.")
PrintDurationUsage()
PrintThreadUsage()
PrintNoConnStatUsage()
PrintBufLenUsage()
PrintProtocolUsage()
PrintIgnoreCertUsage()
PrintPortUsage()
PrintTestType()
PrintIterationUsage()
fmt.Println("\nMode: External Server")
fmt.Println("================================================================================")
PrintModeUsage()
PrintServerUsage()
PrintExtPortUsage()
fmt.Println("\nMode: External Client")
fmt.Println("================================================================================")
PrintModeUsage()
PrintExtClientUsage()
PrintDurationUsage()
PrintThreadUsage()
PrintNoConnStatUsage()
PrintBufLenUsage()
PrintExtProtocolUsage()
PrintExtTestType()
PrintGapUsage()
}

View file

@ -0,0 +1,132 @@
package cmd
import (
"fmt"
"os"
)
func PrintFlagUsage(flag, info string, helptext ...string) {
fmt.Printf("\t-%s %s\n", flag, info)
for _, help := range helptext {
fmt.Printf("\t\t%s\n", help)
}
}
func PrintServerUsage() {
PrintFlagUsage("s", "", "Run in server mode.")
}
func PrintClientUsage() {
PrintFlagUsage("c", "<server>", "Run in client mode and connect to <server>.",
"Server is specified using name, FQDN or IP address.")
}
func PrintExtClientUsage() {
PrintFlagUsage("c", "<destination>", "Run in external client mode and connect to <destination>.",
"<destination> is specified using host:port format.",
"Example: www.microsoft.com:443 or 10.1.0.4:22 etc.")
}
func PrintPortUsage() {
PrintFlagUsage("ports", "<k=v,...>", "Use custom port numbers instead of default ones.",
"A comma separated list of key=value pair is used.",
"Key specifies the protocol, and value specifies base port.",
"Ports used for various tests are calculated from base port.",
"Example: For TCP, Bw: 9999, CPS: 9998, PPS: 9997, Latency: 9996",
"Control is used for control channel communication for ethr.",
"Note: Same configuration must be used on both client & server.",
"Default: 'control=8888,tcp=9999,udp=9999,http=9899,https=9799'")
}
func PrintExtPortUsage() {
PrintFlagUsage("ports", "<k=v,...>", "Use custom port numbers instead of default ones.",
"A comma separated list of key=value pair is used.",
"Key specifies the protocol, and value specifies the port.",
"Default: 'tcp=9999,http=9899,https=9799'")
}
func PrintTestType() {
PrintFlagUsage("t", "<test>", "Test to run (\"b\", \"c\", \"p\", or \"l\")",
"b: Bandwidth",
"c: Connections/s or Requests/s",
"p: Packets/s",
"l: Latency, Loss & Jitter",
"Default: b - Bandwidth measurement.")
}
func PrintExtTestType() {
PrintFlagUsage("t", "<test>", "Test to run (\"b\", \"c\", or \"cl\")",
"b: Bandwidth",
"c: Connections/s or Requests/s",
"cl: TCP connection setup latency",
"Default: cl - TCP connection setup latency.")
}
func PrintThreadUsage() {
PrintFlagUsage("n", "<number>", "Number of Parallel Sessions (and Threads).",
"0: Equal to number of CPUs",
"Default: 1")
}
func PrintDurationUsage() {
PrintFlagUsage("d", "<duration>",
"Duration for the test (format: <num>[ms | s | m | h]",
"0: Run forever",
"Default: 10s")
}
func PrintGapUsage() {
PrintFlagUsage("g", "<gap>",
"Time interval between successive measurements (format: <num>[ms | s | m | h]",
"0: No gap",
"Default: 1s")
}
func PrintBufLenUsage() {
PrintFlagUsage("l", "<length>",
"Length of buffer to use (format: <num>[KB | MB | GB])",
"Only valid for Bandwidth tests. Max 1GB.",
"Default: 16KB")
}
func PrintProtocolUsage() {
PrintFlagUsage("p", "<protocol>",
"Protocol (\"tcp\", \"udp\", \"http\", \"https\", or \"icmp\")",
"Default: tcp")
}
func PrintExtProtocolUsage() {
PrintFlagUsage("p", "<protocol>",
"Protocol (\"tcp\", \"http\", \"https\", or \"icmp\")",
"Default: tcp")
}
func PrintIterationUsage() {
PrintFlagUsage("i", "<iterations>",
"Number of round trip iterations for each latency measurement.",
"Default: 1000")
}
func PrintModeUsage() {
PrintFlagUsage("m", "<mode>",
"'-m x' MUST be specified for external mode.")
}
func PrintNoConnStatUsage() {
PrintFlagUsage("ncs", "",
"No per Connection Stats would be printed if this flag is specified.",
"This is useful to suppress verbose logging when large number of",
"connections are used as specified by -n option for Bandwidth tests.")
}
func PrintIgnoreCertUsage() {
PrintFlagUsage("ic", "",
"Ignore Certificate is useful for HTTPS tests, for cases where a",
"middle box like a proxy is not able to supply a valid Ethr cert.")
}
func PrintUsageError(s string) {
fmt.Printf("Error: %s\n", s)
fmt.Printf("Please use \"ethr -h\" for ethr command line arguments.\n")
os.Exit(1)
}