• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rm-hull / gps-routes-api / 14010624918

22 Mar 2025 05:04PM UTC coverage: 0.0%. Remained the same
14010624918

Pull #15

github

web-flow
Merge 02f474c82 into 7f5e60cab
Pull Request #15: Convert to structured JSON logging

0 of 25 new or added lines in 1 file covered. (0.0%)

0 of 891 relevant lines covered (0.0%)

0.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/cmds/http_server.go
1
package cmds
2

3
import (
4
        "context"
5
        "log"
6
        "log/slog"
7
        "os"
8
        "runtime/debug"
9
        "time"
10

11
        "github.com/Depado/ginprom"
12
        ratelimit "github.com/JGLTechnologies/gin-rate-limit"
13
        "github.com/aurowora/compress"
14
        "github.com/earthboundkid/versioninfo/v2"
15
        "github.com/gin-contrib/cors"
16
        limits "github.com/gin-contrib/size"
17
        "github.com/gin-gonic/gin"
18
        "github.com/jackc/pgx/v5/stdlib"
19
        sloggin "github.com/samber/slog-gin"
20
        healthcheck "github.com/tavsec/gin-healthcheck"
21
        "github.com/tavsec/gin-healthcheck/checks"
22
        hc_config "github.com/tavsec/gin-healthcheck/config"
23
        cachecontrol "go.eigsys.de/gin-cachecontrol/v2"
24

25
        "github.com/rm-hull/gps-routes-api/db"
26
        "github.com/rm-hull/gps-routes-api/middlewares"
27
        "github.com/rm-hull/gps-routes-api/repositories"
28
        "github.com/rm-hull/gps-routes-api/routes"
29
        "github.com/rm-hull/gps-routes-api/services"
30
)
31

32
func NewHttpServer() {
×
33

×
34
        // Connect to Postgres
×
35
        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
×
36
        defer cancel()
×
37

×
NEW
38
        dbConfig := db.ConfigFromEnv()
×
NEW
39
        pool, err := db.NewDBPool(ctx, dbConfig)
×
40
        if err != nil {
×
41
                log.Fatalf("failed to create database pool: %v", err)
×
42
        }
×
43
        defer pool.Close()
×
44

×
45
        engine := gin.New()
×
NEW
46
        logger := createLogger()
×
NEW
47

×
48
        prometheus := ginprom.New(
×
49
                ginprom.Engine(engine),
×
50
                ginprom.Namespace("gps_routes"),
×
51
                ginprom.Subsystem("api"),
×
52
        )
×
53

×
54
        rlStore := ratelimit.InMemoryStore(&ratelimit.InMemoryOptions{
×
55
                Rate:  time.Second,
×
56
                Limit: 5,
×
57
        })
×
58
        rateLimiter := ratelimit.RateLimiter(rlStore, &ratelimit.Options{
×
59
                ErrorHandler: func(c *gin.Context, info ratelimit.Info) {
×
60
                        c.JSON(429, gin.H{
×
61
                                "error":   "Too many requests",
×
62
                                "message": "Try again in " + time.Until(info.ResetTime).String(),
×
63
                        })
×
64
                },
×
65
                KeyFunc: func(c *gin.Context) string {
×
66
                        return c.ClientIP()
×
67
                },
×
68
        })
69

70
        engine.Use(
×
NEW
71
                sloggin.NewWithConfig(logger, sloggin.Config{
×
NEW
72
                        WithSpanID:  true,
×
NEW
73
                        WithTraceID: true,
×
NEW
74
                        Filters: []sloggin.Filter{
×
NEW
75
                                sloggin.IgnorePath("/healthz", "/metrics"),
×
NEW
76
                        }}),
×
77
                gin.Recovery(),
×
78
                cors.Default(),
×
79
                middlewares.ErrorHandler(),
×
80
                compress.Compress(),
×
81
                limits.RequestSizeLimiter(10*1024),
×
82
                cachecontrol.New(cachecontrol.CacheAssetsForeverPreset),
×
83
                prometheus.Instrument(),
×
84
                rateLimiter,
×
85
        )
×
86

×
87
        db := stdlib.OpenDB(*pool.Config().ConnConfig)
×
88
        defer db.Close()
×
89
        err = healthcheck.New(engine, hc_config.DefaultConfig(), []checks.Check{
×
90
                checks.SqlCheck{Sql: db},
×
91
        })
×
92
        if err != nil {
×
93
                log.Fatalf("failed to initialize healthcheck: %v", err)
×
94
        }
×
95

NEW
96
        pg := repositories.NewPostgresRouteRepository(pool, dbConfig.Schema)
×
97
        repo := repositories.NewCachedRepository(prometheus, pg)
×
98
        service := services.NewRoutesService(repo)
×
99

×
100
        router := routes.NewRouterWithGinEngine(engine, routes.ApiHandleFunctions{
×
101
                RoutesAPI: routes.RoutesAPI{
×
102
                        Service: service,
×
103
                },
×
104
        })
×
105

×
NEW
106
        logger.
×
NEW
107
                With("version", versioninfo.Short()).
×
NEW
108
                Info("Server started")
×
NEW
109

×
NEW
110
        err = router.Run(":8080")
×
NEW
111
        logger.
×
NEW
112
                With("error", err).
×
NEW
113
                With("stack", string(debug.Stack())).
×
NEW
114
                Error("Unhandled/unexpected crash")
×
115
}
116

NEW
117
func createLogger() *slog.Logger {
×
NEW
118
        if gin.IsDebugging() {
×
NEW
119
                return slog.New(slog.NewTextHandler(os.Stdout, nil))
×
NEW
120
        }
×
121

NEW
122
        return slog.New(slog.NewJSONHandler(os.Stdout, nil))
×
123
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc