107 lines
2.6 KiB
Go
107 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
|
|
"zwift-activity-loader/internal/config"
|
|
"zwift-activity-loader/internal/service"
|
|
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
)
|
|
|
|
func main() {
|
|
// Load configuration
|
|
cfg, err := config.Load()
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to load configuration: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Set up logging
|
|
logger, err := setupLogger(cfg.LogLevel, cfg.LogFile)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to setup logger: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
defer logger.Sync()
|
|
|
|
// Create service
|
|
svc, err := service.New(cfg, logger)
|
|
if err != nil {
|
|
logger.Fatal("Failed to create service", zap.Error(err))
|
|
}
|
|
|
|
// Set up signal handling for graceful shutdown
|
|
sigChan := make(chan os.Signal, 1)
|
|
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
// Start service in goroutine
|
|
errChan := make(chan error, 1)
|
|
go func() {
|
|
errChan <- svc.Run()
|
|
}()
|
|
|
|
// Wait for shutdown signal or error
|
|
select {
|
|
case sig := <-sigChan:
|
|
logger.Info("Received signal", zap.String("signal", sig.String()))
|
|
if err := svc.Shutdown(); err != nil {
|
|
logger.Error("Error during shutdown", zap.Error(err))
|
|
os.Exit(1)
|
|
}
|
|
case err := <-errChan:
|
|
if err != nil {
|
|
logger.Error("Service error", zap.Error(err))
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
logger.Info("Service exited successfully")
|
|
}
|
|
|
|
// setupLogger creates a zap logger based on configuration
|
|
func setupLogger(logLevel, logFile string) (*zap.Logger, error) {
|
|
// Parse log level
|
|
var level zapcore.Level
|
|
if err := level.UnmarshalText([]byte(logLevel)); err != nil {
|
|
level = zapcore.InfoLevel
|
|
}
|
|
|
|
// Create encoder config
|
|
encoderConfig := zap.NewProductionEncoderConfig()
|
|
encoderConfig.TimeKey = "time"
|
|
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
|
|
|
// Create core
|
|
var core zapcore.Core
|
|
|
|
if logFile != "" {
|
|
// Log to both file and stdout
|
|
file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to open log file: %w", err)
|
|
}
|
|
|
|
fileEncoder := zapcore.NewJSONEncoder(encoderConfig)
|
|
consoleEncoder := zapcore.NewConsoleEncoder(encoderConfig)
|
|
|
|
core = zapcore.NewTee(
|
|
zapcore.NewCore(fileEncoder, zapcore.AddSync(file), level),
|
|
zapcore.NewCore(consoleEncoder, zapcore.AddSync(os.Stdout), level),
|
|
)
|
|
} else {
|
|
// Log to stdout only
|
|
consoleEncoder := zapcore.NewConsoleEncoder(encoderConfig)
|
|
core = zapcore.NewCore(consoleEncoder, zapcore.AddSync(os.Stdout), level)
|
|
}
|
|
|
|
// Create logger
|
|
logger := zap.New(core, zap.AddCaller(), zap.AddStacktrace(zapcore.ErrorLevel))
|
|
|
|
return logger, nil
|
|
}
|