SoFunction
Updated on 2025-03-05

How to use log packages in Go

introduction:

Logging is important in our daily programming. As long as we write the code, there may be bugs. Log files are a way to quickly find these bugs and better understand the working status of the program.

Let's take a look at the definition of the log file:

Log filesIs a file that records events or messages between different users of the communication software that occur during the operation of the operating system or other software. Recording is the act of saving logs.

Logs are the eyes and ears of developers that can be used to track, locate errors, debug and analyze code, and monitor application performance. In the simplest case, messages are written to a single log file.

Go language standard library log package

Because logging is important, the Go language standard library provides​log​​ package, we can make some simple configurations for logs, and we can customize a set of our own loggers.

In Golang​log​​ package implements a simple logging package. It defines a type, a Logger, and a method for formatting the output. It also has a predefined "standard" logger that can be accessed through helper functions​Print[f|ln]​​、​​Fatal[f|ln]​and​Panic[f|ln]​Access, they are easier to use than creating a logger manually.

Basic log entries include: prefix, date and timestamp, which source file is recorded by the log, the line where the source file records the log, and finally the log message. Let's take a look at the simple use​log​Package: The message when the 0 is divided during division operation returns to the program instead of directly exiting the program.

package main
import (
"errors"
"fmt"
"log"
)
func myDiv(x float64, y float64) (float64, error) {
if y == 0 {
return 0, ("The dividend cannot be 0")
}
return x / y, nil
}
func main() {
var x float64 = 128.2
var y float64
res, err := myDiv(x, y)
if err != nil {
(err) // Print Write to standard logger}
(res)
}

Run the program:

$ go run
2022/04/19 23:18:06 Divisor cannot be 0
0

In the above program, we imported three packages:​errors​​ 、​​fmt​​、​​log​​ 。

Then used​log​​ In the package​Print​Function: At this time the logger will write standard errors and print the date and time of each logged message, which is very useful in general. Each log message has an output on a separate line: if the message being printed does not end on a new line, the logger will add a line.

In addition,​log​​ In the package​Fatal​The function is called after writing a log message ​​(1)​​。

func main() {
var x float64 = 128.2
var y float64
res, err := myDiv(x, y)
if err != nil {
(err) // After calling Print(), it will be called (1)}
(res)
}
// 2022/04/19 23:22:44 The dividend cannot be 0// exit status 1

And​Panic​The function is called after writing a log message ​​panic​, unless the program executes​recover()​​ function, otherwise it will cause the program to terminate after printing the call stack.

func main() {
var x float64 = 128.2
var y float64
res, err := myDiv(x, y)
if err != nil {
(err) // Panic will call Print() and then use panic()}
(res)
}

Running results:

2022/04/19 23:24:18 The dividend cannot be 0
panic: The dividend cannot be 0

goroutine 1 [running]:
({0xc000086f60?, 0xc000086f70?, 0x404f99?})
/usr/local/go/src/log/:385 +0x65
()
/home/wade/go/src/logLearning/:26 +0x65
exit status 2

From this we can see that​Print​Series functions are the standard method for writing log messages.

How to store log messages in a file in Go

In the above code, simply printing the log message to the console is far from enough, because the console is real-time, and if the console log message is closed, it will be closed.

Given that we have learned how Go language can read files, we can store log messages in a file and store all logs in that file.

package main
import (
"errors"
"fmt"
"log"
"os"
)
func myDiv(x float64, y float64) (float64, error) {
if y == 0 {
return 0, ("The dividend cannot be 0")
}
return x / y, nil
}
func main() {
var x float64 = 128.2
var y float64
res, exception := myDiv(x, y)
file, err := ("", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
if err != nil {
(err)
}
defer () // Close the file(file)
(exception)
(res)
}

Run the code:

$ go run
0

In addition, we will find that there is an additional created in the directory​​​ File. Open the file and you will see something like the one below printed out.

Customize your logger

To create a custom logger, we need to create a​Logger​​ Type structure, and then configure each logger with an output destination, prefix, and flag. And each logger is multiple goroutines safe, each​Logger​​ Structures have a mutex, meaning that multiple goroutines can call these functions from the same logger at the same time without writing conflicts with each other. Let's take a look ​​Logger​​ The underlying implementation of the structure:

Logger structure

// A Logger represents an active logging object that generates lines of
// output to an . Each logging operation makes a single call to
// the Writer's Write method. A Logger can be used simultaneously from
// multiple goroutines; it guarantees to serialize access to the Writer.
type Logger struct {
mu  // ensures atomic writes; protects the following fields
prefix string // prefix on each line to identify the logger (but see Lmsgprefix)
flag int // properties
out  // destination for output
buf []byte // for accumulating text to write
}

Then let's look at a sample program:

package main
import (
"io"
"io/ioutil"
"log"
"os"
)
var (
Trace * // Record all logsInfo * // Important informationWarning * // Warning messageError * // error message)
func init() {
file, err := ("", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
("Failed to open error log file: ", err)
}
Trace = (,
"Trace: ", ||)
Info = (, "Info: ", ||)
Warning = (, "Warning: ", ||)
Error = ((file, ), "Error: ", ||)
}
func main() {
("hello")
("Information")
("Warning")
("Error")
}

Running results:

Info: 2022/04/20 00:37:34 :36: Information
Warning: 2022/04/20 00:37:34 :37: Warning
Error: 2022/04/20 00:37:34 :38: Error

Use​log​Packed​New​Function, create and initialize a value of type Logger, and then​New​The function returns the address of the newly created value.

New function

func New(out , prefix string, flag int) *Logger {
return &Logger{out: out, prefix: prefix, flag: flag
}
  • The first parameter of the New functionoutSpecifies the destination to be written to the log, and the value passed in this parameter must be implemented.Interface
  • The second parameterprefixIt will appear at the beginning of each row of logs generated
  • The third parameterflagDefine what attributes are included in the log

In this program:

  • Trace logger is usedioutilThe Discard variable in the package is used as the destination to write. All Writer calls will not have any action, but will return successfully. When a level of log is not important, the Discard variable can be used to disable the level of logs.
  • Loggers Info and Warning both use stdout as log output.
  • Logging the first parameter of the New function in Error is used.MultiWriterFunction, this function call will return aThe value of the interface type, which contains the file file that was opened before and stderr. This function is a variable parameter function that can accept any implementation.The value of the interface will be passed inBinding together. When writing this return value, it will be bound to all theValues ​​are written. This enables output to multiple Writers. The advantage of this is that when logging using the Error logger,The output will be written to the file and stderr at the same time

Summarize

Golang​log​The implementation of the package is based on long-term practice and accumulation of the need to record logs. For example, write the output to​stdout​, log the log to​stderr​​, this is also a method used by many programs based on command line interfaces.

The first thing to do when writing a log is to find a perfect library. Then, after you have selected the log library, you also need to plan where to call the logger in your code, how to store the logs, how to make them available at any given time, and how to analyze them.

The best practice for Go logging is to call custom loggers from the main application process, not in goroutines. At the same time, log messages in the application should be written to the local file to be permanently saved. At the same time, reminders should be given for error information, which is convenient for timely location and processing.

This is the end of this article about how to use log packages in Go. For more related contents of Go using log packages, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!