Golang Logrus Complete Tutorial with Examples

When developing enterprise software or any other software for that matter, it is always good practice to have a structured logging framework. Logrus is a structured logger for Go and is compatible with the standard log package. The standard logging package is limited in some ways and that led to development of other logging packages like Logrus, oklog and zerolog. Logging is an important  aspect in modern programming and are used to :

  1. Log Errors or Warning messages that developers need to know about.
  2. Log performance metrics , memory consumption etc
  3. Log Debug messages to help developers troubleshoot their software.

Logging is a way of letting our software communicate to us what is going on. For that reason , not everything should be logged as that will be a waste of time and resources. Developers need to only log messages that are meaningful. These logs messages can be sent to the stdout, or files like log.txt file.

Advertisement

To follow along with this tutorial , please ensure you have basic Go skills and you have Go language installed on your computer.

 

Installing logrus

Logrus is not a standard package that comes with Go. It has to be added into your package manually . To get started , navigate to your working directory and use the below commands to create a module and install Logrus package.

$ go get github.com/sirupsen/logrus
go get: added github.com/sirupsen/logrus v1.9.0
go get: added golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8go get github.com/sirupsen.logrus

Now you can directly start using logrus in your package file:

package main

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

func main() {
   // Your Code
}

 

Getting started with Logrus

Now that we have successfully installed the logrus package, let us now learn how we can use logrus in the initial stages.Logrus has different methods just like the  fmt package used to log messages to the terminal or any other output. These methods are Println(), Printf() , Fatal(), Fatalf() and many more.

Example

package main
 
package main
 
import (
   "os"
 
   "github.com/sirupsen/logrus"
)
 
func main() {
   logrus.Println("Hello, world!")
}

Explanation

Advertisement

In the above example, we are importing the logrus package and assigning it the alias name log. In the main function we use the log alias name to access the Println() methods that come with the logrus package.

Output

$ go run main.go
INFO[0000] Hello, world!

 

Choosing different log levels in logrus

Logrus offers different log levels e.g panic, fatal, error, warning, info, debug and trace. A log level is a way of determining the severity/priority of any type of event. These levels are ordered from the lowest to the highest as shown below.

  • Trace
  • Debug
  • Info
  • Warn
  • Error
  • Fatal
  • Panic

You can set the log level using:

logrus.SetLevel(logrus.TraceLevel)
logrus.SetLevel(logrus.DebugLevel)
logrus.SetLevel(logrus.InfoLevel)
logrus.SetLevel(logrus.WarnLevel)
logrus.SetLevel(logrus.ErrorLevel)
logrus.SetLevel(logrus.FatalLevel)

Here we have set the log level as TraceLevel so we will log everything. For Example:

package main

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

func main() {
	logrus.SetLevel(logrus.TraceLevel)
	logrus.Traceln("Trace Level")
	logrus.Debugln("Debug Level")
	logrus.Infoln("Info Level")
	logrus.Warningln("Warning Level")
	logrus.Errorln("Error Level")
	logrus.Fatalln("Fatal Level")
	logrus.Panicln("Panic Level")
}

Since we have set the log level as TraceLevel so all levels of logs are getting logged. Output:

$ go run main.go 
TRAC[0000] Trace Level 
DEBU[0000] Debug Level 
INFO[0000] Info Level 
WARN[0000] Warning Level 
ERRO[0000] Error Level 
FATA[0000] Fatal Level 
exit status 1

 

Now let us set the log level to DebugLevel:

package main

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

func main() {
	logrus.SetLevel(logrus.DebugLevel)
	logrus.Traceln("Trace Level")
	logrus.Debugln("Debug Level")
	logrus.Infoln("Info Level")
	logrus.Warningln("Warning Level")
	logrus.Errorln("Error Level")
	logrus.Fatalln("Fatal Level")
	logrus.Panicln("Panic Level")
}

As expected, trace level messages are not shown anymore:

$ go run main.go 
DEBU[0000] Debug Level 
INFO[0000] Info Level 
WARN[0000] Warning Level 
ERRO[0000] Error Level 
FATA[0000] Fatal Level 
exit status 1

 

logrus.SetOutput to stdOut, stderr and/or log file

logrus supports different options to print and log messages. We can

  1. Only print messages on console
  2. Only log messages to log file
  3. Print on console and log messages to log file

 

Print messages on console (stdout and stderr)

Use SetOutput to os.Stdout or os.Stderr to print messages on console:

