Golang Flag Package [In-Depth Tutorial]


Written By - Antony Shikubu
Advertisement

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:

  1. Using flag.String(), flag.Int() and flag.Bool() methods
  2. Using flag.StringVar(), flag.IntVar() and flag.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.

Advertisement

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

Advertisement
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

Advertisement
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)

Advertisement
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/

 

Categories GO

Didn't find what you were looking for? Perform a quick search across GoLinuxCloud

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can either use the comments section or contact me form.

Thank You for your support!!

Leave a Comment