Skip to content

Commit cae5bbe

Browse files
committed
feat: use zerolog for logging
1 parent 66b4422 commit cae5bbe

5 files changed

Lines changed: 93 additions & 23 deletions

File tree

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,15 @@ require (
3333
github.com/json-iterator/go v1.1.12 // indirect
3434
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
3535
github.com/leodido/go-urn v1.4.0 // indirect
36+
github.com/mattn/go-colorable v0.1.13 // indirect
3637
github.com/mattn/go-isatty v0.0.20 // indirect
3738
github.com/mattn/go-sqlite3 v1.14.22 // indirect
3839
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
3940
github.com/modern-go/reflect2 v1.0.2 // indirect
4041
github.com/ncruces/go-strftime v0.1.9 // indirect
4142
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
4243
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
44+
github.com/rs/zerolog v1.34.0 // indirect
4345
github.com/sagikazarmark/locafero v0.11.0 // indirect
4446
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
4547
github.com/spf13/afero v1.15.0 // indirect

go.sum

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCy
1212
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
1313
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
1414
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
15+
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
1516
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1617
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
1718
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -51,6 +52,7 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
5152
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
5253
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
5354
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
55+
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
5456
github.com/golang-migrate/migrate/v4 v4.19.0 h1:RcjOnCGz3Or6HQYEJ/EEVLfWnmw9KnoigPSjzhCuaSE=
5557
github.com/golang-migrate/migrate/v4 v4.19.0/go.mod h1:9dyEcu+hO+G9hPSw8AIg50yg622pXJsoHItQnDGZkI0=
5658
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
@@ -81,6 +83,10 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
8183
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
8284
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
8385
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
86+
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
87+
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
88+
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
89+
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
8490
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
8591
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
8692
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
@@ -96,10 +102,14 @@ github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6
96102
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
97103
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
98104
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
105+
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
99106
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
100107
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
101108
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
102109
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
110+
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
111+
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
112+
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
103113
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
104114
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
105115
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
@@ -154,8 +164,10 @@ golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
154164
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
155165
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
156166
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
167+
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
157168
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
158169
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
170+
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
159171
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
160172
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
161173
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=

internal/controller/instances_controller.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"tinyauth-analytics/internal/model"
88

99
"github.com/gin-gonic/gin"
10+
"github.com/rs/zerolog/log"
1011
"gorm.io/gorm"
1112
)
1213

