Table of Contents
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 :
- Log Errors or Warning messages that developers need to know about.
- Log performance metrics , memory consumption etc
- 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.
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
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
- Only print messages on console
- Only log messages to log file
- 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:
# 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.
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:
$ 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
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
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