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)
}
小结 #
本节详细介绍了日志系统的设计和实现,包括:
- 日志架构:完整的日志系统组件设计
- 日志级别:灵活的日志级别管理
- 格式化器:文本和 JSON 格式化器
- 处理器:控制台、文件和轮转文件处理器
- 异步处理:高性能的异步日志处理
- 日志管理:全局日志管理和配置
通过这个日志系统,我们可以实现高性能、可扩展的日志记录功能,为应用程序的监控和调试提供强有力的支持。