2019-02-02 16:18:25 +08:00
|
|
|
|
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
2018-04-19 16:24:48 +08:00
|
|
|
|
//
|
|
|
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
|
|
|
// If a copy of the MIT was not distributed with this file,
|
2019-02-02 16:18:25 +08:00
|
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
2019-04-17 23:50:37 +08:00
|
|
|
|
//
|
2018-08-30 00:00:15 +08:00
|
|
|
|
// @author john, zseeker
|
2018-04-19 16:24:48 +08:00
|
|
|
|
|
|
|
|
|
package glog
|
|
|
|
|
|
|
|
|
|
import (
|
2019-05-21 21:52:17 +08:00
|
|
|
|
"bytes"
|
2019-05-15 23:53:48 +08:00
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"github.com/gogf/gf/g/os/gfile"
|
|
|
|
|
"github.com/gogf/gf/g/os/gfpool"
|
|
|
|
|
"github.com/gogf/gf/g/os/gtime"
|
|
|
|
|
"github.com/gogf/gf/g/text/gregex"
|
|
|
|
|
"io"
|
|
|
|
|
"os"
|
|
|
|
|
"runtime"
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
2018-04-19 16:24:48 +08:00
|
|
|
|
)
|
|
|
|
|
|
2018-10-09 21:41:07 +08:00
|
|
|
|
type Logger struct {
|
2019-05-21 21:52:17 +08:00
|
|
|
|
parent *Logger // Parent logger.
|
|
|
|
|
writer io.Writer // Customized io.Writer.
|
|
|
|
|
flags int // Extra flags for logging output features.
|
|
|
|
|
path string // Logging directory path.
|
|
|
|
|
file string // Format for logging file.
|
|
|
|
|
level int // Output level.
|
|
|
|
|
prefix string // Prefix string for every logging content.
|
|
|
|
|
btSkip int // Skip count for backtrace.
|
|
|
|
|
btStatus int // Backtrace status(1: enabled - default; 0: disabled)
|
|
|
|
|
headerPrint bool // Print header or not(true in default).
|
|
|
|
|
stdoutPrint bool // Output to stdout or not(true in default).
|
2018-10-09 21:41:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-04-19 16:24:48 +08:00
|
|
|
|
const (
|
2018-10-09 21:41:07 +08:00
|
|
|
|
gDEFAULT_FILE_FORMAT = `{Y-m-d}.log`
|
2018-04-19 16:24:48 +08:00
|
|
|
|
gDEFAULT_FILE_POOL_FLAGS = os.O_CREATE|os.O_WRONLY|os.O_APPEND
|
2018-11-11 14:24:04 +08:00
|
|
|
|
gDEFAULT_FPOOL_PERM = os.FileMode(0666)
|
|
|
|
|
gDEFAULT_FPOOL_EXPIRE = 60000
|
2018-04-19 16:24:48 +08:00
|
|
|
|
)
|
|
|
|
|
|
2019-05-21 21:52:17 +08:00
|
|
|
|
const (
|
2019-05-21 23:57:03 +08:00
|
|
|
|
F_FILE_LONG = 1 << iota // Print full file name and line number: /a/b/c/d.go:23.
|
|
|
|
|
F_FILE_SHORT // Print final file name element and line number: d.go:23. overrides F_FILE_LONG.
|
|
|
|
|
F_TIME_DATE // Print the date in the local time zone: 2009-01-23.
|
|
|
|
|
F_TIME_TIME // Print the time in the local time zone: 01:23:23.
|
|
|
|
|
F_TIME_MILLI // Print the time with milliseconds in the local time zone: 01:23:23.675.
|
2019-05-21 21:52:17 +08:00
|
|
|
|
F_TIME_STD = F_TIME_DATE | F_TIME_MILLI
|
|
|
|
|
)
|
|
|
|
|
|
2018-10-18 13:43:00 +08:00
|
|
|
|
var (
|
2019-04-17 23:50:37 +08:00
|
|
|
|
// Default line break.
|
2019-05-21 21:52:17 +08:00
|
|
|
|
ln = "\n"
|
2018-10-18 13:43:00 +08:00
|
|
|
|
)
|
2018-05-23 16:41:21 +08:00
|
|
|
|
|
|
|
|
|
func init() {
|
2019-04-17 23:50:37 +08:00
|
|
|
|
// Initialize log line breaks depending on underlying os.
|
2018-05-23 16:41:21 +08:00
|
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
|
ln = "\r\n"
|
2018-05-24 15:50:35 +08:00
|
|
|
|
}
|
2018-05-23 16:41:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-17 23:50:37 +08:00
|
|
|
|
// New creates and returns a custom logger.
|
2018-08-28 17:06:49 +08:00
|
|
|
|
func New() *Logger {
|
2019-04-17 23:50:37 +08:00
|
|
|
|
logger := &Logger {
|
2019-05-21 21:52:17 +08:00
|
|
|
|
file : gDEFAULT_FILE_FORMAT,
|
2019-05-21 23:57:03 +08:00
|
|
|
|
flags : F_TIME_STD,
|
2019-05-22 09:19:21 +08:00
|
|
|
|
level : LEVEL_ALL,
|
2019-05-21 21:52:17 +08:00
|
|
|
|
btStatus : 1,
|
|
|
|
|
headerPrint : true,
|
|
|
|
|
stdoutPrint : true,
|
2018-08-24 23:41:58 +08:00
|
|
|
|
}
|
2019-05-21 21:52:17 +08:00
|
|
|
|
// Default writer
|
2019-04-18 09:11:14 +08:00
|
|
|
|
logger.writer = &Writer {
|
2019-04-17 23:50:37 +08:00
|
|
|
|
logger : logger,
|
|
|
|
|
}
|
|
|
|
|
return logger
|
2018-08-24 23:41:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-20 11:16:10 +08:00
|
|
|
|
// Clone returns a new logger, which is the clone the current logger.
|
2018-08-28 17:06:49 +08:00
|
|
|
|
func (l *Logger) Clone() *Logger {
|
2019-04-17 23:50:37 +08:00
|
|
|
|
logger := &Logger {
|
2019-05-21 21:52:17 +08:00
|
|
|
|
parent : l,
|
|
|
|
|
path : l.path,
|
|
|
|
|
file : l.file,
|
|
|
|
|
level : l.level,
|
|
|
|
|
flags : l.flags,
|
|
|
|
|
prefix : l.prefix,
|
|
|
|
|
btSkip : l.btSkip,
|
|
|
|
|
btStatus : l.btStatus,
|
|
|
|
|
headerPrint : l.headerPrint,
|
|
|
|
|
stdoutPrint : l.stdoutPrint,
|
|
|
|
|
}
|
|
|
|
|
// Default writer
|
2019-04-18 09:11:14 +08:00
|
|
|
|
logger.writer = &Writer {
|
2019-04-17 23:50:37 +08:00
|
|
|
|
logger : logger,
|
|
|
|
|
}
|
|
|
|
|
return logger
|
2018-08-24 23:41:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-20 11:16:10 +08:00
|
|
|
|
// SetLevel sets the logging level.
|
2018-08-30 13:00:49 +08:00
|
|
|
|
func (l *Logger) SetLevel(level int) {
|
2019-05-21 21:52:17 +08:00
|
|
|
|
l.level = level
|
2018-08-30 13:00:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-20 11:16:10 +08:00
|
|
|
|
// GetLevel returns the logging level value.
|
2018-08-30 13:54:45 +08:00
|
|
|
|
func (l *Logger) GetLevel() int {
|
2019-05-21 21:52:17 +08:00
|
|
|
|
return l.level
|
2018-08-30 13:54:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-20 11:16:10 +08:00
|
|
|
|
// SetDebug enables/disables the debug level for logger.
|
2019-04-17 23:50:37 +08:00
|
|
|
|
// The debug level is enabled in default.
|
2018-08-30 13:00:49 +08:00
|
|
|
|
func (l *Logger) SetDebug(debug bool) {
|
2018-09-18 21:29:31 +08:00
|
|
|
|
if debug {
|
2019-05-21 21:52:17 +08:00
|
|
|
|
l.level = l.level | LEVEL_DEBU
|
2018-09-18 21:29:31 +08:00
|
|
|
|
} else {
|
2019-05-21 21:52:17 +08:00
|
|
|
|
l.level = l.level & ^LEVEL_DEBU
|
2018-09-18 21:29:31 +08:00
|
|
|
|
}
|
2018-08-30 13:00:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-21 23:57:03 +08:00
|
|
|
|
// SetFlags sets extra flags for logging output features.
|
2019-05-21 21:52:17 +08:00
|
|
|
|
func (l *Logger) SetFlags(flags int) {
|
|
|
|
|
l.flags = flags
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetFlags returns the flags of logger.
|
|
|
|
|
func (l *Logger) GetFlags() int {
|
|
|
|
|
return l.flags
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-20 11:16:10 +08:00
|
|
|
|
// SetBacktrace enables/disables the backtrace feature in failure logging outputs.
|
2018-08-30 13:00:49 +08:00
|
|
|
|
func (l *Logger) SetBacktrace(enabled bool) {
|
2018-12-15 15:50:39 +08:00
|
|
|
|
if enabled {
|
2019-05-21 21:52:17 +08:00
|
|
|
|
l.btStatus = 1
|
2018-12-15 15:50:39 +08:00
|
|
|
|
} else {
|
2019-05-21 21:52:17 +08:00
|
|
|
|
l.btStatus = 0
|
2018-12-15 15:50:39 +08:00
|
|
|
|
}
|
2018-08-30 13:00:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-20 11:16:10 +08:00
|
|
|
|
// SetBacktraceSkip sets the backtrace offset from the end point.
|
2018-10-10 18:39:57 +08:00
|
|
|
|
func (l *Logger) SetBacktraceSkip(skip int) {
|
2019-05-21 21:52:17 +08:00
|
|
|
|
l.btSkip = skip
|
2018-10-10 18:39:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-17 23:50:37 +08:00
|
|
|
|
// SetWriter sets the customized logging <writer> for logging.
|
2019-02-20 11:16:10 +08:00
|
|
|
|
// The <writer> object should implements the io.Writer interface.
|
2019-04-17 23:50:37 +08:00
|
|
|
|
// Developer can use customized logging <writer> to redirect logging output to another service,
|
2019-02-20 11:16:10 +08:00
|
|
|
|
// eg: kafka, mysql, mongodb, etc.
|
2018-11-06 18:53:25 +08:00
|
|
|
|
func (l *Logger) SetWriter(writer io.Writer) {
|
2019-04-18 09:11:14 +08:00
|
|
|
|
l.writer = writer
|
2018-04-19 16:24:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-17 23:50:37 +08:00
|
|
|
|
// GetWriter returns the customized writer object, which implements the io.Writer interface.
|
|
|
|
|
// It returns a default writer if no customized writer set.
|
2018-10-18 13:43:00 +08:00
|
|
|
|
func (l *Logger) GetWriter() io.Writer {
|
2019-05-21 21:52:17 +08:00
|
|
|
|
return l.writer
|
2018-04-19 16:24:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-20 11:16:10 +08:00
|
|
|
|
// getFilePointer returns the file pinter for file logging.
|
2019-04-17 23:50:37 +08:00
|
|
|
|
// It returns nil if file logging is disabled, or file opening fails.
|
2018-11-11 14:21:22 +08:00
|
|
|
|
func (l *Logger) getFilePointer() *gfpool.File {
|
2019-05-21 21:52:17 +08:00
|
|
|
|
if path := l.path; path != "" {
|
2019-04-17 23:50:37 +08:00
|
|
|
|
// Content containing "{}" in the file name is formatted using gtime
|
2019-05-21 21:52:17 +08:00
|
|
|
|
file, _ := gregex.ReplaceStringFunc(`{.+?}`, l.file, func(s string) string {
|
2018-10-09 21:41:07 +08:00
|
|
|
|
return gtime.Now().Format(strings.Trim(s, "{}"))
|
|
|
|
|
})
|
2019-04-17 23:50:37 +08:00
|
|
|
|
// Create path if it does not exist。
|
2018-12-19 18:15:22 +08:00
|
|
|
|
if !gfile.Exists(path) {
|
|
|
|
|
if err := gfile.Mkdir(path); err != nil {
|
|
|
|
|
fmt.Fprintln(os.Stderr, fmt.Sprintf(`[glog] mkdir "%s" failed: %s`, path, err.Error()))
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-22 09:19:21 +08:00
|
|
|
|
if fp, err := gfpool.Open(
|
|
|
|
|
path + gfile.Separator + file,
|
|
|
|
|
gDEFAULT_FILE_POOL_FLAGS,
|
|
|
|
|
gDEFAULT_FPOOL_PERM,
|
|
|
|
|
gDEFAULT_FPOOL_EXPIRE); err == nil {
|
2018-04-19 16:24:48 +08:00
|
|
|
|
return fp
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Fprintln(os.Stderr, err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-20 11:16:10 +08:00
|
|
|
|
// SetPath sets the directory path for file logging.
|
2018-04-19 16:24:48 +08:00
|
|
|
|
func (l *Logger) SetPath(path string) error {
|
2019-01-31 13:00:17 +08:00
|
|
|
|
if path == "" {
|
|
|
|
|
return errors.New("path is empty")
|
|
|
|
|
}
|
2018-09-16 16:38:17 +08:00
|
|
|
|
if !gfile.Exists(path) {
|
|
|
|
|
if err := gfile.Mkdir(path); err != nil {
|
2018-12-19 18:15:22 +08:00
|
|
|
|
fmt.Fprintln(os.Stderr, fmt.Sprintf(`[glog] mkdir "%s" failed: %s`, path, err.Error()))
|
2018-09-16 16:38:17 +08:00
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-21 21:52:17 +08:00
|
|
|
|
l.path = strings.TrimRight(path, gfile.Separator)
|
2018-04-19 16:24:48 +08:00
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-20 11:16:10 +08:00
|
|
|
|
// GetPath returns the logging directory path for file logging.
|
|
|
|
|
// It returns empty string if no directory path set.
|
2018-10-10 18:39:57 +08:00
|
|
|
|
func (l *Logger) GetPath() string {
|
2019-05-21 21:52:17 +08:00
|
|
|
|
return l.path
|
2018-10-10 18:39:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-20 11:16:10 +08:00
|
|
|
|
// SetFile sets the file name <pattern> for file logging.
|
|
|
|
|
// Datetime pattern can be used in <pattern>, eg: access-{Ymd}.log.
|
|
|
|
|
// The default file name pattern is: Y-m-d.log, eg: 2018-01-01.log
|
|
|
|
|
func (l *Logger) SetFile(pattern string) {
|
2019-05-21 21:52:17 +08:00
|
|
|
|
l.file = pattern
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetStdPrint sets whether output the logging contents to stdout, which is true in default.
|
|
|
|
|
func (l *Logger) SetStdoutPrint(enabled bool) {
|
|
|
|
|
l.stdoutPrint = enabled
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetHeaderPrint sets whether output header of the logging contents, which is true in default.
|
|
|
|
|
func (l *Logger) SetHeaderPrint(enabled bool) {
|
|
|
|
|
l.headerPrint = enabled
|
2018-10-09 21:41:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-21 21:52:17 +08:00
|
|
|
|
// SetPrefix sets prefix string for every logging content.
|
|
|
|
|
// Prefix is part of header, which means if header output is shut, no prefix will be output.
|
|
|
|
|
func (l *Logger) SetPrefix(prefix string) {
|
|
|
|
|
l.prefix = prefix
|
2018-05-24 12:37:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-17 23:50:37 +08:00
|
|
|
|
// print prints <s> to defined writer, logging file or passed <std>.
|
|
|
|
|
// It internally uses memory lock for file logging to ensure logging sequence.
|
2018-08-30 00:00:15 +08:00
|
|
|
|
func (l *Logger) print(std io.Writer, s string) {
|
2019-04-17 23:50:37 +08:00
|
|
|
|
// Customized writer has the most high priority.
|
2019-05-21 21:52:17 +08:00
|
|
|
|
if l.headerPrint {
|
2018-10-18 13:43:00 +08:00
|
|
|
|
s = l.format(s)
|
|
|
|
|
}
|
|
|
|
|
writer := l.GetWriter()
|
2019-04-17 23:50:37 +08:00
|
|
|
|
if _, ok := writer.(*Writer); ok {
|
2018-09-14 17:02:07 +08:00
|
|
|
|
if f := l.getFilePointer(); f != nil {
|
2018-07-26 13:00:04 +08:00
|
|
|
|
defer f.Close()
|
2019-05-15 23:53:48 +08:00
|
|
|
|
if _, err := io.WriteString(f, s); err != nil {
|
2018-09-15 16:40:13 +08:00
|
|
|
|
fmt.Fprintln(os.Stderr, err.Error())
|
|
|
|
|
}
|
2018-04-19 16:24:48 +08:00
|
|
|
|
}
|
2019-05-22 09:19:21 +08:00
|
|
|
|
// Allow output to stdout?
|
2019-05-21 21:52:17 +08:00
|
|
|
|
if l.stdoutPrint {
|
|
|
|
|
if _, err := std.Write([]byte(s)); err != nil {
|
|
|
|
|
fmt.Fprintln(os.Stderr, err.Error())
|
|
|
|
|
}
|
2018-11-06 18:53:25 +08:00
|
|
|
|
}
|
2018-08-30 00:00:15 +08:00
|
|
|
|
} else {
|
2019-05-21 21:52:17 +08:00
|
|
|
|
if _, err := std.Write([]byte(s)); err != nil {
|
|
|
|
|
fmt.Fprintln(os.Stderr, err.Error())
|
|
|
|
|
}
|
2018-08-30 00:00:15 +08:00
|
|
|
|
}
|
2018-04-19 16:24:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-21 21:52:17 +08:00
|
|
|
|
// printStd prints content <s> without backtrace.
|
|
|
|
|
func (l *Logger) printStd(s string) {
|
2018-04-19 16:24:48 +08:00
|
|
|
|
l.print(os.Stdout, s)
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-21 21:52:17 +08:00
|
|
|
|
// printStd prints content <s> with backtrace check.
|
|
|
|
|
func (l *Logger) printErr(s string) {
|
|
|
|
|
if l.btStatus == 1 {
|
2018-12-15 15:50:39 +08:00
|
|
|
|
s = l.appendBacktrace(s)
|
2018-04-19 16:24:48 +08:00
|
|
|
|
}
|
2019-04-17 23:50:37 +08:00
|
|
|
|
// In matter of sequence, do not use stderr here, but use the same stdout.
|
2018-10-18 13:43:00 +08:00
|
|
|
|
l.print(os.Stdout, s)
|
2018-04-19 16:24:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-17 23:50:37 +08:00
|
|
|
|
// appendBacktrace appends backtrace to the <s>.
|
2018-12-18 20:03:23 +08:00
|
|
|
|
func (l *Logger) appendBacktrace(s string, skip...int) string {
|
|
|
|
|
trace := l.GetBacktrace(skip...)
|
2018-12-15 15:50:39 +08:00
|
|
|
|
if trace != "" {
|
|
|
|
|
backtrace := "Backtrace:" + ln + trace
|
2018-12-18 20:03:23 +08:00
|
|
|
|
if len(s) > 0 {
|
|
|
|
|
if s[len(s)-1] == byte('\n') {
|
|
|
|
|
s = s + backtrace + ln
|
|
|
|
|
} else {
|
|
|
|
|
s = s + ln + backtrace + ln
|
|
|
|
|
}
|
2018-12-15 15:50:39 +08:00
|
|
|
|
} else {
|
2018-12-18 20:03:23 +08:00
|
|
|
|
s = backtrace
|
2018-12-15 15:50:39 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-20 11:16:10 +08:00
|
|
|
|
// PrintBacktrace prints the caller backtrace,
|
2019-04-17 23:50:37 +08:00
|
|
|
|
// the optional parameter <skip> specify the skipped backtrace offset from the end point.
|
2018-10-10 18:39:57 +08:00
|
|
|
|
func (l *Logger) PrintBacktrace(skip...int) {
|
2018-12-18 20:03:23 +08:00
|
|
|
|
l.Println(l.appendBacktrace("", skip...))
|
2018-08-27 23:58:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-20 11:16:10 +08:00
|
|
|
|
// GetBacktrace returns the caller backtrace content,
|
2019-04-17 23:50:37 +08:00
|
|
|
|
// the optional parameter <skip> specify the skipped backtrace offset from the end point.
|
2018-10-10 18:39:57 +08:00
|
|
|
|
func (l *Logger) GetBacktrace(skip...int) string {
|
|
|
|
|
customSkip := 0
|
|
|
|
|
if len(skip) > 0 {
|
|
|
|
|
customSkip = skip[0]
|
|
|
|
|
}
|
2018-08-27 23:58:32 +08:00
|
|
|
|
backtrace := ""
|
2018-04-20 17:53:34 +08:00
|
|
|
|
index := 1
|
2018-10-31 16:23:31 +08:00
|
|
|
|
from := 0
|
|
|
|
|
// 首先定位业务文件开始位置
|
|
|
|
|
for i := 0; i < 10; i++ {
|
2018-11-03 15:27:48 +08:00
|
|
|
|
if _, file, _, ok := runtime.Caller(i); ok {
|
|
|
|
|
if !gregex.IsMatchString("/g/os/glog/glog.+$", file) {
|
2018-10-31 16:23:31 +08:00
|
|
|
|
from = i
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 从业务文件开始位置根据自定义的skip开始backtrace
|
2018-11-03 15:27:48 +08:00
|
|
|
|
goRoot := runtime.GOROOT()
|
2019-05-21 21:52:17 +08:00
|
|
|
|
for i := from + customSkip + l.btSkip; i < 10000; i++ {
|
2018-11-03 15:27:48 +08:00
|
|
|
|
if _, file, cline, ok := runtime.Caller(i); ok && file != "" {
|
2018-10-10 18:39:57 +08:00
|
|
|
|
// 不打印出go源码路径及glog包文件路径,日志打印必须从业务源码文件开始,且从glog包文件开始检索
|
2018-11-03 15:27:48 +08:00
|
|
|
|
if (goRoot == "" || !gregex.IsMatchString("^" + goRoot, file)) && !gregex.IsMatchString(`<autogenerated>`, file) {
|
|
|
|
|
backtrace += fmt.Sprintf(`%d. %s:%d%s`, index, file, cline, ln)
|
2018-04-20 17:53:34 +08:00
|
|
|
|
index++
|
2018-04-19 16:24:48 +08:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return backtrace
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-21 23:57:03 +08:00
|
|
|
|
// format formats the content according the flags.
|
2019-05-21 21:52:17 +08:00
|
|
|
|
func (l *Logger) format(content string) string {
|
|
|
|
|
buffer := bytes.NewBuffer(nil)
|
2019-05-22 09:19:21 +08:00
|
|
|
|
// Time.
|
2019-05-21 21:52:17 +08:00
|
|
|
|
timeFormat := ""
|
|
|
|
|
if l.flags & F_TIME_DATE > 0 {
|
|
|
|
|
timeFormat += "2006-01-02 "
|
|
|
|
|
}
|
|
|
|
|
if l.flags & F_TIME_TIME > 0 {
|
|
|
|
|
timeFormat += "15:04:05 "
|
|
|
|
|
}
|
|
|
|
|
if l.flags & F_TIME_MILLI > 0 {
|
|
|
|
|
timeFormat += "15:04:05.000 "
|
|
|
|
|
}
|
|
|
|
|
if len(timeFormat) > 0 {
|
|
|
|
|
buffer.WriteString(time.Now().Format(timeFormat))
|
|
|
|
|
}
|
2019-05-22 09:19:21 +08:00
|
|
|
|
// Caller path.
|
2019-05-21 21:52:17 +08:00
|
|
|
|
callerPath := ""
|
|
|
|
|
if l.flags & F_FILE_LONG > 0 {
|
|
|
|
|
callerPath = l.getLongFile() + ": "
|
|
|
|
|
}
|
|
|
|
|
if l.flags & F_FILE_SHORT > 0 {
|
|
|
|
|
callerPath = gfile.Basename(l.getLongFile()) + ": "
|
|
|
|
|
}
|
|
|
|
|
if len(callerPath) > 0 {
|
|
|
|
|
buffer.WriteString(callerPath)
|
|
|
|
|
}
|
2019-05-22 09:19:21 +08:00
|
|
|
|
// Prefix.
|
2019-05-21 21:52:17 +08:00
|
|
|
|
if len(l.prefix) > 0 {
|
|
|
|
|
buffer.WriteString(l.prefix + " ")
|
|
|
|
|
}
|
2019-05-22 09:19:21 +08:00
|
|
|
|
// Content.
|
2019-05-21 21:52:17 +08:00
|
|
|
|
buffer.WriteString(content)
|
|
|
|
|
return buffer.String()
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-21 23:57:03 +08:00
|
|
|
|
// getLongFile returns the absolute file path along with its line number of the caller.
|
2019-05-21 21:52:17 +08:00
|
|
|
|
func (l *Logger) getLongFile() string {
|
|
|
|
|
for i := 0; i < 100; i++ {
|
|
|
|
|
if _, file, line, ok := runtime.Caller(i); ok {
|
|
|
|
|
if !gregex.IsMatchString("/g/os/glog/glog.+$", file) {
|
|
|
|
|
return fmt.Sprintf(`%s:%d`, file, line)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ""
|
2018-04-19 16:24:48 +08:00
|
|
|
|
}
|