1
0
mirror of https://github.com/regclient/regclient.git synced 2025-04-18 22:44:00 +03:00

Feat: Switch regbot to slog

This also consolidated the trace logging level to a single definition.

Signed-off-by: Brandon Mitchell <git@bmitch.net>
This commit is contained in:
Brandon Mitchell 2024-11-11 13:21:39 -05:00
parent 6aa3ff18d9
commit 3756788d13
No known key found for this signature in database
GPG Key ID: 6E0FF28C767A8BEE
13 changed files with 154 additions and 162 deletions

View File

@ -7,30 +7,24 @@ import (
"os/signal"
"syscall"
"github.com/sirupsen/logrus"
"github.com/regclient/regclient/internal/godbg"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
log := &logrus.Logger{
Out: os.Stderr,
Formatter: new(logrus.TextFormatter),
Hooks: make(logrus.LevelHooks),
Level: logrus.InfoLevel,
}
rootTopCmd, rootOpts := NewRootCmd()
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
go func() {
<-sig
log.WithFields(logrus.Fields{}).Debug("Interrupt received, stopping")
rootOpts.log.Debug("Interrupt received, stopping")
// clean shutdown
cancel()
}()
godbg.SignalTrace()
rootTopCmd := NewRootCmd(log)
if err := rootTopCmd.ExecuteContext(ctx); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)

View File

@ -4,6 +4,7 @@ import (
"bytes"
"context"
"errors"
"log/slog"
"net/http/httptest"
"net/url"
"os"
@ -12,7 +13,6 @@ import (
"github.com/olareg/olareg"
oConfig "github.com/olareg/olareg/config"
"github.com/sirupsen/logrus"
"github.com/regclient/regclient"
"github.com/regclient/regclient/config"
@ -164,14 +164,9 @@ defaults:
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
rootOpts := rootCmd{
dryRun: tt.dryrun,
conf: conf,
log: &logrus.Logger{
Out: os.Stderr,
Formatter: new(logrus.TextFormatter),
Hooks: make(logrus.LevelHooks),
Level: logrus.InfoLevel,
},
dryRun: tt.dryrun,
conf: conf,
log: slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelInfo})),
rc: rc,
throttle: pq,
}

View File

@ -2,11 +2,13 @@ package main
import (
"context"
"fmt"
"log/slog"
"os"
"strings"
"sync"
"github.com/robfig/cron/v3"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/regclient/regclient"
@ -16,6 +18,7 @@ import (
"github.com/regclient/regclient/internal/version"
"github.com/regclient/regclient/pkg/template"
"github.com/regclient/regclient/scheme/reg"
"github.com/regclient/regclient/types"
)
const (
@ -31,15 +34,15 @@ type rootCmd struct {
verbosity string
logopts []string
format string // for Go template formatting of various commands
log *logrus.Logger
log *slog.Logger
conf *Config
rc *regclient.RegClient
throttle *pqueue.Queue[struct{}]
}
func NewRootCmd(log *logrus.Logger) *cobra.Command {
func NewRootCmd() (*cobra.Command, *rootCmd) {
rootOpts := rootCmd{
log: log,
log: slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelInfo})),
}
var rootTopCmd = &cobra.Command{
Use: "regbot <cmd>",
@ -74,7 +77,7 @@ returns after the last script completes.`,
rootTopCmd.PersistentFlags().StringVarP(&rootOpts.confFile, "config", "c", "", "Config file")
rootTopCmd.PersistentFlags().BoolVarP(&rootOpts.dryRun, "dry-run", "", false, "Dry Run, skip all external actions")
rootTopCmd.PersistentFlags().StringVarP(&rootOpts.verbosity, "verbosity", "v", logrus.InfoLevel.String(), "Log level (debug, info, warn, error, fatal, panic)")
rootTopCmd.PersistentFlags().StringVarP(&rootOpts.verbosity, "verbosity", "v", slog.LevelInfo.String(), "Log level (debug, info, warn, error, fatal, panic)")
rootTopCmd.PersistentFlags().StringArrayVar(&rootOpts.logopts, "logopt", []string{}, "Log options")
versionCmd.Flags().StringVarP(&rootOpts.format, "format", "", "{{printPretty .}}", "Format output with go template syntax")
@ -87,21 +90,31 @@ returns after the last script completes.`,
rootTopCmd.AddCommand(versionCmd)
rootTopCmd.PersistentPreRunE = rootOpts.rootPreRun
return rootTopCmd
return rootTopCmd, &rootOpts
}
func (rootOpts *rootCmd) rootPreRun(cmd *cobra.Command, args []string) error {
lvl, err := logrus.ParseLevel(rootOpts.verbosity)
var lvl slog.Level
err := lvl.UnmarshalText([]byte(rootOpts.verbosity))
if err != nil {
return err
// handle custom levels
if rootOpts.verbosity == strings.ToLower("trace") {
lvl = types.LevelTrace
} else {
return fmt.Errorf("unable to parse verbosity %s: %v", rootOpts.verbosity, err)
}
}
rootOpts.log.SetLevel(lvl)
rootOpts.log.Formatter = &logrus.TextFormatter{FullTimestamp: true}
formatJSON := false
for _, opt := range rootOpts.logopts {
if opt == "json" {
rootOpts.log.Formatter = new(logrus.JSONFormatter)
formatJSON = true
}
}
if formatJSON {
rootOpts.log = slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: lvl}))
} else {
rootOpts.log = slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: lvl}))
}
return nil
}
@ -165,14 +178,12 @@ func (rootOpts *rootCmd) runServer(cmd *cobra.Command, args []string) error {
sched = "@every " + s.Interval.String()
}
if sched != "" {
rootOpts.log.WithFields(logrus.Fields{
"name": s.Name,
"sched": sched,
}).Debug("Scheduled task")
rootOpts.log.Debug("Scheduled task",
slog.String("name", s.Name),
slog.String("sched", sched))
_, errCron := c.AddFunc(sched, func() {
rootOpts.log.WithFields(logrus.Fields{
"name": s.Name,
}).Debug("Running task")
rootOpts.log.Debug("Running task",
slog.String("name", s.Name))
wg.Add(1)
defer wg.Done()
err := rootOpts.process(ctx, s)
@ -181,19 +192,17 @@ func (rootOpts *rootCmd) runServer(cmd *cobra.Command, args []string) error {
}
})
if errCron != nil {
rootOpts.log.WithFields(logrus.Fields{
"name": s.Name,
"sched": sched,
"err": errCron,
}).Error("Failed to schedule cron")
rootOpts.log.Error("Failed to schedule cron",
slog.String("name", s.Name),
slog.String("sched", sched),
slog.String("err", errCron.Error()))
if mainErr != nil {
mainErr = errCron
}
}
} else {
rootOpts.log.WithFields(logrus.Fields{
"name": s.Name,
}).Error("No schedule or interval found, ignoring")
rootOpts.log.Error("No schedule or interval found, ignoring",
slog.String("name", s.Name))
}
}
c.Start()
@ -202,10 +211,10 @@ func (rootOpts *rootCmd) runServer(cmd *cobra.Command, args []string) error {
if done != nil {
<-done
}
rootOpts.log.WithFields(logrus.Fields{}).Info("Stopping server")
rootOpts.log.Info("Stopping server")
// clean shutdown
c.Stop()
rootOpts.log.WithFields(logrus.Fields{}).Debug("Waiting on running tasks")
rootOpts.log.Debug("Waiting on running tasks")
wg.Wait()
return mainErr
}
@ -235,13 +244,12 @@ func (rootOpts *rootCmd) loadConf() error {
if concurrent <= 0 {
concurrent = 1
}
rootOpts.log.WithFields(logrus.Fields{
"concurrent": concurrent,
}).Debug("Configuring parallel settings")
rootOpts.log.Debug("Configuring parallel settings",
slog.Int("concurrent", concurrent))
rootOpts.throttle = pqueue.New(pqueue.Opts[struct{}]{Max: concurrent})
// set the regclient, loading docker creds unless disabled, and inject logins from config file
rcOpts := []regclient.Opt{
regclient.WithLog(rootOpts.log),
regclient.WithSlog(rootOpts.log),
}
if rootOpts.conf.Defaults.BlobLimit != 0 {
rcOpts = append(rcOpts, regclient.WithRegOpts(reg.WithBlobLimit(rootOpts.conf.Defaults.BlobLimit)))
@ -262,9 +270,8 @@ func (rootOpts *rootCmd) loadConf() error {
rcHosts := []config.Host{}
for _, host := range rootOpts.conf.Creds {
if host.Scheme != "" {
rootOpts.log.WithFields(logrus.Fields{
"name": host.Name,
}).Warn("Scheme is deprecated, for http set TLS to disabled")
rootOpts.log.Warn("Scheme is deprecated, for http set TLS to disabled",
slog.String("name", host.Name))
}
rcHosts = append(rcHosts, host)
}
@ -277,9 +284,8 @@ func (rootOpts *rootCmd) loadConf() error {
// process a sync step
func (rootOpts *rootCmd) process(ctx context.Context, s ConfigScript) error {
rootOpts.log.WithFields(logrus.Fields{
"script": s.Name,
}).Debug("Starting script")
rootOpts.log.Debug("Starting script",
slog.String("script", s.Name))
// add a timeout to the context
if s.Timeout > 0 {
ctxTimeout, cancel := context.WithTimeout(ctx, s.Timeout)
@ -289,7 +295,7 @@ func (rootOpts *rootCmd) process(ctx context.Context, s ConfigScript) error {
sbOpts := []sandbox.Opt{
sandbox.WithContext(ctx),
sandbox.WithRegClient(rootOpts.rc),
sandbox.WithLog(rootOpts.log),
sandbox.WithSlog(rootOpts.log),
sandbox.WithThrottle(rootOpts.throttle),
}
if rootOpts.dryRun {
@ -299,15 +305,12 @@ func (rootOpts *rootCmd) process(ctx context.Context, s ConfigScript) error {
defer sb.Close()
err := sb.RunScript(s.Script)
if err != nil {
rootOpts.log.WithFields(logrus.Fields{
"script": s.Name,
"error": err,
}).Warn("Error running script")
rootOpts.log.Warn("Error running script",
slog.String("script", s.Name),
slog.String("error", err.Error()))
return ErrScriptFailed
}
rootOpts.log.WithFields(logrus.Fields{
"script": s.Name,
}).Debug("Finished script")
rootOpts.log.Debug("Finished script",
slog.String("script", s.Name))
return nil
}

View File

@ -4,6 +4,7 @@ import (
"bytes"
"encoding/json"
"io"
"log/slog"
"strings"
// crypto libraries included for go-digest
@ -11,7 +12,6 @@ import (
_ "crypto/sha512"
"github.com/opencontainers/go-digest"
"github.com/sirupsen/logrus"
lua "github.com/yuin/gopher-lua"
"github.com/regclient/regclient/types/blob"
@ -108,11 +108,10 @@ func (s *Sandbox) blobGet(ls *lua.LState) int {
if ls.GetTop() >= 2 {
d = ls.CheckString(2)
}
s.log.WithFields(logrus.Fields{
"script": s.name,
"ref": r.r.CommonName(),
"digest": d,
}).Debug("Retrieve blob")
s.log.Debug("Retrieve blob",
slog.String("script", s.name),
slog.String("ref", r.r.CommonName()),
slog.String("digest", d))
b, err := s.rc.BlobGet(s.ctx, r.r, descriptor.Descriptor{Digest: digest.Digest(d)})
if err != nil {
ls.RaiseError("Failed retrieving \"%s\" blob \"%s\": %v", r.r.CommonName(), d, err)
@ -136,11 +135,10 @@ func (s *Sandbox) blobHead(ls *lua.LState) int {
if ls.GetTop() >= 2 {
d = ls.CheckString(2)
}
s.log.WithFields(logrus.Fields{
"script": s.name,
"ref": r.r.CommonName(),
"digest": d,
}).Debug("Retrieve blob")
s.log.Debug("Retrieve blob",
slog.String("script", s.name),
slog.String("ref", r.r.CommonName()),
slog.String("digest", d))
b, err := s.rc.BlobHead(s.ctx, r.r, descriptor.Descriptor{Digest: digest.Digest(d)})
if err != nil {
ls.RaiseError("Failed retrieving \"%s\" blob \"%s\": %v", r.r.CommonName(), d, err)
@ -161,10 +159,9 @@ func (s *Sandbox) blobPut(ls *lua.LState) int {
}
r := s.checkReference(ls, 1)
var d digest.Digest
s.log.WithFields(logrus.Fields{
"script": s.name,
"ref": r.r.CommonName(),
}).Debug("Put blob")
s.log.Debug("Put blob",
slog.String("script", s.name),
slog.String("ref", r.r.CommonName()))
if ls.GetTop() < 2 {
ls.ArgError(2, "blob content expected")

View File

@ -3,10 +3,10 @@ package sandbox
import (
"context"
"encoding/json"
"log/slog"
"os"
"time"
"github.com/sirupsen/logrus"
lua "github.com/yuin/gopher-lua"
"github.com/regclient/regclient"
@ -84,10 +84,9 @@ func (s *Sandbox) configGet(ls *lua.LState) int {
}
defer done()
}
s.log.WithFields(logrus.Fields{
"script": s.name,
"image": m.r.CommonName(),
}).Debug("Retrieve image config")
s.log.Debug("Retrieve image config",
slog.String("script", s.name),
slog.String("image", m.r.CommonName()))
mi, ok := m.m.(manifest.Imager)
if !ok {
ls.RaiseError("Image methods are not available for manifest")
@ -209,15 +208,15 @@ func (s *Sandbox) imageCopy(ls *lua.LState) int {
}
defer done()
}
s.log.WithFields(logrus.Fields{
"script": s.name,
"source": src.r.CommonName(),
"target": tgt.r.CommonName(),
"digestTags": lOpts.DigestTags,
"forceRecursive": lOpts.ForceRecursive,
"includeExternal": lOpts.IncludeExternal,
"dry-run": s.dryRun,
}).Info("Copy image")
s.log.Info("Copy image",
slog.String("script", s.name),
slog.String("source", src.r.CommonName()),
slog.String("target", tgt.r.CommonName()),
slog.Bool("digestTags", lOpts.DigestTags),
slog.Bool("forceRecursive", lOpts.ForceRecursive),
slog.Bool("includeExternal", lOpts.IncludeExternal),
slog.Bool("dry-run", s.dryRun),
)
if s.dryRun {
return 0
}
@ -341,13 +340,12 @@ func (s *Sandbox) imageRateLimitWait(ls *lua.LState) int {
return 1
}
// delay for freq (until timeout reached), and then retry
s.log.WithFields(logrus.Fields{
"script": s.name,
"image": r.r.CommonName(),
"current": rl.Remain,
"target": limit,
"delay": freq.String(),
}).Info("Delaying for ratelimit")
s.log.Info("Delaying for ratelimit",
slog.String("script", s.name),
slog.String("image", r.r.CommonName()),
slog.Int("current", rl.Remain),
slog.Int("target", limit),
slog.String("delay", freq.String()))
select {
case <-ctx.Done():
ls.Push(lua.LBool(false))

View File

@ -2,9 +2,9 @@ package sandbox
import (
"encoding/json"
"log/slog"
"reflect"
"github.com/sirupsen/logrus"
lua "github.com/yuin/gopher-lua"
"github.com/regclient/regclient/cmd/regbot/internal/go2lua"
@ -107,11 +107,10 @@ func (s *Sandbox) manifestDelete(ls *lua.LState) int {
d := m.m.GetDescriptor()
r.Digest = d.Digest.String()
}
s.log.WithFields(logrus.Fields{
"script": s.name,
"image": r.CommonName(),
"dry-run": s.dryRun,
}).Info("Delete manifest")
s.log.Info("Delete manifest",
slog.String("script", s.name),
slog.String("image", r.CommonName()),
slog.Bool("dry-run", s.dryRun))
if s.dryRun {
return 0
}
@ -192,12 +191,11 @@ func (s *Sandbox) manifestGetWithOpts(ls *lua.LState, list bool) int {
if !list && ls.GetTop() == 2 {
plat = ls.CheckString(2)
}
s.log.WithFields(logrus.Fields{
"script": s.name,
"image": r.r.CommonName(),
"list": list,
"platform": plat,
}).Debug("Retrieve manifest")
s.log.Debug("Retrieve manifest",
slog.String("script", s.name),
slog.String("image", r.r.CommonName()),
slog.Any("list", list),
slog.String("platform", plat))
m, err := s.rcManifestGet(r.r, list, plat)
if err != nil {
ls.RaiseError("Failed retrieving \"%s\" manifest: %v", r.r.CommonName(), err)
@ -218,10 +216,9 @@ func (s *Sandbox) manifestHead(ls *lua.LState) int {
}
r := s.checkReference(ls, 1)
s.log.WithFields(logrus.Fields{
"script": s.name,
"image": r.r.CommonName(),
}).Debug("Retrieve manifest with head")
s.log.Debug("Retrieve manifest with head",
slog.String("script", s.name),
slog.String("image", r.r.CommonName()))
m, err := s.rc.ManifestHead(s.ctx, r.r)
if err != nil {
@ -249,10 +246,9 @@ func (s *Sandbox) manifestJSON(ls *lua.LState) int {
func (s *Sandbox) manifestPut(ls *lua.LState) int {
sbm := s.checkManifest(ls, 1, true, false)
r := s.checkReference(ls, 2)
s.log.WithFields(logrus.Fields{
"script": s.name,
"image": r.r.CommonName(),
}).Debug("Put manifest")
s.log.Debug("Put manifest",
slog.String("script", s.name),
slog.String("image", r.r.CommonName()))
m, err := manifest.New(manifest.WithOrig(sbm.m.GetOrig()))
if err != nil {
@ -282,10 +278,9 @@ func (s *Sandbox) rcManifestGet(r ref.Ref, list bool, pStr string) (manifest.Man
if pStr != "" {
plat, err = platform.Parse(pStr)
if err != nil {
s.log.WithFields(logrus.Fields{
"platform": pStr,
"err": err,
}).Warn("Could not parse platform")
s.log.Warn("Could not parse platform",
slog.String("platform", pStr),
slog.String("err", err.Error()))
}
}
if plat.OS == "" {

View File

@ -2,8 +2,8 @@ package sandbox
import (
"fmt"
"log/slog"
"github.com/sirupsen/logrus"
lua "github.com/yuin/gopher-lua"
"github.com/regclient/regclient/cmd/regbot/internal/go2lua"
@ -49,11 +49,10 @@ func (s *Sandbox) repoLs(ls *lua.LState) int {
optsArgs = append(optsArgs, scheme.WithRepoLast(opts.Last))
}
}
s.log.WithFields(logrus.Fields{
"script": s.name,
"host": host,
"opts": opts,
}).Debug("Listing repositories")
s.log.Debug("Listing repositories",
slog.String("script", s.name),
slog.String("host", host),
slog.Any("opts", opts))
repoList, err := s.rc.RepoList(s.ctx, host, optsArgs...)
if err != nil {
ls.RaiseError("Failed retrieving repo list: %v", err)

View File

@ -3,8 +3,9 @@ package sandbox
import (
"context"
"log/slog"
"os"
"github.com/sirupsen/logrus"
lua "github.com/yuin/gopher-lua"
"github.com/regclient/regclient"
@ -26,7 +27,7 @@ const (
type Sandbox struct {
name string
ctx context.Context
log *logrus.Logger
log *slog.Logger
ls *lua.LState
rc *regclient.RegClient
throttle *pqueue.Queue[struct{}]
@ -66,7 +67,7 @@ func New(name string, opts ...Opt) *Sandbox {
s.ctx = context.Background()
}
if s.log == nil {
s.log = &logrus.Logger{}
s.log = slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelInfo}))
}
if s.rc == nil {
s.rc = regclient.New()
@ -98,8 +99,8 @@ func WithDryRun() Opt {
}
}
// WithLog specifies a logrus logger
func WithLog(log *logrus.Logger) Opt {
// WithSlog specifies a slog logger
func WithSlog(log *slog.Logger) Opt {
return func(s *Sandbox) {
s.log = log
}
@ -134,10 +135,9 @@ func (s *Sandbox) setupMod(name string, funcs map[string]lua.LGFunction, tables
func (s *Sandbox) RunScript(script string) (err error) {
defer func() {
if r := recover(); r != nil {
s.log.WithFields(logrus.Fields{
"script": s.name,
"error": r,
}).Error("Runtime error from script")
s.log.Error("Runtime error from script",
slog.String("script", s.name),
slog.Any("error", r))
err = ErrScriptFailed
}
}()
@ -151,10 +151,9 @@ func (s *Sandbox) Close() {
func (s *Sandbox) sandboxLog(ls *lua.LState) int {
msg := ls.CheckString(1)
s.log.WithFields(logrus.Fields{
"script": s.name,
"message": msg,
}).Info("User script message")
s.log.Info("User script message",
slog.String("script", s.name),
slog.String("message", msg))
return 0
}

View File

@ -1,7 +1,8 @@
package sandbox
import (
"github.com/sirupsen/logrus"
"log/slog"
lua "github.com/yuin/gopher-lua"
)
@ -26,11 +27,10 @@ func (s *Sandbox) tagDelete(ls *lua.LState) int {
ls.RaiseError("Context error: %v", err)
}
r := s.checkReference(ls, 1)
s.log.WithFields(logrus.Fields{
"script": s.name,
"image": r.r.CommonName(),
"dry-run": s.dryRun,
}).Info("Delete tag")
s.log.Info("Delete tag",
slog.String("script", s.name),
slog.String("image", r.r.CommonName()),
slog.Bool("dry-run", s.dryRun))
if s.dryRun {
return 0
}
@ -51,10 +51,9 @@ func (s *Sandbox) tagLs(ls *lua.LState) int {
ls.RaiseError("Context error: %v", err)
}
r := s.checkReference(ls, 1)
s.log.WithFields(logrus.Fields{
"script": s.name,
"repo": r.r.CommonName(),
}).Debug("Listing tags")
s.log.Debug("Listing tags",
slog.String("script", s.name),
slog.String("repo", r.r.CommonName()))
tl, err := s.rc.TagList(s.ctx, r.r)
if err != nil {
ls.RaiseError("Failed retrieving tag list: %v", err)

View File

@ -30,6 +30,7 @@ import (
"github.com/regclient/regclient/internal/auth"
"github.com/regclient/regclient/internal/pqueue"
"github.com/regclient/regclient/internal/reqmeta"
"github.com/regclient/regclient/types"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/warning"
)
@ -875,7 +876,7 @@ func (wt *wrapTransport) RoundTrip(req *http.Request) (*http.Response, error) {
warning.Handle(req.Context(), wt.c.slog, match[1])
}
}
wt.c.slog.Log(req.Context(), slog.LevelDebug-4, "reg http request",
wt.c.slog.Log(req.Context(), types.LevelTrace, "reg http request",
slog.String("req-method", req.Method),
slog.String("req-url", req.URL.String()),
slog.Any("req-headers", reqHead),

View File

@ -7,6 +7,8 @@ import (
"strings"
"github.com/sirupsen/logrus"
"github.com/regclient/regclient/types"
)
func Logrus(logger *logrus.Logger) *logrusHandler {
@ -93,7 +95,7 @@ func (h *logrusHandler) clone() *logrusHandler {
}
var logrusToSlog = map[logrus.Level]slog.Level{
logrus.TraceLevel: slog.LevelDebug - 4,
logrus.TraceLevel: types.LevelTrace,
logrus.DebugLevel: slog.LevelDebug,
logrus.InfoLevel: slog.LevelInfo,
logrus.WarnLevel: slog.LevelWarn,
@ -103,7 +105,7 @@ var logrusToSlog = map[logrus.Level]slog.Level{
}
func slogToLogrus(level slog.Level) logrus.Level {
if level <= slog.LevelDebug-4 {
if level <= types.LevelTrace {
return logrus.TraceLevel
} else if level <= slog.LevelDebug {
return logrus.DebugLevel

View File

@ -8,6 +8,8 @@ import (
"testing"
"github.com/sirupsen/logrus"
"github.com/regclient/regclient/types"
)
func TestLogrus(t *testing.T) {
@ -20,7 +22,7 @@ func TestLogrus(t *testing.T) {
{
name: "trace",
logrusLevel: logrus.TraceLevel,
slogLevel: slog.LevelDebug - 4,
slogLevel: types.LevelTrace,
},
{
name: "debug",
@ -70,15 +72,15 @@ func TestLogrus(t *testing.T) {
slogLogger.Warn("test warn with formatted attributes",
slog.Group("child2", slog.String("attr-c1", "c1"), slog.Int("attr-c2", 2)),
slog.String("attr7", "value7"), slog.Int("attr8", 8))
slogLogger.Log(ctx, slog.LevelDebug-4, "test trace message", "attr9", "value9")
slogLogger.Log(ctx, types.LevelTrace, "test trace message", "attr9", "value9")
// check output for logs and check if enabled based on logging level
logs := out.String()
t.Logf("all logs:\n%s", logs)
if strings.Contains(logs, "test trace message") {
if tc.slogLevel > slog.LevelDebug-4 {
if tc.slogLevel > types.LevelTrace {
t.Errorf("trace message seen")
}
} else if tc.slogLevel <= slog.LevelDebug-4 {
} else if tc.slogLevel <= types.LevelTrace {
t.Errorf("trace message not seen")
}
if strings.Contains(logs, "test debug message") {

8
types/slog.go Normal file
View File

@ -0,0 +1,8 @@
package types
import "log/slog"
const (
// LevelTrace is used for tracing network requests.
LevelTrace = slog.LevelDebug - 4
)