159 lines
3.4 KiB
Go
159 lines
3.4 KiB
Go
package logging
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"time"
|
|
)
|
|
|
|
// Logger provides structured logging with ISO 8601 timestamps
|
|
type Logger struct {
|
|
*log.Logger
|
|
level LogLevel
|
|
}
|
|
|
|
// LogLevel represents the logging level
|
|
type LogLevel int
|
|
|
|
const (
|
|
DebugLevel LogLevel = iota
|
|
InfoLevel
|
|
WarnLevel
|
|
ErrorLevel
|
|
)
|
|
|
|
// New creates a new logger with ISO 8601 timestamp format
|
|
func New(level LogLevel, output io.Writer) *Logger {
|
|
if output == nil {
|
|
output = os.Stdout
|
|
}
|
|
|
|
return &Logger{
|
|
Logger: log.New(output, "", 0), // No flags, we'll format ourselves
|
|
level: level,
|
|
}
|
|
}
|
|
|
|
// NewFromConfig creates a logger from configuration
|
|
func NewFromConfig(levelStr string, outputPath string) (*Logger, error) {
|
|
level := parseLevel(levelStr)
|
|
|
|
var output io.Writer
|
|
switch outputPath {
|
|
case "stdout", "":
|
|
output = os.Stdout
|
|
case "stderr":
|
|
output = os.Stderr
|
|
default:
|
|
file, err := os.OpenFile(outputPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
output = file
|
|
}
|
|
|
|
return New(level, output), nil
|
|
}
|
|
|
|
// formatMessage formats a log message with ISO 8601 timestamp
|
|
func (l *Logger) formatMessage(level string, msg string) string {
|
|
timestamp := time.Now().UTC().Format(time.RFC3339)
|
|
return timestamp + " [" + level + "] " + msg
|
|
}
|
|
|
|
// Debug logs a debug message
|
|
func (l *Logger) Debug(msg string) {
|
|
if l.level <= DebugLevel {
|
|
l.Logger.Println(l.formatMessage("DEBUG", msg))
|
|
}
|
|
}
|
|
|
|
// Debugf logs a formatted debug message
|
|
func (l *Logger) Debugf(format string, args ...interface{}) {
|
|
if l.level <= DebugLevel {
|
|
msg := sprintf(format, args...)
|
|
l.Logger.Println(l.formatMessage("DEBUG", msg))
|
|
}
|
|
}
|
|
|
|
// Info logs an info message
|
|
func (l *Logger) Info(msg string) {
|
|
if l.level <= InfoLevel {
|
|
l.Logger.Println(l.formatMessage("INFO", msg))
|
|
}
|
|
}
|
|
|
|
// Infof logs a formatted info message
|
|
func (l *Logger) Infof(format string, args ...interface{}) {
|
|
if l.level <= InfoLevel {
|
|
msg := sprintf(format, args...)
|
|
l.Logger.Println(l.formatMessage("INFO", msg))
|
|
}
|
|
}
|
|
|
|
// Warn logs a warning message
|
|
func (l *Logger) Warn(msg string) {
|
|
if l.level <= WarnLevel {
|
|
l.Logger.Println(l.formatMessage("WARN", msg))
|
|
}
|
|
}
|
|
|
|
// Warnf logs a formatted warning message
|
|
func (l *Logger) Warnf(format string, args ...interface{}) {
|
|
if l.level <= WarnLevel {
|
|
msg := sprintf(format, args...)
|
|
l.Logger.Println(l.formatMessage("WARN", msg))
|
|
}
|
|
}
|
|
|
|
// Error logs an error message
|
|
func (l *Logger) Error(msg string) {
|
|
if l.level <= ErrorLevel {
|
|
l.Logger.Println(l.formatMessage("ERROR", msg))
|
|
}
|
|
}
|
|
|
|
// Errorf logs a formatted error message
|
|
func (l *Logger) Errorf(format string, args ...interface{}) {
|
|
if l.level <= ErrorLevel {
|
|
msg := sprintf(format, args...)
|
|
l.Logger.Println(l.formatMessage("ERROR", msg))
|
|
}
|
|
}
|
|
|
|
// Fatal logs a fatal message and exits
|
|
func (l *Logger) Fatal(msg string) {
|
|
l.Logger.Println(l.formatMessage("FATAL", msg))
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Fatalf logs a formatted fatal message and exits
|
|
func (l *Logger) Fatalf(format string, args ...interface{}) {
|
|
msg := sprintf(format, args...)
|
|
l.Logger.Println(l.formatMessage("FATAL", msg))
|
|
os.Exit(1)
|
|
}
|
|
|
|
// parseLevel parses a log level string
|
|
func parseLevel(levelStr string) LogLevel {
|
|
switch levelStr {
|
|
case "debug":
|
|
return DebugLevel
|
|
case "info":
|
|
return InfoLevel
|
|
case "warn", "warning":
|
|
return WarnLevel
|
|
case "error":
|
|
return ErrorLevel
|
|
default:
|
|
return InfoLevel
|
|
}
|
|
}
|
|
|
|
// sprintf is a helper using fmt
|
|
func sprintf(format string, args ...interface{}) string {
|
|
return fmt.Sprintf(format, args...)
|
|
}
|