4.6.2 日志系统设计

4.6.2 日志系统设计 #

日志系统是应用程序的重要组成部分,它不仅用于记录程序运行状态,还是问题诊断、性能分析和安全审计的重要工具。本节将深入探讨如何设计和实现一个高性能、可扩展的日志系统。

日志系统架构 #

日志系统组件 #

一个完整的日志系统通常包含以下核心组件:

  • 日志生产者(Producer):应用程序中产生日志的组件
  • 日志格式化器(Formatter):负责格式化日志消息
  • 日志处理器(Handler):处理日志输出的目标和方式
  • 日志过滤器(Filter):根据条件过滤日志消息
  • 日志轮转器(Rotator):管理日志文件的轮转和清理
  • 日志聚合器(Aggregator):收集和聚合分布式日志

日志级别设计 #

package logging

import (
    "fmt"
    "strings"
)

// LogLevel 日志级别
type LogLevel int

const (
    TRACE LogLevel = iota
    DEBUG
    INFO
    WARN
    ERROR
    FATAL
)

// String 返回日志级别的字符串表示
func (l LogLevel) String() string {
    switch l {
    case TRACE:
        return "TRACE"
    case DEBUG:
        return "DEBUG"
    case INFO:
        return "INFO"
    case WARN:
        return "WARN"
    case ERROR:
        return "ERROR"
    case FATAL:
        return "FATAL"
    default:
        return "UNKNOWN"
    }
}

// ParseLogLevel 解析日志级别字符串
func ParseLogLevel(level string) (LogLevel, error) {
    switch strings.ToUpper(level) {
    case "TRACE":
        return TRACE, nil
    case "DEBUG":
        return DEBUG, nil
    case "INFO":
        return INFO, nil
    case "WARN", "WARNING":
        return WARN, nil
    case "ERROR":
        return ERROR, nil
    case "FATAL":
        return FATAL, nil
    default:
        return INFO, fmt.Errorf("unknown log level: %s", level)
    }
}

// IsEnabled 检查指定级别是否启用
func (l LogLevel) IsEnabled(level LogLevel) bool {
    return level >= l
}

日志记录结构 #

日志记录定义 #

import (
    "runtime"
    "time"
)

// LogRecord 日志记录结构
type LogRecord struct {
    Time       time.Time              `json:"time"`
    Level      LogLevel               `json:"level"`
    Message    string                 `json:"message"`
    Logger     string                 `json:"logger"`
    Thread     string                 `json:"thread"`
    File       string                 `json:"file"`
    Line       int                    `json:"line"`
    Function   string                 `json:"function"`
    Fields     map[string]interface{} `json:"fields"`
    TraceID    string                 `json:"trace_id,omitempty"`
    SpanID     string                 `json:"span_id,omitempty"`
    RequestID  string                 `json:"request_id,omitempty"`
}

// NewLogRecord 创建新的日志记录
func NewLogRecord(level LogLevel, message string, fields map[string]interface{}) *LogRecord {
    record := &LogRecord{
        Time:    time.Now(),
        Level:   level,
        Message: message,
        Fields:  fields,
    }

    // 获取调用者信息
    if pc, file, line, ok := runtime.Caller(2); ok {
        record.File = file
        record.Line = line
        if fn := runtime.FuncForPC(pc); fn != nil {
            record.Function = fn.Name()
        }
    }

    return record
}

// WithField 添加字段
func (r *LogRecord) WithField(key string, value interface{}) *LogRecord {
    if r.Fields == nil {
        r.Fields = make(map[string]interface{})
    }
    r.Fields[key] = value
    return r
}

// WithFields 添加多个字段
func (r *LogRecord) WithFields(fields map[string]interface{}) *LogRecord {
    if r.Fields == nil {
        r.Fields = make(map[string]interface{})
    }
    for k, v := range fields {
        r.Fields[k] = v
    }
    return r
}

日志格式化器 #

文本格式化器 #

import (
    "bytes"
    "fmt"
    "path/filepath"
    "sort"
    "strings"
)

