Go log模块的使用技巧
<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">Go log模块使用</a></li><ul class="second_class_ul"><li><a href="#_lab2_0_0">1.主要特性</a></li><li><a href="#_lab2_0_1">2. 基础日志输出</a></li><ul class="third_class_ul"><li><a href="#_label3_0_1_0">2.1 基本日志方法</a></li><li><a href="#_label3_0_1_1">2.2 错误处理日志</a></li></ul><li><a href="#_lab2_0_2">3. 日志格式配置</a></li><ul class="third_class_ul"><li><a href="#_label3_0_2_2">3.1 设置日志标志</a></li><li><a href="#_label3_0_2_3">3.2 可用的日志标志</a></li></ul><li><a href="#_lab2_0_3">4. 日志前缀配置</a></li><ul class="third_class_ul"><li><a href="#_label3_0_3_4">4.1 设置日志前缀</a></li></ul><li><a href="#_lab2_0_4">5. 文件日志输出</a></li><ul class="third_class_ul"><li><a href="#_label3_0_4_5">5.1 将日志输出到文件</a></li><li><a href="#_label3_0_4_6">5.2 文件打开模式说明</a></li></ul><li><a href="#_lab2_0_5">6. 自定义Logger</a></li><ul class="third_class_ul"><li><a href="#_label3_0_5_7">6.1 使用log.New()创建自定义Logger</a></li><li><a href="#_label3_0_5_8">6.2 多个Logger实例</a></li></ul><li><a href="#_lab2_0_6">7. 高级用法</a></li><ul class="third_class_ul"><li><a href="#_label3_0_6_9">7.1 日志级别管理</a></li><li><a href="#_label3_0_6_10">7.2 并发安全的日志记录</a></li></ul><li><a href="#_lab2_0_7">8. 最佳实践</a></li><ul class="third_class_ul"><li><a href="#_label3_0_7_11">8.1 错误处理</a></li></ul></ul></ul></div><p class="maodian"><a name="_label0"></a></p><h2>Go log模块使用</h2><p>对于更复杂的日志需求,可以考虑使用第三方日志库如<code>zap</code>、<code>logrus</code>等,它们提供了更丰富的功能和更好的性能</p>
<p class="maodian"><a name="_lab2_0_0"></a></p><h3>1.主要特性</h3>
<ul><li>线程安全的日志记录</li><li>灵活的日志格式配置</li><li>支持多种输出目标(控制台、文件等)- 内置错误处理和程序终止功能</li><li>支持自定义Logger创建</li></ul>
<p class="maodian"><a name="_lab2_0_1"></a></p><h3>2. 基础日志输出</h3>
<p class="maodian"><a name="_label3_0_1_0"></a></p><h4>2.1 基本日志方法</h4>
<p>log包提供了三种基本的日志输出方法:</p>
<div class="jb51code"><pre class="brush:go;">package main
import "log"
func main() {
// Println - 自动添加换行符
log.Println("这是一条日志信息")
// Printf - 格式化输出
str := "this is a test of log"
log.Printf("%s", str)
// Print - 不添加换行符
log.Print("这条信息没有换行")
}</pre></div>
<p class="maodian"><a name="_label3_0_1_1"></a></p><h4>2.2 错误处理日志</h4>
<p>log包还提供了在记录日志后终止程序的特殊方法:</p>
<div class="jb51code"><pre class="brush:go;">package main
import "log"
func main() {
// Fatal系列函数会在日志输出后调用os.Exit(1)
log.Fatalf("触发fatal错误,程序将退出")
// Panic系列函数会在日志输出后调用panic()
log.Panicln("触发panic错误")
}</pre></div>
<p><strong>注意</strong>:Fatal和Panic方法调用后程序会终止,后续代码不会执行。</p>
<p class="maodian"><a name="_lab2_0_2"></a></p><h3>3. 日志格式配置</h3>
<p class="maodian"><a name="_label3_0_2_2"></a></p><h4>3.1 设置日志标志</h4>
<p>使用<code>SetFlags</code>方法可以配置日志的输出格式:</p>
<div class="jb51code"><pre class="brush:go;">package main
import "log"
func main() {
// 设置日志格式标志
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
log.Println("设置完格式后的日志信息")
}</pre></div>
<p class="maodian"><a name="_label3_0_2_3"></a></p><h4>3.2 可用的日志标志</h4>
<p>log包定义了以下常量来控制日志格式:</p>
<div class="jb51code"><pre class="brush:go;">const (
Ldate = 1 << iota // 日期:2009/01/23
Ltime // 时间:01:23:23
Lmicroseconds // 微秒级别的时间:01:23:23.123123
Llongfile // 文件全路径名+行号:/a/b/c/d.go:23
Lshortfile // 文件名+行号:d.go:23
LUTC // 使用UTC时间
LstdFlags = Ldate | Ltime // 标准logger的初始值
)
</pre></div>
<p class="maodian"><a name="_lab2_0_3"></a></p><h3>4. 日志前缀配置</h3>
<p class="maodian"><a name="_label3_0_3_4"></a></p><h4>4.1 设置日志前缀</h4>
<p>使用<code>SetPrefix</code>方法可以为日志添加前缀:</p>
<div class="jb51code"><pre class="brush:go;">package main
import "log"
func main() {
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
// 默认无前缀
log.Println("没有设置前缀的日志信息")
// 设置前缀
log.SetPrefix("INFO: ")
log.Println("设置完日志前缀的信息")
// 获取当前前缀
prefix := log.Prefix()
log.Printf("当前前缀是:%s", prefix)
}</pre></div>
<p class="maodian"><a name="_lab2_0_4"></a></p><h3>5. 文件日志输出</h3>
<p class="maodian"><a name="_label3_0_4_5"></a></p><h4>5.1 将日志输出到文件</h4>
<p>使用<code>SetOutput</code>方法可以将日志重定向到文件:</p>
<div class="jb51code"><pre class="brush:go;">package main
import (
"log"
"os"
"time"
)
// 全局文件变量
var logfile *os.File
func init() {
// 创建日志目录
os.Mkdir("log", 0755)
// 打开或创建日志文件
var err error
logfile, err = os.OpenFile("log/"+time.Now().Format("2006-01-02")+".log",
os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("打开日志文件失败:%v", err)
return
}
// 配置日志
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
log.SetOutput(logfile)
log.SetPrefix("Prefix:")
}
func main() {
// 确保文件关闭
defer logfile.Close()
log.Println("这是一条写入文件的日志信息")
}</pre></div>
<p class="maodian"><a name="_label3_0_4_6"></a></p><h4>5.2 文件打开模式说明</h4>
<ul><li><code>os.O_CREATE</code>:如果文件不存在则创建</li><li><code>os.O_WRONLY</code>:只写模式打开文件</li><li><code>os.O_APPEND</code>:追加模式,新内容添加到文件末尾</li><li><code>0666</code>:文件权限设置</li></ul>
<p class="maodian"><a name="_lab2_0_5"></a></p><h3>6. 自定义Logger</h3>
<p class="maodian"><a name="_label3_0_5_7"></a></p><h4>6.1 使用log.New()创建自定义Logger</h4>
<p><code>log.New()</code>函数允许创建具有特定配置的Logger实例:</p>
<div class="jb51code"><pre class="brush:go;">package main
import (
"log"
"os"
"time"
)
func main() {
// 创建日志目录
os.Mkdir("log", 0755)
// 打开日志文件
logfile, err := os.OpenFile("log/"+time.Now().Format("2006-01-02")+".log",
os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Fatal(err)
return
}
defer logfile.Close()
// 创建自定义Logger
logger := log.New(logfile, "new:", log.Ldate|log.Ltime|log.Lshortfile)
logger.Println("使用New()来创造自己的logger对象")
}</pre></div>
<p class="maodian"><a name="_label3_0_5_8"></a></p><h4>6.2 多个Logger实例</h4>
<p>可以创建多个Logger实例用于不同的日志目的:</p>
<div class="jb51code"><pre class="brush:go;">package main
import (
"log"
"os"
)
func main() {
// 创建不同用途的Logger
infoLogger := log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime)
errorLogger := log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)
infoLogger.Println("这是一条信息日志")
errorLogger.Println("这是一条错误日志")
}</pre></div>
<p class="maodian"><a name="_lab2_0_6"></a></p><h3>7. 高级用法</h3>
<p class="maodian"><a name="_label3_0_6_9"></a></p><h4>7.1 日志级别管理</h4>
<p>虽然log包本身不提供日志级别,但可以通过自定义实现:</p>
<div class="jb51code"><pre class="brush:go;">package main
import (
"log"
"os"
"io"
)
type LogLevel int
const (
DEBUG LogLevel = iota
INFO
WARN
ERROR
FATAL
)
type Logger struct {
debug *log.Logger
info*log.Logger
warn*log.Logger
error *log.Logger
fatal *log.Logger
level LogLevel
}
func NewLogger(out io.Writer, level LogLevel) *Logger {
flags := log.Ldate | log.Ltime | log.Lshortfile
return &Logger{
debug: log.New(out, "DEBUG: ", flags),
info:log.New(out, "INFO: ", flags),
warn:log.New(out, "WARN: ", flags),
error: log.New(out, "ERROR: ", flags),
fatal: log.New(out, "FATAL: ", flags),
level: level,
}
}
func (l *Logger) Debug(v ...interface{}) {
if l.level <= DEBUG {
l.debug.Println(v...)
}
}
func (l *Logger) Info(v ...interface{}) {
if l.level <= INFO {
l.info.Println(v...)
}
}
// 其他级别方法类似...</pre></div>
<p class="maodian"><a name="_label3_0_6_10"></a></p><h4>7.2 并发安全的日志记录</h4>
<p>log包的所有方法都是线程安全的,可以在并发环境中安全使用:</p>
<div class="jb51code"><pre class="brush:go;">package main
import (
"log"
"sync"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
log.Printf("协程 %d 正在执行", id)
}(i)
}
wg.Wait()
log.Println("所有协程执行完毕")
}</pre></div>
<p class="maodian"><a name="_lab2_0_7"></a></p><h3>8. 最佳实践</h3>
<p class="maodian"><a name="_label3_0_7_11"></a></p><h4>8.1 错误处理</h4>
<div class="jb51code"><pre class="brush:go;">package main
import (
"log"
"os"
)
func setupLogger() (*os.File, error) {
file, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
return nil, err
}
log.SetOutput(file)
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
return file, nil
}
func main() {
logFile, err := setupLogger()
if err != nil {
log.Fatal("初始化日志失败:", err)
}
defer logFile.Close()
// 应用程序逻辑...
log.Println("应用程序启动成功")
}</pre></div>
頁:
[1]