Golang \u7684 log \u5305\u4e3b\u8981\u63d0\u4f9b\u4e86\u4ee5\u4e0b\u51e0\u4e2a\u5177\u5907\u8f93\u51fa\u529f\u80fd\u7684\u51fd\u6570\uff1a<\/p>\n
\r\nfunc Fatal(v ...interface{}) \r\nfunc Fatalf(format string, v ...interface{}) \r\nfunc Fatalln(v ...interface{}) \r\nfunc Panic(v ...interface{}) \r\nfunc Panicf(format string, v ...interface{}) \r\nfunc Panicln(v ...interface{}) \r\nfunc Print(v ...interface{}) \r\nfunc Printf(format string, v ...interface{}) \r\nfunc Println(v ...interface{}) \r\n<\/pre>\n\u8fd9\u4e9b\u51fd\u6570\u7684\u4f7f\u7528\u65b9\u6cd5\u548c fmt \u5305\u5b8c\u5168\u76f8\u540c\uff0c\u901a\u8fc7\u67e5\u770b\u6e90\u7801\u53ef\u4ee5\u53d1\u73b0\uff0cFatal[ln|f] \u548c Panic[ln|f] \u5b9e\u9645\u4e0a\u662f\u8c03\u7528\u7684 Print[ln|f]\uff0c\u800c Print[ln|f] \u5b9e\u9645\u4e0a\u662f\u8c03\u7528\u7684 Output() \u51fd\u6570\u3002<\/p>\n
\u5176\u4e2d Fatal[ln|f] \u662f\u8c03\u7528 Print[ln|f] \u4e4b\u540e\uff0c\u53c8\u8c03\u7528\u4e86 os.Exit(1) \u9000\u51fa\u7a0b\u5e8f\u3002<\/p>\n
\u5176\u4e2d Panic[ln|f] \u662f\u8c03\u7528 Panic[ln|f] \u4e4b\u540e\uff0c\u53c8\u8c03\u7528\u4e86 panic() \u51fd\u6570\uff0c\u629b\u51fa\u4e00\u4e2a\u6050\u614c\u3002<\/p>\n
\u6240\u4ee5\uff0c\u6211\u4eec\u5f88\u6709\u5fc5\u8981\u9605\u8bfb\u4e00\u4e0b Output() \u51fd\u6570\u7684\u6e90\u7801\u3002<\/p>\n
\u51fd\u6570 Output() \u7684\u6e90\u7801\uff1a<\/p>\n
\r\nfunc (l *Logger) Output(calldepth int, s string) error { \r\n now := time.Now() \/\/ get this early. \r\n var file string \r\n var line int \r\n l.mu.Lock() \r\n defer l.mu.Unlock() \r\n if l.flag&(Lshortfile|Llongfile) != 0 { \r\n \/\/ Release lock while getting caller info - it's expensive. \r\n l.mu.Unlock() \r\n var ok bool \r\n _, file, line, ok = runtime.Caller(calldepth) \r\n if !ok { \r\n file = \"???\" \r\n line = 0 \r\n } \r\n l.mu.Lock() \r\n } \r\n l.buf = l.buf[:0] \r\n l.formatHeader(&l.buf, now, file, line) \r\n l.buf = append(l.buf, s...) \r\n if len(s) == 0 || s[len(s)-1] != '\\n' { \r\n l.buf = append(l.buf, '\\n') \r\n } \r\n _, err := l.out.Write(l.buf) \r\n return err \r\n} \r\n<\/pre>\n\u901a\u8fc7\u9605\u8bfb Output() \u51fd\u6570\u7684\u6e90\u7801\uff0c\u53ef\u4ee5\u53d1\u73b0\u4f7f\u7528\u4e92\u65a5\u9501\u6765\u4fdd\u8bc1\u591a\u4e2a goroutine \u5199\u65e5\u5fd7\u7684\u5b89\u5168\uff0c\u5e76\u4e14\u5728\u8c03\u7528 runtime.Caller() \u51fd\u6570\u4e4b\u524d\uff0c\u5148\u91ca\u653e\u4e92\u65a5\u9501\uff0c\u83b7\u53d6\u5230\u4fe1\u606f\u540e\u518d\u52a0\u4e0a\u4e92\u65a5\u9501\u6765\u4fdd\u8bc1\u5b89\u5168\u3002<\/p>\n
\u4f7f\u7528 formatHeader() \u51fd\u6570\u6765\u683c\u5f0f\u5316\u65e5\u5fd7\u7684\u4fe1\u606f\uff0c\u7136\u540e\u4fdd\u5b58\u5230 buf \u4e2d\uff0c\u7136\u540e\u518d\u628a\u65e5\u5fd7\u4fe1\u606f\u8ffd\u52a0\u5230 buf \u7684\u672b\u5c3e\uff0c\u7136\u540e\u518d\u901a\u8fc7\u5224\u65ad\uff0c\u67e5\u770b\u65e5\u5fd7\u662f\u5426\u4e3a\u7a7a\u6216\u672b\u5c3e\u4e0d\u662f \\n\uff0c\u5982\u679c\u662f\u5c31\u518d\u628a \\n \u8ffd\u52a0\u5230 buf \u7684\u672b\u5c3e\uff0c\u6700\u540e\u5c06\u65e5\u5fd7\u4fe1\u606f\u8f93\u51fa\u3002<\/p>\n
\u51fd\u6570 Output() \u7684\u6e90\u7801\u4e5f\u6bd4\u8f83\u7b80\u5355\uff0c\u5176\u4e2d\u6700\u503c\u5f97\u6ce8\u610f\u7684\u662f runtime.Caller() \u51fd\u6570\uff0c\u6e90\u7801\u5982\u4e0b\uff1a<\/p>\n
\r\nfunc Caller(skip int) (pc uintptr, file string, line int, ok bool) { \r\n rpc := make([]uintptr, 1) \r\n n := callers(skip+1, rpc[:]) \r\n if n < 1 { \r\n return \r\n } \r\n frame, _ := CallersFrames(rpc).Next() \r\n return frame.PC, frame.File, frame.Line, frame.PC != 0 \r\n} \r\n<\/pre>\n\u901a\u8fc7\u9605\u8bfb runtime.Caller() \u51fd\u6570\u7684\u6e90\u7801\uff0c\u53ef\u4ee5\u53d1\u73b0\u5b83\u63a5\u6536\u4e00\u4e2a int \u7c7b\u578b\u7684\u53c2\u6570 skip\uff0c\u8be5\u53c2\u6570\u8868\u793a\u8df3\u8fc7\u6808\u5e27\u6570\uff0clog \u5305\u4e2d\u7684\u8f93\u51fa\u529f\u80fd\u7684\u51fd\u6570\uff0c\u4f7f\u7528\u7684\u9ed8\u8ba4\u503c\u90fd\u662f 2\uff0c\u539f\u56e0\u662f\u4ec0\u4e48?<\/p>\n
\u4e3e\u4f8b\u8bf4\u660e\uff0c\u6bd4\u5982\u5728 main \u51fd\u6570\u4e2d\u8c03\u7528 log.Print\uff0c\u65b9\u6cd5\u8c03\u7528\u6808\u4e3a main->log.Print->*Logger.Output->runtime.Caller\uff0c\u6240\u4ee5\u6b64\u65f6\u53c2\u6570 skip \u7684\u503c\u4e3a 2\uff0c\u8868\u793a main \u51fd\u6570\u4e2d\u8c03\u7528 log.Print \u7684\u6e90\u6587\u4ef6\u548c\u4ee3\u7801\u884c\u53f7;<\/p>\n
\u53c2\u6570\u503c\u4e3a 1\uff0c\u8868\u793a log.Print \u51fd\u6570\u4e2d\u8c03\u7528 *Logger.Output \u7684\u6e90\u6587\u4ef6\u548c\u4ee3\u7801\u884c\u53f7;\u53c2\u6570\u503c\u4e3a 0\uff0c\u8868\u793a *Logger.Output \u51fd\u6570\u4e2d\u8c03\u7528 runtime.Caller \u7684\u6e90\u6587\u4ef6\u548c\u4ee3\u7801\u884c\u53f7\u3002<\/p>\n
\u81f3\u6b64\uff0c\u6211\u4eec\u53d1\u73b0 log \u5305\u7684\u8f93\u51fa\u529f\u80fd\u7684\u51fd\u6570\uff0c\u5168\u90e8\u90fd\u662f\u628a\u4fe1\u606f\u8f93\u51fa\u5230\u63a7\u5236\u53f0\uff0c\u90a3\u4e48\u8be5\u600e\u4e48\u5c06\u4fe1\u606f\u8f93\u51fa\u5230\u6587\u4ef6\u4e2d\u5462?<\/p>\n
\u51fd\u6570 SetOutPut \u5c31\u662f\u7528\u6765\u8bbe\u7f6e\u8f93\u51fa\u76ee\u6807\u7684\uff0c\u6e90\u7801\u5982\u4e0b\uff1a<\/p>\n
\r\nfunc SetOutput(w io.Writer) { \r\n std.mu.Lock() \r\n defer std.mu.Unlock() \r\n std.out = w \r\n} \r\n<\/pre>\n\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u51fd\u6570 os.OpenFile \u6765\u6253\u5f00\u4e00\u4e2a\u7528\u4e8e I\/O \u7684\u6587\u4ef6\uff0c\u8fd4\u56de\u503c\u4f5c\u4e3a\u51fd\u6570 SetOutput \u7684\u53c2\u6570\u3002<\/p>\n
\u9664\u6b64\u4e4b\u5916\uff0c\u8bfb\u8005\u5e94\u8be5\u8fd8\u53d1\u73b0\u4e86\u4e00\u4e2a\u95ee\u9898\uff0c\u8f93\u51fa\u4fe1\u606f\u90fd\u662f\u4ee5\u65e5\u671f\u548c\u65f6\u95f4\u5f00\u5934\uff0c\u6211\u4eec\u8be5\u600e\u4e48\u8bb0\u5f55\u66f4\u52a0\u4e30\u5bcc\u7684\u4fe1\u606f\u5462?\u6bd4\u5982\u6e90\u6587\u4ef6\u548c\u884c\u53f7\u3002<\/p>\n
\u8fd9\u5c31\u7528\u5230\u4e86\u51fd\u6570 SetFlags\uff0c\u5b83\u53ef\u4ee5\u8bbe\u7f6e\u8f93\u51fa\u7684\u683c\u5f0f\uff0c\u6e90\u7801\u5982\u4e0b\uff1a<\/p>\n
\r\nfunc SetFlags(flag int) { \r\n std.SetFlags(flag) \r\n} \r\n<\/pre>\n\u53c2\u6570 flag \u7684\u503c\u53ef\u4ee5\u662f\u4ee5\u4e0b\u4efb\u610f\u5e38\u91cf\uff1a<\/p>\n
\r\nconst ( \r\n Ldate = 1 << iota \/\/ the date in the local time zone: 2009\/01\/23 \r\n Ltime \/\/ the time in the local time zone: 01:23:23 \r\n Lmicroseconds \/\/ microsecond resolution: 01:23:23.123123. assumes Ltime. \r\n Llongfile \/\/ full file name and line number: \/a\/b\/c\/d.go:23 \r\n Lshortfile \/\/ final file name element and line number: d.go:23. overrides Llongfile \r\n LUTC \/\/ if Ldate or Ltime is set, use UTC rather than the local time zone \r\n Lmsgprefix \/\/ move the \"prefix\" from the beginning of the line to before the message \r\n LstdFlags = Ldate | Ltime \/\/ initial values for the standard logger \r\n) \r\n<\/pre>\n\u5176\u4e2d Ldate\u3001Ltime \u548c Lmicroseconds \u5206\u522b\u8868\u793a\u65e5\u671f\u3001\u65f6\u95f4\u548c\u5fae\u79d2\uff0c\u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u5982\u679c\u8bbe\u7f6e Lmicroseconds\uff0c\u90a3\u4e48\u8bbe\u7f6e Ltime\uff0c\u4e5f\u4e0d\u4f1a\u751f\u6548\u3002<\/p>\n
\u5176\u4e2d Llongfile \u548c Lshortfile \u5206\u522b\u4ee3\u7801\u7edd\u5bf9\u8def\u5f84\u3001\u6e90\u6587\u4ef6\u540d\u3001\u884c\u53f7\uff0c\u548c\u4ee3\u7801\u76f8\u5bf9\u8def\u5f84\u3001\u6e90\u6587\u4ef6\u540d\u3001\u884c\u53f7\uff0c\u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u5982\u679c\u8bbe\u7f6e Lshortfile\uff0c\u90a3\u4e48\u5373\u4f7f\u8bbe\u7f6e Llongfile\uff0c\u4e5f\u4e0d\u4f1a\u751f\u6548\u3002<\/p>\n
\u5176\u4e2d LUTC \u8868\u793a\u8bbe\u7f6e\u65f6\u533a\u4e3a UTC \u65f6\u533a\u3002<\/p>\n
\u5176\u4e2d LstdFlags \u8868\u793a\u6807\u51c6\u8bb0\u5f55\u5668\u7684\u521d\u59cb\u503c\uff0c\u5305\u542b\u65e5\u671f\u548c\u65f6\u95f4\u3002<\/p>\n
\u622a\u6b62\u5230\u73b0\u5728\uff0c\u8fd8\u7f3a\u5c11\u70b9\u4e1c\u897f\uff0c\u5c31\u662f\u65e5\u5fd7\u4fe1\u606f\u7684\u524d\u7f00\uff0c\u6bd4\u5982\u6211\u4eec\u9700\u8981\u533a\u5206\u65e5\u5fd7\u4fe1\u606f\u4e3a DEBUG\u3001INFO \u548c ERROR\u3002\u662f\u7684\uff0c\u6211\u4eec\u8fd8\u6709\u4e00\u4e2a\u51fd\u6570 SetPrefix \u53ef\u4ee5\u5b9e\u73b0\u6b64\u529f\u80fd\uff0c\u6e90\u7801\u5982\u4e0b\uff1a<\/p>\n
\r\nfunc SetPrefix(prefix string) { \r\n std.SetPrefix(prefix) \r\n} \r\n<\/pre>\n\u51fd\u6570 SetPrefix \u63a5\u6536\u4e00\u4e2a string \u7c7b\u578b\u7684\u53c2\u6570\uff0c\u7528\u6765\u8bbe\u7f6e\u65e5\u5fd7\u4fe1\u606f\u7684\u524d\u7f00\u3002<\/p>\n
03\u3001Logger<\/strong><\/div>\nlog \u5305\u5b9a\u4e49\u4e86\u4e00\u4e2a\u5305\u542b\u5f88\u591a\u65b9\u6cd5\u7684\u7c7b\u578b Logger\u3002\u6211\u4eec\u901a\u8fc7\u67e5\u770b\u8f93\u51fa\u529f\u80fd\u7684\u51fd\u6570\uff0c\u53d1\u73b0\u5b83\u4eec\u90fd\u662f\u8c03\u7528 std.Output\uff0cstd \u662f\u4ec0\u4e48?\u6211\u4eec\u67e5\u770b log \u5305\u7684\u6e90\u7801\u3002<\/p>\n
\r\ntype Logger struct { \r\n mu sync.Mutex \/\/ ensures atomic writes; protects the following fields \r\n prefix string \/\/ prefix on each line to identify the logger (but see Lmsgprefix) \r\n flag int \/\/ properties \r\n out io.Writer \/\/ destination for output \r\n buf []byte \/\/ for accumulating text to write \r\n} \r\n \r\nfunc New(out io.Writer, prefix string, flag int) *Logger { \r\n return &Logger{out: out, prefix: prefix, flag: flag} \r\n} \r\n \r\nvar std = New(os.Stderr, \"\", LstdFlags) \r\n<\/pre>\n\u901a\u8fc7\u9605\u8bfb\u6e90\u7801\uff0c\u6211\u4eec\u53d1\u73b0 std \u5b9e\u9645\u4e0a\u662f Logger \u7c7b\u578b\u7684\u4e00\u4e2a\u5b9e\u4f8b\uff0cOutput \u662f Logger \u7684\u4e00\u4e2a\u65b9\u6cd5\u3002<\/p>\n
std \u901a\u8fc7 New \u51fd\u6570\u521b\u5efa\uff0c\u53c2\u6570\u5206\u522b\u662f os.Stderr\u3001\u7a7a\u5b57\u7b26\u4e32\u548c LstdFlags\uff0c\u5206\u522b\u8868\u793a\u6807\u51c6\u9519\u8bef\u8f93\u51fa\u3001\u7a7a\u5b57\u7b26\u4e32\u524d\u7f00\u548c\u65e5\u671f\u65f6\u95f4\u3002<\/p>\n
Logger \u7c7b\u578b\u7684\u5b57\u6bb5\uff0c\u6ce8\u91ca\u5df2\u7ecf\u8bf4\u660e\u4e86\uff0c\u8fd9\u91cc\u5c31\u4e0d\u518d\u8d58\u8ff0\u4e86\u3002<\/p>\n
\u81ea\u5b9a\u4e49 Logger\uff1a<\/p>\n
\r\nfunc main () { \r\n logFile, err := os.OpenFile(\"error1.log\", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0755) \r\n if err != nil { \r\n fmt.Println(err) \r\n return \r\n } \r\n defer logFile.Close() \r\n logs := DefinesLogger(logFile, \"\", log.LstdFlags|log.Lshortfile) \r\n logs.Debug(\"message\") \r\n logs.Debugf(\"%s\", \"content\") \r\n} \r\n \r\n\/\/ \u81ea\u5b9a\u4e49 logger \r\ntype Logger struct { \r\n definesLogger *log.Logger \r\n} \r\n \r\ntype Level int8 \r\n \r\nconst( \r\n LevelDebug Level = iota \r\n LevelInfo \r\n LevelError \r\n) \r\n \r\nfunc (l Level) String() string { \r\n switch l { \r\n case LevelDebug: \r\n return \" [debug] \" \r\n case LevelInfo: \r\n return \" \" \r\n case LevelError: \r\n return \" [error] \" \r\n } \r\n return \"\" \r\n} \r\n \r\nfunc DefinesLogger(w io.Writer, prefix string, flag int) *Logger { \r\n l := log.New(w, prefix, flag) \r\n return &Logger{definesLogger: l} \r\n} \r\n \r\nfunc (l *Logger) Debug(v ...interface{}) { \r\n l.definesLogger.Print(LevelDebug, fmt.Sprint(v...)) \r\n} \r\n \r\nfunc (l *Logger) Debugf(format string, v ...interface{}) { \r\n l.definesLogger.Print(LevelDebug, fmt.Sprintf(format, v...)) \r\n} \r\n \r\nfunc (l *Logger) Info(v ...interface{}) { \r\n l.definesLogger.Print(LevelInfo, fmt.Sprint(v...)) \r\n} \r\n \r\nfunc (l *Logger) Infof(format string, v ...interface{}) { \r\n l.definesLogger.Print(LevelInfo, fmt.Sprintf(format, v...)) \r\n} \r\n \r\nfunc (l *Logger) Error(v ...interface{}) { \r\n l.definesLogger.Print(LevelError, fmt.Sprint(v...)) \r\n} \r\n \r\nfunc (l *Logger) Errorf(format string, v ...interface{}) { \r\n l.definesLogger.Print(LevelError, fmt.Sprintf(format, v...)) \r\n} \r\n<\/pre>\n04\u3001\u603b\u7ed3<\/strong><\/div>\n\u672c\u6587\u4e3b\u8981\u4ecb\u7ecd Golang \u8bed\u8a00\u7684\u6807\u51c6\u5e93\u4e2d\u7684 log \u5305\uff0c\u5305\u62ec log \u5305\u7684\u51fd\u6570\u548c\u81ea\u5b9a\u4e49\u7c7b\u578b logger \u7684\u4f7f\u7528\u65b9\u6cd5\u548c\u4e00\u4e9b\u7ec6\u8282\u4e0a\u7684\u6ce8\u610f\u4e8b\u9879\u3002\u5f00\u7bc7\u4e5f\u63d0\u5230\u4e86\uff0clog \u5305\u4e0d\u652f\u6301\u65e5\u5fd7\u6587\u4ef6\u7684\u5207\u5272\uff0c\u6211\u4eec\u9700\u8981\u81ea\u5df1\u7f16\u7801\u53bb\u5b9e\u73b0\uff0c\u6216\u8005\u4f7f\u7528\u4e09\u65b9\u5e93\uff0c\u6bd4\u5982 lumberjack\u3002\u5728\u751f\u4ea7\u73af\u5883\u4e2d\uff0c\u4e00\u822c\u6bd4\u8f83\u5c11\u7528 log \u5305\u6765\u8bb0\u5f55\u65e5\u5fd7\uff0c\u901a\u5e38\u4f1a\u4f7f\u7528\u4e09\u65b9\u5e93\u6765\u8bb0\u5f55\u65e5\u5fd7\uff0c\u6bd4\u5982 zap \u548c logrus \u7b49\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"
Golang \u8bed\u8a00\u7684\u6807\u51c6\u5e93\u4e2d\u63d0\u4f9b\u4e86\u4e00\u4e2a\u7b80\u5355\u7684 log \u65e5\u5fd7\u5305\uff0c\u5b83\u4e0d\u4ec5\u63d0\u4f9b\u4e86\u5f88\u591a\u51fd\u6570\uff0c\u8fd8\u5b9a\u4e49\u4e86\u4e00\u4e2a\u5305\u542b\u5f88\u591a\u65b9\u6cd5\u7684 […]<\/p>\n","protected":false},"author":1898,"featured_media":210744,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[55],"tags":[646],"class_list":["post-210741","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-thread","tag-golang"],"acf":[],"_links":{"self":[{"href":"https:\/\/gulass.cn\/wp-json\/wp\/v2\/posts\/210741","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gulass.cn\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gulass.cn\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gulass.cn\/wp-json\/wp\/v2\/users\/1898"}],"replies":[{"embeddable":true,"href":"https:\/\/gulass.cn\/wp-json\/wp\/v2\/comments?post=210741"}],"version-history":[{"count":6,"href":"https:\/\/gulass.cn\/wp-json\/wp\/v2\/posts\/210741\/revisions"}],"predecessor-version":[{"id":210750,"href":"https:\/\/gulass.cn\/wp-json\/wp\/v2\/posts\/210741\/revisions\/210750"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/gulass.cn\/wp-json\/wp\/v2\/media\/210744"}],"wp:attachment":[{"href":"https:\/\/gulass.cn\/wp-json\/wp\/v2\/media?parent=210741"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gulass.cn\/wp-json\/wp\/v2\/categories?post=210741"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gulass.cn\/wp-json\/wp\/v2\/tags?post=210741"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}