Go Language Practical Notes (18) | Go log Log

Source: Internet
Author: User
Tags log log blizzard
This is a creation in Article, where the information may have evolved or changed.

"Go language Combat" reading notes, not to be continued, welcome to sweep code attention flysnow_org to the public or website http://www.flysnow.org/, the first time to see follow-up notes. If you feel helpful, share it with your friends and thank you for your support.

After we develop the program, if there are some problems need to debug the program, the log is necessary, this is our analysis program problems commonly used means.

Log usage

Log analysis, is based on the output of the log information, analysis of the potential problems of mining, we use fmt.Println series functions can also achieve the purpose, because they can also be the information we need to output to the terminal or other files. But fmt.Println the series function output of the system is relatively simple, such as no time, there is no source code lines, etc., for us to troubleshoot problems, missing a lot of information.

In this respect, the go language provides us with a standard log package to track log records. Let's look at log the use of log packages.

1234
func Main ()  {log. Println ("Blizzard Ruthless Blog:", "http://www.flysnow.org") log. Printf ("Blizzard ruthless public Number:%s\n","flysnow_org")}

It is very simple to use, and the function name and usage is fmt similar to the package, but its output is time stamped by default.

12
2017/04/29 13:18:44 Blizzard Ruthless blog: http://www.flysnow.org2017/04/29 13:18:44 Blizzard Ruthless public number: flysnow_org

So we know very clearly, the time to log these logs, which is very useful for us to troubleshoot problems.

With time, we also want more information, the inevitable occurrence of source code line number, etc., for this log package log provides us with a customizable configuration, so that we can customize the log header information.

123
 funcinit()  {log. SetFlags (log. Ldate|log. Lshortfile)}

We use the function init , this function main can be initialized before the function executes, can help us to do some configuration, here we custom log header information is time + file name + source code line number. log.Ldate|log.Lshortfilethat is, the middle is a bitwise operator | , which is then set by the function log.SetFlags . Now let's run a look at the output log.

12
*/// Main.  go:Blizzard Ruthless blog: http://www.flysnow.org//(main). go:One: Blizzard ruthless public number: flysnow_org

More than the previous example, the source file and the line number, but the time is missing, this is the result of our custom. Now let's look at the log packages that provide us with the option constants that can be defined.

 123456789 
 const  (Ldate = 1  << iota  //date example: 2009/01/23  ltime //time example : 01:23:23  lmicroseconds //ms Example: 01:23:23.123123.  Llongfile //absolute path and line number:/a/b/c/d.go:23  lshortfile //file and line number: D.go:23.  LUTC //date time converted to 0 time zone  lstdflags = Ldate | Ltime //go provides standard header information ) 

This is a log package to define some of the header information, there are date, time, millisecond time, absolute path and line number, file name and line number, and so on, there are comments on the above, it should be noted that: if set Lmicroseconds , then Ltime it does not take effect Lshortfile , set, and Llongfile will not take effect, We can test it for ourselves.

LUTCVery special, if we configure the time tag, then if set LUTC , it will be the output date time to 0 time zone of the date and time display.

1
Log. SetFlags (log. Ldate|log. Ltime |log. LUTC)

So for the time of our East eight, we subtract 8 hours, we look at the output:

12
2017/04/29 05:46:29 Blizzard Ruthless blog: http://www.flysnow.org2017/04/29 05:46:29 Blizzard Ruthless public number: flysnow_org

The last one that LstdFlags represents the standard log header is the default, including the date and time.

Most of us have a lot of business, every business need to log, then there is no way to differentiate these businesses? This makes it much easier for us to find the logs.

In this case, the Go language also helps us to consider, this is to set the log prefix, such as a User Center system log, we can set this.

1234
func Init (){log. Setprefix ("usercenter") log. SetFlags (log. Lstdflags | Log. Lshortfile |log. LUTC)}

By log.SetPrefix specifying the prefix of the output log, which we specify as 【UserCenter】 , we can then see that the printout of the log clearly marks the business of our logs.

12
"Usercenter" 2017/04/29 05:53:26 main.go:11: Blizzard Ruthless blog: http://www.flysnow.org "Usercenter" 2017/04/29 05:53:26 main.go : 12: Blizzard ruthless public number: flysnow_org

logPackage In addition to a Print series of functions, Fatal as well as a Panic series of functions, which indicates that the Fatal program encountered a fatal error, need to exit, Fatal when the log is used, then the program exits, that is, the Fatal equivalent of calling Print the print log first, The exit program is then called os.Exit(1) .

Panicthe same is true of the same series of functions, which means that the Print log is used first, and then the calling panic() function throws a panic, and unless recover() the function is used, the program prints the error stack information and the program terminates.

The source code of these series of functions is put down here for better understanding.

 func  println  Span class= "params" > (v ... interface  {})   {std. Output (2 , FMT. Sprintln (v ...))} func  fatalln   (v ... interface  {})   {std. Output (2 , FMT. Sprintln (v ...)) Os. Exit (1 )}func  panicln   (v ... interface  {})   {s: = FMT. Sprintln (v ...) Std.
Output (2 , s) panic  (s)} 
 1234567891011121314 

Implementation principle

Through the source code above, we found that the log packet log of these functions are similar, the key output log is the std.Output method.

12345
func New  stringint) *Logger  {return &logger{out:out, Prefix:prefix, Flag:flag}}var"" , Lstdflags)

