From fb347b96df98e27c96f725f34c09e8f244f3f116 Mon Sep 17 00:00:00 2001 From: sneak Date: Sat, 27 Dec 2025 12:02:05 +0700 Subject: [PATCH] Replace zerolog with log/slog from stdlib - Rewrite logger package to use slog with LevelVar for dynamic levels - Update all packages to use *slog.Logger instead of *zerolog.Logger - Use TextHandler for TTY (dev), JSONHandler for production - Add make check target (runs lint + test) - Add make test target --- Makefile | 5 ++ go.mod | 6 --- go.sum | 21 +------- internal/config/config.go | 9 ++-- internal/database/database.go | 8 +-- internal/handlers/handlers.go | 6 +-- internal/handlers/index.go | 2 +- internal/handlers/login.go | 2 +- internal/handlers/signup.go | 4 +- internal/healthcheck/healthcheck.go | 4 +- internal/logger/logger.go | 82 ++++++++++------------------- internal/middleware/middleware.go | 34 ++++++------ internal/server/http.go | 4 +- internal/server/server.go | 18 +++---- 14 files changed, 76 insertions(+), 129 deletions(-) diff --git a/Makefile b/Makefile index 06ebe2d..98858ba 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,11 @@ lint: golangci-lint run sh -c 'test -z "$$(gofmt -l .)"' +test: + go test ./... + +check: lint test + debug: ./$(FN)d DEBUG=1 GOTRACEBACK=all ./$(FN)d diff --git a/go.mod b/go.mod index cb4c74e..7f2510c 100644 --- a/go.mod +++ b/go.mod @@ -9,11 +9,9 @@ require ( github.com/go-chi/cors v1.2.1 github.com/joho/godotenv v1.4.0 github.com/prometheus/client_golang v1.14.0 - github.com/rs/zerolog v1.28.0 github.com/slok/go-http-metrics v0.10.0 github.com/spf13/viper v1.14.0 go.uber.org/fx v1.18.2 - google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e ) require ( @@ -23,8 +21,6 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/magiconair/properties v1.8.6 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect @@ -41,10 +37,8 @@ require ( go.uber.org/dig v1.15.0 // indirect go.uber.org/multierr v1.8.0 // indirect go.uber.org/zap v1.21.0 // indirect - golang.org/x/net v0.0.0-20221014081412-f15817d10f9b // indirect golang.org/x/sys v0.2.0 // indirect golang.org/x/text v0.4.0 // indirect - google.golang.org/grpc v1.50.1 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index dd7b16b..3adcd61 100644 --- a/go.sum +++ b/go.sum @@ -46,6 +46,7 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -61,7 +62,6 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -93,7 +93,6 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -184,12 +183,6 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= @@ -242,9 +235,6 @@ github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5 github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= -github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= -github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -294,6 +284,7 @@ go.uber.org/dig v1.15.0 h1:vq3YWr8zRj1eFGC7Gvf907hE0eRjPTZ1d3xHadD6liE= go.uber.org/dig v1.15.0/go.mod h1:pKHs0wMynzL6brANhB2hLMro+zalv1osARTviTcqHLM= go.uber.org/fx v1.18.2 h1:bUNI6oShr+OVFQeU8cDNbnN7VFsu+SsjHzUF51V/GAU= go.uber.org/fx v1.18.2/go.mod h1:g0V1KMQ66zIRk8bLu3Ea5Jt2w/cHlOIp4wdRsgh0JaY= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= @@ -380,7 +371,6 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20221014081412-f15817d10f9b h1:tvrvnPFcdzp294diPnrdZZZ8XUt2Tyj7svb7X52iDuU= -golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -448,11 +438,8 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -585,8 +572,6 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e h1:S9GbmC1iCgvbLyAokVCwiO6tVIrU9Y7c5oMx1V/ki/Y= -google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -603,8 +588,6 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/internal/config/config.go b/internal/config/config.go index dc7091a..001d71e 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -2,10 +2,10 @@ package config import ( "fmt" + "log/slog" "git.eeqj.de/sneak/gohttpserver/internal/globals" "git.eeqj.de/sneak/gohttpserver/internal/logger" - "github.com/rs/zerolog" "github.com/spf13/viper" "go.uber.org/fx" @@ -37,7 +37,7 @@ type Config struct { Port int SentryDSN string params *ConfigParams - log *zerolog.Logger + log *slog.Logger } func New(lc fx.Lifecycle, params ConfigParams) (*Config, error) { @@ -69,9 +69,8 @@ func New(lc fx.Lifecycle, params ConfigParams) (*Config, error) { // Config file not found; ignore error if desired } else { // Config file was found but another error was produced - log.Panic(). - Err(err). - Msg("config file malformed") + log.Error("config file malformed", "error", err) + panic(err) } } diff --git a/internal/database/database.go b/internal/database/database.go index a996c3a..738713e 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -2,10 +2,10 @@ package database import ( "context" + "log/slog" "git.eeqj.de/sneak/gohttpserver/internal/config" "git.eeqj.de/sneak/gohttpserver/internal/logger" - "github.com/rs/zerolog" "go.uber.org/fx" // spooky action at a distance! @@ -26,7 +26,7 @@ type DatabaseParams struct { type Database struct { URL string - log *zerolog.Logger + log *slog.Logger params *DatabaseParams } @@ -35,11 +35,11 @@ func New(lc fx.Lifecycle, params DatabaseParams) (*Database, error) { s.params = ¶ms s.log = params.Logger.Get() - s.log.Info().Msg("Database instantiated") + s.log.Info("Database instantiated") lc.Append(fx.Hook{ OnStart: func(ctx context.Context) error { - s.log.Info().Msg("Database OnStart Hook") + s.log.Info("Database OnStart Hook") // FIXME connect to db return nil }, diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go index e9d652f..6f89b66 100644 --- a/internal/handlers/handlers.go +++ b/internal/handlers/handlers.go @@ -3,13 +3,13 @@ package handlers import ( "context" "encoding/json" + "log/slog" "net/http" "git.eeqj.de/sneak/gohttpserver/internal/database" "git.eeqj.de/sneak/gohttpserver/internal/globals" "git.eeqj.de/sneak/gohttpserver/internal/healthcheck" "git.eeqj.de/sneak/gohttpserver/internal/logger" - "github.com/rs/zerolog" "go.uber.org/fx" ) @@ -23,7 +23,7 @@ type HandlersParams struct { type Handlers struct { params *HandlersParams - log *zerolog.Logger + log *slog.Logger hc *healthcheck.Healthcheck } @@ -47,7 +47,7 @@ func (s *Handlers) respondJSON(w http.ResponseWriter, r *http.Request, data inte if data != nil { err := json.NewEncoder(w).Encode(data) if err != nil { - s.log.Error().Err(err).Msg("json encode error") + s.log.Error("json encode error", "error", err) } } } diff --git a/internal/handlers/index.go b/internal/handlers/index.go index 7895d49..0d1c804 100644 --- a/internal/handlers/index.go +++ b/internal/handlers/index.go @@ -12,7 +12,7 @@ func (s *Handlers) HandleIndex() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { err := t.ExecuteTemplate(w, "index.html", nil) if err != nil { - s.log.Error().Err(err).Msg("") + s.log.Error("template execution failed", "error", err) http.Error(w, http.StatusText(500), 500) } } diff --git a/internal/handlers/login.go b/internal/handlers/login.go index f15b847..09ac0d8 100644 --- a/internal/handlers/login.go +++ b/internal/handlers/login.go @@ -12,7 +12,7 @@ func (s *Handlers) HandleLoginGET() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { err := t.ExecuteTemplate(w, "login.html", nil) if err != nil { - s.log.Error().Err(err).Msg("") + s.log.Error("template execution failed", "error", err) http.Error(w, http.StatusText(500), 500) } } diff --git a/internal/handlers/signup.go b/internal/handlers/signup.go index 12e0243..ab4d1d1 100644 --- a/internal/handlers/signup.go +++ b/internal/handlers/signup.go @@ -12,7 +12,7 @@ func (s *Handlers) HandleSignupGET() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { err := t.ExecuteTemplate(w, "signup.html", nil) if err != nil { - s.log.Error().Err(err).Msg("") + s.log.Error("template execution failed", "error", err) http.Error(w, http.StatusText(500), 500) } } @@ -27,7 +27,7 @@ func (s *Handlers) HandleSignupPOST() http.HandlerFunc { err := t.ExecuteTemplate(w, "signup.html", nil) if err != nil { - s.log.Error().Err(err).Msg("") + s.log.Error("template execution failed", "error", err) http.Error(w, http.StatusText(500), 500) } } diff --git a/internal/healthcheck/healthcheck.go b/internal/healthcheck/healthcheck.go index c7ff3a9..9d6a16c 100644 --- a/internal/healthcheck/healthcheck.go +++ b/internal/healthcheck/healthcheck.go @@ -2,13 +2,13 @@ package healthcheck import ( "context" + "log/slog" "time" "git.eeqj.de/sneak/gohttpserver/internal/config" "git.eeqj.de/sneak/gohttpserver/internal/database" "git.eeqj.de/sneak/gohttpserver/internal/globals" "git.eeqj.de/sneak/gohttpserver/internal/logger" - "github.com/rs/zerolog" "go.uber.org/fx" ) @@ -22,7 +22,7 @@ type HealthcheckParams struct { type Healthcheck struct { StartupTime time.Time - log *zerolog.Logger + log *slog.Logger params *HealthcheckParams } diff --git a/internal/logger/logger.go b/internal/logger/logger.go index c127ba2..1597482 100644 --- a/internal/logger/logger.go +++ b/internal/logger/logger.go @@ -1,12 +1,10 @@ package logger import ( - "io" + "log/slog" "os" - "time" "git.eeqj.de/sneak/gohttpserver/internal/globals" - "github.com/rs/zerolog" "go.uber.org/fx" ) @@ -16,82 +14,56 @@ type LoggerParams struct { } type Logger struct { - log *zerolog.Logger + log *slog.Logger + level *slog.LevelVar params LoggerParams } func New(lc fx.Lifecycle, params LoggerParams) (*Logger, error) { l := new(Logger) + l.level = new(slog.LevelVar) + l.level.Set(slog.LevelInfo) - // always log in UTC - zerolog.TimestampFunc = func() time.Time { - return time.Now().UTC() - } - zerolog.SetGlobalLevel(zerolog.InfoLevel) - + // TTY detection for dev vs prod output tty := false if fileInfo, _ := os.Stdout.Stat(); (fileInfo.Mode() & os.ModeCharDevice) != 0 { tty = true } - var writers []io.Writer - + var handler slog.Handler if tty { - // this does cool colorization for console/dev - consoleWriter := zerolog.NewConsoleWriter( - func(w *zerolog.ConsoleWriter) { - // Customize time format - w.TimeFormat = time.RFC3339Nano - }, - ) - - writers = append(writers, consoleWriter) + // Text output for development + handler = slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ + Level: l.level, + AddSource: true, + }) } else { - // log json in prod for the machines - writers = append(writers, os.Stdout) + // JSON output for production + handler = slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: l.level, + AddSource: true, + }) } - /* - // this is how you log to a file, if you do that - // sort of thing still - logfile := viper.GetString("Logfile") - if logfile != "" { - logfileDir := filepath.Dir(logfile) - err := goutil.Mkdirp(logfileDir) - if err != nil { - log.Error().Err(err).Msg("unable to create log dir") - } - - hp.logfh, err = os.OpenFile(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) - if err != nil { - panic("unable to open logfile: " + err.Error()) - } - - writers = append(writers, hp.logfh) - */ - - multi := zerolog.MultiLevelWriter(writers...) - logger := zerolog.New(multi).With().Timestamp().Logger().With().Caller().Logger() - - l.log = &logger - // log.Logger = logger + l.log = slog.New(handler) + l.params = params return l, nil } func (l *Logger) EnableDebugLogging() { - zerolog.SetGlobalLevel(zerolog.DebugLevel) - l.log.Debug().Bool("debug", true).Send() + l.level.Set(slog.LevelDebug) + l.log.Debug("debug logging enabled", "debug", true) } -func (l *Logger) Get() *zerolog.Logger { +func (l *Logger) Get() *slog.Logger { return l.log } func (l *Logger) Identify() { - l.log.Info(). - Str("appname", l.params.Globals.Appname). - Str("version", l.params.Globals.Version). - Str("buildarch", l.params.Globals.Buildarch). - Msg("starting") + l.log.Info("starting", + "appname", l.params.Globals.Appname, + "version", l.params.Globals.Version, + "buildarch", l.params.Globals.Buildarch, + ) } diff --git a/internal/middleware/middleware.go b/internal/middleware/middleware.go index a6605ed..402b111 100644 --- a/internal/middleware/middleware.go +++ b/internal/middleware/middleware.go @@ -1,6 +1,7 @@ package middleware import ( + "log/slog" "net" "net/http" "time" @@ -11,7 +12,6 @@ import ( basicauth "github.com/99designs/basicauth-go" "github.com/go-chi/chi/middleware" "github.com/go-chi/cors" - "github.com/rs/zerolog" metrics "github.com/slok/go-http-metrics/metrics/prometheus" ghmm "github.com/slok/go-http-metrics/middleware" "github.com/slok/go-http-metrics/middleware/std" @@ -27,7 +27,7 @@ type MiddlewareParams struct { } type Middleware struct { - log *zerolog.Logger + log *slog.Logger params *MiddlewareParams } @@ -38,9 +38,6 @@ func New(lc fx.Lifecycle, params MiddlewareParams) (*Middleware, error) { return s, nil } -// the following is from -// https://learning-cloud-native-go.github.io/docs/a6.adding_zerolog_logger/ - func ipFromHostPort(hp string) string { h, _, err := net.SplitHostPort(hp) if err != nil { @@ -70,7 +67,6 @@ func (lrw *loggingResponseWriter) WriteHeader(code int) { // this returns a Middleware that is designed to do every request through the // mux, note the signature: func (s *Middleware) Logging() func(http.Handler) http.Handler { - // FIXME this should use https://github.com/google/go-cloud/blob/master/server/requestlog/requestlog.go return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() @@ -78,18 +74,18 @@ func (s *Middleware) Logging() func(http.Handler) http.Handler { ctx := r.Context() defer func() { latency := time.Since(start) - s.log.Info(). - Time("request_start", start). - Str("method", r.Method). - Str("url", r.URL.String()). - Str("useragent", r.UserAgent()). - Str("request_id", ctx.Value(middleware.RequestIDKey).(string)). - Str("referer", r.Referer()). - Str("proto", r.Proto). - Str("remoteIP", ipFromHostPort(r.RemoteAddr)). - Int("status", lrw.statusCode). - Int("latency_ms", int(latency.Milliseconds())). - Send() + s.log.InfoContext(ctx, "request", + "request_start", start, + "method", r.Method, + "url", r.URL.String(), + "useragent", r.UserAgent(), + "request_id", ctx.Value(middleware.RequestIDKey).(string), + "referer", r.Referer(), + "proto", r.Proto, + "remoteIP", ipFromHostPort(r.RemoteAddr), + "status", lrw.statusCode, + "latency_ms", latency.Milliseconds(), + ) }() next.ServeHTTP(lrw, r) @@ -116,7 +112,7 @@ func (s *Middleware) Auth() func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // CHANGEME you'll want to change this to do stuff. - s.log.Info().Msg("AUTH: before request") + s.log.Info("AUTH: before request") next.ServeHTTP(w, r) }) } diff --git a/internal/server/http.go b/internal/server/http.go index 6c25ffc..6c1bf25 100644 --- a/internal/server/http.go +++ b/internal/server/http.go @@ -20,9 +20,9 @@ func (s *Server) serveUntilShutdown() { // this does any necessary setup in each handler s.SetupRoutes() - s.log.Info().Str("listenaddr", listenAddr).Msg("http begin listen") + s.log.Info("http begin listen", "listenaddr", listenAddr) if err := s.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { - s.log.Error().Msgf("listen:%+s\n", err) + s.log.Error("listen error", "error", err) if s.cancelFunc != nil { s.cancelFunc() } diff --git a/internal/server/server.go b/internal/server/server.go index f3c6a9f..7f67eac 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -3,6 +3,7 @@ package server import ( "context" "fmt" + "log/slog" "net/http" "os" "os/signal" @@ -14,7 +15,6 @@ import ( "git.eeqj.de/sneak/gohttpserver/internal/handlers" "git.eeqj.de/sneak/gohttpserver/internal/logger" "git.eeqj.de/sneak/gohttpserver/internal/middleware" - "github.com/rs/zerolog" "go.uber.org/fx" "github.com/getsentry/sentry-go" @@ -43,7 +43,7 @@ type Server struct { startupTime time.Time exitCode int sentryEnabled bool - log *zerolog.Logger + log *slog.Logger ctx context.Context cancelFunc context.CancelFunc httpServer *http.Server @@ -103,10 +103,10 @@ func (s *Server) enableSentry() { Release: fmt.Sprintf("%s-%s", s.params.Globals.Appname, s.params.Globals.Version), }) if err != nil { - s.log.Fatal().Err(err).Msg("sentry init failure") - return + s.log.Error("sentry init failure", "error", err) + os.Exit(1) } - s.log.Info().Msg("sentry error reporting activated") + s.log.Info("sentry error reporting activated") s.sentryEnabled = true } @@ -121,7 +121,7 @@ func (s *Server) serve() int { signal.Notify(c, os.Interrupt, syscall.SIGTERM) // block and wait for signal sig := <-c - s.log.Info().Msgf("signal received: %+v", sig) + s.log.Info("signal received", "signal", sig) if s.cancelFunc != nil { // cancelling the main context will trigger a clean // shutdown. @@ -140,7 +140,7 @@ func (s *Server) serve() int { } func (s *Server) cleanupForExit() { - s.log.Info().Msg("cleaning up") + s.log.Info("cleaning up") // FIXME unimplemented // close database connections or whatever } @@ -150,9 +150,7 @@ func (s *Server) cleanShutdown() { s.exitCode = 0 ctxShutdown, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second) if err := s.httpServer.Shutdown(ctxShutdown); err != nil { - s.log.Error(). - Err(err). - Msg("server clean shutdown failed") + s.log.Error("server clean shutdown failed", "error", err) } if shutdownCancel != nil { shutdownCancel()