From 720fbc392188b4eec3fa5a9e8e28ac8d242fd009 Mon Sep 17 00:00:00 2001 From: Yunkon Kim Date: Fri, 1 Dec 2023 14:44:39 +0900 Subject: [PATCH 1/2] Create logger package to initialize - Include init() only - Support multi-writer, log level, and env. - Add configuration values related to logging to setup.env --- .gitignore | 1 + cmd/cm-beetle/main.go | 13 ++++---- conf/setup.env | 8 +++++ go.mod | 3 +- go.sum | 5 +++ pkg/logger/logger.go | 75 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 pkg/logger/logger.go diff --git a/.gitignore b/.gitignore index c0de788..fe60439 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,7 @@ pkg/rttmap.csv .idea/ .vscode/ +*.log log/ *.history diff --git a/cmd/cm-beetle/main.go b/cmd/cm-beetle/main.go index fcb509f..3ee29f8 100644 --- a/cmd/cm-beetle/main.go +++ b/cmd/cm-beetle/main.go @@ -24,18 +24,16 @@ import ( //_ "github.com/go-sql-driver/mysql" "github.com/fsnotify/fsnotify" _ "github.com/mattn/go-sqlite3" + "github.com/rs/zerolog/log" "github.com/spf13/viper" "github.com/cloud-barista/cm-beetle/pkg/core/common" restServer "github.com/cloud-barista/cm-beetle/pkg/api/rest/server" -) -// init for main -func init() { - // profile := "cloud_conf" - // setConfig(profile) -} + // Black import (_) is for running a package's init() function without using its other contents. + _ "github.com/cloud-barista/cm-beetle/pkg/logger" +) // setConfig get cloud settings from a config file // func setConfig(profile string) { @@ -86,7 +84,8 @@ func init() { // Main Body func main() { - fmt.Println("") + + log.Info().Msg("CM-Beetle server has started successfully.") // giving a default value of "8056" port := flag.String("port", "8056", "port number for the restapiserver to listen to") diff --git a/conf/setup.env b/conf/setup.env index 5e56167..5249780 100644 --- a/conf/setup.env +++ b/conf/setup.env @@ -4,6 +4,14 @@ export CMBEETLE_ROOT=`cd $SCRIPT_DIR && cd .. && pwd` # Use CMBEETLE_ROOT directly if the SCRIPT_DIR does not work # export CMBEETLE_ROOT=$HOME/go/src/github.com/cloud-barista/cm-beetle +# Configuration for logger / logging +# Set log file path (default ./cm-beetle.log) +export CM_BEETLE_LOG_FILE=cm-beetle.log +# Set environment, such as development, production +export CM_BEETLE_ENV=development +# Set log level, such as trace, debug info, warn, error, fatal, and panic +export CM_BEETLE_LOG_LEVEL=debug + # Set system endpoints export CBSTORE_ROOT=$CMBEETLE_ROOT export CBLOG_ROOT=$CMBEETLE_ROOT diff --git a/go.mod b/go.mod index ff22526..1979bc4 100644 --- a/go.mod +++ b/go.mod @@ -54,6 +54,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/rs/zerolog v1.31.0 // indirect github.com/snowzach/rotatefilehook v0.0.0-20220211133110-53752135082d // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect @@ -80,7 +81,7 @@ require ( go.uber.org/zap v1.26.0 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.14.0 // indirect + golang.org/x/sys v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.7.0 // indirect diff --git a/go.sum b/go.sum index 2c21371..725a9cd 100644 --- a/go.sum +++ b/go.sum @@ -363,6 +363,8 @@ github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= +github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= @@ -664,10 +666,13 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go new file mode 100644 index 0000000..c2143a3 --- /dev/null +++ b/pkg/logger/logger.go @@ -0,0 +1,75 @@ +package logger + +import ( + "os" + "time" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) + +func init() { + + // Set the global logger to use JSON format. + zerolog.TimeFieldFormat = time.RFC3339 + + // Get the log file name from the environment variable. + logFile := os.Getenv("CM_BEETLE_LOG_FILE") + if logFile == "" { + // If the environment variable is not set, use the default file name. + logFile = "cm-beetle.log" + } + + file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + if err != nil { + log.Fatal().Err(err).Msg("Failed to open log file") + } + + // Multi-writer setup: logs to both file and console + multi := zerolog.MultiLevelWriter( + file, + zerolog.ConsoleWriter{Out: os.Stdout}, + ) + + // Set the log level + logLevel := os.Getenv("CM_BEETLE_LOG_LEVEL") + switch logLevel { + case "trace": + zerolog.SetGlobalLevel(zerolog.TraceLevel) + case "debug": + zerolog.SetGlobalLevel(zerolog.DebugLevel) + case "info": + zerolog.SetGlobalLevel(zerolog.InfoLevel) + case "warn": + zerolog.SetGlobalLevel(zerolog.WarnLevel) + case "error": + zerolog.SetGlobalLevel(zerolog.ErrorLevel) + case "fatal": + zerolog.SetGlobalLevel(zerolog.FatalLevel) + case "panic": + zerolog.SetGlobalLevel(zerolog.PanicLevel) + default: + zerolog.SetGlobalLevel(zerolog.InfoLevel) // default level + } + + // Check the execution environment from the environment variable + env := os.Getenv("CM_BEETLE_ENV") + + // Configure the log output + if env == "production" { + // Apply multi-writer to the global logger + // Set the global logger to use JSON format. + log.Logger = zerolog.New(file).With().Timestamp().Caller().Logger() + } else { + // Apply file to the global logger + log.Logger = zerolog.New(multi).With().Timestamp().Caller().Logger() + } + + // Log a message + log.Info().Msgf("Logger initialized: level=%s, file=%s, environment=%s", logLevel, logFile, env) + if env == "production" { + log.Info().Msg("Single-write setup: logs to file only") + } else { + log.Info().Msg("Multi-writes setup: logs to both file and console") + } +} From 948bd735b964fd567306d6f6a9ac5a7b8e55f766 Mon Sep 17 00:00:00 2001 From: Yunkon Kim Date: Mon, 4 Dec 2023 11:35:01 +0900 Subject: [PATCH 2/2] Update logger init() and `setup.env` --- Dockerfile | 25 +++++++++--- cmd/cm-beetle/main.go | 42 +++++++------------- conf/setup.env | 26 +++++++------ pkg/api/rest/server/server.go | 13 +++++-- pkg/logger/logger.go | 73 ++++++++++++++++++++++++++++------- 5 files changed, 117 insertions(+), 62 deletions(-) diff --git a/Dockerfile b/Dockerfile index 96fe66f..10110c0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,33 +38,46 @@ COPY --from=builder /go/src/github.com/cloud-barista/cm-beetle/scripts/ /app/scr COPY --from=builder /go/src/github.com/cloud-barista/cm-beetle/cmd/cm-beetle /app/ #RUN /bin/bash -c "source /app/conf/setup.env" +## Logger configuration +# Set log file path (default ./cm-beetle.log) +ENV CM_BEETLE_LOG_PATH cm-beetle.log +ENV CM_BEETLE_LOG_MAX_SIZE 10 +ENV CM_BEETLE_LOG_MAX_BACKUPS 3 +ENV CM_BEETLE_LOG_MAX_AGE 30 +ENV CM_BEETLE_LOG_COMPRESS false +# Set execution environment, such as development or production +ENV CM_BEETLE_APP_ENV production +# Set log level, such as trace, debug info, warn, error, fatal, and panic +ENV CM_BEETLE_LOG_LEVEL info + +## Set system endpoints ENV CMBEETLE_ROOT /app ENV CBSTORE_ROOT /app ENV CBLOG_ROOT /app # ENV SPIDER_CALL_METHOD REST # ENV SPIDER_REST_URL http://cb-spider:1024/spider +## Set internal DB config (SQLlite) ENV DB_URL localhost:3306 ENV DB_DATABASE cm_beetle ENV DB_USER cm_beetle ENV DB_PASSWORD cm_beetle -# API Setting +## Set API access config # ALLOW_ORIGINS (ex: https://cloud-barista.org,xxx.xxx.xxx.xxx or * for all) ENV ALLOW_ORIGINS * -## Set ENABLE_AUTH=true currently for basic auth for all routes (i.e., url or path) +# Set ENABLE_AUTH=true currently for basic auth for all routes (i.e., url or path) ENV ENABLE_AUTH true ENV API_USERNAME default ENV API_PASSWORD default -# Set period for auto control goroutine invocation +## Set period for auto control goroutine invocation ENV AUTOCONTROL_DURATION_MS 10000 -# Set SELF_ENDPOINT, if you want to access Swagger API dashboard from outside. (Ex: export SELF_ENDPOINT=xxx.xxx.xxx.xxx:8056) +## Set SELF_ENDPOINT, to access Swagger API dashboard outside (Ex: export SELF_ENDPOINT=x.x.x.x:8056) ENV SELF_ENDPOINT localhost:8056 -# Environment variables that you don't need to touch - +## Environment variables that you don't need to touch # Swagger UI API document file path ENV API_DOC_PATH /app/pkg/api/rest/docs/swagger.json diff --git a/cmd/cm-beetle/main.go b/cmd/cm-beetle/main.go index 3ee29f8..32147d9 100644 --- a/cmd/cm-beetle/main.go +++ b/cmd/cm-beetle/main.go @@ -16,7 +16,6 @@ package main import ( "flag" - "fmt" "os" "strconv" "sync" @@ -24,7 +23,6 @@ import ( //_ "github.com/go-sql-driver/mysql" "github.com/fsnotify/fsnotify" _ "github.com/mattn/go-sqlite3" - "github.com/rs/zerolog/log" "github.com/spf13/viper" "github.com/cloud-barista/cm-beetle/pkg/core/common" @@ -33,9 +31,10 @@ import ( // Black import (_) is for running a package's init() function without using its other contents. _ "github.com/cloud-barista/cm-beetle/pkg/logger" + "github.com/rs/zerolog/log" ) -// setConfig get cloud settings from a config file +// // setConfig get cloud settings from a config file // func setConfig(profile string) { // viper.AddConfigPath(".") // optionally look for config in the working directory // viper.AddConfigPath("./conf/") // optionally look for config in the working directory/conf/ @@ -85,28 +84,17 @@ import ( func main() { - log.Info().Msg("CM-Beetle server has started successfully.") + log.Info().Msg("starting CM-Beetle server") - // giving a default value of "8056" + // Set the default port number "8056" for the REST API server to listen on port := flag.String("port", "8056", "port number for the restapiserver to listen to") flag.Parse() - // validate arguments from flag - validationFlag := true - // validation: port - // set validationFlag to false if your number is not in [1-65535] range - if portInt, err := strconv.Atoi(*port); err == nil { - if portInt < 1 || portInt > 65535 { - validationFlag = false - } - } else { - validationFlag = false - } - if !validationFlag { - fmt.Printf("%s is not a valid port number.\n", *port) - fmt.Printf("Please retry with a valid port number (ex: -port=[1-65535]).\n") - os.Exit(1) + // Validate port + if portInt, err := strconv.Atoi(*port); err != nil || portInt < 1 || portInt > 65535 { + log.Fatal().Msgf("%s is not a valid port number. Please retry with a valid port number (ex: -port=[1-65535]).", *port) } + log.Debug().Msgf("port number: %s", *port) common.SpiderRestUrl = common.NVL(os.Getenv("SPIDER_REST_URL"), "http://localhost:1024/spider") common.DragonflyRestUrl = common.NVL(os.Getenv("DRAGONFLY_REST_URL"), "http://localhost:9090/dragonfly") @@ -127,25 +115,25 @@ func main() { //masterConfigInfos = confighandler.GetMasterConfigInfos() //Setup database (meta_db/dat/cmbeetle.s3db) - fmt.Println("") - fmt.Println("[Setup SQL Database]") - + log.Info().Msg("setting SQL Database") err := os.MkdirAll("./meta_db/dat/", os.ModePerm) if err != nil { - fmt.Println(err.Error()) + log.Error().Err(err).Msg("error creating directory") } + log.Debug().Msgf("database file path: %s", "./meta_db/dat/cmbeetle.s3db") + // Watch config file changes go func() { viper.WatchConfig() viper.OnConfigChange(func(e fsnotify.Event) { - fmt.Println("Config file changed:", e.Name) + log.Debug().Str("file", e.Name).Msg("config file changed") err := viper.ReadInConfig() if err != nil { // Handle errors reading the config file - panic(fmt.Errorf("fatal error config file: %w", err)) + log.Fatal().Err(err).Msg("fatal error in config file") } err = viper.Unmarshal(&common.RuntimeConf) if err != nil { - panic(err) + log.Panic().Err(err).Msg("error unmarshaling runtime configuration") } }) }() diff --git a/conf/setup.env b/conf/setup.env index 5249780..6f95637 100644 --- a/conf/setup.env +++ b/conf/setup.env @@ -1,18 +1,22 @@ -# Set CMBEETLE_ROOT based on path of setup.env relatively +## Set CMBEETLE_ROOT based on path of setup.env relatively SCRIPT_DIR=`dirname ${BASH_SOURCE[0]-$0}` export CMBEETLE_ROOT=`cd $SCRIPT_DIR && cd .. && pwd` # Use CMBEETLE_ROOT directly if the SCRIPT_DIR does not work # export CMBEETLE_ROOT=$HOME/go/src/github.com/cloud-barista/cm-beetle -# Configuration for logger / logging +## Logger configuration # Set log file path (default ./cm-beetle.log) -export CM_BEETLE_LOG_FILE=cm-beetle.log -# Set environment, such as development, production -export CM_BEETLE_ENV=development +export CM_BEETLE_LOG_PATH=cm-beetle.log +export CM_BEETLE_LOG_MAX_SIZE=10 +export CM_BEETLE_LOG_MAX_BACKUPS=3 +export CM_BEETLE_LOG_MAX_AGE=30 +export CM_BEETLE_LOG_COMPRESS=false +# Set execution environment, such as development or production +export CM_BEETLE_APP_ENV=development # Set log level, such as trace, debug info, warn, error, fatal, and panic export CM_BEETLE_LOG_LEVEL=debug -# Set system endpoints +## Set system endpoints export CBSTORE_ROOT=$CMBEETLE_ROOT export CBLOG_ROOT=$CMBEETLE_ROOT #export SPIDER_CALL_METHOD=REST @@ -24,10 +28,10 @@ export DB_DATABASE=cm_beetle export DB_USER=cm_beetlee export DB_PASSWORD=cm_beetle -# Set API access config -## ALLOW_ORIGINS (ex: https://cloud-barista.org,http://localhost:8080 or * for all) +## Set API access config +# ALLOW_ORIGINS (ex: https://cloud-barista.org,http://localhost:8080 or * for all) export ALLOW_ORIGINS=* -## Set ENABLE_AUTH=true currently for basic auth for all routes (i.e., url or path) +# Set ENABLE_AUTH=true currently for basic auth for all routes (i.e., url or path) export ENABLE_AUTH=true export API_USERNAME=default export API_PASSWORD=default @@ -38,6 +42,6 @@ export AUTOCONTROL_DURATION_MS=10000 ## Set SELF_ENDPOINT, to access Swagger API dashboard outside (Ex: export SELF_ENDPOINT=x.x.x.x:8056) export SELF_ENDPOINT=localhost:8056 -# Environment variables that you don't need to touch -## Swagger UI API document file path +## Environment variables that you don't need to touch +# Swagger UI API document file path export API_DOC_PATH=$CMBEETLE_ROOT/src/api/rest/docs/swagger.json \ No newline at end of file diff --git a/pkg/api/rest/server/server.go b/pkg/api/rest/server/server.go index ff680a8..f9c5942 100644 --- a/pkg/api/rest/server/server.go +++ b/pkg/api/rest/server/server.go @@ -16,7 +16,6 @@ package server import ( "context" - "log" "os/signal" "sync" "syscall" @@ -38,6 +37,10 @@ import ( // echo-swagger middleware _ "github.com/cloud-barista/cm-beetle/pkg/api/rest/docs" echoSwagger "github.com/swaggo/echo-swagger" + + // Black import (_) is for running a package's init() function without using its other contents. + _ "github.com/cloud-barista/cm-beetle/pkg/logger" + "github.com/rs/zerolog/log" ) //var masterConfigInfos confighandler.MASTERCONFIGTYPE @@ -83,6 +86,8 @@ const ( // @securityDefinitions.basic BasicAuth func RunServer(port string) { + log.Info().Msg("Setting CM-Beetle REST API server") + e := echo.New() // Middleware @@ -96,10 +101,10 @@ func RunServer(port string) { allowedOrigins := os.Getenv("ALLOW_ORIGINS") if allowedOrigins == "" { - log.Fatal("ALLOW_ORIGINS env variable for CORS is " + allowedOrigins + + log.Fatal().Msg("allow_ORIGINS env variable for CORS is " + allowedOrigins + ". Please provide a proper value and source setup.env again. EXITING...") - // allowedOrigins = "*" } + e.Use(middleware.CORSWithConfig(middleware.CORSConfig{ AllowOrigins: []string{allowedOrigins}, AllowMethods: []string{http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete}, @@ -215,6 +220,7 @@ func RunServer(port string) { <-gracefulShutdownContext.Done() fmt.Println("\n[Stop] CM-Beetle REST Server") + log.Info().Msg("stopping CM-Beetle REST Server") ctx, cancel := context.WithTimeout(context.TODO(), 3*time.Second) defer cancel() @@ -223,6 +229,7 @@ func RunServer(port string) { } }(&wg) + log.Info().Msg("starting CM-Beetle REST API server") port = fmt.Sprintf(":%s", port) if err := e.Start(port); err != nil && err != http.ErrServerClosed { e.Logger.Panic("shuttig down the server") diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index c2143a3..bd937bf 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -2,10 +2,12 @@ package logger import ( "os" + "strconv" "time" "github.com/rs/zerolog" "github.com/rs/zerolog/log" + "gopkg.in/natefinch/lumberjack.v2" ) func init() { @@ -13,21 +15,49 @@ func init() { // Set the global logger to use JSON format. zerolog.TimeFieldFormat = time.RFC3339 - // Get the log file name from the environment variable. - logFile := os.Getenv("CM_BEETLE_LOG_FILE") - if logFile == "" { - // If the environment variable is not set, use the default file name. - logFile = "cm-beetle.log" + // Get log-related environment variables + // Default: cm-beetle.log + logFilePath := os.Getenv("CM_BEETLE_LOG_PATH") + if logFilePath == "" { + logFilePath = "cm-beetle.log" } - file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + // Default: 10 MB + maxSize, err := strconv.Atoi(os.Getenv("CM_BEETLE_LOG_MAX_SIZE")) if err != nil { - log.Fatal().Err(err).Msg("Failed to open log file") + log.Fatal().Msg("Invalid CM_BEETLE_LOG_MAX_SIZE value") + } + + // Default: 3 backups + maxBackups, err := strconv.Atoi(os.Getenv("CM_BEETLE_LOG_MAX_BACKUPS")) + if err != nil { + log.Fatal().Msg("Invalid CM_BEETLE_LOG_MAX_BACKUPS value") + } + + // Default: 30 days + maxAge, err := strconv.Atoi(os.Getenv("CM_BEETLE_LOG_MAX_AGE")) + if err != nil { + log.Fatal().Msg("Invalid CM_BEETLE_LOG_MAX_AGE value") + } + + // Default: false + compress, err := strconv.ParseBool(os.Getenv("CM_BEETLE_LOG_COMPRESS")) + if err != nil { + log.Fatal().Msg("Invalid CM_BEETLE_LOG_COMPRESS value") + } + + // lumberjack log file setup (lumberjack is used for log rotation) + logFile := &lumberjack.Logger{ + Filename: logFilePath, // log file path + MaxSize: maxSize, // max size in megabytes before log is rotated + MaxBackups: maxBackups, // max number of old log files to keep + MaxAge: maxAge, // max number of days to retain log files + Compress: compress, // compress/logrotate log files } // Multi-writer setup: logs to both file and console multi := zerolog.MultiLevelWriter( - file, + logFile, zerolog.ConsoleWriter{Out: os.Stdout}, ) @@ -49,27 +79,40 @@ func init() { case "panic": zerolog.SetGlobalLevel(zerolog.PanicLevel) default: - zerolog.SetGlobalLevel(zerolog.InfoLevel) // default level + log.Fatal().Msgf("Invalid CM_BEETLE_LOG_LEVEL value: %s", logLevel) } // Check the execution environment from the environment variable - env := os.Getenv("CM_BEETLE_ENV") + env := os.Getenv("CM_BEETLE_APP_ENV") // Configure the log output if env == "production" { // Apply multi-writer to the global logger - // Set the global logger to use JSON format. - log.Logger = zerolog.New(file).With().Timestamp().Caller().Logger() + log.Logger = zerolog.New(logFile).With().Timestamp().Caller().Logger() } else { // Apply file to the global logger log.Logger = zerolog.New(multi).With().Timestamp().Caller().Logger() } // Log a message - log.Info().Msgf("Logger initialized: level=%s, file=%s, environment=%s", logLevel, logFile, env) + log.Info(). + Str("logLevel", logLevel). + Str("logFilePath", logFilePath). + Str("env", env). + Int("maxSize", maxSize). + Int("maxBackups", maxBackups). + Int("maxAge", maxAge). + Bool("compress", compress). + Msg("Logger initialized") + if env == "production" { - log.Info().Msg("Single-write setup: logs to file only") + log.Info(). + Str("logFilePath", logFilePath). + Msg("Single-write setup (logs to file only)") } else { - log.Info().Msg("Multi-writes setup: logs to both file and console") + log.Info(). + Str("logFilePath", logFilePath). + Str("ConsoleWriter", "os.Stdout"). + Msg("Multi-writes setup (logs to both file and console)") } }