// Formatter 日志格式化器接口
type Formatter interface {
    Format(record *LogRecord) ([]byte, error)
}

// TextFormatter 文本格式化器
type TextFormatter struct {
    TimestampFormat string
    DisableColors   bool
    FullTimestamp   bool
    DisableSorting  bool
    QuoteEmptyFields bool
    FieldMap        map[string]string
}

// NewTextFormatter 创建文本格式化器
func NewTextFormatter() *TextFormatter {
    return &TextFormatter{
        TimestampFormat: "2006-01-02 15:04:05.000",
        FullTimestamp:   true,
    }
}

// Format 格式化日志记录
func (f *TextFormatter) Format(record *LogRecord) ([]byte, error) {
    var buf bytes.Buffer

    // 时间戳
    if f.FullTimestamp {
        buf.WriteString(record.Time.Format(f.TimestampFormat))
        buf.WriteByte(' ')
    }

    // 日志级别
    levelText := record.Level.String()
    if !f.DisableColors {
        levelText = f.colorize(levelText, record.Level)
    }
    buf.WriteString(fmt.Sprintf("[%s]", levelText))
    buf.WriteByte(' ')

    // 调用者信息
    if record.File != "" {
        buf.WriteString(fmt.Sprintf("%s:%d", filepath.Base(record.File), record.Line))
        buf.WriteByte(' ')
    }

    // 日志消息
    buf.WriteString(record.Message)

    // 字段信息
    if len(record.Fields) > 0 {
        buf.WriteByte(' ')
        f.appendFields(&buf, record.Fields)
    }

    buf.WriteByte('\n')
    return buf.Bytes(), nil
}

// colorize 为日志级别添加颜色
func (f *TextFormatter) colorize(text string, level LogLevel) string {
    if f.DisableColors {
        return text
    }

    var color string
    switch level {
    case TRACE:
        color = "\033[37m" // 白色
    case DEBUG:
        color = "\033[36m" // 青色
    case INFO:
        color = "\033[32m" // 绿色
    case WARN:
        color = "\033[33m" // 黄色
    case ERROR:
        color = "\033[31m" // 红色
    case FATAL:
        color = "\033[35m" // 紫色
    default:
        return text
    }

    return color + text + "\033[0m"
}

// appendFields 添加字段到缓冲区
func (f *TextFormatter) appendFields(buf *bytes.Buffer, fields map[string]interface{}) {
    keys := make([]string, 0, len(fields))
    for k := range fields {
        keys = append(keys, k)
    }

    if !f.DisableSorting {
        sort.Strings(keys)
    }

    for i, key := range keys {
        if i > 0 {
            buf.WriteByte(' ')
        }
        f.appendKeyValue(buf, key, fields[key])
    }
}

// appendKeyValue 添加键值对
func (f *TextFormatter) appendKeyValue(buf *bytes.Buffer, key string, value interface{}) {
    buf.WriteString(key)
    buf.WriteByte('=')

    stringVal := fmt.Sprintf("%v", value)
    if f.needsQuoting(stringVal) {
        buf.WriteByte('"')
        buf.WriteString(strings.Replace(stringVal, "\"", "\\\"", -1))
        buf.WriteByte('"')
    } else {
        buf.WriteString(stringVal)
    }
}

// needsQuoting 检查是否需要引号
func (f *TextFormatter) needsQuoting(text string) bool {
    if f.QuoteEmptyFields && len(text) == 0 {
        return true
    }
    for _, ch := range text {
        if !((ch >= 'a' && ch <= 'z') ||
            (ch >= 'A' && ch <= 'Z') ||
            (ch >= '0' && ch <= '9') ||
            ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') {
            return true
        }
    }
    return false
}

JSON 格式化器 #

import (
    "encoding/json"
    "path/filepath"
)

// JSONFormatter JSON 格式化器
type JSONFormatter struct {
    TimestampFormat   string
    DisableTimestamp  bool
    DisableHTMLEscape bool
    DataKey          string
    FieldMap         map[string]string
    PrettyPrint      bool
}

