From 97ba3d32154df596c5744c17ffd454fa4e21d783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=B9=BF?= Date: Tue, 28 Nov 2023 18:29:30 +0800 Subject: [PATCH] add file appender --- .vscode/launch.json | 3 +- console.go | 22 ++++++--- file.go | 55 ++++++++++++++++++++++ main.go | 108 +++++++++++++++++++++++++++++++++++--------- test/main.go | 43 ++++++++++++++++++ 5 files changed, 202 insertions(+), 29 deletions(-) create mode 100644 file.go create mode 100644 test/main.go diff --git a/.vscode/launch.json b/.vscode/launch.json index 90dc044..2c86451 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,8 @@ "type": "go", "request": "launch", "mode": "auto", - "program": "${fileDirname}" + "program": "${fileDirname}", + "cwd": "${workspaceFolder}", } ] } \ No newline at end of file diff --git a/console.go b/console.go index f8e53a3..f3b7ca6 100644 --- a/console.go +++ b/console.go @@ -6,14 +6,15 @@ import ( ) const ( - ErrorTemplate = "\033[1;31;40m%s\033[0m\n" - WarnTemplate = "\033[1;33;40m%s\033[0m\n" - InfoTemplate = "\033[1;32;40m%s\033[0m\n" - DebugTemplate = "\033[1;34;40m%s\033[0m\n" - TraceTemplate = "\033[1;35;40m%s\033[0m\n" + ErrorTemplate = "\033[1;31m%s\033[0m\n" + WarnTemplate = "\033[1;33m%s\033[0m\n" + InfoTemplate = "\033[1;32m%s\033[0m\n" + DebugTemplate = "\033[1;34m%s\033[0m\n" + TraceTemplate = "\033[1;35m%s\033[0m\n" ) -type ConsoleAppender struct{} +type ConsoleAppender struct { +} func (c *ConsoleAppender) GetName() string { return "console" @@ -28,6 +29,8 @@ func (c *ConsoleAppender) Append(logEvent LogEvent) { dmsg := fmt.Sprint(logEvent.Data) dmsg = strings.TrimLeft(dmsg, "[") dmsg = strings.TrimRight(dmsg, "]") + data = append(data, "["+logEvent.Category+"] ") + data = append(data, dmsg) logMsg := fmt.Sprint(data...) switch logEvent.Level { @@ -43,3 +46,10 @@ func (c *ConsoleAppender) Append(logEvent LogEvent) { fmt.Printf(TraceTemplate, logMsg) } } +func makeConsoleAppender(appenderConfig LogAppenderConfig) LoggerAppender { + var appender LoggerAppender = &ConsoleAppender{} + return appender +} +func init() { + RegistAppender("console", makeConsoleAppender) +} diff --git a/file.go b/file.go new file mode 100644 index 0000000..babb370 --- /dev/null +++ b/file.go @@ -0,0 +1,55 @@ +package gologger + +import ( + "fmt" + "os" + "path/filepath" +) + +type FileAppender struct { + filePath string + file *os.File +} + +func (f *FileAppender) GetName() string { + return "FileAppender:" + f.filePath +} + +func (f *FileAppender) Append(logEvent LogEvent) { + if f.file == nil || int(f.file.Fd()) == -1 { + dirName := filepath.Dir(f.filePath) + _, err := os.Stat(dirName) + if err != nil && os.IsNotExist(err) { + os.MkdirAll(dirName, 0755) + } + f.file, _ = os.OpenFile(f.filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + } + + data := []interface{}{ + logEvent.Ts.Format("2006-01-02 15:04:05"), + " ", + } + data = append(data, "["+logEvent.Category+"] ") + dmsg := fmt.Sprint(logEvent.Data...) + data = append(data, dmsg) + logMsg := fmt.Sprint(data...) + f.file.WriteString(logMsg + "\n") + +} + +func makeFileAppender(appenderConfig LogAppenderConfig) LoggerAppender { + var logfile interface{} + var ok bool + logfile, ok = appenderConfig.Options["file"] + if !ok { + logfile = "default.log" + } + var ret LoggerAppender = &FileAppender{ + filePath: logfile.(string), + } + return ret +} + +func init() { + RegistAppender("file", makeFileAppender) +} diff --git a/main.go b/main.go index 2b0247e..c06b91f 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package gologger import ( + "strings" "time" ) @@ -13,22 +14,43 @@ const ( Trace ) +var logLevelMap map[string]int = map[string]int{ + "off": NoLog, + "error": Error, + "warn": Warn, + "info": Info, + "debug": Debug, + "trace": Trace, +} 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 loggerConfig LoggersConfig +type LogAppenderConfig struct { + Type string `json:"type"` + Options map[string]interface{} `json:"options"` +} type LogConfig struct { - Name string - Level int - Appender LoggerAppender + Level string `json:"level"` + Appenders []string `json:"appenders"` +} + +type LoggersConfig struct { + Appenders map[string]LogAppenderConfig `json:"appenders"` + Categories map[string]LogConfig `json:"categories"` } type Logger struct { - LogConfig + category string + level int + appenders []LoggerAppender } type LogEvent struct { - Ts time.Time - Level int - Data []interface{} - ELogger *Logger + Category string + Ts time.Time + Level int + Data []interface{} } type LoggerAppender interface { @@ -37,17 +59,21 @@ type LoggerAppender interface { } var consoleAppender LoggerAppender = &ConsoleAppender{} -var defaultLogger = &LogConfig{ - Level: Error, - Appender: consoleAppender, +var defaultLogger = &Logger{ + + level: Error, + appenders: []LoggerAppender{consoleAppender}, } func (l *Logger) log(Level int, msg []interface{}) { - if Level <= l.Level { + if Level <= l.level { now := time.Now() - logEvent := LogEvent{now, Level, msg, l} - l.Appender.Append(logEvent) + logEvent := LogEvent{l.category, now, Level, msg} + for _, appender := range l.appenders { + appender.Append(logEvent) + } + // l.Appender.Append(logEvent) // fmt.Println(now.Format("2006-01-02 15:04:05"), " ", l.Name, ": ", msg) } } @@ -71,16 +97,54 @@ func (l *Logger) Debug(msg ...interface{}) { func (l *Logger) Trace(msg ...interface{}) { l.log(Trace, msg) } -func GetLogger(logConfig LogConfig) Logger { - if logger, ok := loggerMap[logConfig.Name]; ok { +func GetLogger(name string) Logger { + if logger, ok := loggerMap[name]; ok { return logger } else { - logger := &Logger{logConfig} - if logger.Appender == nil { - logger.Appender = defaultLogger.Appender + logConfig, ok := loggerConfig.Categories[name] + if ok { + return makeLogger(name, logConfig) } - loggerMap[logConfig.Name] = *logger - return *logger + if name == "default" { + return *defaultLogger + } + ret := GetLogger("default") + ret.category = name + return ret } - +} + +func makeLogger(name string, config LogConfig) Logger { + logger := &Logger{category: name} + levelstr := strings.ToLower(config.Level) + logger.level = logLevelMap[levelstr] + if config.Appenders == nil || len(config.Appenders) == 0 { + logger.appenders = []LoggerAppender{consoleAppender} + } else { + logger.appenders = make([]LoggerAppender, len(config.Appenders)) + for i, appenderName := range config.Appenders { + logger.appenders[i] = appenders[appenderName] + } + } + loggerMap[name] = *logger + return *logger +} +func Configure(config LoggersConfig) { + loggerConfig = config + for name, appenderConfig := range loggerConfig.Appenders { + appenderFactory, ok := appenderFactoryMap[appenderConfig.Type] + if ok { + appenders[name] = appenderFactory(appenderConfig) + } else { + appenders[name] = &ConsoleAppender{} + } + } + for name, _ := range loggerConfig.Categories { + GetLogger(name) + } +} + +func RegistAppender(typeName string, appenderCreatCb func(LogAppenderConfig) LoggerAppender) { + + appenderFactoryMap[typeName] = appenderCreatCb } diff --git a/test/main.go b/test/main.go new file mode 100644 index 0000000..7a80aa5 --- /dev/null +++ b/test/main.go @@ -0,0 +1,43 @@ +package main + +import ( + logger "git.pyer.club/kingecg/gologger" +) + +func main() { + logger.Configure(logger.LoggersConfig{ + Categories: map[string]logger.LogConfig{ + "default": { + Level: "debug", + Appenders: []string{ + "console", + }, + }, + "fat": { + Level: "debug", + Appenders: []string{ + "console", + "file", + }, + }, + }, + Appenders: map[string]logger.LogAppenderConfig{ + "console": { + Type: "console", + }, + "file": { + Type: "file", + Options: map[string]interface{}{ + "file": "./log/fat.log", + }, + }, + }, + }) + defaultLogger := logger.GetLogger("default") + defaultLogger.Debug("debug") + fatLogger := logger.GetLogger("fat") + fatLogger.Debug("debug") + defaultLogger.Debug("debug again") + fatLogger.Debug("debug again") + fatLogger.Error("This is error") +}