- Changed the build process to include a web UI build stage using Node.js. - Updated Go build stage to copy web UI files to the correct location. - Removed the main.go file as it is no longer needed. - Added SQLite database configuration to example config. - Updated dependencies in go.mod and go.sum, including new packages for JWT and SQLite. - Modified .gitignore to include new database and configuration files. Signed-off-by: zhenyus <zhenyus@mathmast.com>
164 lines
2.8 KiB
Go
164 lines
2.8 KiB
Go
package logger
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type Level int
|
|
|
|
const (
|
|
DEBUG Level = iota
|
|
INFO
|
|
WARN
|
|
ERROR
|
|
)
|
|
|
|
var levelStrings = map[Level]string{
|
|
DEBUG: "DEBUG",
|
|
INFO: "INFO",
|
|
WARN: "WARN",
|
|
ERROR: "ERROR",
|
|
}
|
|
|
|
var stringToLevel = map[string]Level{
|
|
"debug": DEBUG,
|
|
"info": INFO,
|
|
"warn": WARN,
|
|
"error": ERROR,
|
|
}
|
|
|
|
type Logger struct {
|
|
logger *log.Logger
|
|
level Level
|
|
format string
|
|
mu sync.RWMutex
|
|
jsonWriter *jsonLogWriter
|
|
}
|
|
|
|
type jsonLogWriter struct {
|
|
out io.Writer
|
|
}
|
|
|
|
type Config struct {
|
|
Level string
|
|
Format string
|
|
File string
|
|
}
|
|
|
|
var defaultLogger *Logger
|
|
|
|
func init() {
|
|
defaultLogger = New(Config{
|
|
Level: "info",
|
|
Format: "text",
|
|
})
|
|
}
|
|
|
|
func New(config Config) *Logger {
|
|
var output io.Writer = os.Stdout
|
|
|
|
if config.File != "" {
|
|
file, err := os.OpenFile(config.File, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
|
if err == nil {
|
|
output = io.MultiWriter(file, os.Stdout)
|
|
}
|
|
}
|
|
|
|
level := stringToLevel[strings.ToLower(config.Level)]
|
|
format := strings.ToLower(config.Format)
|
|
|
|
l := &Logger{
|
|
level: level,
|
|
format: format,
|
|
}
|
|
|
|
if format == "json" {
|
|
l.jsonWriter = &jsonLogWriter{out: output}
|
|
l.logger = log.New(l.jsonWriter, "", 0)
|
|
} else {
|
|
l.logger = log.New(output, "", log.LstdFlags|log.Lshortfile)
|
|
}
|
|
|
|
return l
|
|
}
|
|
|
|
func (w *jsonLogWriter) Write(p []byte) (n int, err error) {
|
|
entry := map[string]interface{}{
|
|
"timestamp": time.Now().Format(time.RFC3339),
|
|
"message": strings.TrimSpace(string(p)),
|
|
}
|
|
|
|
jsonData, err := json.Marshal(entry)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
return w.out.Write(append(jsonData, '\n'))
|
|
}
|
|
|
|
func (l *Logger) log(level Level, format string, v ...interface{}) {
|
|
l.mu.RLock()
|
|
defer l.mu.RUnlock()
|
|
|
|
if level < l.level {
|
|
return
|
|
}
|
|
|
|
msg := fmt.Sprintf(format, v...)
|
|
if l.format == "json" {
|
|
entry := map[string]interface{}{
|
|
"timestamp": time.Now().Format(time.RFC3339),
|
|
"level": levelStrings[level],
|
|
"message": msg,
|
|
}
|
|
jsonData, _ := json.Marshal(entry)
|
|
l.logger.Print(string(jsonData))
|
|
} else {
|
|
l.logger.Printf("[%s] %s", levelStrings[level], msg)
|
|
}
|
|
}
|
|
|
|
func (l *Logger) Debug(format string, v ...interface{}) {
|
|
l.log(DEBUG, format, v...)
|
|
}
|
|
|
|
func (l *Logger) Info(format string, v ...interface{}) {
|
|
l.log(INFO, format, v...)
|
|
}
|
|
|
|
func (l *Logger) Warn(format string, v ...interface{}) {
|
|
l.log(WARN, format, v...)
|
|
}
|
|
|
|
func (l *Logger) Error(format string, v ...interface{}) {
|
|
l.log(ERROR, format, v...)
|
|
}
|
|
|
|
// Global logger functions
|
|
func Debug(format string, v ...interface{}) {
|
|
defaultLogger.Debug(format, v...)
|
|
}
|
|
|
|
func Info(format string, v ...interface{}) {
|
|
defaultLogger.Info(format, v...)
|
|
}
|
|
|
|
func Warn(format string, v ...interface{}) {
|
|
defaultLogger.Warn(format, v...)
|
|
}
|
|
|
|
func Error(format string, v ...interface{}) {
|
|
defaultLogger.Error(format, v...)
|
|
}
|
|
|
|
func Configure(config Config) {
|
|
defaultLogger = New(config)
|
|
}
|