Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove logrus #50829

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,6 @@ linters-settings:
desc: 'use "github.com/google/uuid" instead'
- pkg: github.com/pborman/uuid
desc: 'use "github.com/google/uuid" instead'
- pkg: github.com/siddontang/go-log/log
desc: 'use "github.com/sirupsen/logrus" instead'
- pkg: github.com/siddontang/go/log
desc: 'use "github.com/sirupsen/logrus" instead'
- pkg: github.com/tj/assert
desc: 'use "github.com/stretchr/testify/assert" instead'
- pkg: go.uber.org/atomic
Expand All @@ -117,16 +113,29 @@ linters-settings:
desc: 'use "github.com/gravitational/teleport/lib/msgraph" instead'
- pkg: github.com/cloudflare/cfssl
desc: 'use "crypto" or "x/crypto" instead'
# Prevent logrus from being imported by api and e. Once everything in teleport has been converted
# to use log/slog this should be moved into the main block above.
logrus:
# Prevent importing any additional logging libraries.
logging:
files:
- '**/api/**'
- '**/e/**'
- '**/lib/srv/**'
# Integrations are still allowed to use logrus becuase they haven't
# been converted to slog yet. Once they use slog, remove this exception.
- '!**/integrations/**'
# The log package still contains the logrus formatter consumed by the integrations.
# Remove this exception when said formatter is deleted.
- '!**/lib/utils/log/**'
- '!**/lib/utils/cli.go'
deny:
- pkg: github.com/sirupsen/logrus
desc: 'use "log/slog" instead'
- pkg: github.com/siddontang/go-log/log
desc: 'use "log/slog" instead'
- pkg: github.com/siddontang/go/log
desc: 'use "log/slog" instead'
- pkg: github.com/mailgun/log
desc: 'use "log/slog" instead'
- pkg: github.com/saferwall/pe/log
desc: 'use "log/slog" instead'
- pkg: golang.org/x/exp/slog
desc: 'use "log/slog" instead'
# Prevent importing internal packages in client tools or packages containing
# common interfaces consumed by them that are known to bloat binaries or break builds
# because they only support a single platform.
Expand Down
2 changes: 1 addition & 1 deletion e
Submodule e updated from b486de to 498f64
9 changes: 0 additions & 9 deletions integration/helpers/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import (
"github.com/gorilla/websocket"
"github.com/gravitational/trace"
"github.com/jonboulle/clockwork"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/ssh"

Expand Down Expand Up @@ -327,10 +326,6 @@ type InstanceConfig struct {
Priv []byte
// Pub is SSH public key of the instance
Pub []byte
// Log specifies the logger
// Deprecated: Use Logger instead
// TODO(tross): Delete when e is updated
Log utils.Logger
// Logger specifies the logger
Logger *slog.Logger
// Ports is a collection of instance ports.
Expand All @@ -354,10 +349,6 @@ func NewInstance(t *testing.T, cfg InstanceConfig) *TeleInstance {
cfg.Listeners = StandardListenerSetup(t, &cfg.Fds)
}

if cfg.Log == nil {
cfg.Log = logrus.New()
}

if cfg.Logger == nil {
cfg.Logger = slog.New(logutils.DiscardHandler{})
}
Expand Down
4 changes: 2 additions & 2 deletions integration/hostuser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ func TestRootLoginAsHostUser(t *testing.T) {
NodeName: Host,
Priv: privateKey,
Pub: publicKey,
Log: utils.NewLoggerForTests(),
Logger: utils.NewSlogLoggerForTests(),
})

// Create a user that can create a host user.
Expand Down Expand Up @@ -735,7 +735,7 @@ func TestRootStaticHostUsers(t *testing.T) {
NodeName: Host,
Priv: privateKey,
Pub: publicKey,
Log: utils.NewLoggerForTests(),
Logger: utils.NewSlogLoggerForTests(),
})

require.NoError(t, instance.Create(t, nil, false, nil))
Expand Down
21 changes: 10 additions & 11 deletions integrations/lib/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,6 @@ import (
logutils "github.com/gravitational/teleport/lib/utils/log"
)

