Documentation
¶
Overview ¶
Package logit 是 pixiu 的日志模块:门面与核心同包,零第三方依赖,性能优先。
日常使用(不需要轮转时只需 import logit 一个包):
logger := logit.MustNew(logit.OptWriter(logit.Stdout()))
logit.SetDefault(logger) // 显式启用默认日志
defer logit.Close(logger)
ctx := context.Background()
ctx = logit.WithContextLogID(ctx) // 入口初始化字段并生成链路 ID
ctx = logit.WithStart(ctx) // 记录请求起点
msgCtx := logit.NewContextScope(ctx) // 并发消息各用独立字段存储
msgCtx = logit.NewDurationScope(msgCtx) // 独立计时,不继承父请求耗时表
logit.AddField(ctx, logit.Str("uid", "42")) // 请求级字段
logit.Info(ctx, "user login", logit.Int("uid", 42))
logit.AddDownstreamDurationAuto(ctx, "mysql", 12*time.Millisecond) // 自动生成 mysql_1
logit.InfoDuration(ctx, "request done") // 自动追加 mysql_1、self 和 total 耗时
svc := logit.With(logit.Str("mod", "Order")) // 模块级子 Logger
svc.Error(ctx, "create failed", logit.Err(err))
WithContextLogID 每次调用都会追加新的 ID,只在入口调用一次;后续直接传递 ctx。 无需 ID 时仍使用 WithContext;已有 ID 时初始化后调用 AddMeta(ctx, Str(LogId, id))。LogIDFromContext 读取 meta 中最后一个非空字符串 LogId, 不从普通字段或调用点字段读取,不改变日志重复字段的输出规则。
基础功能模块可用 AddDownstreamDurationAuto 自动编号并记录下游耗时;ctx 没有 WithStart 时跳过,不要求未启用耗时统计的调用方额外初始化 context。
按 context 选择命名 Logger(未注册时回退默认 Logger):
logit.SetNamed("http", logit.MustNew(logit.OptWriter(logit.Stderr())))
httpCtx := logit.WithLoggerName(ctx, "http")
if logit.InfoEnabled(httpCtx) {
logit.Output(httpCtx, logit.InfoLevel, 0, "request done")
}
DebugEnabled/InfoEnabled/WarnEnabled/ErrorEnabled 按 ctx 选择 Logger; 任意级别可通过 LoggerFromContext(ctx).Enabled(level) 判断。 无 ctx 的 logit.With 始终基于默认 Logger。上例 Output 的 callDepth=0 指向其直接调用者。
统一记录下游调用时,可用 DownstreamFields 生成四个标准字段:
fields := logit.DownstreamFields("httpcall", "wechat", 12*time.Millisecond,
map[string]any{"method": "POST", "status": 200})
logit.Info(ctx, "downstream call", fields...)
四个标准字段名也可通过普通字段构造器直接写入。
构造专属实例(依赖注入 / 测试):
buf := &bytes.Buffer{}
logger := logit.MustNew(logit.OptWriter(logit.NewWriter(buf)))
生产落盘链路:
file, _ := rotatefile.New("/var/log/app/app.log") // 独立轮转包;要求绝对路径
rotated := logit.NewWriter(file)
logger := logit.MustNew(logit.OptDispatch(
logit.Target{Levels: []logit.Level{logit.DebugLevel, logit.InfoLevel}, Writer: rotated},
))
defer logit.Close(logger) // 应用退出最后一步
_ = logit.SetMinLevel(logger, logit.InfoLevel) // 可在运行期原子调整
应用退出时,先停止接收新请求、等待后台任务结束并关闭其他组件,再关闭 Logger。 其他组件在收尾期间可能仍需记录日志,因此 logit.Close 应是资源关闭的最后一步。
多资源关闭时,可用 lifecycle.Stack 替代上例的 defer,按登记的逆序关闭:
var stack lifecycle.Stack
if err := stack.Register(func() error { return logit.Close(logger) }); err != nil {
return err
}
if err := stack.Register(client.Close); err != nil { // client 由应用创建
return err
}
// 停止业务入口并等待使用 client 的任务结束后:
return stack.Close() // 先关闭 client,最后关闭 logger
全局默认 Logger 初始为空操作 Logger;所有级别(含 Fatal)直接返回,不输出、不退出, 不校验输出字段或执行 Defer 回调;Enabled 始终为 false,With 仍为空操作,Close 返回 nil。 启动期用 SetDefault 显式启用;独立构造和显式注册的命名 Logger 不受默认配置影响。 初始化前取得的 Logger 或 With 子 Logger 保持空操作,需要输出时须重新获取。 使用 bootstrap 的新项目须先完成 MustBaseInit,再通过 Default、With 或 Named 创建和保存模块 Logger; 不要在先于 bootstrap 执行的包变量初始化或 Go 的 init() 中缓存这些 Logger。 后续 SetDefault 或命名注册不会更新已保存的空操作实例;包级 Info(ctx, ...) 等方法每次选择当前 Logger。 WithContext 前置约束及 panic 专用接口语义不受默认 Logger 是否配置影响。 测试可先用 Default 保存旧值,再用 SetDefault 替换并在结束时恢复。 panic 处理见 ReportPanic/RecoverAndReport;processStart 保存包初始化时的时间点, 输出时按当前 time.Local 格式化。应用必须在并发使用日志前完成默认时区设置。
Index ¶
- Constants
- Variables
- func AddDebugField(ctx context.Context, fields ...Field)
- func AddDownstreamDurationAuto(ctx context.Context, prefix string, duration time.Duration)
- func AddField(ctx context.Context, fields ...Field)
- func AddMeta(ctx context.Context, fields ...Field)
- func CallerPath(skip int) string
- func Close(l Logger) error
- func Debug(ctx context.Context, msg string, fields ...Field)
- func DebugEnabled(ctx context.Context) bool
- func Error(ctx context.Context, msg string, fields ...Field)
- func ErrorEnabled(ctx context.Context) bool
- func Fatal(ctx context.Context, msg string, fields ...Field)
- func HookStderr(w Writer) error
- func HookStdout(w Writer) error
- func Info(ctx context.Context, msg string, fields ...Field)
- func InfoDuration(ctx context.Context, msg string, fields ...Field)
- func InfoEnabled(ctx context.Context) bool
- func LogIDFromContext(ctx context.Context) (string, bool)
- func NewContextScope(parent context.Context) context.Context
- func NewDurationScope(parent context.Context) context.Context
- func NewLogID() string
- func Output(ctx context.Context, level Level, callDepth int, msg string, fields ...Field)
- func RecoverAndReport(ctx context.Context)
- func ReportPanic(ctx context.Context, recovered any, fields ...Field) error
- func SetDefault(l Logger)
- func SetMinLevel(l Logger, level Level) error
- func SetNamed(name string, l Logger)
- func SetPanicLogger(w Writer)
- func Warn(ctx context.Context, msg string, fields ...Field)
- func WarnEnabled(ctx context.Context) bool
- func WithContext(ctx context.Context) context.Context
- func WithContextLogID(ctx context.Context) context.Context
- func WithLoggerName(ctx context.Context, name string) context.Context
- func WithStart(ctx context.Context) context.Context
- type Encoder
- type Field
- func Any(key string, v any) Field
- func Auto(key string, v any) Field
- func Bool(key string, v bool) Field
- func Defer(key string, fn func() Field) Field
- func DownstreamFields(kind, id string, duration time.Duration, details map[string]any) []Field
- func Dur(key string, v time.Duration) Field
- func Err(err error) Field
- func ErrKey(key string, err error) Field
- func Float64(key string, v float64) Field
- func Int(key string, v int) Field
- func Int64(key string, v int64) Field
- func Str(key string, v string) Field
- func Time(key string, v time.Time) Field
- func Uint64(key string, v uint64) Field
- type FieldType
- type JSONEncoder
- type Level
- type LevelController
- type Logger
- type Option
- func OptCaller(on bool) Option
- func OptDispatch(targets ...Target) Option
- func OptEncoder(enc Encoder) Option
- func OptFileName(name string) Option
- func OptFilterKeys(keys ...string) Option
- func OptMinLevel(l Level) Option
- func OptNoExit() Option
- func OptOnWriteError(fn func(error)) Option
- func OptWriter(w Writer) Option
- type Target
- type TextEncoder
- type WriteErrorStats
- type Writer
- type WriterKey
Constants ¶
const ( DownstreamTypeKey = "downstream_type" DownstreamDurationMSKey = "downstream_duration_ms" DownstreamIDKey = "downstream_id" DownstreamDetailsKey = "downstream_details" )
下游日志的标准字段名,调用方也可直接用普通字段构造器写入。
const LogId = "logId"
LogId 是链路 ID 的统一日志字段名;通过 AddMeta(ctx, Str(LogId, id)) 设置传播值。
Variables ¶
var DefaultJSONEncoder = JSONEncoder{}
DefaultJSONEncoder 是共享的 JSON 编码器实例(无状态,可复用)。
var DefaultTextEncoder = TextEncoder{}
DefaultTextEncoder 是共享的文本编码器实例(无状态,可复用)。
var ErrLevelControlUnsupported = errors.New("logit: logger does not support runtime level control")
ErrLevelControlUnsupported 表示 Logger 没有实现运行时级别调整。
var ErrLoggerCloseUnsupported = errors.New("logit: logger does not support close")
ErrLoggerCloseUnsupported 表示自定义 Logger 未提供 Close 方法。
var ErrPanicLoggerNotConfigured = errors.New("logit: panic logger not configured")
ErrPanicLoggerNotConfigured 表示尚未设置 panic 专用 Logger。
Functions ¶
func AddDebugField ¶
AddDebugField 添加仅 Debug 级别日志行可见的字段(敏感调试信息不漏进 Info 日志)。 保留字段名会 panic。
func AddDownstreamDurationAuto ¶
AddDownstreamDurationAuto 自动为一次下游调用生成请求内唯一的 prefix_序号; 空 prefix、self、total 会 panic;有效 prefix 在 ctx 没有 WithStart 时跳过。 适合基础功能模块在不要求业务启用耗时统计时调用。
func AddField ¶
AddField 向普通作用域添加字段(所有级别可见)。ctx 必须已经 WithContext, 否则 panic——这是编程错误,应在首次测试时暴露。保留字段名也会 panic。
func CallerPath ¶
CallerPath 返回调用点 file:line(跳过 skip 层栈帧,0 = 调用 CallerPath 处), 路径裁剪掉模块前缀以缩短行宽。定位失败返回 "unknown"。
func Close ¶
Close 关闭 Logger 的全部目标 writer(应用优雅关闭的最后一步调用)。 自定义 Logger 实现 Close() error 时调用该方法,否则返回 ErrLoggerCloseUnsupported。
func DebugEnabled ¶
DebugEnabled 报告 ctx 选中的 Logger 是否输出 Debug,超热路径守卫用:
if logit.DebugEnabled(ctx) { logit.Debug(ctx, "detail", logit.Defer(...)) }
ctx 未指定命名 Logger 时检查默认 Logger。
func ErrorEnabled ¶
func HookStderr ¶
HookStderr 把进程标准错误劫持到 w:未捕获 panic 的 runtime 输出、 三方库错误打印等一并进入 w。要求与注意事项同 HookStdout。
func HookStdout ¶
HookStdout 把进程标准输出劫持到 w:fmt.Println、三方库直接打印等 原本走 stdout 的输出改写入 w(推荐使用 OpenFile 打开独立文件)。 w 需实现 Fd() uintptr;nil Writer 返回错误。进程级一次性操作,重复调用以最后一次为准。
注意:dup2 劫持绑定的是打开瞬间的文件描述符;若目标文件会轮转, 轮转发生后续写仍落在已转出的旧文件(随保留策略被清理)。 建议劫持到独立的非轮转文件(如专用 std.log)。
func InfoDuration ¶
InfoDuration 与 Info 相同;ctx 含 WithStart 起点时追加下游、自身和总耗时。
func InfoEnabled ¶
func LogIDFromContext ¶
LogIDFromContext 返回 meta 中最后一个非空字符串 LogId。 普通字段、非字符串与空值不参与传播,也不会执行惰性字段回调。
func NewContextScope ¶
NewContextScope 在保留 parent 取消与其他值的同时创建独立日志字段存储。 消息等并发入口不能复用 parent 的可变字段存储,否则字段会跨消息累积。
func NewDurationScope ¶
NewDurationScope 创建独立起点和下游耗时表,保留 parent 的取消、期限及其他值。 嵌套的独立工作使用此入口;普通派生仍用 WithStart 保留首次计时。
func RecoverAndReport ¶
RecoverAndReport 是 defer 用的便捷 recover 处理器: 未配置 panic Logger 时重新抛出原 panic,避免静默吞掉异常。
defer logit.RecoverAndReport(ctx)
func ReportPanic ¶
ReportPanic 记录一次 panic:panic 值、保留物理换行的 goroutine 栈、 pid 与按当前本地时区格式化的进程启动时间;以 Fatal 级别同步写入并尽力 Sync, 写入或 Sync 失败通过 PanicLogger 的 WriteErrorStats 观察,不承诺必然落盘。 未配置 panic Logger 时返回 ErrPanicLoggerNotConfigured;记录后不退出进程。 供 recover 处理器调用,也可用更省心的 RecoverAndReport。
func SetMinLevel ¶
SetMinLevel 在 Logger 支持时原子调整最低输出级别。
func SetPanicLogger ¶
func SetPanicLogger(w Writer)
SetPanicLogger 从 Writer 构造 panic 专用 Logger(推荐使用独立 panic 文件, 需要轮转时由外部创建文件并通过 NewWriter 适配)。只路由 Fatal,固定文本编码、无 caller, 写入并尽力 Sync 后继续运行;无效 Writer 在此处 panic。
func WarnEnabled ¶
func WithContext ¶
WithContext 初始化 ctx 的字段存储(普通 + meta 双作用域),已初始化则原样返回。 之后才可调用 AddField/AddMeta 等可变 API;服务入口处调用一次即可。
func WithContextLogID ¶
WithContextLogID 初始化日志字段存储,并生成、追加一个新的链路 ID。 每次调用都会追加新 ID,应只在入口调用;后续直接传递返回的 context。
func WithLoggerName ¶
WithLoggerName 在 ctx 中设置命名 Logger 的路由键;空名字表示使用默认 Logger。 此路由不要求预先调用 WithContext,也不会写入日志字段。
Types ¶
type Encoder ¶
type Encoder interface {
// AppendPrefix 追加行前缀(级别、时间,以及调用方已解析好的 caller)。
AppendPrefix(buf []byte, level Level, now time.Time, caller string) []byte
// AppendField 追加一个字段(f 已完成 Defer 求值与脱敏)。
AppendField(buf []byte, f Field) []byte
// AppendMessage 追加消息体。
AppendMessage(buf []byte, msg string) []byte
// Finish 追加行尾(如换行符)。
Finish(buf []byte) []byte
}
Encoder 负责把一条日志记录的各部分按顺序追加进字节缓冲。 全部方法以 append 风格工作,编码过程零中间对象分配。 包外自定义实现仅支持包装或嵌入内置编码器,由内置编码器处理 Field; Field 的内部值不开放给包外独立实现字段编码。
type Field ¶
type Field struct {
Key string
// contains filtered or unexported fields
}
Field 是值类型的日志字段:数值直接存进 num,不经过 interface 装箱、不逃逸。 float64 以位模式存于 num;布局 64B,5 字段变参切片 344B,降低调用点分配。 构造函数返回值,调用点以变参切片传给 Logger。
func DownstreamFields ¶
DownstreamFields 构造统一的下游调用字段。 kind 为技术类型,id 为稳定的业务目标标识,duration 以毫秒数值输出, details 为自定义详情;nil details 输出空对象。
type JSONEncoder ¶
type JSONEncoder struct{}
JSONEncoder 输出有序 JSON 行:键顺序 = 编码顺序(前缀 → 字段 → msg), 直接追加进调用方缓冲,无中间 map、无排序。
字符串转义使用表驱动扫描和干净段整段拷贝,并转义 U+2028/U+2029; 输出与 encoding/json(SetEscapeHTML(false)) 逐字节一致,不转义 HTML 字符。
行形如:
{"level":"INFO","ts":"2026-09-15T10:00:00.123+08:00","logId":["..."],
"uid":42,"msg":"user login"}
func (JSONEncoder) AppendField ¶
func (JSONEncoder) AppendField(buf []byte, f Field) []byte
AppendField 实现 Encoder:写入 "key":value 与尾随逗号。
func (JSONEncoder) AppendMessage ¶
func (JSONEncoder) AppendMessage(buf []byte, msg string) []byte
AppendMessage 实现 Encoder:写入 "msg":... 与尾随逗号。
func (JSONEncoder) AppendPrefix ¶
AppendPrefix 实现 Encoder:写入 {"level":..,"ts":..(,"caller":..) 与尾随逗号。
func (JSONEncoder) Finish ¶
func (JSONEncoder) Finish(buf []byte) []byte
Finish 实现 Encoder:去掉最后一个尾随逗号,闭合对象并换行。
type Level ¶
type Level uint16
Level 是位掩码日志级别。单个级别只占一个比特,数值大小与严重程度一致, 因此可以直接用数值比较做"最低级别"过滤;字段可见性用位与判断。
const ( // UnknownLevel 未设置级别。 UnknownLevel Level = 0 // DebugLevel 调试信息。 DebugLevel Level = 1 << 0 // InfoLevel 常规运行信息。 InfoLevel Level = 1 << 1 // WarnLevel 需要关注的异常。 WarnLevel Level = 1 << 2 // ErrorLevel 出错,但程序可继续运行。 ErrorLevel Level = 1 << 3 // FatalLevel 致命错误,程序无法继续运行。 FatalLevel Level = 1 << 4 // AllLevels 所有比特位置位,用于字段可见性:任意级别的日志行都输出该字段。 AllLevels Level = 1<<8 - 1 )
func ParseLevel ¶
ParseLevel 解析级别字符串,大小写不敏感,如 "info"、"ERROR"、"Warn"。 仅在加载配置时调用,不在热路径。
type LevelController ¶
LevelController 是 Logger 的可选运行时级别控制能力。
type Logger ¶
type Logger interface {
// Debug 打印 Debug 级别日志。
Debug(ctx context.Context, msg string, fields ...Field)
// Info 打印 Info 级别日志。
Info(ctx context.Context, msg string, fields ...Field)
// Warn 打印 Warn 级别日志。
Warn(ctx context.Context, msg string, fields ...Field)
// Error 打印 Error 级别日志。
Error(ctx context.Context, msg string, fields ...Field)
// Fatal 打印 Fatal 级别日志,尽力 Sync 后退出进程。
Fatal(ctx context.Context, msg string, fields ...Field)
// Output 打印指定级别日志;callDepth 用于二次封装时修正 caller 定位,
// 0 表示 Output 的直接调用者。
Output(ctx context.Context, level Level, callDepth int, msg string, fields ...Field)
// Enabled 报告该级别日志是否会被输出,供热路径手动守卫:
// if l.Enabled(DebugLevel) { ... } 可彻底省掉字段求值与变参分配。
Enabled(level Level) bool
// With 返回预埋了固定字段的子 Logger(如模块级 mod 字段),不改变其余行为。
// 传入保留字段名会 panic。
With(fields ...Field) Logger
}
Logger 是 pixiu 日志的核心接口。业务代码只依赖它,不依赖任何具体实现。
func LoggerFromContext ¶
LoggerFromContext 返回 ctx 指定的命名 Logger;无名字或未注册时返回默认 Logger。
func PanicLogger ¶
func PanicLogger() Logger
PanicLogger 返回 panic 专用 Logger;未调用 SetPanicLogger 时返回 nil。
type Option ¶
type Option func(*config)
Option 是 Logger 的构造选项,支持配置文件与纯编程两种入口(P0 提供编程式, 配置文件加载由上层 app 模块解析后转成 Option 传入)。
func OptDispatch ¶
OptDispatch 设置分级分发目标(如 Warn 以上写 .wf 文件)。 同一 Writer 可被多个 Target 复用。
func OptEncoder ¶
OptEncoder 指定编码器,默认 DefaultTextEncoder;nil 编码器立即 panic。
func OptFileName ¶
OptFileName 设置绝对路径的追加模式日志文件作为单一目标。文件延迟到 New 最终校验后打开; 打开失败会让 New/MustNew 返回错误(启动期暴露,而不是静默丢日志)。
func OptFilterKeys ¶
OptFilterKeys 设置脱敏字段名:命中字段值统一打码为 ***。
func OptMinLevel ¶
OptMinLevel 设置最低输出级别,低于该级别的日志直接丢弃,默认 DebugLevel。
func OptNoExit ¶
func OptNoExit() Option
OptNoExit 让 Fatal 级别日志写入并尽力 Sync 后不退出进程。 用于 panic 日志等需要记录 Fatal、又要继续运行的 Logger。
func OptOnWriteError ¶
OptOnWriteError 注册写入错误回调。日志调用仍不返回该错误;同一 Logger 及其 With 子 Logger 的回调串行执行。回调应快速完成,且不要写回同一个持续失败的 Logger。
type TextEncoder ¶
type TextEncoder struct{}
TextEncoder 输出以下格式的文本行:
INFO: 2026-09-14T18:00:00.000+08:00 main.go:42 uid=[42] msg=[user login]
func (TextEncoder) AppendField ¶
func (TextEncoder) AppendField(buf []byte, f Field) []byte
AppendField 实现 Encoder。
func (TextEncoder) AppendMessage ¶
func (TextEncoder) AppendMessage(buf []byte, msg string) []byte
AppendMessage 实现 Encoder。
func (TextEncoder) AppendPrefix ¶
AppendPrefix 实现 Encoder。
func (TextEncoder) Finish ¶
func (TextEncoder) Finish(buf []byte) []byte
Finish 实现 Encoder:裁掉行尾多余分隔空格后换行。
type WriteErrorStats ¶
WriteErrorStats 暴露被日志调用吞掉的底层写入错误,供监控与健康检查使用。
type Writer ¶
Writer 是日志落盘目标的接口。NewWriter 可适配普通 io.Writer, OpenFile 提供同步追加文件;轮转文件可由外部按需创建后适配。
契约:Write 必须并发安全且单次调用写入完整记录(普通日志一行,panic 堆栈可多行)。 WriterKey 必须返回生命周期内不变的非零 key;同一 Writer 的副本共享 key。
func NewWriter ¶
NewWriter 把非 nil io.Writer 适配为并发安全的 Writer;nil 输入立即 panic。 底层实现 io.Closer 时 Close 透传;带 Fd 的 io.WriteCloser 也透传文件描述符。 非 *os.File 目标发生短写时会在同一把锁内继续,避免与其他调用交错。