// NewJSONFormatter 创建 JSON 格式化器
func NewJSONFormatter() *JSONFormatter {
    return &JSONFormatter{
        TimestampFormat: "2006-01-02T15:04:05.000Z07:00",
        DataKey:        "",
    }
}

// Format 格式化日志记录
func (f *JSONFormatter) Format(record *LogRecord) ([]byte, error) {
    data := make(map[string]interface{})

    // 基本字段
    if !f.DisableTimestamp {
        data["time"] = record.Time.Format(f.TimestampFormat)
    }
    data["level"] = record.Level.String()
    data["msg"] = record.Message

    // 调用者信息
    if record.File != "" {
        data["file"] = filepath.Base(record.File)
        data["line"] = record.Line
    }
    if record.Function != "" {
        data["func"] = record.Function
    }

    // 追踪信息
    if record.TraceID != "" {
        data["trace_id"] = record.TraceID
    }
    if record.SpanID != "" {
        data["span_id"] = record.SpanID
    }
    if record.RequestID != "" {
        data["request_id"] = record.RequestID
    }

    // 自定义字段
    for k, v := range record.Fields {
        key := k
        if f.FieldMap != nil {
            if mappedKey, ok := f.FieldMap[k]; ok {
                key = mappedKey
            }
        }
        data[key] = v
    }

    var jsonData []byte
    var err error

    if f.PrettyPrint {
        jsonData, err = json.MarshalIndent(data, "", "  ")
    } else {
        jsonData, err = json.Marshal(data)
    }

    if err != nil {
        return nil, err
    }

    // 添加换行符
    jsonData = append(jsonData, '\n')
    return jsonData, nil
}

日志处理器 #

处理器接口 #

import (
    "io"
    "sync"
)

// Handler 日志处理器接口
type Handler interface {
    Handle(record *LogRecord) error
    SetLevel(level LogLevel)
    SetFormatter(formatter Formatter)
    Close() error
}

// BaseHandler 基础处理器
type BaseHandler struct {
    level     LogLevel
    formatter Formatter
    mutex     sync.RWMutex
}

// NewBaseHandler 创建基础处理器
func NewBaseHandler() *BaseHandler {
    return &BaseHandler{
        level:     INFO,
        formatter: NewTextFormatter(),
    }
}

// SetLevel 设置日志级别
func (h *BaseHandler) SetLevel(level LogLevel) {
    h.mutex.Lock()
    defer h.mutex.Unlock()
    h.level = level
}

// SetFormatter 设置格式化器
func (h *BaseHandler) SetFormatter(formatter Formatter) {
    h.mutex.Lock()
    defer h.mutex.Unlock()
    h.formatter = formatter
}

// ShouldHandle 检查是否应该处理该日志记录
func (h *BaseHandler) ShouldHandle(record *LogRecord) bool {
    h.mutex.RLock()
    defer h.mutex.RUnlock()
    return record.Level >= h.level
}

// Format 格式化日志记录
func (h *BaseHandler) Format(record *LogRecord) ([]byte, error) {
    h.mutex.RLock()
    defer h.mutex.RUnlock()
    return h.formatter.Format(record)
}

控制台处理器 #

import (
    "os"
)

// ConsoleHandler 控制台处理器
type ConsoleHandler struct {
    *BaseHandler
    writer io.Writer
}

// NewConsoleHandler 创建控制台处理器
func NewConsoleHandler() *ConsoleHandler {
    return &ConsoleHandler{
        BaseHandler: NewBaseHandler(),
        writer:      os.Stdout,
    }
}

// NewConsoleHandlerWithWriter 使用指定 writer 创建控制台处理器
func NewConsoleHandlerWithWriter(writer io.Writer) *ConsoleHandler {
    return &ConsoleHandler{
        BaseHandler: NewBaseHandler(),
        writer:      writer,
    }
}

// Handle 处理日志记录
func (h *ConsoleHandler) Handle(record *LogRecord) error {
    if !h.ShouldHandle(record) {
        return nil
    }

    data, err := h.Format(record)
    if err != nil {
        return err
    }

    _, err = h.writer.Write(data)
    return err
}

// Close 关闭处理器
func (h *ConsoleHandler) Close() error {
    return nil
}

文件处理器 #

import (
    "os"
    "path/filepath"
    "sync"
)

// FileHandler 文件处理器
type FileHandler struct {
    *BaseHandler
    filename string
    file     *os.File
    mutex    sync.Mutex
}

// NewFileHandler 创建文件处理器
func NewFileHandler(filename string) (*FileHandler, error) {
    // 确保目录存在
    dir := filepath.Dir(filename)
    if err := os.MkdirAll(dir, 0755); err != nil {
        return nil, err
    }

    file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
    if err != nil {
        return nil, err
    }

    return &FileHandler{
        BaseHandler: NewBaseHandler(),
        filename:    filename,
        file:        file,
    }, nil
}

// Handle 处理日志记录
func (h *FileHandler) Handle(record *LogRecord) error {
    if !h.ShouldHandle(record) {
        return nil
    }

    data, err := h.Format(record)
    if err != nil {
        return err
    }

    h.mutex.Lock()
    defer h.mutex.Unlock()

    _, err = h.file.Write(data)
    if err != nil {
        return err
    }

    return h.file.Sync()
}

// Close 关闭处理器
func (h *FileHandler) Close() error {
    h.mutex.Lock()
    defer h.mutex.Unlock()

    if h.file != nil {
        return h.file.Close()
    }
    return nil
}

轮转文件处理器 #

import (
    "fmt"
    "os"
    "path/filepath"
    "sort"
    "strings"
    "time"
)

// RotatingFileHandler 轮转文件处理器
type RotatingFileHandler struct {
    *BaseHandler
    filename    string
    maxSize     int64
    maxFiles    int
    currentSize int64
    file        *os.File
    mutex       sync.Mutex
}

// NewRotatingFileHandler 创建轮转文件处理器
func NewRotatingFileHandler(filename string, maxSize int64, maxFiles int) (*RotatingFileHandler, error) {
    dir := filepath.Dir(filename)
    if err := os.MkdirAll(dir, 0755); err != nil {
        return nil, err
    }

    handler := &RotatingFileHandler{
        BaseHandler: NewBaseHandler(),
        filename:    filename,
        maxSize:     maxSize,
        maxFiles:    maxFiles,
    }

    if err := handler.openFile(); err != nil {
        return nil, err
    }

    return handler, nil
}

