Skip to content

Commit

Permalink
Start switching to use slog
Browse files Browse the repository at this point in the history
  • Loading branch information
norkans7 committed Oct 6, 2023
1 parent ccab456 commit 64470aa
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 22 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: CI
on: [push, pull_request]
env:
go-version: "1.20.x"
go-version: "1.21.x"
jobs:
test:
name: Test
Expand Down
26 changes: 20 additions & 6 deletions cmd/courier/main.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package main

import (
"log/slog"
"os"
"os/signal"
"syscall"

"github.com/evalphobia/logrus_sentry"
_ "github.com/lib/pq"
"github.com/nyaruka/courier"
"github.com/nyaruka/courier/utils"
"github.com/sirupsen/logrus"

// load channel handler packages
Expand Down Expand Up @@ -88,10 +90,17 @@ func main() {
logrus.SetOutput(os.Stdout)
level, err := logrus.ParseLevel(config.LogLevel)
if err != nil {
logrus.Fatalf("Invalid log level '%s'", level)
slog.Error("invalid log level", "level", level)
os.Exit(1)
}
logrus.SetLevel(level)

// configure golang std structured logging to route to logrus
slog.SetDefault(slog.New(utils.NewLogrusHandler(logrus.StandardLogger())))

log := slog.With("comp", "main")
log.Info("starting courier", "version", version)

// if we have a DSN entry, try to initialize it
if config.SentryDSN != "" {
hook, err := logrus_sentry.NewSentryHook(config.SentryDSN, []logrus.Level{logrus.PanicLevel, logrus.FatalLevel, logrus.ErrorLevel})
Expand All @@ -100,26 +109,31 @@ func main() {
hook.StacktraceConfiguration.Skip = 4
hook.StacktraceConfiguration.Context = 5
if err != nil {
logrus.Fatalf("Invalid sentry DSN: '%s': %s", config.SentryDSN, err)
log.Error("unable to configure sentry hook", "dsn", config.SentryDSN, "error", err)
os.Exit(1)
}
logrus.StandardLogger().Hooks.Add(hook)
}

// load our backend
backend, err := courier.NewBackend(config)
if err != nil {
logrus.Fatalf("Error creating backend: %s", err)
log.Error("error creating backend", "error", err)
os.Exit(1)
}

server := courier.NewServer(config, backend)
err = server.Start()
if err != nil {
logrus.Fatalf("Error starting server: %s", err)
log.Error("unable to start server", "error", err)
os.Exit(1)
}

ch := make(chan os.Signal)
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
logrus.WithField("comp", "main").WithField("signal", <-ch).Info("stopping")
slog.Info("stopping", "comp", "main", "signal", <-ch)
logrus.WithField("comp", "main").WithField("signal", <-ch)

server.Stop()

}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/nyaruka/courier

go 1.20
go 1.21

require (
github.com/antchfx/xmlquery v1.3.17
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49P
github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
Expand All @@ -46,6 +47,7 @@ github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws
github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc=
github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
Expand Down
5 changes: 3 additions & 2 deletions handlers/jiochat/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"testing"
"time"

"log/slog"

"github.com/nyaruka/courier"
. "github.com/nyaruka/courier/handlers"
"github.com/nyaruka/courier/test"
Expand Down Expand Up @@ -260,8 +262,7 @@ func buildMockJCAPI(testCases []IncomingTestCase) *httptest.Server {

func newServer(backend courier.Backend) courier.Server {
// for benchmarks, log to null
logger := logrus.New()
logger.Out = io.Discard
logger := slog.Default()
logrus.SetOutput(io.Discard)
config := courier.NewConfig()
config.DB = "postgres://courier_test:temba@localhost:5432/courier_test?sslmode=disable"
Expand Down
5 changes: 3 additions & 2 deletions handlers/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"testing"
"time"

"log/slog"

_ "github.com/lib/pq" // postgres driver
"github.com/nyaruka/courier"
"github.com/nyaruka/courier/test"
Expand Down Expand Up @@ -147,8 +149,7 @@ func testHandlerRequest(tb testing.TB, s courier.Server, path string, headers ma

func newServer(backend courier.Backend) courier.Server {
// for benchmarks, log to null
logger := logrus.New()
logger.Out = io.Discard
logger := slog.Default()

Check warning on line 152 in handlers/test.go

View check run for this annotation

Codecov / codecov/patch

handlers/test.go#L152

Added line #L152 was not covered by tests
logrus.SetOutput(io.Discard)

config := courier.NewConfig()
Expand Down
5 changes: 3 additions & 2 deletions handlers/wechat/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"testing"
"time"

"log/slog"

"github.com/nyaruka/courier"
. "github.com/nyaruka/courier/handlers"
"github.com/nyaruka/courier/test"
Expand Down Expand Up @@ -212,8 +214,7 @@ func buildMockWCAPI(testCases []IncomingTestCase) *httptest.Server {

func newServer(backend courier.Backend) courier.Server {
// for benchmarks, log to null
logger := logrus.New()
logger.Out = io.Discard
logger := slog.Default()
logrus.SetOutput(io.Discard)
config := courier.NewConfig()
config.DB = "postgres://courier_test:temba@localhost:5432/courier_test?sslmode=disable"
Expand Down
7 changes: 4 additions & 3 deletions queue/queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import (
"sync"
"time"

"log/slog"

"github.com/gomodule/redigo/redis"
"github.com/sirupsen/logrus"
)

// Priority represents the priority of an item in a queue
Expand Down Expand Up @@ -201,7 +202,7 @@ func PopFromQueue(conn redis.Conn, qType string) (WorkerToken, string, error) {
epochMS := strconv.FormatFloat(float64(time.Now().UnixNano()/int64(time.Microsecond))/float64(1000000), 'f', 6, 64)
values, err := redis.Strings(luaPop.Do(conn, epochMS, qType))
if err != nil {
logrus.Error(err)
slog.Error("error poping from queue", "error", err)

Check warning on line 205 in queue/queue.go

View check run for this annotation

Codecov / codecov/patch

queue/queue.go#L205

Added line #L205 was not covered by tests
return "", "", err
}
return WorkerToken(values[0]), values[1], nil
Expand Down Expand Up @@ -275,7 +276,7 @@ func StartDethrottler(redis *redis.Pool, quitter chan bool, wg *sync.WaitGroup,
conn := redis.Get()
_, err := luaDethrottle.Do(conn, qType)
if err != nil {
logrus.WithError(err).Error("error dethrottling")
slog.Error("error dethrottling", "error", err)

Check warning on line 279 in queue/queue.go

View check run for this annotation

Codecov / codecov/patch

queue/queue.go#L279

Added line #L279 was not covered by tests
}
conn.Close()

Expand Down
6 changes: 4 additions & 2 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"sync"
"time"

"log/slog"

"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/nyaruka/courier/utils"
Expand Down Expand Up @@ -56,13 +58,13 @@ type Server interface {
// afterwards, which is when configuration options are checked.
func NewServer(config *Config, backend Backend) Server {
// create our top level router
logger := logrus.New()
logger := slog.Default()
return NewServerWithLogger(config, backend, logger)
}

// NewServerWithLogger creates a new Server for the passed in configuration. The server will have to be started
// afterwards, which is when configuration options are checked.
func NewServerWithLogger(config *Config, backend Backend, logger *logrus.Logger) Server {
func NewServerWithLogger(config *Config, backend Backend, logger *slog.Logger) Server {
router := chi.NewRouter()
router.Use(middleware.Compress(flate.DefaultCompression))
router.Use(middleware.StripSlashes)
Expand Down
7 changes: 4 additions & 3 deletions server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ import (
"testing"
"time"

"log/slog"

"github.com/nyaruka/courier"
"github.com/nyaruka/courier/test"
"github.com/nyaruka/gocommon/httpx"
"github.com/nyaruka/gocommon/uuids"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestServer(t *testing.T) {
logger := logrus.New()
logger := slog.Default()
config := courier.NewConfig()
config.StatusUsername = "admin"
config.StatusPassword = "password123"
Expand Down Expand Up @@ -89,7 +90,7 @@ func TestFetchAttachment(t *testing.T) {
defer uuids.SetGenerator(uuids.DefaultGenerator)
uuids.SetGenerator(uuids.NewSeededGenerator(1234))

logger := logrus.New()
logger := slog.Default()
config := courier.NewConfig()
config.AuthToken = "sesame"

Expand Down
92 changes: 92 additions & 0 deletions utils/logrus.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Structured logging handler for logrus so we can rewrite code to use slog package incrementally. Once all logging is
// happening via slog, we just need to hook up Sentry directly to that, and then we can get rid of this file.
package utils

import (
"context"
"log/slog"
"slices"
"strings"

"github.com/sirupsen/logrus"
)

var levels = map[slog.Level]logrus.Level{
slog.LevelError: logrus.ErrorLevel,
slog.LevelWarn: logrus.WarnLevel,
slog.LevelInfo: logrus.InfoLevel,
slog.LevelDebug: logrus.DebugLevel,
}

type LogrusHandler struct {
logger *logrus.Logger
groups []string
attrs []slog.Attr
}

func NewLogrusHandler(logger *logrus.Logger) *LogrusHandler {
return &LogrusHandler{logger: logger}

Check warning on line 28 in utils/logrus.go

View check run for this annotation

Codecov / codecov/patch

utils/logrus.go#L27-L28

Added lines #L27 - L28 were not covered by tests
}

func (l *LogrusHandler) clone() *LogrusHandler {
return &LogrusHandler{
logger: l.logger,
groups: slices.Clip(l.groups),
attrs: slices.Clip(l.attrs),
}

Check warning on line 36 in utils/logrus.go

View check run for this annotation

Codecov / codecov/patch

utils/logrus.go#L31-L36

Added lines #L31 - L36 were not covered by tests
}

func (l *LogrusHandler) Enabled(ctx context.Context, level slog.Level) bool {
return levels[level] <= l.logger.GetLevel()

Check warning on line 40 in utils/logrus.go

View check run for this annotation

Codecov / codecov/patch

utils/logrus.go#L39-L40

Added lines #L39 - L40 were not covered by tests
}

func (l *LogrusHandler) Handle(ctx context.Context, r slog.Record) error {
log := logrus.NewEntry(l.logger)
if r.Time.IsZero() {
log = log.WithTime(r.Time)
}

Check warning on line 47 in utils/logrus.go

View check run for this annotation

Codecov / codecov/patch

utils/logrus.go#L43-L47

Added lines #L43 - L47 were not covered by tests

f := logrus.Fields{}
for _, a := range l.attrs {
if a.Key != "" {
f[a.Key] = a.Value
}

Check warning on line 53 in utils/logrus.go

View check run for this annotation

Codecov / codecov/patch

utils/logrus.go#L49-L53

Added lines #L49 - L53 were not covered by tests
}
log = log.WithFields(f)

r.Attrs(func(attr slog.Attr) bool {
if attr.Key == "" {
return true
}
log = log.WithField(attr.Key, attr.Value)
return true

Check warning on line 62 in utils/logrus.go

View check run for this annotation

Codecov / codecov/patch

utils/logrus.go#L55-L62

Added lines #L55 - L62 were not covered by tests
})
log.Logf(levels[r.Level], r.Message)
return nil

Check warning on line 65 in utils/logrus.go

View check run for this annotation

Codecov / codecov/patch

utils/logrus.go#L64-L65

Added lines #L64 - L65 were not covered by tests
}

func (l *LogrusHandler) groupPrefix() string {
if len(l.groups) > 0 {
return strings.Join(l.groups, ":") + ":"
}
return ""

Check warning on line 72 in utils/logrus.go

View check run for this annotation

Codecov / codecov/patch

utils/logrus.go#L68-L72

Added lines #L68 - L72 were not covered by tests
}

func (l *LogrusHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
newHandler := l.clone()
for _, a := range attrs {
newHandler.attrs = append(newHandler.attrs, slog.Attr{
Key: l.groupPrefix() + a.Key,
Value: a.Value,
})
}
return newHandler

Check warning on line 83 in utils/logrus.go

View check run for this annotation

Codecov / codecov/patch

utils/logrus.go#L75-L83

Added lines #L75 - L83 were not covered by tests
}

func (l *LogrusHandler) WithGroup(name string) slog.Handler {
newHandler := l.clone()
newHandler.groups = append(newHandler.groups, name)
return newHandler

Check warning on line 89 in utils/logrus.go

View check run for this annotation

Codecov / codecov/patch

utils/logrus.go#L86-L89

Added lines #L86 - L89 were not covered by tests
}

var _ slog.Handler = &LogrusHandler{}

0 comments on commit 64470aa

Please sign in to comment.