@@ -2,10 +2,9 @@ package main
22
33import (
44 "context"
5+ "fmt"
56 "log"
6- "os"
7- "strconv"
8- "strings"
7+ "log/slog"
98 "time"
109 "tinyauth-analytics/internal/controller"
1110 "tinyauth-analytics/internal/middleware"
@@ -14,85 +13,89 @@ import (
1413
1514 "github.com/gin-contrib/cors"
1615 "github.com/gin-gonic/gin"
16+ "github.com/spf13/viper"
1717 "gorm.io/gorm"
1818)
1919
2020var version = "development"
2121
22- func main () {
23- log .SetFlags (log .LstdFlags | log .Lshortfile )
24-
25- dbPath := os .Getenv ("DB_PATH" )
26-
27- if dbPath == "" {
28- dbPath = "/data/analytics.db"
29- }
30-
31- port := os .Getenv ("PORT" )
32-
33- if port == "" {
34- port = "8080"
35- }
36-
37- address := os .Getenv ("ADDRESS" )
22+ type config struct {
23+ DatabasePath string `mapstructure:"db_path"`
24+ Port string `mapstructure:"port"`
25+ Address string `mapstructure:"address"`
26+ RateLimitCount int `mapstructure:"rate_limit_count"`
27+ CORSAllowedOrigins []string `mapstructure:"cors_allowed_origins"`
28+ TrustedProxies []string `mapstructure:"trusted_proxies"`
29+ LogLevel string `mapstructure:"log_level"`
30+ }
3831
39- if address == "" {
40- address = "0.0.0.0"
41- }
32+ func main () {
33+ logger := slog .New (slog .NewTextHandler (log .Writer (), & slog.HandlerOptions {
34+ Level : slog .LevelInfo ,
35+ }))
36+ slog .SetDefault (logger )
4237
43- var rateLimitCount int
38+ v := viper . New ()
4439
45- rateLimitCountStr := os . Getenv ( "RATE_LIMIT_COUNT" )
40+ v . AutomaticEnv ( )
4641
47- if rateLimitCountStr == "" {
48- rateLimitCount = 3
49- } else {
50- var err error
42+ v .SetDefault ("db_path" , "/data/analytics.db" )
43+ v .SetDefault ("port" , "8080" )
44+ v .SetDefault ("address" , "0.0.0.0" )
45+ v .SetDefault ("rate_limit_count" , 3 )
46+ v .SetDefault ("cors_allowed_origins" , "*" )
47+ v .SetDefault ("trusted_proxies" , "" )
48+ v .SetDefault ("log_level" , "info" )
5149
52- rateLimitCount , err = strconv . Atoi ( rateLimitCountStr )
50+ var conf config
5351
54- if err != nil {
55- log .Fatal ("invalid RATE_LIMIT_COUNT:" , err )
56- }
52+ if err := v .Unmarshal (& conf ); err != nil {
53+ slog .Error ("failed to parse config" , "error" , err )
5754 }
5855
59- var corsAllowedOrigins []string
60-
61- corsAllowedOriginsStr := os .Getenv ("CORS_ALLOWED_ORIGINS" )
62-
63- if corsAllowedOriginsStr != "" {
64- corsAllowedOrigins = append (corsAllowedOrigins , strings .Split (corsAllowedOriginsStr , "," )... )
65- } else {
66- corsAllowedOrigins = append (corsAllowedOrigins , "*" )
56+ switch conf .LogLevel {
57+ case "debug" :
58+ slog .SetLogLoggerLevel (slog .LevelDebug )
59+ case "info" :
60+ slog .SetLogLoggerLevel (slog .LevelInfo )
61+ case "warn" :
62+ slog .SetLogLoggerLevel (slog .LevelWarn )
63+ case "error" :
64+ slog .SetLogLoggerLevel (slog .LevelError )
65+ default :
66+ slog .Error ("invalid log level" , "level" , conf .LogLevel )
6767 }
6868
69- trustedProxies := os .Getenv ("TRUSTED_PROXIES" )
70-
7169 dbSvc := service .NewDatabaseService (service.DatabaseServiceConfig {
72- DatabasePath : dbPath ,
70+ DatabasePath : conf . DatabasePath ,
7371 })
7472
7573 if err := dbSvc .Init (); err != nil {
76- log . Fatal ("failed to initialize database: " , err )
74+ slog . Error ("failed to initialize database" , "error " , err )
7775 }
7876
7977 db := dbSvc .GetDatabase ()
8078
8179 cacheSvc := service .NewCacheService ()
8280
8381 engine := gin .Default ()
82+ engine .Use (gin .Recovery ())
83+
84+ if conf .LogLevel == "debug" || conf .LogLevel == "info" {
85+ engine .Use (gin .Logger ())
86+ }
8487
8588 engine .Use (cors .New (
8689 cors.Config {
87- AllowOrigins : corsAllowedOrigins ,
90+ AllowOrigins : conf . CORSAllowedOrigins ,
8891 },
8992 ))
9093
91- engine .SetTrustedProxies (strings . Split ( trustedProxies , "," ) )
94+ engine .SetTrustedProxies (conf . TrustedProxies )
9295
9396 api := engine .Group ("/v1" )
9497
95- rateLimitMiddleware := middleware .NewRateLimitMiddleware (db , cacheSvc , rateLimitCount )
98+ rateLimitMiddleware := middleware .NewRateLimitMiddleware (db , cacheSvc , conf . RateLimitCount )
9699
97100 instancesCtrl := controller .NewInstancesController (api , db , rateLimitMiddleware )
98101
@@ -104,10 +107,10 @@ func main() {
104107
105108 go clearOldSessions (db )
106109
107- log . Printf ( "Starting analytics server on %s:%s (version: %s)" , address , port , version )
110+ slog . Info ( "starting analytics server" , "address" , conf . Address , "port" , conf . Port , "version" , version )
108111
109- if err := engine .Run (address + ":" + port ); err != nil {
110- log . Fatal ("failed to start server: " , err )
112+ if err := engine .Run (conf . Address + ":" + conf . Port ); err != nil {
113+ slog . Error ("failed to start server" , "error " , err )
111114 }
112115}
113116
@@ -116,17 +119,17 @@ func clearOldSessions(db *gorm.DB) {
116119 defer ticker .Stop ()
117120
118121 for ; true ; <- ticker .C {
119- log . Println ( "Clearing old sessions" )
122+ slog . Info ( "clearing old sessions" )
120123
121124 ctx := context .Background ()
122125 cutoffTime := time .Now ().Add (time .Duration (- 48 ) * time .Hour ).UnixMilli ()
123126 rowsAffected , err := gorm.G [model.Instance ](db ).Where ("last_seen < ?" , cutoffTime ).Delete (ctx )
124127
125128 if err != nil {
126- log . Println ( "Failed to clear old sessions:" , err )
129+ slog . Warn ( "failed to clear old sessions: " , "error " , err )
127130 continue
128131 }
129132
130- log . Printf ( "Cleared %d old sessions\n " , rowsAffected )
133+ slog . Info ( fmt . Sprintf ( "cleared %d old sessions" , rowsAffected ) )
131134 }
132135}
0 commit comments