go的log 包:日志输出与配置

一、log包基础:默认日志器

Go 标准库 log 提供了简单的日志功能,默认日志器(std)可直接使用,无需额外配置。

1. 核心函数

函数

功能

输出示例

log.Print(v…)

输出日志(无换行符自动添加)

2024/11/18 15:00:00 这是一条日志

log.Println(v…)

输出日志并换行

2024/11/18 15:00:00 这是一条日志

log.Printf(format, v…)

格式化输出日志

2024/11/18 15:00:00 数值:100

log.Fatal(v…)

输出日志后调用 os.Exit(1)(终止程序)

2024/11/18 15:00:00 致命错误

log.Panic(v…)

输出日志后触发 panic(可被 recover 捕获)

2024/11/18 15:00:00 恐慌错误

2. 基础用法示例

package main

import "log"

func main() {
	// 基本日志输出
	log.Print("这是一条普通日志")
	log.Println("这是一条带换行的日志")
	log.Printf("这是一条格式化日志,数值:%d", 123)

	// 致命错误(程序终止)
	// log.Fatal("发生致命错误,程序退出")

	// 恐慌错误(触发panic)
	// log.Panic("发生恐慌错误")
}

3. 默认日志特性

  • 输出格式:日期 时间 日志内容(如 2024/11/18 15:00:00 日志内容);
  • 输出目标:默认输出到标准错误流(os.Stderr);
  • 线程安全:支持多 goroutine 并发写入,内部有锁保护。

二、日志配置:自定义输出格式与目标

通过 log 包的配置函数,可自定义日志的前缀、输出目标、时间格式等。

1. 核心配置函数

函数

功能

log.SetPrefix(prefix string)

设置日志前缀(会添加到每条日志前)

log.SetFlags(flags int)

设置日志标志(控制输出内容,如是否显示时间、文件名等)

log.SetOutput(w io.Writer)

设置日志输出目标(默认是 os.Stderr)

2. 常用日志标志(flags参数)

标志常量

含义

log.Ldate

显示日期(如 2024/11/18)

log.Ltime

显示时间(如 15:00:00)

log.Lmicroseconds

显示微秒级时间(如 15:00:00.123456)

log.Llongfile

显示完整文件名和行号(如 /a/b/c.go:23)

log.Lshortfile

显示短文件名和行号(如 c.go:23)

log.LstdFlags

默认标志(Ldate,Ltime)

3. 自定义配置示例

package main

import (
	"io"
	"log"
	"os"
)

func main() {
	// 1. 设置日志前缀
	log.SetPrefix("[INFO] ")

	// 2. 设置日志标志(显示日期、时间、微秒、短文件名)
	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Lshortfile)

	// 3. 设置日志输出到文件(同时输出到控制台)
	logFile, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		log.Fatal("创建日志文件失败:", err)
	}
	defer logFile.Close() // 确保程序结束时关闭文件
	// log.SetOutput(logFile) // 仅输出到文件
	// 同时输出到文件和标准输出(io.MultiWriter 合并多个输出目标)
	log.SetOutput(io.MultiWriter(logFile, os.Stdout)) // 同时输出到文件和控制台

	// 测试日志
	log.Println("程序启动")
	log.Printf("用户%s登录成功", "admin")
	log.Println("日志系统初始化完成")
}

三、创建自定义日志器(log.New)

除了默认日志器,还可通过 log.New 创建多个独立配置的日志器(如区分错误日志、访问日志)。

1.log.New函数定义

func New(out io.Writer, prefix string, flag int) *log.Logger
  • 参数:out:日志输出目标(io.Writer 接口,如文件、网络连接);prefix:日志前缀;flag:日志标志(同 SetFlags 参数);
  • 返回:自定义日志器指针(*log.Logger),可调用 Print/Println 等方法。

2. 多日志器示例(区分 info 和 error 日志)

四、日志轮转与进阶(标准库局限与扩展)

1. 标准库log的局限

  • 不支持日志级别(如 DEBUG/INFO/WARN/ERROR);
  • 不支持日志轮转(按大小 / 时间分割日志文件);
  • 不支持结构化日志(如 JSON 格式)。

2. 日志轮转简易实现(按文件大小)

package main

import (
	"log"
	"os"
	"time"
)

// rotateLog 检查日志文件大小,超过阈值则轮转
func rotateLog(filePath string, maxSize int64) (*os.File, error) {
	// 检查文件是否存在
	fileInfo, err := os.Stat(filePath)
	if err != nil {
		// 如果文件不存在,直接创建新文件
		if os.IsNotExist(err) {
			return os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
		}
		// 其他错误返回
		return nil, err
	}
	
	// 若文件存在且超过最大大小,重命名为备份文件
	if fileInfo.Size() >= maxSize {
		backupPath := filePath + "." + time.Now().Format("20060102150405")
		if err := os.Rename(filePath, backupPath); err != nil {
			return nil, err
		}
	}
	
	// 创建新日志文件
	return os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
}

func main() {
	logPath := "app.log"
	maxSize := int64(1024 * 20) // 最大20kb

	logFile, err := rotateLog(logPath, maxSize)
	if err != nil {
		log.Fatal("日志轮转失败:", err)
	}
	defer logFile.Close() // 确保程序结束时关闭文件
	
	// 设置日志输出目标
	log.SetOutput(logFile)
	
	// 设置日志格式
	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Lshortfile)
	log.SetPrefix("[INFO] ")
	
	log.Println("带轮转功能的日志系统已启动")
	log.Printf("日志文件路径:%s,最大大小:%d bytes", logPath, maxSize)
	// 获取当前日志文件大小
	for i:=100; i>=0; i-- {
	fileInfo, err := os.Stat(logPath)
		log.Println(i)
		if err != nil {
			log.Printf("获取文件信息失败:%v", err)
			} else {
				log.Printf("日志文件路径:%s,当前文件大小:%d bytes", logPath, fileInfo.Size())
			}
		}
}

3. 推荐第三方日志库(解决标准库局限)

  • zap:Uber 开源,高性能、结构化日志,支持级别和轮转;
  • logrus:类 log4j 风格,支持插件和钩子,易用性好;
  • zerolog:极致性能,专注结构化日志,API 简洁。

五、最佳实践

  1. 生产环境日志输出到文件:避免仅依赖控制台输出,确保日志可持久化;
  2. 添加必要上下文:日志中包含时间、文件名、行号、模块名等,便于问题定位;
  3. 区分日志级别:通过第三方库实现 DEBUG/INFO/ERROR 等级别,便于筛选;
  4. 日志轮转:防止单一日志文件过大(如超过 100MB 轮转),并定期清理旧日志;
  5. 敏感信息脱敏:日志中避免明文输出密码、Token 等敏感数据;
  6. 并发安全:多 goroutine 写日志时,确保日志器线程安全(标准库 log 已支持)。

通过 log 包的基础功能和自定义配置,可满足简单日志需求;复杂场景(如级别、轮转)则提议使用第三方库。

© 版权声明

相关文章

暂无评论

none
暂无评论...