mirror of
https://github.com/muety/wakapi.git
synced 2025-12-05 22:20:24 -08:00
Use conf.Log().Fatal to replace log.Fatal; Only initial Sentry logger once
This commit is contained in:
@@ -3,7 +3,6 @@ package config
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -254,12 +253,12 @@ func (c *appConfig) GetAggregationTimeCron() string {
|
||||
timeParts := strings.Split(c.AggregationTime, ":")
|
||||
h, err := strconv.Atoi(timeParts[0])
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
Log().Fatal(err.Error())
|
||||
}
|
||||
|
||||
m, err := strconv.Atoi(timeParts[1])
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
Log().Fatal(err.Error())
|
||||
}
|
||||
|
||||
return fmt.Sprintf("0 %d %d * * *", m, h)
|
||||
@@ -277,12 +276,12 @@ func (c *appConfig) GetWeeklyReportCron() string {
|
||||
|
||||
h, err := strconv.Atoi(timeParts[0])
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
Log().Fatal(err.Error())
|
||||
}
|
||||
|
||||
m, err := strconv.Atoi(timeParts[1])
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
Log().Fatal(err.Error())
|
||||
}
|
||||
|
||||
return fmt.Sprintf("0 %d %d * * %d", m, h, weekday)
|
||||
@@ -302,12 +301,12 @@ func (c *appConfig) GetLeaderboardGenerationTimeCron() []string {
|
||||
timeParts := strings.Split(s, ":")
|
||||
h, err := strconv.Atoi(timeParts[0])
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
Log().Fatal(err.Error())
|
||||
}
|
||||
|
||||
m, err := strconv.Atoi(timeParts[1])
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
Log().Fatal(err.Error())
|
||||
}
|
||||
|
||||
return fmt.Sprintf("0 %d %d * * *", m, h)
|
||||
@@ -361,7 +360,7 @@ func (c *securityConfig) parseRate(rate string) (int, time.Duration) {
|
||||
pattern := regexp.MustCompile("(\\d+)/(\\d+)([smh])")
|
||||
matches := pattern.FindStringSubmatch(rate)
|
||||
if len(matches) != 4 {
|
||||
log.Fatalf("failed to parse rate pattern '%s'", rate)
|
||||
Log().Fatal("failed to parse rate pattern", "rate", rate)
|
||||
}
|
||||
|
||||
limit, _ := strconv.Atoi(matches[1])
|
||||
@@ -425,7 +424,7 @@ func readColors() map[string]map[string]string {
|
||||
|
||||
var colors = make(map[string]map[string]string)
|
||||
if err := json.Unmarshal(raw, &colors); err != nil {
|
||||
log.Fatal(err.Error())
|
||||
Log().Fatal(err.Error())
|
||||
}
|
||||
|
||||
return colors
|
||||
@@ -456,7 +455,7 @@ func Load(configFlag string, version string) *Config {
|
||||
config := &Config{}
|
||||
|
||||
if err := configor.New(&configor.Config{}).Load(config, configFlag); err != nil {
|
||||
log.Fatalf("failed to read config: %v", err)
|
||||
Log().Fatal("failed to read config", "error", err)
|
||||
}
|
||||
|
||||
env = config.Env
|
||||
@@ -510,48 +509,48 @@ func Load(configFlag string, version string) *Config {
|
||||
|
||||
// some validation checks
|
||||
if config.Server.ListenIpV4 == "-" && config.Server.ListenIpV6 == "-" && config.Server.ListenSocket == "" {
|
||||
log.Fatal("either of listen_ipv4 or listen_ipv6 or listen_socket must be set")
|
||||
Log().Fatal("either of listen_ipv4 or listen_ipv6 or listen_socket must be set")
|
||||
}
|
||||
if config.Db.MaxConn <= 0 {
|
||||
log.Fatal("you must allow at least one database connection")
|
||||
Log().Fatal("you must allow at least one database connection")
|
||||
}
|
||||
if config.Db.MaxConn > 1 && config.Db.IsSQLite() {
|
||||
slog.Warn("with sqlite, only a single connection is supported") // otherwise 'PRAGMA foreign_keys=ON' would somehow have to be set for every connection in the pool
|
||||
config.Db.MaxConn = 1
|
||||
}
|
||||
if config.Mail.Provider != "" && utils.FindString(config.Mail.Provider, emailProviders, "") == "" {
|
||||
log.Fatalf("unknown mail provider '%s'", config.Mail.Provider)
|
||||
Log().Fatal("unknown mail provider", "provider", config.Mail.Provider)
|
||||
}
|
||||
if _, err := time.ParseDuration(config.App.HeartbeatMaxAge); err != nil {
|
||||
log.Fatal("invalid duration set for heartbeat_max_age")
|
||||
Log().Fatal("invalid duration set for heartbeat_max_age")
|
||||
}
|
||||
if config.Security.TrustedHeaderAuth && len(config.Security.trustReverseProxyIpParsed) == 0 {
|
||||
config.Security.TrustedHeaderAuth = false
|
||||
}
|
||||
if d, err := time.Parse(config.App.DateFormat, config.App.DateFormat); err != nil || !d.Equal(time.Date(2006, time.January, 2, 0, 0, 0, 0, d.Location())) {
|
||||
log.Fatalf("invalid date format '%s'", config.App.DateFormat)
|
||||
Log().Fatal("invalid date format", "format", config.App.DateFormat)
|
||||
}
|
||||
if d, err := time.Parse(config.App.DateTimeFormat, config.App.DateTimeFormat); err != nil || !d.Equal(time.Date(2006, time.January, 2, 15, 4, 0, 0, d.Location())) {
|
||||
log.Fatalf("invalid datetime format '%s'", config.App.DateTimeFormat)
|
||||
Log().Fatal("invalid datetime format", "format", config.App.DateTimeFormat)
|
||||
}
|
||||
|
||||
cronParser := cron.NewParser(cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor)
|
||||
|
||||
if _, err := cronParser.Parse(config.App.GetWeeklyReportCron()); err != nil {
|
||||
log.Fatal("invalid cron expression for report_time_weekly")
|
||||
Log().Fatal("invalid cron expression for report_time_weekly")
|
||||
}
|
||||
if _, err := cronParser.Parse(config.App.GetAggregationTimeCron()); err != nil {
|
||||
log.Fatal("invalid cron expression for aggregation_time")
|
||||
Log().Fatal("invalid cron expression for aggregation_time")
|
||||
}
|
||||
for _, c := range config.App.GetLeaderboardGenerationTimeCron() {
|
||||
if _, err := cronParser.Parse(c); err != nil {
|
||||
log.Fatal("invalid cron expression for leaderboard_generation_time")
|
||||
Log().Fatal("invalid cron expression for leaderboard_generation_time")
|
||||
}
|
||||
}
|
||||
|
||||
// see models/interval.go
|
||||
if !slice.Contain[string](leaderboardScopes, config.App.LeaderboardScope) {
|
||||
log.Fatal("leaderboard scope is not a valid constant")
|
||||
Log().Fatal("leaderboard scope is not a valid constant")
|
||||
}
|
||||
|
||||
// deprecation notices
|
||||
|
||||
@@ -3,7 +3,6 @@ package config
|
||||
import (
|
||||
"github.com/gorilla/securecookie"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
@@ -15,13 +14,13 @@ func getTemporarySecureKeys() (hashKey, blockKey []byte) {
|
||||
if _, err := os.Stat(keyFile); err == nil {
|
||||
file, err := os.Open(keyFile)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to open dev keys file, %v", err)
|
||||
Log().Fatal("failed to open dev keys file", "error", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
combinedKey, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
log.Fatal("failed to read key from file")
|
||||
Log().Fatal("failed to read key from file", "error", err)
|
||||
}
|
||||
return combinedKey[:32], combinedKey[32:64]
|
||||
}
|
||||
@@ -29,13 +28,13 @@ func getTemporarySecureKeys() (hashKey, blockKey []byte) {
|
||||
// otherwise, generate random keys and save them
|
||||
file, err := os.OpenFile(keyFile, os.O_CREATE|os.O_WRONLY, 0600)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to open dev keys file, %v", err)
|
||||
Log().Fatal("failed to open dev keys file", "error", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
combinedKey := securecookie.GenerateRandomKey(64)
|
||||
if _, err := file.Write(combinedKey); err != nil {
|
||||
log.Fatal("failed to write key to file")
|
||||
Log().Fatal("failed to write key to file", "error", err)
|
||||
}
|
||||
return combinedKey[:32], combinedKey[32:64]
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package config
|
||||
import (
|
||||
"github.com/getsentry/sentry-go"
|
||||
"io"
|
||||
"log"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -14,6 +13,8 @@ import (
|
||||
// Use slog.[Debug|Info|Warn|Error|Fatal]() by default
|
||||
// Use config.Log().[Debug|Info|Warn|Error|Fatal]() when wanting the log to appear in Sentry as well
|
||||
|
||||
var sentryWrapperLogger *SentryWrapperLogger
|
||||
|
||||
type capturingWriter struct {
|
||||
Writer io.Writer
|
||||
Message string
|
||||
@@ -37,18 +38,29 @@ type SentryWrapperLogger struct {
|
||||
}
|
||||
|
||||
func Log() *SentryWrapperLogger {
|
||||
if sentryWrapperLogger != nil {
|
||||
return sentryWrapperLogger
|
||||
}
|
||||
|
||||
ow, ew := &capturingWriter{Writer: os.Stdout}, &capturingWriter{Writer: os.Stderr}
|
||||
var handler slog.Handler
|
||||
if Get().IsDev() {
|
||||
handler = slog.NewTextHandler(io.MultiWriter(ow, ew), &slog.HandlerOptions{
|
||||
Level: slog.LevelDebug,
|
||||
})
|
||||
} else {
|
||||
handler = slog.NewJSONHandler(io.MultiWriter(ow, ew), &slog.HandlerOptions{
|
||||
Level: slog.LevelInfo,
|
||||
})
|
||||
}
|
||||
|
||||
// Create a custom handler that writes to both output and error writers
|
||||
handler := slog.NewJSONHandler(io.MultiWriter(ow, ew), &slog.HandlerOptions{
|
||||
Level: slog.LevelDebug,
|
||||
})
|
||||
|
||||
return &SentryWrapperLogger{
|
||||
sentryWrapperLogger = &SentryWrapperLogger{
|
||||
Logger: slog.New(handler),
|
||||
outWriter: ow,
|
||||
errWriter: ew,
|
||||
}
|
||||
return sentryWrapperLogger
|
||||
}
|
||||
|
||||
func (l *SentryWrapperLogger) Request(req *http.Request) *SentryWrapperLogger {
|
||||
@@ -143,7 +155,7 @@ func initSentry(config sentryConfig, debug bool) {
|
||||
return event
|
||||
},
|
||||
}); err != nil {
|
||||
log.Fatal("failed to initialized sentry -", err)
|
||||
Log().Fatal("failed to initialized sentry", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
24
main.go
24
main.go
@@ -143,7 +143,7 @@ func main() {
|
||||
slog.Info("starting with database", "dialect", config.Db.Dialect)
|
||||
db, err = gorm.Open(config.Db.GetDialector(), &gorm.Config{Logger: gormLogger}, conf.GetWakapiDBOpts(&config.Db))
|
||||
if err != nil {
|
||||
log.Fatal("could not connect to database", "error", err)
|
||||
conf.Log().Fatal("could not connect to database", "error", err)
|
||||
}
|
||||
|
||||
if config.IsDev() {
|
||||
@@ -151,8 +151,7 @@ func main() {
|
||||
}
|
||||
sqlDb, err := db.DB()
|
||||
if err != nil {
|
||||
slog.Error("could not connect to database", "error", err)
|
||||
log.Fatal("could not connect to database")
|
||||
conf.Log().Fatal("could not connect to database", "error", err)
|
||||
}
|
||||
sqlDb.SetMaxIdleConns(int(config.Db.MaxConn))
|
||||
sqlDb.SetMaxOpenConns(int(config.Db.MaxConn))
|
||||
@@ -363,7 +362,7 @@ func listen(handler http.Handler) {
|
||||
if _, err := os.Stat(config.Server.ListenSocket); err == nil {
|
||||
slog.Info("👉 Removing unix socket", "listenSocket", config.Server.ListenSocket)
|
||||
if err := os.Remove(config.Server.ListenSocket); err != nil {
|
||||
log.Fatal(err.Error())
|
||||
conf.Log().Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
sSocket = &http.Server{
|
||||
@@ -378,7 +377,7 @@ func listen(handler http.Handler) {
|
||||
slog.Info("👉 Listening for HTTPS... ✅", "address", s4.Addr)
|
||||
go func() {
|
||||
if err := s4.ListenAndServeTLS(config.Server.TlsCertPath, config.Server.TlsKeyPath); err != nil {
|
||||
log.Fatal(err.Error())
|
||||
conf.Log().Fatal(err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -386,7 +385,7 @@ func listen(handler http.Handler) {
|
||||
slog.Info("👉 Listening for HTTPS... ✅", "address", s6.Addr)
|
||||
go func() {
|
||||
if err := s6.ListenAndServeTLS(config.Server.TlsCertPath, config.Server.TlsKeyPath); err != nil {
|
||||
log.Fatal(err.Error())
|
||||
conf.Log().Fatal(err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -395,13 +394,13 @@ func listen(handler http.Handler) {
|
||||
go func() {
|
||||
unixListener, err := net.Listen("unix", config.Server.ListenSocket)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
conf.Log().Fatal(err.Error())
|
||||
}
|
||||
if err := os.Chmod(config.Server.ListenSocket, os.FileMode(config.Server.ListenSocketMode)); err != nil {
|
||||
slog.Warn("failed to set user permissions for unix socket", "error", err)
|
||||
}
|
||||
if err := sSocket.ServeTLS(unixListener, config.Server.TlsCertPath, config.Server.TlsKeyPath); err != nil {
|
||||
log.Fatal(err.Error())
|
||||
conf.Log().Fatal(err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -410,7 +409,7 @@ func listen(handler http.Handler) {
|
||||
slog.Info("👉 Listening for HTTP... ✅", "address", s4.Addr)
|
||||
go func() {
|
||||
if err := s4.ListenAndServe(); err != nil {
|
||||
log.Fatal(err.Error())
|
||||
conf.Log().Fatal(err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -418,7 +417,7 @@ func listen(handler http.Handler) {
|
||||
slog.Info("👉 Listening for HTTP... ✅", "address", s6.Addr)
|
||||
go func() {
|
||||
if err := s6.ListenAndServe(); err != nil {
|
||||
log.Fatal(err.Error())
|
||||
conf.Log().Fatal(err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -427,13 +426,13 @@ func listen(handler http.Handler) {
|
||||
go func() {
|
||||
unixListener, err := net.Listen("unix", config.Server.ListenSocket)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
conf.Log().Fatal(err.Error())
|
||||
}
|
||||
if err := os.Chmod(config.Server.ListenSocket, os.FileMode(config.Server.ListenSocketMode)); err != nil {
|
||||
slog.Warn("failed to set user permissions for unix socket", "error", err)
|
||||
}
|
||||
if err := sSocket.Serve(unixListener); err != nil {
|
||||
log.Fatal(err.Error())
|
||||
conf.Log().Fatal(err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -451,5 +450,4 @@ func initLogger() {
|
||||
}
|
||||
l := slog.New(handler)
|
||||
slog.SetDefault(l)
|
||||
slog.Info("logger initialized", "env", config.Env)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"github.com/muety/wakapi/config"
|
||||
"github.com/muety/wakapi/models"
|
||||
"gorm.io/gorm"
|
||||
"log"
|
||||
"log/slog"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -79,7 +78,7 @@ func Run(db *gorm.DB, cfg *config.Config) {
|
||||
|
||||
func RunSchemaMigrations(db *gorm.DB, cfg *config.Config) {
|
||||
if err := GetMigrationFunc(cfg)(db); err != nil {
|
||||
log.Fatal(err.Error())
|
||||
config.Log().Fatal("migration failed", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +88,7 @@ func RunPreMigrations(db *gorm.DB, cfg *config.Config) {
|
||||
for _, m := range preMigrations {
|
||||
slog.Info("potentially running migration", "name", m.name)
|
||||
if err := m.f(db, cfg); err != nil {
|
||||
log.Fatalf("migration '%s' failed - %v", m.name, err)
|
||||
config.Log().Fatal("migration failed", "name", m.name, "error", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,7 +99,7 @@ func RunPostMigrations(db *gorm.DB, cfg *config.Config) {
|
||||
for _, m := range postMigrations {
|
||||
slog.Info("potentially running migration", "name", m.name)
|
||||
if err := m.f(db, cfg); err != nil {
|
||||
log.Fatalf("migration '%s' failed - %v", m.name, err)
|
||||
config.Log().Fatal("migration failed", "name", m.name, "error", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
stripeSubscription "github.com/stripe/stripe-go/v74/subscription"
|
||||
"github.com/stripe/stripe-go/v74/webhook"
|
||||
"io"
|
||||
"log"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -59,7 +58,7 @@ func NewSubscriptionHandler(
|
||||
|
||||
price, err := stripePrice.Get(config.Subscriptions.StandardPriceId, nil)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to fetch stripe plan details: %v", err)
|
||||
conf.Log().Fatal("failed to fetch stripe plan details", "error", err)
|
||||
}
|
||||
config.Subscriptions.StandardPrice = strings.TrimSpace(fmt.Sprintf("%2.f €", price.UnitAmountDecimal/100.0)) // TODO: respect actual currency
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/muety/wakapi/repositories"
|
||||
"github.com/muety/wakapi/utils"
|
||||
"github.com/patrickmn/go-cache"
|
||||
"log"
|
||||
"log/slog"
|
||||
"reflect"
|
||||
"strconv"
|
||||
@@ -44,7 +43,7 @@ func NewLeaderboardService(leaderboardRepo repositories.ILeaderboardRepository,
|
||||
|
||||
scope, err := helpers.ParseInterval(srv.config.App.LeaderboardScope)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
config.Log().Fatal(err.Error())
|
||||
}
|
||||
srv.defaultScope = scope
|
||||
|
||||
|
||||
Reference in New Issue
Block a user