Use conf.Log().Fatal to replace log.Fatal; Only initial Sentry logger once

This commit is contained in:
finn
2024-08-23 06:11:53 +07:00
parent d542ae9602
commit 34bf742ca8
7 changed files with 58 additions and 53 deletions

View File

@@ -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

View File

@@ -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]
}

View File

@@ -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
View File

@@ -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)
}

View File

@@ -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)
}
}
}

View File

@@ -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

View File

@@ -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