golang简单分级日志记录封装插件库log的使用

Golang 简单分级日志记录封装插件库 log 的使用

log 是一个基于标准 log 包的简单分级日志记录库。

特性

  • 😻 分级日志记录
  • 😚 简单的 API
  • 🤝 兼容 fmt
  • 👌 零依赖
  • 😮‍💨 没有全局日志记录器
  • 👏 没有复杂的结构化日志

安装

go get github.com/heartwilltell/log

分级日志

StdLog 实现了一个简单的接口:

// Logger 根据 fmt 包的标准格式说明符格式化消息,
// 并将消息写入由具体接口实现指定的写入器。
type Logger interface {
	// Error 格式化并写入错误级别消息。
	Error(format string, v ...any)
	// Warning 格式化并写入警告级别消息。
	Warning(format string, v ...any)
	// Info 格式化并写入信息级别消息。
	Info(format string, v ...any)
	// Debug 格式化并写入调试级别消息。
	Debug(format string, v ...any)
}

使用

👇 使用非常简单。只需创建一个日志记录器实例并调用任何分级方法。

logger := log.New()
logger.Info("Listen on port: %d", 8080)

设置日志级别为 debug

logger := log.New(log.WithLevel(log.DBG))

解析字符串为级别并创建 warning 级别的日志记录器

level, levelErr := log.ParseLevel("warning")
if levelErr != nil {
	// 处理错误
}

logger := log.New(log.WithLevel(level))

使用不同的 io.Writer 创建日志记录器

var w bytes.Buffer 

logger := log.New(log.WithWriter(w))

禁用彩色输出

logger := log.New(log.WithNoColor())

设置 UTC 时间格式

logger := log.New(log.WithUTC())

启用打印代码行号

// 短格式:
// INF: 2022/07/08 11:22:30 server.go:111: message
logger := log.New(log.WithLineNum(log.ShortFmt))

// 长格式:
// INF: 2022/07/08 11:22:30 /Users/heartwilltell/Go/app/server.go:111: message
logger := log.New(log.WithLineNum(log.LongFmt))

将级别标记放在日志前缀的末尾

logger := log.New(log.WithLevelAtPrefixEnd())

将产生这样的输出 👇

// 2022/07/08 11:22:30 INF: message

而不是这样 👇

// INF: 2022/07/08 11:22:30: message

创建无操作日志记录器

logger := log.NewNopLog()

💡 适用于测试或默认情况下应禁用日志记录的地方

完整示例

package main

import (
	"bytes"
	"github.com/heartwilltell/log"
)

func main() {
	// 基本用法
	logger := log.New()
	logger.Info("Application started")
	logger.Warning("This is a warning message")
	logger.Error("Error occurred: %s", "file not found")
	
	// 设置调试级别
	debugLogger := log.New(log.WithLevel(log.DBG))
	debugLogger.Debug("Debug message will be shown")
	
	// 自定义写入器
	var buf bytes.Buffer
	customWriterLogger := log.New(log.WithWriter(&buf))
	customWriterLogger.Info("This goes to buffer")
	
	// 禁用颜色和UTC时间
	noColorLogger := log.New(log.WithNoColor(), log.WithUTC())
	noColorLogger.Info("No color and UTC time")
	
	// 带行号的日志
	lineNumLogger := log.New(log.WithLineNum(log.ShortFmt))
	lineNumLogger.Info("This message includes file and line number")
}

许可证

MIT License。


更多关于golang简单分级日志记录封装插件库log的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang简单分级日志记录封装插件库log的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang 分级日志记录封装库使用指南

在Go语言中实现分级日志记录可以帮助我们更好地管理和调试应用程序。下面我将介绍一个简单的分级日志记录封装库的实现和使用方法。

基础日志封装实现

首先,我们创建一个简单的日志封装库,支持不同级别的日志记录:

package log

import (
	"fmt"
	"io"
	"os"
	"sync"
	"time"
)

// 日志级别类型
type Level int

const (
	LevelDebug Level = iota
	LevelInfo
	LevelWarn
	LevelError
	LevelFatal
)

var levelNames = []string{
	"DEBUG",
	"INFO",
	"WARN",
	"ERROR",
	"FATAL",
}

// Logger 日志记录器
type Logger struct {
	mu     sync.Mutex
	output io.Writer
	level  Level
}

// NewLogger 创建新的日志记录器
func NewLogger(output io.Writer, level Level) *Logger {
	return &Logger{
		output: output,
		level:  level,
	}
}

// 默认日志记录器
var defaultLogger = NewLogger(os.Stderr, LevelInfo)

// SetOutput 设置日志输出
func SetOutput(w io.Writer) {
	defaultLogger.mu.Lock()
	defer defaultLogger.mu.Unlock()
	defaultLogger.output = w
}

// SetLevel 设置日志级别
func SetLevel(level Level) {
	defaultLogger.mu.Lock()
	defer defaultLogger.mu.Unlock()
	defaultLogger.level = level
}

// log 内部日志记录方法
func (l *Logger) log(level Level, format string, args ...interface{}) {
	if level < l.level {
		return
	}

	now := time.Now().Format("2006-01-02 15:04:05")
	msg := fmt.Sprintf(format, args...)
	logEntry := fmt.Sprintf("[%s] %s %s\n", now, levelNames[level], msg)

	l.mu.Lock()
	defer l.mu.Unlock()
	_, _ = fmt.Fprint(l.output, logEntry)
}

// 导出各级别日志方法
func Debug(format string, args ...interface{}) {
	defaultLogger.log(LevelDebug, format, args...)
}

func Info(format string, args ...interface{}) {
	defaultLogger.log(LevelInfo, format, args...)
}

func Warn(format string, args ...interface{}) {
	defaultLogger.log(LevelWarn, format, args...)
}

func Error(format string, args ...interface{}) {
	defaultLogger.log(LevelError, format, args...)
}

func Fatal(format string, args ...interface{}) {
	defaultLogger.log(LevelFatal, format, args...)
	os.Exit(1)
}

使用示例

下面是如何使用这个日志库的示例:

package main

import (
	"os"
	
	"./log" // 替换为你的实际包路径
)

func main() {
	// 设置日志级别为Debug
	log.SetLevel(log.LevelDebug)
	
	// 设置日志输出到文件
	file, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		log.Fatal("无法打开日志文件: %v", err)
	}
	defer file.Close()
	log.SetOutput(file)
	
	// 记录不同级别的日志
	log.Debug("这是一条调试信息")
	log.Info("应用程序启动")
	log.Warn("警告: 配置项缺失, 使用默认值")
	log.Error("处理请求时出错: %v", "连接超时")
	
	// 业务逻辑
	processData()
}

func processData() {
	log.Debug("开始处理数据")
	// 模拟处理过程
	log.Info("数据处理完成")
}

高级功能扩展

如果需要更高级的功能,可以扩展上述基础实现:

  1. JSON格式日志
func (l *Logger) jsonLog(level Level, format string, args ...interface{}) {
	if level < l.level {
		return
	}

	entry := map[string]interface{}{
		"timestamp": time.Now().Format(time.RFC3339),
		"level":     levelNames[level],
		"message":   fmt.Sprintf(format, args...),
	}

	jsonData, _ := json.Marshal(entry)
	
	l.mu.Lock()
	defer l.mu.Unlock()
	_, _ = fmt.Fprintln(l.output, string(jsonData))
}
  1. 日志轮转: 可以使用第三方库如lumberjack实现日志文件轮转:
import "gopkg.in/natefinch/lumberjack.v2"

func setupLogRotation() {
	log.SetOutput(&lumberjack.Logger{
		Filename:   "app.log",
		MaxSize:    100, // MB
		MaxBackups: 3,
		MaxAge:     28, // days
		Compress:   true,
	})
}
  1. 上下文日志
func WithFields(fields map[string]interface{}) *Entry {
	return &Entry{
		logger: defaultLogger,
		fields: fields,
	}
}

type Entry struct {
	logger *Logger
	fields map[string]interface{}
}

func (e *Entry) Info(format string, args ...interface{}) {
	// 将fields和消息一起记录
}

最佳实践

  1. 在应用程序启动时配置日志级别和输出
  2. 生产环境使用LevelInfo或更高级别
  3. 开发环境可以使用LevelDebug以便调试
  4. 错误日志应该包含足够的上下文信息
  5. 避免在热路径上记录过多调试日志

这个简单的日志库已经能满足大多数基本需求,如果需要更复杂的功能,可以考虑使用成熟的日志库如zaplogruszerolog

回到顶部