79b7f16c02c4f2cb7029f165f130ab4c25f0a8f7
- Author
- TheEdgeOfRage <git@theedgeofrage.com>
- Committer
- TheEdgeOfRage <git@theedgeofrage.com>
- Date
Message
Diff
This diff is truncated to protect this page.
1diff --git a/Dockerfile b/Dockerfile
2index 9d71bb5b9685103eeace2f8d6b5eda9eadd38a11..d853d1154d8bcec5171ed248af29af7e0ba9c275 100644
3--- a/Dockerfile
4+++ b/Dockerfile
5@@ -8,13 +8,16 @@ COPY . /app/
6 RUN go build -o dist/ytrssil-api cmd/main.go
7
8 FROM debian:trixie-slim AS api
9+
10+HEALTHCHECK --start-period=10s CMD exec curl -sf localhost:$PORT/healthz
11+ENTRYPOINT ["/app/ytrssil-api"]
12+
13 RUN apt update \
14 && apt install -y ca-certificates curl \
15 && apt clean \
16 && rm -rf /var/lib/apt/lists/*
17
18 COPY --from=builder /app/dist/ /app/
19-ENTRYPOINT ["/app/ytrssil-api"]
20
21 FROM migrate/migrate AS migrations
22 COPY ./migrations/ /migrations/
23diff --git a/Makefile b/Makefile
24index 41a274c7f9f238a37404c442fe79d1f68ce9a26d..5157b5ce5c2a3a9415d533d60d9f9ef1464d2c43 100644
25--- a/Makefile
26+++ b/Makefile
27@@ -3,11 +3,11 @@
28 DB_URI ?= postgres://ytrssil:ytrssil@localhost:5432/ytrssil?sslmode=disable
29
30 bin/moq:
31- GOBIN=$(PWD)/bin go install github.com/matryer/moq@v0.5.3
32+ GOBIN=$(PWD)/bin go install github.com/matryer/moq@v0.6.0
33 bin/golangci-lint:
34- GOBIN=$(PWD)/bin go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.3.1
35+ GOBIN=$(PWD)/bin go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.5.0
36 bin/migrate: bin
37- GOBIN=$(PWD)/bin go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@v4.18.3
38+ GOBIN=$(PWD)/bin go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@v4.19.0
39
40 lint: bin/golangci-lint
41 go mod tidy
42diff --git a/cmd/main.go b/cmd/main.go
43index 37e62ab29f57a1854e74865fd53c32af9bc1e9e9..0a49766e1f711f9a014d05c14d79ee3821267641 100644
44--- a/cmd/main.go
45+++ b/cmd/main.go
46@@ -3,6 +3,7 @@ package main
47 import (
48 "context"
49 "fmt"
50+ "log/slog"
51 "net/http"
52 "os"
53 "os/signal"
54@@ -17,47 +18,58 @@ import (
55 "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/handler"
56 "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/httpserver/auth"
57 "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/httpserver/ytrssil"
58- "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/lib/log"
59 )
60
61+const LevelFatal slog.Level = slog.LevelError + 4
62+
63 func init() {
64 // always use UTC
65 time.Local = time.UTC
66 }
67
68-func fetcherRoutine(l log.Logger, h handler.Handler) {
69+func fetcherRoutine(l *slog.Logger, h handler.Handler) {
70 for {
71 err := h.FetchVideos(context.Background())
72 if err != nil {
73- l.Log("level", "ERROR", "function", "main.fetcherRoutine", "call", "handler.FetchVideos", "err", err)
74+ l.Error("Failed to fetch videos", "call", "handler.FetchVideos", "err", err)
75 }
76 time.Sleep(5 * time.Minute)
77 }
78 }
79
80 func main() {
81- log := log.NewLogger()
82+ logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
83
84 config, err := config.Parse()
85 if err != nil {
86- log.Log("level", "FATAL", "call", "config.Parse", "error", err)
87+ logger.Log(context.Background(), LevelFatal, "Failed to parse config", "call", "config.Parse", "error", err)
88 return
89 }
90- db, err := db.NewPostgresDB(log, config.DB)
91+ db, err := db.NewPostgresDB(logger, config.DB)
92 if err != nil {
93- log.Log("level", "FATAL", "call", "db.NewPostgresDB", "error", err)
94+ logger.Log(
95+ context.Background(), LevelFatal,
96+ "Failed to create DB connection",
97+ "call", "db.NewPostgresDB",
98+ "error", err,
99+ )
100 return
101 }
102- parser := feedparser.NewParser(log)
103- handler := handler.New(log, db, parser)
104+ parser := feedparser.NewParser(logger)
105+ handler := handler.New(logger, db, parser)
106 gin.SetMode(gin.ReleaseMode)
107 router, err := ytrssil.SetupGinRouter(
108- log,
109+ logger,
110 handler,
111 auth.AuthMiddleware(db),
112 )
113 if err != nil {
114- log.Log("level", "FATAL", "call", "ytrssil.SetupGinServer", "error", err)
115+ logger.Log(
116+ context.Background(), LevelFatal,
117+ "Failed to set up gin server",
118+ "call", "ytrssil.SetupGinServer",
119+ "error", err,
120+ )
121 return
122 }
123
124@@ -65,24 +77,16 @@ func main() {
125 Addr: fmt.Sprintf(":%v", config.Gin.Port),
126 Handler: router,
127 }
128- server.RegisterOnShutdown(func() {
129- log.Log("level", "INFO", "msg", "shutdown server.Close()")
130- })
131-
132 quit := make(chan os.Signal, 1)
133 // handle Interrupt (ctrl-c) Term, used by `kill` et al, HUP which is commonly used to reload configs
134 signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
135
136 go func() {
137 s := <-quit
138- log.Log(
139- "level", "INFO",
140- "msg", "signalRecv, for quitting",
141- "signal", s,
142- )
143+ logger.Info("Received signal, shutting down", "signal", s)
144 if err := server.Shutdown(context.Background()); err != nil {
145- log.Log(
146diff --git a/cmd/main_test.go b/cmd/main_test.go
147index 98b8f0aa670d1032e09c4ae107f11ec35bb4b0c6..04f4f31ca58d38f3682aed461e9d6a16b0a32a59 100644
148--- a/cmd/main_test.go
149+++ b/cmd/main_test.go
150@@ -5,6 +5,8 @@ import (
151 "context"
152 "encoding/json"
153 "fmt"
154+ "io"
155+ "log/slog"
156 "net/http"
157 "net/http/httptest"
158 "testing"
159@@ -18,7 +20,6 @@ import (
160 "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/handler"
161 "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/httpserver/auth"
162 "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/httpserver/ytrssil"
163- "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/lib/log"
164 "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/models"
165 )
166
167@@ -29,7 +30,7 @@ func init() {
168 }
169
170 func setupTestServer(t *testing.T) (*http.Server, db.DB) {
171- l := log.NewNopLogger()
172+ l := slog.New(slog.NewTextHandler(io.Discard, nil))
173
174 db, err := db.NewPostgresDB(l, testConfig.DB)
175 if !assert.NoError(t, err) {
176diff --git a/compose.yaml b/compose.yaml
177index 57f3d37cf0f472d2a17d44e49f0a69861d04e3e9..04a2cdda90178cdc837b889ba70fc98ff37d82d5 100644
178--- a/compose.yaml
179+++ b/compose.yaml
180@@ -28,11 +28,6 @@ services:
181 PORT: "80"
182 ports:
183 - "8080:80"
184- healthcheck:
185- test: "curl http://localhost:80/healthz"
186- interval: 5s
187- retries: 5
188- timeout: 2s
189
190 migrations:
191 image: theedgeofrage/ytrssil:migrations
192diff --git a/db/channels.go b/db/channels.go
193index 835e9773cf698f35a8b857629eecc3f757e90df9..4eafc1942cbdfbd7ec46c95f70a3e53ff7fa03d4 100644
194--- a/db/channels.go
195+++ b/db/channels.go
196@@ -11,7 +11,7 @@ var createChannelQuery = `INSERT INTO channels (id, name) VALUES ($1, $2) ON CON
197 func (d *postgresDB) CreateChannel(ctx context.Context, channel models.Channel) error {
198 resp, err := d.db.ExecContext(ctx, createChannelQuery, channel.ID, channel.Name)
199 if err != nil {
200- d.l.Log("level", "ERROR", "function", "db.CreateChannel", "error", err)
201+ d.l.Error("Failed to create channel", "call", "sql.ExecContext", "error", err)
202 return err
203 }
204 if affected, _ := resp.RowsAffected(); affected == 0 {
205@@ -26,7 +26,7 @@ var listChannelsQuery = `SELECT id, name FROM channels`
206 func (d *postgresDB) ListChannels(ctx context.Context) ([]models.Channel, error) {
207 rows, err := d.db.QueryContext(ctx, listChannelsQuery)
208 if err != nil {
209- d.l.Log("level", "ERROR", "function", "db.ListChannels", "call", "sql.QueryContext", "error", err)
210+ d.l.Error("Failed to list channels", "call", "sql.QueryContext", "error", err)
211 return nil, err
212 }
213 defer rows.Close()
214@@ -36,7 +36,7 @@ func (d *postgresDB) ListChannels(ctx context.Context) ([]models.Channel, error)
215 var channel models.Channel
216 err = rows.Scan(&channel.ID, &channel.Name)
217 if err != nil {
218- d.l.Log("level", "ERROR", "function", "db.ListChannels", "call", "sql.Scan", "error", err)
219+ d.l.Error("Failed to scan rows to list channels", "call", "sql.Scan", "error", err)
220 return nil, err
221 }
222 channels = append(channels, channel)
223@@ -50,7 +50,7 @@ var getChannelSubscribersQuery = `SELECT username FROM user_subscriptions WHERE
224 func (d *postgresDB) GetChannelSubscribers(ctx context.Context, channelID string) ([]string, error) {
225 rows, err := d.db.QueryContext(ctx, getChannelSubscribersQuery, channelID)
226 if err != nil {
227- d.l.Log("level", "ERROR", "function", "db.GetChannelSubscribers", "call", "sql.QueryContext", "error", err)
228+ d.l.Error("Filed to query channel subscribers", "call", "sql.QueryContext", "error", err)
229 return nil, err
230 }
231 defer rows.Close()
232@@ -60,7 +60,7 @@ func (d *postgresDB) GetChannelSubscribers(ctx context.Context, channelID string
233 var sub string
234 err = rows.Scan(&sub)
235 if err != nil {
236- d.l.Log("level", "ERROR", "function", "db.GetChannelSubscribers", "call", "sql.Scan", "error", err)
237+ d.l.Error("Failed to scan channel subscribers", "call", "sql.Scan", "error", err)
238 return nil, err
239 }
240 subs = append(subs, sub)
241@@ -80,7 +80,7 @@ ON CONFLICT DO NOTHING
242 func (d *postgresDB) SubscribeUserToChannel(ctx context.Context, username string, channelID string) error {
243 resp, err := d.db.ExecContext(ctx, subscribeUserToChannelQuery, username, channelID)
244 if err != nil {
245- d.l.Log("level", "ERROR", "function", "db.SubscribeUserToChannel", "error", err)
246+ d.l.Error("Failed to subscribe to channel", "call", "sql.ExecContext", "error", err)
247 return err
248 }
249 if affected, _ := resp.RowsAffected(); affected == 0 {
250@@ -95,7 +95,7 @@ var unsubscribeUserFromChannelQuery = `DELETE FROM user_subscriptions WHERE user
251 func (d *postgresDB) UnsubscribeUserFromChannel(ctx context.Context, username string, channelID string) error {
252 resp, err := d.db.ExecContext(ctx, unsubscribeUserFromChannelQuery, username, channelID)
253 if err != nil {
254- d.l.Log("level", "ERROR", "function", "db.SubscribeUserToChannel", "error", err)
255+ d.l.Error("Failed to unsubscribe from channel", "call", "sql.ExecContext", "error", err)
256 return err
257 }
258
259diff --git a/db/psql.go b/db/psql.go
260index 601740b0851563fa4ea2e6f0486042c672dbdd14..8695a3ceac434be9c167bf183aec9e2195b5e2f2 100644
261--- a/db/psql.go
262+++ b/db/psql.go
263@@ -2,19 +2,19 @@ package db
264
265 import (
266 "database/sql"
267+ "log/slog"
268
269 _ "github.com/lib/pq"
270
271 ytrssilConfig "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/config"
272- "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/lib/log"
273 )
274
275 type postgresDB struct {
276- l log.Logger
277+ l *slog.Logger
278 db *sql.DB
279 }
280
281-func NewPostgresDB(log log.Logger, dbCfg ytrssilConfig.DB) (*postgresDB, error) {
282+func NewPostgresDB(log *slog.Logger, dbCfg ytrssilConfig.DB) (*postgresDB, error) {
283 db, err := sql.Open("postgres", dbCfg.DBURI)
284 if err != nil {
285 return nil, err
286diff --git a/db/users.go b/db/users.go
287index c70cae8c0e174117d19bdd7104d834429f7bb652..8faae60a58febab79053662a7a58e900237463ee 100644
288--- a/db/users.go
289+++ b/db/users.go
290@@ -21,13 +21,13 @@ func (d *postgresDB) AuthenticateUser(ctx context.Context, user models.User) (bo
291 return false, nil
292 }
293
294- d.l.Log("level", "ERROR", "function", "db.AuthenticateUser", "error", err)
295+ d.l.Error("Failed to query user for auth", "error", err)
296 return false, err
297 }
298
299 match, err := argon2id.ComparePasswordAndHash(user.Password, hashedPassword)
300 if err != nil {
301- d.l.Log("level", "ERROR", "function", "db.AuthenticateUser", "error", err)
302+ d.l.Error("Failed to hash password", "error", err)
303 return false, err
304 }
305
306@@ -39,7 +39,7 @@ var createUserQuery = `INSERT INTO users (username, password) VALUES ($1, $2) ON
307 func (d *postgresDB) CreateUser(ctx context.Context, user models.User) error {
308 resp, err := d.db.ExecContext(ctx, createUserQuery, user.Username, user.Password)
309 if err != nil {
310- d.l.Log("level", "ERROR", "function", "db.CreateUser", "error", err)
311+ d.l.Error("Failed to create user", "error", err)
312 return err
313 }
314
315@@ -55,7 +55,7 @@ var deleteUserQuery = `DELETE FROM users WHERE username = $1`
316 func (d *postgresDB) DeleteUser(ctx context.Context, username string) error {
317 _, err := d.db.ExecContext(ctx, deleteUserQuery, username)
318 if err != nil {
319- d.l.Log("level", "ERROR", "function", "db.DeleteUser", "error", err)
320+ d.l.Error("Failed to delete user", "error", err)
321 return err
322 }
323
324diff --git a/db/videos.go b/db/videos.go
325index ee8e82e611c0024ea7e9dffde77c7de1d3207ba2..05b5f6665c41b62d1e4436cc6d64c34e9ace2391 100644
326--- a/db/videos.go
327+++ b/db/videos.go
328@@ -27,7 +27,7 @@ var getNewVideosQuery = `
329 func (d *postgresDB) GetNewVideos(ctx context.Context, username string) ([]models.Video, error) {
330 rows, err := d.db.QueryContext(ctx, getNewVideosQuery, username)
331 if err != nil {
332- d.l.Log("level", "ERROR", "function", "db.GetNewVideos", "call", "sql.QueryContext", "error", err)
333+ d.l.Error("Failed to query new videos", "call", "sql.QueryContext", "error", err)
334 return nil, err
335 }
336 defer rows.Close()
337@@ -43,7 +43,7 @@ func (d *postgresDB) GetNewVideos(ctx context.Context, username string) ([]model
338 &video.ChannelName,
339 )
340 if err != nil {
341- d.l.Log("level", "ERROR", "function", "db.GetNewVideos", "call", "sql.Scan", "error", err)
342+ d.l.Error("Failed to scan rows for get new videos", "call", "sql.Scan", "error", err)
343 return nil, err
344 }
345 videos = append(videos, video)
346@@ -72,7 +72,7 @@ var getWatchedVideosQuery = `
347 func (d *postgresDB) GetWatchedVideos(ctx context.Context, username string) ([]models.Video, error) {
348 rows, err := d.db.QueryContext(ctx, getWatchedVideosQuery, username)
349 if err != nil {
350- d.l.Log("level", "ERROR", "function", "db.GetWatchedVideos", "call", "sql.QueryContext", "error", err)
351+ d.l.Error("Failed to query for watched videos", "call", "sql.QueryContext", "error", err)
352 return nil, err
353 }
354 defer rows.Close()
355@@ -88,7 +88,7 @@ func (d *postgresDB) GetWatchedVideos(ctx context.Context, username string) ([]m
356 &video.ChannelName,
357 )
358 if err != nil {
359- d.l.Log("level", "ERROR", "function", "db.GetWatchedVideos", "call", "sql.Scan", "error", err)
360+ d.l.Error("Failed to scan rows for watched videos", "call", "sql.Scan", "error", err)
361 return nil, err
362 }
363 videos = append(videos, video)
364@@ -110,7 +110,7 @@ ON CONFLICT DO NOTHING
365 func (d *postgresDB) AddVideo(ctx context.Context, video models.Video, channelID string) error {
366 resp, err := d.db.ExecContext(ctx, addVideoQuery, video.ID, video.Title, video.PublishedTime, channelID)
367 if err != nil {
368- d.l.Log("level", "ERROR", "function", "db.AddVideo", "call", "sql.Exec", "error", err)
369+ d.l.Error("Failed to add video", "call", "sql.Exec", "error", err)
370 return err
371 }
372 if affected, _ := resp.RowsAffected(); affected == 0 {
373@@ -125,7 +125,7 @@ var addVideoToUserQuery = `INSERT INTO user_videos (username, video_id) VALUES (
374 func (d *postgresDB) AddVideoToUser(ctx context.Context, username string, videoID string) error {
375 _, err := d.db.ExecContext(ctx, addVideoToUserQuery, username, videoID)
376 if err != nil {
377- d.l.Log("level", "ERROR", "function", "db.AddVideoToUser", "error", err)
378+ d.l.Error("Failed to add video to user", "error", err)
379 return err
380 }
381
382@@ -139,7 +139,7 @@ func (d *postgresDB) SetVideoWatchTime(
383 ) error {
384 _, err := d.db.ExecContext(ctx, setVideoWatchTimeQuery, watchTime, username, videoID)
385 if err != nil {
386- d.l.Log("level", "ERROR", "function", "db.WatchVideo", "error", err)
387+ d.l.Error("", "error", err)
388 return err
389 }
390
391diff --git a/feedparser/feedparser.go b/feedparser/feedparser.go
392index 2dbc4a5a3f52732542f90b9642968f8b5a740932..853304c59734a085c9ff4bf9d118955e60d87ee4 100644
393--- a/feedparser/feedparser.go
394+++ b/feedparser/feedparser.go
395@@ -5,12 +5,11 @@ import (
396 "errors"
397 "fmt"
398 "io"
399+ "log/slog"
400 "net/http"
401 "sync"
402
403 "github.com/paulrosania/go-charset/charset"
404-
405- "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/lib/log"
406 )
407
408 var (
409@@ -26,10 +25,10 @@ type Parser interface {
410 }
411
412 type parser struct {
413- log log.Logger
414+ log *slog.Logger
415 }
416
417-func NewParser(l log.Logger) *parser {
418+func NewParser(l *slog.Logger) *parser {
419 return &parser{
420 log: l,
421 }
422@@ -38,13 +37,13 @@ func NewParser(l log.Logger) *parser {
423 func (p *parser) fetch(url string) (io.ReadCloser, error) {
424 req, err := http.NewRequest("GET", url, nil)
425 if err != nil {
426- p.log.Log("level", "ERROR", "function", "feedparser.fetch", "call", "http.NewRequest", "error", err)
427+ p.log.Error("Failed to create request", "call", "http.NewRequest", "error", err)
428 return nil, err
429 }
430
431 response, err := http.DefaultClient.Do(req)
432 if err != nil {
433- p.log.Log("level", "ERROR", "function", "feedparser.fetch", "call", "http.Do", "error", err)
434+ p.log.Error("Failed to fetch feed", "call", "http.Do", "error", err)
435 return nil, err
436 }
437
438@@ -71,7 +70,7 @@ func (p *parser) Parse(channelID string) (*Channel, error) {
439
440 var channel Channel
441 if err := xmlDecoder.Decode(&channel); err != nil {
442- p.log.Log("level", "ERROR", "function", "feedparser.Parse", "call", "xml.Decode", "error", err)
443+ p.log.Error("Failed to decode XML for RSS feed", "call", "xml.Decode", "error", err)
444 return nil, fmt.Errorf("%w: %s", ErrParseFailed, err.Error())
445 }
446 channel.ID = channelID
447diff --git a/go.mod b/go.mod
448index b71422033684c035c3a1ff5e40340d206c88443f..cebd7cb8ad113d0d975ad677790db6aeb51e3729 100644
449--- a/go.mod
450+++ b/go.mod
451@@ -1,46 +1,49 @@
452 module gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api
453
454-go 1.19
455+go 1.23.0
456
457 require (
458 github.com/alexedwards/argon2id v1.0.0
459- github.com/gin-gonic/gin v1.10.1
460- github.com/go-kit/log v0.2.1
461+ github.com/gin-gonic/gin v1.11.0
462 github.com/jessevdk/go-flags v1.6.1
463 github.com/lib/pq v1.10.9
464 github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c
465- github.com/stretchr/testify v1.10.0
466+ github.com/stretchr/testify v1.11.1
467 )
468
469 require (
470- github.com/bytedance/sonic v1.11.6 // indirect
471- github.com/bytedance/sonic/loader v0.1.1 // indirect
472- github.com/cloudwego/base64x v0.1.4 // indirect
473- github.com/cloudwego/iasm v0.2.0 // indirect
474+ github.com/bytedance/sonic v1.14.0 // indirect
475+ github.com/bytedance/sonic/loader v0.3.0 // indirect
476+ github.com/cloudwego/base64x v0.1.6 // indirect
477 github.com/davecgh/go-spew v1.1.1 // indirect
478- github.com/gabriel-vasile/mimetype v1.4.3 // indirect
479- github.com/gin-contrib/sse v0.1.0 // indirect
480- github.com/go-logfmt/logfmt v0.5.1 // indirect
481+ github.com/gabriel-vasile/mimetype v1.4.8 // indirect
482+ github.com/gin-contrib/sse v1.1.0 // indirect
483 github.com/go-playground/locales v0.14.1 // indirect
484 github.com/go-playground/universal-translator v0.18.1 // indirect
485- github.com/go-playground/validator/v10 v10.20.0 // indirect
486+ github.com/go-playground/validator/v10 v10.27.0 // indirect
487 github.com/goccy/go-json v0.10.2 // indirect
488- github.com/google/go-cmp v0.5.8 // indirect
489+ github.com/goccy/go-yaml v1.18.0 // indirect
490 github.com/json-iterator/go v1.1.12 // indirect
491- github.com/klauspost/cpuid/v2 v2.2.7 // indirect
492+ github.com/klauspost/cpuid/v2 v2.3.0 // indirect
493 github.com/leodido/go-urn v1.4.0 // indirect
494 github.com/mattn/go-isatty v0.0.20 // indirect
495 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
496 github.com/modern-go/reflect2 v1.0.2 // indirect
497- github.com/pelletier/go-toml/v2 v2.2.2 // indirect
498+ github.com/pelletier/go-toml/v2 v2.2.4 // indirect
499 github.com/pmezard/go-difflib v1.0.0 // indirect
500+ github.com/quic-go/qpack v0.5.1 // indirect
501+ github.com/quic-go/quic-go v0.54.0 // indirect
502 github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
503- github.com/ugorji/go/codec v1.2.12 // indirect
504- golang.org/x/arch v0.8.0 // indirect
505- golang.org/x/crypto v0.23.0 // indirect
506- golang.org/x/net v0.25.0 // indirect
507- golang.org/x/sys v0.21.0 // indirect
508- golang.org/x/text v0.15.0 // indirect
509- google.golang.org/protobuf v1.34.1 // indirect
510+ github.com/ugorji/go/codec v1.3.0 // indirect
511+ go.uber.org/mock v0.5.0 // indirect
512+ golang.org/x/arch v0.20.0 // indirect
513+ golang.org/x/crypto v0.40.0 // indirect
514+ golang.org/x/mod v0.25.0 // indirect
515+ golang.org/x/net v0.42.0 // indirect
516+ golang.org/x/sync v0.16.0 // indirect
517+ golang.org/x/sys v0.35.0 // indirect
518+ golang.org/x/text v0.27.0 // indirect
519+ golang.org/x/tools v0.34.0 // indirect
520+ google.golang.org/protobuf v1.36.9 // indirect
521 gopkg.in/yaml.v3 v3.0.1 // indirect
522 )
523diff --git a/go.sum b/go.sum
524index fd087c83db106d0209e1124a990c1af62efcb85d..c3639762fd4126bd74dfbf152345cd608530a08b 100644
525--- a/go.sum
526+++ b/go.sum
527@@ -1,46 +1,41 @@
528 github.com/alexedwards/argon2id v1.0.0 h1:wJzDx66hqWX7siL/SRUmgz3F8YMrd/nfX/xHHcQQP0w=
529 github.com/alexedwards/argon2id v1.0.0/go.mod h1:tYKkqIjzXvZdzPvADMWOEZ+l6+BD6CtBXMj5fnJppiw=
530-github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
531-github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
532-github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
533-github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
534-github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
535-github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
536-github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
537-github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
538+github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ=
539+github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA=
540+github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA=
541+github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
542+github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
543+github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
544 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
545 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
546 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
547-github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
548-github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
549-github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
550-github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
551-github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
552-github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
553-github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
554-github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
555-github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
556-github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
557+github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
558+github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
559+github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
560+github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
561+github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
562+github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls=
563 github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
564+github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
565 github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
566 github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
567 github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
568 github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
569-github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
570-github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
571+github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
572+github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
573 github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
574 github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
575-github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
576-github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
577+github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
578+github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
579+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
580+github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
581 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
582 github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4=
583 github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc=
584 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
585 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
586-github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
587-github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
588-github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
589-github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
590+github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
591+github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
592 github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
593 github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
594 github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
595@@ -54,48 +49,53 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
596 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
597 github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c h1:P6XGcuPTigoHf4TSu+3D/7QOQ1MbL6alNwrGhcW7sKw=
598 github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c/go.mod h1:YnNlZP7l4MhyGQ4CBRwv6ohZTPrUJJZtEv4ZgADkbs4=
599-github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
600-github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
601+github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
602+github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
603 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
604 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
605+github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
606+github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
607+github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg=
608+github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
609 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
610 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
611 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
612-github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
613 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
614-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
615 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
616 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
617 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
618-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
619-github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
620-github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
621-github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
622+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
623+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
624 github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
625 github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
626-github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
627diff --git a/handler/handler.go b/handler/handler.go
628index 7a0a0413d302e4cbab2647e23e95d2868aabde9f..7f1a22de4e57002b6741345957b59cb10f5fe3e8 100644
629--- a/handler/handler.go
630+++ b/handler/handler.go
631@@ -2,10 +2,10 @@ package handler
632
633 import (
634 "context"
635+ "log/slog"
636
637 "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/db"
638 "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/feedparser"
639- "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/lib/log"
640 "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/models"
641 )
642
643@@ -21,12 +21,12 @@ type Handler interface {
644 }
645
646 type handler struct {
647- log log.Logger
648+ log *slog.Logger
649 db db.DB
650 parser feedparser.Parser
651 }
652
653-func New(log log.Logger, db db.DB, parser feedparser.Parser) *handler {
654+func New(log *slog.Logger, db db.DB, parser feedparser.Parser) *handler {
655 return &handler{
656 log: log,
657 db: db,
658diff --git a/handler/handler_test.go b/handler/handler_test.go
659index 53ef3613525e53821ce95ec95b742cac22c5f99f..902bc00157c42c16a57fc2ac1b7c0751f4a4637d 100644
660--- a/handler/handler_test.go
661+++ b/handler/handler_test.go
662@@ -2,13 +2,14 @@ package handler
663
664 import (
665 "context"
666+ "io"
667+ "log/slog"
668 "testing"
669 "time"
670
671 "github.com/stretchr/testify/assert"
672
673 "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/config"
674- "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/lib/log"
675 db_mock "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/mocks/db"
676 parser_mock "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/mocks/feedparser"
677 "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/models"
678@@ -21,9 +22,7 @@ func init() {
679 }
680
681 func TestGetNewVideos(t *testing.T) {
682- // Arrange
683- l := log.NewNopLogger()
684-
685+ l := slog.New(slog.NewTextHandler(io.Discard, nil))
686 handler := New(l, &db_mock.DBMock{
687 GetNewVideosFunc: func(ctx context.Context, username string) ([]models.Video, error) {
688 return []models.Video{
689@@ -37,11 +36,8 @@ func TestGetNewVideos(t *testing.T) {
690 }, nil
691 },
692 }, &parser_mock.ParserMock{})
693-
694- // Act
695 resp, err := handler.GetNewVideos(context.TODO(), "username")
696
697- // Assert
698 if assert.NoError(t, err) {
699 if assert.NotNil(t, resp) {
700 assert.Equal(t, resp[0].ID, "test")
701diff --git a/handler/videos.go b/handler/videos.go
702index 695b161040b5d68f1bab54127dcba4697ce5b7fe..8936945698a298115716b0f1299526d74f045387 100644
703--- a/handler/videos.go
704+++ b/handler/videos.go
705@@ -23,14 +23,14 @@ func (h *handler) GetWatchedVideos(ctx context.Context, username string) ([]mode
706 func (h *handler) addVideoToAllSubscribers(ctx context.Context, channelID string, videoID string) error {
707 subs, err := h.db.GetChannelSubscribers(ctx, channelID)
708 if err != nil {
709- h.log.Log("level", "ERROR", "call", "db.GetChannelSubscribers", "err", err)
710+ h.log.Error("failed to get channel subscribers", "call", "db.GetChannelSubscribers", "err", err)
711 return err
712 }
713
714 for _, sub := range subs {
715 err = h.db.AddVideoToUser(ctx, sub, videoID)
716 if err != nil {
717- h.log.Log("level", "ERROR", "call", "db.AddVideoToUser", "err", err)
718+ h.log.Error("Failed to add video to user", "call", "db.AddVideoToUser", "err", err)
719 continue
720 }
721 }
722@@ -42,7 +42,7 @@ func (h *handler) addVideosForChannel(ctx context.Context, parsedChannel *feedpa
723 for _, parsedVideo := range parsedChannel.Videos {
724 date, err := parsedVideo.Published.Parse()
725 if err != nil {
726- h.log.Log("level", "WARNING", "call", "feedparser.Parse", "err", err)
727+ h.log.Warn("Failed to parse video information", "call", "feedparser.Parse", "err", err)
728 continue
729 }
730
731@@ -55,7 +55,7 @@ func (h *handler) addVideosForChannel(ctx context.Context, parsedChannel *feedpa
732 err = h.db.AddVideo(ctx, video, parsedChannel.ID)
733 if err != nil {
734 if !errors.Is(err, db.ErrVideoExists) {
735- h.log.Log("level", "WARNING", "call", "db.AddVideo", "err", err)
736+ h.log.Warn("Failed to save video to db", "call", "db.AddVideo", "err", err)
737 }
738 continue
739 }
740@@ -67,7 +67,7 @@ func (h *handler) addVideosForChannel(ctx context.Context, parsedChannel *feedpa
741 }
742
743 func (h *handler) FetchVideos(ctx context.Context) error {
744- h.log.Log("level", "INFO", "msg", "fetching new videos for all channels")
745+ h.log.Info("Fetching new videos for all channels")
746
747 channels, err := h.db.ListChannels(ctx)
748 if err != nil {
749diff --git a/httpserver/ytrssil/api_setup_test.go b/httpserver/ytrssil/api_setup_test.go
750index 925a7e51865e5b4cb77ead943cabbd79ed077a3d..f4a230d1774d971960d52c7dad40f1e84c867373 100644
751--- a/httpserver/ytrssil/api_setup_test.go
752+++ b/httpserver/ytrssil/api_setup_test.go
753@@ -2,6 +2,8 @@ package ytrssil_test
754
755 import (
756 "fmt"
757+ "io"
758+ "log/slog"
759 "net/http"
760 "net/http/httptest"
761 "testing"
762@@ -14,7 +16,6 @@ import (
763 "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/handler"
764 "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/httpserver/auth"
765 "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/httpserver/ytrssil"
766- "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/lib/log"
767 )
768
769 var testConfig config.Config
770@@ -26,7 +27,7 @@ func init() {
771 }
772
773 func setupTestServer(t *testing.T) *http.Server {
774- l := log.NewNopLogger()
775+ l := slog.New(slog.NewTextHandler(io.Discard, nil))
776
777 handler := handler.New(l, nil, nil)
778
779diff --git a/httpserver/ytrssil/server.go b/httpserver/ytrssil/server.go
780index 548d4e985c29b2645bc2440310e6c418f8de3aa0..ebbe8222d06fa2ed414ab59aaa3ceb3fef7d8616 100644
781--- a/httpserver/ytrssil/server.go
782+++ b/httpserver/ytrssil/server.go
783@@ -1,33 +1,48 @@
784 package ytrssil
785
786 import (
787+ "fmt"
788+ "log/slog"
789 "net/http"
790+ "time"
791
792 "github.com/gin-gonic/gin"
793
794 "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/handler"
795- "gitea.theedgeofrage.com/TheEdgeOfRage/ytrssil-api/lib/log"
796 )
797
798 type server struct {
799- log log.Logger
800+ log *slog.Logger
801 handler handler.Handler
802 }
803
804-func NewServer(log log.Logger, handler handler.Handler) (*server, error) {
805+func NewServer(log *slog.Logger, handler handler.Handler) (*server, error) {
806 return &server{log: log, handler: handler}, nil
807 }
808
809+func ginLogFormatter(param gin.LogFormatterParams) string {
810+ return fmt.Sprintf("timestamp=%v status=%d duration=%v size=%v ip=%s method=%s path=%#v error=%s\n",
811+ param.TimeStamp.UTC().Format(time.RFC3339Nano),
812+ param.StatusCode,
813+ param.Latency,
814+ param.BodySize,
815+ param.ClientIP,
816+ param.Method,
817+ param.Path,
818+ param.ErrorMessage,
819+ )
820+}
821+
822 func (s *server) Healthz(c *gin.Context) {
823 c.String(http.StatusOK, "healthy")
824 }
825
826 // SetupGinRouter sets up routes for all APIs on a Gin server (aka router)
827-func SetupGinRouter(l log.Logger, handler handler.Handler, authMiddleware func(c *gin.Context)) (*gin.Engine, error) {
828+func SetupGinRouter(l *slog.Logger, handler handler.Handler, authMiddleware func(c *gin.Context)) (*gin.Engine, error) {
829 engine := gin.New()
830 // Middlewares are executed top to bottom in a stack-like manner
831 engine.Use(
832- gin.LoggerWithFormatter(log.GinFormatterWithUTCAndBodySize),
833+ gin.LoggerWithFormatter(ginLogFormatter),
834 gin.Recovery(), // Recovery needs to go before other middlewares to catch panics
835 )
836
837diff --git a/lib/log/log.go b/lib/log/log.go
838deleted file mode 100644
839index 8efd86e2d4b1fa079b8a5553dfad3649c799759a..0000000000000000000000000000000000000000
840--- a/lib/log/log.go
841+++ /dev/null
842@@ -1,60 +0,0 @@
843-package log
844-
845-import (
846- "fmt"
847- stdlog "log"
848- "os"
849-
850- "github.com/gin-gonic/gin"
851- "github.com/go-kit/log"
852-)
853-
854-type Logger interface {
855- Log(keyvals ...interface{}) error
856-}
857-
858-func NewLogger() Logger {
859- var logger log.Logger
860- logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
861- stdlog.SetOutput(log.NewStdlibAdapter(logger))
862- logger = log.With(logger, "ts", log.DefaultTimestampUTC)
863- // We're wrapping gotkit, so DefaultCaller would show: log.go:23
864- logger = log.With(logger, "caller", log.Caller(3))
865-
866- return logger
867-}
868-
869-// NewNopLogger is go-kit/log.NewNopLogger
870-func NewNopLogger() log.Logger {
871- return log.NewNopLogger()
872-}
873-
874-// NewSyncLogger is useful for debugging, use sparingly
875-func NewSyncLogger() log.Logger {
876- return log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
877-}
878-
879-// Str is used to log unknown types using fmt
880-func Str(i any) string { return fmt.Sprintf("%+v", i) }
881-
882-// GinFormatterWithUTCAndBodySize is the default gin loggger with:
883-// - UTC times
884-// - logs the response size in bytes
885-func GinFormatterWithUTCAndBodySize(param gin.LogFormatterParams) string {
886- var statusColor, methodColor, resetColor string
887- if param.IsOutputColor() {
888- statusColor = param.StatusCodeColor()
889- methodColor = param.MethodColor()
890- resetColor = param.ResetColor()
891- }
892- return fmt.Sprintf("[DUNE] %v |%s %3d %s| %13v | %6v bytes | %15s |%s %-7s %s %#v\n%s",
893- param.TimeStamp.UTC().Format("2006/01/02 15:04:05.000"),
894- statusColor, param.StatusCode, resetColor,
895- param.Latency,
896- param.BodySize,
897- param.ClientIP,
898- methodColor, param.Method, resetColor,
899- param.Path,
900- param.ErrorMessage,
901- )
902-}