From f0ac742bdf202ec358cf55b4cfaa061977c1c340 Mon Sep 17 00:00:00 2001 From: Tim Ross Date: Wed, 11 Dec 2024 18:33:07 -0500 Subject: [PATCH] Convert lib/srv/db to use slog --- lib/srv/db/access_test.go | 2 +- lib/srv/db/auth_test.go | 4 +- lib/srv/db/cassandra/test.go | 15 +-- lib/srv/db/clickhouse/test.go | 21 ++-- lib/srv/db/cloud/aws.go | 47 ++++---- lib/srv/db/cloud/iam.go | 48 +++++--- lib/srv/db/cloud/iam_test.go | 8 +- lib/srv/db/cloud/meta.go | 18 +-- lib/srv/db/cloud/resource_checker.go | 10 +- .../db/cloud/resource_checker_credentials.go | 63 ++++++---- lib/srv/db/cloud/resource_checker_url.go | 12 +- lib/srv/db/cloud/resource_checker_url_aws.go | 24 ++-- .../db/cloud/resource_checker_url_aws_test.go | 6 +- .../db/cloud/resource_checker_url_azure.go | 7 +- .../cloud/resource_checker_url_azure_test.go | 6 +- lib/srv/db/common/audit.go | 38 ++++-- lib/srv/db/common/auth.go | 114 +++++++++--------- lib/srv/db/dynamodb/test.go | 9 -- lib/srv/db/elasticsearch/test.go | 8 -- lib/srv/db/mongodb/test.go | 31 ++--- lib/srv/db/mysql/gcp_test.go | 3 +- lib/srv/db/mysql/test.go | 33 ++--- lib/srv/db/opensearch/test.go | 16 +-- lib/srv/db/postgres/engine.go | 11 +- lib/srv/db/redis/engine.go | 17 ++- lib/srv/db/redis/test.go | 10 +- lib/srv/db/server.go | 8 +- lib/srv/db/snowflake/test.go | 16 +-- lib/srv/db/spanner/test.go | 10 -- lib/srv/db/sqlserver/kinit/kinit.go | 10 +- lib/srv/db/sqlserver/test.go | 26 ++-- lib/srv/db/watcher.go | 2 - 32 files changed, 337 insertions(+), 316 deletions(-) diff --git a/lib/srv/db/access_test.go b/lib/srv/db/access_test.go index 0adc9a8b28796..8d415fc8953c0 100644 --- a/lib/srv/db/access_test.go +++ b/lib/srv/db/access_test.go @@ -2611,7 +2611,7 @@ func (c *testContext) setupDatabaseServer(ctx context.Context, t testing.TB, p a for _, db := range p.Databases { select { case sender := <-inventoryHandle.Sender(): - dbServer, err := server.getServerInfo(db) + dbServer, err := server.getServerInfo(ctx, db) require.NoError(t, err) require.NoError(t, sender.Send(ctx, proto.InventoryHeartbeat{ DatabaseServer: dbServer, diff --git a/lib/srv/db/auth_test.go b/lib/srv/db/auth_test.go index d58b431483206..f89cd83d4bf29 100644 --- a/lib/srv/db/auth_test.go +++ b/lib/srv/db/auth_test.go @@ -29,7 +29,6 @@ import ( "github.com/aws/aws-sdk-go/service/elasticache" "github.com/aws/aws-sdk-go/service/memorydb" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "golang.org/x/oauth2" @@ -411,8 +410,7 @@ func (a *testAuth) GenerateDatabaseClientKey(ctx context.Context) (*keys.Private return key, trace.Wrap(err) } -func (a *testAuth) WithLogger(getUpdatedLogger func(logrus.FieldLogger) logrus.FieldLogger) common.Auth { - // TODO(greedy52) update WithLogger to use slog. +func (a *testAuth) WithLogger(getUpdatedLogger func(*slog.Logger) *slog.Logger) common.Auth { return &testAuth{ realAuth: a.realAuth, Logger: a.Logger, diff --git a/lib/srv/db/cassandra/test.go b/lib/srv/db/cassandra/test.go index 5461fa3cc380b..1593d2f4ba016 100644 --- a/lib/srv/db/cassandra/test.go +++ b/lib/srv/db/cassandra/test.go @@ -22,6 +22,7 @@ import ( "bytes" "context" "crypto/tls" + "log/slog" "net" "strings" "time" @@ -33,11 +34,11 @@ import ( "github.com/datastax/go-cassandra-native-protocol/primitive" "github.com/gocql/gocql" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/srv/db/common" + "github.com/gravitational/teleport/lib/utils" ) // Session alias for easier use. @@ -97,7 +98,7 @@ type TestServer struct { cfg common.TestServerConfig port string tlsConfig *tls.Config - log logrus.FieldLogger + logger *slog.Logger server *client.CqlServer } @@ -142,10 +143,10 @@ func NewTestServer(config common.TestServerConfig, opts ...TestServerOption) (*T port: port, tlsConfig: tlsConfig, server: server, - log: logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: defaults.ProtocolCassandra, - "name": config.Name, - }), + logger: utils.NewSlogLoggerForTests().With( + teleport.ComponentKey, defaults.ProtocolCassandra, + "name", config.Name, + ), } for _, opt := range opts { opt(testServer) @@ -336,7 +337,7 @@ func handleMessageBatch(request *frame.Frame, conn *client.CqlServerConnection, } responseFrame, err := codec.ConvertFromRawFrame(resp) if err != nil { - logrus.Errorf("Error converting raw frame to frame: %v", err) + slog.ErrorContext(context.Background(), "Error converting raw frame to frame", "error", err) return nil } return responseFrame diff --git a/lib/srv/db/clickhouse/test.go b/lib/srv/db/clickhouse/test.go index fc0d3a349308b..485d6db968a36 100644 --- a/lib/srv/db/clickhouse/test.go +++ b/lib/srv/db/clickhouse/test.go @@ -23,6 +23,7 @@ import ( "crypto/tls" "database/sql" "io" + "log/slog" "net" "net/http" "net/http/httptest" @@ -32,11 +33,11 @@ import ( "github.com/ClickHouse/clickhouse-go/v2" "github.com/ClickHouse/clickhouse-go/v2/lib/proto" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/srv/db/common" + "github.com/gravitational/teleport/lib/utils" ) // TestServerOption allows setting test server options. @@ -63,7 +64,7 @@ type TestServer struct { listener net.Listener port string tlsConfig *tls.Config - log logrus.FieldLogger + logger *slog.Logger protocol string } @@ -92,10 +93,10 @@ func NewTestServer(config common.TestServerConfig, opts ...TestServerOption) (*T listener: config.Listener, port: port, tlsConfig: tlsConfig, - log: logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: defaults.ProtocolClickHouse, - "name": config.Name, - }), + logger: utils.NewSlogLoggerForTests().With( + teleport.ComponentKey, defaults.ProtocolClickHouse, + "name", config.Name, + ), } for _, opt := range opts { @@ -182,27 +183,27 @@ func (s *TestServer) serveHTTP() error { mux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { buff, err := io.ReadAll(request.Body) if err != nil { - s.log.Errorf("Got unexpected error %q", err) + s.logger.ErrorContext(request.Context(), "Got unexpected error", "error", err) } defer request.Body.Close() query := string(buff) enc, ok := encHandler[query] if !ok { - s.log.Errorf("Got unexpected query %q", query) + s.logger.ErrorContext(request.Context(), "Got unexpected query", "query", query) writer.WriteHeader(http.StatusInternalServerError) return } respBuff, err := enc() if err != nil { - s.log.Errorf("Got unexpected error: %v", err) + s.logger.ErrorContext(request.Context(), "Got unexpected error", "error", err) writer.WriteHeader(http.StatusInternalServerError) return } _, err = writer.Write(respBuff) if err != nil { - s.log.Errorf("Got unexpected error: %v", err) + s.logger.ErrorContext(request.Context(), "Got unexpected error", "error", err) writer.WriteHeader(http.StatusInternalServerError) return } diff --git a/lib/srv/db/cloud/aws.go b/lib/srv/db/cloud/aws.go index 5f69145230434..706581952b9d2 100644 --- a/lib/srv/db/cloud/aws.go +++ b/lib/srv/db/cloud/aws.go @@ -21,13 +21,13 @@ package cloud import ( "context" "encoding/json" + "log/slog" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/iam/iamiface" "github.com/aws/aws-sdk-go/service/rds" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" @@ -71,10 +71,10 @@ func newAWS(ctx context.Context, config awsConfig) (*awsClient, error) { return nil, trace.Wrap(err) } - logger := logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: "aws", - "db": config.database.GetName(), - }) + logger := slog.With( + teleport.ComponentKey, "aws", + "db", config.database.GetName(), + ) dbConfigurator, err := getDBConfigurator(ctx, logger, config.clients, config.database) if err != nil { return nil, trace.Wrap(err) @@ -92,7 +92,7 @@ func newAWS(ctx context.Context, config awsConfig) (*awsClient, error) { cfg: config, dbConfigurator: dbConfigurator, iam: iam, - log: logger, + logger: logger, }, nil } @@ -102,10 +102,10 @@ type dbIAMAuthConfigurator interface { } // getDBConfigurator returns a database IAM Auth configurator. -func getDBConfigurator(ctx context.Context, log logrus.FieldLogger, clients cloud.Clients, db types.Database) (dbIAMAuthConfigurator, error) { +func getDBConfigurator(ctx context.Context, logger *slog.Logger, clients cloud.Clients, db types.Database) (dbIAMAuthConfigurator, error) { if db.IsRDS() { // Only setting for RDS instances and Aurora clusters. - return &rdsDBConfigurator{clients: clients, log: log}, nil + return &rdsDBConfigurator{clients: clients, logger: logger}, nil } // IAM Auth for Redshift, ElastiCache, and RDS Proxy is always enabled. return &nopDBConfigurator{}, nil @@ -115,14 +115,14 @@ type awsClient struct { cfg awsConfig dbConfigurator dbIAMAuthConfigurator iam iamiface.IAMAPI - log logrus.FieldLogger + logger *slog.Logger } // setupIAMAuth ensures the IAM Authentication is enbaled for RDS, Aurora, ElastiCache or Redshift database. func (r *awsClient) setupIAMAuth(ctx context.Context) error { if err := r.dbConfigurator.ensureIAMAuth(ctx, r.cfg.database); err != nil { if trace.IsAccessDenied(err) { // Permission errors are expected. - r.log.Debugf("No permissions to enable IAM auth: %v.", err) + r.logger.DebugContext(ctx, "No permissions to enable IAM auth", "error", err) return nil } return trace.Wrap(err) @@ -137,7 +137,7 @@ func (r *awsClient) setupIAMAuth(ctx context.Context) error { func (r *awsClient) setupIAMPolicy(ctx context.Context) (bool, error) { if err := r.ensureIAMPolicy(ctx); err != nil { if trace.IsAccessDenied(err) { // Permission errors are expected. - r.log.Debugf("No permissions to ensure IAM policy: %v.", err) + r.logger.DebugContext(ctx, "No permissions to ensure IAM policy", "error", err) return false, nil } @@ -152,7 +152,7 @@ func (r *awsClient) teardownIAM(ctx context.Context) error { var errors []error if err := r.deleteIAMPolicy(ctx); err != nil { if trace.IsAccessDenied(err) { // Permission errors are expected. - r.log.Debugf("No permissions to delete IAM policy: %v.", err) + r.logger.DebugContext(ctx, "No permissions to delete IAM policy", "error", err) } else { errors = append(errors, err) } @@ -174,10 +174,13 @@ func (r *awsClient) ensureIAMPolicy(ctx context.Context) error { var changed bool dbIAM.ForEach(func(effect, action, resource string, conditions awslib.Conditions) { if policy.EnsureResourceAction(effect, action, resource, conditions) { - r.log.Debugf("Adding permission %q for %q to policy.", action, resource) + r.logger.DebugContext(ctx, "Adding database permission to policy", + "action", action, + "resource", resource, + ) changed = true } else { - r.log.Debugf("Permission %q for %q is already part of policy.", action, resource) + r.logger.DebugContext(ctx, "Permission is already part of policy", "action", action, "resource", resource) } }) if !changed { @@ -189,8 +192,10 @@ func (r *awsClient) ensureIAMPolicy(ctx context.Context) error { } if len(placeholders) > 0 { - r.log.Warnf("Please make sure the database agent has the IAM permissions to fetch cloud metadata, or make sure these values are set in the static config. Placeholders %q are found when configuring the IAM policy for database %v.", - placeholders, r.cfg.database.GetName()) + r.logger.WarnContext(ctx, "Please make sure the database agent has the IAM permissions to fetch cloud metadata, or make sure these values are set in the static config. Placeholders were found when configuring the IAM policy for database.", + "placeholders", placeholders, + "database", r.cfg.database.GetName(), + ) } return nil } @@ -252,7 +257,7 @@ func (r *awsClient) getIAMPolicy(ctx context.Context) (*awslib.PolicyDocument, e // updateIAMPolicy attaches IAM access policy to the identity this agent is running as. func (r *awsClient) updateIAMPolicy(ctx context.Context, policy *awslib.PolicyDocument) error { - r.log.Debugf("Updating IAM policy for %v.", r.cfg.identity) + r.logger.DebugContext(ctx, "Updating IAM policy", "identity", r.cfg.identity) document, err := json.Marshal(policy) if err != nil { return trace.Wrap(err) @@ -278,7 +283,7 @@ func (r *awsClient) updateIAMPolicy(ctx context.Context, policy *awslib.PolicyDo // detachIAMPolicy detaches IAM access policy from the identity this agent is running as. func (r *awsClient) detachIAMPolicy(ctx context.Context) error { - r.log.Debugf("Detaching IAM policy from %v.", r.cfg.identity) + r.logger.DebugContext(ctx, "Detaching IAM policy", "identity", r.cfg.identity) var err error switch r.cfg.identity.(type) { case awslib.Role: @@ -299,13 +304,13 @@ func (r *awsClient) detachIAMPolicy(ctx context.Context) error { type rdsDBConfigurator struct { clients cloud.Clients - log logrus.FieldLogger + logger *slog.Logger } // ensureIAMAuth enables RDS instance IAM auth if it isn't already enabled. func (r *rdsDBConfigurator) ensureIAMAuth(ctx context.Context, db types.Database) error { if db.GetAWS().RDS.IAMAuth { - r.log.Debug("IAM auth already enabled.") + r.logger.DebugContext(ctx, "IAM auth already enabled") return nil } if err := r.enableIAMAuth(ctx, db); err != nil { @@ -316,7 +321,7 @@ func (r *rdsDBConfigurator) ensureIAMAuth(ctx context.Context, db types.Database // enableIAMAuth turns on IAM auth setting on the RDS instance. func (r *rdsDBConfigurator) enableIAMAuth(ctx context.Context, db types.Database) error { - r.log.Debug("Enabling IAM auth for RDS.") + r.logger.DebugContext(ctx, "Enabling IAM auth for RDS") meta := db.GetAWS() rdsClt, err := r.clients.GetAWSRDSClient(ctx, meta.Region, cloud.WithAssumeRoleFromAWSMeta(meta), diff --git a/lib/srv/db/cloud/iam.go b/lib/srv/db/cloud/iam.go index 60cc45ffa2ad0..aa1629157d78f 100644 --- a/lib/srv/db/cloud/iam.go +++ b/lib/srv/db/cloud/iam.go @@ -21,13 +21,13 @@ package cloud import ( "context" "errors" + "log/slog" "sync" "time" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" @@ -92,8 +92,8 @@ type iamTask struct { // same policy. These tasks are processed in a background goroutine to avoid // blocking callers when acquiring the locks with retries. type IAM struct { - cfg IAMConfig - log logrus.FieldLogger + cfg IAMConfig + logger *slog.Logger // agentIdentity is the db agent's identity, as determined by // shared config credential chain used to call AWS STS GetCallerIdentity. // Use getAWSIdentity to get the correct identity for a database, @@ -113,7 +113,7 @@ func NewIAM(ctx context.Context, config IAMConfig) (*IAM, error) { } return &IAM{ cfg: config, - log: logrus.WithField(teleport.ComponentKey, "iam"), + logger: slog.With(teleport.ComponentKey, "iam"), tasks: make(chan iamTask, defaultIAMTaskQueueSize), iamPolicyStatus: sync.Map{}, }, nil @@ -122,8 +122,8 @@ func NewIAM(ctx context.Context, config IAMConfig) (*IAM, error) { // Start starts the IAM configurator service. func (c *IAM) Start(ctx context.Context) error { go func() { - c.log.Info("Started IAM configurator service.") - defer c.log.Info("Stopped IAM configurator service.") + c.logger.InfoContext(ctx, "Started IAM configurator service") + defer c.logger.InfoContext(ctx, "Stopped IAM configurator service") for { select { case <-ctx.Done(): @@ -132,7 +132,10 @@ func (c *IAM) Start(ctx context.Context) error { case task := <-c.tasks: err := c.processTask(ctx, task) if err != nil { - c.log.WithError(err).Errorf("Failed to auto-configure IAM for %v.", task.database) + c.logger.ErrorContext(ctx, "Failed to auto-configure IAM for database", + "error", err, + "database", task.database, + ) } if c.cfg.onProcessedTask != nil { c.cfg.onProcessedTask(task, err) @@ -145,7 +148,7 @@ func (c *IAM) Start(ctx context.Context) error { // Setup sets up cloud IAM policies for the provided database. func (c *IAM) Setup(ctx context.Context, database types.Database) error { - if c.isSetupRequiredForDatabase(database) { + if c.isSetupRequiredForDatabase(ctx, database) { c.iamPolicyStatus.Store(database.GetName(), types.IAMPolicyStatus_IAM_POLICY_STATUS_PENDING) return c.addTask(iamTask{ isSetup: true, @@ -157,7 +160,7 @@ func (c *IAM) Setup(ctx context.Context, database types.Database) error { // Teardown tears down cloud IAM policies for the provided database. func (c *IAM) Teardown(ctx context.Context, database types.Database) error { - if c.isSetupRequiredForDatabase(database) { + if c.isSetupRequiredForDatabase(ctx, database) { return c.addTask(iamTask{ isSetup: false, database: database, @@ -167,8 +170,8 @@ func (c *IAM) Teardown(ctx context.Context, database types.Database) error { } // UpdateIAMStatus updates the IAMPolicyExists for the Database. -func (c *IAM) UpdateIAMStatus(database types.Database) error { - if c.isSetupRequiredForDatabase(database) { +func (c *IAM) UpdateIAMStatus(ctx context.Context, database types.Database) error { + if c.isSetupRequiredForDatabase(ctx, database) { awsStatus := database.GetAWS() iamPolicyStatus, ok := c.iamPolicyStatus.Load(database.GetName()) @@ -188,7 +191,7 @@ func (c *IAM) UpdateIAMStatus(database types.Database) error { } // isSetupRequiredForDatabase returns true if database type is supported. -func (c *IAM) isSetupRequiredForDatabase(database types.Database) bool { +func (c *IAM) isSetupRequiredForDatabase(ctx context.Context, database types.Database) bool { switch database.GetType() { case types.DatabaseTypeRDS, types.DatabaseTypeRDSProxy, @@ -197,16 +200,20 @@ func (c *IAM) isSetupRequiredForDatabase(database types.Database) bool { case types.DatabaseTypeElastiCache: ok, err := iam.CheckElastiCacheSupportsIAMAuth(database) if err != nil { - c.log.WithError(err).Debugf("Assuming database %s supports IAM auth.", - database.GetName()) + c.logger.DebugContext(ctx, "Assuming database supports IAM auth", + "error", err, + "database", database.GetName(), + ) return true } return ok case types.DatabaseTypeMemoryDB: ok, err := iam.CheckMemoryDBSupportsIAMAuth(database) if err != nil { - c.log.WithError(err).Debugf("Assuming database %s supports IAM auth.", - database.GetName()) + c.logger.DebugContext(ctx, "Assuming database supports IAM auth", + "error", err, + "database", database.GetName(), + ) return true } return ok @@ -288,7 +295,9 @@ func (c *IAM) processTask(ctx context.Context, task iamTask) error { if err != nil { c.iamPolicyStatus.Store(task.database.GetName(), types.IAMPolicyStatus_IAM_POLICY_STATUS_FAILED) if errors.Is(trace.Unwrap(err), credentials.ErrNoValidProvidersFoundInChain) { - c.log.Warnf("No AWS credentials provider. Skipping IAM task for database %v.", task.database.GetName()) + c.logger.WarnContext(ctx, "No AWS credentials provider, Skipping IAM task for database", + "database", task.database.GetName(), + ) return nil } return trace.Wrap(err) @@ -326,7 +335,10 @@ func (c *IAM) processTask(ctx context.Context, task iamTask) error { defer func() { err := c.cfg.AccessPoint.CancelSemaphoreLease(ctx, *lease) if err != nil { - c.log.WithError(err).Errorf("Failed to cancel lease: %v.", lease) + c.logger.ErrorContext(ctx, "Failed to cancel lease", + "error", err, + "lease", lease.LeaseID, + ) } }() diff --git a/lib/srv/db/cloud/iam_test.go b/lib/srv/db/cloud/iam_test.go index aa343bb83f4a0..e55c94345fc33 100644 --- a/lib/srv/db/cloud/iam_test.go +++ b/lib/srv/db/cloud/iam_test.go @@ -262,7 +262,7 @@ func TestAWSIAM(t *testing.T) { require.True(t, tt.getIAMAuthEnabled()) require.Contains(t, aws.StringValue(output.PolicyDocument), tt.wantPolicyContains) - err = configurator.UpdateIAMStatus(database) + err = configurator.UpdateIAMStatus(ctx, database) require.NoError(t, err) require.Equal(t, types.IAMPolicyStatus_IAM_POLICY_STATUS_SUCCESS, database.GetAWS().IAMPolicyStatus, "must be success because iam policy was set up") @@ -279,7 +279,7 @@ func TestAWSIAM(t *testing.T) { stsClient.ResetAssumeRoleHistory() } - err = configurator.UpdateIAMStatus(database) + err = configurator.UpdateIAMStatus(ctx, database) require.NoError(t, err) require.Equal(t, types.IAMPolicyStatus_IAM_POLICY_STATUS_UNSPECIFIED, database.GetAWS().IAMPolicyStatus, "must be unspecified because task is tearing down") }) @@ -401,7 +401,7 @@ func TestAWSIAMNoPermissions(t *testing.T) { }) require.NoError(t, err) - err = configurator.UpdateIAMStatus(database) + err = configurator.UpdateIAMStatus(ctx, database) require.NoError(t, err) require.Equal(t, types.IAMPolicyStatus_IAM_POLICY_STATUS_FAILED, database.GetAWS().IAMPolicyStatus, "must be invalid because of perm issues") @@ -411,7 +411,7 @@ func TestAWSIAMNoPermissions(t *testing.T) { }) require.NoError(t, err) - err = configurator.UpdateIAMStatus(database) + err = configurator.UpdateIAMStatus(ctx, database) require.NoError(t, err) require.Equal(t, types.IAMPolicyStatus_IAM_POLICY_STATUS_UNSPECIFIED, database.GetAWS().IAMPolicyStatus, "must be unspecified, task is tearing down") }) diff --git a/lib/srv/db/cloud/meta.go b/lib/srv/db/cloud/meta.go index 382820df8cbea..515ff0d83ecbe 100644 --- a/lib/srv/db/cloud/meta.go +++ b/lib/srv/db/cloud/meta.go @@ -20,6 +20,7 @@ package cloud import ( "context" + "log/slog" "strings" "github.com/aws/aws-sdk-go/aws" @@ -34,13 +35,13 @@ import ( "github.com/aws/aws-sdk-go/service/redshiftserverless" "github.com/aws/aws-sdk-go/service/redshiftserverless/redshiftserverlessiface" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/cloud" "github.com/gravitational/teleport/lib/srv/db/common" discoverycommon "github.com/gravitational/teleport/lib/srv/discovery/common" + logutils "github.com/gravitational/teleport/lib/utils/log" ) // MetadataConfig is the cloud metadata service config. @@ -63,8 +64,8 @@ func (c *MetadataConfig) Check() error { // Metadata is a service that fetches cloud databases metadata. type Metadata struct { - cfg MetadataConfig - log logrus.FieldLogger + cfg MetadataConfig + logger *slog.Logger } // NewMetadata returns a new cloud metadata service. @@ -73,8 +74,8 @@ func NewMetadata(config MetadataConfig) (*Metadata, error) { return nil, trace.Wrap(err) } return &Metadata{ - cfg: config, - log: logrus.WithField(teleport.ComponentKey, "meta"), + cfg: config, + logger: slog.With(teleport.ComponentKey, "meta"), }, nil } @@ -103,13 +104,16 @@ func (m *Metadata) updateAWS(ctx context.Context, database types.Database, fetch fetchedMeta, err := fetchFn(ctx, database) if err != nil { if trace.IsAccessDenied(err) { // Permission errors are expected. - m.log.WithError(err).Debugf("No permissions to fetch metadata for %q.", database) + m.logger.DebugContext(ctx, "No permissions to fetch metadata for database", + "error", err, + "database", database, + ) return nil } return trace.Wrap(err) } - m.log.Debugf("Fetched metadata for %q: %v.", database, fetchedMeta) + m.logger.DebugContext(ctx, "Fetched metadata for dabase", "database", database, "metadata", logutils.StringerAttr(fetchedMeta)) fetchedMeta.AssumeRoleARN = meta.AssumeRoleARN fetchedMeta.ExternalID = meta.ExternalID database.SetStatusAWS(*fetchedMeta) diff --git a/lib/srv/db/cloud/resource_checker.go b/lib/srv/db/cloud/resource_checker.go index 07bc099350a1d..14b5393cebcc9 100644 --- a/lib/srv/db/cloud/resource_checker.go +++ b/lib/srv/db/cloud/resource_checker.go @@ -20,9 +20,9 @@ package cloud import ( "context" + "log/slog" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" @@ -46,8 +46,8 @@ type DiscoveryResourceCheckerConfig struct { Clients cloud.Clients // Context is the database server close context. Context context.Context - // Log is used for logging. - Log logrus.FieldLogger + // Logger is used for logging. + Logger *slog.Logger } // CheckAndSetDefaults validates the config and sets default values. @@ -62,8 +62,8 @@ func (c *DiscoveryResourceCheckerConfig) CheckAndSetDefaults() error { if c.Context == nil { c.Context = context.Background() } - if c.Log == nil { - c.Log = logrus.WithField(teleport.ComponentKey, teleport.ComponentDatabase) + if c.Logger == nil { + c.Logger = slog.With(teleport.ComponentKey, teleport.ComponentDatabase) } return nil } diff --git a/lib/srv/db/cloud/resource_checker_credentials.go b/lib/srv/db/cloud/resource_checker_credentials.go index e7312fb8cc7f1..2cc126c8eb742 100644 --- a/lib/srv/db/cloud/resource_checker_credentials.go +++ b/lib/srv/db/cloud/resource_checker_credentials.go @@ -20,13 +20,12 @@ package cloud import ( "context" - "fmt" + "log/slog" "slices" "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/cloud" @@ -43,7 +42,7 @@ import ( type credentialsChecker struct { cloudClients cloud.Clients resourceMatchers []services.ResourceMatcher - log logrus.FieldLogger + logger *slog.Logger cache *utils.FnCache } @@ -59,7 +58,7 @@ func newCrednentialsChecker(cfg DiscoveryResourceCheckerConfig) (*credentialsChe return &credentialsChecker{ cloudClients: cfg.Clients, resourceMatchers: cfg.ResourceMatchers, - log: cfg.Log, + logger: cfg.Logger, cache: cache, }, nil } @@ -73,7 +72,10 @@ func (c *credentialsChecker) Check(ctx context.Context, database types.Database) case database.IsAzure(): c.checkAzure(ctx, database) default: - c.log.Debugf("Database %q has unknown cloud type %q.", database.GetName(), database.GetType()) + c.logger.DebugContext(ctx, "Database has unknown cloud type", + "database", database.GetName(), + "cloud_type", database.GetType(), + ) } return nil } @@ -82,16 +84,19 @@ func (c *credentialsChecker) checkAWS(ctx context.Context, database types.Databa meta := database.GetAWS() identity, err := c.getAWSIdentity(ctx, &meta) if err != nil { - c.warn(err, database, "Failed to get AWS identity when checking a database created by the discovery service.") + c.warn(ctx, "Failed to get AWS identity when checking a database created by the discovery service", + "database", database.GetName(), + ) return } if meta.AccountID != "" && meta.AccountID != identity.GetAccountID() { - c.warn(nil, database, fmt.Sprintf("The database agent's identity and discovered database %q have different AWS account IDs (%s vs %s).", - database.GetName(), - identity.GetAccountID(), - meta.AccountID, - )) + c.warn(ctx, + "The database agent's identity and discovered database have different AWS account IDs", + "database", database.GetName(), + "agent_account_id", identity.GetAccountID(), + "discovered_account_id", meta.AccountID, + ) return } } @@ -124,36 +129,44 @@ func (c *credentialsChecker) checkAzure(ctx context.Context, database types.Data return client.ListSubscriptionIDs(ctx) }) if err != nil { - c.warn(err, database, "Failed to get Azure subscription IDs when checking a database created by the discovery service.") + c.warn(ctx, "Failed to get Azure subscription IDs when checking a database created by the discovery service", + "error", err, + "database", database.GetName(), + ) return } rid, err := arm.ParseResourceID(database.GetAzure().ResourceID) if err != nil { - c.log.Warnf("Failed to parse resource ID of database %q: %v.", database.GetName(), err) + c.logger.WarnContext(ctx, "Failed to parse resource ID of database", + "database", database.GetName(), + "error", err, + ) return } if !slices.Contains(allSubIDs, rid.SubscriptionID) { - c.warn(nil, database, fmt.Sprintf("The discovered database %q is in a subscription (ID: %s) that the database agent does not have access to.", - database.GetName(), - rid.SubscriptionID, - )) + c.warn(ctx, "The discovered database is in a subscription that the database agent does not have access to", + "database", database.GetName(), + "subscription", rid.SubscriptionID, + ) return } } -func (c *credentialsChecker) warn(err error, database types.Database, msg string) { - log := c.log.WithField("database", database) - if err != nil { - log = log.WithField("error", err.Error()) - } +func (c *credentialsChecker) warn(ctx context.Context, msg string, args ...any) { + logger := c.logger.With( + "help_message", `You can update "db_service.resources" section of this agent's config file to filter out unwanted resources (see https://goteleport.com/docs/database-access/reference/configuration/ for more details). If this database is intended to be handled by this agent, please verify that valid cloud credentials are configured for the agent.`, + ) - logLevel := logrus.InfoLevel if c.isWildcardMatcher() { - logLevel = logrus.WarnLevel + //nolint:sloglint // The passed in message and args trips up the linter + logger.WarnContext(ctx, msg, args...) + return } - log.Logf(logLevel, "%s You can update \"db_service.resources\" section of this agent's config file to filter out unwanted resources (see https://goteleport.com/docs/database-access/reference/configuration/ for more details). If this database is intended to be handled by this agent, please verify that valid cloud credentials are configured for the agent.", msg) + + //nolint:sloglint // The passed in message and args trips up the linter + logger.InfoContext(ctx, msg, args...) } func (c *credentialsChecker) isWildcardMatcher() bool { diff --git a/lib/srv/db/cloud/resource_checker_url.go b/lib/srv/db/cloud/resource_checker_url.go index 75562c7457f43..4ca6ed0b0b081 100644 --- a/lib/srv/db/cloud/resource_checker_url.go +++ b/lib/srv/db/cloud/resource_checker_url.go @@ -21,6 +21,7 @@ package cloud import ( "context" "fmt" + "log/slog" "net" "os" "slices" @@ -28,7 +29,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/utils" @@ -39,7 +39,7 @@ import ( // urlChecker validates the database has the correct URL. type urlChecker struct { clients cloud.Clients - log logrus.FieldLogger + logger *slog.Logger warnOnError bool warnAWSOnce sync.Once @@ -53,7 +53,7 @@ type urlChecker struct { func newURLChecker(cfg DiscoveryResourceCheckerConfig) *urlChecker { return &urlChecker{ clients: cfg.Clients, - log: cfg.Log, + logger: cfg.Logger, warnOnError: getWarnOnError(), } } @@ -73,7 +73,7 @@ func getWarnOnError() bool { boolValue, err := utils.ParseBool(value) if err != nil { - logrus.Warnf("Invalid bool value for TELEPORT_DATABASE_URL_CHECK_WARN_ON_ERROR: %q.", value) + slog.WarnContext(context.Background(), "Invalid bool value for TELEPORT_DATABASE_URL_CHECK_WARN_ON_ERROR", "value", value) } return boolValue } @@ -107,13 +107,13 @@ func (c *urlChecker) Check(ctx context.Context, database types.Database) error { if check := checkersByDatabaseType[database.GetType()]; check != nil { err := check(ctx, database) if err != nil && c.warnOnError { - c.log.Warnf("URL check failed for %q: %v.", database.GetName(), err) + c.logger.WarnContext(ctx, "URL check failed for database", "database", database.GetName(), "error", err) return nil } return trace.Wrap(err) } - c.log.Debugf("URL checker does not support database type %q.", database.GetType()) + c.logger.DebugContext(ctx, "URL checker does not support database type", "database_type", database.GetType()) return nil } diff --git a/lib/srv/db/cloud/resource_checker_url_aws.go b/lib/srv/db/cloud/resource_checker_url_aws.go index 7aa92e4ed867c..87a55c4d26f13 100644 --- a/lib/srv/db/cloud/resource_checker_url_aws.go +++ b/lib/srv/db/cloud/resource_checker_url_aws.go @@ -43,30 +43,30 @@ func (c *urlChecker) checkAWS(describeCheck, basicEndpointCheck checkDatabaseFun // describes. Log a warning and permform a basic endpoint validation // instead. if trace.IsAccessDenied(err) { - c.logAWSAccessDeniedError(database, err) + c.logAWSAccessDeniedError(ctx, database, err) if err := basicEndpointCheck(ctx, database); err != nil { return trace.Wrap(err) } - c.log.Debugf("AWS database %q URL validated by basic endpoint check.", database.GetName()) + c.logger.DebugContext(ctx, "AWS database URL validated by basic endpoint check", "database", database.GetName()) return nil } if err != nil { return trace.Wrap(err) } - c.log.Debugf("AWS database %q URL validated by describe check.", database.GetName()) + c.logger.DebugContext(ctx, "AWS database URL validated by describe check", "database", database.GetName()) return nil } } -func (c *urlChecker) logAWSAccessDeniedError(database types.Database, accessDeniedError error) { +func (c *urlChecker) logAWSAccessDeniedError(ctx context.Context, database types.Database, accessDeniedError error) { c.warnAWSOnce.Do(func() { // TODO(greedy52) add links to doc. - c.log.Warn("No permissions to describe AWS resource metadata that is needed for validating databases created by Discovery Service. Basic AWS endpoint validation will be performed instead. For best security, please provide the Database Service with the proper IAM permissions. Enable --debug mode to see details on which databases require more IAM permissions. See Database Access documentation for more details.") + c.logger.WarnContext(ctx, "No permissions to describe AWS resource metadata that is needed for validating databases created by Discovery Service. Basic AWS endpoint validation will be performed instead. For best security, please provide the Database Service with the proper IAM permissions. Enable --debug mode to see details on which databases require more IAM permissions. See Database Access documentation for more details.") }) - c.log.Debugf("No permissions to describe database %q for URL validation.", database.GetName()) + c.logger.DebugContext(ctx, "No permissions to describe database for URL validation", "database", database.GetName()) } func (c *urlChecker) checkRDS(ctx context.Context, database types.Database) error { @@ -103,8 +103,10 @@ func (c *urlChecker) checkRDSCluster(ctx context.Context, database types.Databas } databases, err := common.NewDatabasesFromRDSCluster(rdsCluster, []*rds.DBInstance{}) if err != nil { - c.log.Warnf("Could not convert RDS cluster %q to database resources: %v.", - aws.StringValue(rdsCluster.DBClusterIdentifier), err) + c.logger.WarnContext(ctx, "Could not convert RDS cluster to database resources", + "cluster", aws.StringValue(rdsCluster.DBClusterIdentifier), + "error", err, + ) // common.NewDatabasesFromRDSCluster maybe partially successful so // continue if at least one database is returned. @@ -290,8 +292,10 @@ func (c *urlChecker) checkDocumentDB(ctx context.Context, database types.Databas } databases, err := common.NewDatabasesFromDocumentDBCluster(cluster) if err != nil { - c.log.Warnf("Could not convert DocumentDB cluster %q to database resources: %v.", - aws.StringValue(cluster.DBClusterIdentifier), err) + c.logger.WarnContext(ctx, "Could not convert DocumentDB cluster to database resources", + "cluster", aws.StringValue(cluster.DBClusterIdentifier), + "error", err, + ) // common.NewDatabasesFromDocumentDBCluster maybe partially successful // so continue if at least one database is returned. diff --git a/lib/srv/db/cloud/resource_checker_url_aws_test.go b/lib/srv/db/cloud/resource_checker_url_aws_test.go index c537fef123180..81928cbd7902c 100644 --- a/lib/srv/db/cloud/resource_checker_url_aws_test.go +++ b/lib/srv/db/cloud/resource_checker_url_aws_test.go @@ -28,7 +28,6 @@ import ( "github.com/aws/aws-sdk-go/service/rds" "github.com/aws/aws-sdk-go/service/redshift" "github.com/aws/aws-sdk-go/service/redshiftserverless" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "github.com/gravitational/teleport/api/types" @@ -36,13 +35,12 @@ import ( "github.com/gravitational/teleport/lib/cloud" "github.com/gravitational/teleport/lib/cloud/mocks" "github.com/gravitational/teleport/lib/srv/discovery/common" + "github.com/gravitational/teleport/lib/utils" ) func TestURLChecker_AWS(t *testing.T) { t.Parallel() - log := logrus.New() - log.SetLevel(logrus.DebugLevel) ctx := context.Background() region := "us-west-2" var testCases types.Databases @@ -177,7 +175,7 @@ func TestURLChecker_AWS(t *testing.T) { t.Run(method.name, func(t *testing.T) { c := newURLChecker(DiscoveryResourceCheckerConfig{ Clients: method.clients, - Log: log, + Logger: utils.NewSlogLoggerForTests(), }) for _, database := range testCases { diff --git a/lib/srv/db/cloud/resource_checker_url_azure.go b/lib/srv/db/cloud/resource_checker_url_azure.go index b4a83b7fdb743..5b921cfcac780 100644 --- a/lib/srv/db/cloud/resource_checker_url_azure.go +++ b/lib/srv/db/cloud/resource_checker_url_azure.go @@ -33,7 +33,7 @@ func (c *urlChecker) checkAzure(ctx context.Context, database types.Database) er if err := c.checkIsAzureEndpoint(ctx, database); err != nil { return trace.Wrap(err) } - c.log.Debugf("Azure database %q URL validated.", database.GetName()) + c.logger.DebugContext(ctx, "Azure database URL validated", "database", database.GetName()) return nil } @@ -48,6 +48,9 @@ func (c *urlChecker) checkIsAzureEndpoint(ctx context.Context, database types.Da case defaults.ProtocolSQLServer: return trace.Wrap(requireDatabaseIsEndpoint(ctx, database, azure.IsMSSQLServerEndpoint)) } - c.log.Debugf("URL checker does not support Azure database type %q protocol %q.", database.GetType(), database.GetProtocol()) + c.logger.DebugContext(ctx, "URL checker does not support Azure database protocol", + "database_type", database.GetType(), + "database_protocol", database.GetProtocol(), + ) return nil } diff --git a/lib/srv/db/cloud/resource_checker_url_azure_test.go b/lib/srv/db/cloud/resource_checker_url_azure_test.go index 38ab88b1e0760..910cdc10a020e 100644 --- a/lib/srv/db/cloud/resource_checker_url_azure_test.go +++ b/lib/srv/db/cloud/resource_checker_url_azure_test.go @@ -22,18 +22,16 @@ import ( "context" "testing" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/defaults" + "github.com/gravitational/teleport/lib/utils" ) func TestURLChecker_Azure(t *testing.T) { t.Parallel() - log := logrus.New() - log.SetLevel(logrus.DebugLevel) ctx := context.Background() testCases := types.Databases{ @@ -49,7 +47,7 @@ func TestURLChecker_Azure(t *testing.T) { } c := newURLChecker(DiscoveryResourceCheckerConfig{ - Log: log, + Logger: utils.NewSlogLoggerForTests(), }) for _, database := range testCases { t.Run(database.GetName(), func(t *testing.T) { diff --git a/lib/srv/db/common/audit.go b/lib/srv/db/common/audit.go index 86c2c68b50217..64b6bd1de9bd7 100644 --- a/lib/srv/db/common/audit.go +++ b/lib/srv/db/common/audit.go @@ -20,10 +20,10 @@ package common import ( "context" + "log/slog" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" apidefaults "github.com/gravitational/teleport/api/defaults" @@ -118,7 +118,7 @@ type audit struct { // cfg is the audit events emitter configuration. cfg AuditConfig // log is used for logging - log logrus.FieldLogger + logger *slog.Logger } // NewAudit returns a new instance of the audit events emitter. @@ -127,8 +127,8 @@ func NewAudit(config AuditConfig) (Audit, error) { return nil, trace.Wrap(err) } return &audit{ - cfg: config, - log: logrus.WithField(teleport.ComponentKey, config.Component), + cfg: config, + logger: slog.With(teleport.ComponentKey, config.Component), }, nil } @@ -303,14 +303,26 @@ func (a *audit) EmitEvent(ctx context.Context, event events.AuditEvent) { defer methodCallMetrics("EmitEvent", a.cfg.Component, a.cfg.Database)() preparedEvent, err := a.cfg.Recorder.PrepareSessionEvent(event) if err != nil { - a.log.WithError(err).Errorf("Failed to setup event: %s - %s.", event.GetType(), event.GetID()) + a.logger.ErrorContext(ctx, "Failed to setup event", + "error", err, + "event_type", event.GetType(), + "event_id", event.GetID(), + ) return } if err := a.cfg.Recorder.RecordEvent(ctx, preparedEvent); err != nil { - a.log.WithError(err).Errorf("Failed to record session event: %s - %s.", event.GetType(), event.GetID()) + a.logger.ErrorContext(ctx, "Failed to record session event", + "error", err, + "event_type", event.GetType(), + "event_id", event.GetID(), + ) } if err := a.cfg.Emitter.EmitAuditEvent(ctx, preparedEvent.GetAuditEvent()); err != nil { - a.log.WithError(err).Errorf("Failed to emit audit event: %s - %s.", event.GetType(), event.GetID()) + a.logger.ErrorContext(ctx, "Failed to emit audit event", + "error", err, + "event_type", event.GetType(), + "event_id", event.GetID(), + ) } } @@ -319,11 +331,19 @@ func (a *audit) RecordEvent(ctx context.Context, event events.AuditEvent) { defer methodCallMetrics("RecordEvent", a.cfg.Component, a.cfg.Database)() preparedEvent, err := a.cfg.Recorder.PrepareSessionEvent(event) if err != nil { - a.log.WithError(err).Errorf("Failed to setup event: %s - %s.", event.GetType(), event.GetID()) + a.logger.ErrorContext(ctx, "Failed to setup event", + "error", err, + "event_type", event.GetType(), + "event_id", event.GetID(), + ) return } if err := a.cfg.Recorder.RecordEvent(ctx, preparedEvent); err != nil { - a.log.WithError(err).Errorf("Failed to record session event: %s - %s.", event.GetType(), event.GetID()) + a.logger.ErrorContext(ctx, "Failed to record session event", + "error", err, + "event_type", event.GetType(), + "event_id", event.GetID(), + ) } } diff --git a/lib/srv/db/common/auth.go b/lib/srv/db/common/auth.go index 5367abdf6a5b9..43f5df408ab85 100644 --- a/lib/srv/db/common/auth.go +++ b/lib/srv/db/common/auth.go @@ -24,6 +24,7 @@ import ( "crypto/x509" "crypto/x509/pkix" "fmt" + "log/slog" "net/http" "net/url" "strings" @@ -43,7 +44,6 @@ import ( "github.com/aws/aws-sdk-go/service/redshiftserverless" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "golang.org/x/oauth2" sqladmin "google.golang.org/api/sqladmin/v1beta4" @@ -107,7 +107,7 @@ type Auth interface { GenerateDatabaseClientKey(context.Context) (*keys.PrivateKey, error) // WithLogger returns a new instance of Auth with updated logger. // The callback function receives the current logger and returns a new one. - WithLogger(getUpdatedLogger func(logrus.FieldLogger) logrus.FieldLogger) Auth + WithLogger(getUpdatedLogger func(*slog.Logger) *slog.Logger) Auth } // AuthClient is an interface that defines a subset of libauth.Client's @@ -134,8 +134,8 @@ type AuthConfig struct { Clients cloud.Clients // Clock is the clock implementation. Clock clockwork.Clock - // Log is used for logging. - Log logrus.FieldLogger + // Logger is used for logging. + Logger *slog.Logger } // CheckAndSetDefaults validates the config and sets defaults. @@ -152,19 +152,19 @@ func (c *AuthConfig) CheckAndSetDefaults() error { if c.Clock == nil { c.Clock = clockwork.NewRealClock() } - if c.Log == nil { - c.Log = logrus.WithField(teleport.ComponentKey, "db:auth") + if c.Logger == nil { + c.Logger = slog.With(teleport.ComponentKey, "db:auth") } return nil } -func (c *AuthConfig) withLogger(getUpdatedLogger func(logrus.FieldLogger) logrus.FieldLogger) AuthConfig { +func (c *AuthConfig) withLogger(getUpdatedLogger func(*slog.Logger) *slog.Logger) AuthConfig { return AuthConfig{ AuthClient: c.AuthClient, AccessPoint: c.AccessPoint, Clients: c.Clients, Clock: c.Clock, - Log: getUpdatedLogger(c.Log), + Logger: getUpdatedLogger(c.Logger), } } @@ -200,17 +200,17 @@ func NewAuth(config AuthConfig) (Auth, error) { // NewAuthForSession returns a copy of Auth with session-specific logging. func NewAuthForSession(auth Auth, sessionCtx *Session) Auth { - return auth.WithLogger(func(logger logrus.FieldLogger) logrus.FieldLogger { - return logger.WithFields(logrus.Fields{ - "session_id": sessionCtx.ID, - "database": sessionCtx.Database.GetName(), - }) + return auth.WithLogger(func(logger *slog.Logger) *slog.Logger { + return logger.With( + "session_id", sessionCtx.ID, + "database", sessionCtx.Database.GetName(), + ) }) } // WithLogger returns a new instance of Auth with updated logger. // The callback function receives the current logger and returns a new one. -func (a *dbAuth) WithLogger(getUpdatedLogger func(logrus.FieldLogger) logrus.FieldLogger) Auth { +func (a *dbAuth) WithLogger(getUpdatedLogger func(*slog.Logger) *slog.Logger) Auth { return &dbAuth{ cfg: a.cfg.withLogger(getUpdatedLogger), azureVirtualMachineCache: a.azureVirtualMachineCache, @@ -228,10 +228,10 @@ func (a *dbAuth) GetRDSAuthToken(ctx context.Context, database types.Database, d if err != nil { return "", trace.Wrap(err) } - a.cfg.Log. - WithField("database", database). - WithField("database_user", databaseUser). - Debug("Generating RDS auth token") + a.cfg.Logger.DebugContext(ctx, "Generating RDS auth token", + "database", database, + "database_user", databaseUser, + ) token, err := rdsutils.BuildAuthToken( database.GetURI(), meta.Region, @@ -295,11 +295,11 @@ Make sure that IAM role %q has a trust relationship with Teleport database agent } // Now make the API call to generate the temporary credentials. - a.cfg.Log. - WithField("database", database). - WithField("database_user", databaseUser). - WithField("database_name", databaseName). - Debug("Generating Redshift IAM role auth token") + a.cfg.Logger.DebugContext(ctx, "Generating Redshift IAM role auth token", + "database", database, + "database_user", databaseUser, + "database_name", databaseName, + ) resp, err := client.GetClusterCredentialsWithIAMWithContext(ctx, &redshift.GetClusterCredentialsWithIAMInput{ ClusterIdentifier: aws.String(meta.Redshift.ClusterID), DbName: aws.String(databaseName), @@ -330,11 +330,11 @@ func (a *dbAuth) getRedshiftDBUserAuthToken(ctx context.Context, database types. if err != nil { return "", "", trace.Wrap(err) } - a.cfg.Log. - WithField("database", database). - WithField("database_user", databaseUser). - WithField("database_name", databaseName). - Debug("Generating Redshift auth token") + a.cfg.Logger.DebugContext(ctx, "Generating Redshift auth token", + "database", database, + "database_user", databaseUser, + "database_name", databaseName, + ) resp, err := redshiftClient.GetClusterCredentialsWithContext(ctx, &redshift.GetClusterCredentialsInput{ ClusterIdentifier: aws.String(meta.Redshift.ClusterID), DbUser: aws.String(databaseUser), @@ -399,11 +399,11 @@ Make sure that IAM role %q has a trust relationship with Teleport database agent } // Now make the API call to generate the temporary credentials. - a.cfg.Log. - WithField("database", database). - WithField("database_user", databaseUser). - WithField("database_name", databaseName). - Debug("Generating Redshift Serverless auth token") + a.cfg.Logger.DebugContext(ctx, "Generating Redshift Serverless auth token", + "database", database, + "database_user", databaseUser, + "database_name", databaseName, + ) resp, err := client.GetCredentialsWithContext(ctx, &redshiftserverless.GetCredentialsInput{ WorkgroupName: aws.String(meta.RedshiftServerless.WorkgroupName), DbName: aws.String(databaseName), @@ -469,7 +469,7 @@ func (a *dbAuth) getCloudTokenSource(ctx context.Context, databaseUser string, s return &cloudTokenSource{ ctx: ctx, client: gcpIAM, - log: a.cfg.Log.WithField("database_user", databaseUser), + log: a.cfg.Logger.With("database_user", databaseUser), serviceAccount: serviceAccountName, scopes: scopes, }, nil @@ -480,7 +480,7 @@ func (a *dbAuth) getCloudTokenSource(ctx context.Context, databaseUser string, s type cloudTokenSource struct { ctx context.Context client *gcpcredentials.IamCredentialsClient - log logrus.FieldLogger + log *slog.Logger serviceAccount string scopes []string } @@ -489,7 +489,7 @@ type cloudTokenSource struct { // Token must be safe for concurrent use by multiple goroutines. // The returned Token must not be modified. func (l *cloudTokenSource) Token() (*oauth2.Token, error) { - l.log.Debug("Generating GCP auth token") + l.log.DebugContext(l.ctx, "Generating GCP auth token") resp, err := l.client.GenerateAccessToken(l.ctx, &gcpcredentialspb.GenerateAccessTokenRequest{ // From GenerateAccessToken docs: @@ -530,10 +530,10 @@ func (a *dbAuth) GetCloudSQLPassword(ctx context.Context, database types.Databas if err != nil { return "", trace.Wrap(err) } - a.cfg.Log. - WithField("database", database). - WithField("database_user", databaseUser). - Debug("Generating GCP user password") + a.cfg.Logger.DebugContext(ctx, "Generating GCP user password", + "database", database, + "database_user", databaseUser, + ) token, err := utils.CryptoRandomHex(defaults.TokenLenBytes) if err != nil { return "", trace.Wrap(err) @@ -586,7 +586,7 @@ SQL Admin" GCP IAM role, or "cloudsql.users.update" IAM permission. // GetAzureAccessToken generates Azure database access token. func (a *dbAuth) GetAzureAccessToken(ctx context.Context) (string, error) { - a.cfg.Log.Debug("Generating Azure access token") + a.cfg.Logger.DebugContext(ctx, "Generating Azure access token") cred, err := a.cfg.Clients.GetAzureCredential() if err != nil { return "", trace.Wrap(err) @@ -613,10 +613,10 @@ func (a *dbAuth) GetElastiCacheRedisToken(ctx context.Context, database types.Da if err != nil { return "", trace.Wrap(err) } - a.cfg.Log. - WithField("database", database). - WithField("database_user", databaseUser). - Debug("Generating ElastiCache Redis auth token") + a.cfg.Logger.DebugContext(ctx, "Generating ElastiCache Redis auth token", + "database", database, + "database_user", databaseUser, + ) tokenReq := &awsRedisIAMTokenRequest{ // For IAM-enabled ElastiCache users, the username and user id properties must be identical. // https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/auth-iam.html#auth-iam-limits @@ -641,10 +641,10 @@ func (a *dbAuth) GetMemoryDBToken(ctx context.Context, database types.Database, if err != nil { return "", trace.Wrap(err) } - a.cfg.Log. - WithField("database", database). - WithField("database_user", databaseUser). - Debug("Generating MemoryDB auth token") + a.cfg.Logger.DebugContext(ctx, "Generating MemoryDB auth token", + "database", database, + "database_user", databaseUser, + ) tokenReq := &awsRedisIAMTokenRequest{ userID: databaseUser, targetID: meta.MemoryDB.ClusterName, @@ -686,10 +686,10 @@ func (a *dbAuth) GetAzureCacheForRedisToken(ctx context.Context, database types. // the message has to be merged to a single line string. Thus logging // the original error as debug and returning a more user friendly // message. - a.cfg.Log. - WithField("database", database). - WithError(err). - Debug("Failed to get token for Azure Redis") + a.cfg.Logger.DebugContext(ctx, "Failed to get token for Azure Redis", + "error", err, + "database", database, + ) switch { case trace.IsAccessDenied(err): return "", trace.AccessDenied("Failed to get token for Azure Redis %q. Please make sure the database agent has the \"listKeys\" permission to the database.", database.GetName()) @@ -1005,9 +1005,7 @@ func (a *dbAuth) getClientCert(ctx context.Context, expiry time.Time, databaseUs } // TODO(r0mant): Cache database certificates to avoid expensive generate // operation on each connection. - a.cfg.Log. - WithField("database_user", databaseUser). - Debug("Generating client certificate") + a.cfg.Logger.DebugContext(ctx, "Generating client certificate", "database_user", databaseUser) resp, err := a.cfg.AuthClient.GenerateDatabaseCert(ctx, &proto.DatabaseCertRequest{ CSR: csr, @@ -1106,7 +1104,7 @@ func (a *dbAuth) buildAWSRoleARNFromDatabaseUser(ctx context.Context, database t if awsutils.IsPartialRoleARN(databaseUser) && awsAccountID == "" { switch { case dbAWS.AssumeRoleARN != "": - a.cfg.Log.Debug("Using AWS Account ID from assumed role") + a.cfg.Logger.DebugContext(ctx, "Using AWS Account ID from assumed role") assumeRoleARN, err := awsutils.ParseRoleARN(dbAWS.AssumeRoleARN) if err != nil { return "", trace.Wrap(err) @@ -1114,7 +1112,7 @@ func (a *dbAuth) buildAWSRoleARNFromDatabaseUser(ctx context.Context, database t awsAccountID = assumeRoleARN.AccountID default: - a.cfg.Log.Debug("Fetching AWS Account ID to build role ARN") + a.cfg.Logger.DebugContext(ctx, "Fetching AWS Account ID to build role ARN") stsClient, err := a.cfg.Clients.GetAWSSTSClient(ctx, dbAWS.Region, cloud.WithAmbientCredentials()) if err != nil { return "", trace.Wrap(err) diff --git a/lib/srv/db/dynamodb/test.go b/lib/srv/db/dynamodb/test.go index 462dc743782ab..8dc31ee1e7379 100644 --- a/lib/srv/db/dynamodb/test.go +++ b/lib/srv/db/dynamodb/test.go @@ -32,10 +32,7 @@ import ( "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/dynamodb" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" - "github.com/gravitational/teleport" - "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/srv/db/common" awsutils "github.com/gravitational/teleport/lib/utils/aws" ) @@ -75,7 +72,6 @@ type TestServerOption func(*TestServer) // TestServer is a DynamoDB test server that mocks AWS signature checking and API. type TestServer struct { cfg common.TestServerConfig - log logrus.FieldLogger port string server *httptest.Server @@ -90,10 +86,6 @@ func NewTestServer(config common.TestServerConfig, opts ...TestServerOption) (*T return nil, trace.Wrap(err) } - log := logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: defaults.ProtocolDynamoDB, - "name": config.Name, - }) tlsConfig, err := common.MakeTestServerTLSConfig(config) if err != nil { return nil, trace.Wrap(err) @@ -124,7 +116,6 @@ func NewTestServer(config common.TestServerConfig, opts ...TestServerOption) (*T server := &TestServer{ cfg: config, - log: log, port: port, server: &httptest.Server{ Listener: config.Listener, diff --git a/lib/srv/db/elasticsearch/test.go b/lib/srv/db/elasticsearch/test.go index b0d81f67d6779..6b46d2afd3d10 100644 --- a/lib/srv/db/elasticsearch/test.go +++ b/lib/srv/db/elasticsearch/test.go @@ -28,10 +28,7 @@ import ( "github.com/elastic/go-elasticsearch/v8" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" - "github.com/gravitational/teleport" - "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/srv/db/common" ) @@ -43,7 +40,6 @@ type TestServer struct { listener net.Listener port string tlsConfig *tls.Config - log logrus.FieldLogger } // NewTestServer returns a new instance of a test Elasticsearch server. @@ -71,10 +67,6 @@ func NewTestServer(config common.TestServerConfig, opts ...TestServerOption) (sv listener: config.Listener, port: port, tlsConfig: tlsConfig, - log: logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: defaults.ProtocolElasticsearch, - "name": config.Name, - }), } for _, opt := range opts { diff --git a/lib/srv/db/mongodb/test.go b/lib/srv/db/mongodb/test.go index e09b77d1359d5..3e04fd810edb9 100644 --- a/lib/srv/db/mongodb/test.go +++ b/lib/srv/db/mongodb/test.go @@ -23,6 +23,7 @@ import ( "crypto/rand" "crypto/tls" "fmt" + "log/slog" "net" "strings" "sync" @@ -30,7 +31,6 @@ import ( "time" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" @@ -42,6 +42,7 @@ import ( "github.com/gravitational/teleport/lib/srv/db/common" "github.com/gravitational/teleport/lib/srv/db/mongodb/protocol" "github.com/gravitational/teleport/lib/utils" + logutils "github.com/gravitational/teleport/lib/utils/log" ) // MakeTestClient returns MongoDB client connection according to the provided @@ -82,7 +83,7 @@ type TestServer struct { cfg common.TestServerConfig listener net.Listener port string - log logrus.FieldLogger + logger *slog.Logger serverVersion string wireVersion int @@ -131,16 +132,16 @@ func NewTestServer(config common.TestServerConfig, opts ...TestServerOption) (sv if err != nil { return nil, trace.Wrap(err) } - log := logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: defaults.ProtocolMongoDB, - "name": config.Name, - }) + log := utils.NewSlogLoggerForTests().With( + teleport.ComponentKey, defaults.ProtocolMongoDB, + "name", config.Name, + ) server := &TestServer{ cfg: config, // MongoDB uses regular TLS handshake so standard TLS listener will work. listener: tls.NewListener(config.Listener, tlsConfig), port: port, - log: log, + logger: log, serverVersion: "7.0.0", usersTracker: usersTracker{ userEventsCh: make(chan UserEvent, 100), @@ -155,27 +156,27 @@ func NewTestServer(config common.TestServerConfig, opts ...TestServerOption) (sv // Serve starts serving client connections. func (s *TestServer) Serve() error { - s.log.Debugf("Starting test MongoDB server on %v.", s.listener.Addr()) - defer s.log.Debug("Test MongoDB server stopped.") + ctx := context.Background() + s.logger.DebugContext(ctx, "Starting test MongoDB server", "listen_addr", s.listener.Addr()) + defer s.logger.DebugContext(ctx, "Test MongoDB server stopped") for { conn, err := s.listener.Accept() if err != nil { if utils.IsOKNetworkError(err) { return nil } - s.log.WithError(err).Error("Failed to accept connection.") + s.logger.ErrorContext(ctx, "Failed to accept connection", "error", err) continue } - s.log.Debug("Accepted connection.") + s.logger.DebugContext(ctx, "Accepted connection") go func() { - defer s.log.Debug("Connection done.") + defer s.logger.DebugContext(ctx, "Connection done") defer conn.Close() atomic.AddInt32(&s.activeConnection, 1) defer atomic.AddInt32(&s.activeConnection, -1) if err := s.handleConnection(conn); err != nil { if !utils.IsOKNetworkError(err) { - s.log.Errorf("Failed to handle connection: %v.", - trace.DebugReport(err)) + s.logger.ErrorContext(ctx, "Failed to handle connection", "error", err) } } }() @@ -263,7 +264,7 @@ func (s *TestServer) handleAuth(message protocol.Message) (protocol.Message, err if err != nil { return nil, trace.Wrap(err) } - s.log.Debugf("Authenticate: %s.", message) + s.logger.DebugContext(context.Background(), "Authenticate", "message", logutils.StringerAttr(message)) if command != commandAuth { return nil, trace.BadParameter("expected authenticate command, got: %s", message) } diff --git a/lib/srv/db/mysql/gcp_test.go b/lib/srv/db/mysql/gcp_test.go index fffdb7a34c750..d1fdf9b7899d8 100644 --- a/lib/srv/db/mysql/gcp_test.go +++ b/lib/srv/db/mysql/gcp_test.go @@ -25,7 +25,6 @@ import ( "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" sqladmin "google.golang.org/api/sqladmin/v1beta4" @@ -56,7 +55,7 @@ func (a fakeAuth) GetCloudSQLPassword(ctx context.Context, database types.Databa return "one-time-password", nil } -func (a fakeAuth) WithLogger(getUpdatedLogger func(logrus.FieldLogger) logrus.FieldLogger) common.Auth { +func (a fakeAuth) WithLogger(getUpdatedLogger func(*slog.Logger) *slog.Logger) common.Auth { if a.Auth != nil { return a.Auth.WithLogger(getUpdatedLogger) } diff --git a/lib/srv/db/mysql/test.go b/lib/srv/db/mysql/test.go index de65d8c72d9ea..07f7eded81e9e 100644 --- a/lib/srv/db/mysql/test.go +++ b/lib/srv/db/mysql/test.go @@ -19,8 +19,10 @@ package mysql import ( + "context" "crypto/tls" "encoding/json" + "log/slog" "net" "strings" "sync" @@ -30,7 +32,6 @@ import ( "github.com/go-mysql-org/go-mysql/mysql" "github.com/go-mysql-org/go-mysql/server" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/lib/defaults" @@ -107,7 +108,7 @@ type TestServer struct { listener net.Listener port string tlsConfig *tls.Config - log logrus.FieldLogger + log *slog.Logger handler *testHandler serverVersion string @@ -150,10 +151,10 @@ func NewTestServer(config common.TestServerConfig, opts ...TestServerOption) (sv listener = tls.NewListener(listener, tlsConfig) } - log := logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: defaults.ProtocolMySQL, - "name": config.Name, - }) + log := utils.NewSlogLoggerForTests().With( + teleport.ComponentKey, defaults.ProtocolMySQL, + "name", config.Name, + ) server := &TestServer{ cfg: config, listener: listener, @@ -178,25 +179,25 @@ func NewTestServer(config common.TestServerConfig, opts ...TestServerOption) (sv // Serve starts serving client connections. func (s *TestServer) Serve() error { - s.log.Debugf("Starting test MySQL server on %v.", s.listener.Addr()) - defer s.log.Debug("Test MySQL server stopped.") + ctx := context.Background() + s.log.DebugContext(ctx, "Starting test MySQL server", "listen_addr", s.listener.Addr()) + defer s.log.DebugContext(ctx, "Test MySQL server stopped") for { conn, err := s.listener.Accept() if err != nil { if utils.IsOKNetworkError(err) { return nil } - s.log.WithError(err).Error("Failed to accept connection.") + s.log.ErrorContext(ctx, "Failed to accept connection", "error", err) continue } - s.log.Debug("Accepted connection.") + s.log.DebugContext(ctx, "Accepted connection") go func() { - defer s.log.Debug("Connection done.") + defer s.log.DebugContext(ctx, "Connection done") defer conn.Close() err = s.handleConnection(conn) if err != nil { - s.log.Errorf("Failed to handle connection: %v.", - trace.DebugReport(err)) + s.log.ErrorContext(ctx, "Failed to handle connection", "error", err) } }() } @@ -294,7 +295,7 @@ func (s *TestServer) UserEventsCh() <-chan UserEvent { type testHandler struct { server.EmptyHandler - log logrus.FieldLogger + log *slog.Logger // queryCount keeps track of the number of queries the server has received. queryCount uint32 @@ -305,7 +306,7 @@ type testHandler struct { } func (h *testHandler) HandleQuery(query string) (*mysql.Result, error) { - h.log.Debugf("Received query %q.", query) + h.log.DebugContext(context.Background(), "Received query", "query", query) atomic.AddUint32(&h.queryCount, 1) // When getting a "show tables" query, construct the response in a way @@ -335,7 +336,7 @@ func (h *testHandler) HandleStmtPrepare(prepare string) (int, int, interface{}, return params, 0, nil, nil } func (h *testHandler) HandleStmtExecute(_ interface{}, query string, args []interface{}) (*mysql.Result, error) { - h.log.Debugf("Received execute %q with args %+v.", query, args) + h.log.DebugContext(context.Background(), "Received execute statement with args", "query", query, "args", args) if strings.HasPrefix(query, "CALL ") { return h.handleCallProcedure(query, args) } diff --git a/lib/srv/db/opensearch/test.go b/lib/srv/db/opensearch/test.go index bf6deeceaef8e..027b2528fa13d 100644 --- a/lib/srv/db/opensearch/test.go +++ b/lib/srv/db/opensearch/test.go @@ -21,6 +21,7 @@ package opensearch import ( "context" "crypto/tls" + "log/slog" "net" "net/http" "net/http/httptest" @@ -28,11 +29,12 @@ import ( "github.com/gravitational/trace" "github.com/opensearch-project/opensearch-go/v2" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/srv/db/common" + "github.com/gravitational/teleport/lib/utils" + logutils "github.com/gravitational/teleport/lib/utils/log" ) // TestServerOption allows setting test server options. @@ -43,7 +45,7 @@ type TestServer struct { listener net.Listener port string tlsConfig *tls.Config - log logrus.FieldLogger + log *slog.Logger } // NewTestServer returns a new instance of a test OpenSearch server. @@ -70,10 +72,10 @@ func NewTestServer(config common.TestServerConfig, opts ...TestServerOption) (sv listener: config.Listener, port: port, tlsConfig: tlsConfig, - log: logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: defaults.ProtocolOpenSearch, - "name": config.Name, - }), + log: utils.NewSlogLoggerForTests().With( + teleport.ComponentKey, defaults.ProtocolOpenSearch, + "name", config.Name, + ), } for _, opt := range opts { @@ -94,7 +96,7 @@ func (s *TestServer) Serve() error { }) mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - s.log.Debugf("URL", r.URL) + s.log.DebugContext(r.Context(), "Handling request", "url", logutils.StringerAttr(r.URL)) w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Length", strconv.Itoa(len(testQueryResponse))) w.Write([]byte(testQueryResponse)) diff --git a/lib/srv/db/postgres/engine.go b/lib/srv/db/postgres/engine.go index 2b5c0692a17e3..5ab9680a1fed6 100644 --- a/lib/srv/db/postgres/engine.go +++ b/lib/srv/db/postgres/engine.go @@ -26,12 +26,12 @@ import ( "errors" "fmt" "io" + "log/slog" "net" "github.com/gravitational/trace" "github.com/jackc/pgconn" "github.com/jackc/pgproto3/v2" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/types/events" @@ -584,8 +584,10 @@ func formatParameters(parameters [][]byte, formatCodes []int16) (formatted []str // https://www.postgresql.org/docs/current/protocol-message-formats.html#PROTOCOL-MESSAGE-FORMATS-BIND // https://www.postgresql.org/docs/current/protocol-message-formats.html#PROTOCOL-MESSAGE-FORMATS-FUNCTIONCALL if len(formatCodes) > 1 && len(formatCodes) != len(parameters) { - logrus.Warnf("Postgres parameter format codes and parameters don't match: %#v %#v.", - parameters, formatCodes) + slog.WarnContext(context.Background(), "Postgres parameter format codes and parameters don't match", + "parameters", parameters, + "format_codes", formatCodes, + ) return formatted } for i, p := range parameters { @@ -614,8 +616,7 @@ func formatParameters(parameters [][]byte, formatCodes []int16) (formatted []str formatted = append(formatted, base64.StdEncoding.EncodeToString(p)) default: // Should never happen but... - logrus.Warnf("Unknown Postgres parameter format code: %#v.", - formatCode) + slog.WarnContext(context.Background(), "Unknown Postgres parameter format code", "format_code", formatCode) formatted = append(formatted, "") } } diff --git a/lib/srv/db/redis/engine.go b/lib/srv/db/redis/engine.go index 9b9f44f3ba6af..13164b1490e7e 100644 --- a/lib/srv/db/redis/engine.go +++ b/lib/srv/db/redis/engine.go @@ -22,6 +22,8 @@ import ( "bytes" "context" "errors" + "fmt" + "log/slog" "net" "slices" "strings" @@ -32,7 +34,6 @@ import ( "github.com/aws/aws-sdk-go/service/memorydb" "github.com/gravitational/trace" "github.com/redis/go-redis/v9" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" @@ -47,6 +48,7 @@ import ( "github.com/gravitational/teleport/lib/srv/db/redis/connection" "github.com/gravitational/teleport/lib/srv/db/redis/protocol" "github.com/gravitational/teleport/lib/utils" + logutils "github.com/gravitational/teleport/lib/utils/log" ) // NewEngine create new Redis engine. @@ -584,15 +586,20 @@ func isTeleportErr(err error) bool { // driverLogger implements go-redis driver's internal logger using logrus and // logs everything at TRACE level. type driverLogger struct { - *logrus.Entry + *slog.Logger } -func (l *driverLogger) Printf(_ context.Context, format string, v ...any) { - l.Entry.Tracef(format, v...) +func (l *driverLogger) Printf(ctx context.Context, format string, v ...any) { + if !l.Logger.Enabled(ctx, logutils.TraceLevel) { + return + } + + //nolint:sloglint // Allow non-static messages + l.Logger.Log(ctx, logutils.TraceLevel, fmt.Sprintf(format, v...)) } func init() { redis.SetLogger(&driverLogger{ - Entry: logrus.WithField(teleport.ComponentKey, "go-redis"), + Logger: slog.With(teleport.ComponentKey, "go-redis"), }) } diff --git a/lib/srv/db/redis/test.go b/lib/srv/db/redis/test.go index 3959c594c7795..7a260f4ae3cc0 100644 --- a/lib/srv/db/redis/test.go +++ b/lib/srv/db/redis/test.go @@ -26,11 +26,8 @@ import ( "github.com/alicebob/miniredis/v2" "github.com/gravitational/trace" "github.com/redis/go-redis/v9" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" - "github.com/gravitational/teleport" - "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/srv/db/common" ) @@ -103,7 +100,6 @@ func MakeTestClient(ctx context.Context, config common.TestClientConfig, opts .. type TestServer struct { cfg common.TestServerConfig server *miniredis.Miniredis - log logrus.FieldLogger // password is the default user password. // If set, AUTH must be sent first to get access to the server. @@ -126,13 +122,9 @@ func NewTestServer(t testing.TB, config common.TestServerConfig, opts ...TestSer if err != nil { return nil, trace.Wrap(err) } - log := logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: defaults.ProtocolRedis, - "name": config.Name, - }) + server := &TestServer{ cfg: config, - log: log, } for _, opt := range opts { diff --git a/lib/srv/db/server.go b/lib/srv/db/server.go index 10f54db7343f8..b91245d6898ef 100644 --- a/lib/srv/db/server.go +++ b/lib/srv/db/server.go @@ -717,21 +717,21 @@ func (s *Server) getServerInfoFunc(database types.Database) func(context.Context if s.cfg.GetServerInfoFn != nil { return s.cfg.GetServerInfoFn(database) } - return func(context.Context) (*types.DatabaseServerV3, error) { - return s.getServerInfo(database) + return func(ctx context.Context) (*types.DatabaseServerV3, error) { + return s.getServerInfo(ctx, database) } } // getServerInfo returns up-to-date database resource e.g. with updated dynamic // labels. -func (s *Server) getServerInfo(database types.Database) (*types.DatabaseServerV3, error) { +func (s *Server) getServerInfo(ctx context.Context, database types.Database) (*types.DatabaseServerV3, error) { // Make sure to return a new object, because it gets cached by // heartbeat and will always compare as equal otherwise. s.mu.RLock() copy := s.copyDatabaseWithUpdatedLabelsLocked(database) s.mu.RUnlock() if s.cfg.CloudIAM != nil { - s.cfg.CloudIAM.UpdateIAMStatus(copy) + s.cfg.CloudIAM.UpdateIAMStatus(ctx, copy) } expires := s.cfg.Clock.Now().UTC().Add(apidefaults.ServerAnnounceTTL) diff --git a/lib/srv/db/snowflake/test.go b/lib/srv/db/snowflake/test.go index d13d0998d121b..4b667049e4ae8 100644 --- a/lib/srv/db/snowflake/test.go +++ b/lib/srv/db/snowflake/test.go @@ -33,11 +33,8 @@ import ( "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" - "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" - "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/jwt" "github.com/gravitational/teleport/lib/srv/db/common" ) @@ -58,7 +55,6 @@ type TestServer struct { listener net.Listener port string tlsConfig *tls.Config - log logrus.FieldLogger authorizationToken string forceTokenRefresh bool } @@ -82,14 +78,10 @@ func NewTestServer(config common.TestServerConfig, opts ...TestServerOption) (*T } testServer := &TestServer{ - cfg: config, - listener: config.Listener, - port: port, - tlsConfig: tlsConfig, - log: logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: defaults.ProtocolSnowflake, - "name": config.Name, - }), + cfg: config, + listener: config.Listener, + port: port, + tlsConfig: tlsConfig, authorizationToken: "test-token-123", } diff --git a/lib/srv/db/spanner/test.go b/lib/srv/db/spanner/test.go index 5dcef45959735..5ff4a77900e18 100644 --- a/lib/srv/db/spanner/test.go +++ b/lib/srv/db/spanner/test.go @@ -30,7 +30,6 @@ import ( "cloud.google.com/go/spanner/apiv1/spannerpb" "github.com/google/uuid" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "google.golang.org/api/option" "google.golang.org/grpc" "google.golang.org/grpc/connectivity" @@ -39,10 +38,8 @@ import ( "google.golang.org/grpc/metadata" "google.golang.org/protobuf/types/known/structpb" - "github.com/gravitational/teleport" apidefaults "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/types" - "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/srv/db/common" "github.com/gravitational/teleport/lib/tlsca" @@ -162,7 +159,6 @@ type TestServer struct { srv *grpc.Server listener net.Listener port string - log logrus.FieldLogger spannerpb.UnimplementedSpannerServer } @@ -183,11 +179,6 @@ func NewTestServer(config common.TestServerConfig) (tsrv *TestServer, err error) return nil, trace.Wrap(err) } - logger := logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: defaults.ProtocolSpanner, - "name": config.Name, - }) - checker := credentialChecker{expectToken: "Bearer " + config.AuthToken} testServer := &TestServer{ srv: grpc.NewServer( @@ -197,7 +188,6 @@ func NewTestServer(config common.TestServerConfig) (tsrv *TestServer, err error) ), listener: config.Listener, port: port, - log: logger, } spannerpb.RegisterSpannerServer(testServer.srv, testServer) diff --git a/lib/srv/db/sqlserver/kinit/kinit.go b/lib/srv/db/sqlserver/kinit/kinit.go index fc9ec2328d5ad..77d213aa99a6a 100644 --- a/lib/srv/db/sqlserver/kinit/kinit.go +++ b/lib/srv/db/sqlserver/kinit/kinit.go @@ -24,6 +24,7 @@ import ( "context" "crypto/x509" "fmt" + "log/slog" "os" "os/exec" "path/filepath" @@ -33,7 +34,6 @@ import ( "github.com/gravitational/trace" "github.com/jcmturner/gokrb5/v8/config" "github.com/jcmturner/gokrb5/v8/credentials" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/auth/windows" @@ -126,7 +126,7 @@ func NewCommandLineInitializer(config CommandConfig) *CommandLineInitializer { certGetter: config.CertGetter, ldapCertificate: config.LDAPCA, ldapCertificatePEM: config.LDAPCAPEM, - log: logrus.StandardLogger(), + logger: slog.Default(), } if cmd.command == nil { cmd.command = &execCmd{} @@ -173,7 +173,7 @@ type CommandLineInitializer struct { ldapCertificate *x509.Certificate ldapCertificatePEM string - log logrus.FieldLogger + logger *slog.Logger } // CertGetter is an interface for getting a new cert/key pair along with a CA cert @@ -246,7 +246,7 @@ func (k *CommandLineInitializer) UseOrCreateCredentials(ctx context.Context) (*c defer func() { err = os.RemoveAll(tmp) if err != nil { - k.log.Errorf("failed removing temporary kinit directory: %s", err) + k.logger.ErrorContext(ctx, "failed removing temporary kinit directory", "error", err) } }() @@ -308,7 +308,7 @@ func (k *CommandLineInitializer) UseOrCreateCredentials(ctx context.Context) (*c cmd.Env = append(cmd.Env, []string{fmt.Sprintf("%s=%s", krb5ConfigEnv, krbConfPath)}...) kinitOutput, err := cmd.CombinedOutput() if err != nil { - k.log.Errorf("Failed to authenticate with KDC: %s", kinitOutput) + k.logger.ErrorContext(ctx, "Failed to authenticate with KDC", "cmd_output", string(kinitOutput)) return nil, nil, trace.AccessDenied("authentication failed") } ccache, err := credentials.LoadCCache(cachePath) diff --git a/lib/srv/db/sqlserver/test.go b/lib/srv/db/sqlserver/test.go index 96d85b1913efc..a69094bd2a2ed 100644 --- a/lib/srv/db/sqlserver/test.go +++ b/lib/srv/db/sqlserver/test.go @@ -21,13 +21,13 @@ package sqlserver import ( "context" "io" + "log/slog" "net" "strconv" "github.com/gravitational/trace" mssql "github.com/microsoft/go-mssqldb" "github.com/microsoft/go-mssqldb/msdsn" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/lib/defaults" @@ -118,7 +118,7 @@ type TestServer struct { cfg common.TestServerConfig listener net.Listener port string - log logrus.FieldLogger + log *slog.Logger } // NewTestServer returns a new instance of a test MSServer. @@ -133,10 +133,10 @@ func NewTestServer(config common.TestServerConfig) (svr *TestServer, err error) if err != nil { return nil, trace.Wrap(err) } - log := logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: defaults.ProtocolSQLServer, - "name": config.Name, - }) + log := utils.NewSlogLoggerForTests().With( + teleport.ComponentKey, defaults.ProtocolSQLServer, + "name", config.Name, + ) server := &TestServer{ cfg: config, listener: config.Listener, @@ -153,25 +153,25 @@ func (s *TestServer) Port() string { // Serve starts serving client connections. func (s *TestServer) Serve() error { - s.log.Debugf("Starting test MSServer server on %v.", s.listener.Addr()) - defer s.log.Debug("Test MSServer server stopped.") + ctx := context.Background() + s.log.DebugContext(ctx, "Starting test MSServer server", "listen_addr", s.listener.Addr()) + defer s.log.DebugContext(ctx, "Test MSServer server stopped") for { conn, err := s.listener.Accept() if err != nil { if utils.IsOKNetworkError(err) { return nil } - s.log.WithError(err).Error("Failed to accept connection.") + s.log.ErrorContext(ctx, "Failed to accept connection", "error", err) continue } - s.log.Debug("Accepted connection.") + s.log.DebugContext(ctx, "Accepted connection") go func() { - defer s.log.Debug("Connection done.") + defer s.log.DebugContext(ctx, "Connection done") defer conn.Close() err = s.handleConnection(conn) if err != nil { - s.log.Errorf("Failed to handle connection: %v.", - trace.DebugReport(err)) + s.log.ErrorContext(ctx, "Failed to handle connection", "error", err) } }() } diff --git a/lib/srv/db/watcher.go b/lib/srv/db/watcher.go index 22bb41c94956e..e2f1b9cf442a9 100644 --- a/lib/srv/db/watcher.go +++ b/lib/srv/db/watcher.go @@ -22,7 +22,6 @@ import ( "context" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" @@ -127,7 +126,6 @@ func (s *Server) startCloudWatcher(ctx context.Context) error { watcher, err := discovery.NewWatcher(ctx, discovery.WatcherConfig{ FetchersFn: discovery.StaticFetchers(allFetchers), - Log: logrus.WithField(teleport.ComponentKey, "watcher:cloud"), Origin: types.OriginCloud, }) if err != nil {