209 lines
5.0 KiB
Go
209 lines
5.0 KiB
Go
package logger
|
|
|
|
import (
|
|
"io"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/rs/zerolog"
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
const (
|
|
LevelDebug = "debug"
|
|
LevelInfo = "info"
|
|
LevelWarn = "warn"
|
|
LevelError = "error"
|
|
)
|
|
|
|
// Init initializes the global logger with environment-specific settings.
|
|
// Call this once at application startup.
|
|
//
|
|
// Environment determines output format:
|
|
// - development: Pretty console output with colors
|
|
// - staging/production: JSON output for log aggregation
|
|
//
|
|
// Example:
|
|
//
|
|
// logger.Init("development")
|
|
// log.Info().Msg("Application started")
|
|
func Init(enviroment string) {
|
|
|
|
// Configuring the time format for loggin
|
|
// Unix style timestamp in production for efficiency
|
|
// Humar-readable in development
|
|
if enviroment == "production" {
|
|
// This is the unixtimestamp format used in production for efficiency : 1732632645
|
|
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
|
|
} else {
|
|
zerolog.TimeFieldFormat = time.RFC3339
|
|
// This is format for human readable format : 2025-11-26T10:30:45-05:00
|
|
}
|
|
|
|
var output io.Writer = os.Stdout
|
|
|
|
if enviroment == "development" {
|
|
output = zerolog.ConsoleWriter{
|
|
Out: os.Stdout,
|
|
TimeFormat: time.RFC3339, // 2025-11-26T10:30:45-05:00
|
|
NoColor: false, // Enabling Colours
|
|
}
|
|
}
|
|
|
|
// Production uses default JSON output to stdout
|
|
|
|
// Set global logger
|
|
// Caller() : this caused adtional overhead as runtime.Caller() is called, which is worth
|
|
// for debugging value, should disable in production
|
|
log.Logger = zerolog.New(output).
|
|
With().
|
|
Timestamp().
|
|
Caller(). // This line is to add file and line number information into the log
|
|
Logger()
|
|
|
|
// set global log level
|
|
// Debug (most verbose)
|
|
// ↓
|
|
// Info
|
|
// ↓
|
|
// Warn
|
|
// ↓
|
|
// Error
|
|
// ↓
|
|
// Fatal (least verbose)
|
|
switch enviroment {
|
|
case "production":
|
|
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
|
case "UAT":
|
|
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
|
case "staging":
|
|
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
|
case "test":
|
|
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
|
case "development":
|
|
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
|
}
|
|
|
|
// Log initialization
|
|
log.Info().
|
|
Str("environment", enviroment).
|
|
Str("log_level", zerolog.GlobalLevel().String()).
|
|
Msg("logger initialized")
|
|
}
|
|
|
|
func InitWithLevel(environment, level string) {
|
|
Init(environment)
|
|
|
|
switch level {
|
|
case LevelDebug:
|
|
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
|
case LevelInfo:
|
|
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
|
case LevelWarn:
|
|
zerolog.SetGlobalLevel(zerolog.WarnLevel)
|
|
case LevelError:
|
|
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
|
|
default:
|
|
log.Warn().
|
|
Str("provided_level", level).
|
|
Str("using_level", zerolog.GlobalLevel().String()).
|
|
Msg("Invalid log level, using default")
|
|
}
|
|
|
|
log.Info().
|
|
Str("environment", environment).
|
|
Str("log_level", zerolog.GlobalLevel().String()).
|
|
Msg("Logger initialized with custom level")
|
|
}
|
|
|
|
// GetLogger returns the global logger instance.
|
|
// Use this to get a logger with additional context.
|
|
//
|
|
// Example :
|
|
//
|
|
// logger := logger.GetLogger().
|
|
// With().
|
|
// Str("module","auth").
|
|
// Logger()
|
|
// logger.Info().Msg("Auth module started")
|
|
func GetLogger() *zerolog.Logger {
|
|
return &log.Logger
|
|
}
|
|
|
|
// WithContext returns a logger with additional context fields.
|
|
// Useful for adding request-specific context.
|
|
//
|
|
// Example:
|
|
//
|
|
// contextLogger := logger.WithContext(map[string]interface{}{
|
|
// "request_id": "abc-123",
|
|
// "user_id": "user-456",
|
|
// })
|
|
// contextLogger.Info().Msg("Processing request")
|
|
func WithContext(fields map[string]interface{}) *zerolog.Logger {
|
|
logger := log.Logger
|
|
for key, value := range fields {
|
|
logger = logger.With().Interface(key, value).Logger()
|
|
}
|
|
|
|
return &logger
|
|
}
|
|
|
|
// Example Usage log functions (for familiarizing its usage)
|
|
|
|
// LogDebug logs debug information (these are verbose, development only)
|
|
func ExampleDebug() {
|
|
log.Debug().
|
|
Str("function", "ExampleDebug").
|
|
Int("iteration", 1).
|
|
Msg("Debug information")
|
|
}
|
|
|
|
func ExampleInfo() {
|
|
log.Info().
|
|
Str("user_id", "123").
|
|
Str("reason", "invalid_token").
|
|
Msg("User logged in successfully")
|
|
}
|
|
|
|
func ExampleError() {
|
|
log.Error().
|
|
Err(nil). // we add the actual error here
|
|
Str("user_id", "123").
|
|
Str("operation", "database_query").
|
|
Msg("Failed to fetch user data")
|
|
}
|
|
|
|
// Log Fatal logs fatal erros and exits the application
|
|
// user sparingly - only for unrecoverable errors
|
|
func ExmapleFatal() {
|
|
// log.Fatal().
|
|
// Err(err).
|
|
// Msg("Cannot connect to database")
|
|
// -- Application exits after this
|
|
}
|
|
|
|
// Log with fields demonstrated logging mutliple fields
|
|
func ExampleWithFields() {
|
|
log.Info().
|
|
Str("user_id", "123").
|
|
Str("email", "user@example.com").
|
|
Int("login_attemtps", 3).
|
|
Bool("success", true).
|
|
Dur("duration", 150*time.Millisecond).
|
|
Msg("login completed")
|
|
}
|
|
|
|
// Log with SubLogger demonstrates creating sub-loggers
|
|
func ExampleSubLogger() {
|
|
|
|
// create a sub-logger for a specific module
|
|
authLogger := log.With().
|
|
Str("module", "auth").
|
|
Str("version", "v1").
|
|
Logger()
|
|
|
|
authLogger.Info().Msg("Auth module initialized")
|
|
authLogger.Debug().Msg("Loading auth configuration")
|
|
}
|