Introduction to the
The previous article introduced the log library in the Go standard library. Finally, we mentioned that the log library provides only three sets of interfaces, which is too simple. Today, we introduce logrus, a “star library” of log libraries. As of this writing (2020.02.07), Logrus has reached 13.8K stars on GitHub. Logrus is fully compatible with standard log libraries and supports both text and JSON log output formats. Many well-known open source projects use this library, such as the well-known Docker.
Quick to use
Third-party libraries need to be installed first:
$ go get github.com/sirupsen/logrus
Copy the code
After using:
package main
import (
"github.com/sirupsen/logrus"
)
func main(a) {
logrus.SetLevel(logrus.TraceLevel)
logrus.Trace("trace msg")
logrus.Debug("debug msg")
logrus.Info("info msg")
logrus.Warn("warn msg")
logrus.Error("error msg")
logrus.Fatal("fatal msg")
logrus.Panic("panic msg")}Copy the code
Logrus is very simple to use, similar to the standard library log. Logrus supports more logging levels:
Panic
: Log and thenpanic
.Fatal
: Fatal error, the program will not work properly when an error occurs. After the log output, the program exits.Error
: Error log, you need to view the cause.Warn
: warning message to remind programmers;Info
: Logs of key operations and core processes;Debug
: Debugging information output in common programs.Trace
: Very fine-grained information, generally not needed;
The log levels are increased from top to bottom. The log levels are the largest for Trace and the smallest for Panic. Logrus has a log level above which logs are not output. The default level is InfoLevel. So to see Trace and Debug logs, we set the log level to TraceLevel on the first line of the main function.
Run the program, output:
$ go run main.go
time="2020-02-07T21:22:42+08:00" level=trace msg="trace msg"
time="2020-02-07T21:22:42+08:00" level=debug msg="debug msg"
time="2020-02-07T21:22:42+08:00" level=info msg="info msg"
time="2020-02-07T21:22:42+08:00" level=info msg="warn msg"
time="2020-02-07T21:22:42+08:00" level=error msg="error msg"
time="2020-02-07T21:22:42+08:00" level=fatal msg="fatal msg"
exit status 1
Copy the code
The following logrus.Panic will not be executed because logrus.Fatal causes the program to exit.
In addition, we observe three key messages in the output, time, level, and MSG:
time
: Indicates the time when logs are outputted.level
: Log level;msg
: Indicates a log.
custom
Output file name
Call logrus.setreportCaller (true) to add file name and method information to the output log:
package main
import (
"github.com/sirupsen/logrus"
)
func main(a) {
logrus.SetReportCaller(true)
logrus.Info("info msg")}Copy the code
Logrus = method; logrus = method; logrus = method;
$ go run main.go
time="2020-02-07T21:46:03+08:00" level=info msg="info msg" func=main.main file="D:/code/golang/src/github.com/darjun/go-daily-lib/logrus/caller/main.go:10"
Copy the code
Add fields
Sometimes you need to add fields to the output by calling logrus.withfield and logrus.withFields. Logrus. WithFields takes an argument of type logrus.Fields, which is actually map[string]interface{} :
// github.com/sirupsen/logrus/logrus.go
type Fields map[string]interface{}
Copy the code
Add two fields name and age to the output:
package main
import (
"github.com/sirupsen/logrus"
)
func main(a) {
logrus.WithFields(logrus.Fields{
"name": "dj"."age": 18,
}).Info("info msg")}Copy the code
If you need to add some fields to all logs in a function, you can use the return value of WithFields. For example, in the handler of a Web request, the log is added with the user_id and IP fields:
package main
import (
"github.com/sirupsen/logrus"
)
func main(a) {
requestLogger := logrus.WithFields(logrus.Fields{
"user_id": 10010."ip": "192.168.32.15",
})
requestLogger.Info("info msg")
requestLogger.Error("error msg")}Copy the code
In fact, WithFields returns a value of type Logrus.entry, which saves logrus.logger and the logrus.fields set. When the Entry method is called to output the log, the saved logrus.fields are also output.
Redirection output
By default, logs are output to IO.Stderr. We can call logrus.SetOutput to pass in an io.Writer argument. The logs of subsequent method calls will be written to IO.Writer. Now, we can do something like we did in the last article when we introduced log. Pass in an IO.MultiWriter and write the log to bytes.buffer, standard output, and a file:
package main
import (
"bytes"
"io"
"log"
"os"
"github.com/sirupsen/logrus"
)
func main(a) {
writer1 := &bytes.Buffer{}
writer2 := os.Stdout
writer3, err := os.OpenFile("log.txt", os.O_WRONLY|os.O_CREATE, 0755)
iferr ! =nil {
log.Fatalf("create file log.txt failed: %v", err)
}
logrus.SetOutput(io.MultiWriter(writer1, writer2, writer3))
logrus.Info("info msg")}Copy the code
The custom
In fact, for ease of use, libraries typically create an object with default values, and the outermost methods of the package typically operate on the default object.
We’ve mentioned this in several previous posts:
- Go a library of flags per day:
flag
In the standard libraryCommandLine
Object; - Go A library of logs per day:
log
In the standard librarystd
Object.
This technique has been used in many library developments, as has Logrus:
// github.com/sirupsen/logrus/exported.go
var (
std = New()
)
func StandardLogger(a) *Logger {
return std
}
func SetOutput(out io.Writer) {
std.SetOutput(out)
}
func SetFormatter(formatter Formatter) {
std.SetFormatter(formatter)
}
func SetReportCaller(include bool) {
std.SetReportCaller(include)
}
func SetLevel(level Level) {
std.SetLevel(level)
}
Copy the code
First, use the default configuration defines a Logger object STD, SetOutput/SetFormatter/SetReportCaller/SetLevel these methods are called STD corresponding method of an object.
We can also create our own Logger object in a similar way to calling Logrus directly:
package main
import "github.com/sirupsen/logrus"
func main(a) {
log := logrus.New()
log.SetLevel(logrus.InfoLevel)
log.SetFormatter(&logrus.JSONFormatter{})
log.Info("info msg")}Copy the code
Log format
Logrus supports two log formats, text and JSON, with the default text format. Log formatting can be set with logrus.setformatter:
package main
import (
"github.com/sirupsen/logrus"
)
func main(a) {
logrus.SetLevel(logrus.TraceLevel)
logrus.SetFormatter(&logrus.JSONFormatter{})
logrus.Trace("trace msg")
logrus.Debug("debug msg")
logrus.Info("info msg")
logrus.Warn("warn msg")
logrus.Error("error msg")
logrus.Fatal("fatal msg")
logrus.Panic("panic msg")}Copy the code
The program outputs a JSON log:
$ go run main.go
{"level":"trace"."msg":"trace msg"."time":"2020-02-07T21:40:04+08:00"}
{"level":"debug"."msg":"debug msg"."time":"2020-02-07T21:40:04+08:00"}
{"level":"info"."msg":"info msg"."time":"2020-02-07T21:40:04+08:00"}
{"level":"info"."msg":"warn msg"."time":"2020-02-07T21:40:04+08:00"}
{"level":"error"."msg":"error msg"."time":"2020-02-07T21:40:04+08:00"}
{"level":"fatal"."msg":"fatal msg"."time":"2020-02-07T21:40:04+08:00"}
exit status 1
Copy the code
Third party format
In addition to the built-in TextFormatter and JSONFormatter, there is also a number of third-party format support. We introduce a nested-logrus-formatter here.
First installation:
$ go get github.com/antonfisher/nested-logrus-formatter
Copy the code
After using:
package main
import (
nested "github.com/antonfisher/nested-logrus-formatter"
"github.com/sirupsen/logrus"
)
func main(a) {
logrus.SetFormatter(&nested.Formatter{
HideKeys: true,
FieldsOrder: []string{"component"."category"},
})
logrus.Info("info msg")}Copy the code
Program output:
Feb 8 15:22:59.077 [INFO] INFO MSGCopy the code
The nested format provides multiple fields to customize behavior:
// github.com/antonfisher/nested-logrus-formatter/formatter.go
type Formatter struct {
FieldsOrder []string
TimestampFormat string
HideKeys bool
NoColors bool
NoFieldsColors bool
ShowFullLevel bool
TrimMessages bool
}
Copy the code
- By default,
logrus
The field in the output log iskey=value
It looks like this. usenested
Format, we can set byHideKeys
fortrue
Hide key, output value only; - By default,
logrus
Is the alphabetical output field of a key, which can be setFieldsOrder
Define the order of output fields; - By setting the
TimestampFormat
Set the date format.
package main
import (
"time"
nested "github.com/antonfisher/nested-logrus-formatter"
"github.com/sirupsen/logrus"
)
func main(a) {
logrus.SetFormatter(&nested.Formatter{
// HideKeys: true,
TimestampFormat: time.RFC3339,
FieldsOrder: []string{"name"."age"},
})
logrus.WithFields(logrus.Fields{
"name": "dj"."age": 18,
}).Info("info msg")}Copy the code
If the key is not hidden, the program outputs:
$ 2020-02-08T15:40:07+08:00 [INFO] [name:dj] [age:18] info msg
Copy the code
Hide key, program output:
$ 2020-02-08T15:41:58+08:00 [INFO] [dj] [18] info msg
Copy the code
Notice that we have set the time format to time.RFC3339, which is 2006-01-02T15:04:05Z07:00.
By implementing the interfacelogrus.Formatter
You can implement your own format.
// github.com/sirupsen/logrus/formatter.go
type Formatter interface {
Format(*Entry) ([]byte, error)
}
Copy the code
Set the hook
You can also set up hooks for Logrus, and each log output is preceded by a hook specific method. So, we can add output fields and output logs to different destinations depending on the level. Logrus also has a syslog hook built in to output logs to syslog. Here we implement a hook that adds an app=awesome-web field to the output log.
Hooks need to implement the Logrus.hook interface:
// github.com/sirupsen/logrus/hooks.go
type Hook interface {
Levels() []Level
Fire(*Entry) error
}
Copy the code
The Levels() method returns the log level of interest and does not trigger the hook when other logs are printed. Fire is the hook method called before logging.
package main
import (
"github.com/sirupsen/logrus"
)
type AppHook struct {
AppName string
}
func (h *AppHook) Levels(a) []logrus.Level {
return logrus.AllLevels
}
func (h *AppHook) Fire(entry *logrus.Entry) error {
entry.Data["app"] = h.AppName
return nil
}
func main(a) {
h := &AppHook{AppName: "awesome-web"}
logrus.AddHook(h)
logrus.Info("info msg")}Copy the code
Simply add fields for entry.data in the Fire method implementation and it will be printed to the log.
Program output:
$ time="2020-02-08T15:51:52+08:00" level=info msg="info msg" app=awesome-web
Copy the code
Logrus has many third-party hooks. We can use some hooks to send logs to redis/mongodb and other stores:
- Mgorus: sends logs to mongodb.
- Logrus-redis-hook: send logs to redis;
- Logrus-amqp: Send logs to ActiveMQ.
Here we demonstrate one Redis that is interested in self-verifying the others. Logrus-redis-hook:
$ go get github.com/rogierlommers/logrus-redis-hook
Copy the code
Then write the program:
package main
import (
"io/ioutil"
logredis "github.com/rogierlommers/logrus-redis-hook"
"github.com/sirupsen/logrus"
)
func init(a) {
hookConfig := logredis.HookConfig{
Host: "localhost",
Key: "mykey",
Format: "v0",
App: "aweosome",
Hostname: "localhost",
TTL: 3600,
}
hook, err := logredis.NewHook(hookConfig)
if err == nil {
logrus.AddHook(hook)
} else {
logrus.Errorf("logredis error: %q", err)
}
}
func main(a) {
logrus.Info("just some info logging...")
logrus.WithFields(logrus.Fields{
"animal": "walrus"."foo": "bar"."this": "that",
}).Info("additional fields are being logged as well")
logrus.SetOutput(ioutil.Discard)
logrus.Info("This will only be sent to Redis")}Copy the code
For the program to work properly, we also need to install Redis.
Install Redis directly with Choco on Windows:
Choco install Redis-64 chocatey v0.10.15 Installing the following packages PS C:\Users\Administrator> Choco install Redis-64 redis-64 By installing you accept licensesforThe packages. Progress: Downloading RedIS-64 3.0.503... 100% ReDIS-64 V3.0.503 [Approved] Redis-64 package files install completed. Performing other Installation steps. ShimGen has successfully created a shimfor redis-benchmark.exe
ShimGen has successfully created a shim for redis-check-aof.exe
ShimGen has successfully created a shim for redis-check-dump.exe
ShimGen has successfully created a shim for redis-cli.exe
ShimGen has successfully created a shim for redis-server.exe
The install of redis-64 was successful.
Software install location not explicitly set, could be in package or
default install location if installer.
Chocolatey installed 1/1 packages.
See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).
Copy the code
Enter redis-server to start the server:
After running the program, we use redis-cli to view:
We see that myKey is a list, and every time a log comes in, a new entry is added to the list.
conclusion
This article introduces the basic usage of Logrus. Logrus has great scalability, allowing for the introduction of third-party formats and Hook enhancements. It’s also popular in the community.
reference
- Logrus making warehouse
- Hooks
I
My blog
Welcome to follow my wechat public account [GoUpUp], learn together, progress together ~
This article is published by OpenWrite!