1dfccf513a
- Initialize slog in the serve command with terminal/file support - Introduce `AppError` with HTTP status for unified service-layer errors - Replace ad-hoc `api.Error` calls with `api.RespondError` - Wrap internal errors with `model.NewInternalError` and add reference IDs - Add `RequestID` middleware and switch router from `gin.Default` to `gin.New`
60 lines
1.3 KiB
Go
60 lines
1.3 KiB
Go
package cmd
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log/slog"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/dhao2001/mygo/internal/app"
|
|
"github.com/dhao2001/mygo/internal/config"
|
|
mygolog "github.com/dhao2001/mygo/internal/log"
|
|
"github.com/dhao2001/mygo/internal/server"
|
|
)
|
|
|
|
var serveConfigFile string
|
|
|
|
var serveCmd = &cobra.Command{
|
|
Use: "serve",
|
|
Short: "Start the MyGO HTTP server",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
v := config.New()
|
|
cfg, err := config.Load(v, serveConfigFile)
|
|
if err != nil {
|
|
return fmt.Errorf("load config: %w", err)
|
|
}
|
|
|
|
// Set up structured logging before anything else.
|
|
appLogger := mygolog.NewLogger(cfg.Log)
|
|
slog.SetDefault(appLogger)
|
|
slog.Info("mygo server starting")
|
|
|
|
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
|
defer stop()
|
|
|
|
webApp, err := app.Bootstrap(cfg)
|
|
if err != nil {
|
|
return fmt.Errorf("bootstrap: %w", err)
|
|
}
|
|
defer func() {
|
|
if err := webApp.Close(); err != nil {
|
|
fmt.Fprintf(os.Stderr, "close webapp: %v\n", err)
|
|
}
|
|
}()
|
|
|
|
router := server.NewRouter(webApp)
|
|
addr := server.Address(webApp.Config.Server)
|
|
|
|
return server.RunWithGracefulShutdown(ctx, addr, router)
|
|
},
|
|
}
|
|
|
|
func init() {
|
|
serveCmd.Flags().StringVar(&serveConfigFile, "config", "", "config file path")
|
|
rootCmd.AddCommand(serveCmd)
|
|
}
|