From the above source code can be seen, the variable std is actually a *Logger , through the log.New function creation, the default output to the os.Stderr device, the prefix is empty, the log header information is the standard header LstdFlags .

os.StderrThe output device corresponding to the standard error warning information in UNIX is also used as the default log output destination. For the first time, there are standard output devices os.Stdout as well as standard input devices os.Stdin .

12345
var (Stdin  = NewFile (uintptr"/dev/stdin") Stdout = NewFile (uintptr"/dev/stdout" ) Stderr = NewFile (uintptr"/dev/stderr"))

The above is the standard three devices defined for UNIX, respectively, for input, output, and warning error messages. Understand os.Stderr , now we look at Logger this structure, the information and operation of the log, all through this Logger operation.

 1234567 
 type  Logger struct  {mu sync. Mutex //ensures atomic writes; protects the following fields  prefix  String  //prefix to write at beginning of all line  flag in T  //properties  out IO. Writer //destination for output  buf []byte  //for accumulating text to write } 
    1. The field mu is a mutex, mainly to ensure that this logger is Logger also safe under multiple goroutine.
    2. Field prefix is the prefix for each row of logs
    3. Field flag is log header information
    4. The field out is the destination of the log output, which is by default os.Stderr .
    5. The field buf is a log output text buffer, which will eventually be written out in.

"Go language Combat" reading notes, not to be continued, welcome to sweep code attention flysnow_org to the public or website http://www.flysnow.org/, the first time to see follow-up notes. If you feel helpful, share it with your friends and thank you for your support.

Understanding the structure Logger of the field, you can now look at its most important method Output , this method will output the formatted good log information.

12345678910111213141516171819202122232425262728293031
 func (l *logger) Output(calldepth int, s string)  Error {Now: = time. Now ()//Get this early.varFilestringvarLineint//locking to ensure safety under multiple GoroutineL.mu.lock ()deferL.mu.unlock ()//If get file and line number are configuredifl.flag& (lshortfile| Llongfile)! =0{//Because of runtime. Caller price is relatively large, first without lockingL.mu.unlock ()varOkBOOL_, file, line, OK = runtime. Caller (calldepth)if!ok {file ="???"line =0}//Get the line number and other information, and then lock to ensure securityL.mu.lock ()}//Stitching Our log information and settings log headerL.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 ')}//Output splicing good buffer buf log information to the destination_, Err: = L.out.write (L.BUF)returnErr

The entire code is relatively concise, in order to multi-goroutine security mutex is also used, but in the acquisition of the call stack information, the first time to unlock, because this process is heavier. After obtaining information such as file, line number and so on, continue to add the mutex to ensure security.

The following is relatively simple, the formatHeader Main method is to format the log header information, and then stored in buf the buffer, and finally put our own log information to the buf back of the buffer, and then for the log output to append a newline character, so that each log output is a row of one line.

With the final log information buf , and then write it to the output of the destination out , which is a type of implementation of the io.Writer interface, as long as the implementation of this interface, can be used as the output destination.

12345
func (l *logger) Setoutput (w io.) Writer)  {l.mu.lock ()defer l.mu.unlock () l.out = w}

logThe function of the package SetOutput , you can set the output destination. This is a little bit easier to describe runtime.Caller , and it can get the invocation information of the runtime method.

1
func Caller  int)  uintptrstringintbool)

