From 00e796c6080d575fa6cbb98fba2188aa6e403fef Mon Sep 17 00:00:00 2001 From: Gabriel Radureau Date: Sat, 4 Apr 2026 13:24:33 +0200 Subject: [PATCH] Enhance build system and logging configuration - Add scripts/build.sh to compile binaries into bin/ directory - Move all zerolog setup logic from cmd/server/main.go to pkg/config - Add log level configuration support (trace, debug, info, warn, error, fatal, panic) - Simplify cmd/server/main.go from 57 to 27 lines (53% reduction) - Update .gitignore to use bin/ directory instead of individual files - Document build process and bin directory in AGENTS.md - Maintain backward compatibility with all existing functionality --- .gitignore | 3 +-- AGENTS.md | 29 +++++++++++++++++++-- cmd/server/main.go | 32 +---------------------- config.example.yaml | 5 ++++ pkg/config/config.go | 60 +++++++++++++++++++++++++++++++++++++++++++- scripts/build.sh | 26 +++++++++++++++++++ 6 files changed, 119 insertions(+), 36 deletions(-) create mode 100755 scripts/build.sh diff --git a/.gitignore b/.gitignore index 4344009..87af0e9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,7 @@ *.exe *.test *.out -server -greet +bin/ # Dependency directories vendor/ diff --git a/AGENTS.md b/AGENTS.md index d129493..7f33d5b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -355,12 +355,37 @@ go test ./... go test ./pkg/greet/ ``` -### 5. Make Changes +### 5. Build Binaries + +The project uses a build script to compile binaries into the `bin/` directory: + +```bash +# Build both server and greet binaries +./scripts/build.sh + +# This creates: +# - ./bin/server - The web server binary +# - ./bin/greet - The CLI greeting tool +``` + +**Binary Usage:** +```bash +# Run the server +./bin/server + +# Use the greet CLI +./bin/greet # Output: Hello world! +./bin/greet John # Output: Hello John! +``` + +**The `bin/` directory is gitignored** to prevent binary files from being committed to the repository. + +### 6. Make Changes - Edit source files in `pkg/` or `cmd/` - Follow existing patterns and interfaces - Add tests for new functionality -### 6. Stop and Restart +### 7. Stop and Restart ```bash ./scripts/start-server.sh restart ``` diff --git a/cmd/server/main.go b/cmd/server/main.go index d0462d2..3196aba 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -2,49 +2,19 @@ package main import ( "context" - "os" "DanceLessonsCoach/pkg/config" "DanceLessonsCoach/pkg/server" - "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) func main() { - // Initialize Zerolog with default console format first - zerolog.SetGlobalLevel(zerolog.TraceLevel) - zerolog.TimeFieldFormat = zerolog.TimeFormatUnix - consoleWriter := zerolog.ConsoleWriter{Out: os.Stderr} - - // Check if JSON logging is requested via environment variable - // This allows JSON logging even during config loading - jsonLogging := os.Getenv("DLC_LOGGING_JSON") == "true" - - if jsonLogging { - // JSON output for structured logging - log.Logger = log.Output(os.Stderr) - } else { - // Console output for initial logging - log.Logger = log.Output(consoleWriter) - } - - // Load configuration + // Load configuration (this will also setup logging) cfg, err := config.LoadConfig() if err != nil { log.Fatal().Err(err).Msg("Failed to load configuration") } - // Reconfigure logging based on loaded configuration (overrides env var) - if cfg.Logging.JSON { - // JSON output for structured logging - log.Logger = log.Output(os.Stderr) - } else { - // Keep console output - log.Logger = log.Output(consoleWriter) - } - - log.Info().Bool("json_logging", cfg.Logging.JSON).Msg("Logging configured") - // Create readiness context to control readiness state readyCtx, readyCancel := context.WithCancel(context.Background()) defer readyCancel() diff --git a/config.example.yaml b/config.example.yaml index 3fa2286..f7c83f3 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -21,6 +21,10 @@ logging: # Enable JSON output for structured logging (default: false) # When true, logs are output in JSON format instead of console format json: false + + # Log level (default: "trace") + # Options: "trace", "debug", "info", "warn", "error", "fatal", "panic" + level: trace # Telemetry configuration (OpenTelemetry) telemetry: @@ -53,6 +57,7 @@ telemetry: # DLC_SERVER_PORT=8080 # DLC_SHUTDOWN_TIMEOUT=30s # DLC_LOGGING_JSON=false +# DLC_LOGGING_LEVEL=trace # DLC_TELEMETRY_ENABLED=true # DLC_TELEMETRY_OTLP_ENDPOINT="jaeger:4317" # DLC_TELEMETRY_SERVICE_NAME="DanceLessonsCoach" diff --git a/pkg/config/config.go b/pkg/config/config.go index b32ca88..d1aacc8 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -3,8 +3,10 @@ package config import ( "fmt" "os" + "strings" "time" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/spf13/viper" ) @@ -30,7 +32,8 @@ type ShutdownConfig struct { // LoggingConfig holds logging-related configuration type LoggingConfig struct { - JSON bool `mapstructure:"json"` + JSON bool `mapstructure:"json"` + Level string `mapstructure:"level"` } // TelemetryConfig holds OpenTelemetry-related configuration @@ -53,12 +56,17 @@ type SamplerConfig struct { // To specify a custom config file path, set DLC_CONFIG_FILE environment variable func LoadConfig() (*Config, error) { v := viper.New() + + // Set up initial console logging for config loading messages + consoleWriter := zerolog.ConsoleWriter{Out: os.Stderr} + log.Logger = log.Output(consoleWriter) // Set default values v.SetDefault("server.host", "0.0.0.0") v.SetDefault("server.port", 8080) v.SetDefault("shutdown.timeout", 30*time.Second) v.SetDefault("logging.json", false) + v.SetDefault("logging.level", "trace") // Telemetry defaults v.SetDefault("telemetry.enabled", false) @@ -97,6 +105,7 @@ func LoadConfig() (*Config, error) { v.BindEnv("server.port", "DLC_SERVER_PORT") v.BindEnv("shutdown.timeout", "DLC_SHUTDOWN_TIMEOUT") v.BindEnv("logging.json", "DLC_LOGGING_JSON") + v.BindEnv("logging.level", "DLC_LOGGING_LEVEL") // Telemetry environment variables v.BindEnv("telemetry.enabled", "DLC_TELEMETRY_ENABLED") @@ -113,11 +122,23 @@ func LoadConfig() (*Config, error) { return nil, fmt.Errorf("config unmarshal error: %w", err) } + // Configure log output format (JSON or console) first + if config.Logging.JSON { + log.Logger = log.Output(os.Stderr) + } else { + consoleWriter := zerolog.ConsoleWriter{Out: os.Stderr} + log.Logger = log.Output(consoleWriter) + } + + // Setup logging based on configuration + config.SetupLogging() + log.Info(). Str("host", config.Server.Host). Int("port", config.Server.Port). Dur("shutdown_timeout", config.Shutdown.Timeout). Bool("logging_json", config.Logging.JSON). + Str("logging_level", config.Logging.Level). Bool("telemetry_enabled", config.Telemetry.Enabled). Str("telemetry_service", config.Telemetry.ServiceName). Msg("Configuration loaded") @@ -159,3 +180,40 @@ func (c *Config) GetSamplerType() string { func (c *Config) GetSamplerRatio() float64 { return c.Telemetry.Sampler.Ratio } + +// GetLogLevel returns the logging level +func (c *Config) GetLogLevel() string { + return c.Logging.Level +} + +// SetupLogging configures zerolog based on the configuration +func (c *Config) SetupLogging() { + // Parse log level + level := parseLogLevel(c.GetLogLevel()) + zerolog.SetGlobalLevel(level) + + zerolog.TimeFieldFormat = zerolog.TimeFormatUnix +} + +// parseLogLevel converts a string log level to zerolog.Level +func parseLogLevel(level string) zerolog.Level { + switch strings.ToLower(level) { + case "trace": + return zerolog.TraceLevel + case "debug": + return zerolog.DebugLevel + case "info": + return zerolog.InfoLevel + case "warn", "warning": + return zerolog.WarnLevel + case "error": + return zerolog.ErrorLevel + case "fatal": + return zerolog.FatalLevel + case "panic": + return zerolog.PanicLevel + default: + log.Warn().Str("level", level).Msg("Unknown log level, defaulting to trace") + return zerolog.TraceLevel + } +} diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..719f7c9 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# DanceLessonsCoach Build Script +# Builds binaries into the bin/ directory + +set -e + +echo "🔨 Building DanceLessonsCoach binaries..." + +# Create bin directory if it doesn't exist +mkdir -p bin + +# Build server binary +echo "📦 Building server..." +go build -o bin/server ./cmd/server + +# Build greet CLI binary +echo "📦 Building greet CLI..." +go build -o bin/greet ./cmd/greet + +echo "✅ Build complete!" +echo " Server binary: ./bin/server" +echo " Greet binary: ./bin/greet" +echo "" +echo "💡 To run the server: ./bin/server" +echo "💡 To use the greet CLI: ./bin/greet [name]"