@@ -45,6 +46,7 @@ func (ic *InstancesController) listAllInstances(c *gin.Context) {
4546
instances, err := gorm.G[model.Instance](ic.database).Find(ctx)
4647

4748
if err != nil {
49+
log.Error().Err(err).Msg("failed to fetch instances")
4850
c.JSON(500, gin.H{
4951
"status": 500,
5052
"message": "Database error",
@@ -74,6 +76,7 @@ func (ic *InstancesController) heartbeat(c *gin.Context) {
7476
instance, err := gorm.G[model.Instance](ic.database).Where("uuid = ?", heartbeat.UUID).First(ctx)
7577

7678
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
79+
log.Error().Err(err).Msg("failed to fetch instance")
7780
c.JSON(500, gin.H{
7881
"status": 500,
7982
"message": "Database error",
@@ -91,6 +94,7 @@ func (ic *InstancesController) heartbeat(c *gin.Context) {
9194
})
9295

9396
if err != nil {
97+
log.Error().Err(err).Msg("failed to create instance")
9498
c.JSON(500, gin.H{
9599
"status": 500,
96100
"message": "Database error",
@@ -108,6 +112,7 @@ func (ic *InstancesController) heartbeat(c *gin.Context) {
108112
_, err = gorm.G[model.Instance](ic.database).Where("id = ?", instance.ID).Update(ctx, "last_seen", t)
109113

110114
if err != nil {
115+
log.Error().Err(err).Msg("failed to update instance")
111116
c.JSON(500, gin.H{
112117
"status": 500,
113118
"message": "Database error",
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package middleware
2+
3+
import (
4+
"time"
5+
6+
"github.com/gin-gonic/gin"
7+
"github.com/rs/zerolog"
8+
"github.com/rs/zerolog/log"
9+
)
10+
11+
type ZerologMiddleware struct {
12+
level zerolog.Level
13+
}
14+
15+
func NewZerologMiddleware(level zerolog.Level) *ZerologMiddleware {
16+
return &ZerologMiddleware{
17+
level: level,
18+
}
19+
}
20+
21+
func (zm *ZerologMiddleware) Middleware() gin.HandlerFunc {
22+
return func(c *gin.Context) {
23+
tStart := time.Now()
24+
25+
c.Next()
26+
27+
code := c.Writer.Status()
28+
address := c.Request.RemoteAddr
29+
clientIP := c.ClientIP()
30+
method := c.Request.Method
31+
path := c.Request.URL.Path
32+
33+
latency := time.Since(tStart).String()
34+
35+
subLogger := log.With().Str("method", method).
36+
Str("path", path).
37+
Int("status", code).
38+
Str("latency", latency).Logger()
39+
40+
if zm.level == zerolog.DebugLevel {
41+
subLogger = subLogger.With().Str("address", address).Str("client_ip", clientIP).Logger()
42+
}
43+
44+
switch {
45+
case code >= 400 && code < 500:
46+
subLogger.Warn().Msg("Client Error")
47+
case code >= 500:
48+
subLogger.Error().Msg("Server Error")
49+
default:
50+
subLogger.Info().Msg("Request")
51+
}
52+
}
53+
}

main.go

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ package main
22

33
import (
44
"context"
5-
"fmt"
6-
"log"
7-
"log/slog"
5+
"os"
86
"time"
97
"tinyauth-analytics/internal/controller"
108
"tinyauth-analytics/internal/middleware"
@@ -13,6 +11,8 @@ import (
1311

1412
"github.com/gin-contrib/cors"
1513
"github.com/gin-gonic/gin"
14+
"github.com/rs/zerolog"
15+
"github.com/rs/zerolog/log"
1616
"github.com/spf13/viper"
1717
"gorm.io/gorm"
1818
)
@@ -30,10 +30,7 @@ type config struct {
3030
}
3131

3232
func main() {
33-
logger := slog.New(slog.NewTextHandler(log.Writer(), &slog.HandlerOptions{
34-
Level: slog.LevelInfo,
35-
}))
36-
slog.SetDefault(logger)
33+
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).With().Timestamp().Caller().Logger().Level(zerolog.FatalLevel)
3734

3835
v := viper.New()
3936

@@ -50,40 +47,41 @@ func main() {
5047
var conf config
5148

5249
if err := v.Unmarshal(&conf); err != nil {
53-
slog.Error("failed to parse config", "error", err)
50+
log.Fatal().Err(err).Msg("failed to parse config")
5451
}
5552

5653
switch conf.LogLevel {
5754
case "debug":
58-
slog.SetLogLoggerLevel(slog.LevelDebug)
55+
log.Level(zerolog.DebugLevel)
5956
case "info":
60-
slog.SetLogLoggerLevel(slog.LevelInfo)
57+
log.Level(zerolog.InfoLevel)
6158
case "warn":
62-
slog.SetLogLoggerLevel(slog.LevelWarn)
59+
log.Level(zerolog.WarnLevel)
6360
case "error":
64-
slog.SetLogLoggerLevel(slog.LevelError)
61+
log.Level(zerolog.ErrorLevel)
62+
case "fatal":
63+
log.Level(zerolog.FatalLevel)
6564
default:
66-
slog.Error("invalid log level", "level", conf.LogLevel)
65+
log.Fatal().Str("level", conf.LogLevel).Msg("invalid log level")
6766
}
6867

6968
dbSvc := service.NewDatabaseService(service.DatabaseServiceConfig{
7069
DatabasePath: conf.DatabasePath,
7170
})
7271

7372
if err := dbSvc.Init(); err != nil {
74-
slog.Error("failed to initialize database", "error", err)
73+
log.Fatal().Err(err).Msg("failed to initialize database")
7574
}
7675

7776
db := dbSvc.GetDatabase()
7877

7978
cacheSvc := service.NewCacheService()
8079

80+
zerologMiddleware := middleware.NewZerologMiddleware(log.Logger.GetLevel())
81+
8182
engine := gin.Default()
8283
engine.Use(gin.Recovery())
83-
84-
if conf.LogLevel == "debug" || conf.LogLevel == "info" {
85-
engine.Use(gin.Logger())
86-
}
84+
engine.Use(zerologMiddleware.Middleware())
8785

8886
engine.Use(cors.New(
8987
cors.Config{
@@ -107,10 +105,10 @@ func main() {
107105

108106
go clearOldSessions(db)
109107

110-
slog.Info("starting analytics server", "address", conf.Address, "port", conf.Port, "version", version)
108+
log.Info().Str("port", conf.Port).Str("address", conf.Address).Msg("starting server, version " + version)
111109

112110
if err := engine.Run(conf.Address + ":" + conf.Port); err != nil {
113-
slog.Error("failed to start server", "error", err)
111+
log.Fatal().Err(err).Msg("server error")
114112
}
115113
}
116114

@@ -119,17 +117,17 @@ func clearOldSessions(db *gorm.DB) {
119117
defer ticker.Stop()
120118

121119
for ; true; <-ticker.C {
122-
slog.Info("clearing old sessions")
120+
log.Info().Msg("clearing old sessions")
123121

124122
ctx := context.Background()
125123
cutoffTime := time.Now().Add(time.Duration(-48) * time.Hour).UnixMilli()
126124
rowsAffected, err := gorm.G[model.Instance](db).Where("last_seen < ?", cutoffTime).Delete(ctx)
127125

128126
if err != nil {
129-
slog.Warn("failed to clear old sessions: ", "error", err)
127+
log.Warn().Err(err).Msg("failed to clear old sessions")
130128
continue
131129
}
132130

133-
slog.Info(fmt.Sprintf("cleared %d old sessions", rowsAffected))
131+
log.Info().Msgf("cleared %d old sessions", rowsAffected)
134132
}
135133
}

0 commit comments

Comments
 (0)