paint-brush
Top 6 Golang Logging Best Practices by@wagslane
1,061 reads
1,061 reads

Top 6 Golang Logging Best Practices

by Lane WagnerMay 15th, 2022
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Use Errors Where Appropriate, Not Strings, Wrap Errors and Format Structs Where appropriate. Use the Built-in Log Package and use the Formatters like fmt.Errorf() to log errors. Go has a built-in `error` type that makes it clear that something is wrong when the error isn’t `nil` Use the 'error' type to differentiate errors from “normal” strings. Use a function that can be used in other places to make sure functions exit without a problem in more explicit way.

People Mentioned

Mention Thumbnail

Coin Mentioned

Mention Thumbnail
featured image - Top 6 Golang Logging Best Practices
Lane Wagner HackerNoon profile picture

Top 6 Golang Logging Best Practices


Let’s discuss a few rules of thumb for logging in Go, as well as some features you may not have heard of that can make debugging easier. Best practices for logging in Go are not so obvious and sometimes we need to look closer to see what is the best choice, considering the unique situation of error handling in Go.
  1. Use Errors Where Appropriate, Not Strings
  2. Wrap Errors
  3. Use Formatters Like fmt.Errorf()
  4. Format Structs Where Appropriate
  5. Use the variadic forms of functions like fmt.Println()
  6. Use the Built-in Log Package

#1 - Use Errors Where Appropriate, Not Strings

Go has a built-in error type, which allows developers to easily differentiate errors from “normal” strings and check to make sure functions exit without a problem in a more explicit way. The error type is an that simply requires the type in question to define an Error() function that prints itself as a string.

type error interface {
    Error() string
}

Never use a normal string where an error is appropriate! When a string is returned from your function you imply to other developers that when the string isn’t empty it’s just “business as usual”. The error type makes it clear that something is wrong when the error isn’t nil.

For example, let’s pretend we have a function that divides two numbers safely and returns a result.
func divide(a, b float64) (float64, string) {
    if b == 0 {
        return 0.0, "can't divide by zero"
    }
    return a / b, ""
}

This will work perfectly. In fact, anywhere an error type works a string could be used instead. However, if we’re interested in writing code that other developers can more quickly understand and make contributions to, we should use an error type:

func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0.0, errors.New("can't divide by zero")
    }
    return a / b, nil
}

#2 - Wrap Errors

Often times out of laziness we simply pass errors up a call chain. For example, let’s look at this function that formats hours and minutes into a time message:
func formatTimeWithMessage(hours, minutes int) (string, error) {
	formatted, err := formatTime(hours, minutes)
	if err != nil {
		return "", err
	}
	return "It is " + formatted + " o'clock", nil
}

The problem here is that the formatTime function can be called many other places within our application or library. If all we do is pass along the raw error, when the error is eventually printed, it gets really hard to tell where exactly the error originated from. Instead, let’s do the following:

func formatTimeWithMessage(hours, minutes int) (string, error) {
	formatted, err := formatTime(hours, minutes)
	if err != nil {
		return "", fmt.Errorf("formatTimeWithMessage: %v", err)
	}
	return "It is " + formatted + " o'clock", nil
}
Additionally, if you are working in Go 1.13 or later, then you can look into the more explicit method for error chains.

#3 - Use Formatters Like fmt.Errorf()

[fmt.Errorf()](//golang.org/pkg/fmt/#Errorf) is similar to fmt.Printf(), but returns an error instead of a string. You may have done this in the past:

err := errors.New("Bad thing happened! " + oldErr.Error()) 
This can be accomplished more succinctly using fmt.Errorf():
err := fmt.Errorf("Bad thing happened! %v", oldError) 
The difference in readability becomes even more obvious when the formatting in question is more complicated and includes more variables.

#4 - Format Structs Where Appropriate

Printing structs can be quite ugly and unreadable. For example, the following code:
func main() {
    make := "Toyota"
    myCar := Car{year:1996, make: &make}
    fmt.Println(myCar)
}
Will print something like:
{1996 0x40c138}

We likely want to get the value in the pointer, and we probably want to see the keys of the struct. So we can implement a default String() method on our struct. If we do so, then the Go compiler will use that method when printing.

func (c Car)String() string{
    return fmt.Sprintf("{make:%s, year:%d}", *c.make, c.year)
}

func main() {
    make := "Toyota"
    myCar := Car{year:1996, make: &make}
    fmt.Println(myCar)
}
Which will print something like:
{make:Toyota, year:1996}

#5 - Use the variadic forms of functions like fmt.Println()

In the past, I’ve often done the following when logging:
fmt.Printf("%s beat %s in the game\n", playerOne, playerTwo)

Turns out, it is much easier to just use the fmt.Println() function’s ability to add spacing:

fmt.Println(playerOne, "beat", playerTwo, "in the game")

#6 - Use the Built-in Log Package

It’s often tempting to roll your own logging package, but I would advise that in most cases, the is probably all you need. The standard library defines a type, , which you can use to customize your logging in an idiomatic way. If you don’t want that much power and responsibility, you can do what I usually do and use the standard and functions which just print to standard output along with a formatted date and time prefix.

Best Practices

Glad you’ve made it this far! Learning to properly handle errors in Go is one of the things that sets advanced developers apart from newcomers. Striving to improve the readability and developer usability of your code will make you a better , and help you find more in the future.


-By Lane Wagner on Jan 7, 2020
Also Published
바카라사이트 바카라사이트 온라인바카라