// openFile 打开日志文件
func (h *RotatingFileHandler) openFile() error {
    file, err := os.OpenFile(h.filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
    if err != nil {
        return err
    }

    // 获取当前文件大小
    if stat, err := file.Stat(); err == nil {
        h.currentSize = stat.Size()
    }

    h.file = file
    return nil
}

// Handle 处理日志记录
func (h *RotatingFileHandler) Handle(record *LogRecord) error {
    if !h.ShouldHandle(record) {
        return nil
    }

    data, err := h.Format(record)
    if err != nil {
        return err
    }

    h.mutex.Lock()
    defer h.mutex.Unlock()

    // 检查是否需要轮转
    if h.currentSize+int64(len(data)) > h.maxSize {
        if err := h.rotate(); err != nil {
            return err
        }
    }

    n, err := h.file.Write(data)
    if err != nil {
        return err
    }

    h.currentSize += int64(n)
    return h.file.Sync()
}

// rotate 执行日志轮转
func (h *RotatingFileHandler) rotate() error {
    // 关闭当前文件
    if h.file != nil {
        h.file.Close()
    }

    // 轮转文件
    for i := h.maxFiles - 1; i > 0; i-- {
        oldName := fmt.Sprintf("%s.%d", h.filename, i)
        newName := fmt.Sprintf("%s.%d", h.filename, i+1)

        if _, err := os.Stat(oldName); err == nil {
            os.Rename(oldName, newName)
        }
    }

    // 将当前文件重命名为 .1
    if _, err := os.Stat(h.filename); err == nil {
        os.Rename(h.filename, h.filename+".1")
    }

    // 清理超出数量的文件
    h.cleanup()

    // 重新打开文件
    h.currentSize = 0
    return h.openFile()
}

// cleanup 清理旧的日志文件
func (h *RotatingFileHandler) cleanup() {
    dir := filepath.Dir(h.filename)
    base := filepath.Base(h.filename)

    files, err := filepath.Glob(filepath.Join(dir, base+".*"))
    if err != nil {
        return
    }

    // 按文件名排序
    sort.Strings(files)

    // 删除超出数量的文件
    if len(files) > h.maxFiles {
        for _, file := range files[h.maxFiles:] {
            os.Remove(file)
        }
    }
}

// Close 关闭处理器
func (h *RotatingFileHandler) Close() error {
    h.mutex.Lock()
    defer h.mutex.Unlock()

    if h.file != nil {
        return h.file.Close()
    }
    return nil
}

日志器实现 #

核心日志器 #

import (
    "context"
    "sync"
)

// Logger 日志器接口
type Logger interface {
    Trace(msg string, fields ...map[string]interface{})
    Debug(msg string, fields ...map[string]interface{})
    Info(msg string, fields ...map[string]interface{})
    Warn(msg string, fields ...map[string]interface{})
    Error(msg string, fields ...map[string]interface{})
    Fatal(msg string, fields ...map[string]interface{})

    WithField(key string, value interface{}) Logger
    WithFields(fields map[string]interface{}) Logger
    WithContext(ctx context.Context) Logger

    SetLevel(level LogLevel)
    AddHandler(handler Handler)
    RemoveHandler(handler Handler)
}

// StandardLogger 标准日志器实现
type StandardLogger struct {
    name     string
    level    LogLevel
    handlers []Handler
    fields   map[string]interface{}
    context  context.Context
    mutex    sync.RWMutex
}

// NewLogger 创建新的日志器
func NewLogger(name string) *StandardLogger {
    return &StandardLogger{
        name:     name,
        level:    INFO,
        handlers: make([]Handler, 0),
        fields:   make(map[string]interface{}),
    }
}

// SetLevel 设置日志级别
func (l *StandardLogger) SetLevel(level LogLevel) {
    l.mutex.Lock()
    defer l.mutex.Unlock()
    l.level = level
}

// AddHandler 添加处理器
func (l *StandardLogger) AddHandler(handler Handler) {
    l.mutex.Lock()
    defer l.mutex.Unlock()
    l.handlers = append(l.handlers, handler)
}

// RemoveHandler 移除处理器
func (l *StandardLogger) RemoveHandler(handler Handler) {
    l.mutex.Lock()
    defer l.mutex.Unlock()

    for i, h := range l.handlers {
        if h == handler {
            l.handlers = append(l.handlers[:i], l.handlers[i+1:]...)
            break
        }
    }
}

// log 记录日志
func (l *StandardLogger) log(level LogLevel, msg string, fields ...map[string]interface{}) {
    l.mutex.RLock()
    if level < l.level {
        l.mutex.RUnlock()
        return
    }

    handlers := make([]Handler, len(l.handlers))
    copy(handlers, l.handlers)
    l.mutex.RUnlock()

    // 合并字段
    allFields := make(map[string]interface{})
    for k, v := range l.fields {
        allFields[k] = v
    }
    for _, fieldMap := range fields {
        for k, v := range fieldMap {
            allFields[k] = v
        }
    }

    // 创建日志记录
    record := NewLogRecord(level, msg, allFields)
    record.Logger = l.name

    // 从上下文中提取追踪信息
    if l.context != nil {
        if traceID := l.context.Value("trace_id"); traceID != nil {
            if id, ok := traceID.(string); ok {
                record.TraceID = id
            }
        }
        if spanID := l.context.Value("span_id"); spanID != nil {
            if id, ok := spanID.(string); ok {
                record.SpanID = id
            }
        }
        if requestID := l.context.Value("request_id"); requestID != nil {
            if id, ok := requestID.(string); ok {
                record.RequestID = id
            }
        }
    }

    // 发送到所有处理器
    for _, handler := range handlers {
        go func(h Handler) {
            if err := h.Handle(record); err != nil {
                // 处理错误,可以记录到错误日志或发送到监控系统
                fmt.Printf("Error handling log record: %v\n", err)
            }
        }(handler)
    }
}

// Trace 记录 TRACE 级别日志
func (l *StandardLogger) Trace(msg string, fields ...map[string]interface{}) {
    l.log(TRACE, msg, fields...)
}

// Debug 记录 DEBUG 级别日志
func (l *StandardLogger) Debug(msg string, fields ...map[string]interface{}) {
    l.log(DEBUG, msg, fields...)
}

// Info 记录 INFO 级别日志
func (l *StandardLogger) Info(msg string, fields ...map[string]interface{}) {
    l.log(INFO, msg, fields...)
}

// Warn 记录 WARN 级别日志
func (l *StandardLogger) Warn(msg string, fields ...map[string]interface{}) {
    l.log(WARN, msg, fields...)
}

// Error 记录 ERROR 级别日志
func (l *StandardLogger) Error(msg string, fields ...map[string]interface{}) {
    l.log(ERROR, msg, fields...)
}

// Fatal 记录 FATAL 级别日志
func (l *StandardLogger) Fatal(msg string, fields ...map[string]interface{}) {
    l.log(FATAL, msg, fields...)
    os.Exit(1)
}

// WithField 添加字段
func (l *StandardLogger) WithField(key string, value interface{}) Logger {
    newFields := make(map[string]interface{})
    for k, v := range l.fields {
        newFields[k] = v
    }
    newFields[key] = value

    return &StandardLogger{
        name:     l.name,
        level:    l.level,
        handlers: l.handlers,
        fields:   newFields,
        context:  l.context,
    }
}

// WithFields 添加多个字段
func (l *StandardLogger) WithFields(fields map[string]interface{}) Logger {
    newFields := make(map[string]interface{})
    for k, v := range l.fields {
        newFields[k] = v
    }
    for k, v := range fields {
        newFields[k] = v
    }

    return &StandardLogger{
        name:     l.name,
        level:    l.level,
        handlers: l.handlers,
        fields:   newFields,
        context:  l.context,
    }
}

// WithContext 添加上下文
func (l *StandardLogger) WithContext(ctx context.Context) Logger {
    return &StandardLogger{
        name:     l.name,
        level:    l.level,
        handlers: l.handlers,
        fields:   l.fields,
        context:  ctx,
    }
}

异步日志处理 #

异步处理器 #

import (
    "context"
    "sync"
    "time"
)

// AsyncHandler 异步处理器
type AsyncHandler struct {
    handler    Handler
    buffer     chan *LogRecord
    bufferSize int
    timeout    time.Duration
    wg         sync.WaitGroup
    ctx        context.Context
    cancel     context.CancelFunc
}

// NewAsyncHandler 创建异步处理器
func NewAsyncHandler(handler Handler, bufferSize int, timeout time.Duration) *AsyncHandler {
    ctx, cancel := context.WithCancel(context.Background())

    ah := &AsyncHandler{
        handler:    handler,
        buffer:     make(chan *LogRecord, bufferSize),
        bufferSize: bufferSize,
        timeout:    timeout,
        ctx:        ctx,
        cancel:     cancel,
    }

    ah.wg.Add(1)
    go ah.worker()

    return ah
}

// Handle 处理日志记录
func (ah *AsyncHandler) Handle(record *LogRecord) error {
    select {
    case ah.buffer <- record:
        return nil
    case <-time.After(ah.timeout):
        return fmt.Errorf("async handler buffer full, timeout after %v", ah.timeout)
    }
}

// worker 工作协程
func (ah *AsyncHandler) worker() {
    defer ah.wg.Done()

    ticker := time.NewTicker(100 * time.Millisecond)
    defer ticker.Stop()

    batch := make([]*LogRecord, 0, 100)

    for {
        select {
        case <-ah.ctx.Done():
            // 处理剩余的日志记录
            ah.flushBatch(batch)
            return

        case record := <-ah.buffer:
            batch = append(batch, record)
            if len(batch) >= 100 {
                ah.flushBatch(batch)
                batch = batch[:0]
            }

        case <-ticker.C:
            if len(batch) > 0 {
                ah.flushBatch(batch)
                batch = batch[:0]
            }
        }
    }
}

// flushBatch 批量处理日志记录
func (ah *AsyncHandler) flushBatch(batch []*LogRecord) {
    for _, record := range batch {
        if err := ah.handler.Handle(record); err != nil {
            // 处理错误
            fmt.Printf("Error in async handler: %v\n", err)
        }
    }
}

// SetLevel 设置日志级别
func (ah *AsyncHandler) SetLevel(level LogLevel) {
    ah.handler.SetLevel(level)
}

// SetFormatter 设置格式化器
func (ah *AsyncHandler) SetFormatter(formatter Formatter) {
    ah.handler.SetFormatter(formatter)
}

// Close 关闭处理器
func (ah *AsyncHandler) Close() error {
    ah.cancel()
    ah.wg.Wait()
    close(ah.buffer)
    return ah.handler.Close()
}

日志管理器 #

全局日志管理 #

import (
    "sync"
)

// LogManager 日志管理器
type LogManager struct {
    loggers map[string]*StandardLogger
    mutex   sync.RWMutex
}

var (
    defaultManager *LogManager
    once          sync.Once
)

// GetLogManager 获取默认日志管理器
func GetLogManager() *LogManager {
    once.Do(func() {
        defaultManager = &LogManager{
            loggers: make(map[string]*StandardLogger),
        }
    })
    return defaultManager
}

// GetLogger 获取指定名称的日志器
func (lm *LogManager) GetLogger(name string) *StandardLogger {
    lm.mutex.RLock()
    logger, exists := lm.loggers[name]
    lm.mutex.RUnlock()

    if exists {
        return logger
    }

    lm.mutex.Lock()
    defer lm.mutex.Unlock()

    // 双重检查
    if logger, exists := lm.loggers[name]; exists {
        return logger
    }

    logger = NewLogger(name)
    lm.loggers[name] = logger
    return logger
}

// SetGlobalLevel 设置全局日志级别
func (lm *LogManager) SetGlobalLevel(level LogLevel) {
    lm.mutex.RLock()
    defer lm.mutex.RUnlock()

    for _, logger := range lm.loggers {
        logger.SetLevel(level)
    }
}

// AddGlobalHandler 为所有日志器添加处理器
func (lm *LogManager) AddGlobalHandler(handler Handler) {
    lm.mutex.RLock()
    defer lm.mutex.RUnlock()

    for _, logger := range lm.loggers {
        logger.AddHandler(handler)
    }
}

// 便利函数
func GetLogger(name string) *StandardLogger {
    return GetLogManager().GetLogger(name)
}

func SetGlobalLevel(level LogLevel) {
    GetLogManager().SetGlobalLevel(level)
}

func AddGlobalHandler(handler Handler) {
    GetLogManager().AddGlobalHandler(handler)
}

使用示例 #

基本使用 #

package main

import (
    "context"
    "time"
)

func main() {
    // 创建日志器
    logger := GetLogger("main")

    // 添加控制台处理器
    consoleHandler := NewConsoleHandler()
    consoleHandler.SetFormatter(NewTextFormatter())
    logger.AddHandler(consoleHandler)

    // 添加文件处理器
    fileHandler, err := NewRotatingFileHandler("logs/app.log", 10*1024*1024, 5)
    if err != nil {
        panic(err)
    }
    fileHandler.SetFormatter(NewJSONFormatter())
    logger.AddHandler(fileHandler)

    // 设置日志级别
    logger.SetLevel(DEBUG)

    // 记录日志
    logger.Info("Application started")
    logger.Debug("Debug information", map[string]interface{}{
        "version": "1.0.0",
        "env":     "production",
    })

    // 使用字段链式调用
    logger.WithField("user_id", 12345).
        WithField("action", "login").
        Info("User logged in")

    // 使用上下文
    ctx := context.WithValue(context.Background(), "request_id", "req-123")
    logger.WithContext(ctx).Error("Database connection failed")

    // 清理资源
    fileHandler.Close()
}

高级配置 #

// 配置结构
type LogConfig struct {
    Level      string            `json:"level"`
    Handlers   []HandlerConfig   `json:"handlers"`
    Formatters map[string]interface{} `json:"formatters"`
}

type HandlerConfig struct {
    Type      string                 `json:"type"`
    Level     string                 `json:"level"`
    Formatter string                 `json:"formatter"`
    Options   map[string]interface{} `json:"options"`
}

// 从配置创建日志器
func NewLoggerFromConfig(name string, config *LogConfig) (*StandardLogger, error) {
    logger := NewLogger(name)

    // 设置级别
    if level, err := ParseLogLevel(config.Level); err == nil {
        logger.SetLevel(level)
    }

    // 创建处理器
    for _, handlerConfig := range config.Handlers {
        handler, err := createHandler(handlerConfig)
        if err != nil {
            return nil, err
        }
        logger.AddHandler(handler)
    }

    return logger, nil
}

func createHandler(config HandlerConfig) (Handler, error) {
    var handler Handler
    var err error

    switch config.Type {
    case "console":
        handler = NewConsoleHandler()
    case "file":
        filename := config.Options["filename"].(string)
        handler, err = NewFileHandler(filename)
    case "rotating_file":
        filename := config.Options["filename"].(string)
        maxSize := int64(config.Options["max_size"].(float64))
        maxFiles := int(config.Options["max_files"].(float64))
        handler, err = NewRotatingFileHandler(filename, maxSize, maxFiles)
    default:
        return nil, fmt.Errorf("unknown handler type: %s", config.Type)
    }

    if err != nil {
        return nil, err
    }

    // 设置级别
    if config.Level != "" {
        if level, err := ParseLogLevel(config.Level); err == nil {
            handler.SetLevel(level)
        }
    }

    // 设置格式化器
    switch config.Formatter {
    case "json":
        handler.SetFormatter(NewJSONFormatter())
    case "text":
        handler.SetFormatter(NewTextFormatter())
    }

    return handler, nil
}

性能优化 #

对象池优化 #

import (
    "sync"
)

var (
    recordPool = sync.Pool{
        New: func() interface{} {
            return &LogRecord{
                Fields: make(map[string]interface{}),
            }
        },
    }

    bufferPool = sync.Pool{
        New: func() interface{} {
            return make([]byte, 0, 1024)
        },
    }
)

// 优化的日志记录创建
func NewLogRecordOptimized(level LogLevel, message string, fields map[string]interface{}) *LogRecord {
    record := recordPool.Get().(*LogRecord)

    // 重置记录
    record.Time = time.Now()
    record.Level = level
    record.Message = message
    record.Logger = ""
    record.Thread = ""
    record.File = ""
    record.Line = 0
    record.Function = ""
    record.TraceID = ""
    record.SpanID = ""
    record.RequestID = ""

    // 清空字段映射
    for k := range record.Fields {
        delete(record.Fields, k)
    }

    // 复制新字段
    for k, v := range fields {
        record.Fields[k] = v
    }

    return record
}

// 释放日志记录
func ReleaseLogRecord(record *LogRecord) {
    recordPool.Put(record)
}

小结 #

本节详细介绍了日志系统的设计和实现,包括:

  1. 日志架构:完整的日志系统组件设计
  2. 日志级别:灵活的日志级别管理
  3. 格式化器:文本和 JSON 格式化器
  4. 处理器:控制台、文件和轮转文件处理器
  5. 异步处理:高性能的异步日志处理
  6. 日志管理:全局日志管理和配置

通过这个日志系统,我们可以实现高性能、可扩展的日志记录功能,为应用程序的监控和调试提供强有力的支持。