Files
cloudnest/internal/pkg/logger/logger.go
T

132 lines
2.4 KiB
Go

package logger
import (
"encoding/json"
"fmt"
"io"
"os"
"sync"
"sync/atomic"
"time"
)
// Level represents log level.
type Level int
const (
LevelDebug Level = iota
LevelInfo
LevelWarn
LevelError
)
func (l Level) String() string {
switch l {
case LevelDebug:
return "DEBUG"
case LevelInfo:
return "INFO"
case LevelWarn:
return "WARN"
case LevelError:
return "ERROR"
default:
return "INFO"
}
}
// Logger is a simple JSON logger compatible with Go 1.20.
type Logger struct {
level Level
writer io.Writer
mu sync.Mutex
}
// Default is the global default logger.
var Default atomic.Value
func init() {
Default.Store(&Logger{level: LevelInfo, writer: os.Stderr})
}
func getDefault() *Logger {
if l, ok := Default.Load().(*Logger); ok && l != nil {
return l
}
return &Logger{level: LevelInfo, writer: os.Stderr}
}
// Init initializes the logger with the specified log level.
func Init(level string) {
InitWithWriter(level, os.Stdout)
}
// InitWithWriter initializes the logger with the specified log level and writer.
func InitWithWriter(level string, writer io.Writer) {
var lvl Level
switch level {
case "debug":
lvl = LevelDebug
case "info":
lvl = LevelInfo
case "warn":
lvl = LevelWarn
case "error":
lvl = LevelError
default:
lvl = LevelInfo
}
if writer == nil {
writer = os.Stdout
}
Default.Store(&Logger{level: lvl, writer: writer})
}
func (l *Logger) log(level Level, msg string, args ...any) {
if level < l.level {
return
}
record := map[string]any{
"time": time.Now().Format(time.RFC3339Nano),
"level": level.String(),
"msg": msg,
}
for i := 0; i < len(args)-1; i += 2 {
key, ok := args[i].(string)
if !ok {
continue
}
record[key] = args[i+1]
}
l.mu.Lock()
defer l.mu.Unlock()
data, _ := json.Marshal(record)
fmt.Fprintln(l.writer, string(data))
}
// Debug logs a message at Debug level.
func Debug(msg string, args ...any) {
getDefault().log(LevelDebug, msg, args...)
}
// Info logs a message at Info level.
func Info(msg string, args ...any) {
getDefault().log(LevelInfo, msg, args...)
}
// Warn logs a message at Warn level.
func Warn(msg string, args ...any) {
getDefault().log(LevelWarn, msg, args...)
}
// Error logs a message at Error level.
func Error(msg string, args ...any) {
getDefault().log(LevelError, msg, args...)
}
// Fatal logs a message at Error level and exits.
func Fatal(msg string, args ...any) {
getDefault().log(LevelError, msg, args...)
os.Exit(1)
}