Compare commits
9 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
8c6cf6310f | |
|
|
ecd906084a | |
|
|
0c28c10c1e | |
|
|
27fcdad135 | |
|
|
1004333534 | |
|
|
107b8f3050 | |
|
|
42beab28a3 | |
|
|
b5ea719c56 | |
|
|
c8e7426d2d |
76
README.md
76
README.md
|
|
@ -1,3 +1,77 @@
|
||||||
# gologger
|
# gologger
|
||||||
|
|
||||||
a logger used in go
|
GoLogger 是一个简单但功能强大的 Go 语言日志库,提供灵活的日志记录功能。它支持多种日志输出方式(控制台、文件等),并允许自定义日志格式。
|
||||||
|
|
||||||
|
## 特性
|
||||||
|
- 支持多种日志级别:ERROR, WARN, INFO, DEBUG, TRACE
|
||||||
|
- 支持多种输出方式:控制台、文件(支持滚动策略)
|
||||||
|
- 可定制日志格式
|
||||||
|
- 支持按类别记录日志
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
```bash
|
||||||
|
go get github.com/yourusername/gologger
|
||||||
|
```
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/yourusername/gologger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// 获取默认logger
|
||||||
|
logger := gologger.GetLogger("main")
|
||||||
|
|
||||||
|
// 设置全局日志级别
|
||||||
|
gologger.Configure(gologger.LoggersConfig{
|
||||||
|
Level: "info",
|
||||||
|
Appenders: []gologger.LogAppenderConfig{
|
||||||
|
{
|
||||||
|
Type: "console",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "file",
|
||||||
|
Options: map[string]interface{}{
|
||||||
|
"filePath": "app.log",
|
||||||
|
"EnableRolling": true,
|
||||||
|
"MaxSize": 1024 * 1024 * 10, // 10MB
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// 记录日志
|
||||||
|
logger.Info("Application started")
|
||||||
|
logger.Error("An error occurred")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 配置说明
|
||||||
|
|
||||||
|
### 日志级别
|
||||||
|
支持的级别包括:off, error, warn, info, debug, trace
|
||||||
|
|
||||||
|
### 输出方式(Appenders)
|
||||||
|
|
||||||
|
1. **ConsoleAppender** - 控制台输出
|
||||||
|
配置示例:
|
||||||
|
```go
|
||||||
|
{
|
||||||
|
Type: "console",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **FileAppender** - 文件输出,支持滚动策略
|
||||||
|
配置参数:
|
||||||
|
- filePath: 日志文件路径
|
||||||
|
- EnableRolling: 是否启用滚动(默认true)
|
||||||
|
- MaxSize: 单个文件最大大小(字节,默认10MB)
|
||||||
|
- MaxAge: 文件最大保存时间(秒,默认86400秒=24小时)
|
||||||
|
|
||||||
|
### 格式化器
|
||||||
|
可以通过SelectFormatter选择不同的日志格式:
|
||||||
|
- simple: 简单格式 `[timestamp] level : category - message`
|
||||||
|
- json: JSON 格式输出
|
||||||
21
console.go
21
console.go
|
|
@ -4,6 +4,18 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ConsoleAppender implements the LoggerAppender interface for console output.
|
||||||
|
// It uses color-coded templates for different log levels.
|
||||||
|
// Example:
|
||||||
|
// appender := &ConsoleAppender{
|
||||||
|
// formatter: NewSimpleFormatter(),
|
||||||
|
// }
|
||||||
|
// appender.Append(event)
|
||||||
|
// appender.Close()
|
||||||
|
type ConsoleAppender struct {
|
||||||
|
formatter LogFormatter
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ErrorTemplate = "\033[1;31m%s\033[0m"
|
ErrorTemplate = "\033[1;31m%s\033[0m"
|
||||||
WarnTemplate = "\033[1;33m%s\033[0m"
|
WarnTemplate = "\033[1;33m%s\033[0m"
|
||||||
|
|
@ -12,9 +24,6 @@ const (
|
||||||
TraceTemplate = "\033[1;35m%s\033[0m"
|
TraceTemplate = "\033[1;35m%s\033[0m"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConsoleAppender struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close implements LoggerAppender.
|
// Close implements LoggerAppender.
|
||||||
func (c *ConsoleAppender) Close() {
|
func (c *ConsoleAppender) Close() {
|
||||||
|
|
||||||
|
|
@ -26,7 +35,7 @@ func (c *ConsoleAppender) GetName() string {
|
||||||
|
|
||||||
func (c *ConsoleAppender) Append(logEvent LogEvent) {
|
func (c *ConsoleAppender) Append(logEvent LogEvent) {
|
||||||
|
|
||||||
logMsg := format(logEvent)
|
logMsg := c.formatter(logEvent)
|
||||||
switch logEvent.Level {
|
switch logEvent.Level {
|
||||||
case Error:
|
case Error:
|
||||||
fmt.Printf(ErrorTemplate, logMsg)
|
fmt.Printf(ErrorTemplate, logMsg)
|
||||||
|
|
@ -41,7 +50,9 @@ func (c *ConsoleAppender) Append(logEvent LogEvent) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func makeConsoleAppender(appenderConfig LogAppenderConfig) *LoggerAppender {
|
func makeConsoleAppender(appenderConfig LogAppenderConfig) *LoggerAppender {
|
||||||
var appender LoggerAppender = &ConsoleAppender{}
|
consoleAppender := &ConsoleAppender{}
|
||||||
|
consoleAppender.formatter = SelectFormatter(appenderConfig.Formatter)
|
||||||
|
var appender LoggerAppender = consoleAppender
|
||||||
return &appender
|
return &appender
|
||||||
}
|
}
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
||||||
136
file.go
136
file.go
|
|
@ -3,13 +3,34 @@ package gologger
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// FileAppender implements the LoggerAppender interface for file output.
|
||||||
|
// It supports log rotation based on file size and age.
|
||||||
|
// Example:
|
||||||
|
// appender := &FileAppender{
|
||||||
|
// formatter: NewSimpleFormatter(),
|
||||||
|
// filePath: "app.log",
|
||||||
|
// EnableRolling: true,
|
||||||
|
// MaxSize: 1024 * 1024 * 10, // 10MB
|
||||||
|
// }
|
||||||
|
// appender.Append(event)
|
||||||
|
// appender.Close()
|
||||||
type FileAppender struct {
|
type FileAppender struct {
|
||||||
|
formatter LogFormatter
|
||||||
filePath string
|
filePath string
|
||||||
lchan chan LogEvent
|
lchan chan LogEvent
|
||||||
file *os.File
|
file *os.File
|
||||||
stopChan chan struct{}
|
stopChan chan struct{}
|
||||||
|
// 新增滚动相关字段
|
||||||
|
EnableRolling bool
|
||||||
|
MaxSize int64 // 文件最大大小(字节)
|
||||||
|
MaxAge int64 // 文件最大时间(秒)
|
||||||
|
currentFileSize int64 // 当前文件大小
|
||||||
|
createdAt int64 // 文件创建时间戳
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close implements LoggerAppender.
|
// Close implements LoggerAppender.
|
||||||
|
|
@ -32,6 +53,13 @@ func (f *FileAppender) start() {
|
||||||
os.MkdirAll(dirName, 0755)
|
os.MkdirAll(dirName, 0755)
|
||||||
}
|
}
|
||||||
f.file, _ = os.OpenFile(f.filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
f.file, _ = os.OpenFile(f.filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
|
||||||
|
// 获取当前文件大小
|
||||||
|
if stat, err := f.file.Stat(); err == nil {
|
||||||
|
f.currentFileSize = stat.Size()
|
||||||
|
}
|
||||||
|
// 记录文件创建时间
|
||||||
|
f.createdAt = time.Now().Unix()
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -41,13 +69,53 @@ func (f *FileAppender) start() {
|
||||||
case <-f.stopChan:
|
case <-f.stopChan:
|
||||||
return
|
return
|
||||||
case logEvent := <-f.lchan:
|
case logEvent := <-f.lchan:
|
||||||
logMsg := format(logEvent)
|
// 检查日志滚动
|
||||||
|
if f.EnableRolling {
|
||||||
|
f.checkAndRoll(logEvent)
|
||||||
|
}
|
||||||
|
logMsg := f.formatter(logEvent)
|
||||||
f.file.WriteString(logMsg)
|
f.file.WriteString(logMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增日志滚动方法
|
||||||
|
func (f *FileAppender) checkAndRoll(logEvent LogEvent) {
|
||||||
|
// 按大小滚动
|
||||||
|
if f.MaxSize > 0 && f.currentFileSize >= f.MaxSize {
|
||||||
|
f.rollFile(logEvent)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按时间滚动
|
||||||
|
if f.MaxAge > 0 && time.Now().Unix()-f.createdAt >= f.MaxAge {
|
||||||
|
f.rollFile(logEvent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 日志文件滚动
|
||||||
|
func (f *FileAppender) rollFile(logEvent LogEvent) {
|
||||||
|
// 关闭当前文件
|
||||||
|
f.file.Close()
|
||||||
|
|
||||||
|
// 重命名旧文件
|
||||||
|
timestamp := time.Now().Format("20060102150405")
|
||||||
|
newPath := f.filePath + "." + timestamp
|
||||||
|
os.Rename(f.filePath, newPath)
|
||||||
|
|
||||||
|
// 创建新文件
|
||||||
|
f.file, _ = os.OpenFile(f.filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
|
||||||
|
// 重置状态
|
||||||
|
f.currentFileSize = 0
|
||||||
|
f.createdAt = time.Now().Unix()
|
||||||
|
|
||||||
|
// 重新写入当前日志
|
||||||
|
logMsg := format(logEvent)
|
||||||
|
f.file.WriteString(logMsg)
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FileAppender) Append(logEvent LogEvent) {
|
func (f *FileAppender) Append(logEvent LogEvent) {
|
||||||
|
|
||||||
f.lchan <- logEvent
|
f.lchan <- logEvent
|
||||||
|
|
@ -60,8 +128,72 @@ func makeFileAppender(appenderConfig LogAppenderConfig) *LoggerAppender {
|
||||||
if !ok {
|
if !ok {
|
||||||
logfile = "default.log"
|
logfile = "default.log"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增滚动配置参数
|
||||||
|
rollingEnabled := false
|
||||||
|
if enable, ok := appenderConfig.Options["enableRolling"].(bool); ok {
|
||||||
|
rollingEnabled = enable
|
||||||
|
}
|
||||||
|
|
||||||
|
maxSize := int64(0)
|
||||||
|
if size, ok := appenderConfig.Options["maxSize"].(int64); ok {
|
||||||
|
maxSize = size * 1024 * 1024 // 将兆转换为字节
|
||||||
|
} else if sizeStr, ok := appenderConfig.Options["maxSize"].(string); ok {
|
||||||
|
// 解析带单位的大小配置(支持KB, MB, GB)
|
||||||
|
var re = regexp.MustCompile(`(?i)^(\d+)([kmg]b)?$`)
|
||||||
|
matches := re.FindStringSubmatch(sizeStr)
|
||||||
|
if len(matches) > 0 {
|
||||||
|
num, _ := strconv.ParseInt(matches[1], 10, 64)
|
||||||
|
unit := ""
|
||||||
|
if len(matches) > 2 {
|
||||||
|
unit = matches[2]
|
||||||
|
}
|
||||||
|
switch unit {
|
||||||
|
case "KB", "kb":
|
||||||
|
maxSize = num * 1024
|
||||||
|
case "MB", "mb":
|
||||||
|
maxSize = num * 1024 * 1024
|
||||||
|
case "GB", "gb":
|
||||||
|
maxSize = num * 1024 * 1024 * 1024
|
||||||
|
default:
|
||||||
|
maxSize = num * 1024 * 1024 // 默认按MB处理
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
maxAge := int64(0)
|
||||||
|
if ageStr, ok := appenderConfig.Options["maxAge"].(string); ok {
|
||||||
|
// 解析带单位的时间配置
|
||||||
|
re := regexp.MustCompile(`^\d+[hd]?$`)
|
||||||
|
if re.MatchString(ageStr) {
|
||||||
|
// 提取数字部分和单位
|
||||||
|
numStr := ""
|
||||||
|
unit := ""
|
||||||
|
for _, c := range ageStr {
|
||||||
|
if c >= '0' && c <= '9' {
|
||||||
|
numStr += string(c)
|
||||||
|
} else {
|
||||||
|
unit = string(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num, _ := strconv.ParseInt(numStr, 10, 64)
|
||||||
|
switch unit {
|
||||||
|
case "h":
|
||||||
|
maxAge = num * 3600 // 小时转秒
|
||||||
|
default:
|
||||||
|
maxAge = num * 86400 // 默认按天转秒
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ageInt, ok := appenderConfig.Options["maxAge"].(int64); ok {
|
||||||
|
maxAge = ageInt
|
||||||
|
}
|
||||||
|
|
||||||
var ret LoggerAppender = &FileAppender{
|
var ret LoggerAppender = &FileAppender{
|
||||||
|
formatter: SelectFormatter(appenderConfig.Formatter),
|
||||||
filePath: logfile.(string),
|
filePath: logfile.(string),
|
||||||
|
EnableRolling: rollingEnabled,
|
||||||
|
MaxSize: maxSize,
|
||||||
|
MaxAge: maxAge,
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.(*FileAppender).start()
|
ret.(*FileAppender).start()
|
||||||
|
|
|
||||||
36
format.go
36
format.go
|
|
@ -1,12 +1,26 @@
|
||||||
|
// Package gologger provides a simple logging implementation with multiple appenders and formatters.
|
||||||
|
// It supports console, file, and HTTP logging with customizable formats.
|
||||||
package gologger
|
package gologger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// LogFormatter is a function type that formats a LogEvent into a string.
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// formatter := func(event LogEvent) string {
|
||||||
|
// return fmt.Sprintf("[%s] %s: %v", event.Ts.Format("2006-01-02"), event.Level, event.Data)
|
||||||
|
// }
|
||||||
|
type LogFormatter = func(LogEvent) string
|
||||||
|
|
||||||
const logTemplate = "[%s] %s : %s - %s\n"
|
const logTemplate = "[%s] %s : %s - %s\n"
|
||||||
|
|
||||||
|
// format is the default formatter that converts a LogEvent to a string using the default template.
|
||||||
|
// It handles both simple values and formatted strings.
|
||||||
|
// Template: "[timestamp] level : category - data"
|
||||||
func format(logEvent LogEvent) string {
|
func format(logEvent LogEvent) string {
|
||||||
data := logEvent.Ts.Format("2006-01-02 15:04:05")
|
data := logEvent.Ts.Format("2006-01-02 15:04:05")
|
||||||
msg := ""
|
msg := ""
|
||||||
|
|
@ -37,7 +51,7 @@ func isFormatString(f interface{}) bool {
|
||||||
}
|
}
|
||||||
// 尝试使用空接口来格式化字符串
|
// 尝试使用空接口来格式化字符串
|
||||||
m := fmt.Sprintf(s, []interface{}{}...)
|
m := fmt.Sprintf(s, []interface{}{}...)
|
||||||
return strings.Index(m, "MISSING") != -1
|
return strings.Contains(m, "MISSING")
|
||||||
}
|
}
|
||||||
|
|
||||||
func sprint(s []interface{}) string {
|
func sprint(s []interface{}) string {
|
||||||
|
|
@ -51,3 +65,23 @@ func sprint(s []interface{}) string {
|
||||||
}
|
}
|
||||||
return fmt.Sprint(str...)
|
return fmt.Sprint(str...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func jsonFormatter(logEvent LogEvent) string {
|
||||||
|
_, err := json.Marshal(logEvent.Data)
|
||||||
|
if err != nil {
|
||||||
|
logEvent.Data = []interface{}{fmt.Sprintf("%v", logEvent.Data)}
|
||||||
|
}
|
||||||
|
d, _ := json.Marshal(logEvent)
|
||||||
|
return string(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SelectFormatter(formatter string) LogFormatter {
|
||||||
|
switch strings.ToLower(formatter) {
|
||||||
|
case "json":
|
||||||
|
return jsonFormatter
|
||||||
|
case "text":
|
||||||
|
return format
|
||||||
|
default:
|
||||||
|
return format
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ func TestFormat(t *testing.T) {
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if got := format(tt.logEvent); strings.Index(got, tt.want) == -1 {
|
if got := format(tt.logEvent); strings.Contains(got, tt.want) {
|
||||||
t.Errorf("format() = %v, want %v", got, tt.want)
|
t.Errorf("format() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
2
go.mod
2
go.mod
|
|
@ -1,3 +1,3 @@
|
||||||
module git.pyer.club/kingecg/gologger
|
module git.kingecg.top/kingecg/gologger
|
||||||
|
|
||||||
go 1.19
|
go 1.19
|
||||||
|
|
|
||||||
88
main.go
88
main.go
|
|
@ -1,3 +1,5 @@
|
||||||
|
// Package gologger provides a simple logging implementation with multiple appenders and formatters.
|
||||||
|
// It supports console, file, and HTTP logging with customizable formats.
|
||||||
package gologger
|
package gologger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -25,10 +27,25 @@ var logLevelMap map[string]int = map[string]int{
|
||||||
var loggerMap map[string]*Logger = map[string]*Logger{}
|
var loggerMap map[string]*Logger = map[string]*Logger{}
|
||||||
var appenderFactoryMap map[string]func(LogAppenderConfig) *LoggerAppender = map[string]func(LogAppenderConfig) *LoggerAppender{}
|
var appenderFactoryMap map[string]func(LogAppenderConfig) *LoggerAppender = map[string]func(LogAppenderConfig) *LoggerAppender{}
|
||||||
var appenders map[string]*LoggerAppender = map[string]*LoggerAppender{}
|
var appenders map[string]*LoggerAppender = map[string]*LoggerAppender{}
|
||||||
var loggerConfig LoggersConfig
|
var loggerConfig LoggersConfig = LoggersConfig{
|
||||||
|
Appenders: map[string]LogAppenderConfig{
|
||||||
|
"console": {
|
||||||
|
Type: "console",
|
||||||
|
Formatter: "text",
|
||||||
|
Options: map[string]interface{}{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Categories: map[string]LogConfig{
|
||||||
|
"default": {
|
||||||
|
Level: "error",
|
||||||
|
Appenders: []string{"console"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
type LogAppenderConfig struct {
|
type LogAppenderConfig struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
Formatter string `json:"formatter"`
|
||||||
Options map[string]interface{} `json:"options"`
|
Options map[string]interface{} `json:"options"`
|
||||||
}
|
}
|
||||||
type LogConfig struct {
|
type LogConfig struct {
|
||||||
|
|
@ -40,6 +57,14 @@ type LoggersConfig struct {
|
||||||
Appenders map[string]LogAppenderConfig `json:"appenders"`
|
Appenders map[string]LogAppenderConfig `json:"appenders"`
|
||||||
Categories map[string]LogConfig `json:"categories"`
|
Categories map[string]LogConfig `json:"categories"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Logger represents a logger instance for a specific category.
|
||||||
|
// It maintains the log level and appenders for that category.
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// logger := GetLogger("mycategory")
|
||||||
|
// logger.Info("This is an info message")
|
||||||
|
// logger.Error("This is an error message")
|
||||||
type Logger struct {
|
type Logger struct {
|
||||||
category string
|
category string
|
||||||
level int
|
level int
|
||||||
|
|
@ -47,10 +72,10 @@ type Logger struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogEvent struct {
|
type LogEvent struct {
|
||||||
Category string
|
Category string `json:"category"`
|
||||||
Ts time.Time
|
Ts time.Time `json:"ts"`
|
||||||
Level int
|
Level int `json:"level"`
|
||||||
Data []interface{}
|
Data []interface{} `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LoggerAppender interface {
|
type LoggerAppender interface {
|
||||||
|
|
@ -59,7 +84,7 @@ type LoggerAppender interface {
|
||||||
Close()
|
Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
var consoleAppender LoggerAppender = &ConsoleAppender{}
|
var consoleAppender LoggerAppender = *makeConsoleAppender(LogAppenderConfig{})
|
||||||
var defaultLogger = &Logger{
|
var defaultLogger = &Logger{
|
||||||
|
|
||||||
level: Error,
|
level: Error,
|
||||||
|
|
@ -106,13 +131,11 @@ func GetLogger(name string) *Logger {
|
||||||
if ok {
|
if ok {
|
||||||
return makeLogger(name, logConfig)
|
return makeLogger(name, logConfig)
|
||||||
}
|
}
|
||||||
if name == "default" {
|
logConfig, ok = loggerConfig.Categories["default"]
|
||||||
return defaultLogger
|
l := makeLogger(name, logConfig)
|
||||||
}
|
|
||||||
l := *GetLogger("default")
|
|
||||||
l.category = name
|
l.category = name
|
||||||
loggerMap[name] = &l
|
loggerMap[name] = l
|
||||||
return &l
|
return l
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,7 +144,7 @@ func makeLogger(name string, config LogConfig) *Logger {
|
||||||
levelstr := strings.ToLower(config.Level)
|
levelstr := strings.ToLower(config.Level)
|
||||||
logger.level = logLevelMap[levelstr]
|
logger.level = logLevelMap[levelstr]
|
||||||
|
|
||||||
if config.Appenders == nil || len(config.Appenders) == 0 {
|
if len(config.Appenders) == 0 {
|
||||||
logger.appenders = []*LoggerAppender{&consoleAppender}
|
logger.appenders = []*LoggerAppender{&consoleAppender}
|
||||||
} else {
|
} else {
|
||||||
logger.appenders = make([]*LoggerAppender, len(config.Appenders))
|
logger.appenders = make([]*LoggerAppender, len(config.Appenders))
|
||||||
|
|
@ -132,9 +155,15 @@ func makeLogger(name string, config LogConfig) *Logger {
|
||||||
loggerMap[name] = logger
|
loggerMap[name] = logger
|
||||||
return logger
|
return logger
|
||||||
}
|
}
|
||||||
func Configure(config LoggersConfig) {
|
|
||||||
|
func ReconfigLoggers(config LoggersConfig) {
|
||||||
|
validateConfig(config)
|
||||||
loggerConfig = config
|
loggerConfig = config
|
||||||
for name, appenderConfig := range loggerConfig.Appenders {
|
for name, appenderConfig := range loggerConfig.Appenders {
|
||||||
|
oldappender, ok := appenders[name]
|
||||||
|
if ok {
|
||||||
|
(*oldappender).Close()
|
||||||
|
}
|
||||||
appenderFactory, ok := appenderFactoryMap[appenderConfig.Type]
|
appenderFactory, ok := appenderFactoryMap[appenderConfig.Type]
|
||||||
if ok {
|
if ok {
|
||||||
appenders[name] = appenderFactory(appenderConfig)
|
appenders[name] = appenderFactory(appenderConfig)
|
||||||
|
|
@ -142,12 +171,39 @@ func Configure(config LoggersConfig) {
|
||||||
appenders[name] = &consoleAppender
|
appenders[name] = &consoleAppender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for name, _ := range loggerConfig.Categories {
|
for name, logger := range loggerMap {
|
||||||
GetLogger(name)
|
logConfig, ok := loggerConfig.Categories[name]
|
||||||
|
if !ok {
|
||||||
|
logConfig, _ = loggerConfig.Categories["default"]
|
||||||
}
|
}
|
||||||
|
logger.level = logLevelMap[strings.ToLower(logConfig.Level)]
|
||||||
|
if len(logConfig.Appenders) == 0 {
|
||||||
|
logger.appenders = []*LoggerAppender{&consoleAppender}
|
||||||
|
} else {
|
||||||
|
logger.appenders = make([]*LoggerAppender, len(logConfig.Appenders))
|
||||||
|
for i, appenderName := range logConfig.Appenders {
|
||||||
|
logger.appenders[i] = appenders[appenderName]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func validateConfig(config LoggersConfig) {
|
||||||
|
_, ok := loggerConfig.Categories["default"]
|
||||||
|
if !ok {
|
||||||
|
panic("default logger config not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func Configure(config LoggersConfig) {
|
||||||
|
validateConfig(config)
|
||||||
|
ReconfigLoggers(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RegistAppender(typeName string, appenderCreatCb func(LogAppenderConfig) *LoggerAppender) {
|
func RegistAppender(typeName string, appenderCreatCb func(LogAppenderConfig) *LoggerAppender) {
|
||||||
|
|
||||||
appenderFactoryMap[typeName] = appenderCreatCb
|
appenderFactoryMap[typeName] = appenderCreatCb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
loggerMap["default"] = defaultLogger
|
||||||
|
appenders["console"] = &consoleAppender
|
||||||
|
}
|
||||||
|
|
|
||||||
25
main_test.go
25
main_test.go
|
|
@ -10,7 +10,30 @@ func TestGetLogger(t *testing.T) {
|
||||||
if dl != defaultLogger {
|
if dl != defaultLogger {
|
||||||
t.Errorf("GetLogger(\"defult\") should return defaultLogger")
|
t.Errorf("GetLogger(\"defult\") should return defaultLogger")
|
||||||
}
|
}
|
||||||
|
dl.Error("test")
|
||||||
|
Configure(LoggersConfig{
|
||||||
|
Appenders: map[string]LogAppenderConfig{
|
||||||
|
"console": {
|
||||||
|
Type: "console",
|
||||||
|
Formatter: "json",
|
||||||
|
Options: map[string]interface{}{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Categories: map[string]LogConfig{
|
||||||
|
"default": {
|
||||||
|
Level: "info",
|
||||||
|
Appenders: []string{"console"},
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
Level: "debug",
|
||||||
|
Appenders: []string{"console"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
dl.Info("test")
|
||||||
|
if dl.level != Info {
|
||||||
|
t.Errorf("GetLogger(\"default\") should return defaultLogger")
|
||||||
|
}
|
||||||
al := GetLogger("app")
|
al := GetLogger("app")
|
||||||
|
|
||||||
if al == dl {
|
if al == dl {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
logger "git.pyer.club/kingecg/gologger"
|
logger "git.kingecg.top/kingecg/gologger"
|
||||||
)
|
)
|
||||||
|
|
||||||
func aqmain() {
|
func aqmain() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue