golang实现PHP Monolog风格日志记录功能插件库glo的使用
golang实现PHP Monolog风格日志记录功能插件库glo的使用
GLO是一个受PHP Monolog启发的Golang日志库,其严重级别与Monolog完全相同。
安装
go get github.com/lajosbencz/glo
严重级别
Debug = 100
Info = 200
Notice = 250
Warning = 300
Error = 400
Critical = 500
Alert = 550
Emergency = 600
简单示例
package main
import "github.com/lajosbencz/glo"
func main() {
// Info - Warning 会输出到 os.Stdout
// Error - Emergency 会输出到 os.Stderr
log := glo.NewStdFacility()
// 输出到 os.Stdout
log.Debug("Detailed debug line: %#v", map[string]string{"x": "foo", "y": "bar"})
// 输出到 os.Stderr
log.Error("Oooof!")
}
输出:
2019-01-22T15:16:08+01:00 [DEBUG] Detailed debug line [map[x:foo y:bar]]
2019-01-22T15:16:08+01:00 [ERROR] Oooof! []
自定义示例
package main
import (
"bytes"
"fmt"
"os"
"strings"
"github.com/lajosbencz/glo"
)
func main() {
log := glo.NewFacility()
// 将所有日志写入缓冲区
bfr := bytes.NewBufferString("")
handlerBfr := glo.NewHandler(bfr)
log.PushHandler(handlerBfr)
// 只将错误及以上级别的日志以简短格式写入stdout
handlerStd := glo.NewHandler(os.Stdout)
formatter := glo.NewFormatter("{L}: {M}")
filter := glo.NewFilterLevel(glo.Error)
handlerStd.SetFormatter(formatter)
handlerStd.PushFilter(filter)
log.PushHandler(handlerStd)
fmt.Println("Log output:")
fmt.Println(strings.Repeat("=", 70))
log.Info("Only written to the buffer")
log.Alert("Written to both buffer and stdout")
fmt.Println("")
fmt.Println("Buffer contents:")
fmt.Println(strings.Repeat("=", 70))
fmt.Println(bfr.String())
}
输出:
Log output:
======================================================================
ALERT: Written to both buffer and stdout []
Buffer contents:
======================================================================
2019-01-22T15:14:16+01:00 [INFO] Only written to the buffer []
2019-01-22T15:14:16+01:00 [ALERT] Written to both buffer and stdout []
自定义过滤器
package main
import (
"os"
"regexp"
"github.com/lajosbencz/glo"
)
func main() {
handler := glo.NewHandler(os.Stdout)
filterEmptyLines := &filterRgx{regexp.MustCompile(`^.+$`)}
handler.PushFilter(filterEmptyLines)
log := glo.NewFacility()
log.PushHandler(handler)
log.Debug("", "format is empty, should be ignored")
log.Debug("only this should appear at the output")
}
type filterRgx struct {
rgx *regexp.Regexp
}
func (f *filterRgx) Check(level glo.Level, line string, params ...interface{}) bool {
return f.rgx.MatchString(line)
}
输出:
2019-01-22T15:30:23+01:00 [DEBUG] only this should appear at the output
更多关于golang实现PHP Monolog风格日志记录功能插件库glo的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang实现PHP Monolog风格日志记录功能插件库glo的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用Golang实现PHP Monolog风格的日志记录库glo
PHP Monolog是一个流行的日志记录库,提供了灵活的日志处理功能。在Golang中,我们可以创建一个类似的库"glo"来实现相似的功能。下面我将介绍如何实现这样一个库及其使用方法。
基本设计思路
glo库将包含以下Monolog的核心特性:
- 多级别日志记录 (Debug, Info, Warning, Error等)
- 多种日志处理器 (文件、控制台、网络等)
- 日志格式化
- 日志通道概念
- 上下文信息记录
实现代码
package glo
import (
"fmt"
"io"
"os"
"sync"
"time"
)
// 日志级别
type Level int
const (
Debug Level = iota
Info
Warning
Error
Critical
)
var levelNames = []string{
"DEBUG",
"INFO",
"WARNING",
"ERROR",
"CRITICAL",
}
// 日志记录结构
type Record struct {
Message string
Level Level
Timestamp time.Time
Context map[string]interface{}
}
// 日志处理器接口
type Handler interface {
Handle(record Record) error
Close() error
}
// 格式化接口
type Formatter interface {
Format(record Record) string
}
// 默认格式化器
type LineFormatter struct{}
func (f *LineFormatter) Format(record Record) string {
return fmt.Sprintf("[%s] %s: %s %v\n",
record.Timestamp.Format("2006-01-02 15:04:05"),
levelNames[record.Level],
record.Message,
record.Context)
}
// 基础处理器
type BaseHandler struct {
formatter Formatter
writer io.Writer
}
func NewBaseHandler(writer io.Writer, formatter Formatter) *BaseHandler {
return &BaseHandler{
writer: writer,
formatter: formatter,
}
}
func (h *BaseHandler) Handle(record Record) error {
_, err := fmt.Fprint(h.writer, h.formatter.Format(record))
return err
}
func (h *BaseHandler) Close() error {
if closer, ok := h.writer.(io.Closer); ok {
return closer.Close()
}
return nil
}
// 文件处理器
type FileHandler struct {
BaseHandler
file *os.File
}
func NewFileHandler(filename string, formatter Formatter) (*FileHandler, error) {
file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return nil, err
}
return &FileHandler{
BaseHandler: *NewBaseHandler(file, formatter),
file: file,
}, nil
}
// 控制台处理器
type ConsoleHandler struct {
BaseHandler
}
func NewConsoleHandler(formatter Formatter) *ConsoleHandler {
return &ConsoleHandler{
BaseHandler: *NewBaseHandler(os.Stdout, formatter),
}
}
// 日志记录器
type Logger struct {
name string
handlers []Handler
minLevel Level
context map[string]interface{}
contextMu sync.RWMutex
}
func NewLogger(name string) *Logger {
return &Logger{
name: name,
handlers: make([]Handler, 0),
minLevel: Debug,
context: make(map[string]interface{}),
}
}
func (l *Logger) AddHandler(handler Handler) {
l.handlers = append(l.handlers, handler)
}
func (l *Logger) SetLevel(level Level) {
l.minLevel = level
}
func (l *Logger) WithContext(key string, value interface{}) *Logger {
l.contextMu.Lock()
defer l.contextMu.Unlock()
newLogger := NewLogger(l.name)
newLogger.handlers = l.handlers
newLogger.minLevel = l.minLevel
// 复制上下文
for k, v := range l.context {
newLogger.context[k] = v
}
newLogger.context[key] = value
return newLogger
}
func (l *Logger) log(level Level, message string, context map[string]interface{}) {
if level < l.minLevel {
return
}
// 合并上下文
mergedContext := make(map[string]interface{})
l.contextMu.RLock()
for k, v := range l.context {
mergedContext[k] = v
}
l.contextMu.RUnlock()
for k, v := range context {
mergedContext[k] = v
}
record := Record{
Message: message,
Level: level,
Timestamp: time.Now(),
Context: mergedContext,
}
for _, handler := range l.handlers {
_ = handler.Handle(record)
}
}
// 各级别日志方法
func (l *Logger) Debug(message string, context map[string]interface{}) {
l.log(Debug, message, context)
}
func (l *Logger) Info(message string, context map[string]interface{}) {
l.log(Info, message, context)
}
func (l *Logger) Warning(message string, context map[string]interface{}) {
l.log(Warning, message, context)
}
func (l *Logger) Error(message string, context map[string]interface{}) {
l.log(Error, message, context)
}
func (l *Logger) Critical(message string, context map[string]interface{}) {
l.log(Critical, message, context)
}
// 关闭所有处理器
func (l *Logger) Close() error {
var err error
for _, handler := range l.handlers {
if e := handler.Close(); e != nil {
err = e
}
}
return err
}
使用示例
package main
import (
"log"
"path/to/glo"
)
func main() {
// 创建日志记录器
logger := glo.NewLogger("myapp")
// 添加控制台处理器
consoleHandler := glo.NewConsoleHandler(&glo.LineFormatter{})
logger.AddHandler(consoleHandler)
// 添加文件处理器
fileHandler, err := glo.NewFileHandler("app.log", &glo.LineFormatter{})
if err != nil {
log.Fatal(err)
}
logger.AddHandler(fileHandler)
// 设置日志级别
logger.SetLevel(glo.Info)
// 记录日志
logger.Info("Application started", nil)
// 带上下文的日志
ctxLogger := logger.WithContext("request_id", "12345")
ctxLogger.Warning("Something might be wrong", map[string]interface{}{
"user": "john_doe",
})
// 错误日志
logger.Error("Failed to connect to database", map[string]interface{}{
"error": "connection timeout",
})
// 关闭日志处理器
if err := logger.Close(); err != nil {
log.Println("Failed to close logger:", err)
}
}
功能扩展建议
-
更多处理器:
- 实现SyslogHandler、SocketHandler等
- 添加RotatingFileHandler支持日志轮转
-
更丰富的格式化:
- 实现JSONFormatter
- 支持自定义格式化模板
-
高级功能:
- 添加日志缓冲
- 实现日志处理器组
- 添加日志过滤功能
-
性能优化:
- 使用缓冲写入
- 异步日志记录
这个glo库实现了Monolog的核心功能,包括多级别日志记录、多种处理器、上下文信息和格式化功能。您可以根据需要进一步扩展它,添加更多高级特性。