Skip to content

Commit

Permalink
Migrate to slog for the logging package
Browse files Browse the repository at this point in the history
log/slog is a new package added in Go 1.21 which supports structured
logging.
  • Loading branch information
VoyTechnology committed Sep 12, 2023
1 parent 82a7425 commit 252361e
Show file tree
Hide file tree
Showing 15 changed files with 156 additions and 116 deletions.
39 changes: 22 additions & 17 deletions internal/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ import (
"encoding/json"
"errors"
"fmt"
"log/slog"
"net/http"
"strings"

"go.uber.org/zap"

"safer.place/internal/database"
)

Expand All @@ -27,7 +26,7 @@ type githubTokenResponse struct {
// but if needed this can be expanded.
type Config struct {
Handler http.Handler
Log *zap.Logger
Log *slog.Logger
Domain string
ClientID string
ClientSecret string
Expand All @@ -41,7 +40,7 @@ type Auth struct {
mux *http.ServeMux
cfg *Config
client *http.Client
log *zap.Logger
log *slog.Logger
db database.Database
}

Expand Down Expand Up @@ -69,8 +68,8 @@ func Register(prefix string, cfg *Config) func() (string, http.Handler) {
a.mux.HandleFunc("/", a.index)

cfg.Log.Info("authentication set up",
zap.String("prefix", prefix),
zap.String("callback", a.callbackURL),
slog.String("prefix", prefix),
slog.String("callback", a.callbackURL),
)

return func() (string, http.Handler) {
Expand All @@ -91,7 +90,8 @@ func (a *Auth) index(w http.ResponseWriter, r *http.Request) {
}

func (a *Auth) callback(w http.ResponseWriter, r *http.Request) {
a.log.Info("callback")
ctx := r.Context()
a.log.DebugContext(ctx, "callback")
code := r.URL.Query().Get("code")

if code == "" {
Expand All @@ -105,8 +105,7 @@ func (a *Auth) callback(w http.ResponseWriter, r *http.Request) {
"code": code,
})

req, err := http.NewRequestWithContext(
r.Context(),
req, err := http.NewRequestWithContext(ctx,
http.MethodPost,
"https://github.com/login/oauth/access_token",
bytes.NewBuffer(requestData),
Expand All @@ -118,15 +117,15 @@ func (a *Auth) callback(w http.ResponseWriter, r *http.Request) {
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")

a.log.Info("sending the request to github to validate code")
a.log.DebugContext(ctx, "sending the request to github to validate code")

resp, err := a.client.Do(req)
if err != nil {
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}

a.log.Info("request validated")
a.log.DebugContext(ctx, "request validated")

var tokenData githubTokenResponse
if err := json.NewDecoder(resp.Body).Decode(&tokenData); err != nil {
Expand Down Expand Up @@ -154,29 +153,35 @@ func (a *Auth) callback(w http.ResponseWriter, r *http.Request) {
}

func (a *Auth) authenticated(r *http.Request) (bool, error) {
ctx := r.Context()
cookie, err := r.Cookie("Authorization")
if err != nil {
a.log.Info("cookie not found")
a.log.DebugContext(ctx, "cookie not found")
return false, nil
}

a.log.Info("checking if cookie", zap.Any("cookie", cookie))
a.log.DebugContext(ctx, "checking if cookie",
slog.Any("cookie", cookie),
)

bearerToken := strings.Split(cookie.Value, " ")
if len(bearerToken) != 2 {
a.log.Info("not in 2 parts")
a.log.WarnContext(ctx, "token is not composed of 2 parts")
return false, ErrBadFormat
}

if bearerToken[0] != "Bearer" {
a.log.Info("bad format")
a.log.WarnContext(ctx, "token does not contain Bearer")
return false, ErrBadFormat
}

session := bearerToken[1]

if err := a.db.IsValidSession(r.Context(), session); err != nil {
a.log.Error("unable to authenticate", zap.String("session", session), zap.Error(err))
if err := a.db.IsValidSession(ctx, session); err != nil {
a.log.WarnContext(ctx, "unable to authenticate",
slog.String("session", session),
"error", err,
)
return false, nil
}

Expand Down
12 changes: 6 additions & 6 deletions internal/cmd/saferplace/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import (
"fmt"
"slices"

"go.uber.org/zap"
"golang.org/x/exp/maps"
"golang.org/x/exp/slog"
"golang.org/x/sync/errgroup"
"safer.place/internal/config"
"safer.place/internal/review"
Expand Down Expand Up @@ -130,7 +130,7 @@ func createServices(ctx context.Context, cfg *config.Config, wantedComponents []

func registerConsumer(ctx context.Context, cfg *config.Config, deps *dependencies, eg *errgroup.Group) error {
consumer := review.New(
deps.logger.With(zap.String("component", "review")),
deps.logger.With(slog.String("component", "review")),

Check failure on line 133 in internal/cmd/saferplace/components.go

View workflow job for this annotation

GitHub Actions / Lint

slog: slog.Logger.With arg "slog.String(\"component\", \"review\")" should be a string or a slog.Attr (possible missing key or value) (govet)

Check failure on line 133 in internal/cmd/saferplace/components.go

View workflow job for this annotation

GitHub Actions / Build

slog.Logger.With arg "slog.String(\"component\", \"review\")" should be a string or a slog.Attr (possible missing key or value)
deps.queue,
deps.database,
deps.notifer,
Expand All @@ -146,20 +146,20 @@ func registerConsumer(ctx context.Context, cfg *config.Config, deps *dependencie
func registerReview(_ context.Context, _ *config.Config, deps *dependencies) (service.Service, error) {
return reviewv1.Register(
deps.database,
deps.logger.With(zap.String("service", "reviewv1")),
deps.logger.With(slog.String("service", "reviewv1")),

Check failure on line 149 in internal/cmd/saferplace/components.go

View workflow job for this annotation

GitHub Actions / Lint

slog: slog.Logger.With arg "slog.String(\"service\", \"reviewv1\")" should be a string or a slog.Attr (possible missing key or value) (govet)

Check failure on line 149 in internal/cmd/saferplace/components.go

View workflow job for this annotation

GitHub Actions / Build

slog.Logger.With arg "slog.String(\"service\", \"reviewv1\")" should be a string or a slog.Attr (possible missing key or value)
), nil
}

func registerReport(_ context.Context, _ *config.Config, deps *dependencies) (service.Service, error) {
return reportv1.Register(
deps.queue,
deps.logger.With(zap.String("service", "reportv1")),
deps.logger.With(slog.String("service", "reportv1")),

Check failure on line 156 in internal/cmd/saferplace/components.go

View workflow job for this annotation

GitHub Actions / Lint

slog: slog.Logger.With arg "slog.String(\"service\", \"reportv1\")" should be a string or a slog.Attr (possible missing key or value) (govet)

Check failure on line 156 in internal/cmd/saferplace/components.go

View workflow job for this annotation

GitHub Actions / Build

slog.Logger.With arg "slog.String(\"service\", \"reportv1\")" should be a string or a slog.Attr (possible missing key or value)
), nil
}

func registerUploader(_ context.Context, _ *config.Config, deps *dependencies) (service.Service, error) {
return imageupload.Register(
imageupload.Logger(deps.logger.With(zap.String("service", "imageupload"))),
imageupload.Logger(deps.logger.With(slog.String("service", "imageupload"))),

Check failure on line 162 in internal/cmd/saferplace/components.go

View workflow job for this annotation

GitHub Actions / Lint

slog: slog.Logger.With arg "slog.String(\"service\", \"imageupload\")" should be a string or a slog.Attr (possible missing key or value) (govet)

Check failure on line 162 in internal/cmd/saferplace/components.go

View workflow job for this annotation

GitHub Actions / Build

slog.Logger.With arg "slog.String(\"service\", \"imageupload\")" should be a string or a slog.Attr (possible missing key or value)
imageupload.Tracer(deps.tracing.Tracer("imageupload")),
imageupload.Storage(deps.storage),
), nil
Expand All @@ -168,6 +168,6 @@ func registerUploader(_ context.Context, _ *config.Config, deps *dependencies) (
func registerViewer(_ context.Context, _ *config.Config, deps *dependencies) (service.Service, error) {
return viewerv1.Register(
deps.database,
deps.logger.With(zap.String("service", "viewerv1")),
deps.logger.With(slog.String("service", "viewerv1")),

Check failure on line 171 in internal/cmd/saferplace/components.go

View workflow job for this annotation

GitHub Actions / Lint

slog: slog.Logger.With arg "slog.String(\"service\", \"viewerv1\")" should be a string or a slog.Attr (possible missing key or value) (govet)

Check failure on line 171 in internal/cmd/saferplace/components.go

View workflow job for this annotation

GitHub Actions / Build

slog.Logger.With arg "slog.String(\"service\", \"viewerv1\")" should be a string or a slog.Attr (possible missing key or value)
), nil
}
53 changes: 26 additions & 27 deletions internal/cmd/saferplace/dependencies.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"errors"
"fmt"
"io"
"log/slog"
"os"
"slices"
"time"

Expand All @@ -15,10 +17,9 @@ import (
"github.com/saferplace/webserver-go/certificate"
"github.com/saferplace/webserver-go/certificate/insecure"
"github.com/saferplace/webserver-go/certificate/temporary"

"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"

"safer.place/internal/config"
"safer.place/internal/database"
"safer.place/internal/database/sqldatabase"
Expand All @@ -42,13 +43,13 @@ const (
NotifierDependency Dependency = "notifier"
)

func dependenciesToStrings(dependencies []Dependency) []string {
res := make([]string, 0, len(dependencies))
for _, dependency := range dependencies {
res = append(res, string(dependency))
}
return res
}
// func dependenciesToStrings(dependencies []Dependency) []string {
// res := make([]string, 0, len(dependencies))
// for _, dependency := range dependencies {
// res = append(res, string(dependency))
// }
// return res
// }

// StringsToDependencies converts a string slice into dependecy slice
func StringsToDependencies(ss []string) []Dependency {
Expand All @@ -74,7 +75,7 @@ type dependencies struct {
// always created dependencies
tracing trace.TracerProvider
metrics *prometheus.Registry
logger *zap.Logger
logger *slog.Logger

// dynamically created dependencies
database database.Database
Expand All @@ -93,7 +94,7 @@ func createDependencies(ctx context.Context, cfg *config.Config, components []Co
metrics: prometheus.NewRegistry(),
}

mc := multiCloser{closer(func() error { return deps.logger.Sync() })}
mc := multiCloser{}

tracing, tracingCloser, err := tracing.NewTracingProvider(ctx, cfg.Tracing)
if err != nil {
Expand All @@ -102,9 +103,9 @@ func createDependencies(ctx context.Context, cfg *config.Config, components []Co
mc = append(mc, tracingCloser)
deps.tracing = tracing

deps.logger.Debug("initializing dependencies",
zap.Strings("components", ComponentsToStrings(components)),
zap.Strings("dependencies", dependenciesToStrings(wantedDependencies)),
deps.logger.DebugContext(ctx, "initializing dependencies",
"components", components,
"dependencies", wantedDependencies,
)

deps.metrics.MustRegister(
Expand Down Expand Up @@ -212,7 +213,7 @@ func registerStorage(ctx context.Context, cfg *config.Config, deps *dependencies

func registerNotifier(_ context.Context, cfg *config.Config, deps *dependencies) (err error) {
var v notifier.Notifier
log := deps.logger.With(zap.String("notifier", cfg.Notifier.Provider))
log := deps.logger.With(slog.String("notifier", cfg.Notifier.Provider))
switch cfg.Notifier.Provider {
case "log":
v = lognotifier.New(log)
Expand All @@ -228,28 +229,26 @@ func registerNotifier(_ context.Context, cfg *config.Config, deps *dependencies)
return nil
}

func newLogger(cfg *config.Config) *zap.Logger {
var logger *zap.Logger
func newLogger(cfg *config.Config) *slog.Logger {
var logger *slog.Logger
if cfg.Debug {
logger, _ = zap.NewDevelopment()
logger.Debug("debug mode enabled")
logger = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelDebug,
AddSource: true,
}))
} else {
logger, _ = zap.NewProduction()
logger = slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{
Level: slog.LevelInfo,
}))
}

logger.Debug("using configuration",
zap.Any("config", cfg),
slog.Any("config", cfg),
)

return logger
}

type closer func() error

func (c closer) Close() error {
return c()
}

type multiCloser []io.Closer

func (mc multiCloser) Close() error {
Expand Down
4 changes: 2 additions & 2 deletions internal/cmd/saferplace/saferplace.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/saferplace/webserver-go"
"github.com/saferplace/webserver-go/middleware"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
"safer.place/internal/auth"
"safer.place/internal/config"
Expand Down Expand Up @@ -84,7 +83,8 @@ func Run(ctx context.Context, components []Component, cfg *config.Config) (err e
}

srv, err := webserver.New(
webserver.Logger(deps.logger.With(zap.String("component", "server"))),
// TODO: Enable slog in webserver
// webserver.Logger(deps.logger.With(slog.String("component", "server"))),
webserver.Services(services...),
webserver.TLSConfig(tlsConfig),
webserver.Middlewares(middlewares...),
Expand Down
13 changes: 11 additions & 2 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

"github.com/kelseyhightower/envconfig"
"golang.org/x/exp/slog"
"gopkg.in/yaml.v3"
"safer.place/internal/database/sqldatabase"
"safer.place/internal/storage/minio"
Expand All @@ -27,6 +28,10 @@ type Config struct {
Notifier NotifierConfig `yaml:"notifier"`
}

func (c Config) LogValue() slog.Value {
return slog.StringValue(fmt.Sprintf("%+v", c))
}

// WebserverConfig contains all configuration used to setup the webserver and middleware
type WebserverConfig struct {
Port int `yaml:"port" envconfig:"PORT" default:"8001"`
Expand Down Expand Up @@ -127,6 +132,10 @@ func (d *Duration) UnmarshalText(text []byte) error {
return nil
}

func (d *Duration) String() string {
return time.Duration(*d).String()
func (d Duration) LogValue() slog.Value {
return slog.DurationValue(time.Duration(d))
}

func (d Duration) String() string {
return time.Duration(d).String()
}
12 changes: 12 additions & 0 deletions internal/config/secret/secret.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package secret

import "log/slog"

// Secret hides secrets which do not want to log by accident.
type Secret string

// LogValue implements slog.LogValuer.
// It avoids revealing the token.
func (Secret) LogValue() slog.Value {
return slog.StringValue("<redacted>")
}
10 changes: 5 additions & 5 deletions internal/notifier/discordnotifier/discordnotifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"

"github.com/bwmarrin/discordgo"
Expand Down Expand Up @@ -56,13 +55,14 @@ func (n *Notifier) Notify(ctx context.Context, i *incident.Incident) error {
return fmt.Errorf("unable to encode webhook body: %w", err)
}

log.Println(body)

req, err := http.NewRequest(http.MethodPost, n.endpoint, body)
req, err := http.NewRequestWithContext(ctx,
http.MethodPost,
n.endpoint,
body,
)
if err != nil {
return fmt.Errorf("unable to create request: %w", err)
}
req = req.WithContext(ctx)
req.Header.Set("Content-Type", "application/json")

resp, err := n.client.Do(req)
Expand Down
Loading

0 comments on commit 252361e

Please sign in to comment.