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
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,8 +2,7 @@
|
|||||||
*.exe
|
*.exe
|
||||||
*.test
|
*.test
|
||||||
*.out
|
*.out
|
||||||
server
|
bin/
|
||||||
greet
|
|
||||||
|
|
||||||
# Dependency directories
|
# Dependency directories
|
||||||
vendor/
|
vendor/
|
||||||
|
|||||||
29
AGENTS.md
29
AGENTS.md
@@ -355,12 +355,37 @@ go test ./...
|
|||||||
go test ./pkg/greet/
|
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/`
|
- Edit source files in `pkg/` or `cmd/`
|
||||||
- Follow existing patterns and interfaces
|
- Follow existing patterns and interfaces
|
||||||
- Add tests for new functionality
|
- Add tests for new functionality
|
||||||
|
|
||||||
### 6. Stop and Restart
|
### 7. Stop and Restart
|
||||||
```bash
|
```bash
|
||||||
./scripts/start-server.sh restart
|
./scripts/start-server.sh restart
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -2,49 +2,19 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"os"
|
|
||||||
|
|
||||||
"DanceLessonsCoach/pkg/config"
|
"DanceLessonsCoach/pkg/config"
|
||||||
"DanceLessonsCoach/pkg/server"
|
"DanceLessonsCoach/pkg/server"
|
||||||
"github.com/rs/zerolog"
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Initialize Zerolog with default console format first
|
// Load configuration (this will also setup logging)
|
||||||
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
|
|
||||||
cfg, err := config.LoadConfig()
|
cfg, err := config.LoadConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal().Err(err).Msg("Failed to load configuration")
|
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
|
// Create readiness context to control readiness state
|
||||||
readyCtx, readyCancel := context.WithCancel(context.Background())
|
readyCtx, readyCancel := context.WithCancel(context.Background())
|
||||||
defer readyCancel()
|
defer readyCancel()
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ logging:
|
|||||||
# Enable JSON output for structured logging (default: false)
|
# Enable JSON output for structured logging (default: false)
|
||||||
# When true, logs are output in JSON format instead of console format
|
# When true, logs are output in JSON format instead of console format
|
||||||
json: false
|
json: false
|
||||||
|
|
||||||
|
# Log level (default: "trace")
|
||||||
|
# Options: "trace", "debug", "info", "warn", "error", "fatal", "panic"
|
||||||
|
level: trace
|
||||||
|
|
||||||
# Telemetry configuration (OpenTelemetry)
|
# Telemetry configuration (OpenTelemetry)
|
||||||
telemetry:
|
telemetry:
|
||||||
@@ -53,6 +57,7 @@ telemetry:
|
|||||||
# DLC_SERVER_PORT=8080
|
# DLC_SERVER_PORT=8080
|
||||||
# DLC_SHUTDOWN_TIMEOUT=30s
|
# DLC_SHUTDOWN_TIMEOUT=30s
|
||||||
# DLC_LOGGING_JSON=false
|
# DLC_LOGGING_JSON=false
|
||||||
|
# DLC_LOGGING_LEVEL=trace
|
||||||
# DLC_TELEMETRY_ENABLED=true
|
# DLC_TELEMETRY_ENABLED=true
|
||||||
# DLC_TELEMETRY_OTLP_ENDPOINT="jaeger:4317"
|
# DLC_TELEMETRY_OTLP_ENDPOINT="jaeger:4317"
|
||||||
# DLC_TELEMETRY_SERVICE_NAME="DanceLessonsCoach"
|
# DLC_TELEMETRY_SERVICE_NAME="DanceLessonsCoach"
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ package config
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
@@ -30,7 +32,8 @@ type ShutdownConfig struct {
|
|||||||
|
|
||||||
// LoggingConfig holds logging-related configuration
|
// LoggingConfig holds logging-related configuration
|
||||||
type LoggingConfig struct {
|
type LoggingConfig struct {
|
||||||
JSON bool `mapstructure:"json"`
|
JSON bool `mapstructure:"json"`
|
||||||
|
Level string `mapstructure:"level"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TelemetryConfig holds OpenTelemetry-related configuration
|
// 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
|
// To specify a custom config file path, set DLC_CONFIG_FILE environment variable
|
||||||
func LoadConfig() (*Config, error) {
|
func LoadConfig() (*Config, error) {
|
||||||
v := viper.New()
|
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
|
// Set default values
|
||||||
v.SetDefault("server.host", "0.0.0.0")
|
v.SetDefault("server.host", "0.0.0.0")
|
||||||
v.SetDefault("server.port", 8080)
|
v.SetDefault("server.port", 8080)
|
||||||
v.SetDefault("shutdown.timeout", 30*time.Second)
|
v.SetDefault("shutdown.timeout", 30*time.Second)
|
||||||
v.SetDefault("logging.json", false)
|
v.SetDefault("logging.json", false)
|
||||||
|
v.SetDefault("logging.level", "trace")
|
||||||
|
|
||||||
// Telemetry defaults
|
// Telemetry defaults
|
||||||
v.SetDefault("telemetry.enabled", false)
|
v.SetDefault("telemetry.enabled", false)
|
||||||
@@ -97,6 +105,7 @@ func LoadConfig() (*Config, error) {
|
|||||||
v.BindEnv("server.port", "DLC_SERVER_PORT")
|
v.BindEnv("server.port", "DLC_SERVER_PORT")
|
||||||
v.BindEnv("shutdown.timeout", "DLC_SHUTDOWN_TIMEOUT")
|
v.BindEnv("shutdown.timeout", "DLC_SHUTDOWN_TIMEOUT")
|
||||||
v.BindEnv("logging.json", "DLC_LOGGING_JSON")
|
v.BindEnv("logging.json", "DLC_LOGGING_JSON")
|
||||||
|
v.BindEnv("logging.level", "DLC_LOGGING_LEVEL")
|
||||||
|
|
||||||
// Telemetry environment variables
|
// Telemetry environment variables
|
||||||
v.BindEnv("telemetry.enabled", "DLC_TELEMETRY_ENABLED")
|
v.BindEnv("telemetry.enabled", "DLC_TELEMETRY_ENABLED")
|
||||||
@@ -113,11 +122,23 @@ 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
|
||||||
|
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().
|
log.Info().
|
||||||
Str("host", config.Server.Host).
|
Str("host", config.Server.Host).
|
||||||
Int("port", config.Server.Port).
|
Int("port", config.Server.Port).
|
||||||
Dur("shutdown_timeout", config.Shutdown.Timeout).
|
Dur("shutdown_timeout", config.Shutdown.Timeout).
|
||||||
Bool("logging_json", config.Logging.JSON).
|
Bool("logging_json", config.Logging.JSON).
|
||||||
|
Str("logging_level", config.Logging.Level).
|
||||||
Bool("telemetry_enabled", config.Telemetry.Enabled).
|
Bool("telemetry_enabled", config.Telemetry.Enabled).
|
||||||
Str("telemetry_service", config.Telemetry.ServiceName).
|
Str("telemetry_service", config.Telemetry.ServiceName).
|
||||||
Msg("Configuration loaded")
|
Msg("Configuration loaded")
|
||||||
@@ -159,3 +180,40 @@ func (c *Config) GetSamplerType() string {
|
|||||||
func (c *Config) GetSamplerRatio() float64 {
|
func (c *Config) GetSamplerRatio() float64 {
|
||||||
return c.Telemetry.Sampler.Ratio
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
26
scripts/build.sh
Executable file
26
scripts/build.sh
Executable file
@@ -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]"
|
||||||
Reference in New Issue
Block a user