Files
loggerx/options.go
T

326 lines
8.0 KiB
Go
Raw Normal View History

2024-01-22 18:05:51 +08:00
package loggerx
import (
2026-09-13 21:53:37 +08:00
"compress/gzip"
"io"
"os"
"time"
)
2024-04-15 23:26:55 +08:00
2024-01-22 18:05:51 +08:00
type loggerOption struct {
2024-01-23 00:12:08 +08:00
prefix string // 日志前缀
2026-09-14 00:14:30 +08:00
format Format // json / text
2024-01-23 00:12:08 +08:00
dir string // 文件目录
isGinLog bool
isGid bool
2024-07-09 15:36:11 +08:00
isPrintFile bool
2026-09-14 00:14:30 +08:00
asGlobalLog bool // 是否接管全局 stdlib log(默认 false
2024-11-22 20:08:25 +08:00
writeType writeType // 是否异步罗盘
traceField string // trace字段
errorToInfo bool // 错误日志是否写入info日志
days int // 日志保存天数
drivers []io.Writer // 文件落盘驱动器
fileSplit FileSplit // 文件切割规则
2026-09-13 21:53:37 +08:00
sizeSplit int // 根据文件大小切割(字节,<=0 不切割)
compress bool // 归档文件是否压缩为 .gz
compressLvl int // gzip 压缩级别
flushEvery time.Duration // 定时刷盘间隔,0 表示不开启
2026-09-14 00:14:30 +08:00
minLevel Level // 最低输出级别
onError func(error) // 内部错误回调
timeZone *time.Location // 时区
2025-01-15 15:29:45 +08:00
escapeHTML bool
2025-06-10 15:41:44 +08:00
expandData map[string]string // 扩展字段
2024-01-22 18:05:51 +08:00
}
2024-11-22 20:08:25 +08:00
type writeType uint8
const (
// 0.默认(同步) 1.指定同步 2.指定异步
writeTypeDefault writeType = iota
writeTypeSync
writeTypeAsync
)
2024-01-22 18:05:51 +08:00
func defaultOptions() loggerOption {
return loggerOption{
2026-09-14 00:14:30 +08:00
isGinLog: false, // 默认不接管 gin 写手:非 Gin 服务不该被改全局状态
2024-07-09 15:36:11 +08:00
isGid: true,
isPrintFile: true,
2024-11-22 20:08:25 +08:00
writeType: writeTypeDefault, // 默认同步
2026-09-14 00:14:30 +08:00
format: FormatJSON,
2024-07-09 15:36:11 +08:00
dir: "./log",
traceField: "trace_id",
days: 7,
fileSplit: FileSplitTimeE,
2026-09-13 21:53:37 +08:00
compress: true,
compressLvl: gzip.BestSpeed,
2024-07-09 15:36:11 +08:00
timeZone: time.Local,
2025-01-15 15:29:45 +08:00
escapeHTML: true,
2025-06-10 15:41:44 +08:00
expandData: make(map[string]string),
2024-01-22 18:05:51 +08:00
}
}
type Option func(*loggerOption)
2024-01-23 00:12:08 +08:00
// trace字段
func SetTraceField(traceField string) Option {
return func(o *loggerOption) {
o.traceField = traceField
}
}
2025-08-23 19:17:40 +08:00
// 1.info 2.error 3.debug 4.warn 5.fatal
2025-06-10 15:41:44 +08:00
// 附加字段
func SetExpandData(key string, value string) Option {
return func(o *loggerOption) {
if o.expandData == nil {
o.expandData = make(map[string]string)
}
o.expandData[key] = value
}
}
2024-11-22 20:08:25 +08:00
// 是否异步写入
func SetWriteAsync() Option {
return func(o *loggerOption) {
o.writeType = writeTypeAsync
}
}
// 打印到控制台
func SetToConsole() Option {
return func(o *loggerOption) {
o.drivers = append(o.drivers, os.Stdout)
}
}
2024-01-23 00:12:08 +08:00
// 错误日志是否写入info日志
func SetErrorToInfo() Option {
return func(o *loggerOption) {
o.errorToInfo = true
}
}
2026-09-14 00:14:30 +08:00
// 日志前缀
// 会加在每行日志最前面(JSON 与 text 都生效),便于多实例共用一个目录时区分来源
2024-01-22 18:05:51 +08:00
func SetPrefix(prefix string) Option {
return func(o *loggerOption) {
o.prefix = prefix
}
}
2026-09-14 00:14:30 +08:00
// 输出格式
type Format string
const (
// FormatJSON 每行一条 JSON(默认,推荐给采集端)
FormatJSON Format = "json"
// FormatText 每行一条紧凑文本,适合人直接看
FormatText Format = "text"
)
// 日志格式(默认 FormatJSON
// 传非法值时保持原值,不会静默切到别的格式
func SetFormat(format Format) Option {
2024-01-22 18:05:51 +08:00
return func(o *loggerOption) {
2026-09-14 00:14:30 +08:00
if format == FormatJSON || format == FormatText {
o.format = format
}
2024-01-22 18:05:51 +08:00
}
}
2024-07-09 15:36:11 +08:00
// 设置是否打印到文件
func SetPrintFile(print bool) Option {
return func(o *loggerOption) {
o.isPrintFile = print
}
}
2024-01-22 18:05:51 +08:00
// 是否保存gin的日志
2024-04-15 23:40:55 +08:00
func SetGinLog(open bool) Option {
2024-01-22 18:05:51 +08:00
return func(o *loggerOption) {
2024-04-15 23:40:55 +08:00
o.isGinLog = open
2024-01-22 18:05:51 +08:00
}
}
2026-09-14 00:14:30 +08:00
// 日志级别。级别低于设定值的日志会被直接丢弃,不落盘
type Level uint8
const (
LevelDebug Level = iota
LevelInfo
LevelWarn
LevelError
// LevelOff 关闭所有级别(连 error 也不写)
LevelOff
)
// String 便于打印
func (lv Level) String() string {
switch lv {
case LevelDebug:
return "debug"
case LevelInfo:
return "info"
case LevelWarn:
return "warn"
case LevelError:
return "error"
case LevelOff:
return "off"
default:
return "unknown"
}
}
// SetMinLevel 设置最低输出级别(默认 LevelDebug,即全部输出)
//
// 生产环境通常设成 LevelInfo:这样代码里的 Debug 调用不会白算一遍
// JSON、也不会落盘占空间
func SetMinLevel(lv Level) Option {
return func(o *loggerOption) {
o.minLevel = lv
}
}
// SetErrorHandler 注册内部错误处理回调(默认 nil)
//
// 用于把「日志库自身的故障」暴露给运维:磁盘满、句柄失效、归档压缩失败、
// 定时刷盘失败等。不注册时这些错误只体现在返回值里,而调用方通常忽略返回值,
// 问题就完全不可见了。
//
// 建议接到告警通道或一个「不会失败」的输出(例如 stderr):
//
// loggerx.NewLogger(ctx, loggerx.SetErrorHandler(func(err error) {
// fmt.Fprintln(os.Stderr, "loggerx:", err)
// }))
//
// 回调在写日志的调用栈上同步执行,务必保持轻量,
// 且不要在里面再调用本实例的日志方法(可能递归)
func SetErrorHandler(fn func(error)) Option {
return func(o *loggerOption) {
o.onError = fn
}
}
// 是否把全局标准库 log 的输出接管到本实例(默认 false,不接管)
//
// 默认不接管是刻意的:日志库在 import / NewLogger 时静默劫持宿主全局 log
// 会带来两个生产事故场景 —— 多个实例时后建的把先建的顶掉;
// Close 之后全局 log 仍指向已关闭实例,之后的日志被静默丢弃。
// 确需接管(例如老代码大量使用 log.Printf)时再显式打开。
func SetAsGlobalLog() Option {
return func(o *loggerOption) {
o.asGlobalLog = true
}
}
2024-01-23 00:12:08 +08:00
// 文件路径
func SetDir(dir string) Option {
2024-01-22 18:05:51 +08:00
return func(o *loggerOption) {
2024-03-13 16:39:42 +08:00
if dir != "" {
o.dir = dir
}
2024-01-22 18:05:51 +08:00
}
}
// 保存goroutine的ID信息
2024-04-15 23:40:55 +08:00
func SetGID(open bool) Option {
2024-01-22 18:05:51 +08:00
return func(o *loggerOption) {
2024-04-15 23:40:55 +08:00
o.isGid = open
2024-01-22 18:05:51 +08:00
}
}
2024-01-23 13:37:51 +08:00
// 日志保存天数
func SetDays(days int) Option {
return func(o *loggerOption) {
o.days = days
}
}
2024-04-15 23:26:55 +08:00
// 设置时区
func SetTimeZone(loc *time.Location) Option {
2024-04-15 23:26:55 +08:00
return func(o *loggerOption) {
o.timeZone = loc
2024-04-15 23:26:55 +08:00
}
}
// 文件额外的驱动
func SetExtraDriver(ds ...io.Writer) Option {
return func(o *loggerOption) {
2024-04-21 12:23:26 +08:00
for _, d := range ds {
if d != nil {
o.drivers = append(o.drivers, d)
}
}
2024-04-15 23:26:55 +08:00
}
}
2024-01-22 18:05:51 +08:00
// 文件切割规则
2024-01-23 00:12:08 +08:00
// 1.文件大小
// 2.时间A(年/月/日/时)
// 3.时间B(年/月-日)
// 4.时间C(年-月-日-时)
// 5.时间D(年-月-日)
2024-05-08 16:33:58 +08:00
func SetFileSplit(split FileSplit) Option {
return func(o *loggerOption) {
o.fileSplit = split
}
}
2024-01-23 00:12:08 +08:00
2024-05-08 16:33:58 +08:00
type FileSplit string
const (
FileSplitNone FileSplit = "none" // 不切割
FileSplitTimeA FileSplit = "timeA" // (年/月/日/时)
FileSplitTimeB FileSplit = "timeB" // (年/月/日)
FileSplitTimeC FileSplit = "timeC" // (年/月-日)
FileSplitTimeD FileSplit = "timeD" // (年-月-日-时)
FileSplitTimeE FileSplit = "timeE" // (年-月-日)
)
2026-09-13 21:53:37 +08:00
// 根据文件大小切割
// m 为单个文件的大小上限(字节);<=0 表示不按大小切割
// 超过上限时当前文件会被改名归档(并可选压缩),随后写入新文件
2024-05-08 16:33:58 +08:00
func SetSizeSplit(m int) Option {
return func(o *loggerOption) {
o.sizeSplit = m
}
}
2025-01-15 15:29:45 +08:00
2026-09-13 21:53:37 +08:00
// 归档文件是否压缩成 .gz(默认开启)
// 压缩在后台协程完成,不阻塞写入
func SetCompress(open bool) Option {
return func(o *loggerOption) {
o.compress = open
}
}
// 压缩级别 1~9,数字越大压缩率越高、CPU 开销越大,默认 gzip.BestSpeed
func SetCompressLevel(level int) Option {
return func(o *loggerOption) {
if level >= gzip.HuffmanOnly && level <= gzip.BestCompression {
o.compressLvl = level
}
}
}
// 定时刷盘间隔(默认 0 = 不开启)
// 开启后会按间隔把内存缓冲刷到磁盘,把「进程崩溃时可能丢失的数据量」
// 从「最多 32KB 缓冲」压缩到「一个间隔内产生的日志量」
func SetFlushInterval(d time.Duration) Option {
return func(o *loggerOption) {
if d > 0 {
o.flushEvery = d
}
}
}
2025-01-15 15:29:45 +08:00
func SetEscapeHTML(b bool) Option {
return func(o *loggerOption) {
o.escapeHTML = b
}
}