$ mkdir logging-frameworks && cd logging-frameworks
$ cat > native.go <<EOF
package main
import "log"
func main() {
log.Println("Hello world!")
log.Debug("Debugging is fun")
log.Info("Something is interesting!")
log.Warn("Something bad may come!")
log.Error("Something must be wrong!")
log.Fatal("OMG!")
}
EOF
$ go run native.go
INFO[0000] Hello world!
INFO[0000] Something is interesting!
WARN[0000] Something bad may come!
ERRO[0000] Something must be wrong!
FATA[0000] OMG!
exit status 1
The code above prints the text "Hello world!" to the standard error, but it also includes the date and time, which is handy for filtering log messages by date.
Logging to a File
A file named logs.txt will be created with content:
You can basically output your logs to any destination that implements the io.Writer interface, so you have a lot of flexibility when deciding where to log messages in your application.
Creating custom loggers
Output in logs.txt:
Log flags
There are log flags we can use to enhance the logs:
So:
Community Logging Frameworks
Surprisingly, there is a long list of community logging frameworks, with different design philosophies. Let's name some of the popular ones
As logrus is fully compliant to Golang's standard logging APIs, it can be very easy to get started:
Logging in JSON
Log levels
Unlike the standard log package, logrus supports log levels.
We will get:
Notice that the Debug level message was not printed. To include it in the logs, set log level to equal log.DebugLevel:
Logging Method Name
Using Fields
Default Fields
Often it's helpful to have fields always attached to log statements in an application or parts of one. For example, you may want to always log the request_id and user_ip in the context of a request. Instead of writing log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip}) on every line, you can create a logrus.Entry to pass around instead:
We got this -- note that only user activity logs logged with extra fields:
package main
import (
"log"
"os"
)
var (
WarningLogger *log.Logger
InfoLogger *log.Logger
ErrorLogger *log.Logger
)
func init() {
file, err := os.OpenFile("logs.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
log.Fatal(err)
}
InfoLogger = log.New(file, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
WarningLogger = log.New(file, "WARNING: ", log.Ldate|log.Ltime|log.Lshortfile)
ErrorLogger = log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)
}
func main() {
InfoLogger.Println("Starting the application...")
InfoLogger.Println("Something noteworthy happened")
WarningLogger.Println("There is something you should know about")
ErrorLogger.Println("Something went wrong")
}
INFO: 2021/03/14 22:14:06 custom-logger.go:26: Starting the application...
INFO: 2021/03/14 22:14:06 custom-logger.go:27: Something noteworthy happened
WARNING: 2021/03/14 22:14:06 custom-logger.go:28: There is something you should know about
ERROR: 2021/03/14 22:14:06 custom-logger.go:29: Something went wrong
const (
Ldate = 1 << iota // the date in the local time zone: 2009/01/23
Ltime // the time in the local time zone: 01:23:23
Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime.
Llongfile // full file name and line number: /a/b/c/d.go:23
Lshortfile // final file name element and line number: d.go:23. overrides Llongfile
LUTC // if Ldate or Ltime is set, use UTC rather than the local time zone
Lmsgprefix // move the "prefix" from the beginning of the line to before the message
LstdFlags = Ldate | Ltime // initial values for the standard logger
)
$ cat > logrus-getstarted.go <<EOF
package main
import (
log "github.com/sirupsen/logrus"
)
func main() {
log.Println("Hello world!")
}
EOF
# Starting from golang v1.16, let's enable module if not running in GOPATH
$ go mod init github.com/brightzheng100/logging-frameworks
$ go mod tidy
go: finding module for package github.com/sirupsen/logrus
go: found github.com/sirupsen/logrus in github.com/sirupsen/logrus v1.8.1
go: downloading golang.org/x/sys v0.0.0-20191026070338-33540a1f6037
$ go run logrus-getstarted.go
INFO[0000] Hello world!
...
log.Trace("Something very low level.")
log.Debug("Useful debugging information.")
log.Info("Something noteworthy happened!")
log.Warn("You should probably take a look at this.")
log.Error("Something failed but I'm not quitting.")
// Calls os.Exit(1) after logging
log.Fatal("Bye.")
// Calls panic() after logging
log.Panic("I'm bailing.")
}
{"level":"info","msg":"Something noteworthy happened!","time":"2021-03-14T22:49:08+08:00"}
{"level":"warning","msg":"You should probably take a look at this.","time":"2021-03-14T22:49:08+08:00"}
{"level":"error","msg":"Something failed but I'm not quitting.","time":"2021-03-14T22:49:08+08:00"}
{"level":"fatal","msg":"Bye.","time":"2021-03-14T22:49:08+08:00"}
exit status 1
requestLogger := log.WithFields(log.Fields{
"user_id": "u1234",
"tx_id": "t0001",
})
requestLogger.Info("user activity")
log.Warn("You should probably take a look at this.")
log.Error("Something failed but I'm not quitting.")
{"level":"info","msg":"user activity","time":"2021-03-15T12:48:09+08:00","tx_id":"t0001","user_id":"u1234"}
{"level":"warning","msg":"You should probably take a look at this.","time":"2021-03-15T12:48:09+08:00"}
{"level":"error","msg":"Something failed but I'm not quitting.","time":"2021-03-15T12:48:09+08:00"}
package main
import (
"io/ioutil"
"os"
log "github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/writer"
)
func main() {
log.SetOutput(ioutil.Discard) // Send all logs to nowhere by default
log.AddHook(&writer.Hook{ // Send logs with level higher than warning to stderr
Writer: os.Stderr,
LogLevels: []log.Level{
log.PanicLevel,
log.FatalLevel,
log.ErrorLevel,
log.WarnLevel,
},
})
log.AddHook(&writer.Hook{ // Send info and debug logs to stdout
Writer: os.Stdout,
LogLevels: []log.Level{
log.InfoLevel,
log.DebugLevel,
},
})
log.Info("This will go to stdout")
log.Warn("This will go to stderr")
}
$ go run logrus-hooks.go
time="2021-03-15T13:59:37+08:00" level=info msg="This will go to stdout"
time="2021-03-15T13:59:37+08:00" level=warning msg="This will go to stderr"