From 67f6b78aaa412981e797b2322189bc222e5021ac Mon Sep 17 00:00:00 2001 From: sneak Date: Mon, 28 Jul 2025 01:14:51 +0200 Subject: [PATCH] Add custom logger with source location tracking and remove verbose database logs - Create internal/logger package with Logger wrapper around slog - Logger automatically adds source file, line number, and function name to all log entries - Use golang.org/x/term to properly detect if stdout is a terminal - Replace all slog.Logger usage with logger.Logger throughout the codebase - Remove verbose logging from database GetStats() method - Update all constructors and dependencies to use the new logger --- cmd/streamdumper/main.go | 8 +- go.mod | 1 + go.sum | 2 + internal/database/database.go | 14 +- internal/database/slowquery.go | 7 +- internal/logger/logger.go | 150 ++++++++++++++++++++ internal/routewatch/app.go | 32 +---- internal/routewatch/app_integration_test.go | 3 +- internal/routewatch/app_test.go | 11 +- internal/routewatch/cli.go | 4 +- internal/routewatch/dbhandler.go | 7 +- internal/routewatch/dbhandler_batched.go | 6 +- internal/routewatch/handler.go | 10 +- internal/routewatch/peerhandler.go | 6 +- internal/routewatch/peerhandler_batched.go | 6 +- internal/routewatch/routingtablehandler.go | 6 +- internal/routingtable/routingtable.go | 6 +- internal/routingtable/routingtable_test.go | 8 +- internal/server/server.go | 6 +- internal/snapshotter/snapshotter.go | 6 +- internal/streamer/streamer.go | 6 +- internal/streamer/streamer_test.go | 4 +- 22 files changed, 212 insertions(+), 97 deletions(-) create mode 100644 internal/logger/logger.go diff --git a/cmd/streamdumper/main.go b/cmd/streamdumper/main.go index d1e184a..7754d7a 100644 --- a/cmd/streamdumper/main.go +++ b/cmd/streamdumper/main.go @@ -9,16 +9,14 @@ import ( "os/signal" "syscall" + "git.eeqj.de/sneak/routewatch/internal/logger" "git.eeqj.de/sneak/routewatch/internal/metrics" "git.eeqj.de/sneak/routewatch/internal/streamer" - "log/slog" ) func main() { - // Set up logger to only show errors - logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{ - Level: slog.LevelError, - })) + // Set up logger + logger := logger.New() // Create metrics tracker metricsTracker := metrics.New() diff --git a/go.mod b/go.mod index 42ab925..aa6bc3c 100644 --- a/go.mod +++ b/go.mod @@ -15,4 +15,5 @@ require ( go.uber.org/multierr v1.10.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/sys v0.34.0 // indirect + golang.org/x/term v0.33.0 // indirect ) diff --git a/go.sum b/go.sum index f051d1f..0bffb02 100644 --- a/go.sum +++ b/go.sum @@ -24,5 +24,7 @@ go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/database/database.go b/internal/database/database.go index b57045f..6e2b1ad 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -5,12 +5,12 @@ import ( "database/sql" _ "embed" "fmt" - "log/slog" "os" "path/filepath" "time" "git.eeqj.de/sneak/routewatch/internal/config" + "git.eeqj.de/sneak/routewatch/internal/logger" "git.eeqj.de/sneak/routewatch/pkg/asinfo" "github.com/google/uuid" _ "github.com/mattn/go-sqlite3" // CGO SQLite driver @@ -24,12 +24,12 @@ const dirPermissions = 0750 // rwxr-x--- // Database manages the SQLite database connection and operations. type Database struct { db *sql.DB - logger *slog.Logger + logger *logger.Logger path string } // New creates a new database connection and initializes the schema. -func New(cfg *config.Config, logger *slog.Logger) (*Database, error) { +func New(cfg *config.Config, logger *logger.Logger) (*Database, error) { dbPath := filepath.Join(cfg.GetStateDir(), "db.sqlite") // Log database path @@ -348,28 +348,24 @@ func (d *Database) GetStats() (Stats, error) { var stats Stats // Count ASNs - d.logger.Info("Counting ASNs") err := d.queryRow("SELECT COUNT(*) FROM asns").Scan(&stats.ASNs) if err != nil { return stats, err } // Count prefixes - d.logger.Info("Counting prefixes") err = d.queryRow("SELECT COUNT(*) FROM prefixes").Scan(&stats.Prefixes) if err != nil { return stats, err } // Count IPv4 and IPv6 prefixes - d.logger.Info("Counting IPv4 prefixes") const ipVersionV4 = 4 err = d.queryRow("SELECT COUNT(*) FROM prefixes WHERE ip_version = ?", ipVersionV4).Scan(&stats.IPv4Prefixes) if err != nil { return stats, err } - d.logger.Info("Counting IPv6 prefixes") const ipVersionV6 = 6 err = d.queryRow("SELECT COUNT(*) FROM prefixes WHERE ip_version = ?", ipVersionV6).Scan(&stats.IPv6Prefixes) if err != nil { @@ -377,14 +373,12 @@ func (d *Database) GetStats() (Stats, error) { } // Count peerings - d.logger.Info("Counting peerings") err = d.queryRow("SELECT COUNT(*) FROM asn_peerings").Scan(&stats.Peerings) if err != nil { return stats, err } // Get database file size - d.logger.Info("Getting database file size") fileInfo, err := os.Stat(d.path) if err != nil { d.logger.Warn("Failed to get database file size", "error", err) @@ -393,7 +387,5 @@ func (d *Database) GetStats() (Stats, error) { stats.FileSizeBytes = fileInfo.Size() } - d.logger.Info("Stats collection complete") - return stats, nil } diff --git a/internal/database/slowquery.go b/internal/database/slowquery.go index 8ebc4cd..2565ca1 100644 --- a/internal/database/slowquery.go +++ b/internal/database/slowquery.go @@ -3,14 +3,15 @@ package database import ( "context" "database/sql" - "log/slog" "time" + + "git.eeqj.de/sneak/routewatch/internal/logger" ) const slowQueryThreshold = 50 * time.Millisecond // logSlowQuery logs queries that take longer than slowQueryThreshold -func logSlowQuery(logger *slog.Logger, query string, start time.Time) { +func logSlowQuery(logger *logger.Logger, query string, start time.Time) { elapsed := time.Since(start) if elapsed > slowQueryThreshold { logger.Debug("Slow query", "query", query, "duration", elapsed) @@ -47,7 +48,7 @@ func (d *Database) exec(query string, args ...interface{}) error { // loggingTx wraps sql.Tx to log slow queries type loggingTx struct { *sql.Tx - logger *slog.Logger + logger *logger.Logger } // QueryRow wraps sql.Tx.QueryRow to log slow queries diff --git a/internal/logger/logger.go b/internal/logger/logger.go new file mode 100644 index 0000000..16ea557 --- /dev/null +++ b/internal/logger/logger.go @@ -0,0 +1,150 @@ +// Package logger provides a structured logger with source location tracking +package logger + +import ( + "log/slog" + "os" + "path/filepath" + "runtime" + "strings" + + "golang.org/x/term" +) + +// Logger wraps slog.Logger to add source location information +type Logger struct { + *slog.Logger +} + +// AsSlog returns the underlying slog.Logger +func (l *Logger) AsSlog() *slog.Logger { + return l.Logger +} + +// New creates a new logger with appropriate handler based on environment +func New() *Logger { + level := slog.LevelInfo + if debug := os.Getenv("DEBUG"); strings.Contains(debug, "routewatch") { + level = slog.LevelDebug + } + + opts := &slog.HandlerOptions{ + Level: level, + } + + var handler slog.Handler + if term.IsTerminal(int(os.Stdout.Fd())) { + // Terminal, use text + handler = slog.NewTextHandler(os.Stdout, opts) + } else { + // Not a terminal, use JSON + handler = slog.NewJSONHandler(os.Stdout, opts) + } + + return &Logger{Logger: slog.New(handler)} +} + +const sourceSkipLevel = 2 // Skip levels for source location tracking + +// getSourceAttrs returns attributes for the calling source location +func getSourceAttrs() []slog.Attr { + pc, file, line, ok := runtime.Caller(sourceSkipLevel) + if !ok { + return nil + } + + // Get just the filename without the full path + file = filepath.Base(file) + + // Get the function name + fn := runtime.FuncForPC(pc) + var funcName string + if fn != nil { + funcName = filepath.Base(fn.Name()) + } + + attrs := []slog.Attr{ + slog.String("source", file), + slog.Int("line", line), + } + + if funcName != "" { + attrs = append(attrs, slog.String("func", funcName)) + } + + return attrs +} + +// Debug logs at debug level with source location +func (l *Logger) Debug(msg string, args ...any) { + sourceAttrs := getSourceAttrs() + allArgs := make([]any, 0, len(args)+len(sourceAttrs)*2) + + // Add source attributes first + for _, attr := range sourceAttrs { + allArgs = append(allArgs, attr) + } + + // Add user args + allArgs = append(allArgs, args...) + + l.Logger.Debug(msg, allArgs...) +} + +// Info logs at info level with source location +func (l *Logger) Info(msg string, args ...any) { + sourceAttrs := getSourceAttrs() + allArgs := make([]any, 0, len(args)+len(sourceAttrs)*2) + + // Add source attributes first + for _, attr := range sourceAttrs { + allArgs = append(allArgs, attr) + } + + // Add user args + allArgs = append(allArgs, args...) + + l.Logger.Info(msg, allArgs...) +} + +// Warn logs at warn level with source location +func (l *Logger) Warn(msg string, args ...any) { + sourceAttrs := getSourceAttrs() + allArgs := make([]any, 0, len(args)+len(sourceAttrs)*2) + + // Add source attributes first + for _, attr := range sourceAttrs { + allArgs = append(allArgs, attr) + } + + // Add user args + allArgs = append(allArgs, args...) + + l.Logger.Warn(msg, allArgs...) +} + +// Error logs at error level with source location +func (l *Logger) Error(msg string, args ...any) { + sourceAttrs := getSourceAttrs() + allArgs := make([]any, 0, len(args)+len(sourceAttrs)*2) + + // Add source attributes first + for _, attr := range sourceAttrs { + allArgs = append(allArgs, attr) + } + + // Add user args + allArgs = append(allArgs, args...) + + l.Logger.Error(msg, allArgs...) +} + +// With returns a new logger with additional attributes +func (l *Logger) With(args ...any) *Logger { + return &Logger{Logger: l.Logger.With(args...)} +} + +// WithGroup returns a new logger with a group prefix +func (l *Logger) WithGroup(name string) *Logger { + return &Logger{Logger: l.Logger.WithGroup(name)} +} diff --git a/internal/routewatch/app.go b/internal/routewatch/app.go index 5bb9677..192906d 100644 --- a/internal/routewatch/app.go +++ b/internal/routewatch/app.go @@ -5,14 +5,13 @@ package routewatch import ( "context" "fmt" - "log/slog" "os" - "strings" "sync" "time" "git.eeqj.de/sneak/routewatch/internal/config" "git.eeqj.de/sneak/routewatch/internal/database" + "git.eeqj.de/sneak/routewatch/internal/logger" "git.eeqj.de/sneak/routewatch/internal/metrics" "git.eeqj.de/sneak/routewatch/internal/routingtable" "git.eeqj.de/sneak/routewatch/internal/server" @@ -35,7 +34,7 @@ type Dependencies struct { RoutingTable *routingtable.RoutingTable Streamer *streamer.Streamer Server *server.Server - Logger *slog.Logger + Logger *logger.Logger Config *config.Config } @@ -46,7 +45,7 @@ type RouteWatch struct { streamer *streamer.Streamer server *server.Server snapshotter *snapshotter.Snapshotter - logger *slog.Logger + logger *logger.Logger maxRuntime time.Duration shutdown bool mu sync.Mutex @@ -229,34 +228,11 @@ func (rw *RouteWatch) logRoutingTableStats(ctx context.Context) { } } -// NewLogger creates a structured logger -func NewLogger() *slog.Logger { - level := slog.LevelInfo - if debug := os.Getenv("DEBUG"); strings.Contains(debug, "routewatch") { - level = slog.LevelDebug - } - - opts := &slog.HandlerOptions{ - Level: level, - } - - var handler slog.Handler - if os.Stdout.Name() != "/dev/stdout" || os.Getenv("TERM") == "" { - // Not a terminal, use JSON - handler = slog.NewJSONHandler(os.Stdout, opts) - } else { - // Terminal, use text - handler = slog.NewTextHandler(os.Stdout, opts) - } - - return slog.New(handler) -} - // getModule provides all fx dependencies func getModule() fx.Option { return fx.Options( fx.Provide( - NewLogger, + logger.New, config.New, metrics.New, fx.Annotate( diff --git a/internal/routewatch/app_integration_test.go b/internal/routewatch/app_integration_test.go index 574e6f9..2a011fe 100644 --- a/internal/routewatch/app_integration_test.go +++ b/internal/routewatch/app_integration_test.go @@ -9,6 +9,7 @@ import ( "git.eeqj.de/sneak/routewatch/internal/config" "git.eeqj.de/sneak/routewatch/internal/database" + "git.eeqj.de/sneak/routewatch/internal/logger" "git.eeqj.de/sneak/routewatch/internal/metrics" "git.eeqj.de/sneak/routewatch/internal/routingtable" "git.eeqj.de/sneak/routewatch/internal/server" @@ -164,7 +165,7 @@ func TestRouteWatchLiveFeed(t *testing.T) { mockDB := newMockStore() defer mockDB.Close() - logger := NewLogger() + logger := logger.New() // Create metrics tracker metricsTracker := metrics.New() diff --git a/internal/routewatch/app_test.go b/internal/routewatch/app_test.go index b2ea3af..6adfec8 100644 --- a/internal/routewatch/app_test.go +++ b/internal/routewatch/app_test.go @@ -1,12 +1,3 @@ package routewatch -import ( - "testing" -) - -func TestNewLogger(t *testing.T) { - logger := NewLogger() - if logger == nil { - t.Fatal("NewLogger returned nil") - } -} +// Tests for routewatch package are in app_integration_test.go diff --git a/internal/routewatch/cli.go b/internal/routewatch/cli.go index 06abbba..b2ec0b8 100644 --- a/internal/routewatch/cli.go +++ b/internal/routewatch/cli.go @@ -2,12 +2,12 @@ package routewatch import ( "context" - "log/slog" "os" "os/signal" "syscall" "time" + "git.eeqj.de/sneak/routewatch/internal/logger" "go.uber.org/fx" ) @@ -21,7 +21,7 @@ func CLIEntry() { app := fx.New( getModule(), fx.StopTimeout(shutdownTimeout), // Allow 60 seconds for graceful shutdown - fx.Invoke(func(lc fx.Lifecycle, rw *RouteWatch, logger *slog.Logger) { + fx.Invoke(func(lc fx.Lifecycle, rw *RouteWatch, logger *logger.Logger) { lc.Append(fx.Hook{ OnStart: func(_ context.Context) error { go func() { diff --git a/internal/routewatch/dbhandler.go b/internal/routewatch/dbhandler.go index cc5c566..06c517f 100644 --- a/internal/routewatch/dbhandler.go +++ b/internal/routewatch/dbhandler.go @@ -1,9 +1,8 @@ package routewatch import ( - "log/slog" - "git.eeqj.de/sneak/routewatch/internal/database" + "git.eeqj.de/sneak/routewatch/internal/logger" "git.eeqj.de/sneak/routewatch/internal/ristypes" ) @@ -15,13 +14,13 @@ const ( // DatabaseHandler handles BGP messages and stores them in the database type DatabaseHandler struct { db database.Store - logger *slog.Logger + logger *logger.Logger } // NewDatabaseHandler creates a new database handler func NewDatabaseHandler( db database.Store, - logger *slog.Logger, + logger *logger.Logger, ) *DatabaseHandler { return &DatabaseHandler{ db: db, diff --git a/internal/routewatch/dbhandler_batched.go b/internal/routewatch/dbhandler_batched.go index aa12b9c..2ec635b 100644 --- a/internal/routewatch/dbhandler_batched.go +++ b/internal/routewatch/dbhandler_batched.go @@ -1,11 +1,11 @@ package routewatch import ( - "log/slog" "sync" "time" "git.eeqj.de/sneak/routewatch/internal/database" + "git.eeqj.de/sneak/routewatch/internal/logger" "git.eeqj.de/sneak/routewatch/internal/ristypes" ) @@ -23,7 +23,7 @@ const ( // BatchedDatabaseHandler handles BGP messages and stores them in the database using batched operations type BatchedDatabaseHandler struct { db database.Store - logger *slog.Logger + logger *logger.Logger // Batching mu sync.Mutex @@ -54,7 +54,7 @@ type peeringOp struct { // NewBatchedDatabaseHandler creates a new batched database handler func NewBatchedDatabaseHandler( db database.Store, - logger *slog.Logger, + logger *logger.Logger, ) *BatchedDatabaseHandler { h := &BatchedDatabaseHandler{ db: db, diff --git a/internal/routewatch/handler.go b/internal/routewatch/handler.go index 1559b16..c6a6789 100644 --- a/internal/routewatch/handler.go +++ b/internal/routewatch/handler.go @@ -1,19 +1,23 @@ package routewatch import ( + "git.eeqj.de/sneak/routewatch/internal/logger" "git.eeqj.de/sneak/routewatch/internal/ristypes" - "log/slog" ) // SimpleHandler is a basic implementation of streamer.MessageHandler type SimpleHandler struct { - logger *slog.Logger + logger *logger.Logger messageTypes []string callback func(*ristypes.RISMessage) } // NewSimpleHandler creates a handler that accepts specific message types -func NewSimpleHandler(logger *slog.Logger, messageTypes []string, callback func(*ristypes.RISMessage)) *SimpleHandler { +func NewSimpleHandler( + logger *logger.Logger, + messageTypes []string, + callback func(*ristypes.RISMessage), +) *SimpleHandler { return &SimpleHandler{ logger: logger, messageTypes: messageTypes, diff --git a/internal/routewatch/peerhandler.go b/internal/routewatch/peerhandler.go index a004383..3688c6a 100644 --- a/internal/routewatch/peerhandler.go +++ b/internal/routewatch/peerhandler.go @@ -1,10 +1,10 @@ package routewatch import ( - "log/slog" "strconv" "git.eeqj.de/sneak/routewatch/internal/database" + "git.eeqj.de/sneak/routewatch/internal/logger" "git.eeqj.de/sneak/routewatch/internal/ristypes" ) @@ -16,11 +16,11 @@ const ( // PeerHandler tracks BGP peers from all message types type PeerHandler struct { db database.Store - logger *slog.Logger + logger *logger.Logger } // NewPeerHandler creates a new peer tracking handler -func NewPeerHandler(db database.Store, logger *slog.Logger) *PeerHandler { +func NewPeerHandler(db database.Store, logger *logger.Logger) *PeerHandler { return &PeerHandler{ db: db, logger: logger, diff --git a/internal/routewatch/peerhandler_batched.go b/internal/routewatch/peerhandler_batched.go index 95f5450..4c1d5e6 100644 --- a/internal/routewatch/peerhandler_batched.go +++ b/internal/routewatch/peerhandler_batched.go @@ -1,12 +1,12 @@ package routewatch import ( - "log/slog" "strconv" "sync" "time" "git.eeqj.de/sneak/routewatch/internal/database" + "git.eeqj.de/sneak/routewatch/internal/logger" "git.eeqj.de/sneak/routewatch/internal/ristypes" ) @@ -24,7 +24,7 @@ const ( // BatchedPeerHandler tracks BGP peers from all message types using batched operations type BatchedPeerHandler struct { db database.Store - logger *slog.Logger + logger *logger.Logger // Batching mu sync.Mutex @@ -42,7 +42,7 @@ type peerUpdate struct { } // NewBatchedPeerHandler creates a new batched peer tracking handler -func NewBatchedPeerHandler(db database.Store, logger *slog.Logger) *BatchedPeerHandler { +func NewBatchedPeerHandler(db database.Store, logger *logger.Logger) *BatchedPeerHandler { h := &BatchedPeerHandler{ db: db, logger: logger, diff --git a/internal/routewatch/routingtablehandler.go b/internal/routewatch/routingtablehandler.go index fbbbaef..75b7254 100644 --- a/internal/routewatch/routingtablehandler.go +++ b/internal/routewatch/routingtablehandler.go @@ -1,9 +1,9 @@ package routewatch import ( - "log/slog" "strconv" + "git.eeqj.de/sneak/routewatch/internal/logger" "git.eeqj.de/sneak/routewatch/internal/ristypes" "git.eeqj.de/sneak/routewatch/internal/routingtable" "github.com/google/uuid" @@ -17,11 +17,11 @@ const ( // RoutingTableHandler handles BGP messages and updates the in-memory routing table type RoutingTableHandler struct { rt *routingtable.RoutingTable - logger *slog.Logger + logger *logger.Logger } // NewRoutingTableHandler creates a new routing table handler -func NewRoutingTableHandler(rt *routingtable.RoutingTable, logger *slog.Logger) *RoutingTableHandler { +func NewRoutingTableHandler(rt *routingtable.RoutingTable, logger *logger.Logger) *RoutingTableHandler { return &RoutingTableHandler{ rt: rt, logger: logger, diff --git a/internal/routingtable/routingtable.go b/internal/routingtable/routingtable.go index ce9e1ba..db97b6d 100644 --- a/internal/routingtable/routingtable.go +++ b/internal/routingtable/routingtable.go @@ -5,7 +5,6 @@ import ( "compress/gzip" "encoding/json" "fmt" - "log/slog" "os" "path/filepath" "strings" @@ -14,6 +13,7 @@ import ( "time" "git.eeqj.de/sneak/routewatch/internal/config" + "git.eeqj.de/sneak/routewatch/internal/logger" "github.com/google/uuid" ) @@ -68,7 +68,7 @@ type RoutingTable struct { } // New creates a new routing table, loading from snapshot if available -func New(cfg *config.Config, logger *slog.Logger) *RoutingTable { +func New(cfg *config.Config, logger *logger.Logger) *RoutingTable { rt := &RoutingTable{ routes: make(map[RouteKey]*Route), byPrefix: make(map[uuid.UUID]map[RouteKey]*Route), @@ -452,7 +452,7 @@ func isIPv6(prefix string) bool { } // loadFromSnapshot attempts to load the routing table from a snapshot file -func (rt *RoutingTable) loadFromSnapshot(logger *slog.Logger) error { +func (rt *RoutingTable) loadFromSnapshot(logger *logger.Logger) error { // If no snapshot directory specified, nothing to load if rt.snapshotDir == "" { return nil diff --git a/internal/routingtable/routingtable_test.go b/internal/routingtable/routingtable_test.go index 3f96281..d20c3d6 100644 --- a/internal/routingtable/routingtable_test.go +++ b/internal/routingtable/routingtable_test.go @@ -1,18 +1,18 @@ package routingtable import ( - "log/slog" "sync" "testing" "time" "git.eeqj.de/sneak/routewatch/internal/config" + "git.eeqj.de/sneak/routewatch/internal/logger" "github.com/google/uuid" ) func TestRoutingTable(t *testing.T) { // Create a test logger - logger := slog.Default() + logger := logger.New() // Create test config with empty state dir (no snapshot loading) cfg := &config.Config{ @@ -129,7 +129,7 @@ func TestRoutingTable(t *testing.T) { func TestRoutingTableConcurrency(t *testing.T) { // Create a test logger - logger := slog.Default() + logger := logger.New() // Create test config with empty state dir (no snapshot loading) cfg := &config.Config{ @@ -189,7 +189,7 @@ func TestRoutingTableConcurrency(t *testing.T) { func TestRouteUpdate(t *testing.T) { // Create a test logger - logger := slog.Default() + logger := logger.New() // Create test config with empty state dir (no snapshot loading) cfg := &config.Config{ diff --git a/internal/server/server.go b/internal/server/server.go index 24cc7b3..eaba6de 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -4,12 +4,12 @@ package server import ( "context" "encoding/json" - "log/slog" "net/http" "os" "time" "git.eeqj.de/sneak/routewatch/internal/database" + "git.eeqj.de/sneak/routewatch/internal/logger" "git.eeqj.de/sneak/routewatch/internal/routingtable" "git.eeqj.de/sneak/routewatch/internal/streamer" "git.eeqj.de/sneak/routewatch/internal/templates" @@ -23,12 +23,12 @@ type Server struct { db database.Store routingTable *routingtable.RoutingTable streamer *streamer.Streamer - logger *slog.Logger + logger *logger.Logger srv *http.Server } // New creates a new HTTP server -func New(db database.Store, rt *routingtable.RoutingTable, streamer *streamer.Streamer, logger *slog.Logger) *Server { +func New(db database.Store, rt *routingtable.RoutingTable, streamer *streamer.Streamer, logger *logger.Logger) *Server { s := &Server{ db: db, routingTable: rt, diff --git a/internal/snapshotter/snapshotter.go b/internal/snapshotter/snapshotter.go index e379e21..5b4f88c 100644 --- a/internal/snapshotter/snapshotter.go +++ b/internal/snapshotter/snapshotter.go @@ -7,7 +7,7 @@ import ( "context" "encoding/json" "fmt" - "log/slog" + "git.eeqj.de/sneak/routewatch/internal/logger" "os" "path/filepath" "sync" @@ -27,7 +27,7 @@ const ( type Snapshotter struct { rt *routingtable.RoutingTable stateDir string - logger *slog.Logger + logger *logger.Logger ctx context.Context cancel context.CancelFunc mu sync.Mutex // Ensures only one snapshot runs at a time @@ -36,7 +36,7 @@ type Snapshotter struct { } // New creates a new Snapshotter instance -func New(rt *routingtable.RoutingTable, cfg *config.Config, logger *slog.Logger) (*Snapshotter, error) { +func New(rt *routingtable.RoutingTable, cfg *config.Config, logger *logger.Logger) (*Snapshotter, error) { stateDir := cfg.GetStateDir() // If state directory is specified, ensure it exists diff --git a/internal/streamer/streamer.go b/internal/streamer/streamer.go index fe7f6b0..962c665 100644 --- a/internal/streamer/streamer.go +++ b/internal/streamer/streamer.go @@ -7,13 +7,13 @@ import ( "context" "encoding/json" "fmt" - "log/slog" "net/http" "os" "sync" "sync/atomic" "time" + "git.eeqj.de/sneak/routewatch/internal/logger" "git.eeqj.de/sneak/routewatch/internal/metrics" "git.eeqj.de/sneak/routewatch/internal/ristypes" ) @@ -63,7 +63,7 @@ type handlerInfo struct { // Streamer handles streaming BGP updates from RIS Live type Streamer struct { - logger *slog.Logger + logger *logger.Logger client *http.Client handlers []*handlerInfo rawHandler RawMessageHandler @@ -75,7 +75,7 @@ type Streamer struct { } // New creates a new RIS streamer -func New(logger *slog.Logger, metrics *metrics.Tracker) *Streamer { +func New(logger *logger.Logger, metrics *metrics.Tracker) *Streamer { return &Streamer{ logger: logger, client: &http.Client{ diff --git a/internal/streamer/streamer_test.go b/internal/streamer/streamer_test.go index 103ab56..1c788a4 100644 --- a/internal/streamer/streamer_test.go +++ b/internal/streamer/streamer_test.go @@ -3,12 +3,12 @@ package streamer import ( "testing" + "git.eeqj.de/sneak/routewatch/internal/logger" "git.eeqj.de/sneak/routewatch/internal/metrics" - "log/slog" ) func TestNewStreamer(t *testing.T) { - logger := slog.Default() + logger := logger.New() metricsTracker := metrics.New() s := New(logger, metricsTracker)