Compare commits

..

No commits in common. "master" and "v1.0.5" have entirely different histories.

10 changed files with 66 additions and 685 deletions

View File

@ -1,77 +1,3 @@
# gologger
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 格式输出
a logger used in go

View File

@ -4,18 +4,6 @@ import (
"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 (
ErrorTemplate = "\033[1;31m%s\033[0m"
WarnTemplate = "\033[1;33m%s\033[0m"
@ -24,6 +12,9 @@ const (
TraceTemplate = "\033[1;35m%s\033[0m"
)
type ConsoleAppender struct {
}
// Close implements LoggerAppender.
func (c *ConsoleAppender) Close() {
@ -35,7 +26,7 @@ func (c *ConsoleAppender) GetName() string {
func (c *ConsoleAppender) Append(logEvent LogEvent) {
logMsg := c.formatter(logEvent)
logMsg := format(logEvent)
switch logEvent.Level {
case Error:
fmt.Printf(ErrorTemplate, logMsg)
@ -50,9 +41,7 @@ func (c *ConsoleAppender) Append(logEvent LogEvent) {
}
}
func makeConsoleAppender(appenderConfig LogAppenderConfig) *LoggerAppender {
consoleAppender := &ConsoleAppender{}
consoleAppender.formatter = SelectFormatter(appenderConfig.Formatter)
var appender LoggerAppender = consoleAppender
var appender LoggerAppender = &ConsoleAppender{}
return &appender
}
func init() {

208
file.go
View File

@ -3,40 +3,13 @@ package gologger
import (
"os"
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
"sync"
"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 {
formatter LogFormatter
filePath string
lchan chan LogEvent
file *os.File
stopChan chan struct{}
mu sync.Mutex
// 新增滚动相关字段
EnableRolling bool
MaxSize int64 // 文件最大大小(字节)
MaxAge int64 // 文件最大时间(秒)
MaxCount int // 最大文件数量
currentFileSize int64 // 当前文件大小
createdAt int64 // 文件创建时间戳
filePath string
lchan chan LogEvent
file *os.File
stopChan chan struct{}
}
// Close implements LoggerAppender.
@ -59,193 +32,36 @@ func (f *FileAppender) start() {
os.MkdirAll(dirName, 0755)
}
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() {
defer f.file.Close()
for {
select {
case <-f.stopChan:
f.mu.Lock()
if f.file != nil {
f.file.Close()
}
f.mu.Unlock()
return
case logEvent := <-f.lchan:
f.mu.Lock()
// 检查日志滚动
if f.EnableRolling {
if f.checkAndRoll(logEvent) {
f.mu.Unlock()
continue
}
}
logMsg := f.formatter(logEvent)
n, err := f.file.WriteString(logMsg)
if err == nil {
f.currentFileSize += int64(n)
}
f.mu.Unlock()
logMsg := format(logEvent)
f.file.WriteString(logMsg)
}
}
}()
}
// 新增日志滚动方法,返回是否进行了滚动
func (f *FileAppender) checkAndRoll(logEvent LogEvent) bool {
// 按大小滚动
if f.MaxSize > 0 && f.currentFileSize >= f.MaxSize {
f.rollFile(logEvent)
return true
}
// 按时间滚动
if f.MaxAge > 0 && time.Now().Unix()-f.createdAt >= f.MaxAge {
f.rollFile(logEvent)
return true
}
return false
}
// 日志文件滚动
func (f *FileAppender) rollFile(logEvent LogEvent) {
// 关闭当前文件
if f.file != nil {
f.file.Close()
}
// 重命名旧文件
timestamp := time.Now().Format("20060102150405")
newPath := f.filePath + "." + timestamp
if err := os.Rename(f.filePath, newPath); err != nil {
// 重命名失败,直接创建新文件
f.file, _ = os.OpenFile(f.filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
return
}
// 创建新文件
var err error
f.file, err = os.OpenFile(f.filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return
}
// 重置状态
f.currentFileSize = 0
f.createdAt = time.Now().Unix()
// 重新写入当前日志
logMsg := f.formatter(logEvent)
if _, err := f.file.WriteString(logMsg); err == nil {
f.currentFileSize += int64(len(logMsg))
}
// 清理超过MaxCount的旧文件
if f.MaxCount > 0 {
logDir := filepath.Dir(newPath)
logFileBase := filepath.Base(f.filePath)
files, _ := filepath.Glob(logDir + "/" + logFileBase + ".*")
if len(files) > f.MaxCount {
sort.Slice(files, func(i, j int) bool {
return files[i] < files[j]
})
for i := 0; i < len(files)-f.MaxCount; i++ {
os.Remove(files[i])
}
}
}
}
func (f *FileAppender) Append(logEvent LogEvent) {
f.lchan <- logEvent
}
func makeFileAppender(appenderConfig LogAppenderConfig) *LoggerAppender {
logfile, ok := appenderConfig.Options["file"]
var logfile interface{}
var ok bool
logfile, ok = appenderConfig.Options["file"]
if !ok {
logfile = "default.log"
}
// 新增滚动配置参数
rollingEnabled := false
if enable, ok := appenderConfig.Options["enableRolling"].(bool); ok {
rollingEnabled = enable
}
maxSize := int64(0)
if size, ok := appenderConfig.Options["maxSize"].(float64); ok {
maxSize = int64(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) {
// 提取数字部分和单位
var numStr strings.Builder
unit := ""
for _, c := range ageStr {
if c >= '0' && c <= '9' {
numStr.WriteRune(c)
} else {
unit = string(c)
}
}
num, _ := strconv.ParseInt(numStr.String(), 10, 64)
switch unit {
case "h":
maxAge = num * 3600 // 小时转秒
default:
maxAge = num * 86400 // 默认按天转秒
}
}
} else if ageInt, ok := appenderConfig.Options["maxAge"].(int64); ok {
maxAge = ageInt
}
maxCount := int(1)
if count, ok := appenderConfig.Options["maxCount"].(float64); ok {
maxCount = int(count)
} else if count, ok := appenderConfig.Options["maxCount"].(int); ok {
maxCount = count
}
var ret LoggerAppender = &FileAppender{
formatter: SelectFormatter(appenderConfig.Formatter),
filePath: logfile.(string),
EnableRolling: rollingEnabled,
MaxSize: maxSize,
MaxAge: maxAge,
MaxCount: maxCount,
filePath: logfile.(string),
}
ret.(*FileAppender).start()

View File

@ -1,226 +0,0 @@
package gologger
import (
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
"time"
)
func TestFileRollingBySize(t *testing.T) {
// 创建临时目录
tmpDir := t.TempDir()
logFile := filepath.Join(tmpDir, "test.log")
config := LogAppenderConfig{
Options: map[string]interface{}{
"file": logFile,
"enableRolling": true,
"maxSize": float64(1), // 1MB触发滚动
},
}
appender := *makeFileAppender(config)
f := appender.(*FileAppender)
defer f.Close()
// 写入小于 MaxSize 的日志,不应触发滚动
smallMsg := LogEvent{
Ts: time.Now(),
Category: "test",
Level: Info,
Data: []interface{}{"small message"},
}
f.Append(smallMsg)
time.Sleep(100 * time.Millisecond)
// 检查文件存在
if _, err := os.Stat(logFile); os.IsNotExist(err) {
t.Fatalf("log file should exist: %v", err)
}
// 写入大量日志,触发大小滚动
// 每次写入约100字节需要约10000次才能超过1MB
largeData := strings.Repeat("x", 100)
for i := 0; i < 10500; i++ {
msg := LogEvent{
Ts: time.Now(),
Category: "test",
Level: Info,
Data: []interface{}{largeData},
}
f.Append(msg)
}
time.Sleep(200 * time.Millisecond)
// 检查是否有滚动文件产生
files, _ := filepath.Glob(logFile + ".*")
if len(files) == 0 {
t.Fatalf("expected rolled file to exist, but none found")
}
t.Logf("Rolled files found: %v", files)
}
func TestFileRollingByMaxCount(t *testing.T) {
tmpDir := t.TempDir()
logFile := filepath.Join(tmpDir, "test.log")
config := LogAppenderConfig{
Options: map[string]interface{}{
"file": logFile,
"enableRolling": true,
"maxSize": float64(1), // 1MB
"maxCount": float64(3), // 最多保留3个旧文件
},
}
appender := *makeFileAppender(config)
f := appender.(*FileAppender)
defer f.Close()
// 多次触发滚动,产生多个旧文件
largeData := strings.Repeat("x", 1024)
for round := 0; round < 5; round++ {
for i := 0; i < 10500; i++ {
msg := LogEvent{
Ts: time.Now(),
Category: "test",
Level: Info,
Data: []interface{}{largeData},
}
f.Append(msg)
}
time.Sleep(100 * time.Millisecond)
}
// 等待清理完成
time.Sleep(300 * time.Millisecond)
// 检查旧文件数量不应超过 maxCount
files, _ := filepath.Glob(logFile + ".*")
if len(files) > 3 {
t.Errorf("expected at most %d rolled files, but got %d: %v", 3, len(files), files)
}
t.Logf("Rolled files count: %d, files: %v", len(files), files)
}
func TestFileRollingMaxCountFromJSON(t *testing.T) {
// 模拟 JSON 解析场景
jsonStr := `{
"enableRolling": true,
"file": "logs/test.log",
"maxSize": "50M",
"maxCount": 10
}`
var options map[string]interface{}
if err := json.Unmarshal([]byte(jsonStr), &options); err != nil {
t.Fatalf("json unmarshal failed: %v", err)
}
// 验证 JSON 解析后的 maxCount 类型
count := options["maxCount"]
t.Logf("maxCount type: %T, value: %v", count, count)
// 测试类型断言
if c, ok := options["maxCount"].(float64); ok {
t.Logf("maxCount as float64: %v -> int: %d", c, int(c))
if int(c) != 10 {
t.Errorf("expected maxCount=10, got %d", int(c))
}
} else if _, ok := options["maxCount"].(int); ok {
t.Log("maxCount is int type")
} else {
t.Errorf("maxCount has unexpected type: %T", count)
}
}
func TestMakeFileAppenderConfig(t *testing.T) {
tmpDir := t.TempDir()
logFile := filepath.Join(tmpDir, "app.log")
tests := []struct {
name string
config LogAppenderConfig
wantRolling bool
wantMaxSize int64
wantMaxCount int
}{
{
name: "string maxSize and maxCount",
config: LogAppenderConfig{
Options: map[string]interface{}{
"file": logFile,
"enableRolling": true,
"maxSize": "10MB",
"maxCount": float64(5),
},
},
wantRolling: true,
wantMaxSize: 10 * 1024 * 1024,
wantMaxCount: 5,
},
{
name: "int maxSize and int maxCount",
config: LogAppenderConfig{
Options: map[string]interface{}{
"file": logFile,
"enableRolling": true,
"maxSize": float64(20),
"maxCount": float64(3),
},
},
wantRolling: true,
wantMaxSize: 20 * 1024 * 1024,
wantMaxCount: 3,
},
{
name: "KB unit",
config: LogAppenderConfig{
Options: map[string]interface{}{
"file": logFile,
"enableRolling": true,
"maxSize": "100KB",
"maxCount": float64(2),
},
},
wantRolling: true,
wantMaxSize: 100 * 1024,
wantMaxCount: 2,
},
{
name: "GB unit",
config: LogAppenderConfig{
Options: map[string]interface{}{
"file": logFile,
"enableRolling": true,
"maxSize": "1GB",
"maxCount": float64(1),
},
},
wantRolling: true,
wantMaxSize: 1 * 1024 * 1024 * 1024,
wantMaxCount: 1,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
appender := *makeFileAppender(tt.config)
f := appender.(*FileAppender)
defer f.Close()
if f.EnableRolling != tt.wantRolling {
t.Errorf("EnableRolling = %v, want %v", f.EnableRolling, tt.wantRolling)
}
if f.MaxSize != tt.wantMaxSize {
t.Errorf("MaxSize = %v, want %v", f.MaxSize, tt.wantMaxSize)
}
if f.MaxCount != tt.wantMaxCount {
t.Errorf("MaxCount = %v, want %v", f.MaxCount, tt.wantMaxCount)
}
})
}
}

View File

@ -1,39 +1,24 @@
// Package gologger provides a simple logging implementation with multiple appenders and formatters.
// It supports console, file, and HTTP logging with customizable formats.
package gologger
import (
"encoding/json"
"fmt"
"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"
// 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 {
data := logEvent.Ts.Format("2006-01-02 15:04:05")
var msg string
if len(logEvent.Data) > 0 {
firstMsg := logEvent.Data[0]
if isFormatString(firstMsg) {
msg = fmt.Sprintf(firstMsg.(string), logEvent.Data[1:]...)
} else {
msg = sprint(logEvent.Data)
}
msg := ""
firstMsg := logEvent.Data[0]
if isFormatString(firstMsg) {
msg = fmt.Sprintf(firstMsg.(string), logEvent.Data[1:]...)
} else {
msg = sprint(logEvent.Data)
}
return fmt.Sprintf(logTemplate, data, logEvent.Category, getLogLevelStr(logEvent.Level), msg)
ret := fmt.Sprintf(logTemplate, data, logEvent.Category, getLogLevelStr(logEvent.Level), msg)
return ret
}
func getLogLevelStr(level int) string {
@ -45,45 +30,24 @@ func getLogLevelStr(level int) string {
return "Unknown"
}
func isFormatString(f any) bool {
func isFormatString(f interface{}) bool {
s, ok := f.(string)
if !ok {
return false
}
// 检查是否包含常见格式化动词
return strings.Contains(s, "%s") || strings.Contains(s, "%d") ||
strings.Contains(s, "%v") || strings.Contains(s, "%f") ||
strings.Contains(s, "%x") || strings.Contains(s, "%t") ||
strings.Contains(s, "%c") || strings.Contains(s, "%b") ||
strings.Contains(s, "%e") || strings.Contains(s, "%g")
// 尝试使用空接口来格式化字符串
m := fmt.Sprintf(s, []interface{}{}...)
return strings.Index(m, "MISSING") != -1
}
func sprint(s []any) string {
var b strings.Builder
func sprint(s []interface{}) string {
str := make([]any, len(s))
for i, v := range s {
if i > 0 {
b.WriteString(" ")
str[i] = fmt.Sprintf(" %v", v)
} else {
str[i] = fmt.Sprintf("%v", v)
}
fmt.Fprintf(&b, "%v", v)
}
return b.String()
}
func jsonFormatter(logEvent LogEvent) string {
d, err := json.Marshal(logEvent)
if err != nil {
return fmt.Sprintf(`{"error":"%v"}`, logEvent.Data)
}
return string(d)
}
func SelectFormatter(formatter string) LogFormatter {
switch strings.ToLower(formatter) {
case "json":
return jsonFormatter
case "text":
return format
default:
return format
}
return fmt.Sprint(str...)
}

View File

@ -46,7 +46,7 @@ func TestFormat(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := format(tt.logEvent); strings.Contains(got, tt.want) {
if got := format(tt.logEvent); strings.Index(got, tt.want) == -1 {
t.Errorf("format() = %v, want %v", got, tt.want)
}
})

2
go.mod
View File

@ -1,3 +1,3 @@
module git.kingecg.top/kingecg/gologger
module git.pyer.club/kingecg/gologger
go 1.19

117
main.go
View File

@ -1,10 +1,7 @@
// Package gologger provides a simple logging implementation with multiple appenders and formatters.
// It supports console, file, and HTTP logging with customizable formats.
package gologger
import (
"strings"
"sync"
"time"
)
@ -28,27 +25,11 @@ var logLevelMap map[string]int = map[string]int{
var loggerMap map[string]*Logger = map[string]*Logger{}
var appenderFactoryMap map[string]func(LogAppenderConfig) *LoggerAppender = map[string]func(LogAppenderConfig) *LoggerAppender{}
var appenders map[string]*LoggerAppender = map[string]*LoggerAppender{}
var mu sync.RWMutex
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"},
},
},
}
var loggerConfig LoggersConfig
type LogAppenderConfig struct {
Type string `json:"type"`
Formatter string `json:"formatter"`
Options map[string]interface{} `json:"options"`
Type string `json:"type"`
Options map[string]interface{} `json:"options"`
}
type LogConfig struct {
Level string `json:"level"`
@ -59,14 +40,6 @@ type LoggersConfig struct {
Appenders map[string]LogAppenderConfig `json:"appenders"`
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 {
category string
level int
@ -74,10 +47,10 @@ type Logger struct {
}
type LogEvent struct {
Category string `json:"category"`
Ts time.Time `json:"ts"`
Level int `json:"level"`
Data []interface{} `json:"data"`
Category string
Ts time.Time
Level int
Data []interface{}
}
type LoggerAppender interface {
@ -86,7 +59,7 @@ type LoggerAppender interface {
Close()
}
var consoleAppender LoggerAppender = *makeConsoleAppender(LogAppenderConfig{})
var consoleAppender LoggerAppender = &ConsoleAppender{}
var defaultLogger = &Logger{
level: Error,
@ -126,24 +99,21 @@ func (l *Logger) Trace(msg ...interface{}) {
l.log(Trace, msg)
}
func GetLogger(name string) *Logger {
mu.RLock()
if logger, ok := loggerMap[name]; ok {
mu.RUnlock()
return logger
} else {
logConfig, ok := loggerConfig.Categories[name]
if ok {
return makeLogger(name, logConfig)
}
if name == "default" {
return defaultLogger
}
l := *GetLogger("default")
l.category = name
loggerMap[name] = &l
return &l
}
mu.RUnlock()
logConfig, ok := loggerConfig.Categories[name]
if !ok {
logConfig = loggerConfig.Categories["default"]
}
l := makeLogger(name, logConfig)
l.category = name
mu.Lock()
loggerMap[name] = l
mu.Unlock()
return l
}
func makeLogger(name string, config LogConfig) *Logger {
@ -151,7 +121,7 @@ func makeLogger(name string, config LogConfig) *Logger {
levelstr := strings.ToLower(config.Level)
logger.level = logLevelMap[levelstr]
if len(config.Appenders) == 0 {
if config.Appenders == nil || len(config.Appenders) == 0 {
logger.appenders = []*LoggerAppender{&consoleAppender}
} else {
logger.appenders = make([]*LoggerAppender, len(config.Appenders))
@ -162,57 +132,22 @@ func makeLogger(name string, config LogConfig) *Logger {
loggerMap[name] = logger
return logger
}
func ReconfigLoggers(config LoggersConfig) {
validateConfig(config)
mu.Lock()
defer mu.Unlock()
func Configure(config LoggersConfig) {
loggerConfig = config
for name, appenderConfig := range loggerConfig.Appenders {
if oldappender, ok := appenders[name]; ok {
(*oldappender).Close()
}
if appenderFactory, ok := appenderFactoryMap[appenderConfig.Type]; ok {
appenderFactory, ok := appenderFactoryMap[appenderConfig.Type]
if ok {
appenders[name] = appenderFactory(appenderConfig)
} else {
appenders[name] = &consoleAppender
}
}
for name, logger := range loggerMap {
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]
}
}
for name, _ := range loggerConfig.Categories {
GetLogger(name)
}
}
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) {
appenderFactoryMap[typeName] = appenderCreatCb
}
func init() {
loggerMap["default"] = defaultLogger
appenders["console"] = &consoleAppender
}

View File

@ -10,30 +10,7 @@ func TestGetLogger(t *testing.T) {
if dl != 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")
if al == dl {

View File

@ -1,7 +1,7 @@
package main
import (
logger "git.kingecg.top/kingecg/gologger"
logger "git.pyer.club/kingecg/gologger"
)
func aqmain() {