// These values are meant to be kept in sync with teleport/lib/config.
// (We avoid importing that package here because integrations must not require CGo)
const (
// logFileDefaultMode is the preferred permissions mode for log file.
logFileDefaultMode fs.FileMode = 0o644
// logFileDefaultFlag is the preferred flags set to log file.
logFileDefaultFlag = os.O_WRONLY | os.O_CREATE | os.O_APPEND
)

type Config struct {
Output string `toml:"output"`
Severity string `toml:"severity"`
Expand Down Expand Up @@ -108,8 +99,16 @@ func Setup(conf Config) error {
}

// NewSLogLogger builds a slog.Logger from the logger.Config.
// TODO: this code is adapted from `config.applyLogConfig`, we'll want to deduplicate the logic next time we refactor the logging setup
// TODO(tross): Defer logging initialization to logutils.Initialize and use the
// global slog loggers once integrations has been updated to use slog.
func (conf Config) NewSLogLogger() (*slog.Logger, error) {
codingllama marked this conversation as resolved.
Show resolved Hide resolved
const (
// logFileDefaultMode is the preferred permissions mode for log file.
logFileDefaultMode fs.FileMode = 0o644
// logFileDefaultFlag is the preferred flags set to log file.
logFileDefaultFlag = os.O_WRONLY | os.O_CREATE | os.O_APPEND
)

var w io.Writer
switch conf.Output {
case "":
Expand All @@ -120,7 +119,7 @@ func (conf Config) NewSLogLogger() (*slog.Logger, error) {
w = logutils.NewSharedWriter(os.Stdout)
case teleport.Syslog:
w = os.Stderr
sw, err := utils.NewSyslogWriter()
sw, err := logutils.NewSyslogWriter()
if err != nil {
slog.Default().ErrorContext(context.Background(), "Failed to switch logging to syslog", "error", err)
break
Expand Down
20 changes: 18 additions & 2 deletions lib/client/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"slices"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"unicode/utf8"
Expand Down Expand Up @@ -2850,6 +2851,21 @@ type execResult struct {
exitStatus int
}

// sharedWriter is an [io.Writer] implementation that protects
// writes with a mutex. This allows a single [io.Writer] to be shared
// by both logrus and slog without their output clobbering each other.
type sharedWriter struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So what hapeened / will happen to lib/utils/log.SharedWriter? Is it being moved here? Why don't I see it being deleted in this PR?

(Also, since this file is already huge, can this struct remain in a separate one?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log.SharedWriter is going to be removed with the logrus formatter once we are no longer using logrus. I opted to copy it locally here preemptively since a little bit of copying is better than a little bit of dependency.

mu sync.Mutex
io.Writer
}

func (s *sharedWriter) Write(p []byte) (int, error) {
s.mu.Lock()
defer s.mu.Unlock()

return s.Writer.Write(p)
}

// runCommandOnNodes executes a given bash command on a bunch of remote nodes.
func (tc *TeleportClient) runCommandOnNodes(ctx context.Context, clt *ClusterClient, nodes []TargetNode, command []string) error {
cluster := clt.ClusterName()
Expand Down Expand Up @@ -2909,10 +2925,10 @@ func (tc *TeleportClient) runCommandOnNodes(ctx context.Context, clt *ClusterCli
}
}

stdout := logutils.NewSharedWriter(tc.Stdout)
stdout := &sharedWriter{Writer: tc.Stdout}
stderr := stdout
if tc.Stdout != tc.Stderr {
stderr = logutils.NewSharedWriter(tc.Stderr)
stderr = &sharedWriter{Writer: tc.Stderr}
}

for _, node := range nodes {
Expand Down
81 changes: 8 additions & 73 deletions lib/config/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
"crypto/x509"
"errors"
"io"
"io/fs"
"log/slog"
"maps"
"net"
Expand Down Expand Up @@ -72,13 +71,6 @@ import (
logutils "github.com/gravitational/teleport/lib/utils/log"
)

const (
// logFileDefaultMode is the preferred permissions mode for log file.
logFileDefaultMode fs.FileMode = 0o644
// logFileDefaultFlag is the preferred flags set to log file.
logFileDefaultFlag = os.O_WRONLY | os.O_CREATE | os.O_APPEND
)

// CommandLineFlags stores command line flag values, it's a much simplified subset
// of Teleport configuration (which is fully expressed via YAML config file)
type CommandLineFlags struct {
Expand Down Expand Up @@ -789,79 +781,22 @@ func applyAuthOrProxyAddress(fc *FileConfig, cfg *servicecfg.Config) error {
}

func applyLogConfig(loggerConfig Log, cfg *servicecfg.Config) error {
// TODO: this code is copied in the access plugin logging setup `logger.Config.NewSLogLogger`
// We'll want to deduplicate the logic next time we refactor the logging setup
var w io.Writer
switch loggerConfig.Output {
case "":
w = os.Stderr
case "stderr", "error", "2":
w = os.Stderr
cfg.Console = io.Discard // disable console printing
case "stdout", "out", "1":
w = os.Stdout
case "stderr", "error", "2", "stdout", "out", "1":
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm having a hard time understanding what's going on here. Why do we disable console printing when the user wants to print to the console? I know it wasn't commented in the original code either, but I still think it warrants a word or two.

The documentation comments of Config.Console and Config.Logger don't help too much, either, as they both sound like serving roughly the same purpose.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at Console more closely, I don't actually see it being used anywhere. For now I'm going to leave this as is and in a follow up PR I will remove it entirely.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe keep the cases for "" and teleport.Syslog in the meantime? Is the case for teleport.Syslog obsolete too?

Copy link
Contributor Author

@rosstimothy rosstimothy Jan 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"" and teleport.Syslog are handled by log.Initialize.

cfg.Console = io.Discard // disable console printing
case teleport.Syslog:
var err error
w, err = utils.NewSyslogWriter()
if err != nil {
slog.ErrorContext(context.Background(), "Failed to switch logging to syslog", "error", err)
break
}
default:
// Assume this is a file path.
sharedWriter, err := logutils.NewFileSharedWriter(loggerConfig.Output, logFileDefaultFlag, logFileDefaultMode)
if err != nil {
return trace.Wrap(err, "failed to init the log file shared writer")
}
w = logutils.NewWriterFinalizer[*logutils.FileSharedWriter](sharedWriter)
if err := sharedWriter.RunWatcherReopen(context.Background()); err != nil {
return trace.Wrap(err)
}
}

level := new(slog.LevelVar)
switch strings.ToLower(loggerConfig.Severity) {
case "", "info":
level.Set(slog.LevelInfo)
case "err", "error":
level.Set(slog.LevelError)
case teleport.DebugLevel:
level.Set(slog.LevelDebug)
case "warn", "warning":
level.Set(slog.LevelWarn)
case "trace":
level.Set(logutils.TraceLevel)
default:
return trace.BadParameter("unsupported logger severity: %q", loggerConfig.Severity)
}

configuredFields, err := logutils.ValidateFields(loggerConfig.Format.ExtraFields)
logger, level, err := logutils.Initialize(logutils.Config{
Output: loggerConfig.Output,
Severity: loggerConfig.Severity,
Format: loggerConfig.Format.Output,
ExtraFields: loggerConfig.Format.ExtraFields,
EnableColors: utils.IsTerminal(os.Stderr),
})
if err != nil {
return trace.Wrap(err)
}

var logger *slog.Logger
switch strings.ToLower(loggerConfig.Format.Output) {
case "":
fallthrough // not set. defaults to 'text'
case "text":
logger = slog.New(logutils.NewSlogTextHandler(w, logutils.SlogTextHandlerConfig{
Level: level,
EnableColors: utils.IsTerminal(os.Stderr),
ConfiguredFields: configuredFields,
}))
slog.SetDefault(logger)
case "json":
logger = slog.New(logutils.NewSlogJSONHandler(w, logutils.SlogJSONHandlerConfig{
Level: level,
ConfiguredFields: configuredFields,
}))
slog.SetDefault(logger)
default:
return trace.BadParameter("unsupported log output format : %q", loggerConfig.Format.Output)
}

cfg.Logger = logger
cfg.LoggerLevel = level
return nil
Expand Down
5 changes: 0 additions & 5 deletions lib/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ import (
"github.com/jonboulle/clockwork"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/quic-go/quic-go"
"github.com/sirupsen/logrus"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"go.opentelemetry.io/otel/attribute"
"golang.org/x/crypto/acme"
Expand Down Expand Up @@ -992,10 +991,6 @@ func NewTeleport(cfg *servicecfg.Config) (*TeleportProcess, error) {
}

processID := fmt.Sprintf("%v", nextProcessID())
cfg.Log = utils.WrapLogger(cfg.Log.WithFields(logrus.Fields{
teleport.ComponentKey: teleport.Component(teleport.ComponentProcess, processID),
"pid": fmt.Sprintf("%v.%v", os.Getpid(), processID),
}))
cfg.Logger = cfg.Logger.With(
teleport.ComponentKey, teleport.Component(teleport.ComponentProcess, processID),
"pid", fmt.Sprintf("%v.%v", os.Getpid(), processID),
Expand Down
1 change: 0 additions & 1 deletion lib/service/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -948,7 +948,6 @@ func TestTeleportProcess_reconnectToAuth(t *testing.T) {
cfg.Testing.ConnectFailureC = make(chan time.Duration, 5)
cfg.Testing.ClientTimeout = time.Millisecond
cfg.InstanceMetadataClient = imds.NewDisabledIMDSClient()
cfg.Log = utils.NewLoggerForTests()
cfg.Logger = utils.NewSlogLoggerForTests()
process, err := NewTeleport(cfg)
require.NoError(t, err)
Expand Down
15 changes: 0 additions & 15 deletions lib/service/servicecfg/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import (
"github.com/ghodss/yaml"
"github.com/gravitational/trace"
"github.com/jonboulle/clockwork"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"

"github.com/gravitational/teleport"
Expand All @@ -52,7 +51,6 @@ import (
"github.com/gravitational/teleport/lib/sshca"
usagereporter "github.com/gravitational/teleport/lib/usagereporter/teleport"
"github.com/gravitational/teleport/lib/utils"
logutils "github.com/gravitational/teleport/lib/utils/log"
)

// Config contains the configuration for all services that Teleport can run.
Expand Down Expand Up @@ -223,10 +221,6 @@ type Config struct {
// Kube is a Kubernetes API gateway using Teleport client identities.
Kube KubeConfig

// Log optionally specifies the logger.
// Deprecated: use Logger instead.
Log utils.Logger

// Logger outputs messages using slog. The underlying handler respects
// the user supplied logging config.
Logger *slog.Logger
Expand Down Expand Up @@ -518,10 +512,6 @@ func ApplyDefaults(cfg *Config) {

cfg.Version = defaults.TeleportConfigVersionV1

if cfg.Log == nil {
cfg.Log = utils.NewLogger()
}

if cfg.Logger == nil {
cfg.Logger = slog.Default()
}
Expand Down Expand Up @@ -698,10 +688,6 @@ func applyDefaults(cfg *Config) {
cfg.Console = io.Discard
}

if cfg.Log == nil {
cfg.Log = logrus.StandardLogger()
}

if cfg.Logger == nil {
cfg.Logger = slog.Default()
}
Expand Down Expand Up @@ -799,7 +785,6 @@ func verifyEnabledService(cfg *Config) error {
// If called after `config.ApplyFileConfig` or `config.Configure` it will also
// change the global loggers.
func (c *Config) SetLogLevel(level slog.Level) {
c.Log.SetLevel(logutils.SlogLevelToLogrusLevel(level))
c.LoggerLevel.Set(level)
}

Expand Down
Loading
Loading