Add a 'logging' section to config.yaml supporting:
- output: stderr (default), stdout, or a file path
- level: debug, info, warn, error (default: info)
Implementation:
- New internal/logging package with Setup() for output destination
and Logger struct with level-aware Debug/Info/Warn/Error methods
- Config struct extended with Logging section (output + level fields)
- Hub refactored to accept *logging.Logger via constructor injection
- main.go initializes logging early after config load
The leveled logger suppresses messages below the configured threshold
while maintaining the stdlib log format. File output uses append mode
with 0644 permissions for safe log rotation.
🤖 Assisted by the code-assist SOP
136 lines
2.8 KiB
Go
136 lines
2.8 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
)
|
|
|
|
func TestLoad(t *testing.T) {
|
|
testConfig := `server:
|
|
port: 9000
|
|
tls:
|
|
enabled: false
|
|
cert_file: test.pem
|
|
key_file: test.key`
|
|
|
|
tmpFile, err := os.CreateTemp("", "config_test_*.yaml")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.Remove(tmpFile.Name())
|
|
|
|
if _, err := tmpFile.WriteString(testConfig); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tmpFile.Close()
|
|
|
|
config, err := Load(tmpFile.Name())
|
|
if err != nil {
|
|
t.Fatalf("Load failed: %v", err)
|
|
}
|
|
|
|
if config.Server.Port != 9000 {
|
|
t.Errorf("Expected port 9000, got %d", config.Server.Port)
|
|
}
|
|
if config.Server.TLS.Enabled != false {
|
|
t.Errorf("Expected TLS disabled, got %v", config.Server.TLS.Enabled)
|
|
}
|
|
}
|
|
|
|
func TestLoadFileNotFound(t *testing.T) {
|
|
_, err := Load("nonexistent.yaml")
|
|
if err == nil {
|
|
t.Error("Expected error for nonexistent file")
|
|
}
|
|
}
|
|
|
|
func TestLoadLoggingOutput(t *testing.T) {
|
|
testConfig := `server:
|
|
port: 8443
|
|
logging:
|
|
output: /var/log/relay.log
|
|
level: debug`
|
|
|
|
tmpFile, err := os.CreateTemp("", "config_logging_*.yaml")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.Remove(tmpFile.Name())
|
|
|
|
if _, err := tmpFile.WriteString(testConfig); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tmpFile.Close()
|
|
|
|
cfg, err := Load(tmpFile.Name())
|
|
if err != nil {
|
|
t.Fatalf("Load failed: %v", err)
|
|
}
|
|
|
|
if cfg.Logging.Output != "/var/log/relay.log" {
|
|
t.Errorf("Expected output '/var/log/relay.log', got '%s'", cfg.Logging.Output)
|
|
}
|
|
if cfg.Logging.Level != "debug" {
|
|
t.Errorf("Expected level 'debug', got '%s'", cfg.Logging.Level)
|
|
}
|
|
}
|
|
|
|
func TestLoadLoggingDefaults(t *testing.T) {
|
|
testConfig := `server:
|
|
port: 8443`
|
|
|
|
tmpFile, err := os.CreateTemp("", "config_defaults_*.yaml")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.Remove(tmpFile.Name())
|
|
|
|
if _, err := tmpFile.WriteString(testConfig); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tmpFile.Close()
|
|
|
|
cfg, err := Load(tmpFile.Name())
|
|
if err != nil {
|
|
t.Fatalf("Load failed: %v", err)
|
|
}
|
|
|
|
if cfg.Logging.Output != "" {
|
|
t.Errorf("Expected empty output default, got '%s'", cfg.Logging.Output)
|
|
}
|
|
if cfg.Logging.Level != "" {
|
|
t.Errorf("Expected empty level default, got '%s'", cfg.Logging.Level)
|
|
}
|
|
}
|
|
|
|
func TestLoadLoggingStdout(t *testing.T) {
|
|
testConfig := `server:
|
|
port: 8443
|
|
logging:
|
|
output: stdout
|
|
level: warn`
|
|
|
|
tmpFile, err := os.CreateTemp("", "config_stdout_*.yaml")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.Remove(tmpFile.Name())
|
|
|
|
if _, err := tmpFile.WriteString(testConfig); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tmpFile.Close()
|
|
|
|
cfg, err := Load(tmpFile.Name())
|
|
if err != nil {
|
|
t.Fatalf("Load failed: %v", err)
|
|
}
|
|
|
|
if cfg.Logging.Output != "stdout" {
|
|
t.Errorf("Expected output 'stdout', got '%s'", cfg.Logging.Output)
|
|
}
|
|
if cfg.Logging.Level != "warn" {
|
|
t.Errorf("Expected level 'warn', got '%s'", cfg.Logging.Level)
|
|
}
|
|
}
|