AppDividend
Latest Code Tutorials

Golang Log Example | Log Package In Go

0

In computing paradigm, a log file is a file that records either events that occur in the operating system or other software runs or messages between the different users of communication software. Logging is an act of keeping a log. In the simplest case, messages are written to the single log file. Let’s deep dive into Golang Log Example.

Golang Log

Large corporations that depend on the distributed systems often write their applications in Go to take advantage of the concurrency features like channels and goroutines (e.g., Heroku, Basecamp).

If you are responsible for building or supporting the Go applications, a well-considered logging strategy can help you to understand user behavior, localize errors, and monitor the performance of your applications. 

The package log implements the simple logging package.

It defines a type, Logger, with methods for formatting output.

Golang Log will be helpful in the critical scenarios in the realtime applications.

It also has the predefined ‘standard’ Logger accessible through helper functions Print[f|ln], Fatal[f|ln], and Panic[f|ln], which are easier to use than creating the Logger manually.

Golang gives you the wealth of options when choosing a logging package, and we’ll explore several of these below.

How to use log in Go

Golang has built-in logging library, called log, comes with the default logger that writes to standard error and adds the timestamp without the need for configuration.

You can use these rough-and-ready logs for local development in which you need to get fast feedback from your code may be more important than generating rich, structured logs.

If you want to generate rich and structured logs then third party packages will be more helpful.

For example, you can define the division function that returns the error to the caller, rather than exiting the program, when you attempt to divide by zero.

See the following code.

// hello.go

package main

import (
	"errors"
	"fmt"
	"log"
)

func division(x float32, y float32) (float32, error) {
	if y == 0 {
		return 0, errors.New("can't divide by zero")
	}

	return x / y, nil
}

func main() {

	var x float32 = 11
	var y float32

	res, err := division(x, y)

	if err != nil {
		log.Print(err)
	}

	fmt.Println(res)
}

Output

➜  hello go run hello.go
2019/11/28 18:50:19 can't divide by zero
0
➜  hello

In the above program, we have imported three packages.

  1. errors
  2. fmt
  3. log

Then we have defined a function division(), which accepts two parameters. 

We are checking the dividing by 0 error, and if it occurs, then we log that error in console.

If we met the divide by 0 condition, then one error will be generated, and then we log that error in the console and also prints the return value in the console.

In the above program, we got the divide by 0 condition; that is why we got the log in the output.

The logger writes to standard error and prints the date and time of each logged message which is quite useful in general case scenarios.

Every log message has an output on the separate line: if the message being printed does not end in the newline, the logger will add one line.

The Fatal functions call os.Exit(1) after writing the log message.

The Panic functions call panic after writing a log message.

How to store the logged messages in files in Go

In the above code, we have print the log message in the console. Let’s store the message in a file because, in a real-time application, all the logs are saved in the file.

See the following code.

// hello.go

package main

import (
	"errors"
	"fmt"
	"log"
	"os"
)

func division(x float32, y float32) (float32, error) {
	if y == 0 {
		return 0, errors.New("can't divide by zero")
	}

	return x / y, nil
}

func main() {
	var x float32 = 11
	var y float32

	res, exception := division(x, y)
	file, err := os.OpenFile("info.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)

	if err != nil {
		log.Fatal(err)
	}

	defer file.Close()

	log.SetOutput(file)
	log.Print(exception)
	fmt.Println(res)
}

Output

➜  hello go run hello.go
0
➜  hello

Also, you will find the info.log created in your directory. Open the file, and you will see something like the following printed.

2019/11/28 19:29:33 can't divide by zero

The os interface in Go is intended to be uniform across all operating systems. Features not generally available appear in the system-specific package syscall.

If the open fails on file, then the error string will be self-explanatory.

What we are doing in the above code is that we are creating one log file and print our log message inside that file.

After printing the log message, we are closing the file, and that is it.

Github package logrus for formatted logs

The logrus, a logging package designed for structured logging that is well-suited for logging in JSON. The JSON format makes it possible for machines to parse your Golang logs quickly.

And since JSON is a well-defined standard, it makes it straightforward to add context by including new fields—a parser should be able to pick them up automatically.

Using the logrus package, you can define standard fields to add to your JSON logs by using the function WithFields, as shown below.

You can then make calls to the logger at different levels, such as Info(), Warn(), and Error().

The logrus library will write the log as JSON automatically and insert the standard fields, along with any fields you’ve defined on the fly.

Now, to use the package, first, you need to install it. Type the following command.

 

go get github.com/Sirupsen/logrus

Now, you can import the package in your file. See the following code.

// hello.go

package main

import (
	log "github.com/sirupsen/logrus"
)

func main() {
	log.WithFields(log.Fields{
		"Best Song": "Sunflower",
	}).Info("One of the best song")
}

Output

 

Golang Log Example

Note that it’s utterly api-compatible with the stdlib logger so that you can replace your log imports everywhere with log “github.com/sirupsen/logrus” and you’ll now have the flexibility of Logrus. You can customize it all you want:

// hello.go

package main

import (
	"os"

	log "github.com/sirupsen/logrus"
)

func init() {
	// Log as JSON instead of the default ASCII formatter.
	log.SetFormatter(&log.JSONFormatter{})

	// Output to stdout instead of the default stderr
	// Can be any io.Writer, see below for File example
	log.SetOutput(os.Stdout)

	// Only log the warning severity or above.
	log.SetLevel(log.WarnLevel)
}

func main() {
	log.WithFields(log.Fields{
		"animal": "walrus",
		"size":   10,
	}).Info("A group of walrus emerges from the ocean")

	log.WithFields(log.Fields{
		"omg":    true,
		"number": 122,
	}).Warn("The group's number increased tremendously!")

	log.WithFields(log.Fields{
		"omg":    true,
		"number": 100,
	}).Fatal("The ice breaks!")

	// A common pattern is to re-use fields between logging statements by re-using
	// the logrus.Entry returned from WithFields()
	contextLogger := log.WithFields(log.Fields{
		"common": "this is a common field",
		"other":  "I also should be logged always",
	})

	contextLogger.Info("I'll be logged with common and other field")
	contextLogger.Info("Me too")
}

Output

➜  hello go run hello.go
{"level":"warning","msg":"The group's number increased tremendously!","number":122,"omg":true,"time":"2019-11-28T19:44:30+05:30"}
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,"time":"2019-11-28T19:44:30+05:30"}
exit status 1
➜  hello

Best practices for writing and storing Golang logs

The first thing while writing a log is to find a perfect library, and then after you have chosen the logging library, you’ll also want to plan for where in your code to make calls to the logger, how to store your logs, and how to make them available at any given time, and how to analyze them.

Let’s see some of the best practices.

  1. You can make calls to the logger from within your primary application process, not within goroutines.
  2. It is considered good practice if you write logs from your application to a local file, even if you will ship them to a central platform later.
  3. You can standardize your logs with a set of predefined messages.
  4. You can send your logs to the central platform so you can analyze and aggregate them.
  5. Use the HTTP headers and unique IDs to log user behavior across microservices.

Conclusion

In this post, we have gone thorugh the benefits and tradeoffs of several Go logging libraries. 

We have also recommended ways to ensure that your logs are available and accessible when you need them and the information they contain is handy, consistent and easy to analyze.

Finally, Golang Log Example | Log Package In Go article is over.

Recommended Posts

Golang Templates

Golang Maps

Golang Structs

Golang Interface

Golang Receiver Function

Leave A Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.