How to play GO log
Last time we shared GO’s timer timer and timed task cron
, let’s review:
- What is Timer
- How to use Timer
- What is Ticker
- How to use Ticker
- What is cron
- How to use cron
If you want to know the answer to the above question, welcome to check the article GO Timer Timer and timing task cron
Today, let’s take a look at the log package log
Specific source code path: src/log/log.go
How to simply use log package
Let’s take a look at using the log
package in the editor. What are the hints?
At first glance, log
package. They are not complicated at all. The methods are as shown in the figure above.
Let's use a small case, and then look at the data structure
package main
import "log"
func main() {
log.Println("小魔童打日志 ... ")
test := "Hello wrold "
// Printf 有格式控制符
log.Printf("%s 小魔童打日志 ... \n", test)
log.Fatalln("小魔童 打日志,触发了 Fatal")
log.Panicln("小魔童 打日志,触发了 Panic")
}
Run the above code, the effect is as follows:
2021/06/xx xx:25:53 小魔童打日志 ...
2021/06/xx xx:25:53 Hello wrold 小魔童打日志 ...
2021/06/xx xx:25:53 小魔童 打日志,触发了 Fatal
exit status 1
The date, time, and printed content can be printed by default
How to configure log and the corresponding principle
Use GO
inside this log
package, we use the default log
it is certainly not enough, for example, the log of the small print of cases, you do not know specifically which line of code to print out, and print settings to log which log files Inside, wait
Let's take a look at how to configure log
, starting from the creation of logger
Create a new logger
Let's add a prefix to the basic log
func main() {
// 打印到标准输出上
myLog := log.New(os.Stdout, "<XMT>", log.Lshortfile|log.Ldate|log.Ltime)
myLog.Println("小魔童打印了带有前缀的日志 ... ")
}
The implementation effect is as follows:
<XMT>2021/06/28 12:35:47 main.go:20: 小魔童打印了带有前缀的日志 ...
Let's take a look at the specific implementation of the log.New
Specific source code path: src/log/log.go
func New(out io.Writer, prefix string, flag int) *Logger {
return &Logger{out: out, prefix: prefix, flag: flag}
}
It can be seen that the func New(out io.Writer, prefix string, flag int) *Logger
method actually calls the Logger
data structure, let’s take a look
// A Logger represents an active logging object that generates lines of
// output to an io.Writer. 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 sync.Mutex // ensures atomic writes; protects the following fields
prefix string // prefix on each line to identify the logger (but see Lmsgprefix)
flag int // properties
out io.Writer // destination for output
buf []byte // for accumulating text to write
}
type Logger struct
has the above members. It seems that each parameter is easy to understand. You can basically know the meaning according to the member name.
- mu sync.Mutex
Lock to ensure atomic operation
- prefix string
The prefix of each log line
- out io.Writer
The output location can be a file or standard output
- buf []byte
Buffer
- flag int
Specific attributes, we can see from the source code, there are several options for specific attributes as follows
These parameters are used to control the details of the log output, such as time, number of lines of code, prefix, etc.
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
)
The comments written in the source code are still very clear. What exactly each field does, and what effect will be after using it, is clear at a glance according to this comment.
We can check the source code to know why in the above small case, the date, time, and specific content are output by default in the log, because the log
package will default to New
for our default use
Here var std = New(os.Stderr, "", LstdFlags)
New needs to be filled with attributes, and LstdFlags
LstdFlags = Ldate | Ltime // initial values for the standard logger
LstdFlags
attributes, the default is to print the date and time
// Println calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Println.
func (l *Logger) Println(v ...interface{}) { l.Output(2, fmt.Sprintln(v...)) }
(l *Logger) Println
for specific output, calling (l *Logger) Output
// Output writes the output for a logging event. The string s contains
// the text to print after the prefix specified by the flags of the
// Logger. A newline is appended if the last character of s is not
// already a newline. Calldepth is used to recover the PC and is
// provided for generality, although at the moment on all pre-defined
// paths it will be 2.
func (l *Logger) Output(calldepth int, s string) error {
now := time.Now() // get this early.
var file string
var line int
l.mu.Lock()
defer l.mu.Unlock()
if l.flag&(Lshortfile|Llongfile) != 0 {
// Release lock while getting caller info - it's expensive.
l.mu.Unlock()
var ok bool
_, file, line, ok = runtime.Caller(calldepth)
if !ok {
file = "???"
line = 0
}
l.mu.Lock()
}
l.buf = l.buf[:0]
l.formatHeader(&l.buf, now, file, line)
l.buf = append(l.buf, s...)
if len(s) == 0 || s[len(s)-1] != '\n' {
l.buf = append(l.buf, '\n')
}
_, err := l.out.Write(l.buf)
return err
}
func (l *Logger) Output(calldepth int, s string) error {
function does the following things:
- Concatenate log string data
- Output to
out
, whereout
is standard output by default, or you can set the output to a file by yourself
Configure a logger
Let's use log
to set the output log to the file
func main() {
logFile, err := os.OpenFile("./XMT.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
fmt.Println("os.OpenFile error :", err)
return
}
// 设置输出位置 ,里面有锁进行控制
log.SetOutput(logFile)
// 设置日志属性
log.SetFlags(log.Llongfile | log.Ltime | log.Ldate)
// 打印日志
log.Println("小魔童的 新 日志 ... ")
// 手动设置前缀
log.SetPrefix("【重点】")
log.Println("小魔童的重要日志...")
}
Run the above code, the effect is as follows:
2021/06/28 12:57:14 D:/mycode/my_new_first/my_log/main.go:36: 小魔童的 新 日志 ...
【重点】2021/06/28 12:57:14 D:/mycode/my_new_first/my_log/main.go:40: 小魔童的重要日志...
log.SetOutput
log.SetOutput
actually calledLogger
correspondingfunc (l *Logger) SetOutput(w io.Writer)
method
func (l *Logger) SetOutput(w io.Writer) {
l.mu.Lock()
defer l.mu.Unlock()
l.out = w
}
log.SetFlags
log.SetFlags
actually calledLogger
correspondingSetFlags
method
SetPrefix
is the same reason
// SetFlags sets the output flags for the logger.
// The flag bits are Ldate, Ltime, and so on.
func (l *Logger) SetFlags(flag int) {
l.mu.Lock()
defer l.mu.Unlock()
l.flag = flag
}
Summarize
- How to use the
log
package log
package principle and specific implementation- Custom log
Welcome to like, follow, favorite
Friends, writing is not easy
Your support and encouragement are my motivation to keep sharing and improve quality
Well, that’s it for this time, GO unit test and performance test sharing
Technology is open, and our mindset should be more open. Embrace the change, live toward the sun, and work hard to move forward.
I am Nezha , welcome to like and follow the collection, see you next time~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。