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") }