You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
crate/log/logsdk/entry.go

217 lines
6.2 KiB
Go

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
}