Flags in Go
Introduction
In the realm of Go applications, the flag package reigns supreme when it comes to wielding command-line arguments. It empowers you to gracefully accept user-specified instructions, tailoring your program’s behavior on the fly.
Key Functionalities:
- Defining Flags: Craft flags using functions like String, Int, Bool, Var and more. Each flag carries a name (short and long versions), a default value, and a usage description.
var name string
var verbose bool
func init() {
flag.StringVar(&name, "name", "", "Your name (default: empty)")
flag.BoolVar(&verbose, "verbose", false, "Enable verbose output")
}
- Parsing Arguments: When your program launches, unleash the flag.Parse() function. It meticulously dissects the command-line arguments, matching them to the meticulously defined flags and assigning the extracted values to their designated variables.
flag.Parse()
- Accessing Values: Once parsing is complete, the flag variables hold the user-provided values, ready to be employed within your program’s logic.
fmt.Println("Hello,", name)
if verbose {
fmt.Println("Verbose mode enabled!")
}
Making Connections Flexible with Go’s flag Package: A Real-World Example
The flag package empowers you to create command-line programs with dynamic configurations through user-defined flags. We’ll delve into how this code leverages flags to control retry attempts and data for an HTTP request.
type ArrayValue []string
func (s *ArrayValue) String() string {
return fmt.Sprintf("%v", *s)
}
func (a *ArrayValue) Set(s string) error {
*a = strings.Split(s, ",")
return nil
}
func main() {
retry := flag.Int("retry", -1, "Defines the max retry count")
var logPrefix string
flag.StringVar(&logPrefix, "prefix", "", "Logging prefix")
var arr ArrayValue
flag.Var(&arr, "array", "Input array to iterate through. ")
flag.Parse() // required for assigning values
logger := log.New(os.Stdout, logPrefix, log.Ldate)
retryCount := 0
for retryCount < *retry {
logger.Println("*Retrying connection")
post()
logger.Printf("Sending array %v\n", arr)
retryCount++
}
}
func makePostRequest(data []byte) ([]byte, error) {
url := "http://localhost:8080" // Target URL
req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}
func post() {
data := []byte(`{"message": "Hello from Go!"}`)
responseBody, err := makePostRequest(data)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Response:", string(responseBody))
}
}
Running the Program with Flags
Let’s see how this code works in action. To retry this request twice we give an integer of 2 and prefix the logs we named “dre,” we can run:
go run main.go -retry 2 -prefix dre
This will output:
dre2024/03/02 *Retrying connection
Response: {"message": "Hello from Go!"}
dre2024/03/02 Sending array []
dre2024/03/02 *Retrying connection
Response: {"message": "Hello from Go!"}
dre2024/03/02 Sending array []
Let’s break down the code’s flow:
-
Flag Parsing: The program starts by parsing the command-line arguments using flag.Parse(). This allows users to control retry count, logging prefix, and the input array via flags.
-
Logging Setup: Based on the -prefix flag, a logger object is created using the log package. This ensures informative logs with user-defined prefixes.
-
Retry Loop: The program enters a loop that continues until the maximum retry count (retry) is reached. Inside the loop:
-
Making the Request: The post function constructs a POST request to a designated URL (http://localhost:8080). It utilizes a helper function, makePostRequest, which is responsible for building and executing the request.
This example explores a practical example of using the flag package in Go. The
flag
package empowers you to create command-line programs with dynamic configurations through user-defined flags. We’ll delve into how this code leverages flags to control retry attempts and data for an HTTP request.
Understanding the Code
The code defines a program that attempts to send data via a POST request. However, the magic lies in its configurability through flags.
The ArrayValue struct tackles a specific challenge: handling comma-separated lists of strings from the -array
flag. Standard flag functions don’t handle this natively.
The Set method parses the user’s input, splitting the comma-separated string into individual values stored within the ArrayValue slice. The String method provides a user-friendly way to represent the array content when needed (e.g., during logging).
The flag.Var
function accepts a value with the following interface, ArrayValue
implements this inteface
type Value interface {
String() string
Set(string) error
}
-
retry: This flag, defined with
flag.Int
, allows users to specify the maximum number of retry attempts before giving up. -
prefix: Defined with
flag.StringVar
, this flag lets users set a prefix for log messages, adding context to their output. -
array: This custom flag utilizes
flag.Var
and aArrayValue
struct to accept a comma-separated list of strings as input.
The flag.Parse()
function is crucial, as it interprets command-line arguments and assigns them to the corresponding flags.
Did I make a mistake? Please consider sending a pull request .