skipthe parameter represents the number of skipped stack frames, which means that 0 the caller is not skipped runtime.Caller . 1is to go up one level, indicating the caller's caller.

The log log is used in the package 2 , which means that we call in the source code log.Print , and the log.Fatal log.Panic callers of these functions.

In the main case of a function call log.Println , main->log.Println->*Logger.Output->runtime.Caller This is a method call stack, so at this point, the value of skip represents:

    1. 0Represents *Logger.Output runtime.Caller The source code file and line number that is called in
    2. 1Represents log.Println *Logger.Output The source code file and line number that is called in
    3. 2Represents main log.Println The source code file and line number that is called in

So that's log why the value of this bag skip is always 2 the reason.

Customize your own logs

Through the above source analysis, we know that the root of the log is a logger Logger , so we customize their own log, in fact, is to create a different Logger .

1234567891011121314151617181920212223
var(Info *log. Loggerwarning *log. Loggererror * log. Logger) func init() {Errfile,err:=os. OpenFile ("Errors.log", OS. O_create|os. O_wronly|os. O_append,0666)iferr!=Nil{log. Fatalln ("Failed to open log file:", err)}info = log. New (OS. Stdout,"Info:", log. Ldate | Log. Ltime | Log. Lshortfile) Warning = log. New (OS. Stdout,"Warning:", log. Ldate | Log. Ltime | Log. Lshortfile) Error = log. New (IO. Multiwriter (OS. Stderr,errfile),"Error:", log. Ldate | Log. Ltime | Log. Lshortfile)} func main() {Info.println ("Blizzard Ruthless blog:","http://www.flysnow.org") warning.printf ("Blizzard ruthless public Number:%s\n","flysnow_org") Error.println ("Welcome to follow the message")}

We defined three different logger based on the log level, respectively, for Info the Warning Error output of different levels of logging. These three types of loggers are log.New created using functions.

When the logger is created here, Info and Warning both are normal, Error there are multiple destination outputs, where you can simultaneously output the error log to the os.Stderr file we created errors.log .

io.MultiWriterThe function can wrap multiple io.Writer for one io.Writer , so that we can achieve the same io.Writer purpose for multiple output logs simultaneously.

io.MultiWriterImplementation is also simple, define a type implementation io.Writer , and then loop through the implemented method Write to invoke the multiple interfaces to be wrapped Writer Write .

 12345678910111213 
 func   (t *multiwriter)  write   (p []byte )   (n int , err Error)   {for  _, W: = range  t.writers {n, err = W.write (p) if  err! = nil  {return }if  n! = len  (p) {err = Errshortwritereturn }}return  len  (p), nil } 

Here we define a number of logger to distinguish between different log levels, the use of more trouble, in this case, you can use the third-party log framework, you can also customize the wrapper definition, directly through different levels of methods to record different levels of the log, you can set the level of logging and so on.

"Go language Combat" reading notes, not to be continued, welcome to sweep code attention flysnow_org to the public or website http://www.flysnow.org/, the first time to see follow-up notes. If you feel helpful, share it with your friends and thank you for your support.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.