package main

import (
	"os"

	log "github.com/sirupsen/logrus"
)

func main() {
	// Output to stdout instead of the default stderr
	log.SetOutput(os.Stdout)

	// Only log the debug severity or above
	log.SetLevel(log.DebugLevel)

	log.Info("Info message")
	log.Warn("Warn message")
	log.Error("Error message")
	log.Fatal("Fatal message")
}

 

Log messages in log file

To log messages into log file use SetOutput with the filename using logrus.SetOutput(file):

package main

import (
	"fmt"
	"os"

	log "github.com/sirupsen/logrus"
)

func main() {
	logFile := "log.txt"
	f, err := os.OpenFile(logFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
	if err != nil {
		fmt.Println("Failed to create logfile" + logFile)
		panic(err)
	}
	defer f.Close()
	// Output to stdout instead of the default stderr
	log.SetOutput(f)

	// Only log the debug severity or above
	log.SetLevel(log.DebugLevel)

	log.Info("Info message")
	log.Warn("Warn message")
	log.Error("Error message")
	log.Fatal("Fatal message")
}

 

Print on console and also in log file

package main

import (
	"fmt"
	"io"
	"os"

	"github.com/sirupsen/logrus"
	easy "github.com/t-tomalak/logrus-easy-formatter"
)

func main() {
	f, err := os.OpenFile("log.txt", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
	if err != nil {
		fmt.Println("Failed to create logfile" + "log.txt")
		panic(err)
	}
	defer f.Close()

	log := &logrus.Logger{
                // Log into f file handler and on os.Stdout
		Out:   io.MultiWriter(f, os.Stdout),
		Level: logrus.DebugLevel,
		Formatter: &easy.Formatter{
			TimestampFormat: "2006-01-02 15:04:05",
			LogFormat:       "[%lvl%]: %time% - %msg%\n",
		},
	}

	log.Trace("Trace message")
	log.Info("Info message")
	log.Warn("Warn message")
	log.Error("Error message")
	log.Fatal("Fatal message")
}

Output:

Advertisement
# go run main.go 
[INFO]: 2022-08-25 11:27:06 - Info message
[WARNING]: 2022-08-25 11:27:06 - Warn message
[ERROR]: 2022-08-25 11:27:06 - Error message
[FATAL]: 2022-08-25 11:27:06 - Fatal message
exit status 1

Content of log.txt file

[INFO]: 2022-08-25 11:27:06 - Info message
[WARNING]: 2022-08-25 11:27:06 - Warn message
[ERROR]: 2022-08-25 11:27:06 - Error message
[FATAL]: 2022-08-25 11:27:06 - Fatal message

 

Alternatively you can just set multi writer using SetOutput:

multi := io.MultiWriter(logFile, os.Stdout)
logrus.SetOutput(multi)

 

logrus show line number

To print the line number of the entries in the code which is printing or logging the messages we can use SetReportCaller:

package main

import (
	"os"

	log "github.com/sirupsen/logrus"
)

func main() {

	// Output to stdout instead of the default stderr
	log.SetOutput(os.Stdout)

	// Only log the debug severity or above
	log.SetLevel(log.DebugLevel)

        // logrus show line number
	log.SetReportCaller(true)

	log.Info("Info message")
	log.Warn("Warn message")
	log.Error("Error message")
	log.Fatal("Fatal message")
}

Output:

$ go run main.go 
INFO[0000]/opt/deepak/scripts/goexamples/global-vars/main.go:18 main.main() Info message 
WARN[0000]/opt/deepak/scripts/goexamples/global-vars/main.go:19 main.main() Warn message 
ERRO[0000]/opt/deepak/scripts/goexamples/global-vars/main.go:20 main.main() Error message 
FATA[0000]/opt/deepak/scripts/goexamples/global-vars/main.go:21 main.main() Fatal message 
exit status 1

 

Format logrus messages

Logrus has two main built-in formatters namely logrus.TextFormatter and logrus.JSONFormatter. They are used to format the logs coming from the logger using an object formatter. By default the the formatter in logrus will set logrus.TextFormatter.The logrus.TextFormatter can be used to log events in colors if the stdout is a tty. To be able to switch between these two formatters, logrus offers a method called logger.SetFormatter(), that takes the format type as the input. In the following examples we will use logrus.TextFormatter as the object formatter.

 

Set custom date and time format

Logrus package can be formatted to print logs containing date and time.The date and time will be put immediately after the log level . In the previous examples, the date and time attributes were represented as e.g TRAC[0000], INFO[0000] ect. The [0000] the time.To set the time , user FullTimeStamp and TimestampFormat as fields to the log.TextFormatter. FullTImeStamp is a boolean type while TImestampFormat is a string type and the string refers to the date time you want to add to the log output.

Advertisement

Example

package main
 
import (
   log "github.com/sirupsen/logrus"
)
 
func main() {
   log.SetFormatter(&log.TextFormatter{
       FullTimestamp:   true,
       TimestampFormat: "2006-01-02 15:04:05",
   })
   log.SetLevel(log.TraceLevel)
   log.Trace("Trace message")
   log.Info("Info message")
   log.Warn("Warn message")
   log.Error("Error message")
   log.Fatal("Fatal message")
}

Output

$ go run main.go
TRAC[2022-08-24 23:32:22] Trace message                               
INFO[2022-08-24 23:32:22] Info message                                
WARN[2022-08-24 23:32:22] Warn message                                
ERRO[2022-08-24 23:32:22] Error message                               
FATA[2022-08-24 23:32:22] Fatal message                               
exit status 1

 

To set time stamp format to print nano seconds:

	log.SetFormatter(&log.TextFormatter{
		FullTimestamp:   true,
		TimestampFormat: "2006-01-02T15:04:05.9999999Z07:00",
	})

 

Change log output format

By default logrus prints in below format

<LOG LEVEL> <TIMESTAMP> <MESSAGE>

logrus itself doesn't support changing the log output format. To modify the log format we have to use logrus-easy-formatter module from github.com/t-tomalak/logrus-easy-formatter module.

To install this module we have to execute:

Advertisement
$ go get "github.com/t-tomalak/logrus-easy-formatter"
go get: added github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816

 

Next we can use LogFormat to define the order of output:

LogFormat       = "%time%, %lvl%, %msg%"

Here we will print the log message in below order:

<TIMESTAMP> <LOG LEVEL> <MESSAGE>

Let's check this in one practical example:

package main

import (
	"os"

	"github.com/sirupsen/logrus"
	easy "github.com/t-tomalak/logrus-easy-formatter"
)

func main() {
	log := &logrus.Logger{
		Out:   os.Stderr,
		Level: logrus.DebugLevel,
		Formatter: &easy.Formatter{
			TimestampFormat: "2006-01-02 15:04:05",
			LogFormat:       "[%lvl%]: %time% - %msg%\n",
		},
	}

	log.Trace("Trace message")
	log.Info("Info message")
	log.Warn("Warn message")
	log.Error("Error message")
	log.Fatal("Fatal message")
}

Output:

$ go run main.go 
[INFO]: 2022-08-25 11:12:13 - Info message
[WARNING]: 2022-08-25 11:12:13 - Warn message
[ERROR]: 2022-08-25 11:12:13 - Error message
[FATAL]: 2022-08-25 11:12:13 - Fatal message
exit status 1

 

Setting Color in the log output

To set colors in the log output, use the key DisableColors to false as shown below.

Example

Advertisement
package main
 
import (
   log "github.com/sirupsen/logrus"
)
 
func main() {
   log.SetFormatter(&log.TextFormatter{
       ForceColors:   true,
       DisableColors: false,
   })
   log.SetLevel(log.TraceLevel)
   log.Trace("Trace message")
   log.Info("Info message")
   log.Warn("Warn message")
   log.Error("Error message")
   log.Fatal("Fatal message")
}

Explanation

In the above example we are using the logrus.TextFormatter with ForceColors and DisableColors fields . ForceColors fields, ensures the log level of the terminal is colored. The DisableColors field is used to prevent the log levels being colored. Also by setting the DisableColors field to true, the output returns the time, log level and the message on the terminal as shown below in the output. The logrus.TexFormatter has more fields that can be added to it such as ForceQuote,EnvironmentOverrideColors, DisableTimestamp,FullTimestamp,TimestampFormat. To learn more about these fields, look at the go general docs .

Output

$ go run main.go

Golang Logrus Complete Tutorial with Examples

 

Summary

Structured logging determines how reliable an application is. Go comes with a standard logger which is limited in terms of functionality. Logrus makes logging easy and fun and can be used to build metrics, log latency and many more. It also tries to make logging possible in a structured fashion.

 

References

https://pkg.go.dev/github.com/sirupsen/logrus#JSONFormatter
logrus set output format

 

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

X