120 lines
3.3 KiB
Go
120 lines
3.3 KiB
Go
package logger
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/config"
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
)
|
|
|
|
// emojiCore wraps a zapcore.Core to add emoji icon field
|
|
type emojiCore struct {
|
|
zapcore.Core
|
|
}
|
|
|
|
func (c *emojiCore) With(fields []zapcore.Field) zapcore.Core {
|
|
return &emojiCore{c.Core.With(fields)}
|
|
}
|
|
|
|
func (c *emojiCore) Check(entry zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
|
|
if c.Enabled(entry.Level) {
|
|
return ce.AddCore(entry, c)
|
|
}
|
|
return ce
|
|
}
|
|
|
|
func (c *emojiCore) Write(entry zapcore.Entry, fields []zapcore.Field) error {
|
|
// Only add emoji icon field for warnings and errors
|
|
// Skip for info and debug to keep output clean
|
|
var emoji string
|
|
var addEmoji bool
|
|
|
|
switch entry.Level {
|
|
case zapcore.WarnLevel:
|
|
emoji = "🟡" // Yellow circle for warnings
|
|
addEmoji = true
|
|
case zapcore.ErrorLevel:
|
|
emoji = "🔴" // Red circle for errors
|
|
addEmoji = true
|
|
case zapcore.DPanicLevel:
|
|
emoji = "🔴" // Red circle for panic
|
|
addEmoji = true
|
|
case zapcore.PanicLevel:
|
|
emoji = "🔴" // Red circle for panic
|
|
addEmoji = true
|
|
case zapcore.FatalLevel:
|
|
emoji = "🔴" // Red circle for fatal
|
|
addEmoji = true
|
|
default:
|
|
// No emoji for debug and info levels
|
|
addEmoji = false
|
|
}
|
|
|
|
// Only prepend emoji field if we're adding one
|
|
if addEmoji {
|
|
fieldsWithEmoji := make([]zapcore.Field, 0, len(fields)+1)
|
|
fieldsWithEmoji = append(fieldsWithEmoji, zap.String("ico", emoji))
|
|
fieldsWithEmoji = append(fieldsWithEmoji, fields...)
|
|
return c.Core.Write(entry, fieldsWithEmoji)
|
|
}
|
|
|
|
// For debug/info, write as-is without emoji
|
|
return c.Core.Write(entry, fields)
|
|
}
|
|
|
|
// ProvideLogger creates a new zap logger based on configuration
|
|
func ProvideLogger(cfg *config.Config) (*zap.Logger, error) {
|
|
var zapConfig zap.Config
|
|
|
|
// Set config based on environment
|
|
if cfg.App.Environment == "production" {
|
|
zapConfig = zap.NewProductionConfig()
|
|
} else {
|
|
zapConfig = zap.NewDevelopmentConfig()
|
|
}
|
|
|
|
// Set log level
|
|
level, err := zapcore.ParseLevel(cfg.Logger.Level)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid log level %s: %w", cfg.Logger.Level, err)
|
|
}
|
|
zapConfig.Level = zap.NewAtomicLevelAt(level)
|
|
|
|
// Set encoding format
|
|
if cfg.Logger.Format == "console" {
|
|
zapConfig.Encoding = "console"
|
|
zapConfig.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
|
|
} else {
|
|
zapConfig.Encoding = "json"
|
|
}
|
|
|
|
// Build logger with environment-specific options
|
|
var loggerOptions []zap.Option
|
|
|
|
// Enable caller information in development for easier debugging
|
|
if cfg.App.Environment != "production" {
|
|
loggerOptions = append(loggerOptions, zap.AddCaller())
|
|
loggerOptions = append(loggerOptions, zap.AddCallerSkip(0))
|
|
}
|
|
|
|
// Add stack traces for error level and above
|
|
loggerOptions = append(loggerOptions, zap.AddStacktrace(zapcore.ErrorLevel))
|
|
|
|
// Wrap core with emoji core to add icon field
|
|
loggerOptions = append(loggerOptions, zap.WrapCore(func(core zapcore.Core) zapcore.Core {
|
|
return &emojiCore{core}
|
|
}))
|
|
|
|
logger, err := zapConfig.Build(loggerOptions...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to build logger: %w", err)
|
|
}
|
|
|
|
logger.Info("✓ Logger initialized",
|
|
zap.String("level", cfg.Logger.Level),
|
|
zap.String("format", cfg.Logger.Format),
|
|
zap.String("environment", cfg.App.Environment))
|
|
|
|
return logger, nil
|
|
}
|