This is a creation in Article, where the information may have evolved or changed.
Glog Introduction
Glog is the Golang version of the famous Google open-source C + + log library Glog, Glog is a lightweight log library, easy to use without configuration files and stable and efficient, but there is less content to customize the control. Glog mainly has the following characteristics:
- Glog has four log levels of info < waring < ERROR < FATAL, different levels of logs are printed to different files, and low-level log files (INFO) contain high-level log information (ERROR)
- The command-line pass parameter--log_dir specifies the storage directory for the log file, which defaults to the OS. TempDir ()
- You can cut log files based on file size, but you cannot cut log files by date
- The log output format is fixed (LMMDD hh:mm:ss.uuuuuu threadid file:line] msg ...) Can not be customized
- You need to call flag at the beginning of the program. Parse () parses the command-line arguments and calls Glog when the program exits. Flush () ensures that the contents of the buffer are output to a file.
Use cases
func main() { //初始化命令行参数 flag.Parse() //退出时调用,确保日志写入文件中 defer glog.Flush() glog.Info("hello, glog") glog.Warning("warning glog") glog.Error("error glog") glog.Infof("info %d", 1) glog.Warningf("warning %d", 2) glog.Errorf("error %d", 3) }//假设编译后的可执行程序名为demo,运行时指定log_dir参数将日志文件保存到特定的目录// ./demo --log_dir=./log
SOURCE Analysis
We follow the Glog in the case code. Error ("Error Glog") This line of code to see how the log content is exported to the file.
Func Error (args ... interface{}) {Logging.print (errorlog, args ...)} Errorlog is a glog-defined log level tag, and the underlying is a int32 type variable type severity Int32 const (infoLog severity = Iota Warninglog errorlog Fatallog numseverity = 4)//The error function is actually just a layer of simple encapsulation, actually called the Loggering object's print function, loggering is a loggingt type of global variable func (l *loggi NgT) print (s severity, args ... interface{}) {l.printdepth (S, 1, args ...)} PrintDepth can specify the call hierarchy of the output log stack func (l *loggingt) printdepth (s severity, depth int, args ... interface{}) {//header constructs the formatted additional information LMMDD hh:mm:ss.uuuuuu ThreadID File:line],glog in this process to do a lot of optimization, specific view of the source//header function from a freelist to take the buffer object, If it does not exist, a new buffer object is created, and after the use is finished, call Putbuffer to put buffer back into freelist buf, file, line: = L.header (s, depth) fmt. Fprint (buf, args ...) If buf. Bytes () [BUF. Len ()-1]! = ' \ n ' {buf. WriteByte (' \ n ')} l.output (S, buf, file, line, False)}func (l *loggingt) output (s severity, buf *buffer, file string , line int, alsotostderr bool) {data: = buf. Bytes ()//glog creates a different log file for each level of log, when the log is printedFirst make sure that the level of the log file already exists if l.file[s] = = Nil {if err: = L.createfiles (s); Err! = nil {os. Stderr.write (data) L.exit (ERR)}}//glog will print high-level log information to a low-level log file//Remove Fallthrough in the code snippet, you can implement the Err The or log is only output to the error file, and does not continue to output to the info-level log file in switch s {case Fatallog:l.file[fatallog]. Write (data) Fallthrough case Errorlog:l.file[errorlog]. Write (data) Fallthrough case Warninglog:l.file[warninglog]. Write (data) Fallthrough case Infolog:l.file[infolog]. Write (data)} if s = = Fatallog {//If it is fatal log information, exit the program OS. Exit (255)}//Put the used buffer object into the buffer pool L.putbuffer (BUF)}//loggingt.file is an array of Flushsyncwriter interface types, in Glog the actual object is Syncbuffe R,syncbuffer encapsulates the underlying write file operation, adding buffers to avoid overly frequent system calls to improve the write log efficiency of type Syncbuffer struct {*bufio. Writer file *os. File SEv Severity nbytes UInt64//The number of bytes written to this file}//will determine if the log file has exceeded the specified maximum size, if it is exceeded, to create a new The log file//log content is written first to the in-memory sb. Writer = bufIo. Newwritersize (Sb.file, BufferSize) func (SB *syncbuffer) Write (P []byte) (n int, err error) {if Sb.nbytes+uint64 (Len (P) ) >= MaxSize {if err: = Sb.rotatefile (time. Now ()); Err! = Nil {sb.logger.exit (err)}} N, err = sb. Writer.write (p) sb.nbytes + = UInt64 (n) return}//We output the log content by calling the Syncbuffer.write function, but when is the contents of the Syncbuffer buffer output to the file? The/glog init function will open a goroutine timed call to Flushsyncwriter's flush function to brush the in-memory log contents into the file func init () {go Logging.flushdaemon ()}func (l *LOGGINGT) Flushdaemon () {For _ = range time. Newticker (Flushinterval). C {for S: = Fatallog; s >= infoLog; s--{file: = l.file[s] If file! = Nil {file. Flush () file. Sync ()}}}
Vlog Introduction
A typical log library provides the log output level, which is not output when the level of the log information is lower than the output level. Log is used when we use other log libraries. Debug () Print out debugging information, in the test environment, the output level of the log library is set to debug, debugging information will be output so that we can see the specific operation of the program, and the online program will be the output level of the log is set to info debug information will not be output. Glog in another way to achieve this function, Glog provides users with the ability to customize the grading information, the user-defined rating and Glog with the log level (INFO ERROR) is completely separate, in the command line parameter settings to set the "V" or "vmodule" parameter to control.
if glog.V(1) { glog.Info("Starting transaction...")}glog.V(1).Infoln("Processed", nItems, "elements")
In the test environment, when we run the program, we specify a user-defined level of 1 (--v=1), and the above log information is output. In the online environment, the specified custom level is 0 (--v=0), and the above log information is not output.
func init(){ flag.Var(&logging.verbosity, "v", "log level for V logs")}type Verbose boolfunc V(level Level) Verbose { if logging.verbosity.get() >= level { return Verbose(true) } return Verbose(false)}func (v Verbose) Info(args ...interface{}) { if v { logging.print(infoLog, args...) }}
Modify Glog Source code
Glog some features and our common log library is not the same or do not have the function we expect, you can modify the Glog source code to achieve our needs. For example, we used the log library is the debug INFO ERROR fatal level, we can modify the Glog source code to increase the debug level, delete Warn level, has been consistent with our original system. Specific changes to view GitHub source code
set the output implementation principle of the level control log : Define an output level variable, provide an interface to the user can set the value of the variable, the default is info, in the output log when the log information level is greater than the output level, if greater than the output log information otherwise not output
var outputSeverity severity//outputLevel 必须为INFO ERROR等字符串,否则panic//SetLevelString 不是线程安全的,主要是因为我都是在程序开启时在主进程中调用一次SetLevelString函数,而不会在程序运行中随意调用func SetLevelString(outputLevel string) { severity, ok := severityByName(outputLevel) if !ok { panic(fmt.Errorf("unknown severity name %s", outputLevel)) } outputSeverity = severity}func (l *loggingT) println(s severity, args ...interface{}) { if s < outputSeverity { return } buf, file, line := l.header(s, 0) fmt.Fprintln(buf, args...) l.output(s, buf, file, line, false)}//用户在测试环境下调用 SetLevelString("DEBUG")则调试信息能够正常输出到文件中,而在线上环境下调用SetLevelString("INFO")屏蔽调试信息
Automatically cut log files every day
Implementation principle: When the log file is created, the date when the file was created (MMDD), the output of each log information to determine whether the current date is consistent with the log file creation date, if inconsistent, create a new log file.
func init () {flag. Boolvar (&logging.dailyrolling, "dailyrolling", false, "weather to handle log files daily")} func (SB *syncbuff ER) Write (P []byte) (n int, err error) {if logging.dailyrolling {if sb.createddate! = string (P[1:5]) { If err: = Sb.rotatefile (time. Now ()); Err! = Nil {sb.logger.exit (ERR)}}}//write log information}func (SB *syncbuffer) Rotatefile (now Time. Time) Error {sb.createddate = FMT. Sprintf ("%02d%02d", month, day)//Create new log file}