Table of Contents
Overview on golang flag package
Flags in software engineering are essentially variables that are used inside conditional statements so that statements in these conditions can be toggled on or off depending on the value of the flag. This allows developers to control the flow of their software and skip or bypass features that are not ready to be rolled out. A good example of using flags is switching between development and production databases e.g redis cache and PostgreSQL.
Flags can be used in the following scenarios.
- Hiding or disabling a feature
- Adding an new feature to an application
- Switching between features
About Golang flags
Go has a flag package that supports basic command line flag parsing. To get started with Go flags, you first need to import the flag package in your go program. Go defines flags for three major data types, namely string, integer and boolean. Before defining a flag it is important to consider what type of data you want to store in your flag. Go makes it easy to define the data type of your flags using methods in the flag package namely flag.String()
, flag.Int()
, flag.Bool()
, flag.StringVar()
, flag.IntVar()
and flag.BoolVar()
.
Note that these methods return a pointer to the caller and to access the values you will need to dereference them using (*) operator.
Different types of flag methods
These golang flag methods achieve the same results but differ in the way they are defined and used. These categories are:
- Using
flag.String()
,flag.Int()
andflag.Bool()
methods - Using
flag.StringVar()
,flag.IntVar()
andflag.BoolVar()
methods
Regardless of the method that you choose, after defining these flags, call the flag.Parse()
method to parse the command line into the defined flags. These flags can be used directly in the code. One thing to note though is that when you use flag.String()
, flag.Int()
and flag.Bool()
methods, they all return pointers while flag.StringVar()
, flag.IntVar()
and flag.BoolVar()
methods return values.
After parsing , the arguments following the flags are available as the slice flag.Args()
or flag.Arg(i)
for individual flags.
Using flag.String(), flag.Int() and flag.Bool() in golang
To get started, create a main.go
file in your working directory and write the below code. These methods take three arguments by default namely , flag name, flag default value and flag usage.
Example
package main
import (
"flag"
"log"
)
func main() {
// Defining a string flag
strFlag := flag.String("language", "Golang", "Golang is the awesome google language")
// Defining an integer flag
intFlag := flag.Int("downloads", 1000000, "Number of times Go has been downloaded")
// Defining a boolean flag
boolFlag := flag.Bool("isAwesome", true, "Yes! Go is awesome")
// Call flag.Parse() to parse the command-line flags
flag.Parse()
// Log the flags to the terminal
log.Println("String flag ", *strFlag)
log.Println("Integer flag ", *intFlag)
log.Println("Boolean flag ", *boolFlag)
}
To run this code, on your terminal enter this command go run main.go . The results will be the default value of each flag defined in the code. Please note that when using the golang flags themselves , they are all pointers and therefore they need to be dereferenced using the asterisk(*
) operator.
Output
2022/06/08 15:54:16 String flag Golang
2022/06/08 15:54:16 Integer flag 1000000
2022/06/08 15:54:16 Boolean flag true
Execute code with flags
When the above code is executed , the flags return default values assigned to them during variable definition. We can pass our custom values to the golang flags when executing the code like so go run main.go -language=Python -downloads=2000000 -isAwesome=true
Example
go run main.go -language=Python -downloads=2000000 -isAwesome=true
Output
2022/06/10 07:09:45 String flag Python
2022/06/10 07:09:45 Integer flag 2000000
2022/06/10 07:09:45 Boolean flag true
The preferred way to execute this code is by compiling the code and executing the resulting binaries.
Example
go build main.go
./main -language=Python -downloads=2000000 -isAwesome=true
Output
2022/06/10 07:09:45 String flag Python
2022/06/10 07:09:45 Integer flag 2000000
2022/06/10 07:09:45 Boolean flag true
Using flag.StringVar(), flag.IntVar() and flag.BoolVar() methods
These methods take four arguments namely flag variable, flag name, flag value and flag usage. The returned values from the flags are all pointers. Binding them to a variable will return values.
To successfully bind flags to their respective variables, use the var()
function. Start by initializing the variable and bind them to their flags later in the program
Example
package main
import (
"flag"
"log"
)
var (
strFlag string
intFlag int
boolFlag bool
)
func init() {
flag.StringVar(&strFlag, "language", "Golang", "Golang is the awesome google language")
flag.IntVar(&intFlag, "downloads", 1000000, "Number of times Go has been downloaded")
flag.BoolVar(&boolFlag, "isAwesome", true, "Yes! Go is awesome")
}
func main() {
// Call flag.Parse() to parse the command-line flags
flag.Parse()
// Log the flags to the terminal
log.Println("String flag ", strFlag)
log.Println("Integer flag ", intFlag)
log.Println("Boolean flag ", boolFlag)
}
To execute the code run the below command in the terminal.
go build main.go
./main -language=Python -downloads=2000000 -isAwesome=true
Output
2022/06/10 07:32:19 String flag Python
2022/06/10 07:32:19 Integer flag 2000000
2022/06/10 07:32:19 Boolean flag true
Command line flag syntax
To pass a flag in the terminal, the golang flags are prefixed with a single or a double dashes followed by the flag name. Flag parsing stops just before the first non-flag arguments(“-
” is a non-flag argument) or after the terminator “--
".
Integer flags accept 1234, 0664, 0x1234 and negative values. Boolean flags maybe 1, 0, t, f, T, F, true, false, TRUE, FALSE, True, False
Accessing golang flag usage
Sometimes it is important to understand what each flag does. During flag definition , its usage needs to be defined as well. To access flag usage across the enter ./main -h for built binary files or go run main.go -h for non built binary files.
Example
./main -h
Output
Usage of ./main:
-downloads int
Number of times Go has been downloaded (default 1000000)
-isAwesome
Yes! Go is awesome (default true)
-language string
Golang is the awesome google language (default "Golang")
In case you pass a flag that does not exist in the program, the standard flag will log messages on the console indicating the passed flag does not exist.
Example
./main -coding=true
Output
flag provided but not defined: -coding
Usage of ./main:
-downloads int
Number of times Go is downloaded in a month (default 1000000)
-goIsAwesome
Yes! go is awesome (default true)
-language string
My awesome programming language (default "Golang")
Example: Using golang flag in a simple web server
In this example , we are running a web server with redis db switched on and off the server will execute based on the flag value.
package main
import (
"flag"
"fmt"
"log"
"net/http"
)
var (
redis bool
)
func init() {
flag.BoolVar(&redis, "redis", false, "Add redis datatabase")
}
func main() {
// Call flag.Parse() to parse the command-line flags
flag.Parse()
// Create a simple route to access the server resources
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "redis")
})
// Set logs
log.SetFlags(log.LstdFlags | log.Lshortfile)
log.Println("[INFO]: Server running on 127.0.0.1:5000 ...")
// If redis is true, use redis db
if redis {
log.Println("[INFO]: Redis db running")
} else {
// If redis is false, warn the user about missing database
log.Println("[WARN] : No database running")
}
log.Fatal(http.ListenAndServe(":5000", nil))
}
Execute without a flag(Without redis database)
go build main.go ./main
Output
2022/06/10 08:27:46 main.go:26: [INFO]: Server running on 127.0.0.1:5000 ...
2022/06/10 08:27:46 main.go:32: [WARN] : No database running
Execute with a flag (With redis database)
./main --redis=true
Output
2022/06/10 08:59:29 main.go:26: [INFO]: Server runnig on 127.0.0.1:5000 ...
2022/06/10 08:59:29 main.go:29: [INFO]: Redis db running
Summary
Big and small tech companies use flags in their development cycles. One good practice working with flags is to have them in small numbers. Having many flags in your program adds more complexity hence causing tech debt for future developers of the program.
On the flip side, flags help software teams ship more often , minimize risks and increase productivity.
References
https://pkg.go.dev/flag
https://apiumhub.com/tech-blog-barcelona/benefits-feature-toggles-feature-flags/