Redirecting to Standard Error Output in Go
Hello, I'm incompetent.
I couldn't find many articles explaining this part for Go, so I'm writing it down.
Checking Return Values
When you first have code like this.
func main() {
if len(os.Args) < 2 {
fmt.Println("Usage: go run main.go https://soulminingrig.com/")
return
}
url := os.Args[1]
title, err := fetchTitle(url)
if err != nil {
fmt.Printf( "Error: %v\n", err)
return
}
fmt.Printf("Title: %s\n", title)
}
Of course, errors in Go will be output as errors even with the above code, but what if you want to get the error return value of the executable binary after building it?
alleycat:[haturatu]:~/git/go-title$ ./go-title
Usage: go run main.go https://soulminingrig.com/
alleycat:[haturatu]:~/git/go-title$ echo $?
0
alleycat:[haturatu]:~/git/go-title$ ./go-title http://https://soulminingrig.nodomain/
Error: failed to fetch URL: Get "http://https//soulminingrig.nodomain/": dial tcp: lookup https: no such host
alleycat:[haturatu]:~/git/go-title$ echo $?
0
Everything is treated as standard output.
os.Exit to specify return value
Therefore, to ensure it's properly treated as an error, you need to specify it with os.Exit, so correct it as follows.
func main() {
if len(os.Args) < 2 {
fmt.Println("Usage: go run main.go https://soulminingrig.com/")
os.Exit(1)
}
url := os.Args[1]
title, err := fetchTitle(url)
if err != nil {
fmt.Printf( "Error: %v\n", err)
os.Exit(2)
}
fmt.Printf("Title: %s\n", title)
}
Now, build and run again.
alleycat:[haturatu]:~/git/go-title$ ./go-title
Usage: go run main.go https://soulminingrig.com/
alleycat:[haturatu]:~/git/go-title$ echo $?
1
alleycat:[haturatu]:~/git/go-title$ ./go-title http://https://soulminingrig.nodomain/
Error: failed to fetch URL: Get "http://https//soulminingrig.nodomain/": dial tcp: lookup https: no such host
alleycat:[haturatu]:~/git/go-title$ echo $?
2
The return value was correctly returned.
Trying to discard successful patterns (return value 0) to /dev/null
Since you can discard only standard output with a return value of 0 using > /dev/null, let's try it.
alleycat:[haturatu]:~/git/go-title$ ./go-title > /dev/null
alleycat:[haturatu]:~/git/go-title$ ./go-title http://https://soulminingrig.nodomain/ > /dev/null
In this case, fmt.Println is treated as standard output, so error messages cannot be seen.
For most proper GNU Tools and other executables, error messages are not typically output to standard output, so error messages must also be output to standard error.
Even in the official documentation, most examples use fmt.Print for output,
Return and handle an error
https://pkg.go.dev/errors
While there isn't much need to explicitly use standard error output when creating modules in the Go ecosystem, it doesn't meet the need to see only error output when debugging using just > /dev/null.
Ultimately, this needs to be handled with fprint, similar to C language.
Next, let's try giving os.Stderr as the first argument to fprint, representing standard error output.
Difference between fmt.Print and fmt.Fprint
Let's try changing it as follows.
This article is very easy to understand.
I want to properly distinguish and use Go's fmt.Print family of functions
If even this article makes you wonder 'What is this?!', you might find a satisfactory explanation by researching the differences in C language's print-family outputs.
If you don't understand printf, you can try it with awk.
$ ls -la | awk '{print $9}'
$ ls -la | awk '{printf $9}'
fprint with awk is... I don't know due to lack of knowledge...
If anyone knows, I'd appreciate it if you could tell me.
func main() {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "Usage: go run main.go https://soulminingrig.com/")
os.Exit(1)
}
url := os.Args[1]
title, err := fetchTitle(url)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(2)
}
fmt.Printf("Title: %s\n", title)
}
Let's look at the results now.
alleycat:[haturatu]:~/git/go-title$ ./go-title > /dev/null
Usage: go run main.go https://soulminingrig.com/
alleycat:[haturatu]:~/git/go-title$ echo $?
1
alleycat:[haturatu]:~/git/go-title$ ./go-title http://https://soulminingrig.nodomain/ > /dev/null
Error: failed to fetch URL: Get "http://https//soulminingrig.nodomain/": dial tcp: lookup https: no such host
alleycat:[haturatu]:~/git/go-title$ echo $?
2
Error output was performed correctly.
Handling this kind of thing is really easy to forget, so I strongly felt that I need to be careful, especially with correct error output.