-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
135 lines (113 loc) · 3.78 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package main
import (
"context"
"database/sql"
"flag"
"fmt"
"net/http"
"os"
"time"
dbx "github.com/go-ozzo/ozzo-dbx"
routing "github.com/go-ozzo/ozzo-routing/v2"
"github.com/go-ozzo/ozzo-routing/v2/content"
"github.com/go-ozzo/ozzo-routing/v2/cors"
_ "github.com/lib/pq"
"github.com/pauluswi/rhine/internal/auth"
"github.com/pauluswi/rhine/internal/config"
"github.com/pauluswi/rhine/internal/errors"
"github.com/pauluswi/rhine/internal/healthcheck"
"github.com/pauluswi/rhine/internal/trxhistory"
"github.com/pauluswi/rhine/pkg/accesslog"
"github.com/pauluswi/rhine/pkg/dbcontext"
"github.com/pauluswi/rhine/pkg/log"
rh "github.com/pauluswi/rhine/pkg/repohelper"
)
// Version indicates the current version of the application.
var Version = "1.0.0"
var flagConfig = flag.String("config", "./config/local.yml", "path to the config file")
func main() {
flag.Parse()
// create root logger tagged with server version
logger := log.New().With(context.TODO(), "version", Version)
// load application configurations
cfg, err := config.Load(*flagConfig, logger)
if err != nil {
logger.Errorf("failed to load application configuration: %s", err)
os.Exit(-1)
}
// connect to the database
db, err := dbx.MustOpen("postgres", cfg.DSN)
if err != nil {
logger.Error(err)
os.Exit(-1)
}
db.QueryLogFunc = logDBQuery(logger)
db.ExecLogFunc = logDBExec(logger)
defer func() {
if err := db.Close(); err != nil {
logger.Error(err)
}
}()
// build HTTP server
address := fmt.Sprintf(":%v", cfg.ServerPort)
hs := &http.Server{
Addr: address,
Handler: buildHandler(logger, dbcontext.New(db), cfg),
}
// start the HTTP server with graceful shutdown
go routing.GracefulShutdown(hs, 10*time.Second, logger.Infof)
logger.Infof("server %v is running at %v", Version, address)
if err := hs.ListenAndServe(); err != nil && err != http.ErrServerClosed {
logger.Error(err)
os.Exit(-1)
}
}
// buildHandler sets up the HTTP routing and builds an HTTP handler.
func buildHandler(logger log.Logger, db *dbcontext.DB, cfg *config.Config) http.Handler {
router := routing.New()
router.Use(
accesslog.Handler(logger),
errors.Handler(logger),
content.TypeNegotiator(content.JSON),
cors.Handler(cors.AllowAll),
)
healthcheck.RegisterHandlers(router, Version)
rg := router.Group("/v1")
authHandler := auth.Handler(cfg.JWTSigningKey)
kafkaRepo := rh.KafkaConnection(cfg)
redisRepo := rh.RedisConnection(cfg)
kafkaSvc := trxhistory.NewKafkaService(kafkaRepo, redisRepo)
trxhistory.RegisterHandlers(rg.Group(""),
trxhistory.NewService(trxhistory.NewRepository(db, logger), kafkaRepo, redisRepo, logger),
authHandler, logger,
)
auth.RegisterHandlers(rg.Group(""),
auth.NewService(cfg.JWTSigningKey, cfg.JWTExpiration, logger),
logger,
)
ctx := context.Background()
go func() { // just assume that this is another service that register kafka topic
kafkaSvc.ReadMessage(ctx, trxhistory.NewRepository(db, logger), redisRepo)
}()
return router
}
// logDBQuery returns a logging function that can be used to log SQL queries.
func logDBQuery(logger log.Logger) dbx.QueryLogFunc {
return func(ctx context.Context, t time.Duration, sql string, rows *sql.Rows, err error) {
if err == nil {
logger.With(ctx, "duration", t.Milliseconds(), "sql", sql).Info("DB query successful")
} else {
logger.With(ctx, "sql", sql).Errorf("DB query error: %v", err)
}
}
}
// logDBExec returns a logging function that can be used to log SQL executions.
func logDBExec(logger log.Logger) dbx.ExecLogFunc {
return func(ctx context.Context, t time.Duration, sql string, result sql.Result, err error) {
if err == nil {
logger.With(ctx, "duration", t.Milliseconds(), "sql", sql).Info("DB execution successful")
} else {
logger.With(ctx, "sql", sql).Errorf("DB execution error: %v", err)
}
}
}