🐛 fix: emit all config-loading logs in correct JSON format from the start #16
@@ -118,6 +118,34 @@ type SamplerConfig struct {
|
|||||||
Ratio float64 `mapstructure:"ratio"`
|
Ratio float64 `mapstructure:"ratio"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// peekJSONLogging determines whether JSON logging should be used before the full
|
||||||
|
// config is loaded, solving the chicken-and-egg problem where the logger format
|
||||||
|
// must be known before any log is emitted, yet the format is stored in the config.
|
||||||
|
//
|
||||||
|
// Resolution order (mirrors Viper's own priority):
|
||||||
|
// 1. DLC_LOGGING_JSON env var — checked directly via os.Getenv (zero overhead)
|
||||||
|
// 2. logging.json key in the config file — read with a minimal throwaway Viper
|
||||||
|
// instance so we don't parse the whole config twice unnecessarily
|
||||||
|
func peekJSONLogging() bool {
|
||||||
|
// 1. Env var takes highest priority — check it first
|
||||||
|
if env := os.Getenv("DLC_LOGGING_JSON"); env != "" {
|
||||||
|
return strings.EqualFold(env, "true") || env == "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Try to read logging.json from the config file
|
||||||
|
preV := viper.New()
|
||||||
|
preV.SetDefault("logging.json", false)
|
||||||
|
if configFile := os.Getenv("DLC_CONFIG_FILE"); configFile != "" {
|
||||||
|
preV.SetConfigFile(configFile)
|
||||||
|
} else {
|
||||||
|
preV.SetConfigName("config")
|
||||||
|
preV.SetConfigType("yaml")
|
||||||
|
preV.AddConfigPath(".")
|
||||||
|
}
|
||||||
|
_ = preV.ReadInConfig() // ignore errors — defaults apply on failure
|
||||||
|
return preV.GetBool("logging.json")
|
||||||
|
}
|
||||||
|
|
||||||
// LoadConfig loads configuration from file, environment variables, and defaults
|
// LoadConfig loads configuration from file, environment variables, and defaults
|
||||||
// Configuration priority: file > environment variables > defaults
|
// Configuration priority: file > environment variables > defaults
|
||||||
// To specify a custom config file path, set DLC_CONFIG_FILE environment variable
|
// To specify a custom config file path, set DLC_CONFIG_FILE environment variable
|
||||||
@@ -129,9 +157,17 @@ func LoadConfig() (*Config, error) {
|
|||||||
|
|
||||||
v := viper.New()
|
v := viper.New()
|
||||||
|
|
||||||
// Set up initial console logging for config loading messages
|
// Configure the logger format before emitting any log output.
|
||||||
consoleWriter := zerolog.ConsoleWriter{Out: os.Stderr}
|
// peekJSONLogging reads the JSON setting early (env var + config file pre-read)
|
||||||
log.Logger = log.Output(consoleWriter)
|
// so that every log line — including those produced during config loading — is
|
||||||
|
// already in the correct format.
|
||||||
|
jsonLogging := peekJSONLogging()
|
||||||
|
if jsonLogging {
|
||||||
|
log.Logger = log.Output(os.Stderr)
|
||||||
|
} else {
|
||||||
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||||
|
}
|
||||||
|
log.Info().Bool("json", jsonLogging).Msg("Logging configured")
|
||||||
|
|
||||||
// Set default values
|
// Set default values
|
||||||
v.SetDefault("server.host", "0.0.0.0")
|
v.SetDefault("server.host", "0.0.0.0")
|
||||||
@@ -227,15 +263,9 @@ func LoadConfig() (*Config, error) {
|
|||||||
return nil, fmt.Errorf("config unmarshal error: %w", err)
|
return nil, fmt.Errorf("config unmarshal error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure log output format (JSON or console) first
|
// Setup logging based on configuration (level, output file, time format).
|
||||||
if config.Logging.JSON {
|
// The JSON/console format was already applied at the top of LoadConfig via
|
||||||
log.Logger = log.Output(os.Stderr)
|
// peekJSONLogging, so SetupLogging only needs to handle the remaining knobs.
|
||||||
} else {
|
|
||||||
consoleWriter := zerolog.ConsoleWriter{Out: os.Stderr}
|
|
||||||
log.Logger = log.Output(consoleWriter)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup logging based on configuration
|
|
||||||
config.SetupLogging()
|
config.SetupLogging()
|
||||||
|
|
||||||
log.Info().
|
log.Info().
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
# This script starts the server in the background and provides control functions
|
# This script starts the server in the background and provides control functions
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
PROJECT_DIR="/Users/gabrielradureau/Work/Vibe/dance-lessons-coach"
|
SCRIPTS_DIR=$(dirname "$(realpath "${BASH_SOURCE[0]}")")
|
||||||
|
PROJECT_DIR=$(dirname "$SCRIPTS_DIR")
|
||||||
SERVER_CMD="go run ./cmd/server"
|
SERVER_CMD="go run ./cmd/server"
|
||||||
LOG_FILE="server.log"
|
LOG_FILE="server.log"
|
||||||
PID_FILE="server.pid"
|
PID_FILE="server.pid"
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
PROJECT_DIR="/Users/gabrielradureau/Work/Vibe/dance-lessons-coach"
|
SCRIPTS_DIR=$(dirname "$(realpath "${BASH_SOURCE[0]}")")
|
||||||
|
PROJECT_DIR=$(dirname "$SCRIPTS_DIR")
|
||||||
SERVER_CMD="./scripts/start-server.sh"
|
SERVER_CMD="./scripts/start-server.sh"
|
||||||
LOG_FILE="server.log"
|
LOG_FILE="server.log"
|
||||||
PID_FILE="server.pid"
|
PID_FILE="server.pid"
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ echo -e "\033[1;34m=== dance-lessons-coach OpenTelemetry Test ===\033[0m"
|
|||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
PROJECT_DIR="/Users/gabrielradureau/Work/Vibe/dance-lessons-coach"
|
SCRIPTS_DIR=$(dirname "$(realpath "${BASH_SOURCE[0]}")")
|
||||||
|
PROJECT_DIR=$(dirname "$SCRIPTS_DIR")
|
||||||
SERVER_CMD="./scripts/start-server.sh"
|
SERVER_CMD="./scripts/start-server.sh"
|
||||||
LOG_FILE="server.log"
|
LOG_FILE="server.log"
|
||||||
PID_FILE="server.pid"
|
PID_FILE="server.pid"
|
||||||
|
|||||||
Reference in New Issue
Block a user