diff --git a/go.mod b/go.mod index b22dda7..2055b3d 100644 --- a/go.mod +++ b/go.mod @@ -12,11 +12,15 @@ require ( github.com/joho/godotenv v1.5.1 github.com/mattn/go-sqlite3 v1.14.28 github.com/stretchr/testify v1.10.0 + go.opentelemetry.io/contrib/bridges/otelslog v0.11.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 go.opentelemetry.io/otel v1.36.0 + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.36.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0 + go.opentelemetry.io/otel/log v0.12.2 go.opentelemetry.io/otel/sdk v1.36.0 + go.opentelemetry.io/otel/sdk/log v0.12.2 go.opentelemetry.io/otel/sdk/metric v1.36.0 go.opentelemetry.io/otel/trace v1.36.0 golang.org/x/crypto v0.39.0 diff --git a/go.sum b/go.sum index 6d0ea05..64654f5 100644 --- a/go.sum +++ b/go.sum @@ -53,20 +53,30 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/bridges/otelslog v0.11.0 h1:EMIiYTms4Z4m3bBuKp1VmMNRLZcl6j4YbvOPL1IhlWo= +go.opentelemetry.io/contrib/bridges/otelslog v0.11.0/go.mod h1:DIEZmUR7tzuOOVUTDKvkGWtYWSHFV18Qg8+GMb8wPJw= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 h1:06ZeJRe5BnYXceSM9Vya83XXVaNGe3H1QqsvqRANQq8= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2/go.mod h1:DvPtKE63knkDVP88qpatBj81JxN+w1bqfVbsbCbj1WY= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.36.0 h1:zwdo1gS2eH26Rg+CoqVQpEK1h8gvt5qyU5Kk5Bixvow= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.36.0/go.mod h1:rUKCPscaRWWcqGT6HnEmYrK+YNe5+Sw64xgQTOJ5b30= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 h1:dNzwXjZKpMpE2JhmO+9HsPl42NIXFIFSUSSs0fiqra0= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0/go.mod h1:90PoxvaEB5n6AOdZvi+yWJQoE95U8Dhhw2bSyRqnTD0= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0 h1:JgtbA0xkWHnTmYk7YusopJFX6uleBmAuZ8n05NEh8nQ= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0/go.mod h1:179AK5aar5R3eS9FucPy6rggvU0g52cvKId8pv4+v0c= +go.opentelemetry.io/otel/log v0.12.2 h1:yob9JVHn2ZY24byZeaXpTVoPS6l+UrrxmxmPKohXTwc= +go.opentelemetry.io/otel/log v0.12.2/go.mod h1:ShIItIxSYxufUMt+1H5a2wbckGli3/iCfuEbVZi/98E= go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= +go.opentelemetry.io/otel/sdk/log v0.12.2 h1:yNoETvTByVKi7wHvYS6HMcZrN5hFLD7I++1xIZ/k6W0= +go.opentelemetry.io/otel/sdk/log v0.12.2/go.mod h1:DcpdmUXHJgSqN/dh+XMWa7Vf89u9ap0/AAk/XGLnEzY= +go.opentelemetry.io/otel/sdk/log/logtest v0.0.0-20250521073539-a85ae98dcedc h1:uqxdywfHqqCl6LmZzI3pUnXT1RGFYyUgxj0AkWPFxi0= +go.opentelemetry.io/otel/sdk/log/logtest v0.0.0-20250521073539-a85ae98dcedc/go.mod h1:TY/N/FT7dmFrP/r5ym3g0yysP1DefqGpAZr4f82P0dE= go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= diff --git a/internal/db/auth.go b/internal/db/auth.go index c31e9dc..ac47439 100644 --- a/internal/db/auth.go +++ b/internal/db/auth.go @@ -1,11 +1,10 @@ package db import ( - "errors" - "spend-sparrow/internal/log" - "spend-sparrow/internal/types" - "database/sql" + "errors" + "log/slog" + "spend-sparrow/internal/types" "strings" "time" @@ -52,7 +51,7 @@ func (db AuthSqlite) InsertUser(user *types.User) error { return ErrAlreadyExists } - log.L.Error("SQL error InsertUser", "err", err) + slog.Error("SQL error InsertUser", "err", err) return types.ErrInternal } @@ -67,7 +66,7 @@ func (db AuthSqlite) UpdateUser(user *types.User) error { user.EmailVerified, user.EmailVerifiedAt, user.Password, user.Id) if err != nil { - log.L.Error("SQL error UpdateUser", "err", err) + slog.Error("SQL error UpdateUser", "err", err) return types.ErrInternal } @@ -93,7 +92,7 @@ func (db AuthSqlite) GetUserByEmail(email string) (*types.User, error) { if errors.Is(err, sql.ErrNoRows) { return nil, ErrNotFound } else { - log.L.Error("SQL error GetUser", "err", err) + slog.Error("SQL error GetUser", "err", err) return nil, types.ErrInternal } } @@ -120,7 +119,7 @@ func (db AuthSqlite) GetUser(userId uuid.UUID) (*types.User, error) { if errors.Is(err, sql.ErrNoRows) { return nil, ErrNotFound } else { - log.L.Error("SQL error GetUser", "err", err) + slog.Error("SQL error GetUser", "err", err) return nil, types.ErrInternal } } @@ -131,55 +130,55 @@ func (db AuthSqlite) GetUser(userId uuid.UUID) (*types.User, error) { func (db AuthSqlite) DeleteUser(userId uuid.UUID) error { tx, err := db.db.Begin() if err != nil { - log.L.Error("Could not start transaction", "err", err) + slog.Error("Could not start transaction", "err", err) return types.ErrInternal } _, err = tx.Exec("DELETE FROM account WHERE user_id = ?", userId) if err != nil { _ = tx.Rollback() - log.L.Error("Could not delete accounts", "err", err) + slog.Error("Could not delete accounts", "err", err) return types.ErrInternal } _, err = tx.Exec("DELETE FROM token WHERE user_id = ?", userId) if err != nil { _ = tx.Rollback() - log.L.Error("Could not delete user tokens", "err", err) + slog.Error("Could not delete user tokens", "err", err) return types.ErrInternal } _, err = tx.Exec("DELETE FROM session WHERE user_id = ?", userId) if err != nil { _ = tx.Rollback() - log.L.Error("Could not delete sessions", "err", err) + slog.Error("Could not delete sessions", "err", err) return types.ErrInternal } _, err = tx.Exec("DELETE FROM user WHERE user_id = ?", userId) if err != nil { _ = tx.Rollback() - log.L.Error("Could not delete user", "err", err) + slog.Error("Could not delete user", "err", err) return types.ErrInternal } _, err = tx.Exec("DELETE FROM treasure_chest WHERE user_id = ?", userId) if err != nil { _ = tx.Rollback() - log.L.Error("Could not delete user", "err", err) + slog.Error("Could not delete user", "err", err) return types.ErrInternal } _, err = tx.Exec("DELETE FROM \"transaction\" WHERE user_id = ?", userId) if err != nil { _ = tx.Rollback() - log.L.Error("Could not delete user", "err", err) + slog.Error("Could not delete user", "err", err) return types.ErrInternal } err = tx.Commit() if err != nil { - log.L.Error("Could not commit transaction", "err", err) + slog.Error("Could not commit transaction", "err", err) return types.ErrInternal } @@ -192,7 +191,7 @@ func (db AuthSqlite) InsertToken(token *types.Token) error { VALUES (?, ?, ?, ?, ?, ?)`, token.UserId, token.SessionId, token.Type, token.Token, token.CreatedAt, token.ExpiresAt) if err != nil { - log.L.Error("Could not insert token", "err", err) + slog.Error("Could not insert token", "err", err) return types.ErrInternal } @@ -217,23 +216,23 @@ func (db AuthSqlite) GetToken(token string) (*types.Token, error) { if err != nil { if errors.Is(err, sql.ErrNoRows) { - log.L.Info("Token not found", "token", token) + slog.Info("Token not found", "token", token) return nil, ErrNotFound } else { - log.L.Error("Could not get token", "err", err) + slog.Error("Could not get token", "err", err) return nil, types.ErrInternal } } createdAt, err = time.Parse(time.RFC3339, createdAtStr) if err != nil { - log.L.Error("Could not parse token.created_at", "err", err) + slog.Error("Could not parse token.created_at", "err", err) return nil, types.ErrInternal } expiresAt, err = time.Parse(time.RFC3339, expiresAtStr) if err != nil { - log.L.Error("Could not parse token.expires_at", "err", err) + slog.Error("Could not parse token.expires_at", "err", err) return nil, types.ErrInternal } @@ -248,7 +247,7 @@ func (db AuthSqlite) GetTokensByUserIdAndType(userId uuid.UUID, tokenType types. AND type = ?`, userId, tokenType) if err != nil { - log.L.Error("Could not get token", "err", err) + slog.Error("Could not get token", "err", err) return nil, types.ErrInternal } @@ -263,7 +262,7 @@ func (db AuthSqlite) GetTokensBySessionIdAndType(sessionId string, tokenType typ AND type = ?`, sessionId, tokenType) if err != nil { - log.L.Error("Could not get token", "err", err) + slog.Error("Could not get token", "err", err) return nil, types.ErrInternal } @@ -287,19 +286,19 @@ func getTokensFromQuery(query *sql.Rows, userId uuid.UUID, sessionId string, tok err := query.Scan(&token, &createdAtStr, &expiresAtStr) if err != nil { - log.L.Error("Could not scan token", "err", err) + slog.Error("Could not scan token", "err", err) return nil, types.ErrInternal } createdAt, err = time.Parse(time.RFC3339, createdAtStr) if err != nil { - log.L.Error("Could not parse token.created_at", "err", err) + slog.Error("Could not parse token.created_at", "err", err) return nil, types.ErrInternal } expiresAt, err = time.Parse(time.RFC3339, expiresAtStr) if err != nil { - log.L.Error("Could not parse token.expires_at", "err", err) + slog.Error("Could not parse token.expires_at", "err", err) return nil, types.ErrInternal } @@ -316,7 +315,7 @@ func getTokensFromQuery(query *sql.Rows, userId uuid.UUID, sessionId string, tok func (db AuthSqlite) DeleteToken(token string) error { _, err := db.db.Exec("DELETE FROM token WHERE token = ?", token) if err != nil { - log.L.Error("Could not delete token", "err", err) + slog.Error("Could not delete token", "err", err) return types.ErrInternal } return nil @@ -328,7 +327,7 @@ func (db AuthSqlite) InsertSession(session *types.Session) error { VALUES (?, ?, ?, ?)`, session.Id, session.UserId, session.CreatedAt, session.ExpiresAt) if err != nil { - log.L.Error("Could not insert new session", "err", err) + slog.Error("Could not insert new session", "err", err) return types.ErrInternal } @@ -348,7 +347,7 @@ func (db AuthSqlite) GetSession(sessionId string) (*types.Session, error) { WHERE session_id = ?`, sessionId).Scan(&userId, &createdAt, &expiresAt) if err != nil { - log.L.Warn("Session not found", "session-id", sessionId, "err", err) + slog.Warn("Session not found", "session-id", sessionId, "err", err) return nil, ErrNotFound } @@ -362,7 +361,7 @@ func (db AuthSqlite) GetSessions(userId uuid.UUID) ([]*types.Session, error) { FROM session WHERE user_id = ?`, userId) if err != nil { - log.L.Error("Could not get sessions", "err", err) + slog.Error("Could not get sessions", "err", err) return nil, types.ErrInternal } @@ -375,7 +374,7 @@ func (db AuthSqlite) DeleteOldSessions(userId uuid.UUID) error { WHERE expires_at < datetime('now') AND user_id = ?`, userId) if err != nil { - log.L.Error("Could not delete old sessions", "err", err) + slog.Error("Could not delete old sessions", "err", err) return types.ErrInternal } return nil @@ -385,7 +384,7 @@ func (db AuthSqlite) DeleteSession(sessionId string) error { if sessionId != "" { _, err := db.db.Exec("DELETE FROM session WHERE session_id = ?", sessionId) if err != nil { - log.L.Error("Could not delete session", "err", err) + slog.Error("Could not delete session", "err", err) return types.ErrInternal } } diff --git a/internal/db/error.go b/internal/db/error.go index ef9c3d0..8078340 100644 --- a/internal/db/error.go +++ b/internal/db/error.go @@ -3,7 +3,7 @@ package db import ( "database/sql" "errors" - "spend-sparrow/internal/log" + "log/slog" "spend-sparrow/internal/types" ) @@ -17,19 +17,19 @@ func TransformAndLogDbError(module string, r sql.Result, err error) error { if errors.Is(err, sql.ErrNoRows) { return ErrNotFound } - log.L.Error("database sql", "module", module, "err", err) + slog.Error("database sql", "module", module, "err", err) return types.ErrInternal } if r != nil { rows, err := r.RowsAffected() if err != nil { - log.L.Error("database rows affected", "module", module, "err", err) + slog.Error("database rows affected", "module", module, "err", err) return types.ErrInternal } if rows == 0 { - log.L.Info("row not found", "module", module) + slog.Info("row not found", "module", module) return ErrNotFound } } diff --git a/internal/db/migration.go b/internal/db/migration.go index f6e2df8..f1b670f 100644 --- a/internal/db/migration.go +++ b/internal/db/migration.go @@ -1,10 +1,9 @@ package db import ( - "spend-sparrow/internal/log" - "spend-sparrow/internal/types" - "errors" + "log/slog" + "spend-sparrow/internal/types" "github.com/golang-migrate/migrate/v4" "github.com/golang-migrate/migrate/v4/database/sqlite3" @@ -15,7 +14,7 @@ import ( type migrationLogger struct{} func (l migrationLogger) Printf(format string, v ...any) { - log.L.Info(format, v...) + slog.Info(format, v...) } func (l migrationLogger) Verbose() bool { return false @@ -24,7 +23,7 @@ func (l migrationLogger) Verbose() bool { func RunMigrations(db *sqlx.DB, pathPrefix string) error { driver, err := sqlite3.WithInstance(db.DB, &sqlite3.Config{}) if err != nil { - log.L.Error("Could not create Migration instance", "err", err) + slog.Error("Could not create Migration instance", "err", err) return types.ErrInternal } @@ -33,14 +32,14 @@ func RunMigrations(db *sqlx.DB, pathPrefix string) error { "", driver) if err != nil { - log.L.Error("Could not create migrations instance", "err", err) + slog.Error("Could not create migrations instance", "err", err) return types.ErrInternal } m.Log = migrationLogger{} if err = m.Up(); err != nil && !errors.Is(err, migrate.ErrNoChange) { - log.L.Error("Could not run migrations", "err", err) + slog.Error("Could not run migrations", "err", err) return types.ErrInternal } diff --git a/internal/default.go b/internal/default.go index cb91b7a..ef99297 100644 --- a/internal/default.go +++ b/internal/default.go @@ -3,6 +3,7 @@ package internal import ( "errors" "fmt" + "log/slog" "spend-sparrow/internal/db" "spend-sparrow/internal/handler" "spend-sparrow/internal/handler/middleware" @@ -26,7 +27,27 @@ func Run(ctx context.Context, database *sqlx.DB, migrationsPrefix string, env fu ctx, cancel := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM) defer cancel() - log.L.Info("Starting server...") + otelEnabled := types.IsOtelEnabled(env) + if otelEnabled { + // use context.Background(), otherwise the shutdown can't be called, as the context is already cancelled + otelShutdown, err := setupOTelSDK(context.Background()) + if err != nil { + return fmt.Errorf("could not setup OpenTelemetry SDK: %w", err) + } + defer func() { + // User context.Background(), as the main context is already cancelled + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + err = otelShutdown(ctx) + if err != nil { + slog.Error("error shutting down OpenTelemetry SDK", "err", err) + } + cancel() + }() + + slog.SetDefault(log.NewLogPropagator()) + } + + slog.Info("Starting server...") // init server settings serverSettings, err := types.NewSettingsFromEnv(env) @@ -40,25 +61,6 @@ func Run(ctx context.Context, database *sqlx.DB, migrationsPrefix string, env fu return fmt.Errorf("could not run migrations: %w", err) } - if serverSettings.OtelEnabled { - // use context.Background(), otherwise the shutdown can't be called, as the context is already cancelled - otelShutdown, err := setupOTelSDK(context.Background()) - if err != nil { - return fmt.Errorf("could not setup OpenTelemetry SDK: %w", err) - } - defer func() { - // User context.Background(), as the main context is already cancelled - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - err = otelShutdown(ctx) - if err != nil { - log.L.Error("error shutting down OpenTelemetry SDK", "err", err) - } - cancel() - }() - - log.InitOtelLogger() - } - // init server httpServer := &http.Server{ Addr: ":" + serverSettings.Port, @@ -77,9 +79,9 @@ func Run(ctx context.Context, database *sqlx.DB, migrationsPrefix string, env fu } func startServer(s *http.Server) { - log.L.Info("Starting server", "addr", s.Addr) + slog.Info("Starting server", "addr", s.Addr) if err := s.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { - log.L.Error("error listening and serving", "err", err) + slog.Error("error listening and serving", "err", err) } } @@ -94,9 +96,9 @@ func shutdownServer(s *http.Server, ctx context.Context, wg *sync.WaitGroup) { shutdownCtx, cancel := context.WithTimeout(shutdownCtx, 10*time.Second) defer cancel() if err := s.Shutdown(shutdownCtx); err != nil { - log.L.Error("error shutting down http server", "err", err) + slog.Error("error shutting down http server", "err", err) } else { - log.L.Info("Gracefully stopped http server", "addr", s.Addr) + slog.Info("Gracefully stopped http server", "addr", s.Addr) } } diff --git a/internal/handler/auth.go b/internal/handler/auth.go index 5dd328b..27db437 100644 --- a/internal/handler/auth.go +++ b/internal/handler/auth.go @@ -1,16 +1,15 @@ package handler import ( + "errors" + "log/slog" + "net/http" + "net/url" "spend-sparrow/internal/handler/middleware" - "spend-sparrow/internal/log" "spend-sparrow/internal/service" "spend-sparrow/internal/template/auth" "spend-sparrow/internal/types" "spend-sparrow/internal/utils" - - "errors" - "net/http" - "net/url" "time" ) @@ -168,7 +167,7 @@ func (handler AuthImpl) handleVerifyResendComp() http.HandlerFunc { _, err := w.Write([]byte("

Verification email sent

")) if err != nil { - log.L.Error("Could not write response", "err", err) + slog.Error("Could not write response", "err", err) } } } @@ -203,13 +202,13 @@ func (handler AuthImpl) handleSignUp() http.HandlerFunc { var password = r.FormValue("password") _, err := utils.WaitMinimumTime(securityWaitDuration, func() (any, error) { - log.L.Info("signing up", "email", email) + slog.Info("signing up", "email", email) user, err := handler.service.SignUp(email, password) if err != nil { return nil, err } - log.L.Info("Sending verification email", "to", user.Email) + slog.Info("Sending verification email", "to", user.Email) go handler.service.SendVerificationMail(user.Id, user.Email) return nil, nil }) @@ -389,7 +388,7 @@ func (handler AuthImpl) handleForgotPasswordResponseComp() http.HandlerFunc { pageUrl, err := url.Parse(r.Header.Get("Hx-Current-Url")) if err != nil { - log.L.Error("Could not get current URL", "err", err) + slog.Error("Could not get current URL", "err", err) utils.TriggerToastWithStatus(w, r, "error", "Internal Server Error", http.StatusInternalServerError) return } diff --git a/internal/handler/middleware/cross_site_request_forgery.go b/internal/handler/middleware/cross_site_request_forgery.go index 1527b38..65b7373 100644 --- a/internal/handler/middleware/cross_site_request_forgery.go +++ b/internal/handler/middleware/cross_site_request_forgery.go @@ -1,13 +1,12 @@ package middleware import ( + "log/slog" "net/http" - "strings" - - "spend-sparrow/internal/log" "spend-sparrow/internal/service" "spend-sparrow/internal/types" "spend-sparrow/internal/utils" + "strings" ) type csrfResponseWriter struct { @@ -46,7 +45,7 @@ func CrossSiteRequestForgery(auth service.Auth) func(http.Handler) http.Handler csrfToken := r.Header.Get("Csrf-Token") if session == nil || csrfToken == "" || !auth.IsCsrfTokenValid(csrfToken, session.Id) { - log.L.Info("CSRF-Token not correct", "token", csrfToken) + slog.Info("CSRF-Token not correct", "token", csrfToken) if r.Header.Get("Hx-Request") == "true" { utils.TriggerToastWithStatus(w, r, "error", "CSRF-Token not correct", http.StatusBadRequest) } else { diff --git a/internal/handler/middleware/gzip.go b/internal/handler/middleware/gzip.go index 7676640..8ed9ed6 100644 --- a/internal/handler/middleware/gzip.go +++ b/internal/handler/middleware/gzip.go @@ -4,10 +4,9 @@ import ( "compress/gzip" "errors" "io" + "log/slog" "net/http" "strings" - - "spend-sparrow/internal/log" ) type gzipResponseWriter struct { @@ -34,7 +33,7 @@ func Gzip(next http.Handler) http.Handler { err := gz.Close() if err != nil && !errors.Is(err, http.ErrBodyNotAllowed) { - log.L.Error("Gzip: could not close Writer", "err", err) + slog.Error("Gzip: could not close Writer", "err", err) } }) } diff --git a/internal/handler/middleware/logger.go b/internal/handler/middleware/logger.go index ba002cb..7a1ea16 100644 --- a/internal/handler/middleware/logger.go +++ b/internal/handler/middleware/logger.go @@ -1,8 +1,8 @@ package middleware import ( + "log/slog" "net/http" - "spend-sparrow/internal/log" "time" ) @@ -20,15 +20,13 @@ func Log(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() - log.L.Info("request pattern", "pattern", r.Pattern) - wrapped := &WrappedWriter{ ResponseWriter: w, StatusCode: http.StatusOK, } next.ServeHTTP(wrapped, r) - log.L.Info("request", + slog.Info("request", "remoteAddr", r.RemoteAddr, "status", wrapped.StatusCode, "method", r.Method, diff --git a/internal/handler/middleware/security_headers.go b/internal/handler/middleware/security_headers.go index c024295..4ea4c59 100644 --- a/internal/handler/middleware/security_headers.go +++ b/internal/handler/middleware/security_headers.go @@ -2,7 +2,6 @@ package middleware import ( "net/http" - "spend-sparrow/internal/types" ) diff --git a/internal/handler/render.go b/internal/handler/render.go index f3392f4..85a05e8 100644 --- a/internal/handler/render.go +++ b/internal/handler/render.go @@ -1,8 +1,8 @@ package handler import ( + "log/slog" "net/http" - "spend-sparrow/internal/log" "spend-sparrow/internal/template" "spend-sparrow/internal/template/auth" "spend-sparrow/internal/types" @@ -22,7 +22,7 @@ func (render *Render) RenderWithStatus(r *http.Request, w http.ResponseWriter, c w.WriteHeader(status) err := comp.Render(r.Context(), w) if err != nil { - log.L.Error("Failed to render layout", "err", err) + slog.Error("Failed to render layout", "err", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) } } diff --git a/internal/handler/transaction.go b/internal/handler/transaction.go index db3e9df..d596360 100644 --- a/internal/handler/transaction.go +++ b/internal/handler/transaction.go @@ -105,8 +105,6 @@ func (h TransactionImpl) handleTransactionItemComp() http.HandlerFunc { return } - // log.L.Info("request", "pattern", r.Pattern, "path", r.URL.Path, "method", r.Method, "path", r.URL.Path) - accounts, err := h.account.GetAll(user) if err != nil { handleError(w, r, err) diff --git a/internal/log/default.go b/internal/log/default.go index 725f507..e673ca9 100644 --- a/internal/log/default.go +++ b/internal/log/default.go @@ -1,14 +1,50 @@ package log import ( + "context" "log/slog" - // "go.opentelemetry.io/contrib/bridges/otelslog". + "os" + + "go.opentelemetry.io/contrib/bridges/otelslog" ) -var ( - L = slog.New(slog.Default().Handler()) -) - -func InitOtelLogger() { - // L = otelslog.NewLogger("spend-sparrow") +func NewLogPropagator() *slog.Logger { + return slog.New(&logHandler{ + console: slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{}), + otel: otelslog.NewHandler("spend-sparrow"), + }) +} + +type logHandler struct { + console slog.Handler + otel slog.Handler +} + +// Enabled implements slog.Handler. +func (l *logHandler) Enabled(ctx context.Context, level slog.Level) bool { + return l.console.Enabled(ctx, level) +} + +// Handle implements slog.Handler. +func (l *logHandler) Handle(ctx context.Context, rec slog.Record) error { + if err := l.console.Handle(ctx, rec); err != nil { + return err + } + return l.otel.Handle(ctx, rec) +} + +// WithAttrs implements slog.Handler. +func (l *logHandler) WithAttrs(attrs []slog.Attr) slog.Handler { + return &logHandler{ + console: l.console.WithAttrs(attrs), + otel: l.otel.WithAttrs(attrs), + } +} + +// WithGroup implements slog.Handler. +func (l *logHandler) WithGroup(name string) slog.Handler { + return &logHandler{ + console: l.console.WithGroup(name), + otel: l.otel.WithGroup(name), + } } diff --git a/internal/otel.go b/internal/otel.go index 2ab8815..ef49600 100644 --- a/internal/otel.go +++ b/internal/otel.go @@ -6,12 +6,12 @@ import ( "time" "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc" "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" - // "go.opentelemetry.io/otel/exporters/stdout/stdoutlog". "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" - // "go.opentelemetry.io/otel/log/global". + "go.opentelemetry.io/otel/log/global" "go.opentelemetry.io/otel/propagation" - // "go.opentelemetry.io/otel/sdk/log". + "go.opentelemetry.io/otel/sdk/log" "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/trace" ) @@ -66,13 +66,13 @@ func setupOTelSDK(ctx context.Context) (func(context.Context) error, error) { otel.SetMeterProvider(meterProvider) // Set up logger provider. - // loggerProvider, err := newLoggerProvider() - // if err != nil { - // handleErr(err) - // return - // } - // shutdownFuncs = append(shutdownFuncs, loggerProvider.Shutdown) - // global.SetLoggerProvider(loggerProvider) + loggerProvider, err := newLoggerProvider(ctx) + if err != nil { + handleErr(ctx, err) + return nil, err + } + shutdownFuncs = append(shutdownFuncs, loggerProvider.Shutdown) + global.SetLoggerProvider(loggerProvider) return shutdown, nil } @@ -110,14 +110,17 @@ func newMeterProvider(ctx context.Context) (*metric.MeterProvider, error) { exp, metric.WithInterval(15*time.Second)))), nil } -// func newLoggerProvider() (*log.LoggerProvider, error) { -// logExporter, err := stdoutlog.New() -// if err != nil { -// return nil, err -// } -// -// loggerProvider := log.NewLoggerProvider( -// log.WithProcessor(log.NewBatchProcessor(logExporter)), -// ) -// return loggerProvider, nil -// } +func newLoggerProvider(ctx context.Context) (*log.LoggerProvider, error) { + logExporter, err := otlploggrpc.New( + ctx, + otlploggrpc.WithInsecure(), + otlploggrpc.WithEndpoint(otelEndpoint)) + if err != nil { + return nil, err + } + + loggerProvider := log.NewLoggerProvider( + log.WithProcessor(log.NewBatchProcessor(logExporter)), + ) + return loggerProvider, nil +} diff --git a/internal/service/account.go b/internal/service/account.go index bced1db..f05513b 100644 --- a/internal/service/account.go +++ b/internal/service/account.go @@ -3,8 +3,8 @@ package service import ( "errors" "fmt" + "log/slog" "spend-sparrow/internal/db" - "spend-sparrow/internal/log" "spend-sparrow/internal/types" "github.com/google/uuid" @@ -85,7 +85,7 @@ func (s AccountImpl) UpdateName(user *types.User, id string, name string) (*type } uuid, err := uuid.Parse(id) if err != nil { - log.L.Error("account update", "err", err) + slog.Error("account update", "err", err) return nil, fmt.Errorf("could not parse Id: %w", ErrBadRequest) } @@ -141,7 +141,7 @@ func (s AccountImpl) Get(user *types.User, id string) (*types.Account, error) { } uuid, err := uuid.Parse(id) if err != nil { - log.L.Error("account get", "err", err) + slog.Error("account get", "err", err) return nil, fmt.Errorf("could not parse Id: %w", ErrBadRequest) } @@ -150,7 +150,7 @@ func (s AccountImpl) Get(user *types.User, id string) (*types.Account, error) { SELECT * FROM account WHERE user_id = ? AND id = ?`, user.Id, uuid) err = db.TransformAndLogDbError("account Get", nil, err) if err != nil { - log.L.Error("account get", "err", err) + slog.Error("account get", "err", err) return nil, err } @@ -179,7 +179,7 @@ func (s AccountImpl) Delete(user *types.User, id string) error { } uuid, err := uuid.Parse(id) if err != nil { - log.L.Error("account delete", "err", err) + slog.Error("account delete", "err", err) return fmt.Errorf("could not parse Id: %w", ErrBadRequest) } diff --git a/internal/service/auth.go b/internal/service/auth.go index 0e347c7..29f0928 100644 --- a/internal/service/auth.go +++ b/internal/service/auth.go @@ -4,9 +4,9 @@ import ( "context" "crypto/subtle" "errors" + "log/slog" "net/mail" "spend-sparrow/internal/db" - "spend-sparrow/internal/log" mailTemplate "spend-sparrow/internal/template/mail" "spend-sparrow/internal/types" "strings" @@ -125,7 +125,7 @@ func (service AuthImpl) SignInAnonymous() (*types.Session, error) { return nil, types.ErrInternal } - log.L.Info("anonymous session created", "session-id", session.Id) + slog.Info("anonymous session created", "session-id", session.Id) return session, nil } @@ -201,7 +201,7 @@ func (service AuthImpl) SendVerificationMail(userId uuid.UUID, email string) { var w strings.Builder err = mailTemplate.Register(service.serverSettings.BaseUrl, token.Token).Render(context.Background(), &w) if err != nil { - log.L.Error("Could not render welcome email", "err", err) + slog.Error("Could not render welcome email", "err", err) return } @@ -340,7 +340,7 @@ func (service AuthImpl) SendForgotPasswordMail(email string) error { var mail strings.Builder err = mailTemplate.ResetPassword(service.serverSettings.BaseUrl, token.Token).Render(context.Background(), &mail) if err != nil { - log.L.Error("Could not render reset password email", "err", err) + slog.Error("Could not render reset password email", "err", err) return types.ErrInternal } service.mail.SendMail(email, "Reset Password", mail.String()) @@ -370,7 +370,7 @@ func (service AuthImpl) ForgotPassword(tokenStr string, newPass string) error { user, err := service.db.GetUser(token.UserId) if err != nil { - log.L.Error("Could not get user from token", "err", err) + slog.Error("Could not get user from token", "err", err) return types.ErrInternal } @@ -440,7 +440,7 @@ func (service AuthImpl) GetCsrfToken(session *types.Session) (string, error) { return "", types.ErrInternal } - log.L.Info("CSRF-Token created", "token", tokenStr) + slog.Info("CSRF-Token created", "token", tokenStr) return tokenStr, nil } diff --git a/internal/service/mail.go b/internal/service/mail.go index 1801dc2..b90cbb0 100644 --- a/internal/service/mail.go +++ b/internal/service/mail.go @@ -2,8 +2,8 @@ package service import ( "fmt" + "log/slog" "net/smtp" - "spend-sparrow/internal/log" "spend-sparrow/internal/types" ) @@ -47,9 +47,9 @@ func (m MailImpl) internalSendMail(to string, subject string, message string) { subject, message) - log.L.Info("sending mail", "to", to) + slog.Info("sending mail", "to", to) err := smtp.SendMail(s.Host+":"+s.Port, auth, s.FromMail, []string{to}, []byte(msg)) if err != nil { - log.L.Error("Error sending mail", "err", err) + slog.Error("Error sending mail", "err", err) } } diff --git a/internal/service/random_generator.go b/internal/service/random_generator.go index 33dd90f..d8193f8 100644 --- a/internal/service/random_generator.go +++ b/internal/service/random_generator.go @@ -3,7 +3,7 @@ package service import ( "crypto/rand" "encoding/base64" - "spend-sparrow/internal/log" + "log/slog" "spend-sparrow/internal/types" "github.com/google/uuid" @@ -26,7 +26,7 @@ func (r *RandomImpl) Bytes(size int) ([]byte, error) { b := make([]byte, 32) _, err := rand.Read(b) if err != nil { - log.L.Error("Error generating random bytes", "err", err) + slog.Error("Error generating random bytes", "err", err) return []byte{}, types.ErrInternal } @@ -36,7 +36,7 @@ func (r *RandomImpl) Bytes(size int) ([]byte, error) { func (r *RandomImpl) String(size int) (string, error) { bytes, err := r.Bytes(size) if err != nil { - log.L.Error("Error generating random string", "err", err) + slog.Error("Error generating random string", "err", err) return "", types.ErrInternal } @@ -46,7 +46,7 @@ func (r *RandomImpl) String(size int) (string, error) { func (r *RandomImpl) UUID() (uuid.UUID, error) { id, err := uuid.NewRandom() if err != nil { - log.L.Error("Error generating random UUID", "err", err) + slog.Error("Error generating random UUID", "err", err) return uuid.Nil, types.ErrInternal } diff --git a/internal/service/transaction.go b/internal/service/transaction.go index 01dc2ee..3754a76 100644 --- a/internal/service/transaction.go +++ b/internal/service/transaction.go @@ -3,8 +3,8 @@ package service import ( "errors" "fmt" + "log/slog" "spend-sparrow/internal/db" - "spend-sparrow/internal/log" "spend-sparrow/internal/types" "time" @@ -208,7 +208,7 @@ func (s TransactionImpl) Get(user *types.User, id string) (*types.Transaction, e } uuid, err := uuid.Parse(id) if err != nil { - log.L.Error("transaction get", "err", err) + slog.Error("transaction get", "err", err) return nil, fmt.Errorf("could not parse Id: %w", ErrBadRequest) } @@ -260,7 +260,7 @@ func (s TransactionImpl) Delete(user *types.User, id string) error { } uuid, err := uuid.Parse(id) if err != nil { - log.L.Error("transaction delete", "err", err) + slog.Error("transaction delete", "err", err) return fmt.Errorf("could not parse Id: %w", ErrBadRequest) } @@ -362,7 +362,7 @@ func (s TransactionImpl) RecalculateBalances(user *types.User) error { defer func() { err := rows.Close() if err != nil { - log.L.Error("transaction RecalculateBalances", "err", err) + slog.Error("transaction RecalculateBalances", "err", err) } }() @@ -455,7 +455,7 @@ func (s TransactionImpl) validateAndEnrichTransaction(tx *sqlx.Tx, oldTransactio return nil, err } if rowCount == 0 { - log.L.Error("transaction validate", "err", err) + slog.Error("transaction validate", "err", err) return nil, fmt.Errorf("account not found: %w", ErrBadRequest) } } diff --git a/internal/service/transaction_recurring.go b/internal/service/transaction_recurring.go index 434fc27..c4825fe 100644 --- a/internal/service/transaction_recurring.go +++ b/internal/service/transaction_recurring.go @@ -3,9 +3,9 @@ package service import ( "errors" "fmt" + "log/slog" "math" "spend-sparrow/internal/db" - "spend-sparrow/internal/log" "spend-sparrow/internal/types" "strconv" "time" @@ -92,7 +92,7 @@ func (s TransactionRecurringImpl) Update( } uuid, err := uuid.Parse(input.Id) if err != nil { - log.L.Error("transactionRecurring update", "err", err) + slog.Error("transactionRecurring update", "err", err) return nil, fmt.Errorf("could not parse Id: %w", ErrBadRequest) } @@ -175,7 +175,7 @@ func (s TransactionRecurringImpl) GetAllByAccount(user *types.User, accountId st accountUuid, err := uuid.Parse(accountId) if err != nil { - log.L.Error("transactionRecurring GetAllByAccount", "err", err) + slog.Error("transactionRecurring GetAllByAccount", "err", err) return nil, fmt.Errorf("could not parse accountId: %w", ErrBadRequest) } @@ -230,7 +230,7 @@ func (s TransactionRecurringImpl) GetAllByTreasureChest( treasureChestUuid, err := uuid.Parse(treasureChestId) if err != nil { - log.L.Error("transactionRecurring GetAllByTreasureChest", "err", err) + slog.Error("transactionRecurring GetAllByTreasureChest", "err", err) return nil, fmt.Errorf("could not parse treasureChestId: %w", ErrBadRequest) } @@ -281,7 +281,7 @@ func (s TransactionRecurringImpl) Delete(user *types.User, id string) error { } uuid, err := uuid.Parse(id) if err != nil { - log.L.Error("transactionRecurring delete", "err", err) + slog.Error("transactionRecurring delete", "err", err) return fmt.Errorf("could not parse Id: %w", ErrBadRequest) } @@ -413,7 +413,7 @@ func (s TransactionRecurringImpl) validateAndEnrichTransactionRecurring( if input.AccountId != "" { temp, err := uuid.Parse(input.AccountId) if err != nil { - log.L.Error("transactionRecurring validate", "err", err) + slog.Error("transactionRecurring validate", "err", err) return nil, fmt.Errorf("could not parse accountId: %w", ErrBadRequest) } accountUuid = &temp @@ -423,7 +423,7 @@ func (s TransactionRecurringImpl) validateAndEnrichTransactionRecurring( return nil, err } if rowCount == 0 { - log.L.Error("transactionRecurring validate", "err", err) + slog.Error("transactionRecurring validate", "err", err) return nil, fmt.Errorf("account not found: %w", ErrBadRequest) } @@ -433,7 +433,7 @@ func (s TransactionRecurringImpl) validateAndEnrichTransactionRecurring( if input.TreasureChestId != "" { temp, err := uuid.Parse(input.TreasureChestId) if err != nil { - log.L.Error("transactionRecurring validate", "err", err) + slog.Error("transactionRecurring validate", "err", err) return nil, fmt.Errorf("could not parse treasureChestId: %w", ErrBadRequest) } treasureChestUuid = &temp @@ -453,17 +453,17 @@ func (s TransactionRecurringImpl) validateAndEnrichTransactionRecurring( } if !hasAccount && !hasTreasureChest { - log.L.Error("transactionRecurring validate", "err", err) + slog.Error("transactionRecurring validate", "err", err) return nil, fmt.Errorf("either account or treasure chest is required: %w", ErrBadRequest) } if hasAccount && hasTreasureChest { - log.L.Error("transactionRecurring validate", "err", err) + slog.Error("transactionRecurring validate", "err", err) return nil, fmt.Errorf("either account or treasure chest is required, not both: %w", ErrBadRequest) } valueFloat, err := strconv.ParseFloat(input.Value, 64) if err != nil { - log.L.Error("transactionRecurring validate", "err", err) + slog.Error("transactionRecurring validate", "err", err) return nil, fmt.Errorf("could not parse value: %w", ErrBadRequest) } value := int64(math.Round(valueFloat * DECIMALS_MULTIPLIER)) @@ -482,18 +482,18 @@ func (s TransactionRecurringImpl) validateAndEnrichTransactionRecurring( } intervalMonths, err = strconv.ParseInt(input.IntervalMonths, 10, 0) if err != nil { - log.L.Error("transactionRecurring validate", "err", err) + slog.Error("transactionRecurring validate", "err", err) return nil, fmt.Errorf("could not parse intervalMonths: %w", ErrBadRequest) } if intervalMonths < 1 { - log.L.Error("transactionRecurring validate", "err", err) + slog.Error("transactionRecurring validate", "err", err) return nil, fmt.Errorf("intervalMonths needs to be greater than 0: %w", ErrBadRequest) } var nextExecution *time.Time = nil if input.NextExecution != "" { t, err := time.Parse("2006-01-02", input.NextExecution) if err != nil { - log.L.Error("transaction validate", "err", err) + slog.Error("transaction validate", "err", err) return nil, fmt.Errorf("could not parse timestamp: %w", ErrBadRequest) } diff --git a/internal/service/treasure_chest.go b/internal/service/treasure_chest.go index c606e14..17570e0 100644 --- a/internal/service/treasure_chest.go +++ b/internal/service/treasure_chest.go @@ -3,9 +3,9 @@ package service import ( "errors" "fmt" + "log/slog" "slices" "spend-sparrow/internal/db" - "spend-sparrow/internal/log" "spend-sparrow/internal/types" "github.com/google/uuid" @@ -97,7 +97,7 @@ func (s TreasureChestImpl) Update(user *types.User, idStr, parentId, name string } id, err := uuid.Parse(idStr) if err != nil { - log.L.Error("treasureChest update", "err", err) + slog.Error("treasureChest update", "err", err) return nil, fmt.Errorf("could not parse Id: %w", ErrBadRequest) } @@ -175,7 +175,7 @@ func (s TreasureChestImpl) Get(user *types.User, id string) (*types.TreasureChes } uuid, err := uuid.Parse(id) if err != nil { - log.L.Error("treasureChest get", "err", err) + slog.Error("treasureChest get", "err", err) return nil, fmt.Errorf("could not parse Id: %w", ErrBadRequest) } @@ -213,7 +213,7 @@ func (s TreasureChestImpl) Delete(user *types.User, idStr string) error { } id, err := uuid.Parse(idStr) if err != nil { - log.L.Error("treasureChest delete", "err", err) + slog.Error("treasureChest delete", "err", err) return fmt.Errorf("could not parse Id: %w", ErrBadRequest) } diff --git a/internal/types/settings.go b/internal/types/settings.go index cb291b1..1d3f47a 100644 --- a/internal/types/settings.go +++ b/internal/types/settings.go @@ -2,7 +2,7 @@ package types import ( "errors" - "spend-sparrow/internal/log" + "log/slog" ) var ( @@ -10,8 +10,7 @@ var ( ) type Settings struct { - Port string - OtelEnabled bool + Port string BaseUrl string Environment string @@ -41,27 +40,27 @@ func NewSettingsFromEnv(env func(string) string) (*Settings, error) { settings := &Settings{ Port: env("PORT"), - OtelEnabled: env("OTEL_ENABLED") == "true", BaseUrl: env("BASE_URL"), Environment: env("ENVIRONMENT"), Smtp: smtp, } if settings.BaseUrl == "" { - log.L.Error("BASE_URL must be set") + slog.Error("BASE_URL must be set") return nil, ErrMissingConfig } if settings.Port == "" { - log.L.Error("PORT must be set") + slog.Error("PORT must be set") return nil, ErrMissingConfig } if settings.Environment == "" { - log.L.Error("ENVIRONMENT must be set") + slog.Error("ENVIRONMENT must be set") return nil, ErrMissingConfig } - log.L.Info("settings read", "BASE_URL", settings.BaseUrl) - log.L.Info("settings read", "ENVIRONMENT", settings.Environment) + slog.Info("settings read", "BASE_URL", settings.BaseUrl) + slog.Info("settings read", "ENVIRONMENT", settings.Environment) + slog.Info("settings read", "ENVIRONMENT", settings.Environment) return settings, nil } @@ -77,29 +76,33 @@ func getSmtpSettings(env func(string) string) (*SmtpSettings, error) { } if smtp.Host == "" { - log.L.Error("SMTP_HOST must be set") + slog.Error("SMTP_HOST must be set") return nil, ErrMissingConfig } if smtp.Port == "" { - log.L.Error("SMTP_PORT must be set") + slog.Error("SMTP_PORT must be set") return nil, ErrMissingConfig } if smtp.User == "" { - log.L.Error("SMTP_USER must be set") + slog.Error("SMTP_USER must be set") return nil, ErrMissingConfig } if smtp.Pass == "" { - log.L.Error("SMTP_PASS must be set") + slog.Error("SMTP_PASS must be set") return nil, ErrMissingConfig } if smtp.FromMail == "" { - log.L.Error("SMTP_FROM_MAIL must be set") + slog.Error("SMTP_FROM_MAIL must be set") return nil, ErrMissingConfig } if smtp.FromName == "" { - log.L.Error("SMTP_FROM_NAME must be set") + slog.Error("SMTP_FROM_NAME must be set") return nil, ErrMissingConfig } return &smtp, nil } + +func IsOtelEnabled(env func(string) string) bool { + return env("OTEL_ENABLED") == "true" +} diff --git a/internal/utils/http.go b/internal/utils/http.go index d741c87..a170dc0 100644 --- a/internal/utils/http.go +++ b/internal/utils/http.go @@ -2,18 +2,17 @@ package utils import ( "fmt" + "log/slog" "net/http" "strings" "time" - - "spend-sparrow/internal/log" ) func TriggerToast(w http.ResponseWriter, r *http.Request, class string, message string) { if IsHtmx(r) { w.Header().Set("Hx-Trigger", fmt.Sprintf(`{"toast": "%v|%v"}`, class, strings.ReplaceAll(message, `"`, `\"`))) } else { - log.L.Error("Trying to trigger toast in non-HTMX request") + slog.Error("Trying to trigger toast in non-HTMX request") } } diff --git a/main.go b/main.go index c42b9f5..abd9bf8 100644 --- a/main.go +++ b/main.go @@ -2,9 +2,9 @@ package main import ( "context" + "log/slog" "os" "spend-sparrow/internal" - "spend-sparrow/internal/log" "github.com/jmoiron/sqlx" "github.com/joho/godotenv" @@ -14,23 +14,23 @@ import ( func main() { err := godotenv.Load() if err != nil { - log.L.Error("Error loading .env file") + slog.Error("Error loading .env file") return } db, err := sqlx.Open("sqlite3", "./data/spend-sparrow.db") if err != nil { - log.L.Error("Could not open Database data.db", "err", err) + slog.Error("Could not open Database data.db", "err", err) return } defer func() { if err = db.Close(); err != nil { - log.L.Error("Database close failed", "err", err) + slog.Error("Database close failed", "err", err) } }() if err = internal.Run(context.Background(), db, "", os.Getenv); err != nil { - log.L.Error("Error running server", "err", err) + slog.Error("Error running server", "err", err) return } } diff --git a/test/auth_test.go b/test/auth_test.go index 903e517..e14e539 100644 --- a/test/auth_test.go +++ b/test/auth_test.go @@ -18,7 +18,6 @@ import ( var ( settings = types.Settings{ Port: "", - OtelEnabled: false, BaseUrl: "", Environment: "test", Smtp: nil,