logging
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 2m23s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 2m23s
This commit is contained in:
parent
36cbda5e7a
commit
f00226a0d6
@ -52,6 +52,8 @@
|
||||
### Logging
|
||||
|
||||
- Zap JSON logs
|
||||
- Uber Zap logger will be initialized in `cmd/api/main.go` and injected into services/middleware (no global loggers).
|
||||
- Logs will be written directly to a file from the application, with log rotation implemented via `lumberjack`.
|
||||
- Correlation/request ID in middleware
|
||||
- Structured error logging from middleware and service boundaries
|
||||
|
||||
@ -64,6 +66,7 @@
|
||||
- SQL-only migrations
|
||||
- Keep up/down migration scripts
|
||||
- Run on startup in non-prod optional, required in CI/CD/deploy step
|
||||
- Migrations are securely bundled into the binary using Go's `embed.FS` from a dedicated `migrations` package to isolate them from `internal` db logic.
|
||||
|
||||
### SQLC
|
||||
|
||||
@ -82,7 +85,10 @@
|
||||
- `emit_interface: true` (generated `Querier` interface)
|
||||
- `emit_json_tags: false` (can be revisited if API structs are returned directly)
|
||||
- Initial queries implemented for users: `GetUser`, `CreateUser`, `DeleteUser`
|
||||
- DB pool wiring into `cmd/api` and service construction is planned next
|
||||
- **Goose startup migrations** have been wired into `cmd/api/main.go`, utilizing the `embed.FS` strategy and logging via Zap adapter.
|
||||
- DB pool is successfully wired in `cmd/api`.
|
||||
- Environment-aware Zap logger is configured (development vs production).
|
||||
- **Next Planned:** Implement application-level file logging with rotation (using `lumberjack`), and build initial Gin API routes for health checks.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -2,16 +2,21 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"git.kanopo.dev/rhythm/rhythm-backend/internal/config"
|
||||
"git.kanopo.dev/rhythm/rhythm-backend/internal/db"
|
||||
"git.kanopo.dev/rhythm/rhythm-backend/internal/logger"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfg := config.Load()
|
||||
log := logger.New(cfg.AppEnv)
|
||||
defer log.Sync()
|
||||
|
||||
log.Info("Starting rhythm")
|
||||
|
||||
ctx := context.Background()
|
||||
pool, err := pgxpool.New(ctx, cfg.DbUrl)
|
||||
if err != nil {
|
||||
@ -25,9 +30,9 @@ func main() {
|
||||
if err := pool.Ping(ctx); err != nil {
|
||||
log.Fatalf("ping to db failed %v", err.Error())
|
||||
}
|
||||
log.Printf("successfully connected to database")
|
||||
log.Info("successfully connected to database")
|
||||
|
||||
db.RunMigrations(cfg.DbUrl)
|
||||
db.RunMigrations(cfg.DbUrl, log)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
3
go.mod
3
go.mod
@ -5,6 +5,7 @@ go 1.26.2
|
||||
require (
|
||||
github.com/jackc/pgx/v5 v5.9.2
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/pressly/goose v2.7.0+incompatible
|
||||
github.com/pressly/goose/v3 v3.27.0
|
||||
)
|
||||
|
||||
@ -13,8 +14,10 @@ require (
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/mfridman/interpolate v0.0.2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/sethvargo/go-retry v0.3.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.1
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
)
|
||||
|
||||
6
go.sum
6
go.sum
@ -21,8 +21,12 @@ github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6B
|
||||
github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg=
|
||||
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
|
||||
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pressly/goose v2.7.0+incompatible h1:PWejVEv07LCerQEzMMeAtjuyCKbyprZ/LBa6K5P0OCQ=
|
||||
github.com/pressly/goose v2.7.0+incompatible/go.mod h1:m+QHWCqxR3k8D9l7qfzuC/djtlfzxr34mozWDYEu1z8=
|
||||
github.com/pressly/goose/v3 v3.27.0 h1:/D30gVTuQhu0WsNZYbJi4DMOsx1lNq+6SkLe+Wp59BM=
|
||||
github.com/pressly/goose/v3 v3.27.0/go.mod h1:3ZBeCXqzkgIRvrEMDkYh1guvtoJTU5oMMuDdkutoM78=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
@ -36,6 +40,8 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
||||
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=
|
||||
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
|
||||
@ -8,6 +8,7 @@ import (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
AppEnv string
|
||||
DbUrl string
|
||||
}
|
||||
|
||||
@ -24,7 +25,13 @@ func Load() Config {
|
||||
dbUrl = fmt.Sprintf("postgres://%v:%v@%v:%v/%v?sslmode=disable", username, password, host, port, name)
|
||||
}
|
||||
|
||||
appEnv := os.Getenv("APP_ENV")
|
||||
if appEnv == "" {
|
||||
appEnv = "development"
|
||||
}
|
||||
|
||||
cfg := Config{
|
||||
AppEnv: appEnv,
|
||||
DbUrl: dbUrl,
|
||||
}
|
||||
|
||||
|
||||
@ -4,17 +4,22 @@ import (
|
||||
"database/sql"
|
||||
"log"
|
||||
|
||||
"git.kanopo.dev/rhythm/rhythm-backend/internal/logger"
|
||||
"git.kanopo.dev/rhythm/rhythm-backend/migrations"
|
||||
_ "github.com/jackc/pgx/v5/stdlib"
|
||||
"github.com/pressly/goose/v3"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func RunMigrations(dbURL string) {
|
||||
func RunMigrations(dbURL string, zLog *zap.SugaredLogger) {
|
||||
db, err := sql.Open("pgx", dbURL)
|
||||
if err != nil {
|
||||
log.Fatalf("open db for migrations: %v", err.Error())
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
goose.SetLogger(&logger.GooseLogger{SugaredLogger: zLog})
|
||||
|
||||
// 2. Pass the exported FS to Goose!
|
||||
goose.SetBaseFS(migrations.FS)
|
||||
if err := goose.SetDialect("postgres"); err != nil {
|
||||
|
||||
43
internal/logger/logger.go
Normal file
43
internal/logger/logger.go
Normal file
@ -0,0 +1,43 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"go.uber.org/zap"
|
||||
"log"
|
||||
)
|
||||
|
||||
func New(env string) *zap.SugaredLogger {
|
||||
var zapLogger *zap.Logger
|
||||
var err error
|
||||
|
||||
if env == "production" {
|
||||
zapLogger, err = zap.NewProduction()
|
||||
} else {
|
||||
zapLogger, err = zap.NewDevelopment()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("failed to initialize zap logger: %v", err)
|
||||
}
|
||||
|
||||
return zapLogger.Sugar()
|
||||
}
|
||||
|
||||
type GooseLogger struct {
|
||||
*zap.SugaredLogger
|
||||
}
|
||||
|
||||
func (l *GooseLogger) Fatal(v ...interface{}) {
|
||||
l.SugaredLogger.Fatal(v...)
|
||||
}
|
||||
|
||||
func (l *GooseLogger) Fatalf(format string, v ...interface{}) {
|
||||
l.SugaredLogger.Fatalf(format, v...)
|
||||
}
|
||||
|
||||
func (l *GooseLogger) Print(v ...interface{}) {
|
||||
l.SugaredLogger.Info(v...)
|
||||
}
|
||||
|
||||
func (l *GooseLogger) Printf(format string, v ...interface{}) {
|
||||
l.SugaredLogger.Infof(format, v...)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user