Go 基础语法 - 从零实现 Mini 日志库
2025/5/22大约 4 分钟
当然可以!以下是专为你定制的实战项目,完全基于你的开发环境:
- 操作系统:Linux Mint XFCE
- Go 版本:go1.22.2 linux/amd64
- 项目目录:
/home/liumangmang/GolandProjects
📌 标题:
从零实现 Mini 日志库:Go 结构体、接口与 fmt 的完美结合
✅ 步骤 1:创建项目结构
打开终端,执行以下命令:
cd /home/liumangmang/GolandProjects
mkdir go-mini-logger && cd go-mini-logger
go mod init go-mini-logger我们将实现一个支持多级别(Info/Warn/Error)、可输出到控制台或文件、并可通过接口扩展的轻量日志库。
✅ 步骤 2:定义日志接口(logger.go)
创建 logger.go:
nano logger.go粘贴以下代码:
package main
import (
"fmt"
"io"
"os"
"time"
)
// LogLevel 日志级别
type LogLevel int
const (
LevelInfo LogLevel = iota
LevelWarn
LevelError
)
func (l LogLevel) String() string {
switch l {
case LevelInfo:
return "INFO"
case LevelWarn:
return "WARN"
case LevelError:
return "ERROR"
default:
return "UNKNOWN"
}
}
// Logger 接口:定义日志行为
type Logger interface {
Log(level LogLevel, format string, args ...any)
Info(format string, args ...any)
Warn(format string, args ...any)
Error(format string, args ...any)
SetMinLevel(level LogLevel)
}
// defaultLogger 结构体:默认实现
type defaultLogger struct {
minLevel LogLevel
writer io.Writer
}
// NewLogger 创建新日志实例,默认输出到 os.Stdout
func NewLogger() Logger {
return &defaultLogger{
minLevel: LevelInfo,
writer: os.Stdout,
}
}
// NewFileLogger 创建写入文件的日志实例
func NewFileLogger(filename string) (Logger, error) {
file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return nil, fmt.Errorf("无法创建日志文件 %s: %w", filename, err)
}
return &defaultLogger{
minLevel: LevelInfo,
writer: file,
}, nil
}
// SetMinLevel 设置最低日志级别
func (l *defaultLogger) SetMinLevel(level LogLevel) {
l.minLevel = level
}
// Log 核心日志方法
func (l *defaultLogger) Log(level LogLevel, format string, args ...any) {
if level < l.minLevel {
return // 低于最小级别,丢弃
}
// 构建日志消息:[时间] [级别] 消息
timestamp := time.Now().Format("2006-01-02 15:04:05")
message := fmt.Sprintf(format, args...)
line := fmt.Sprintf("[%s] [%s] %s\n", timestamp, level.String(), message)
// 写入目标(控制台或文件)
fmt.Fprint(l.writer, line)
}
// 快捷方法
func (l *defaultLogger) Info(format string, args ...any) { l.Log(LevelInfo, format, args...) }
func (l *defaultLogger) Warn(format string, args ...any) { l.Log(LevelWarn, format, args...) }
func (l *defaultLogger) Error(format string, args ...any) { l.Log(LevelError, format, args...) }保存退出(Ctrl+O → Enter → Ctrl+X)。
✅ 步骤 3:编写使用示例(main.go)
创建 main.go:
nano main.go粘贴以下代码:
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("=== 1. 控制台日志 ===")
consoleLogger := NewLogger()
consoleLogger.Info("程序启动,PID: %d", os.Getpid())
consoleLogger.Warn("磁盘使用率超过 80%")
consoleLogger.Error("数据库连接失败: timeout")
fmt.Println("\n=== 2. 设置最低级别为 WARN ===")
consoleLogger.SetMinLevel(LevelWarn)
consoleLogger.Info("这条不会显示") // 被过滤
consoleLogger.Warn("这条会显示") // 显示
consoleLogger.Error("错误也会显示") // 显示
fmt.Println("\n=== 3. 文件日志(写入 app.log)===")
fileLogger, err := NewFileLogger("app.log")
if err != nil {
consoleLogger.Error("无法创建文件日志: %v", err)
return
}
fileLogger.Info("应用开始处理请求")
fileLogger.Warn("用户 %s 尝试越权操作", "liumangmang")
fileLogger.Error("写入数据库时发生唯一键冲突")
fmt.Println("日志已写入 app.log,请查看内容:")
os.ReadFile("app.log") // 不打印,仅确保写入
fmt.Println("✅ 查看 app.log 可验证文件日志内容")
}保存退出。
✅ 步骤 4:格式化并运行
go fmt
go run .预期终端输出:
=== 1. 控制台日志 ===
[2025-11-25 21:30:05] [INFO] 程序启动,PID: 12345
[2025-11-25 21:30:05] [WARN] 磁盘使用率超过 80%
[2025-11-25 21:30:05] [ERROR] 数据库连接失败: timeout
=== 2. 设置最低级别为 WARN ===
[2025-11-25 21:30:05] [WARN] 这条会显示
[2025-11-25 21:30:05] [ERROR] 错误也会显示
=== 3. 文件日志(写入 app.log)===
日志已写入 app.log,请查看内容:
✅ 查看 app.log 可验证文件日志内容同时,当前目录会生成 app.log 文件。你可以查看它:
cat app.log内容类似:
[2025-11-25 21:30:05] [INFO] 应用开始处理请求
[2025-11-25 21:30:05] [WARN] 用户 liumangmang 尝试越权操作
[2025-11-25 21:30:05] [ERROR] 写入数据库时发生唯一键冲突🔍 设计亮点解析
| Go 特性 | 在本项目中的体现 |
|---|---|
| 结构体 | defaultLogger 封装 writer 和 minLevel |
| 接口 | Logger 接口解耦调用方与实现,便于未来扩展(如网络日志、JSON 格式等) |
| fmt 包 | 使用 fmt.Sprintf 格式化消息,fmt.Fprint 写入任意 io.Writer |
| io.Writer | 支持无缝切换输出目标(控制台、文件、网络流) |
| 可扩展性 | 只需实现 Logger 接口,即可插入新的日志后端 |
💡 为什么用接口?
未来你可以轻松添加JSONLogger、SyslogLogger等,而无需修改业务代码——只需传入不同的Logger实现。
✅ 在 GoLand 中进一步探索
- 打开项目:
/home/liumangmang/GolandProjects/go-mini-logger - 右键点击
Logger接口 → Go to → Implementations,查看所有实现(目前只有defaultLogger) - 尝试新增一个
SilentLogger(不输出任何内容),验证接口的灵活性 - 在
main.go中将consoleLogger替换为fileLogger,观察行为变化
🧭 扩展建议(课后练习)
- 添加
WithField(key, value string)方法支持结构化日志 - 支持日志轮转(log rotation)
- 增加
Debug级别,并通过 build tag 控制是否编译
如果你希望我继续带你实现 带上下文(context)的日志、JSON 格式输出、或集成 zap/logrus 对比分析,欢迎随时告诉我!祝你编码愉快,日志清晰 🚀
