# How to Implement Verbose Mode in a Go CLI App Using the Standard Library

A lot of CLI tools provide a verbose mode to get logs with additional information, which is helpful for scenarios when something breaks or when a user wants to understand in more detail what is happening in the background.

It is an essential part of the standard experience expected of a CLI app.

One such example is the **cURL** command. Following is a gif of the difference in output when using the `curl` command with the verbose flag and without.

[![asciicast](https://asciinema.org/a/595706.svg align="left")](https://asciinema.org/a/595706)

Today we'll try to see how to implement such a feature in a CLI app using Go.

### Defining the feature

Let's define the flag we are going to implement

* It should work for all commands and subcommands in the application
    
* When provided, it should show additional logs of all the commands, in addition, to the output that is shown by default.
    
* It should be easy to maintain, every command or every log statement must not need to handle or know about this flag
    

Luckily for us, Go has amazing standard packages we can compose to create this effect with ease.

### Tres Amigos

We will use three packages to accomplish this.

1. [flag](https://pkg.go.dev/flag): We will use it to easily parse the arguments provided by the user
    
2. [log](https://pkg.go.dev/log): We will use the standard package to log stuff
    
3. [io](https://pkg.go.dev/io): We will utilise a very special Writer provided by this package.
    

#### flag

The flag parsing works in three steps which need to be followed in the exact same order

1. Define the expected flags
    
2. Invoke the `Parse()` method
    
3. Start accessing the values
    

```go
func main() {
    // Define the flag that is expected 
    // We can pass the name, a default value & a description
    // It will return a pointer which is guranteed to have value 
    // Only after flag.Parse is called
	verboseP := flag.Bool("v", false, "Enable verbosity")
    
    // From the docs: Must be called after all flags are defined 
    // and before flags are accessed by the program.
	flag.Parse()

    // Access the value after 
    isVerbose := *verboseP
}
```

#### log

Log package contains a function called `SetOutput` which can be set to anything that implements the `Writer` interface.

We can use this to redirect all the logs to a specific writer.

`log.setOutput(SomeWriter)`

#### io

IO will provide us with the last missing piece, `Writer` which does nothing.

Basically discards any logs sent to it. It's called `io.Discard`

### Putting it all together

```go
package main

import (
	"flag"
	"fmt"
	"io"
	"log"
)

func main() {
    // Define the flags
	verboseP := flag.Bool("v", false, "Enable verbosity")

    // Invoke the parser
	flag.Parse()
    
    // Access it 
	isVerbose := *verboseP

    // If verbosity is not required discard all upcoming logs
	if !isVerbose {
		log.SetOutput(io.Discard)
	}

	fmt.Println("Hello world!")
	log.Println("I'm tired of printing this")
}
```

[![asciicast](https://asciinema.org/a/608521.svg align="left")](https://asciinema.org/a/608521)

Try it on [repl.it](https://replit.com/@ShuvojitSarkar/Simple-Verbose-Flag#main.go)
