diff --git a/lib/auditd/auditd_linux.go b/lib/auditd/auditd_linux.go index b22860b992b6c..dcff0d6c37bd7 100644 --- a/lib/auditd/auditd_linux.go +++ b/lib/auditd/auditd_linux.go @@ -20,8 +20,10 @@ package auditd import ( "bytes" + "context" "encoding/binary" "errors" + "log/slog" "math" "os" "strconv" @@ -32,7 +34,6 @@ import ( "github.com/gravitational/trace" "github.com/mdlayher/netlink" "github.com/mdlayher/netlink/nlenc" - log "github.com/sirupsen/logrus" ) // featureStatus is a 3 state boolean yes/no/unknown type. @@ -92,7 +93,7 @@ func IsLoginUIDSet() bool { client := NewClient(Message{}) defer func() { if err := client.Close(); err != nil { - log.WithError(err).Warn("Failed to close auditd client.") + slog.WarnContext(context.TODO(), "Failed to close auditd client", "error", err) } }() // We don't need to acquire the internal client mutex as the connection is @@ -108,7 +109,7 @@ func IsLoginUIDSet() bool { loginuid, err := getSelfLoginUID() if err != nil { - log.WithError(err).Debug("failed to read login UID") + slog.DebugContext(context.TODO(), "Failed to read login UID", "error", err) return false } @@ -142,7 +143,7 @@ func SendEvent(event EventType, result ResultType, msg Message) error { defer func() { err := client.Close() if err != nil { - log.WithError(err).Error("failed to close auditd client") + slog.ErrorContext(context.TODO(), "Failed to close auditd client", "error", err) } }() @@ -206,7 +207,7 @@ func NewClient(msg Message) *Client { execName, err := os.Executable() if err != nil { - log.WithError(err).Warn("failed to get executable name") + slog.WarnContext(context.TODO(), "Failed to get executable name", "error", err) execName = UnknownValue } diff --git a/lib/auth/join/join.go b/lib/auth/join/join.go index 038a8a693283f..4b11e995c92b7 100644 --- a/lib/auth/join/join.go +++ b/lib/auth/join/join.go @@ -26,7 +26,6 @@ import ( "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - log "github.com/sirupsen/logrus" "go.opentelemetry.io/otel" "golang.org/x/crypto/ssh" @@ -261,13 +260,13 @@ func Register(ctx context.Context, params RegisterParams) (result *RegisterResul // If an explicit AuthClient has been provided, we want to go straight to // using that rather than trying both proxy and auth dialing. if params.AuthClient != nil { - log.Info("Attempting registration with existing auth client.") + slog.InfoContext(ctx, "Attempting registration with existing auth client.") result, err := registerThroughAuthClient(ctx, token, params, params.AuthClient) if err != nil { - log.WithError(err).Error("Registration with existing auth client failed.") + slog.ErrorContext(ctx, "Registration with existing auth client failed.", "error", err) return nil, trace.Wrap(err) } - log.Info("Successfully registered with existing auth client.") + slog.InfoContext(ctx, "Successfully registered with existing auth client.") return result, nil } @@ -282,35 +281,35 @@ func Register(ctx context.Context, params RegisterParams) (result *RegisterResul registerMethods := []registerMethod{registerThroughAuth, registerThroughProxy} if !params.ProxyServer.IsEmpty() { - log.WithField("proxy-server", params.ProxyServer).Debugf("Registering node to the cluster.") + slog.DebugContext(ctx, "Registering node to the cluster.", "proxy_server", params.ProxyServer) registerMethods = []registerMethod{registerThroughProxy} if proxyServerIsAuth(params.ProxyServer) { - log.Debugf("The specified proxy server appears to be an auth server.") + slog.DebugContext(ctx, "The specified proxy server appears to be an auth server.") } } else { - log.WithField("auth-servers", params.AuthServers).Debugf("Registering node to the cluster.") + slog.DebugContext(ctx, "Registering node to the cluster.", "auth_servers", params.AuthServers) if params.GetHostCredentials == nil { - log.Debugf("Missing client, it is not possible to register through proxy.") + slog.DebugContext(ctx, "Missing client, it is not possible to register through proxy.") registerMethods = []registerMethod{registerThroughAuth} } else if authServerIsProxy(params.AuthServers) { - log.Debugf("The first specified auth server appears to be a proxy.") + slog.DebugContext(ctx, "The first specified auth server appears to be a proxy.") registerMethods = []registerMethod{registerThroughProxy, registerThroughAuth} } } var collectedErrs []error for _, method := range registerMethods { - log.Infof("Attempting registration %s.", method.desc) + slog.InfoContext(ctx, "Attempting registration.", "method", method.desc) result, err := method.call(ctx, token, params) if err != nil { collectedErrs = append(collectedErrs, err) - log.WithError(err).Debugf("Registration %s failed.", method.desc) + slog.DebugContext(ctx, "Registration failed.", "method", method.desc, "error", err) continue } - log.Infof("Successfully registered %s.", method.desc) + slog.InfoContext(ctx, "Successfully registered.", "method", method.desc) return result, nil } return nil, trace.NewAggregate(collectedErrs...) @@ -411,19 +410,19 @@ func registerThroughAuth( // depending on the configured values for Insecure, CAPins and CAPath. switch { case params.Insecure: - log.Warnf("Insecure mode enabled. Auth Server cert will not be validated and CAPins and CAPath value will be ignored.") - client, err = insecureRegisterClient(params) + slog.WarnContext(ctx, "Insecure mode enabled. Auth Server cert will not be validated and CAPins and CAPath value will be ignored.") + client, err = insecureRegisterClient(ctx, params) case len(params.CAPins) != 0: // CAPins takes precedence over CAPath client, err = pinRegisterClient(ctx, params) case params.CAPath != "": - client, err = caPathRegisterClient(params) + client, err = caPathRegisterClient(ctx, params) default: // We fall back to insecure mode here - this is a little odd but is // necessary to preserve the behavior of registration. At a later date, // we may consider making this an error asking the user to provide // Insecure, CAPins or CAPath. - client, err = insecureRegisterClient(params) + client, err = insecureRegisterClient(ctx, params) } if err != nil { return nil, trace.Wrap(err, "building auth client") @@ -487,11 +486,12 @@ func getHostAddresses(params RegisterParams) []string { // insecureRegisterClient attempts to connects to the Auth Server using the // CA on disk. If no CA is found on disk, Teleport will not verify the Auth // Server it is connecting to. -func insecureRegisterClient(params RegisterParams) (*authclient.Client, error) { - log.Warnf("Joining cluster without validating the identity of the Auth " + - "Server. This may open you up to a Man-In-The-Middle (MITM) attack if an " + - "attacker can gain privileged network access. To remedy this, use the CA pin " + - "value provided when join token was generated to validate the identity of " + +func insecureRegisterClient(ctx context.Context, params RegisterParams) (*authclient.Client, error) { + //nolint:sloglint // Conjoined string literals trip up the linter. + slog.WarnContext(ctx, "Joining cluster without validating the identity of the Auth "+ + "Server. This may open you up to a Man-In-The-Middle (MITM) attack if an "+ + "attacker can gain privileged network access. To remedy this, use the CA pin "+ + "value provided when join token was generated to validate the identity of "+ "the Auth Server or point to a valid Certificate via the CA Path option.") tlsConfig := utils.TLSConfig(params.CipherSuites) @@ -504,6 +504,7 @@ func insecureRegisterClient(params RegisterParams) (*authclient.Client, error) { client.LoadTLS(tlsConfig), }, CircuitBreakerConfig: params.CircuitBreakerConfig, + Context: ctx, }) if err != nil { return nil, trace.Wrap(err, "creating insecure auth client") @@ -531,6 +532,7 @@ func pinRegisterClient( client.LoadTLS(tlsConfig), }, CircuitBreakerConfig: params.CircuitBreakerConfig, + Context: ctx, }) if err != nil { return nil, trace.Wrap(err) @@ -564,7 +566,7 @@ func pinRegisterClient( } } - log.Infof("Joining remote cluster %v with CA pin.", certs[0].Subject.CommonName) + slog.InfoContext(ctx, "Joining remote cluster with CA pin.", "cluster", certs[0].Subject.CommonName) // Create another client, but this time with the CA provided to validate // that the Auth Server was issued a certificate by the same CA. @@ -582,6 +584,7 @@ func pinRegisterClient( client.LoadTLS(tlsConfig), }, CircuitBreakerConfig: params.CircuitBreakerConfig, + Context: ctx, }) if err != nil { return nil, trace.Wrap(err) @@ -590,7 +593,7 @@ func pinRegisterClient( return authClient, nil } -func caPathRegisterClient(params RegisterParams) (*authclient.Client, error) { +func caPathRegisterClient(ctx context.Context, params RegisterParams) (*authclient.Client, error) { tlsConfig := utils.TLSConfig(params.CipherSuites) tlsConfig.Time = params.Clock.Now @@ -604,15 +607,15 @@ func caPathRegisterClient(params RegisterParams) (*authclient.Client, error) { // we may wish to consider changing this to return an error - but this is a // breaking change. if trace.IsNotFound(err) { - log.Warnf("Falling back to insecurely joining because a missing or empty CA Path was provided.") - return insecureRegisterClient(params) + slog.WarnContext(ctx, "Falling back to insecurely joining because a missing or empty CA Path was provided.") + return insecureRegisterClient(ctx, params) } certPool := x509.NewCertPool() certPool.AddCert(cert) tlsConfig.RootCAs = certPool - log.Infof("Joining remote cluster %v, validating connection with certificate on disk.", cert.Subject.CommonName) + slog.InfoContext(ctx, "Joining remote cluster, validating connection with certificate on disk.", "cluster", cert.Subject.CommonName) client, err := authclient.NewClient(client.Config{ Addrs: getHostAddresses(params), @@ -620,6 +623,7 @@ func caPathRegisterClient(params RegisterParams) (*authclient.Client, error) { client.LoadTLS(tlsConfig), }, CircuitBreakerConfig: params.CircuitBreakerConfig, + Context: ctx, }) if err != nil { return nil, trace.Wrap(err) @@ -659,7 +663,7 @@ func registerUsingTokenRequestForParams(token string, hostKeys *newHostKeys, par func registerUsingIAMMethod( ctx context.Context, joinServiceClient joinServiceClient, token string, hostKeys *newHostKeys, params RegisterParams, ) (*proto.Certs, error) { - log.Infof("Attempting to register %s with IAM method using regional STS endpoint", params.ID.Role) + slog.InfoContext(ctx, "Attempting to register with IAM method using region STS endpoint.", "role", params.ID.Role) // Call RegisterUsingIAMMethod and pass a callback to respond to the challenge with a signed join request. certs, err := joinServiceClient.RegisterUsingIAMMethod(ctx, func(challenge string) (*proto.RegisterUsingIAMMethodRequest, error) { // create the signed sts:GetCallerIdentity request and include the challenge @@ -677,11 +681,11 @@ func registerUsingIAMMethod( }, nil }) if err != nil { - log.WithError(err).Infof("Failed to register %s using regional STS endpoint", params.ID.Role) + slog.InfoContext(ctx, "Failed to register using regional STS endpoint", "role", params.ID.Role, "error", err) return nil, trace.Wrap(err, "registering via IAM method streaming RPC") } - log.Infof("Successfully registered %s with IAM method using regional STS endpoint", params.ID.Role) + slog.InfoContext(ctx, "Successfully registered with IAM method using regional STS endpoint.", "role", params.ID.Role) return certs, nil } diff --git a/lib/cgroup/cgroup.go b/lib/cgroup/cgroup.go index e611aa5bb563e..da7baef34c6cb 100644 --- a/lib/cgroup/cgroup.go +++ b/lib/cgroup/cgroup.go @@ -29,6 +29,7 @@ import "C" import ( "bufio" "bytes" + "context" "encoding/binary" "os" "path/filepath" @@ -38,17 +39,15 @@ import ( "github.com/google/uuid" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "golang.org/x/sys/unix" "github.com/gravitational/teleport" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/utils" + logutils "github.com/gravitational/teleport/lib/utils/log" ) -var log = logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: teleport.ComponentCgroup, -}) +var logger = logutils.NewPackageLogger(teleport.ComponentKey, teleport.ComponentCgroup) // Config holds configuration for the cgroup service. type Config struct { @@ -97,7 +96,7 @@ func New(config *Config) (*Service, error) { return nil, trace.Wrap(err) } - log.Debugf("Teleport session hierarchy mounted at: %v.", s.teleportRoot) + logger.DebugContext(context.TODO(), "Teleport session hierarchy mounted.", "hierarchy_root", s.teleportRoot) return s, nil } @@ -110,7 +109,7 @@ func (s *Service) Close(skipUnmount bool) error { } if skipUnmount { - log.Debugf("Cleaned up Teleport session hierarchy at: %v.", s.teleportRoot) + logger.DebugContext(context.TODO(), "Cleaned up Teleport session hierarchy.", "hierarchy_root", s.teleportRoot) return nil } @@ -119,7 +118,7 @@ func (s *Service) Close(skipUnmount bool) error { return trace.Wrap(err) } - log.Debugf("Cleaned up and unmounted Teleport session hierarchy at: %v.", s.teleportRoot) + logger.DebugContext(context.TODO(), "Cleaned up and unmounted Teleport session hierarchy.", "hierarchy_root", s.teleportRoot) return nil } @@ -154,7 +153,7 @@ func (s *Service) Remove(sessionID string) error { return trace.Wrap(err) } - log.Debugf("Removed cgroup for session: %v.", sessionID) + logger.DebugContext(context.TODO(), "Removed cgroup for session.", "session_id", sessionID) return nil } @@ -320,7 +319,7 @@ func (s *Service) mount() error { if err != nil { return trace.Wrap(err) } - log.Debugf("Mounted cgroup filesystem to %v.", s.MountPath) + logger.DebugContext(context.TODO(), "Mounted cgroup filesystem.", "mount_path", s.MountPath) // Create cgroup that will hold Teleport sessions. err = os.MkdirAll(s.teleportRoot, fileMode) diff --git a/lib/observability/tracing/tracing.go b/lib/observability/tracing/tracing.go index 272f54d3dff19..92809fd2b1619 100644 --- a/lib/observability/tracing/tracing.go +++ b/lib/observability/tracing/tracing.go @@ -21,13 +21,13 @@ package tracing import ( "context" "crypto/tls" + "log/slog" "net" "net/url" "strings" "time" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/propagation" @@ -73,7 +73,7 @@ type Config struct { // DialTimeout is the timeout for dialing the exporter. DialTimeout time.Duration // Logger is the logger to use. - Logger logrus.FieldLogger + Logger *slog.Logger // Client is the client to use to export traces. This takes precedence over creating a // new client with the ExporterURL. Ownership of the client is transferred to the // tracing provider. It should **NOT** be closed by the caller. @@ -99,7 +99,7 @@ func (c *Config) CheckAndSetDefaults() error { } if c.Logger == nil { - c.Logger = logrus.WithField(teleport.ComponentKey, teleport.ComponentTracing) + c.Logger = slog.With(teleport.ComponentKey, teleport.ComponentTracing) } if c.Client != nil { @@ -218,7 +218,7 @@ func NewTraceProvider(ctx context.Context, cfg Config) (*Provider, error) { // override the global logging handled with one that uses the // configured logger instead otel.SetErrorHandler(otel.ErrorHandlerFunc(func(err error) { - cfg.Logger.WithError(err).Warnf("failed to export traces.") + cfg.Logger.WarnContext(ctx, "Failed to export traces", "error", err) })) // set global provider to our provider wrapper to have all tracers use the common TracerOptions diff --git a/lib/observability/tracing/tracing_test.go b/lib/observability/tracing/tracing_test.go index b754bf7715112..ce7253b380eb1 100644 --- a/lib/observability/tracing/tracing_test.go +++ b/lib/observability/tracing/tracing_test.go @@ -38,7 +38,6 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" ) @@ -515,8 +514,8 @@ func TestConfig_CheckAndSetDefaults(t *testing.T) { } require.Empty(t, cmp.Diff(tt.expectedCfg, tt.cfg, cmpopts.IgnoreUnexported(Config{}), - cmpopts.IgnoreInterfaces(struct{ logrus.FieldLogger }{})), - ) + cmpopts.IgnoreFields(Config{}, "Logger"), + )) require.NotNil(t, tt.cfg.Logger) }) } diff --git a/lib/player/player.go b/lib/player/player.go index fa52f790d8611..e36b980d98b4b 100644 --- a/lib/player/player.go +++ b/lib/player/player.go @@ -20,15 +20,16 @@ package player import ( + "cmp" "context" "errors" + "log/slog" "math" "sync/atomic" "time" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "golang.org/x/exp/maps" "github.com/gravitational/teleport" @@ -42,7 +43,7 @@ import ( type Player struct { // read only config fields clock clockwork.Clock - log logrus.FieldLogger + log *slog.Logger sessionID session.ID streamer Streamer skipIdleTime bool @@ -108,7 +109,7 @@ type sessionPrintTranslator interface { // Config configures a session player. type Config struct { Clock clockwork.Clock - Log logrus.FieldLogger + Log *slog.Logger SessionID session.ID Streamer Streamer SkipIdleTime bool @@ -128,10 +129,10 @@ func New(cfg *Config) (*Player, error) { clk = clockwork.NewRealClock() } - var log logrus.FieldLogger = cfg.Log - if log == nil { - log = logrus.New().WithField(teleport.ComponentKey, "player") - } + log := cmp.Or( + cfg.Log, + slog.With(teleport.ComponentKey, "player"), + ) p := &Player{ clock: clk, @@ -190,19 +191,19 @@ func (p *Player) stream() { close(p.emit) return case err := <-errC: - p.log.Warn(err) + p.log.WarnContext(ctx, "Event streamer encountered error", "error", err) p.err = err close(p.emit) return case evt := <-eventsC: if evt == nil { - p.log.Debugf("reached end of playback for session %v", p.sessionID) + p.log.DebugContext(ctx, "Reached end of playback for session", "session_id", p.sessionID) close(p.emit) return } if err := p.waitWhilePaused(); err != nil { - p.log.Warn(err) + p.log.WarnContext(ctx, "Encountered error in pause state", "error", err) close(p.emit) return } @@ -238,7 +239,7 @@ func (p *Player) stream() { switch err := p.applyDelay(lastDelay, currentDelay); { case errors.Is(err, errSeekWhilePaused): - p.log.Debug("seeked during pause, will restart stream") + p.log.DebugContext(ctx, "Seeked during pause, will restart stream") go p.stream() return case err != nil: diff --git a/lib/release/release.go b/lib/release/release.go index 0e06efb90a908..4a442daf70b95 100644 --- a/lib/release/release.go +++ b/lib/release/release.go @@ -23,12 +23,12 @@ import ( "crypto/tls" "encoding/json" "fmt" + "log/slog" "net/http" "os" "github.com/gravitational/roundtrip" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/utils" @@ -95,7 +95,7 @@ func (c *Client) ListReleases(ctx context.Context) ([]*types.Release, error) { resp, err := c.client.Get(ctx, c.client.Endpoint(types.EnterpriseReleaseEndpoint), nil) if err != nil { - log.WithError(err).Error("failed to retrieve releases from release server") + slog.ErrorContext(ctx, "failed to retrieve releases from release server", "error", err) return nil, trace.Wrap(err) } diff --git a/lib/service/service.go b/lib/service/service.go index 0870695cef8fd..01e4fdad21224 100644 --- a/lib/service/service.go +++ b/lib/service/service.go @@ -2018,7 +2018,7 @@ func (process *TeleportProcess) initAuthService() error { if err != nil { return trace.Wrap(err) } - traceConf.Logger = process.log.WithField(teleport.ComponentKey, teleport.ComponentTracing) + traceConf.Logger = process.logger.With(teleport.ComponentKey, teleport.ComponentTracing) clt, err := tracing.NewStartedClient(process.ExitContext(), *traceConf) if err != nil { @@ -3629,7 +3629,7 @@ func (process *TeleportProcess) initTracingService() error { if err != nil { return trace.Wrap(err) } - traceConf.Logger = process.log.WithField(teleport.ComponentKey, teleport.Component(teleport.ComponentTracing, process.id)) + traceConf.Logger = process.logger.With(teleport.ComponentKey, teleport.Component(teleport.ComponentTracing, process.id)) provider, err := tracing.NewTraceProvider(process.ExitContext(), *traceConf) if err != nil { @@ -4486,7 +4486,7 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error { if err != nil { return trace.Wrap(err) } - traceConf.Logger = process.log.WithField(teleport.ComponentKey, teleport.ComponentTracing) + traceConf.Logger = process.logger.With(teleport.ComponentKey, teleport.ComponentTracing) clt, err := tracing.NewStartedClient(process.ExitContext(), *traceConf) if err != nil { diff --git a/lib/web/desktop/playback_test.go b/lib/web/desktop/playback_test.go index 43225b2b18022..12c52ad7e2862 100644 --- a/lib/web/desktop/playback_test.go +++ b/lib/web/desktop/playback_test.go @@ -81,7 +81,8 @@ func newServer(t *testing.T, streamInterval time.Duration, events []apievents.Au t.Helper() fs := eventstest.NewFakeStreamer(events, streamInterval) - log := utils.NewLoggerForTests() + log := utils.NewSlogLoggerForTests() + logrusLogger := utils.NewLoggerForTests() s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { upgrader := websocket.Upgrader{ @@ -102,7 +103,7 @@ func newServer(t *testing.T, streamInterval time.Duration, events []apievents.Au }) assert.NoError(t, err) player.Play() - desktop.PlayRecording(r.Context(), log, ws, player) + desktop.PlayRecording(r.Context(), logrusLogger, ws, player) })) t.Cleanup(s.Close) diff --git a/lib/web/desktop_playback.go b/lib/web/desktop_playback.go index 9c50cdcc153c7..f4755f18fe789 100644 --- a/lib/web/desktop_playback.go +++ b/lib/web/desktop_playback.go @@ -52,7 +52,7 @@ func (h *Handler) desktopPlaybackHandle( player, err := player.New(&player.Config{ Clock: h.clock, - Log: h.log, + Log: h.logger, SessionID: session.ID(sID), Streamer: clt, }) diff --git a/lib/web/tty_playback.go b/lib/web/tty_playback.go index 232ec37e525bf..76c603c1e49ec 100644 --- a/lib/web/tty_playback.go +++ b/lib/web/tty_playback.go @@ -85,7 +85,7 @@ func (h *Handler) ttyPlaybackHandle( player, err := player.New(&player.Config{ Clock: h.clock, - Log: h.log, + Log: h.logger, SessionID: session.ID(sID), Streamer: clt, })