Files
Ant-Browser/backend/internal/logger/logger.go
T
Ant Browser Release Bot 6f58a6c19a publish: 1.0.0 snapshot (bad2ec1)
channel: master
version: 1.0.0
source-ref: master
published-at-utc: 2026-03-13T15:19:28Z
2026-03-13 23:19:29 +08:00

547 lines
12 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package logger
import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
"sync"
"time"
)
// Level 日志级别
type Level int
const (
DEBUG Level = iota
INFO
WARN
ERROR
)
// String 返回日志级别的字符串表示
func (l Level) String() string {
switch l {
case DEBUG:
return "DEBUG"
case INFO:
return "INFO"
case WARN:
return "WARN"
case ERROR:
return "ERROR"
default:
return "UNKNOWN"
}
}
// ParseLevel 解析日志级别字符串
func ParseLevel(levelStr string) Level {
switch strings.ToLower(levelStr) {
case "debug":
return DEBUG
case "info":
return INFO
case "warn", "warning":
return WARN
case "error":
return ERROR
default:
return INFO
}
}
// Field 结构化日志字段
type Field struct {
Key string
Value interface{}
}
// LoggerConfig 日志配置
type LoggerConfig struct {
Level string
FileEnabled bool
FilePath string
Format string // "text" or "json"
BufferSize int // 缓冲区大小(KB
AsyncQueueSize int // 异步队列大小
FlushIntervalMs int // 刷新间隔(毫秒)
// 分片配置
Rotation RotationConfig
}
// RotationConfig 日志分片配置
type RotationConfig struct {
Enabled bool
MaxSizeMB int // 单文件最大大小(MB
MaxAge int // 保留天数
MaxBackups int // 保留文件数
TimeInterval string // 时间间隔: "daily", "hourly"
}
// Logger 日志记录器
type Logger struct {
level Level
component string
ctx context.Context
// 写入器
writers []Writer
consoleWriter Writer
fileWriter *FileWriter
// 分片管理器
rotationManager *RotationManager
// 并发安全
mu sync.RWMutex
// 文件写入失败标志
fileWriteFailed bool
}
// 全局日志实例
var (
globalLogger *Logger
globalMu sync.RWMutex
)
// DefaultLoggerConfig 返回默认日志配置
func DefaultLoggerConfig() LoggerConfig {
return LoggerConfig{
Level: "info",
FileEnabled: false,
FilePath: "data/logs/app.log",
Format: "text",
BufferSize: 4, // 4KB
AsyncQueueSize: 1000,
FlushIntervalMs: 1000, // 1秒
Rotation: RotationConfig{
Enabled: false,
MaxSizeMB: 100,
MaxAge: 7,
MaxBackups: 5,
TimeInterval: "daily",
},
}
}
// Init 初始化全局日志(简单版本,仅控制台输出)
func Init(ctx context.Context, levelStr string) {
InitWithConfig(ctx, LoggerConfig{
Level: levelStr,
FileEnabled: false,
Format: "text",
})
}
// InitWithConfig 使用配置初始化全局日志
func InitWithConfig(ctx context.Context, config LoggerConfig) {
globalMu.Lock()
defer globalMu.Unlock()
// 解析日志级别,无效级别使用默认 INFO
level := ParseLevel(config.Level)
if config.Level != "" && level == INFO && strings.ToLower(config.Level) != "info" {
// 无效级别,记录警告(使用 fmt 因为 logger 还未初始化)
fmt.Printf("[WARN] Invalid log level '%s', using default 'INFO'\n", config.Level)
}
// 创建格式化器
var formatter Formatter
switch strings.ToLower(config.Format) {
case "json":
formatter = NewJSONFormatter()
default:
formatter = NewTextFormatter()
}
// 创建控制台写入器
consoleWriter := NewConsoleWriter(formatter)
logger := &Logger{
level: level,
ctx: ctx,
writers: []Writer{consoleWriter, globalMemoryWriter},
consoleWriter: consoleWriter,
}
// 如果启用文件日志,创建文件写入器
if config.FileEnabled && config.FilePath != "" {
fileWriter, rotationManager, err := createFileWriterWithRotation(config, formatter)
if err != nil {
// 文件写入器创建失败,回退到仅控制台输出
fmt.Printf("[WARN] Failed to create file writer: %v, falling back to console only\n", err)
logger.fileWriteFailed = true
} else {
logger.fileWriter = fileWriter
logger.rotationManager = rotationManager
logger.writers = append(logger.writers, fileWriter)
}
}
globalLogger = logger
}
// createFileWriterWithRotation 创建带分片功能的文件写入器
func createFileWriterWithRotation(config LoggerConfig, formatter Formatter) (*FileWriter, *RotationManager, error) {
// 确保目录存在
dir := filepath.Dir(config.FilePath)
if dir != "" && dir != "." {
if err := os.MkdirAll(dir, 0755); err != nil {
return nil, nil, fmt.Errorf("failed to create log directory: %w", err)
}
}
// 计算缓冲区大小(KB -> 字节)
bufferSize := config.BufferSize * 1024
if bufferSize <= 0 {
bufferSize = 4 * 1024 // 默认 4KB
}
// 计算刷新间隔
flushInterval := time.Duration(config.FlushIntervalMs) * time.Millisecond
if flushInterval <= 0 {
flushInterval = time.Second
}
// 异步队列大小
asyncQueueSize := config.AsyncQueueSize
if asyncQueueSize <= 0 {
asyncQueueSize = 1000
}
fileConfig := FileWriterConfig{
FilePath: config.FilePath,
BufferSize: bufferSize,
FlushInterval: flushInterval,
AsyncQueueSize: asyncQueueSize,
}
// 使用异步文件写入器
fileWriter, err := NewAsyncFileWriter(fileConfig, formatter)
if err != nil {
return nil, nil, err
}
// 创建分片管理器(如果启用)
var rotationManager *RotationManager
if config.Rotation.Enabled {
rotationPolicy := createRotationPolicy(config.Rotation)
rotationManager = NewRotationManager(RotationManagerConfig{
BasePath: config.FilePath,
MaxBackups: config.Rotation.MaxBackups,
MaxAge: config.Rotation.MaxAge,
Policy: rotationPolicy,
})
}
return fileWriter, rotationManager, nil
}
// createRotationPolicy 根据配置创建分片策略
func createRotationPolicy(config RotationConfig) RotationPolicy {
var policies []RotationPolicy
// 时间分片策略
if config.TimeInterval != "" {
var interval TimeInterval
switch strings.ToLower(config.TimeInterval) {
case "hourly":
interval = Hourly
default:
interval = Daily
}
policies = append(policies, NewTimeRotationPolicy(interval))
}
// 大小分片策略
if config.MaxSizeMB > 0 {
policies = append(policies, NewSizeRotationPolicyMB(config.MaxSizeMB))
}
// 如果有多个策略,使用组合策略
if len(policies) > 1 {
return NewCompositeRotationPolicy(policies...)
} else if len(policies) == 1 {
return policies[0]
}
// 默认按天分片
return NewTimeRotationPolicy(Daily)
}
// Close 关闭全局日志
func Close() error {
globalMu.Lock()
defer globalMu.Unlock()
if globalLogger == nil {
return nil
}
var lastErr error
for _, writer := range globalLogger.writers {
if err := writer.Close(); err != nil {
lastErr = err
}
}
globalLogger = nil
return lastErr
}
// New 创建新的日志记录器
func New(component string) *Logger {
globalMu.RLock()
defer globalMu.RUnlock()
if globalLogger == nil {
// 如果全局日志未初始化,创建一个默认的
consoleWriter := NewConsoleWriter(NewTextFormatter())
return &Logger{
level: INFO,
component: component,
writers: []Writer{consoleWriter},
consoleWriter: consoleWriter,
}
}
return &Logger{
level: globalLogger.level,
component: component,
ctx: globalLogger.ctx,
writers: globalLogger.writers,
consoleWriter: globalLogger.consoleWriter,
fileWriter: globalLogger.fileWriter,
rotationManager: globalLogger.rotationManager,
fileWriteFailed: globalLogger.fileWriteFailed,
}
}
// SetLevel 动态设置日志级别(并发安全)
func (l *Logger) SetLevel(level Level) {
l.mu.Lock()
defer l.mu.Unlock()
l.level = level
}
// SetLevelString 通过字符串动态设置日志级别
func (l *Logger) SetLevelString(levelStr string) {
l.SetLevel(ParseLevel(levelStr))
}
// GetLevel 获取当前日志级别
func (l *Logger) GetLevel() Level {
l.mu.RLock()
defer l.mu.RUnlock()
return l.level
}
// SetGlobalLevel 设置全局日志级别
func SetGlobalLevel(level Level) {
globalMu.Lock()
defer globalMu.Unlock()
if globalLogger != nil {
globalLogger.mu.Lock()
globalLogger.level = level
globalLogger.mu.Unlock()
}
}
// SetGlobalLevelString 通过字符串设置全局日志级别
func SetGlobalLevelString(levelStr string) {
SetGlobalLevel(ParseLevel(levelStr))
}
// Debug 记录调试日志
func (l *Logger) Debug(msg string, fields ...Field) {
l.mu.RLock()
level := l.level
l.mu.RUnlock()
if level <= DEBUG {
l.log(DEBUG, msg, fields...)
}
}
// Info 记录信息日志
func (l *Logger) Info(msg string, fields ...Field) {
l.mu.RLock()
level := l.level
l.mu.RUnlock()
if level <= INFO {
l.log(INFO, msg, fields...)
}
}
// Warn 记录警告日志
func (l *Logger) Warn(msg string, fields ...Field) {
l.mu.RLock()
level := l.level
l.mu.RUnlock()
if level <= WARN {
l.log(WARN, msg, fields...)
}
}
// Error 记录错误日志
func (l *Logger) Error(msg string, fields ...Field) {
l.mu.RLock()
level := l.level
l.mu.RUnlock()
if level <= ERROR {
l.log(ERROR, msg, fields...)
}
}
// log 内部日志记录方法
func (l *Logger) log(level Level, msg string, fields ...Field) {
// 创建日志条目
entry := NewLogEntry(level, l.component, msg)
// 添加字段
if len(fields) > 0 {
fieldMap := make(map[string]interface{}, len(fields))
for _, field := range fields {
fieldMap[field.Key] = field.Value
}
entry.WithFields(fieldMap)
}
// 写入所有写入器
l.writeEntry(entry)
}
// writeEntry 写入日志条目到所有写入器
func (l *Logger) writeEntry(entry *LogEntry) {
l.mu.RLock()
writers := l.writers
fileWriter := l.fileWriter
consoleWriter := l.consoleWriter
fileWriteFailed := l.fileWriteFailed
l.mu.RUnlock()
// 如果文件写入已失败,只写入控制台
if fileWriteFailed {
if consoleWriter != nil {
_ = consoleWriter.Write(entry)
}
return
}
// 写入所有写入器
for _, writer := range writers {
if err := writer.Write(entry); err != nil {
// 如果是文件写入器失败,标记并回退到控制台
if writer == fileWriter {
l.handleFileWriteError(entry, err)
}
}
}
}
// handleFileWriteError 处理文件写入错误
func (l *Logger) handleFileWriteError(entry *LogEntry, err error) {
l.mu.Lock()
if !l.fileWriteFailed {
l.fileWriteFailed = true
// 记录错误到控制台
fmt.Printf("[ERROR] File write failed: %v, falling back to console only\n", err)
}
l.mu.Unlock()
}
// LogEntry 直接写入日志条目(用于拦截器等高级用法)
func (l *Logger) LogEntry(entry *LogEntry) {
l.mu.RLock()
level := l.level
l.mu.RUnlock()
// 检查日志级别
if entry.Level < level {
return
}
l.writeEntry(entry)
}
// WithComponent 创建带有组件名的新日志记录器
func (l *Logger) WithComponent(component string) *Logger {
l.mu.RLock()
defer l.mu.RUnlock()
return &Logger{
level: l.level,
component: component,
ctx: l.ctx,
writers: l.writers,
consoleWriter: l.consoleWriter,
fileWriter: l.fileWriter,
rotationManager: l.rotationManager,
fileWriteFailed: l.fileWriteFailed,
}
}
// Flush 刷新所有写入器的缓冲区
func (l *Logger) Flush() error {
l.mu.RLock()
fileWriter := l.fileWriter
l.mu.RUnlock()
if fileWriter != nil {
return fileWriter.Flush()
}
return nil
}
// GetRotationManager 获取分片管理器
func (l *Logger) GetRotationManager() *RotationManager {
l.mu.RLock()
defer l.mu.RUnlock()
return l.rotationManager
}
// F 创建字段的便捷函数
func F(key string, value interface{}) Field {
return Field{Key: key, Value: value}
}
// Fs 创建多个字段的便捷函数
func Fs(keyValues ...interface{}) []Field {
fields := make([]Field, 0, len(keyValues)/2)
for i := 0; i < len(keyValues)-1; i += 2 {
if key, ok := keyValues[i].(string); ok {
fields = append(fields, Field{Key: key, Value: keyValues[i+1]})
}
}
return fields
}
// IsFileEnabled 检查文件日志是否启用
func (l *Logger) IsFileEnabled() bool {
l.mu.RLock()
defer l.mu.RUnlock()
return l.fileWriter != nil && !l.fileWriteFailed
}
// GetWriters 获取所有写入器(用于测试)
func (l *Logger) GetWriters() []Writer {
l.mu.RLock()
defer l.mu.RUnlock()
return l.writers
}
// ShouldLog 检查指定级别是否应该被记录
func (l *Logger) ShouldLog(level Level) bool {
l.mu.RLock()
defer l.mu.RUnlock()
return level >= l.level
}