2021-01-17 21:46:25 +08:00
|
|
|
// Copyright GoFrame Author(https://goframe.org). 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.
|
2018-04-19 16:24:48 +08:00
|
|
|
|
|
|
|
package glog
|
|
|
|
|
|
|
|
import (
|
2021-08-12 21:58:06 +08:00
|
|
|
"bytes"
|
2020-05-08 17:12:37 +08:00
|
|
|
"context"
|
2019-05-15 23:53:48 +08:00
|
|
|
"fmt"
|
2021-08-08 16:23:25 +08:00
|
|
|
"github.com/fatih/color"
|
2021-10-11 21:41:56 +08:00
|
|
|
"github.com/gogf/gf/v2/container/gtype"
|
|
|
|
"github.com/gogf/gf/v2/internal/intlog"
|
|
|
|
"github.com/gogf/gf/v2/os/gctx"
|
|
|
|
"github.com/gogf/gf/v2/os/gfpool"
|
|
|
|
"github.com/gogf/gf/v2/os/gmlock"
|
|
|
|
"github.com/gogf/gf/v2/os/gtimer"
|
2021-01-26 01:19:55 +08:00
|
|
|
"go.opentelemetry.io/otel/trace"
|
2019-05-15 23:53:48 +08:00
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
"time"
|
2019-06-29 10:45:50 +08:00
|
|
|
|
2021-10-11 21:41:56 +08:00
|
|
|
"github.com/gogf/gf/v2/debug/gdebug"
|
2019-08-24 23:08:17 +08:00
|
|
|
|
2021-10-11 21:41:56 +08:00
|
|
|
"github.com/gogf/gf/v2/os/gfile"
|
|
|
|
"github.com/gogf/gf/v2/os/gtime"
|
|
|
|
"github.com/gogf/gf/v2/text/gregex"
|
|
|
|
"github.com/gogf/gf/v2/util/gconv"
|
2018-04-19 16:24:48 +08:00
|
|
|
)
|
|
|
|
|
2020-02-14 21:57:35 +08:00
|
|
|
// Logger is the struct for logging management.
|
2018-10-09 21:41:07 +08:00
|
|
|
type Logger struct {
|
2021-09-27 21:27:24 +08:00
|
|
|
init *gtype.Bool // Initialized.
|
|
|
|
parent *Logger // Parent logger, if it is not empty, it means the logger is used in chaining function.
|
|
|
|
config Config // Logger configuration.
|
2018-10-09 21:41:07 +08:00
|
|
|
}
|
|
|
|
|
2018-04-19 16:24:48 +08:00
|
|
|
const (
|
2021-06-26 16:23:54 +08:00
|
|
|
defaultFileFormat = `{Y-m-d}.log`
|
|
|
|
defaultFileFlags = os.O_CREATE | os.O_WRONLY | os.O_APPEND
|
|
|
|
defaultFilePerm = os.FileMode(0666)
|
|
|
|
defaultFileExpire = time.Minute
|
|
|
|
pathFilterKey = "/os/glog/glog"
|
|
|
|
memoryLockPrefixForPrintingToFile = "glog.printToFile:"
|
2018-04-19 16:24:48 +08:00
|
|
|
)
|
|
|
|
|
2019-05-21 21:52:17 +08:00
|
|
|
const (
|
2019-06-01 19:34:03 +08:00
|
|
|
F_ASYNC = 1 << iota // Print logging content asynchronously。
|
|
|
|
F_FILE_LONG // Print full file name and line number: /a/b/c/d.go:23.
|
2019-05-21 23:57:03 +08:00
|
|
|
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.
|
2020-06-22 11:04:57 +08:00
|
|
|
F_CALLER_FN // Print Caller function name and package: main.main
|
2019-06-19 09:06:52 +08:00
|
|
|
F_TIME_STD = F_TIME_DATE | F_TIME_MILLI
|
2019-05-21 21:52:17 +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 {
|
2020-03-15 19:32:26 +08:00
|
|
|
logger := &Logger{
|
2020-07-30 21:09:45 +08:00
|
|
|
init: gtype.NewBool(),
|
2019-10-26 10:58:07 +08:00
|
|
|
config: DefaultConfig(),
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2020-03-15 19:32:26 +08:00
|
|
|
return logger
|
2018-08-24 23:41:58 +08:00
|
|
|
}
|
|
|
|
|
2020-02-26 23:26:24 +08:00
|
|
|
// NewWithWriter creates and returns a custom logger with io.Writer.
|
|
|
|
func NewWithWriter(writer io.Writer) *Logger {
|
|
|
|
l := New()
|
|
|
|
l.SetWriter(writer)
|
|
|
|
return l
|
|
|
|
}
|
|
|
|
|
2019-02-20 11:16:10 +08:00
|
|
|
// Clone returns a new logger, which is the clone the current logger.
|
2020-03-15 19:32:26 +08:00
|
|
|
// It's commonly used for chaining operations.
|
2018-08-28 17:06:49 +08:00
|
|
|
func (l *Logger) Clone() *Logger {
|
2021-08-12 21:58:06 +08:00
|
|
|
newLogger := New()
|
|
|
|
newLogger.config = l.config
|
|
|
|
newLogger.parent = l
|
|
|
|
return newLogger
|
2018-08-24 23:41:58 +08:00
|
|
|
}
|
|
|
|
|
2020-03-15 19:32:26 +08:00
|
|
|
// getFilePath returns the logging file path.
|
2020-03-25 23:36:56 +08:00
|
|
|
// The logging file name must have extension name of "log".
|
2020-03-24 19:48:10 +08:00
|
|
|
func (l *Logger) getFilePath(now time.Time) string {
|
2020-03-15 19:32:26 +08:00
|
|
|
// Content containing "{}" in the file name is formatted using gtime.
|
|
|
|
file, _ := gregex.ReplaceStringFunc(`{.+?}`, l.config.File, func(s string) string {
|
2020-03-24 19:48:10 +08:00
|
|
|
return gtime.New(now).Format(strings.Trim(s, "{}"))
|
2020-03-15 19:32:26 +08:00
|
|
|
})
|
2020-03-25 23:36:56 +08:00
|
|
|
file = gfile.Join(l.config.Path, file)
|
|
|
|
return file
|
2020-03-15 19:32:26 +08:00
|
|
|
}
|
|
|
|
|
2021-08-08 13:56:26 +08:00
|
|
|
// print prints `s` to defined writer, logging file or passed `std`.
|
2021-06-02 09:42:27 +08:00
|
|
|
func (l *Logger) print(ctx context.Context, level int, values ...interface{}) {
|
2020-07-30 20:49:11 +08:00
|
|
|
// Lazy initialize for rotation feature.
|
2020-08-26 14:37:02 +08:00
|
|
|
// It uses atomic reading operation to enhance the performance checking.
|
2020-07-30 20:49:11 +08:00
|
|
|
// It here uses CAP for performance and concurrent safety.
|
2020-08-26 14:37:02 +08:00
|
|
|
p := l
|
|
|
|
if p.parent != nil {
|
|
|
|
p = p.parent
|
|
|
|
}
|
2021-06-26 11:18:44 +08:00
|
|
|
// It just initializes once for each logger.
|
|
|
|
if p.config.RotateSize > 0 || p.config.RotateExpire > 0 {
|
|
|
|
if !p.init.Val() && p.init.Cas(false, true) {
|
2021-10-30 15:36:10 +08:00
|
|
|
gtimer.AddOnce(context.Background(), p.config.RotateCheckInterval, p.rotateChecksTimely)
|
2021-06-26 16:23:54 +08:00
|
|
|
intlog.Printf(ctx, "logger rotation initialized: every %s", p.config.RotateCheckInterval.String())
|
2020-08-03 20:00:00 +08:00
|
|
|
}
|
2020-07-30 20:18:18 +08:00
|
|
|
}
|
|
|
|
|
2020-03-24 19:48:10 +08:00
|
|
|
var (
|
2021-06-02 09:42:27 +08:00
|
|
|
now = time.Now()
|
|
|
|
input = &HandlerInput{
|
2021-08-12 21:58:06 +08:00
|
|
|
Logger: l,
|
|
|
|
Buffer: bytes.NewBuffer(nil),
|
|
|
|
Ctx: ctx,
|
|
|
|
Time: now,
|
|
|
|
Color: defaultLevelColor[level],
|
|
|
|
Level: level,
|
|
|
|
handlerIndex: -1,
|
2021-06-02 09:42:27 +08:00
|
|
|
}
|
2020-03-24 19:48:10 +08:00
|
|
|
)
|
2019-10-26 10:58:07 +08:00
|
|
|
if l.config.HeaderPrint {
|
2019-06-19 09:06:52 +08:00
|
|
|
// Time.
|
|
|
|
timeFormat := ""
|
2019-10-26 10:58:07 +08:00
|
|
|
if l.config.Flags&F_TIME_DATE > 0 {
|
2021-06-02 09:42:27 +08:00
|
|
|
timeFormat += "2006-01-02"
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2019-10-26 10:58:07 +08:00
|
|
|
if l.config.Flags&F_TIME_TIME > 0 {
|
2021-06-02 09:42:27 +08:00
|
|
|
if timeFormat != "" {
|
|
|
|
timeFormat += " "
|
|
|
|
}
|
|
|
|
timeFormat += "15:04:05"
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2019-10-26 10:58:07 +08:00
|
|
|
if l.config.Flags&F_TIME_MILLI > 0 {
|
2021-06-02 09:42:27 +08:00
|
|
|
if timeFormat != "" {
|
|
|
|
timeFormat += " "
|
|
|
|
}
|
|
|
|
timeFormat += "15:04:05.000"
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
if len(timeFormat) > 0 {
|
2021-06-02 09:42:27 +08:00
|
|
|
input.TimeFormat = now.Format(timeFormat)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2021-06-02 09:42:27 +08:00
|
|
|
|
|
|
|
// Level string.
|
|
|
|
input.LevelFormat = l.getLevelPrefixWithBrackets(level)
|
|
|
|
|
2020-06-22 11:04:57 +08:00
|
|
|
// Caller path and Fn name.
|
|
|
|
if l.config.Flags&(F_FILE_LONG|F_FILE_SHORT|F_CALLER_FN) > 0 {
|
2020-11-12 18:38:58 +08:00
|
|
|
callerFnName, path, line := gdebug.CallerWithFilter(pathFilterKey, l.config.StSkip)
|
2020-06-22 11:04:57 +08:00
|
|
|
if l.config.Flags&F_CALLER_FN > 0 {
|
2021-08-20 15:44:08 +08:00
|
|
|
if len(callerFnName) > 2 {
|
|
|
|
input.CallerFunc = fmt.Sprintf(`[%s]`, callerFnName)
|
|
|
|
}
|
2020-06-22 11:04:57 +08:00
|
|
|
}
|
2021-08-20 15:44:08 +08:00
|
|
|
if line >= 0 && len(path) > 1 {
|
|
|
|
if l.config.Flags&F_FILE_LONG > 0 {
|
|
|
|
input.CallerPath = fmt.Sprintf(`%s:%d:`, path, line)
|
|
|
|
}
|
|
|
|
if l.config.Flags&F_FILE_SHORT > 0 {
|
|
|
|
input.CallerPath = fmt.Sprintf(`%s:%d:`, gfile.Basename(path), line)
|
|
|
|
}
|
2020-06-22 11:04:57 +08:00
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
// Prefix.
|
2019-10-26 10:58:07 +08:00
|
|
|
if len(l.config.Prefix) > 0 {
|
2021-06-02 09:42:27 +08:00
|
|
|
input.Prefix = l.config.Prefix
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
}
|
2019-06-30 22:21:08 +08:00
|
|
|
// Convert value to string.
|
2021-06-02 09:42:27 +08:00
|
|
|
if ctx != nil {
|
2021-01-26 01:19:55 +08:00
|
|
|
// Tracing values.
|
2021-06-02 09:42:27 +08:00
|
|
|
spanCtx := trace.SpanContextFromContext(ctx)
|
2021-03-29 16:00:56 +08:00
|
|
|
if traceId := spanCtx.TraceID(); traceId.IsValid() {
|
2021-08-20 15:44:08 +08:00
|
|
|
input.CtxStr = traceId.String()
|
2021-01-26 01:19:55 +08:00
|
|
|
}
|
|
|
|
// Context values.
|
|
|
|
if len(l.config.CtxKeys) > 0 {
|
2021-08-11 13:20:00 +08:00
|
|
|
for _, ctxKey := range l.config.CtxKeys {
|
|
|
|
var ctxValue interface{}
|
|
|
|
if ctxValue = ctx.Value(ctxKey); ctxValue == nil {
|
|
|
|
ctxValue = ctx.Value(gctx.StrKey(gconv.String(ctxKey)))
|
|
|
|
}
|
|
|
|
if ctxValue != nil {
|
2021-08-20 15:44:08 +08:00
|
|
|
if input.CtxStr != "" {
|
|
|
|
input.CtxStr += ", "
|
2021-01-26 01:19:55 +08:00
|
|
|
}
|
2021-08-20 15:44:08 +08:00
|
|
|
input.CtxStr += gconv.String(ctxValue)
|
2020-05-08 17:12:37 +08:00
|
|
|
}
|
|
|
|
}
|
2021-08-20 15:44:08 +08:00
|
|
|
}
|
|
|
|
if input.CtxStr != "" {
|
|
|
|
input.CtxStr = "{" + input.CtxStr + "}"
|
2020-05-08 17:12:37 +08:00
|
|
|
}
|
|
|
|
}
|
2021-06-02 09:42:27 +08:00
|
|
|
var tempStr string
|
2020-05-08 17:12:37 +08:00
|
|
|
for _, v := range values {
|
2020-12-11 01:12:53 +08:00
|
|
|
tempStr = gconv.String(v)
|
2021-06-02 09:42:27 +08:00
|
|
|
if len(input.Content) > 0 {
|
|
|
|
if input.Content[len(input.Content)-1] == '\n' {
|
2019-07-16 19:49:21 +08:00
|
|
|
// Remove one blank line(\n\n).
|
2019-06-29 23:35:32 +08:00
|
|
|
if tempStr[0] == '\n' {
|
2021-06-02 09:42:27 +08:00
|
|
|
input.Content += tempStr[1:]
|
2019-06-29 23:35:32 +08:00
|
|
|
} else {
|
2021-06-02 09:42:27 +08:00
|
|
|
input.Content += tempStr
|
2019-06-29 23:35:32 +08:00
|
|
|
}
|
|
|
|
} else {
|
2021-06-02 09:42:27 +08:00
|
|
|
input.Content += " " + tempStr
|
2019-06-29 23:35:32 +08:00
|
|
|
}
|
|
|
|
} else {
|
2021-06-02 09:42:27 +08:00
|
|
|
input.Content = tempStr
|
2019-06-01 11:01:57 +08:00
|
|
|
}
|
|
|
|
}
|
2019-10-26 10:58:07 +08:00
|
|
|
if l.config.Flags&F_ASYNC > 0 {
|
2021-06-02 09:42:27 +08:00
|
|
|
input.IsAsync = true
|
2021-10-30 18:09:58 +08:00
|
|
|
err := asyncPool.Add(ctx, func(ctx context.Context) {
|
2021-06-02 09:42:27 +08:00
|
|
|
input.Next()
|
2019-06-01 19:34:03 +08:00
|
|
|
})
|
2019-11-01 20:36:09 +08:00
|
|
|
if err != nil {
|
2021-06-26 16:23:54 +08:00
|
|
|
intlog.Error(ctx, err)
|
2019-11-01 20:36:09 +08:00
|
|
|
}
|
2019-06-01 19:34:03 +08:00
|
|
|
} else {
|
2021-06-02 09:42:27 +08:00
|
|
|
input.Next()
|
2019-06-01 19:34:03 +08:00
|
|
|
}
|
|
|
|
}
|
2019-06-01 11:01:57 +08:00
|
|
|
|
2021-08-12 21:58:06 +08:00
|
|
|
// doDefaultPrint outputs the logging content according configuration.
|
2021-08-12 22:14:31 +08:00
|
|
|
func (l *Logger) doDefaultPrint(ctx context.Context, input *HandlerInput) *bytes.Buffer {
|
|
|
|
var buffer *bytes.Buffer
|
2019-10-26 10:58:07 +08:00
|
|
|
if l.config.Writer == nil {
|
2019-06-01 19:34:03 +08:00
|
|
|
// Allow output to stdout?
|
2019-10-26 10:58:07 +08:00
|
|
|
if l.config.StdoutPrint {
|
2021-08-12 22:14:31 +08:00
|
|
|
if buf := l.printToStdout(ctx, input); buf != nil {
|
|
|
|
buffer = buf
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Output content to disk file.
|
|
|
|
if l.config.Path != "" {
|
|
|
|
if buf := l.printToFile(ctx, input.Time, input); buf != nil {
|
|
|
|
buffer = buf
|
|
|
|
}
|
2019-06-01 19:34:03 +08:00
|
|
|
}
|
|
|
|
} else {
|
2021-07-15 13:31:32 +08:00
|
|
|
// Output to custom writer.
|
2021-08-12 22:14:31 +08:00
|
|
|
if buf := l.printToWriter(ctx, input); buf != nil {
|
|
|
|
buffer = buf
|
|
|
|
}
|
2021-07-15 13:31:32 +08:00
|
|
|
}
|
2021-08-12 22:14:31 +08:00
|
|
|
return buffer
|
2021-07-15 13:31:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// printToWriter writes buffer to writer.
|
2021-08-12 22:14:31 +08:00
|
|
|
func (l *Logger) printToWriter(ctx context.Context, input *HandlerInput) *bytes.Buffer {
|
2021-07-15 13:31:32 +08:00
|
|
|
if l.config.Writer != nil {
|
|
|
|
var (
|
2021-08-12 21:58:06 +08:00
|
|
|
buffer = input.getRealBuffer(l.config.WriterColorEnable)
|
2021-07-15 13:31:32 +08:00
|
|
|
)
|
|
|
|
if _, err := l.config.Writer.Write(buffer.Bytes()); err != nil {
|
|
|
|
intlog.Error(ctx, err)
|
|
|
|
}
|
2021-08-12 22:14:31 +08:00
|
|
|
return buffer
|
2021-07-15 13:31:32 +08:00
|
|
|
}
|
2021-08-12 22:14:31 +08:00
|
|
|
return nil
|
2021-07-15 13:31:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// printToStdout outputs logging content to stdout.
|
2021-08-12 22:14:31 +08:00
|
|
|
func (l *Logger) printToStdout(ctx context.Context, input *HandlerInput) *bytes.Buffer {
|
2021-07-15 13:31:32 +08:00
|
|
|
if l.config.StdoutPrint {
|
2021-08-12 22:14:31 +08:00
|
|
|
var (
|
|
|
|
buffer = input.getRealBuffer(true)
|
|
|
|
)
|
2021-08-09 19:29:11 +08:00
|
|
|
// This will lose color in Windows os system.
|
2021-08-12 21:58:06 +08:00
|
|
|
// if _, err := os.Stdout.Write(input.getRealBuffer(true).Bytes()); err != nil {
|
2021-09-01 16:14:17 +08:00
|
|
|
|
2021-08-09 19:29:11 +08:00
|
|
|
// This will print color in Windows os system.
|
2021-09-01 16:14:17 +08:00
|
|
|
if _, err := fmt.Fprint(color.Output, buffer.String()); err != nil {
|
2021-06-26 16:23:54 +08:00
|
|
|
intlog.Error(ctx, err)
|
2019-06-01 19:34:03 +08:00
|
|
|
}
|
2021-08-12 22:14:31 +08:00
|
|
|
return buffer
|
2019-06-01 19:34:03 +08:00
|
|
|
}
|
2021-08-12 22:14:31 +08:00
|
|
|
return nil
|
2018-04-19 16:24:48 +08:00
|
|
|
}
|
|
|
|
|
2020-03-25 23:36:56 +08:00
|
|
|
// printToFile outputs logging content to disk file.
|
2021-08-12 22:14:31 +08:00
|
|
|
func (l *Logger) printToFile(ctx context.Context, t time.Time, in *HandlerInput) *bytes.Buffer {
|
2020-03-25 23:36:56 +08:00
|
|
|
var (
|
2021-08-12 21:58:06 +08:00
|
|
|
buffer = in.getRealBuffer(l.config.WriterColorEnable)
|
2021-06-02 09:42:27 +08:00
|
|
|
logFilePath = l.getFilePath(t)
|
2021-06-26 16:23:54 +08:00
|
|
|
memoryLockKey = memoryLockPrefixForPrintingToFile + logFilePath
|
2020-03-25 23:36:56 +08:00
|
|
|
)
|
|
|
|
gmlock.Lock(memoryLockKey)
|
|
|
|
defer gmlock.Unlock(memoryLockKey)
|
2020-12-08 18:54:42 +08:00
|
|
|
|
|
|
|
// Rotation file size checks.
|
|
|
|
if l.config.RotateSize > 0 {
|
|
|
|
if gfile.Size(logFilePath) > l.config.RotateSize {
|
2021-09-27 21:27:24 +08:00
|
|
|
l.rotateFileBySize(ctx, t)
|
2020-12-08 18:54:42 +08:00
|
|
|
}
|
|
|
|
}
|
2020-12-09 13:54:27 +08:00
|
|
|
// Logging content outputting to disk file.
|
2021-06-26 16:23:54 +08:00
|
|
|
if file := l.getFilePointer(ctx, logFilePath); file == nil {
|
|
|
|
intlog.Errorf(ctx, `got nil file pointer for: %s`, logFilePath)
|
2020-12-09 13:54:27 +08:00
|
|
|
} else {
|
|
|
|
if _, err := file.Write(buffer.Bytes()); err != nil {
|
2021-06-26 16:23:54 +08:00
|
|
|
intlog.Error(ctx, err)
|
2020-12-09 13:54:27 +08:00
|
|
|
}
|
|
|
|
if err := file.Close(); err != nil {
|
2021-06-26 16:23:54 +08:00
|
|
|
intlog.Error(ctx, err)
|
2020-12-09 13:54:27 +08:00
|
|
|
}
|
2020-03-25 23:36:56 +08:00
|
|
|
}
|
2021-08-12 22:14:31 +08:00
|
|
|
return buffer
|
2020-03-25 23:36:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// getFilePointer retrieves and returns a file pointer from file pool.
|
2021-06-26 16:23:54 +08:00
|
|
|
func (l *Logger) getFilePointer(ctx context.Context, path string) *gfpool.File {
|
2020-03-25 23:36:56 +08:00
|
|
|
file, err := gfpool.Open(
|
|
|
|
path,
|
2020-11-12 18:38:58 +08:00
|
|
|
defaultFileFlags,
|
|
|
|
defaultFilePerm,
|
|
|
|
defaultFileExpire,
|
2020-03-25 23:36:56 +08:00
|
|
|
)
|
|
|
|
if err != nil {
|
2020-09-01 21:22:19 +08:00
|
|
|
// panic(err)
|
2021-06-26 16:23:54 +08:00
|
|
|
intlog.Error(ctx, err)
|
2020-03-25 23:36:56 +08:00
|
|
|
}
|
|
|
|
return file
|
|
|
|
}
|
|
|
|
|
2021-08-08 13:56:26 +08:00
|
|
|
// printStd prints content `s` without stack.
|
2021-09-27 21:27:24 +08:00
|
|
|
func (l *Logger) printStd(ctx context.Context, level int, value ...interface{}) {
|
|
|
|
l.print(ctx, level, value...)
|
2018-04-19 16:24:48 +08:00
|
|
|
}
|
|
|
|
|
2021-08-08 13:56:26 +08:00
|
|
|
// printStd prints content `s` with stack check.
|
2021-09-27 21:27:24 +08:00
|
|
|
func (l *Logger) printErr(ctx context.Context, level int, value ...interface{}) {
|
2019-10-26 10:58:07 +08:00
|
|
|
if l.config.StStatus == 1 {
|
2019-06-29 10:45:50 +08:00
|
|
|
if s := l.GetStack(); s != "" {
|
2019-06-29 23:35:32 +08:00
|
|
|
value = append(value, "\nStack:\n"+s)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// In matter of sequence, do not use stderr here, but use the same stdout.
|
2021-09-27 21:27:24 +08:00
|
|
|
l.print(ctx, level, value...)
|
2019-06-01 22:36:12 +08:00
|
|
|
}
|
|
|
|
|
2021-08-08 13:56:26 +08:00
|
|
|
// format formats `values` using fmt.Sprintf.
|
2019-06-19 09:06:52 +08:00
|
|
|
func (l *Logger) format(format string, value ...interface{}) string {
|
2019-06-01 22:36:12 +08:00
|
|
|
return fmt.Sprintf(format, value...)
|
2018-12-15 15:50:39 +08:00
|
|
|
}
|
|
|
|
|
2019-06-29 10:45:50 +08:00
|
|
|
// PrintStack prints the caller stack,
|
2021-08-08 13:56:26 +08:00
|
|
|
// the optional parameter `skip` specify the skipped stack offset from the end point.
|
2021-09-27 21:27:24 +08:00
|
|
|
func (l *Logger) PrintStack(ctx context.Context, skip ...int) {
|
2019-06-29 10:45:50 +08:00
|
|
|
if s := l.GetStack(skip...); s != "" {
|
2021-10-30 19:44:22 +08:00
|
|
|
l.Print(ctx, "Stack:\n"+s)
|
2019-06-01 11:01:57 +08:00
|
|
|
} else {
|
2021-10-30 19:44:22 +08:00
|
|
|
l.Print(ctx)
|
2019-06-01 11:01:57 +08:00
|
|
|
}
|
2018-08-27 23:58:32 +08:00
|
|
|
}
|
|
|
|
|
2019-06-29 10:45:50 +08:00
|
|
|
// GetStack returns the caller stack content,
|
2021-08-08 13:56:26 +08:00
|
|
|
// the optional parameter `skip` specify the skipped stack offset from the end point.
|
2019-06-29 10:45:50 +08:00
|
|
|
func (l *Logger) GetStack(skip ...int) string {
|
2019-10-26 10:58:07 +08:00
|
|
|
stackSkip := l.config.StSkip
|
2019-08-24 23:08:17 +08:00
|
|
|
if len(skip) > 0 {
|
|
|
|
stackSkip += skip[0]
|
|
|
|
}
|
2020-11-12 18:38:58 +08:00
|
|
|
filters := []string{pathFilterKey}
|
2019-10-26 10:58:07 +08:00
|
|
|
if l.config.StFilter != "" {
|
|
|
|
filters = append(filters, l.config.StFilter)
|
2019-08-26 20:09:24 +08:00
|
|
|
}
|
|
|
|
return gdebug.StackWithFilters(filters, stackSkip)
|
2019-05-23 19:14:16 +08:00
|
|
|
}
|
2021-08-12 21:58:06 +08:00
|
|
|
|
|
|
|
// GetConfig returns the configuration of current Logger.
|
|
|
|
func (l *Logger) GetConfig() Config {
|
|
|
|
return l.config
|
|
|
|
}
|