Add log abstraction

This commit is contained in:
Christian Schaible 2024-10-07 13:57:06 +02:00
parent 3bbf1cca71
commit a98e802f55
10 changed files with 224 additions and 19 deletions

View file

@ -4,9 +4,7 @@ import (
"context"
"encoding/json"
"errors"
"log/slog"
"net/url"
"os"
"strings"
"testing"
"time"
@ -20,7 +18,6 @@ import (
)
func TestDynamicLegacyAuditApi(t *testing.T) {
slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, nil)))
// Specify test timeout
ctx, cancelFn := context.WithTimeout(context.Background(), 120*time.Second)

View file

@ -5,9 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"log/slog"
"net/url"
"os"
"strings"
"testing"
"time"
@ -22,7 +20,6 @@ import (
)
func TestLegacyAuditApi(t *testing.T) {
slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, nil)))
// Specify test timeout
ctx, cancelFn := context.WithTimeout(context.Background(), 120*time.Second)

View file

@ -4,10 +4,10 @@ import (
"context"
"dev.azure.com/schwarzit/schwarzit.stackit-core-platform/audit-go.git/audit/utils"
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-core-platform/audit-go.git/gen/go/audit/v1"
"dev.azure.com/schwarzit/schwarzit.stackit-core-platform/audit-go.git/log"
"errors"
"fmt"
"go.opentelemetry.io/otel/trace"
"log/slog"
"time"
)
@ -59,7 +59,7 @@ func getObjectIdAndTypeFromAuditParams(
// Convert to plural type
plural, err := objectType.AsPluralType()
if err != nil {
slog.LogAttrs(ctx, slog.LevelError, "failed to convert singular type to plural type", slog.Any("error", err))
log.AuditLogger.Error("failed to convert singular type to plural type", err)
return "", nil, nil, err
}
return objectId, objectType, &plural, nil

View file

@ -2,11 +2,11 @@ package api
import (
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-core-platform/audit-go.git/gen/go/audit/v1"
"dev.azure.com/schwarzit/schwarzit.stackit-core-platform/audit-go.git/log"
"encoding/json"
"errors"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"log/slog"
"time"
)
@ -14,7 +14,7 @@ import (
func LogEvent(event *CloudEvent) error {
if event.DataType == DataTypeLegacyAuditEventV1 {
slog.Info(string(event.Data))
log.AuditLogger.Info(string(event.Data))
return nil
} else if event.DataType != "audit.v1.RoutableAuditEvent" {
return errors.New("Unsupported data type " + event.DataType)
@ -75,7 +75,7 @@ func LogEvent(event *CloudEvent) error {
return err
}
slog.Info(string(cloudEventJson))
log.AuditLogger.Info(string(cloudEventJson))
return nil
}

View file

@ -2,10 +2,10 @@ package messaging
import (
"context"
"dev.azure.com/schwarzit/schwarzit.stackit-core-platform/audit-go.git/log"
"errors"
"fmt"
"github.com/Azure/go-amqp"
"log/slog"
"strings"
"sync"
"time"
@ -111,16 +111,16 @@ func NewAmqpApi(amqpConfig AmqpConfig) (*Api, error) {
// connect opens a new connection and session to the AMQP messaging system.
// The connection attempt will be cancelled after connectionTimeoutSeconds.
func (a *AmqpApi) connect() error {
slog.Info("connecting to messaging system")
log.AuditLogger.Info("connecting to messaging system")
// Set credentials if specified
auth := amqp.SASLTypeAnonymous()
if a.config.User != "" && a.config.Password != "" {
auth = amqp.SASLTypePlain(a.config.User, a.config.Password)
slog.Info("using username and password for messaging")
log.AuditLogger.Info("using username and password for messaging")
} else {
slog.Warn("using anonymous messaging!")
log.AuditLogger.Warn("using anonymous messaging!")
}
options := &amqp.ConnOptions{
@ -159,7 +159,7 @@ func (a *AmqpApi) Send(ctx context.Context, topic string, data []byte, contentTy
}
// Drop the current sender, as it cannot connect to the broker anymore
slog.Error("message sender error, recreating", slog.Any("error", err))
log.AuditLogger.Error("message sender error, recreating", err)
err = a.resetConnection(ctx)
if err != nil {
@ -211,7 +211,7 @@ func (a *AmqpApi) resetConnection(ctx context.Context) error {
_ = (*a.session).Close(ctx)
err := a.connection.Close()
if err != nil {
slog.Error("failed to close message connection", slog.Any("error", err))
log.AuditLogger.Error("failed to close message connection", err)
}
return a.connect()

View file

@ -3,6 +3,7 @@ package messaging
import (
"bytes"
"context"
"dev.azure.com/schwarzit/schwarzit.stackit-core-platform/audit-go.git/log"
"encoding/json"
"errors"
"fmt"
@ -10,7 +11,6 @@ import (
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
"io"
"log/slog"
"net/http"
"regexp"
"strings"
@ -168,7 +168,7 @@ func NewSolaceContainer(ctx context.Context) (*SolaceContainer, error) {
_ = container.Terminate(ctx)
return nil, err
}
slog.Info("UI Port: " + sempPort.Port())
log.AuditLogger.Info("UI Port: " + sempPort.Port())
// Construct connection strings
amqpConnectionString := fmt.Sprintf("amqp://%s:%s/", host, amqpPort.Port())

3
go.mod
View file

@ -7,6 +7,7 @@ require (
github.com/Azure/go-amqp v1.1.0
github.com/bufbuild/protovalidate-go v0.6.4
github.com/google/uuid v1.6.0
github.com/rs/zerolog v1.33.0
github.com/stretchr/testify v1.9.0
github.com/testcontainers/testcontainers-go v0.33.0
go.opentelemetry.io/otel v1.24.0
@ -38,6 +39,8 @@ require (
github.com/klauspost/compress v1.17.4 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect

13
go.sum
View file

@ -22,6 +22,7 @@ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E=
github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
@ -50,6 +51,7 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/google/cel-go v0.21.0 h1:cl6uW/gxN+Hy50tNYvI691+sXxioCnstFzLp2WO4GCI=
@ -74,6 +76,11 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
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.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
@ -98,6 +105,9 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4=
github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
@ -171,8 +181,11 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

82
log/log.go Normal file
View file

@ -0,0 +1,82 @@
package log
import (
"errors"
"log/slog"
)
import "github.com/rs/zerolog/log"
var AuditLogger = NewSlogAuditLogger(slog.Default())
func NewSlogAuditLogger(logger *slog.Logger) Logger {
return SlogLogger{logger: logger}
}
func NewZerologAuditLogger() Logger {
return ZeroLogLogger{}
}
type Logger interface {
Debug(msg string, err ...error)
Info(msg string, err ...error)
Warn(msg string, err ...error)
Error(msg string, err ...error)
}
type SlogLogger struct {
logger *slog.Logger
}
func (s SlogLogger) Debug(msg string, err ...error) {
s.logger.Debug(msg, s.getWrappedError(err))
}
func (s SlogLogger) Info(msg string, err ...error) {
s.logger.Info(msg, s.getWrappedError(err))
}
func (s SlogLogger) Warn(msg string, err ...error) {
s.logger.Warn(msg, s.getWrappedError(err))
}
func (s SlogLogger) Error(msg string, err ...error) {
s.logger.Error(msg, s.getWrappedError(err))
}
func (s SlogLogger) getWrappedError(err []error) slog.Attr {
var wrappedErr slog.Attr
if err != nil {
wrappedErr = slog.Any("error", wrapErr(err))
}
return wrappedErr
}
type ZeroLogLogger struct{}
func (l ZeroLogLogger) Debug(msg string, err ...error) {
log.Debug().Err(wrapErr(err)).Msg(msg)
}
func (l ZeroLogLogger) Info(msg string, err ...error) {
log.Info().Err(wrapErr(err)).Msg(msg)
}
func (l ZeroLogLogger) Warn(msg string, err ...error) {
log.Warn().Err(wrapErr(err)).Msg(msg)
}
func (l ZeroLogLogger) Error(msg string, err ...error) {
log.Error().Err(wrapErr(err)).Msg(msg)
}
func wrapErr(err []error) error {
var e error
if len(err) == 0 {
e = nil
} else if len(err) == 1 {
e = err[0]
} else {
e = errors.Join(err...)
}
return e
}

113
log/log_test.go Normal file
View file

@ -0,0 +1,113 @@
package log
import (
"errors"
"log/slog"
"testing"
)
func Test_DefaultLogger(t *testing.T) {
t.Run("debug", func(t *testing.T) {
AuditLogger.Debug("debug message")
})
t.Run("debug with error details", func(t *testing.T) {
AuditLogger.Debug("debug message", errors.New("custom error"))
})
t.Run("info", func(t *testing.T) {
AuditLogger.Info("info message")
})
t.Run("info with error details", func(t *testing.T) {
AuditLogger.Info("info message", errors.New("custom error"))
})
t.Run("warn", func(t *testing.T) {
AuditLogger.Warn("warn message")
})
t.Run("warn with error details", func(t *testing.T) {
AuditLogger.Warn("warn message", errors.New("custom error"))
})
t.Run("error", func(t *testing.T) {
AuditLogger.Error("error message")
})
t.Run("error with error details", func(t *testing.T) {
AuditLogger.Error("error message", errors.New("custom error"))
})
}
func Test_SlogLogger(t *testing.T) {
AuditLogger = NewSlogAuditLogger(slog.Default())
t.Run("debug", func(t *testing.T) {
AuditLogger.Debug("debug message")
})
t.Run("debug with error details", func(t *testing.T) {
AuditLogger.Debug("debug message", errors.New("custom error"))
})
t.Run("info", func(t *testing.T) {
AuditLogger.Info("info message")
})
t.Run("info with error details", func(t *testing.T) {
AuditLogger.Info("info message", errors.New("custom error"))
})
t.Run("warn", func(t *testing.T) {
AuditLogger.Warn("warn message")
})
t.Run("warn with error details", func(t *testing.T) {
AuditLogger.Warn("warn message", errors.New("custom error"))
})
t.Run("error", func(t *testing.T) {
AuditLogger.Error("error message")
})
t.Run("error with error details", func(t *testing.T) {
AuditLogger.Error("error message", errors.New("custom error"))
})
}
func Test_ZerologLogger(t *testing.T) {
AuditLogger = NewZerologAuditLogger()
t.Run("debug", func(t *testing.T) {
AuditLogger.Debug("debug message")
})
t.Run("debug with error details", func(t *testing.T) {
AuditLogger.Debug("debug message", errors.New("custom error"))
})
t.Run("info", func(t *testing.T) {
AuditLogger.Info("info message")
})
t.Run("info with error details", func(t *testing.T) {
AuditLogger.Info("info message", errors.New("custom error"))
})
t.Run("warn", func(t *testing.T) {
AuditLogger.Warn("warn message")
})
t.Run("warn with error details", func(t *testing.T) {
AuditLogger.Warn("warn message", errors.New("custom error"))
})
t.Run("error", func(t *testing.T) {
AuditLogger.Error("error message")
})
t.Run("error with error details", func(t *testing.T) {
AuditLogger.Error("error message", errors.New("custom error"))
})
}