The log package defines the Logger type, which provides methods for formatting output. This package also provides a predefined "standard" logger, which can be used by calling the functions Print series (Print|Printf|Println), Fatal series (Fatal|Fatalf|Fatalln), and Panic series (Panic|Panicf|Panicln) , which is easier to use than creating a logger object yourself.
Logger
package main import ( "log" ) func main() { log.Println("This is a test log.") v := "very common" log.Printf("This is a %s log.\n", v) log.Fatalln("This is a log that will trigger fatal.") log.Panicln("This is a log that will trigger a panic.") }
Standard logger configuration
The SetFlags function is used to set the output configuration of the standard logger.
const ( // Control the details of the output log information, but cannot control the order and format of the output. // The output log will be separated by a colon after each item: for example, 2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message Ldate = 1 << iota // date: 2009/01/23 Ltime // Time: 01:23:23 Lmicroseconds // Time at the microsecond level: 01:23:23.123123 (used to enhance the Ltime bit) Llongfile // Full file path name + line number: /a/b/c/d.go:23 Lshortfile// file name + line number: d.go:23 (will overwrite Llongfile) LUTC // use UTC time LstdFlags = Ldate | Ltime // Initial value of standard logger )
func main() { log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate) log.Println("This is a very common log.") }
Configure the log prefix (SetPrefix)
func main() { log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate) log.Println("This is a very common log.") log.SetPrefix("[hahaha]") log.Println("This is a very common log.") }
Configure the log output location
The SetOutput function is used to set the output destination of the standard logger, and the default is the standard error output.
func init() { logFile, err := os.OpenFile("./xx.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) if err != nil { fmt.Println("open log file failed, err:", err) return } log.SetOutput(logFile) log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate) }
create new logger object
The log standard library also provides a constructor for creating a new logger object - New, which supports us to create our own logger examples. The signature of the New function is as follows:
func New(out io.Writer, prefix string, flag int) *Logger
New creates a Logger object. Among them, the parameter out sets the destination where the log information is written. The parameter prefix will be added to the front of each generated log. The parameter flag defines the attributes of the log (time, file, etc.).
for example:
func main() { logger := log.New(os.Stdout, "<New>", log.Lshortfile|log.Ldate|log.Ltime) logger.Println("This is the log recorded by the custom logger.") } //<New>2017/06/19 14:06:51 main.go:34: This is the log recorded by the custom logger.
Supplement: Go's built-in log library has limited functions. For example, it cannot meet the needs of recording logs of different levels. You need to choose a third-party log library, such as logrus, zap, etc.
log library level
package log import ( "errors" "fmt" "strings" "time" ) type LogLevel uint16 // log constant const ( UNKNOW LogLevel = iota DEBUG TRACE INFO WARNIG ERROR FATAL ) // parse log level func paraLogLevel(s string) (LogLevel,error) { s = strings.ToLower(s) switch s { case "debug": return DEBUG,nil case "tarce": return TRACE,nil case "info": return INFO,nil case "warnig": return WARNIG,nil case "error": return ERROR,nil case "fatal": return FATAL,nil default: err:= errors.New("Invalid log level") return UNKNOW,err } } //Define the log level mechanism type Logger struct{ Level LogLevel } //constructor func NewLog(levelLog string) Logger { level, err := paraLogLevel(levelLog) if err !=nil{ panic(err) } return Logger{ Level: level, } } //Whether it is possible to print a certain level of log func (l Logger) enable(logLevel LogLevel) bool { return l.Level >logLevel } func (l Logger) Debug(msg string) { if l.enable(DEBUG){ now := time.Now() fmt.Printf("[%s] [Debug] %s",now.Format("2006-01-02 15:04:05"),msg); } } func (l Logger) Info(msg string) { if l.enable(INFO){ now := time.Now() fmt.Printf("[%s] [Info] %s",now.Format("2006-01-02 15:04:05"),msg); } } func (l Logger) Warning(msg string) { if l.enable(WARNIG){ now := time.Now() fmt.Printf("[%s] [Warning] %s",now.Format("2006-01-02 15:04:05"),msg); } } func (l Logger) Error(msg string) { if l.enable(ERROR){ now := time.Now() fmt.Printf("[%s] [Error] %s",now.Format("2006-01-02 15:04:05"),msg); } } func (l Logger) Fatal(msg string) { if l.enable(FATAL){ now := time.Now() fmt.Printf("[%s] [Fatal] %s",now.Format("2006-01-02 15:04:05"),msg); } }
import "gostudy/log" func main() { newLog := log.NewLog("warnig") newLog.Debug("This is the debug log") newLog.Info("This is the info log") newLog.Warning("This is a Warning log") newLog.Error("This is the ERROR log") newLog.Fatal("This is a FATAL log") }
Print result: [2022-08-04 10:41:56] [Debug] This is the debug log [2022-08-04 10:41:56] [Info] This is the info log
runtime.Caller
Can get the file name function name and line number variadic log //......interface{} represents any variable parameter, which can be passed without or with any length func (l Logger) Debug(msg string, a ...interface{}) { msg = fmt.Sprint(msg,a) if l.enable(DEBUG){ now := time.Now() fmt.Printf("[%s] [Debug] %s",now.Format("2006-01-02 15:04:05"),msg); } } Realize writing logs to the file 1.new build fileloger.go file, used to provide the function of writing to the log package log import ( "errors" "fmt" "os" "path" "strings" "time" ) type LogLevel uint16 //log level const ( UNKNOW LogLevel = iota DEBUG TRACE INFO WARNIG ERROR FATAL ) //parsing log func paraLogLevel(s string) (LogLevel,error) { s = strings.ToLower(s) switch s { case "debug": return DEBUG,nil case "tarce": return TRACE,nil case "info": return INFO,nil case "warnig": return WARNIG,nil case "error": return ERROR,nil case "fatal": return FATAL,nil default: err:= errors.New("invalid log level") return UNKNOW,err } } //Get the string format of the log func getLogStr (level LogLevel) string { switch level { case DEBUG: return "debug" case TRACE: return "tarce" case INFO: return "info" case WARNIG: return "warnig" case ERROR: return "error" case FATAL: return "fatal" default: return "unknow" } } //Define the structure of the log type FileLogger struct{ Level LogLevel filePath string fileName string //Files to open and write to, a log file and an error log file fileObj *os.File errfileObj *os.File maxFileSize int64 } //Constructor func NewFlieLogger(LeveStr ,fp,fn string,size int64) *FileLogger{ level, err := paraLogLevel(LeveStr) if err != nil { panic(err) } f1 := &FileLogger{ Level: level, filePath: fp, fileName: fn, maxFileSize: size, } err= f1.initFile() if err != nil { panic(err) } return f1 } //Operation that initializes the log file to be opened and written func (f *FileLogger) initFile() (error) { join := path.Join(f.filePath, f.fileName) fileObj, err := os.OpenFile(join, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { fmt.Printf("open log fail ,err: %v\n",err) return err } errFileObj, err := os.OpenFile(join+".err", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { fmt.Printf("open log fail ,err: %v\n",err) return err } //log files are open f.fileObj = fileObj; f.errfileObj = errFileObj; return nil } //judgment level func (l FileLogger) enable(logLevel LogLevel) bool { return l.Level >logLevel } //print log operation func (f *FileLogger) Log(leve LogLevel,msg string) { now := time.Now() if f.enable(leve){ fmt.Fprintf(f.fileObj,"[%s] [%s] %s",now.Format("2006-01-02 15:04:05"),getLogStr(leve),msg); } if leve >ERROR{ fmt.Fprintf(f.errfileObj,"[%s] [%s] %s",now.Format("2006-01-02 15:04:05"),getLogStr(leve),msg); } } func (l FileLogger) Debug(msg string, a ...interface{}) { msg = fmt.Sprint(msg,a) if l.enable(DEBUG){ l.Log(DEBUG,msg) } } func (l FileLogger) Info(msg string, a ...interface{}) { msg = fmt.Sprint(msg,a) if l.enable(WARNIG){ l.Log(WARNIG,msg) } } func (l FileLogger) Warning(msg string, a ...interface{}) { msg = fmt.Sprint(msg,a) if l.enable(WARNIG){ l.Log(WARNIG,msg) } } func (l FileLogger) Error(msg string, a ...interface{}) { msg = fmt.Sprint(msg,a) if l.enable(ERROR){ l.Log(ERROR,msg) } } func (l FileLogger) Fatal(msg string, a ...interface{}) { msg = fmt.Sprint(msg,a) if l.enable(FATAL){ l.Log(FATAL,msg) } } func (f *FileLogger) Colse() { f.fileObj.Close() f.errfileObj.Close() } 2.test: func main() { newLog := log.NewFlieLogger("warnig","./","now.log",100*1024*1024) newLog.Debug("This is debug log") newLog.Info("This is info log") newLog.Warning("This is Warning log") newLog.Error("This is ERROR log") newLog.Fatal("This is FATAL log") newLog.Colse() } //After running it twice, print the result:
Log cutting (cutting by file size, cutting by date)
In fact, every time the size of the record file is exceeded, a new file will be written.
Get some information about the file through the Stat() function
open, _:= os.Open("file name") stat, _, := open.Stat() stat.Size()//Get the file size
Date cut:
Get the name of the file or check if there is a log file of the day, if not, create a new one.