|
|
|
package logsdk
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Entry 包含日志所需的全部中间信息并负责输出日志
|
|
|
|
type Entry struct {
|
|
|
|
logger *Logger
|
|
|
|
time time.Time
|
|
|
|
fields []KV
|
|
|
|
callerSkip int
|
|
|
|
reportCaller bool
|
|
|
|
isReportCallerSet bool
|
|
|
|
reportStack bool
|
|
|
|
isReportStackSet bool
|
|
|
|
initialized bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (entry Entry) copy() Entry {
|
|
|
|
if entry.initialized {
|
|
|
|
return entry
|
|
|
|
}
|
|
|
|
return entry.logger.newEntry()
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddCallerSkip 增加调用 [runtime.Callers] 时的 skip 参数,
|
|
|
|
// 当通过装饰器等方式封装 Entry 导致增加调用 Entry 方法的深度时使用 AddCallerSkip 调整 skip,
|
|
|
|
// 直接在需要日志的地方调用 Entry 的方法时不需要 AddCallerSkip.
|
|
|
|
func (entry Entry) AddCallerSkip(n int) Entry {
|
|
|
|
newEntry := entry.copy()
|
|
|
|
newEntry.callerSkip += n
|
|
|
|
return newEntry
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithField 增加1组键值对
|
|
|
|
func (entry Entry) WithField(key string, value any) Entry {
|
|
|
|
return entry.WithFields(Field(key, value))
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithFields 增加键值对
|
|
|
|
func (entry Entry) WithFields(fields ...KV) Entry {
|
|
|
|
newEntry := entry.copy()
|
|
|
|
newEntry.fields = make([]KV, len(entry.fields)+len(fields))
|
|
|
|
copy(newEntry.fields, entry.fields)
|
|
|
|
copy(newEntry.fields, fields)
|
|
|
|
return newEntry
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithTime 设置日志的时间,
|
|
|
|
// Entry 默认使用调用 Log 等最终方法的时间作为日志的时间.
|
|
|
|
func (entry Entry) WithTime(t time.Time) Entry {
|
|
|
|
newEntry := entry.copy()
|
|
|
|
newEntry.time = t
|
|
|
|
return newEntry
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetReportCaller 获取是否收集调用记录,
|
|
|
|
// 默认使用 Logger 上的对应配置.
|
|
|
|
func (entry Entry) GetReportCaller() bool {
|
|
|
|
if entry.isReportCallerSet {
|
|
|
|
return entry.reportCaller
|
|
|
|
}
|
|
|
|
return entry.logger.GetReportCaller()
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithReportCaller 设置是否收集调用记录
|
|
|
|
func (entry Entry) WithReportCaller(reportCaller bool) Entry {
|
|
|
|
newEntry := entry.copy()
|
|
|
|
newEntry.reportCaller = reportCaller
|
|
|
|
newEntry.isReportCallerSet = true
|
|
|
|
return newEntry
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetReportStack 获取是否收集调用栈,
|
|
|
|
// 默认使用 Logger 上的对应配置.
|
|
|
|
func (entry Entry) GetReportStack() bool {
|
|
|
|
if entry.isReportStackSet {
|
|
|
|
return entry.reportStack
|
|
|
|
}
|
|
|
|
return entry.logger.GetReportStack()
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithReportStack 设置是否收集调用栈
|
|
|
|
func (entry Entry) WithReportStack(reportStack bool) Entry {
|
|
|
|
newEntry := entry.copy()
|
|
|
|
newEntry.reportStack = reportStack
|
|
|
|
newEntry.isReportStackSet = true
|
|
|
|
return newEntry
|
|
|
|
}
|
|
|
|
|
|
|
|
// Log 输出日志
|
|
|
|
func (entry Entry) Log(ctx context.Context, level Level, args ...any) {
|
|
|
|
entry.log(ctx, level, fmt.Sprint(args...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Trace 输出 LevelTrace 等级的日志
|
|
|
|
func (entry Entry) Trace(ctx context.Context, args ...any) {
|
|
|
|
entry.log(ctx, LevelTrace, fmt.Sprint(args...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Debug 输出 LevelDebug 等级的日志
|
|
|
|
func (entry Entry) Debug(ctx context.Context, args ...any) {
|
|
|
|
entry.log(ctx, LevelDebug, fmt.Sprint(args...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Info 输出 LevelInfo 等级的日志
|
|
|
|
func (entry Entry) Info(ctx context.Context, args ...any) {
|
|
|
|
entry.log(ctx, LevelInfo, fmt.Sprint(args...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Warn 输出 LevelWarn 等级的日志
|
|
|
|
func (entry Entry) Warn(ctx context.Context, args ...any) {
|
|
|
|
entry.log(ctx, LevelWarn, fmt.Sprint(args...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Error 输出 LevelError 等级的日志
|
|
|
|
func (entry Entry) Error(ctx context.Context, args ...any) {
|
|
|
|
entry.log(ctx, LevelError, fmt.Sprint(args...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fatal 输出 LevelFatal 等级的日志并调用 Logger.Exit
|
|
|
|
func (entry Entry) Fatal(ctx context.Context, args ...any) {
|
|
|
|
entry.log(ctx, LevelFatal, fmt.Sprint(args...))
|
|
|
|
entry.logger.Exit(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Panic 输出 LevelPanic 等级的日志后执行 panic,
|
|
|
|
// 即使 Logger 日志等级高于 LevelPanic 也会 panic.
|
|
|
|
func (entry Entry) Panic(ctx context.Context, args ...any) {
|
|
|
|
entry.log(ctx, LevelPanic, fmt.Sprint(args...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Logf 格式化输出日志
|
|
|
|
func (entry Entry) Logf(ctx context.Context, level Level, format string, args ...any) {
|
|
|
|
entry.log(ctx, level, fmt.Sprintf(format, args...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tracef 格式化输出 LevelTrace 等级的日志
|
|
|
|
func (entry Entry) Tracef(ctx context.Context, format string, args ...any) {
|
|
|
|
entry.log(ctx, LevelTrace, fmt.Sprintf(format, args...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Debugf 格式化输出 LevelDebug 等级的日志
|
|
|
|
func (entry Entry) Debugf(ctx context.Context, format string, args ...any) {
|
|
|
|
entry.log(ctx, LevelDebug, fmt.Sprintf(format, args...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Infof 格式化输出 LevelInfo 等级的日志
|
|
|
|
func (entry Entry) Infof(ctx context.Context, format string, args ...any) {
|
|
|
|
entry.log(ctx, LevelInfo, fmt.Sprintf(format, args...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Warnf 格式化输出 LevelWarn 等级的日志
|
|
|
|
func (entry Entry) Warnf(ctx context.Context, format string, args ...any) {
|
|
|
|
entry.log(ctx, LevelWarn, fmt.Sprintf(format, args...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Errorf 格式化输出 LevelError 等级的日志
|
|
|
|
func (entry Entry) Errorf(ctx context.Context, format string, args ...any) {
|
|
|
|
entry.log(ctx, LevelError, fmt.Sprintf(format, args...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fatalf 格式化输出 LevelFatal 等级的日志并调用 Logger.Exit
|
|
|
|
func (entry Entry) Fatalf(ctx context.Context, format string, args ...any) {
|
|
|
|
entry.log(ctx, LevelFatal, fmt.Sprintf(format, args...))
|
|
|
|
entry.logger.Exit(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Panicf 格式化输出 LevelPanic 等级的日志,
|
|
|
|
// 即使 Logger 日志等级高于 LevelPanic 也会 panic.
|
|
|
|
func (entry Entry) Panicf(ctx context.Context, format string, args ...any) {
|
|
|
|
entry.log(ctx, LevelPanic, fmt.Sprintf(format, args...))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (entry Entry) log(ctx context.Context, level Level, message string) {
|
|
|
|
defer func() {
|
|
|
|
if level == LevelPanic {
|
|
|
|
panic(message)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
newEntry := entry.copy()
|
|
|
|
if newEntry.logger.GetLevel() < level {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
readonlyEntry := ReadonlyEntry{
|
|
|
|
Fields: newEntry.fields,
|
|
|
|
Message: message,
|
|
|
|
Time: newEntry.time,
|
|
|
|
Level: level,
|
|
|
|
}
|
|
|
|
if readonlyEntry.Time.IsZero() {
|
|
|
|
readonlyEntry.Time = time.Now()
|
|
|
|
}
|
|
|
|
if newEntry.GetReportCaller() {
|
|
|
|
readonlyEntry.Caller = getCaller(newEntry.callerSkip)
|
|
|
|
}
|
|
|
|
if newEntry.GetReportStack() || level <= newEntry.logger.GetReportStackLevel() {
|
|
|
|
readonlyEntry.Stack = getStack(newEntry.callerSkip, maximumFrames)
|
|
|
|
}
|
|
|
|
for _, processor := range newEntry.logger.getLevelProcessors(level) {
|
|
|
|
processor.Process(ctx, readonlyEntry)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ReadonlyEntry 是日志系统收集到1条日志记录
|
|
|
|
type ReadonlyEntry struct {
|
|
|
|
Caller Frame
|
|
|
|
Stack []Frame
|
|
|
|
Time time.Time
|
|
|
|
Message string
|
|
|
|
Fields []KV
|
|
|
|
Level Level
|
|
|
|
}
|