diff --git a/cmd/fleet/cron.go b/cmd/fleet/cron.go index 7c0ff88b94..1554f99cb2 100644 --- a/cmd/fleet/cron.go +++ b/cmd/fleet/cron.go @@ -1044,7 +1044,7 @@ func newCleanupsAndAggregationSchedule( schedule.WithJob( "renew_scep_certificates", func(ctx context.Context) error { - return service.RenewSCEPCertificates(ctx, logger, ds, config, commander) + return service.RenewSCEPCertificates(ctx, logger.SlogLogger(), ds, config, commander) }, ), schedule.WithJob("renew_host_mdm_managed_certificates", func(ctx context.Context) error { @@ -1419,10 +1419,10 @@ func newAppleMDMProfileManagerSchedule( ctx, name, instanceID, defaultInterval, ds, ds, schedule.WithLogger(logger), schedule.WithJob("manage_apple_profiles", func(ctx context.Context) error { - return service.ReconcileAppleProfiles(ctx, ds, commander, logger) + return service.ReconcileAppleProfiles(ctx, ds, commander, logger.SlogLogger()) }), schedule.WithJob("manage_apple_declarations", func(ctx context.Context) error { - return service.ReconcileAppleDeclarations(ctx, ds, commander, logger) + return service.ReconcileAppleDeclarations(ctx, ds, commander, logger.SlogLogger()) }), ) @@ -1495,7 +1495,7 @@ func newMDMAppleServiceDiscoverySchedule( ctx, name, instanceID, interval, ds, ds, schedule.WithLogger(logger), schedule.WithJob("mdm_apple_account_driven_enrollment_profile", func(ctx context.Context) error { - return service.EnsureMDMAppleServiceDiscovery(ctx, ds, depStorage, logger, urlPrefix) + return service.EnsureMDMAppleServiceDiscovery(ctx, ds, depStorage, logger.SlogLogger(), urlPrefix) }), ) return s, nil @@ -1534,7 +1534,7 @@ func newMDMAPNsPusher( return nil } - return service.SendPushesToPendingDevices(ctx, ds, commander, logger) + return service.SendPushesToPendingDevices(ctx, ds, commander, logger.SlogLogger()) }), ) @@ -1722,7 +1722,7 @@ func cronUninstallSoftwareMigration( schedule.WithLogger(logger), schedule.WithRunOnce(true), schedule.WithJob(name, func(ctx context.Context) error { - return eeservice.UninstallSoftwareMigration(ctx, ds, softwareInstallStore, logger) + return eeservice.UninstallSoftwareMigration(ctx, ds, softwareInstallStore, logger.SlogLogger()) }), ) return s, nil @@ -1750,7 +1750,7 @@ func cronUpgradeCodeSoftwareMigration( // ensures it runs a few seconds after Fleet is started schedule.WithDefaultPrevRunCreatedAt(time.Now().Add(priorJobDiff)), schedule.WithJob(name, func(ctx context.Context) error { - return eeservice.UpgradeCodeMigration(ctx, ds, softwareInstallStore, logger) + return eeservice.UpgradeCodeMigration(ctx, ds, softwareInstallStore, logger.SlogLogger()) }), ) return s, nil diff --git a/cmd/fleet/serve.go b/cmd/fleet/serve.go index f430a447ff..4e2261e81a 100644 --- a/cmd/fleet/serve.go +++ b/cmd/fleet/serve.go @@ -604,7 +604,7 @@ the way that the Fleet server works. } var mdmPushService push.Pusher - nanoMDMLogger := service.NewNanoMDMLogger(logger.With("component", "apple-mdm-push")) + nanoMDMLogger := service.NewNanoMDMLogger(logger.With("component", "apple-mdm-push").SlogLogger()) pushProviderFactory := buford.NewPushProviderFactory(buford.WithNewClient(func(cert *tls.Certificate) (*http.Client, error) { return fleethttp.NewClient(fleethttp.WithTLSClientConfig(&tls.Config{ Certificates: []tls.Certificate{*cert}, @@ -871,8 +871,8 @@ the way that the Fleet server works. } eh := errorstore.NewHandler(ctx, redisPool, logger.SlogLogger(), config.Logging.ErrorRetentionPeriod) - scepConfigMgr := eeservice.NewSCEPConfigService(logger, nil) - digiCertService := digicert.NewService(digicert.WithLogger(logger)) + scepConfigMgr := eeservice.NewSCEPConfigService(logger.SlogLogger(), nil) + digiCertService := digicert.NewService(digicert.WithLogger(logger.SlogLogger())) ctx = ctxerr.NewContext(ctx, eh) activitiesModule := activities.NewActivityModule() @@ -896,7 +896,7 @@ the way that the Fleet server works. ds, task, resultStore, - logger, + logger.SlogLogger(), &service.OsqueryLogger{ Status: osquerydStatusLogger, Result: osquerydResultLogger, @@ -930,7 +930,7 @@ the way that the Fleet server works. var softwareTitleIconStore fleet.SoftwareTitleIconStore var distributedLock fleet.Lock if license.IsPremium() { - hydrantService := est.NewService(est.WithLogger(logger)) + hydrantService := est.NewService(est.WithLogger(logger.SlogLogger())) profileMatcher := apple_mdm.NewProfileMatcher(redisPool) if config.S3.SoftwareInstallersBucket != "" { if config.S3.BucketsAndPrefixesMatch() { @@ -1009,7 +1009,7 @@ the way that the Fleet server works. svc, err = eeservice.NewService( svc, ds, - logger, + logger.SlogLogger(), config, mailService, clock.C, @@ -1333,7 +1333,7 @@ the way that the Fleet server works. level.Info(logger).Log("msg", fmt.Sprintf("started cron schedules: %s", strings.Join(cronSchedules.ScheduleNames(), ", "))) // StartCollectors starts a goroutine per collector, using ctx to cancel. - task.StartCollectors(ctx, logger.With("cron", "async_task")) + task.StartCollectors(ctx, logger.With("cron", "async_task").SlogLogger()) // Flush seen hosts every second hostsAsyncCfg := config.Osquery.AsyncConfigForTask(configpkg.AsyncTaskHostLastSeen) @@ -1375,7 +1375,7 @@ the way that the Fleet server works. var httpSigVerifier func(http.Handler) http.Handler if license.IsPremium() { - httpSigVerifier, err = httpsig.Middleware(ds, config.Auth.RequireHTTPMessageSignature, logger.With("component", "http-sig-verifier")) + httpSigVerifier, err = httpsig.Middleware(ds, config.Auth.RequireHTTPMessageSignature, logger.With("component", "http-sig-verifier").SlogLogger()) if err != nil { initFatal(err, "initializing HTTP signature verifier") } @@ -1385,10 +1385,10 @@ the way that the Fleet server works. { frontendHandler = service.PrometheusMetricsHandler( "get_frontend", - service.ServeFrontend(config.Server.URLPrefix, config.Server.SandboxEnabled, httpLogger), + service.ServeFrontend(config.Server.URLPrefix, config.Server.SandboxEnabled, httpLogger.SlogLogger()), ) - frontendHandler = service.WithMDMEnrollmentMiddleware(svc, httpLogger, frontendHandler) + frontendHandler = service.WithMDMEnrollmentMiddleware(svc, httpLogger.SlogLogger(), frontendHandler) var extra []service.ExtraHandlerOption if config.MDM.SSORateLimitPerMinute > 0 { @@ -1396,7 +1396,7 @@ the way that the Fleet server works. } extra = append(extra, service.WithHTTPSigVerifier(httpSigVerifier)) - apiHandler = service.MakeHandler(svc, config, httpLogger, limiterStore, redisPool, carveStore, + apiHandler = service.MakeHandler(svc, config, httpLogger.SlogLogger(), limiterStore, redisPool, carveStore, []endpointer.HandlerRoutesFunc{android_service.GetRoutes(svc, androidSvc), activityRoutes}, extra...) setupRequired, err := svc.SetupRequired(baseCtx) @@ -1407,17 +1407,17 @@ the way that the Fleet server works. // By performing the same check inside main, we can make server startups // more efficient after the first startup. if setupRequired { - apiHandler = service.WithSetup(svc, logger, apiHandler) - frontendHandler = service.RedirectLoginToSetup(svc, logger, frontendHandler, config.Server.URLPrefix) + apiHandler = service.WithSetup(svc, logger.SlogLogger(), apiHandler) + frontendHandler = service.RedirectLoginToSetup(svc, logger.SlogLogger(), frontendHandler, config.Server.URLPrefix) } else { - frontendHandler = service.RedirectSetupToLogin(svc, logger, frontendHandler, config.Server.URLPrefix) + frontendHandler = service.RedirectSetupToLogin(svc, logger.SlogLogger(), frontendHandler, config.Server.URLPrefix) } endUserEnrollOTAHandler = service.ServeEndUserEnrollOTA( svc, config.Server.URLPrefix, ds, - logger, + logger.SlogLogger(), ) } @@ -1441,7 +1441,7 @@ the way that the Fleet server works. } // Instantiate a gRPC service to handle launcher requests. - launcher := launcher.New(svc, logger, grpc.NewServer( + launcher := launcher.New(svc, logger.SlogLogger(), grpc.NewServer( grpc.ChainUnaryInterceptor( grpc_recovery.UnaryServerInterceptor(), ), @@ -1451,26 +1451,26 @@ the way that the Fleet server works. ), healthCheckers) rootMux := http.NewServeMux() - rootMux.Handle("/healthz", service.PrometheusMetricsHandler("healthz", otelmw.WrapHandler(health.Handler(httpLogger, healthCheckers), "/healthz", config))) + rootMux.Handle("/healthz", service.PrometheusMetricsHandler("healthz", otelmw.WrapHandler(health.Handler(httpLogger.SlogLogger(), healthCheckers), "/healthz", config))) rootMux.Handle("/version", service.PrometheusMetricsHandler("version", otelmw.WrapHandler(version.Handler(), "/version", config))) rootMux.Handle("/assets/", service.PrometheusMetricsHandler("static_assets", otelmw.WrapHandlerDynamic(service.ServeStaticAssets("/assets/"), config))) if len(config.Server.PrivateKey) > 0 { commander := apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPushService) - ddmService := service.NewMDMAppleDDMService(ds, logger) + ddmService := service.NewMDMAppleDDMService(ds, logger.SlogLogger()) vppInstaller := svc.(fleet.AppleMDMVPPInstaller) mdmCheckinAndCommandService := service.NewMDMAppleCheckinAndCommandService( ds, commander, vppInstaller, license.IsPremium(), - logger, + logger.SlogLogger(), redis_key_value.New(redisPool), svc.NewActivity, ) - mdmCheckinAndCommandService.RegisterResultsHandler("InstalledApplicationList", service.NewInstalledApplicationListResultsHandler(ds, commander, logger, config.Server.VPPVerifyTimeout, config.Server.VPPVerifyRequestDelay, svc.NewActivity)) - mdmCheckinAndCommandService.RegisterResultsHandler(fleet.DeviceLocationCmdName, service.NewDeviceLocationResultsHandler(ds, commander, logger)) + mdmCheckinAndCommandService.RegisterResultsHandler("InstalledApplicationList", service.NewInstalledApplicationListResultsHandler(ds, commander, logger.SlogLogger(), config.Server.VPPVerifyTimeout, config.Server.VPPVerifyRequestDelay, svc.NewActivity)) + mdmCheckinAndCommandService.RegisterResultsHandler(fleet.DeviceLocationCmdName, service.NewDeviceLocationResultsHandler(ds, commander, logger.SlogLogger())) hasSCEPChallenge, err := checkMDMAssets([]fleet.MDMAssetName{fleet.MDMAssetSCEPChallenge}) if err != nil { @@ -1503,7 +1503,7 @@ the way that the Fleet server works. config.MDM, mdmStorage, scepStorage, - logger, + logger.SlogLogger(), mdmCheckinAndCommandService, ddmService, commander, @@ -1516,7 +1516,7 @@ the way that the Fleet server works. if license.IsPremium() { // SCEP proxy (for NDES, etc.) - if err = service.RegisterSCEPProxy(rootMux, ds, logger, nil, &config); err != nil { + if err = service.RegisterSCEPProxy(rootMux, ds, logger.SlogLogger(), nil, &config); err != nil { initFatal(err, "setup SCEP proxy") } if err = scim.RegisterSCIM(rootMux, ds, svc, logger.SlogLogger(), &config); err != nil { @@ -1528,7 +1528,7 @@ the way that the Fleet server works. if err != nil { initFatal(err, "setup host identity SCEP depot") } - if err = hostidentity.RegisterSCEP(rootMux, hostIdentitySCEPDepot, ds, logger, &config); err != nil { + if err = hostidentity.RegisterSCEP(rootMux, hostIdentitySCEPDepot, ds, logger.SlogLogger(), &config); err != nil { initFatal(err, "setup host identity SCEP") } @@ -1537,12 +1537,12 @@ the way that the Fleet server works. if err != nil { initFatal(err, "setup conditional access SCEP depot") } - if err = condaccess.RegisterSCEP(ctx, rootMux, condAccessSCEPDepot, ds, logger, &config); err != nil { + if err = condaccess.RegisterSCEP(ctx, rootMux, condAccessSCEPDepot, ds, logger.SlogLogger(), &config); err != nil { initFatal(err, "setup conditional access SCEP") } // Conditional Access IdP (Okta) - if err = condaccess.RegisterIdP(rootMux, ds, logger, &config); err != nil { + if err = condaccess.RegisterIdP(rootMux, ds, logger.SlogLogger(), &config); err != nil { initFatal(err, "setup conditional access IdP") } } else { diff --git a/cmd/fleetctl/fleetctl/preview.go b/cmd/fleetctl/fleetctl/preview.go index 541ee80231..7ad7296441 100644 --- a/cmd/fleetctl/fleetctl/preview.go +++ b/cmd/fleetctl/fleetctl/preview.go @@ -382,7 +382,7 @@ Use the stop and reset subcommands to manage the server and dependencies once st c.Context, address, token, - logger, + logger.SlogLogger(), fleethttp.NewClient, service.NewClient, nil, // No mock ApplyGroup for production code diff --git a/cmd/fleetctl/integrationtest/gitops/gitops_enterprise_integration_test.go b/cmd/fleetctl/integrationtest/gitops/gitops_enterprise_integration_test.go index 5d99803022..968f5eab04 100644 --- a/cmd/fleetctl/integrationtest/gitops/gitops_enterprise_integration_test.go +++ b/cmd/fleetctl/integrationtest/gitops/gitops_enterprise_integration_test.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "log/slog" "maps" "net/http" "net/http/httptest" @@ -110,7 +111,7 @@ func (s *enterpriseIntegrationGitopsTestSuite) SetupSuite() { SCEPStorage: scepStorage, Pool: redisPool, APNSTopic: "com.apple.mgmt.External.10ac3ce5-4668-4e58-b69a-b2b5ce667589", - SCEPConfigService: eeservice.NewSCEPConfigService(logging.NewLogfmtLogger(os.Stdout), nil), + SCEPConfigService: eeservice.NewSCEPConfigService(slog.New(slog.NewTextHandler(os.Stdout, nil)), nil), DigiCertService: digicert.NewService(), SoftwareTitleIconStore: softwareTitleIconStore, } diff --git a/cmd/osquery-perf/hostidentity/hostidentity.go b/cmd/osquery-perf/hostidentity/hostidentity.go index f58ffe0f76..f3226b390a 100644 --- a/cmd/osquery-perf/hostidentity/hostidentity.go +++ b/cmd/osquery-perf/hostidentity/hostidentity.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "log" + "log/slog" "math/big" "math/rand" "net/http" @@ -19,7 +20,6 @@ import ( "github.com/fleetdm/fleet/v4/pkg/fleethttpsig" scepclient "github.com/fleetdm/fleet/v4/server/mdm/scep/client" "github.com/fleetdm/fleet/v4/server/mdm/scep/x509util" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/remitly-oss/httpsig-go" "github.com/smallstep/scep" ) @@ -107,7 +107,7 @@ func (c *Client) RequestCertificate() error { // Create SCEP client with no-op logger and 30-second timeout scepURL := fmt.Sprintf("%s/api/fleet/orbit/host_identity/scep", c.config.ServerAddress) timeout := 30 * time.Second - scepClient, err := scepclient.New(scepURL, logging.NewNopLogger(), + scepClient, err := scepclient.New(scepURL, slog.New(slog.DiscardHandler), scepclient.WithTimeout(&timeout), scepclient.Insecure(), ) diff --git a/ee/orbit/pkg/scep/scep.go b/ee/orbit/pkg/scep/scep.go index 60dd640319..8e8d89b7be 100644 --- a/ee/orbit/pkg/scep/scep.go +++ b/ee/orbit/pkg/scep/scep.go @@ -150,7 +150,8 @@ func NewClient(opts ...Option) (*Client, error) { func (c *Client) FetchCert(ctx context.Context) (*x509.Certificate, error) { // We assume the required fields have already been validated by the NewClient factory. - scepLogger := logging.NewLogger(slog.New(&zerologSlogHandler{logger: c.logger})) + slogLogger := slog.New(&zerologSlogHandler{logger: c.logger}) + scepLogger := logging.NewLogger(slogLogger) opts := []scepclient.Option{ scepclient.WithTimeout(c.timeout), scepclient.WithRootCA(c.rootCA), @@ -159,7 +160,7 @@ func (c *Client) FetchCert(ctx context.Context) (*x509.Certificate, error) { opts = append(opts, scepclient.Insecure()) } - scepClient, err := scepclient.New(c.scepURL, scepLogger, opts...) + scepClient, err := scepclient.New(c.scepURL, slogLogger, opts...) if err != nil { return nil, fmt.Errorf("create SCEP client: %w", err) } diff --git a/ee/orbit/pkg/scep/scep_test.go b/ee/orbit/pkg/scep/scep_test.go index 30b14fc64e..9a756f6a07 100644 --- a/ee/orbit/pkg/scep/scep_test.go +++ b/ee/orbit/pkg/scep/scep_test.go @@ -211,7 +211,7 @@ func StartTestSCEPServer(t *testing.T) *httptest.Server { } logger := logging.NewNopLogger() e := scepserver.MakeServerEndpoints(svc) - scepHandler := scepserver.MakeHTTPHandler(e, svc, logger) + scepHandler := scepserver.MakeHTTPHandler(e, svc, logger.SlogLogger()) r := mux.NewRouter() r.Handle("/scep", scepHandler) server = httptest.NewServer(r) diff --git a/ee/server/integrationtest/condaccess/condaccess_test.go b/ee/server/integrationtest/condaccess/condaccess_test.go index f51b68b5aa..89c3ef6c63 100644 --- a/ee/server/integrationtest/condaccess/condaccess_test.go +++ b/ee/server/integrationtest/condaccess/condaccess_test.go @@ -270,7 +270,7 @@ func requestSCEPCertificateWithOptions(t *testing.T, s *Suite, uris []*url.URL, // Create SCEP client scepURL := fmt.Sprintf("%s/api/fleet/conditional_access/scep", s.Server.URL) - scepClient, err := scepclient.New(scepURL, s.Logger) + scepClient, err := scepclient.New(scepURL, s.Logger.SlogLogger()) require.NoError(t, err) // Get CA certificate diff --git a/ee/server/integrationtest/hostidentity/hostidentity_test.go b/ee/server/integrationtest/hostidentity/hostidentity_test.go index 4b14266761..2f956c3312 100644 --- a/ee/server/integrationtest/hostidentity/hostidentity_test.go +++ b/ee/server/integrationtest/hostidentity/hostidentity_test.go @@ -124,7 +124,7 @@ func testGetCertWithCurve(t *testing.T, s *Suite, curve elliptic.Curve) (cert *x // Create SCEP client scepURL := fmt.Sprintf("%s/api/fleet/orbit/host_identity/scep", s.Server.URL) - scepClient, err := scepclient.New(scepURL, s.Logger) + scepClient, err := scepclient.New(scepURL, s.Logger.SlogLogger()) require.NoError(t, err) // Get CA certificate @@ -595,7 +595,7 @@ func testCertificateRenewal(t *testing.T, s *Suite, existingCert *x509.Certifica // Create SCEP client scepURL := fmt.Sprintf("%s/api/fleet/orbit/host_identity/scep", s.Server.URL) - scepClient, err := scepclient.New(scepURL, s.Logger) + scepClient, err := scepclient.New(scepURL, s.Logger.SlogLogger()) require.NoError(t, err) // Get CA certificate @@ -963,7 +963,7 @@ func testSCEPFailure(t *testing.T, s *Suite, config SCEPFailureConfig) { // Create SCEP client scepURL := fmt.Sprintf("%s/api/fleet/orbit/host_identity/scep", s.Server.URL) - scepClient, err := scepclient.New(scepURL, s.Logger) + scepClient, err := scepclient.New(scepURL, s.Logger.SlogLogger()) require.NoError(t, err) // Get CA certificate diff --git a/ee/server/integrationtest/hostidentity/scep_rate_limit_test.go b/ee/server/integrationtest/hostidentity/scep_rate_limit_test.go index b7486ce835..2c7576d94b 100644 --- a/ee/server/integrationtest/hostidentity/scep_rate_limit_test.go +++ b/ee/server/integrationtest/hostidentity/scep_rate_limit_test.go @@ -102,7 +102,7 @@ func requestSCEPCertificate(t *testing.T, s *Suite, hostIdentifier string) (*htt // Create SCEP client scepURL := s.Server.URL + "/api/fleet/orbit/host_identity/scep" timeout := 30 * time.Second - scepClient, err := scepclient.New(scepURL, s.Logger, scepclient.WithTimeout(&timeout)) + scepClient, err := scepclient.New(scepURL, s.Logger.SlogLogger(), scepclient.WithTimeout(&timeout)) require.NoError(t, err) // Get CA certificate diff --git a/ee/server/service/calendar.go b/ee/server/service/calendar.go index 6760bf20cc..95463dd1cb 100644 --- a/ee/server/service/calendar.go +++ b/ee/server/service/calendar.go @@ -95,7 +95,7 @@ func (svc *Service) CalendarWebhook(ctx context.Context, eventUUID string, chann GoogleCalendarIntegration: *googleCalendarIntegrationConfig, ServerURL: appConfig.ServerSettings.ServerURL, } - userCalendar := calendar.CreateUserCalendarFromConfig(ctx, localConfig, svc.logger.SlogLogger()) + userCalendar := calendar.CreateUserCalendarFromConfig(ctx, localConfig, svc.logger) // Authenticate request. We will use the channel ID for authentication. svc.authz.SkipAuthorization(ctx) @@ -231,7 +231,7 @@ func (svc *Service) processCalendarEvent(ctx context.Context, eventDetails *flee return "", false, err } - body, generatedTag = calendar.GenerateCalendarEventBody(ctx, svc.ds, team.Name, host, &sync.Map{}, conflict, svc.logger.SlogLogger()) + body, generatedTag = calendar.GenerateCalendarEventBody(ctx, svc.ds, team.Name, host, &sync.Map{}, conflict, svc.logger) return body, true, nil } @@ -443,7 +443,7 @@ func (svc *Service) processCalendarEventAsync(ctx context.Context, eventUUID str GoogleCalendarIntegration: *googleCalendarIntegrationConfig, ServerURL: appConfig.ServerSettings.ServerURL, } - userCalendar := calendar.CreateUserCalendarFromConfig(ctx, localConfig, svc.logger.SlogLogger()) + userCalendar := calendar.CreateUserCalendarFromConfig(ctx, localConfig, svc.logger) err = svc.processCalendarEvent(ctx, eventDetails, googleCalendarIntegrationConfig, userCalendar) if err != nil { diff --git a/ee/server/service/calendar_test.go b/ee/server/service/calendar_test.go index d5432fac78..16c79f6f28 100644 --- a/ee/server/service/calendar_test.go +++ b/ee/server/service/calendar_test.go @@ -3,13 +3,13 @@ package service import ( "context" "errors" + "log/slog" "testing" "github.com/fleetdm/fleet/v4/server/authz" authz_ctx "github.com/fleetdm/fleet/v4/server/contexts/authz" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/mock" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/ptr" "github.com/fleetdm/fleet/v4/server/service/calendar" "github.com/stretchr/testify/assert" @@ -389,7 +389,7 @@ func TestCalendarWebhookErrorCases(t *testing.T) { ds: ds, distributedLock: lock, authz: auth, - logger: logging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), } // Apply test-specific mocks diff --git a/ee/server/service/certificate_authorities_test.go b/ee/server/service/certificate_authorities_test.go index 2d4cc3e111..1c3a4d2902 100644 --- a/ee/server/service/certificate_authorities_test.go +++ b/ee/server/service/certificate_authorities_test.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "log/slog" "net/http" "net/http/httptest" "os" @@ -18,7 +19,6 @@ import ( "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/mock" scep_mock "github.com/fleetdm/fleet/v4/server/mock/scep" - "github.com/fleetdm/fleet/v4/server/platform/logging" common_mysql "github.com/fleetdm/fleet/v4/server/platform/mysql" "github.com/fleetdm/fleet/v4/server/ptr" "github.com/stretchr/testify/assert" @@ -200,7 +200,7 @@ func TestCreatingCertificateAuthorities(t *testing.T) { require.NoError(t, err) svc := &Service{ - logger: logging.NewLogfmtLogger(os.Stdout), + logger: slog.New(slog.NewTextHandler(os.Stdout, nil)), ds: ds, authz: authorizer, digiCertService: digicert.NewService(), @@ -1195,7 +1195,7 @@ func TestUpdatingCertificateAuthorities(t *testing.T) { require.NoError(t, err) svc := &Service{ - logger: logging.NewLogfmtLogger(os.Stdout), + logger: slog.New(slog.NewTextHandler(os.Stdout, nil)), ds: ds, authz: authorizer, digiCertService: digicert.NewService(), diff --git a/ee/server/service/condaccess/idp.go b/ee/server/service/condaccess/idp.go index 4b2fd65a1e..6a9a9f5fe2 100644 --- a/ee/server/service/condaccess/idp.go +++ b/ee/server/service/condaccess/idp.go @@ -8,6 +8,7 @@ import ( "encoding/pem" "errors" "fmt" + "log/slog" "net/http" "net/url" "os" @@ -20,10 +21,8 @@ import ( "github.com/fleetdm/fleet/v4/server/contexts/ctxerr" "github.com/fleetdm/fleet/v4/server/dev_mode" "github.com/fleetdm/fleet/v4/server/fleet" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/service/middleware/log" "github.com/fleetdm/fleet/v4/server/service/middleware/otel" - "github.com/go-kit/log/level" "github.com/google/uuid" dsig "github.com/russellhaering/goxmldsig" ) @@ -62,7 +61,7 @@ func (e *notFoundError) IsNotFound() bool { // idpService implements the Okta conditional access IdP functionality. type idpService struct { ds fleet.Datastore - logger *logging.Logger + logger *slog.Logger certSerialFormat string } @@ -70,7 +69,7 @@ type idpService struct { func RegisterIdP( mux *http.ServeMux, ds fleet.Datastore, - logger *logging.Logger, + logger *slog.Logger, fleetConfig *config.FleetConfig, ) error { if fleetConfig == nil { @@ -84,7 +83,7 @@ func RegisterIdP( } // Create logging middleware - loggingMiddleware := log.NewLoggingMiddleware(svc.logger.SlogLogger()) + loggingMiddleware := log.NewLoggingMiddleware(svc.logger) // Register handlers with logging and OpenTelemetry middleware // Order: OTEL wraps logging to capture full request lifecycle @@ -104,12 +103,9 @@ func RegisterIdP( // This function should be used whenever returning StatusInternalServerError to ensure // consistent error handling across the IdP service. // Additional key-value pairs can be passed for logging context (e.g., "host_id", hostID). -func handleInternalServerError(ctx context.Context, w http.ResponseWriter, logger *logging.Logger, msg string, err error, keyvals ...any) { - // Build the log keyvals starting with msg and err - logKeyvals := []any{"msg", msg, "err", err} - logKeyvals = append(logKeyvals, keyvals...) - - level.Error(logger).Log(logKeyvals...) +func handleInternalServerError(ctx context.Context, w http.ResponseWriter, logger *slog.Logger, msg string, err error, keyvals ...any) { + logKeyvals := append([]any{"err", err}, keyvals...) + logger.ErrorContext(ctx, msg, logKeyvals...) ctxerr.Handle(ctx, err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) } @@ -129,7 +125,7 @@ func (s *idpService) serveMetadata(w http.ResponseWriter, r *http.Request) { // Get Fleet server URL from config serverURL := appConfig.ServerSettings.ServerURL if serverURL == "" { - level.Error(s.logger).Log("msg", "server URL not configured") + s.logger.ErrorContext(ctx, "server URL not configured") http.Error(w, "Server URL not configured", http.StatusNotFound) return } @@ -138,7 +134,7 @@ func (s *idpService) serveMetadata(w http.ResponseWriter, r *http.Request) { idp, err := s.buildIdentityProvider(ctx, serverURL) if err != nil { if fleet.IsNotFound(err) { - level.Error(s.logger).Log("msg", "IdP certificate or key not found", "err", err) + s.logger.ErrorContext(ctx, "IdP certificate or key not found", "err", err) http.Error(w, "IdP not configured", http.StatusNotFound) return } @@ -155,8 +151,7 @@ func (s *idpService) serveMetadata(w http.ResponseWriter, r *http.Request) { func (s *idpService) serveSSO(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - level.Info(s.logger).Log( - "msg", "received SSO request", + s.logger.InfoContext(ctx, "received SSO request", "method", r.Method, "remote_addr", r.RemoteAddr, ) @@ -164,7 +159,7 @@ func (s *idpService) serveSSO(w http.ResponseWriter, r *http.Request) { // Extract certificate serial number from header (set by load balancer) serialStr := r.Header.Get("X-Client-Cert-Serial") if serialStr == "" { - level.Error(s.logger).Log("msg", "missing client certificate serial", "remote_addr", r.RemoteAddr) + s.logger.ErrorContext(ctx, "missing client certificate serial", "remote_addr", r.RemoteAddr) http.Redirect(w, r, certificateErrorURL, http.StatusSeeOther) return } @@ -172,7 +167,9 @@ func (s *idpService) serveSSO(w http.ResponseWriter, r *http.Request) { // Parse serial number (hex or decimal string to uint64, based on config) serial, err := parseSerialNumber(serialStr, s.certSerialFormat) if err != nil { - level.Error(s.logger).Log("msg", "invalid certificate serial format", "serial", serialStr, "format", s.certSerialFormat, "err", err) + s.logger.ErrorContext(ctx, "invalid certificate serial format", + "serial", serialStr, "format", s.certSerialFormat, "err", err, + ) http.Redirect(w, r, certificateErrorURL, http.StatusSeeOther) return } @@ -181,7 +178,7 @@ func (s *idpService) serveSSO(w http.ResponseWriter, r *http.Request) { hostID, err := s.ds.GetConditionalAccessCertHostIDBySerialNumber(ctx, serial) if err != nil { if fleet.IsNotFound(err) { - level.Error(s.logger).Log("msg", "certificate not recognized", "serial", serial, "err", err) + s.logger.ErrorContext(ctx, "certificate not recognized", "serial", serial, "err", err) http.Redirect(w, r, certificateErrorURL, http.StatusSeeOther) return } @@ -189,7 +186,7 @@ func (s *idpService) serveSSO(w http.ResponseWriter, r *http.Request) { return } - level.Debug(s.logger).Log("msg", "found host for certificate", "host_id", hostID, "serial", serial) + s.logger.DebugContext(ctx, "found host for certificate", "host_id", hostID, "serial", serial) // Load AppConfig for IdP configuration appConfig, err := s.ds.AppConfig(ctx) @@ -209,7 +206,7 @@ func (s *idpService) serveSSO(w http.ResponseWriter, r *http.Request) { idp, err := s.buildIdentityProvider(ctx, serverURL) if err != nil { if fleet.IsNotFound(err) { - level.Error(s.logger).Log("msg", "IdP certificate or key not found", "err", err) + s.logger.ErrorContext(ctx, "IdP certificate or key not found", "err", err) http.Redirect(w, r, certificateErrorURL, http.StatusSeeOther) return } @@ -225,7 +222,7 @@ func (s *idpService) serveSSO(w http.ResponseWriter, r *http.Request) { } // ServeSSO handles SAML AuthnRequest parsing, generates assertion, and returns response - level.Debug(s.logger).Log("msg", "calling SAML IdP ServeSSO", "host_id", hostID) + s.logger.DebugContext(ctx, "calling SAML IdP ServeSSO", "host_id", hostID) // Wrap response writer to intercept 400 errors and redirect to certificate error page wrappedWriter := &statusInterceptingWriter{ @@ -243,7 +240,7 @@ func (s *idpService) serveSSO(w http.ResponseWriter, r *http.Request) { type statusInterceptingWriter struct { http.ResponseWriter ctx context.Context - logger *logging.Logger + logger *slog.Logger r *http.Request redirectURL string headerWritten bool @@ -255,7 +252,7 @@ func (w *statusInterceptingWriter) WriteHeader(statusCode int) { } w.headerWritten = true if statusCode == http.StatusBadRequest { - level.Error(w.logger).Log("msg", "SAML IdP returned bad request, redirecting to error page", "status", statusCode) + w.logger.ErrorContext(w.ctx, "SAML IdP returned bad request, redirecting to error page", "status", statusCode) http.Redirect(w.ResponseWriter, w.r, w.redirectURL, http.StatusSeeOther) return } @@ -301,7 +298,7 @@ func extractNameID(req *saml.IdpAuthnRequest) string { // device health verification during SAML SSO flow. type deviceHealthSessionProvider struct { ds fleet.Datastore - logger *logging.Logger + logger *slog.Logger hostID uint } @@ -314,13 +311,13 @@ func (p *deviceHealthSessionProvider) GetSession(w http.ResponseWriter, r *http. // Okta sends this to identify which user is authenticating nameID := extractNameID(req) - level.Debug(p.logger).Log("msg", "processing SAML session", "host_id", p.hostID) + p.logger.DebugContext(ctx, "processing SAML session", "host_id", p.hostID) // Load host to get team ID hostLite, err := p.ds.HostLite(ctx, p.hostID) if err != nil { if fleet.IsNotFound(err) { - level.Error(p.logger).Log("msg", "host not found", "host_id", p.hostID, "err", err) + p.logger.ErrorContext(ctx, "host not found", "host_id", p.hostID, "err", err) http.Redirect(w, r, certificateErrorURL, http.StatusSeeOther) return nil } @@ -377,8 +374,7 @@ func (p *deviceHealthSessionProvider) GetSession(w http.ResponseWriter, r *http. } if failingConditionalAccessCount > 0 { - level.Debug(p.logger).Log( - "msg", "device has failing conditional access policies", + p.logger.DebugContext(ctx, "device has failing conditional access policies", "host_id", p.hostID, "failing_conditional_access_policies_count", failingConditionalAccessCount, ) @@ -397,7 +393,7 @@ func (p *deviceHealthSessionProvider) GetSession(w http.ResponseWriter, r *http. if fleet.IsNotFound(loadErr) { needNewToken = true // Case 1: token exists but is expired } else { - level.Error(p.logger).Log("msg", "failed to validate device auth token", "err", loadErr, "host_id", p.hostID) + p.logger.ErrorContext(ctx, "failed to validate device auth token", "err", loadErr, "host_id", p.hostID) ctxerr.Handle(ctx, loadErr) http.Redirect(w, r, remediateURL, http.StatusSeeOther) return nil @@ -407,8 +403,7 @@ func (p *deviceHealthSessionProvider) GetSession(w http.ResponseWriter, r *http. needNewToken = true // Case 2: no token exists (e.g. fresh install without Fleet Desktop) default: // Unexpected error. Log and redirect to generic remediation page. - level.Error(p.logger).Log( - "msg", "failed to get device auth token", + p.logger.ErrorContext(ctx, "failed to get device auth token", "err", getErr, "host_id", p.hostID, ) @@ -424,8 +419,7 @@ func (p *deviceHealthSessionProvider) GetSession(w http.ResponseWriter, r *http. // previous_token for one rotation cycle. authToken = uuid.NewString() if setErr := p.ds.SetOrUpdateDeviceAuthToken(ctx, host.ID, authToken); setErr != nil { - level.Error(p.logger).Log( - "msg", "failed to create device auth token", + p.logger.ErrorContext(ctx, "failed to create device auth token", "err", setErr, "host_id", p.hostID, ) @@ -461,8 +455,7 @@ func (p *deviceHealthSessionProvider) GetSession(w http.ResponseWriter, r *http. } // Host has clicked "bypass" for this check, we have consumed it and will let them through - level.Info(p.logger).Log( - "msg", "device has bypassed conditional access checks", + p.logger.InfoContext(ctx, "device has bypassed conditional access checks", "host_id", p.hostID, ) } @@ -472,11 +465,10 @@ func (p *deviceHealthSessionProvider) GetSession(w http.ResponseWriter, r *http. // If no NameID was provided in the request, fall back to host-based identifier if nameID == "" { nameID = fmt.Sprintf("host-%d", p.hostID) - level.Debug(p.logger).Log("msg", "no NameID in request, using host-based identifier", "name_id", nameID) + p.logger.DebugContext(ctx, "no NameID in request, using host-based identifier", "name_id", nameID) } - level.Info(p.logger).Log( - "msg", "device is compliant, generating SAML assertion", + p.logger.InfoContext(ctx, "device is compliant, generating SAML assertion", "host_id", p.hostID, ) @@ -489,7 +481,7 @@ func (p *deviceHealthSessionProvider) GetSession(w http.ResponseWriter, r *http. // Okta service provider metadata to the IdP. type oktaServiceProviderProvider struct { ds fleet.Datastore - logger *logging.Logger + logger *slog.Logger } // GetServiceProvider returns the Okta service provider metadata. @@ -513,9 +505,10 @@ func (p *oktaServiceProviderProvider) GetServiceProvider(r *http.Request, servic // Check if the requested service provider ID (entityID) matches our configured Okta Audience URI if serviceProviderID != appConfig.ConditionalAccess.OktaAudienceURI.Value { - level.Debug(p.logger).Log("msg", "service provider ID mismatch", + p.logger.DebugContext(ctx, "service provider ID mismatch", "requested", serviceProviderID, - "configured", appConfig.ConditionalAccess.OktaAudienceURI.Value) + "configured", appConfig.ConditionalAccess.OktaAudienceURI.Value, + ) return nil, os.ErrNotExist } @@ -607,7 +600,7 @@ func (s *idpService) buildIdentityProvider(ctx context.Context, serverURL string } ssoURL = ssoURL.JoinPath(idpSSOPath) - samlLogger := &slogAdapter{ctx: ctx, logger: s.logger.SlogLogger().With("component", "saml-idp")} + samlLogger := &slogAdapter{ctx: ctx, logger: s.logger.With("component", "saml-idp")} // Build IdentityProvider // Note: SessionProvider is set dynamically in serveSSO based on the authenticated device diff --git a/ee/server/service/condaccess/idp_test.go b/ee/server/service/condaccess/idp_test.go index c3077f50a2..058ca5223f 100644 --- a/ee/server/service/condaccess/idp_test.go +++ b/ee/server/service/condaccess/idp_test.go @@ -3,6 +3,7 @@ package condaccess import ( "context" "errors" + "log/slog" "net/http" "net/http/httptest" "testing" @@ -14,7 +15,6 @@ import ( "github.com/fleetdm/fleet/v4/server/config" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/mock" - "github.com/fleetdm/fleet/v4/server/platform/logging" common_mysql "github.com/fleetdm/fleet/v4/server/platform/mysql" "github.com/jmoiron/sqlx" "github.com/stretchr/testify/require" @@ -75,13 +75,13 @@ b1ctZeF7HaWwFdTC8GqWI6zzRFn+YA3f/yYibhowuEypPQeSjlI= func newTestService() (*idpService, *mock.Store) { ds := new(mock.Store) - logger := logging.NewNopLogger() + logger := slog.New(slog.DiscardHandler) return &idpService{ds: ds, logger: logger, certSerialFormat: config.CertSerialFormatHex}, ds } func newTestServiceWithCertFormat(certFormat string) (*idpService, *mock.Store) { ds := new(mock.Store) - logger := logging.NewNopLogger() + logger := slog.New(slog.DiscardHandler) return &idpService{ds: ds, logger: logger, certSerialFormat: certFormat}, ds } @@ -116,7 +116,7 @@ func mockCertAssetsFunc(includeCerts bool) func(context.Context, []fleet.MDMAsse func TestRegisterIdP(t *testing.T) { ds := new(mock.Store) - logger := logging.NewNopLogger() + logger := slog.New(slog.DiscardHandler) cfg := &config.FleetConfig{} ds.AppConfigFunc = mockAppConfigFunc("https://fleet.example.com") @@ -525,7 +525,7 @@ func TestParseCertAndKeyBytes(t *testing.T) { } func TestDeviceHealthSessionProvider(t *testing.T) { - logger := logging.NewNopLogger() + logger := slog.New(slog.DiscardHandler) now := time.Now() tests := []struct { diff --git a/ee/server/service/condaccess/scep.go b/ee/server/service/condaccess/scep.go index d4fd2260d8..2a2c7a0a39 100644 --- a/ee/server/service/condaccess/scep.go +++ b/ee/server/service/condaccess/scep.go @@ -7,6 +7,7 @@ import ( "crypto/x509" "errors" "fmt" + "log/slog" "net/http" "github.com/cenkalti/backoff/v4" @@ -44,7 +45,7 @@ func RegisterSCEP( mux *http.ServeMux, scepStorage scepdepot.Depot, ds fleet.Datastore, - logger *logging.Logger, + logger *slog.Logger, fleetConfig *config.FleetConfig, ) error { if fleetConfig == nil { @@ -111,7 +112,7 @@ var _ scepserver.Service = (*service)(nil) type service struct { // The (chainable) CSR signing function signer scepserver.CSRSignerContext - logger *logging.Logger + logger *slog.Logger ds fleet.Datastore } @@ -158,7 +159,7 @@ func (svc *service) PKIOperation(ctx context.Context, data []byte) ([]byte, erro if len(data) == 0 { return nil, &fleet.BadRequestError{Message: "missing data for PKIOperation"} } - msg, err := scep.ParsePKIMessage(data, scep.WithLogger(svc.logger)) + msg, err := scep.ParsePKIMessage(data, scep.WithLogger(logging.NewLogger(svc.logger))) if err != nil { return nil, err } @@ -182,7 +183,7 @@ func (svc *service) PKIOperation(ctx context.Context, data []byte) ([]byte, erro err = errors.New("signer returned nil certificate without error") } if err != nil { - svc.logger.Log("msg", "failed to sign CSR", "err", err) + svc.logger.ErrorContext(ctx, "failed to sign CSR", "err", err) // Check if this is a rate limit error (permanent error from backoff) var permanentErr *backoff.PermanentError @@ -211,7 +212,7 @@ func (svc *service) GetNextCACert(_ context.Context) ([]byte, error) { } // NewSCEPService creates a new conditional access SCEP service. -func NewSCEPService(ds fleet.Datastore, signer scepserver.CSRSignerContext, logger *logging.Logger) scepserver.Service { +func NewSCEPService(ds fleet.Datastore, signer scepserver.CSRSignerContext, logger *slog.Logger) scepserver.Service { return &service{ ds: ds, signer: signer, diff --git a/ee/server/service/devices.go b/ee/server/service/devices.go index 73f53ed529..5d0e9621b0 100644 --- a/ee/server/service/devices.go +++ b/ee/server/service/devices.go @@ -80,7 +80,7 @@ func (svc *Service) TriggerMigrateMDMDevice(ctx context.Context, host *fleet.Hos p.Host.UUID = host.UUID p.Host.HardwareSerial = host.HardwareSerial - if err := server.PostJSONWithTimeout(ctx, ac.MDM.MacOSMigration.WebhookURL, p, svc.logger.SlogLogger()); err != nil { + if err := server.PostJSONWithTimeout(ctx, ac.MDM.MacOSMigration.WebhookURL, p, svc.logger); err != nil { return ctxerr.Wrap(ctx, err, "posting macOS migration webhook") } diff --git a/ee/server/service/digicert/digicert.go b/ee/server/service/digicert/digicert.go index ed00648a6c..3a25af8758 100644 --- a/ee/server/service/digicert/digicert.go +++ b/ee/server/service/digicert/digicert.go @@ -8,6 +8,7 @@ import ( "crypto/x509/pkix" "encoding/hex" "encoding/pem" + "log/slog" "net/http" "net/url" "os" @@ -18,7 +19,6 @@ import ( "github.com/fleetdm/fleet/v4/server" "github.com/fleetdm/fleet/v4/server/contexts/ctxerr" "github.com/fleetdm/fleet/v4/server/fleet" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/go-json-experiment/json" "software.sslmate.com/src/go-pkcs12" ) @@ -35,7 +35,7 @@ const ( ) type Service struct { - logger *logging.Logger + logger *slog.Logger timeout time.Duration } @@ -59,7 +59,7 @@ func WithTimeout(t time.Duration) Opt { } // WithLogger sets the logger to use for the service. -func WithLogger(logger *logging.Logger) Opt { +func WithLogger(logger *slog.Logger) Opt { return func(s *Service) { s.logger = logger } @@ -118,7 +118,7 @@ func (s *Service) populateOpts(opts []Opt) { s.timeout = defaultTimeout } if s.logger == nil { - s.logger = logging.NewLogfmtLogger(os.Stderr) + s.logger = slog.New(slog.NewTextHandler(os.Stderr, nil)) } } diff --git a/ee/server/service/est/est.go b/ee/server/service/est/est.go index 516600dc2d..5a150eff40 100644 --- a/ee/server/service/est/est.go +++ b/ee/server/service/est/est.go @@ -4,6 +4,7 @@ import ( "context" "encoding/base64" "io" + "log/slog" "net/http" "net/url" "os" @@ -13,14 +14,13 @@ import ( "github.com/fleetdm/fleet/v4/pkg/fleethttp" "github.com/fleetdm/fleet/v4/server/contexts/ctxerr" "github.com/fleetdm/fleet/v4/server/fleet" - "github.com/fleetdm/fleet/v4/server/platform/logging" ) // defaultTimeout is the timeout for requests. const defaultTimeout = 20 * time.Second type Service struct { - logger *logging.Logger + logger *slog.Logger timeout time.Duration client *http.Client } @@ -46,7 +46,7 @@ func WithTimeout(t time.Duration) Opt { } // WithLogger sets the logger to use for the service. -func WithLogger(logger *logging.Logger) Opt { +func WithLogger(logger *slog.Logger) Opt { return func(s *Service) { s.logger = logger } @@ -60,7 +60,7 @@ func (s *Service) populateOpts(opts []Opt) { s.timeout = defaultTimeout } if s.logger == nil { - s.logger = logging.NewLogfmtLogger(os.Stdout) + s.logger = slog.New(slog.NewTextHandler(os.Stdout, nil)) } } @@ -125,7 +125,7 @@ func (s *Service) GetCertificate(ctx context.Context, estCA fleet.ESTProxyCA, cs if len(bytes) > 1000 { bytesToLog = bytes[:1000] } - s.logger.Log("msg", "unexpected EST CA status code", "status_code", resp.StatusCode, "response_body", string(bytesToLog)) + s.logger.ErrorContext(ctx, "unexpected EST CA status code", "status_code", resp.StatusCode, "response_body", string(bytesToLog)) return nil, ctxerr.Errorf(ctx, "unexpected EST CA status code: %d", resp.StatusCode) } diff --git a/ee/server/service/hostidentity/httpsig/httpsig.go b/ee/server/service/hostidentity/httpsig/httpsig.go index c1f9a1c8a8..890d4f4a93 100644 --- a/ee/server/service/hostidentity/httpsig/httpsig.go +++ b/ee/server/service/hostidentity/httpsig/httpsig.go @@ -5,20 +5,19 @@ import ( "crypto/elliptic" "errors" "fmt" + "log/slog" "net/http" "strconv" "github.com/fleetdm/fleet/v4/ee/server/service/hostidentity/types" "github.com/fleetdm/fleet/v4/pkg/fleethttpsig" "github.com/fleetdm/fleet/v4/server/fleet" - "github.com/fleetdm/fleet/v4/server/platform/logging" - "github.com/go-kit/log/level" "github.com/remitly-oss/httpsig-go" ) type HTTPSig struct { ds fleet.Datastore - logger *logging.Logger + logger *slog.Logger } type KeySpecer struct { @@ -33,7 +32,7 @@ func (k KeySpecer) KeySpec() (httpsig.KeySpec, error) { // _ ensures that KeySpecer implements the httpsig.KeySpecer interface. var _ httpsig.KeySpecer = KeySpecer{} -func NewHTTPSig(ds fleet.Datastore, logger *logging.Logger) *HTTPSig { +func NewHTTPSig(ds fleet.Datastore, logger *slog.Logger) *HTTPSig { return &HTTPSig{ ds: ds, logger: logger, @@ -51,7 +50,7 @@ func (h *HTTPSig) FetchByKeyID(ctx context.Context, _ http.Header, keyID string) keyIDInt, err := strconv.ParseUint(keyID, 16, 64) if err != nil { err = fmt.Errorf("invalid hex key ID: %w", err) - h.logger.Log("level", "info", "msg", "FetchByKeyID error", "err", err) + h.logger.InfoContext(ctx, "FetchByKeyID error", "err", err) return nil, err } identityCert, err := h.ds.GetHostIdentityCertBySerialNumber(ctx, keyIDInt) @@ -60,13 +59,13 @@ func (h *HTTPSig) FetchByKeyID(ctx context.Context, _ http.Header, keyID string) return nil, fmt.Errorf("certificate not found with keyID: %d", keyIDInt) case err != nil: err = fmt.Errorf("loading certificate: %w", err) - level.Error(h.logger).Log("msg", "FetchByKeyID error", "err", err) + h.logger.ErrorContext(ctx, "FetchByKeyID error", "err", err) return nil, err } publicKey, err := identityCert.UnmarshalPublicKey() if err != nil { err = fmt.Errorf("unmarshaling public key: %w", err) - level.Error(h.logger).Log("msg", "FetchByKeyID error", "err", err) + h.logger.ErrorContext(ctx, "FetchByKeyID error", "err", err) return nil, err } @@ -78,7 +77,7 @@ func (h *HTTPSig) FetchByKeyID(ctx context.Context, _ http.Header, keyID string) algo = httpsig.Algo_ECDSA_P384_SHA384 default: err = fmt.Errorf("unsupported elliptic curve: %s", publicKey.Curve.Params().Name) - h.logger.Log("level", "info", "msg", "FetchByKeyID error", "err", err) + h.logger.InfoContext(ctx, "FetchByKeyID error", "err", err) return nil, err } diff --git a/ee/server/service/hostidentity/httpsig/middleware.go b/ee/server/service/hostidentity/httpsig/middleware.go index c9d1a161c6..b60d8ebd5e 100644 --- a/ee/server/service/hostidentity/httpsig/middleware.go +++ b/ee/server/service/hostidentity/httpsig/middleware.go @@ -3,6 +3,7 @@ package httpsig import ( "context" "fmt" + "log/slog" "net/http" "regexp" "strings" @@ -10,8 +11,6 @@ import ( "github.com/fleetdm/fleet/v4/ee/server/service/hostidentity/types" "github.com/fleetdm/fleet/v4/server/contexts/ctxerr" "github.com/fleetdm/fleet/v4/server/fleet" - "github.com/fleetdm/fleet/v4/server/platform/logging" - "github.com/go-kit/log/level" ) type key int @@ -49,7 +48,7 @@ func FromContext(ctx context.Context) (types.HostIdentityCertificate, bool) { // to it, and then calls the handler passed as parameter to the MiddlewareFunc. type MiddlewareFunc func(http.Handler) http.Handler -func Middleware(ds fleet.Datastore, requireSignature bool, logger *logging.Logger) (MiddlewareFunc, error) { +func Middleware(ds fleet.Datastore, requireSignature bool, logger *slog.Logger) (MiddlewareFunc, error) { // Initialize HTTP signature verifier httpSig := NewHTTPSig(ds, logger) verifier, err := httpSig.Verifier() @@ -107,7 +106,7 @@ func Middleware(ds fleet.Datastore, requireSignature bool, logger *logging.Logge return } - level.Debug(logger).Log("msg", "httpsig verified", "host_id", keySpecer.hostIdentityCert.HostID) + logger.DebugContext(req.Context(), "httpsig verified", "host_id", keySpecer.hostIdentityCert.HostID) // Signature is valid, we set the identity data in the context and proceed with processing the request. req = req.WithContext(NewContext(req.Context(), keySpecer.hostIdentityCert)) diff --git a/ee/server/service/hostidentity/scep.go b/ee/server/service/hostidentity/scep.go index 597786833a..4837007e6c 100644 --- a/ee/server/service/hostidentity/scep.go +++ b/ee/server/service/hostidentity/scep.go @@ -11,6 +11,7 @@ import ( "encoding/json" "errors" "fmt" + "log/slog" "math/big" "net/http" "strconv" @@ -27,7 +28,6 @@ import ( scepserver "github.com/fleetdm/fleet/v4/server/mdm/scep/server" "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/service/middleware/otel" - "github.com/go-kit/log/level" "github.com/smallstep/scep" ) @@ -66,7 +66,7 @@ func RegisterSCEP( mux *http.ServeMux, scepStorage scepdepot.Depot, ds fleet.Datastore, - logger *logging.Logger, + logger *slog.Logger, fleetConfig *config.FleetConfig, ) error { if fleetConfig == nil { @@ -139,7 +139,7 @@ func hasRenewalExtension(csr *x509.CertificateRequest) bool { } // renewalMiddleware handles certificate renewal with proof-of-possession -func renewalMiddleware(ds fleet.Datastore, logger *logging.Logger, next scepserver.CSRSignerContext) scepserver.CSRSignerContextFunc { +func renewalMiddleware(ds fleet.Datastore, logger *slog.Logger, next scepserver.CSRSignerContext) scepserver.CSRSignerContextFunc { return func(ctx context.Context, m *scep.CSRReqMessage) (*x509.Certificate, error) { // Check if this is a renewal request var renewalData types.RenewalData @@ -159,7 +159,7 @@ func renewalMiddleware(ds fleet.Datastore, logger *logging.Logger, next scepserv return next.SignCSRContext(ctx, m) } - logger.Log("msg", "processing renewal request", "serial", renewalData.SerialNumber) + logger.InfoContext(ctx, "processing renewal request", "serial", renewalData.SerialNumber) // Parse the serial number from hex serialBigInt := new(big.Int) @@ -192,7 +192,7 @@ func renewalMiddleware(ds fleet.Datastore, logger *logging.Logger, next scepserv return nil, errors.New("invalid renewal signature") } - logger.Log("msg", "renewal signature verified", "serial", renewalData.SerialNumber, "cn", oldCertData.CommonName) + logger.InfoContext(ctx, "renewal signature verified", "serial", renewalData.SerialNumber, "cn", oldCertData.CommonName) // Issue the new certificate newCert, err := next.SignCSRContext(ctx, m) @@ -206,7 +206,7 @@ func renewalMiddleware(ds fleet.Datastore, logger *logging.Logger, next scepserv if err != nil { // Log the error but don't fail the renewal ctxerr.Handle(ctx, err) - level.Error(logger).Log("msg", "failed to update host_id for renewed certificate", "err", err, "new_serial", + logger.ErrorContext(ctx, "failed to update host_id for renewed certificate", "err", err, "new_serial", newCert.SerialNumber.Uint64(), "host_id", *oldCertData.HostID) } } @@ -223,7 +223,7 @@ type service struct { // issuance, RA proxying, etc. signer scepserver.CSRSignerContext - logger *logging.Logger + logger *slog.Logger ds fleet.Datastore } @@ -269,7 +269,7 @@ func (svc *service) PKIOperation(ctx context.Context, data []byte) ([]byte, erro if len(data) == 0 { return nil, &fleet.BadRequestError{Message: "missing data for PKIOperation"} } - msg, err := scep.ParsePKIMessage(data, scep.WithLogger(svc.logger)) + msg, err := scep.ParsePKIMessage(data, scep.WithLogger(logging.NewLogger(svc.logger))) if err != nil { return nil, err } @@ -293,7 +293,7 @@ func (svc *service) PKIOperation(ctx context.Context, data []byte) ([]byte, erro err = errors.New("signer returned nil certificate without error") } if err != nil { - svc.logger.Log("msg", "failed to sign CSR", "err", err) + svc.logger.ErrorContext(ctx, "failed to sign CSR", "err", err) // Check if this is a rate limit error (permanent error from backoff) var permanentErr *backoff.PermanentError @@ -321,7 +321,7 @@ func (svc *service) GetNextCACert(_ context.Context) ([]byte, error) { } // NewSCEPService creates a new scep service -func NewSCEPService(ds fleet.Datastore, signer scepserver.CSRSignerContext, logger *logging.Logger) scepserver.Service { +func NewSCEPService(ds fleet.Datastore, signer scepserver.CSRSignerContext, logger *slog.Logger) scepserver.Service { return &service{ ds: ds, signer: signer, diff --git a/ee/server/service/maintained_apps.go b/ee/server/service/maintained_apps.go index 03c2db89c6..3dee4eed56 100644 --- a/ee/server/service/maintained_apps.go +++ b/ee/server/service/maintained_apps.go @@ -16,7 +16,6 @@ import ( "github.com/fleetdm/fleet/v4/server/dev_mode" "github.com/fleetdm/fleet/v4/server/fleet" maintained_apps "github.com/fleetdm/fleet/v4/server/mdm/maintainedapps" - "github.com/go-kit/kit/log/level" ) // noCheckHash is used by homebrew to signal that a hash shouldn't be checked, and FMA carries this convention over @@ -220,7 +219,7 @@ func (svc *Service) AddFleetMaintainedApp( } if err := svc.NewActivity(ctx, authz.UserFromContext(ctx), policyAct); err != nil { - level.Warn(svc.logger).Log("msg", "failed to create activity for create automatic install policy for FMA", "err", err) + svc.logger.WarnContext(ctx, "failed to create activity for create automatic install policy for FMA", "err", err) } } diff --git a/ee/server/service/mdm.go b/ee/server/service/mdm.go index 748813dd09..efa2cb5bdc 100644 --- a/ee/server/service/mdm.go +++ b/ee/server/service/mdm.go @@ -265,7 +265,7 @@ func (svc *Service) updateAppConfigMDMAppleSetup(ctx context.Context, payload fl } func (svc *Service) updateMacOSSetupEnableEndUserAuth(ctx context.Context, enable bool, teamID *uint, teamName *string) error { - if _, err := worker.QueueMacosSetupAssistantJob(ctx, svc.ds, svc.logger.SlogLogger(), worker.MacosSetupAssistantUpdateProfile, teamID); err != nil { + if _, err := worker.QueueMacosSetupAssistantJob(ctx, svc.ds, svc.logger, worker.MacosSetupAssistantUpdateProfile, teamID); err != nil { return ctxerr.Wrap(ctx, err, "queue macos setup assistant update profile job") } @@ -657,7 +657,7 @@ func (svc *Service) SetOrUpdateMDMAppleSetupAssistant(ctx context.Context, asst if _, err := worker.QueueMacosSetupAssistantJob( ctx, svc.ds, - svc.logger.SlogLogger(), + svc.logger, worker.MacosSetupAssistantProfileChanged, newAsst.TeamID); err != nil { return nil, ctxerr.Wrap(ctx, err, "enqueue macos setup assistant profile changed job") @@ -702,7 +702,7 @@ func (svc *Service) DeleteMDMAppleSetupAssistant(ctx context.Context, teamID *ui if _, err := worker.QueueMacosSetupAssistantJob( ctx, svc.ds, - svc.logger.SlogLogger(), + svc.logger, worker.MacosSetupAssistantProfileDeleted, teamID); err != nil { return ctxerr.Wrap(ctx, err, "enqueue macos setup assistant profile deleted job") @@ -922,7 +922,7 @@ func (svc *Service) mdmSSOHandleCallbackAuth( // For more details, check https://github.com/fleetdm/fleet/issues/10744#issuecomment-1540605146 username, _, found := strings.Cut(auth.UserID(), "@") if !found { - svc.logger.Log("mdm-sso-callback", "IdP UserID doesn't look like an email, using raw value") + svc.logger.InfoContext(ctx, "IdP UserID doesn't look like an email, using raw value", "component", "mdm-sso-callback") username = auth.UserID() } @@ -988,7 +988,7 @@ func (svc *Service) mdmSSOHandleCallbackAuth( } func (svc *Service) mdmAppleSyncDEPProfiles(ctx context.Context) error { - if _, err := worker.QueueMacosSetupAssistantJob(ctx, svc.ds, svc.logger.SlogLogger(), worker.MacosSetupAssistantUpdateAllProfiles, nil); err != nil { + if _, err := worker.QueueMacosSetupAssistantJob(ctx, svc.ds, svc.logger, worker.MacosSetupAssistantUpdateAllProfiles, nil); err != nil { return ctxerr.Wrap(ctx, err, "queue macos setup assistant update all profiles job") } return nil @@ -1405,7 +1405,7 @@ func (svc *Service) UploadABMToken(ctx context.Context, token io.Reader) (*fleet EncryptedToken: encryptedToken, } - if err := apple_mdm.SetDecryptedABMTokenMetadata(ctx, tok, decryptedToken, svc.depStorage, svc.ds, svc.logger.SlogLogger(), false); err != nil { + if err := apple_mdm.SetDecryptedABMTokenMetadata(ctx, tok, decryptedToken, svc.depStorage, svc.ds, svc.logger, false); err != nil { return nil, ctxerr.Wrap(ctx, err, "setting ABM token metadata") } @@ -1566,7 +1566,7 @@ func (svc *Service) RenewABMToken(ctx context.Context, token io.Reader, tokenID return nil, ctxerr.Wrap(ctx, err, "decrypting ABM token for renewal") } - if err := apple_mdm.SetDecryptedABMTokenMetadata(ctx, oldTok, decryptedToken, svc.depStorage, svc.ds, svc.logger.SlogLogger(), true); err != nil { + if err := apple_mdm.SetDecryptedABMTokenMetadata(ctx, oldTok, decryptedToken, svc.depStorage, svc.ds, svc.logger, true); err != nil { return nil, ctxerr.Wrap(ctx, err, "setting ABM token metadata") } diff --git a/ee/server/service/mdm_external_test.go b/ee/server/service/mdm_external_test.go index 64616849d9..a6339c3f01 100644 --- a/ee/server/service/mdm_external_test.go +++ b/ee/server/service/mdm_external_test.go @@ -78,7 +78,7 @@ func setupMockDatastorePremiumService(t testing.TB) (*mock.Store, *eeservice.Ser ds, nil, nil, - logger, + logger.SlogLogger(), nil, fleetConfig, nil, @@ -110,7 +110,7 @@ func setupMockDatastorePremiumService(t testing.TB) (*mock.Store, *eeservice.Ser svc, err := eeservice.NewService( freeSvc, ds, - logger, + logger.SlogLogger(), fleetConfig, nil, clock.C, diff --git a/ee/server/service/request_certificate_test.go b/ee/server/service/request_certificate_test.go index 3908900dc2..db972ba1ff 100644 --- a/ee/server/service/request_certificate_test.go +++ b/ee/server/service/request_certificate_test.go @@ -3,6 +3,7 @@ package service import ( "context" "encoding/json" + "log/slog" "net/http" "net/http/httptest" "os" @@ -17,7 +18,6 @@ import ( "github.com/fleetdm/fleet/v4/server/contexts/viewer" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/mock" - "github.com/fleetdm/fleet/v4/server/platform/logging" common_mysql "github.com/fleetdm/fleet/v4/server/platform/mysql" "github.com/fleetdm/fleet/v4/server/ptr" "github.com/stretchr/testify/require" @@ -150,7 +150,7 @@ func TestRequestCertificate(t *testing.T) { authorizer, err := authz.NewAuthorizer() require.NoError(t, err) - logger := logging.NewLogfmtLogger(os.Stdout) + logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) svc := &Service{ logger: logger, ds: ds, diff --git a/ee/server/service/scep_proxy.go b/ee/server/service/scep_proxy.go index ccf2a28824..90fb2e2095 100644 --- a/ee/server/service/scep_proxy.go +++ b/ee/server/service/scep_proxy.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "io" + "log/slog" "net/http" "net/url" "regexp" @@ -21,9 +22,7 @@ import ( "github.com/fleetdm/fleet/v4/server/fleet" scepclient "github.com/fleetdm/fleet/v4/server/mdm/scep/client" scepserver "github.com/fleetdm/fleet/v4/server/mdm/scep/server" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/ptr" - "github.com/go-kit/kit/log/level" "github.com/google/uuid" "golang.org/x/net/html/charset" "golang.org/x/text/encoding/unicode" @@ -200,12 +199,12 @@ func (a *certificateTemplateForHostAdapter) GetProfileUUID() string { type scepProxyService struct { ds fleet.Datastore // info logging is implemented in the service middleware layer. - debugLogger *logging.Logger + debugLogger *slog.Logger Timeout *time.Duration } // NewSCEPProxyService creates a new scep proxy service -func NewSCEPProxyService(ds fleet.Datastore, logger *logging.Logger, timeout *time.Duration) scepserver.ServiceWithIdentifier { +func NewSCEPProxyService(ds fleet.Datastore, logger *slog.Logger, timeout *time.Duration) scepserver.ServiceWithIdentifier { if timeout == nil { timeout = ptr.Duration(30 * time.Second) } @@ -436,11 +435,10 @@ func (svc *scepProxyService) validateIdentifier(ctx context.Context, identifier // FIXME: The layered logging implementation of the scepProxyService not // intuitive. Can we make it so that we return fleet.ErrWithInternal to // better capture/log the context errors here? - svc.debugLogger.Log( - "msg", "custom scep proxy: failed to handle fleet challenge", + svc.debugLogger.ErrorContext(ctx, "custom scep proxy: failed to handle fleet challenge", "host_uuid", hostUUID, "profile_uuid", profileUUID, - "err", err.Error(), + "err", err, ) return "", &scepserver.BadRequestError{ Message: "custom scep challenge failed", @@ -485,12 +483,12 @@ func (svc *scepProxyService) handleFleetChallenge(ctx context.Context, fleetChal } type SCEPConfigService struct { - logger *logging.Logger + logger *slog.Logger // Timeout is the timeout for SCEP requests. Timeout *time.Duration } -func NewSCEPConfigService(logger *logging.Logger, timeout *time.Duration) fleet.SCEPConfigService { +func NewSCEPConfigService(logger *slog.Logger, timeout *time.Duration) fleet.SCEPConfigService { if timeout == nil { timeout = ptr.Duration(30 * time.Second) } @@ -557,7 +555,7 @@ func (s *SCEPConfigService) GetNDESSCEPChallenge(ctx context.Context, proxy flee } // If we can't find a specific error, we log more context in terms of the request to further diagnose - level.Debug(s.logger).Log("msg", "failed to parse NDES challenge from admin URL response", "ca_type", fleet.CATypeNDESSCEPProxy, "raw_response", htmlString, "request_duration", endRequestTime.Sub(startRequestTime).Seconds()) + s.logger.DebugContext(ctx, "failed to parse NDES challenge from admin URL response", "ca_type", fleet.CATypeNDESSCEPProxy, "raw_response", htmlString, "request_duration", endRequestTime.Sub(startRequestTime).Seconds()) return "", ctxerr.Wrap(ctx, NewNDESInvalidError("could not retrieve the enrollment challenge password; invalid admin URL or credentials; please correct and try again")) } @@ -618,9 +616,13 @@ func (s *SCEPConfigService) GetSmallstepSCEPChallenge(ctx context.Context, ca fl if resp.StatusCode != http.StatusOK { reader := io.LimitReader(resp.Body, units.MiB*2) if b, err := io.ReadAll(reader); err == nil { - level.Debug(s.logger).Log("msg", "failed to get Smallstep SCEP challenge", "status_code", resp.StatusCode, "status", resp.Status, "ca_type", fleet.CATypeSmallstep, "raw_response", string(b), "request_duration", endRequestTime.Sub(startRequestTime).Seconds()) + s.logger.DebugContext(ctx, "failed to get Smallstep SCEP challenge", + "status_code", resp.StatusCode, "status", resp.Status, "ca_type", fleet.CATypeSmallstep, + "raw_response", string(b), "request_duration", endRequestTime.Sub(startRequestTime).Seconds()) } else { - level.Debug(s.logger).Log("msg", "failed to get Smallstep SCEP challenge and failed to read response body", "status_code", resp.StatusCode, "status", resp.Status, "ca_type", fleet.CATypeSmallstep, "read_error", err.Error(), "request_duration", endRequestTime.Sub(startRequestTime).Seconds()) + s.logger.DebugContext(ctx, "failed to get Smallstep SCEP challenge and failed to read response body", + "status_code", resp.StatusCode, "status", resp.Status, "ca_type", fleet.CATypeSmallstep, + "read_error", err.Error(), "request_duration", endRequestTime.Sub(startRequestTime).Seconds()) } return "", ctxerr.Wrap(ctx, fmt.Errorf("status code %d", resp.StatusCode), "getting Smallstep SCEP challenge") } diff --git a/ee/server/service/scep_proxy_test.go b/ee/server/service/scep_proxy_test.go index 9ec921b5a2..6ce2517e57 100644 --- a/ee/server/service/scep_proxy_test.go +++ b/ee/server/service/scep_proxy_test.go @@ -5,6 +5,7 @@ import ( "database/sql" "encoding/binary" "errors" + "log/slog" "net/http" "net/http/httptest" "net/url" @@ -14,7 +15,6 @@ import ( "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/mock" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -45,7 +45,7 @@ func TestValidateNDESSCEPAdminURL(t *testing.T) { } returnStatus = http.StatusNotFound - logger := logging.NewNopLogger() + logger := slog.New(slog.DiscardHandler) svc := NewSCEPConfigService(logger, nil) err := svc.ValidateNDESSCEPAdminURL(context.Background(), proxy) assert.ErrorContains(t, err, "unexpected status code") @@ -185,7 +185,7 @@ func TestValidateSCEPURL(t *testing.T) { proxy := fleet.NDESSCEPProxyCA{ URL: srv.URL + "/scep", } - logger := logging.NewNopLogger() + logger := slog.New(slog.DiscardHandler) svc := NewSCEPConfigService(logger, nil) err := svc.ValidateSCEPURL(context.Background(), proxy.URL) assert.NoError(t, err) @@ -199,7 +199,7 @@ func TestValidateIdentifier(t *testing.T) { t.Parallel() ctx := context.Background() - logger := logging.NewNopLogger() + logger := slog.New(slog.DiscardHandler) // Helper to create a scepProxyService with a mock datastore newTestService := func(ds *mock.DataStore) *scepProxyService { diff --git a/ee/server/service/service.go b/ee/server/service/service.go index a4aeb75438..376bbdaba3 100644 --- a/ee/server/service/service.go +++ b/ee/server/service/service.go @@ -2,6 +2,7 @@ package service import ( "fmt" + "log/slog" "github.com/WatchBeam/clock" "github.com/fleetdm/fleet/v4/server/authz" @@ -10,7 +11,6 @@ import ( "github.com/fleetdm/fleet/v4/server/mdm/android" apple_mdm "github.com/fleetdm/fleet/v4/server/mdm/apple" "github.com/fleetdm/fleet/v4/server/mdm/nanodep/storage" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/sso" ) @@ -19,7 +19,7 @@ type Service struct { fleet.Service ds fleet.Datastore - logger *logging.Logger + logger *slog.Logger config config.FleetConfig clock clock.Clock authz *authz.Authorizer @@ -42,7 +42,7 @@ type Service struct { func NewService( svc fleet.Service, ds fleet.Datastore, - logger *logging.Logger, + logger *slog.Logger, config config.FleetConfig, mailService fleet.MailService, c clock.Clock, @@ -75,7 +75,7 @@ func NewService( depStorage: depStorage, mdmAppleCommander: mdmAppleCommander, ssoSessionStore: sso, - depService: apple_mdm.NewDEPService(ds, depStorage, logger.SlogLogger()), + depService: apple_mdm.NewDEPService(ds, depStorage, logger), profileMatcher: profileMatcher, softwareInstallStore: softwareInstallStore, bootstrapPackageStore: bootstrapPackageStore, diff --git a/ee/server/service/software_installers.go b/ee/server/service/software_installers.go index cadaf0d60e..b9fa0644f0 100644 --- a/ee/server/service/software_installers.go +++ b/ee/server/service/software_installers.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "io" + "log/slog" "net/http" "net/url" "path" @@ -28,11 +29,9 @@ import ( "github.com/fleetdm/fleet/v4/server/mdm/apple/vpp" maintained_apps "github.com/fleetdm/fleet/v4/server/mdm/maintainedapps" "github.com/fleetdm/fleet/v4/server/mdm/nanomdm/mdm" - "github.com/fleetdm/fleet/v4/server/platform/logging" common_mysql "github.com/fleetdm/fleet/v4/server/platform/mysql" "github.com/fleetdm/fleet/v4/server/ptr" "github.com/fleetdm/fleet/v4/server/worker" - "github.com/go-kit/log/level" "github.com/google/uuid" "golang.org/x/sync/errgroup" ) @@ -136,7 +135,7 @@ func (svc *Service) UploadSoftwareInstaller(ctx context.Context, payload *fleet. if err != nil { return nil, ctxerr.Wrap(ctx, err, "matching or creating software installer") } - level.Debug(svc.logger).Log("msg", "software installer uploaded", "installer_id", installerID) + svc.logger.DebugContext(ctx, "software installer uploaded", "installer_id", installerID) var teamName *string if payload.TeamID != nil && *payload.TeamID != 0 { @@ -832,7 +831,7 @@ func (svc *Service) deleteVPPApp(ctx context.Context, teamID *uint, meta *fleet. if err != nil { return &fleet.BadRequestError{Message: "Android MDM is not enabled", InternalErr: err} } - err = worker.QueueMakeAndroidAppUnavailableJob(ctx, svc.ds, svc.logger.SlogLogger(), meta.VPPAppID.AdamID, androidHostsUUIDToPolicyID, enterprise.Name()) + err = worker.QueueMakeAndroidAppUnavailableJob(ctx, svc.ds, svc.logger, meta.VPPAppID.AdamID, androidHostsUUIDToPolicyID, enterprise.Name()) if err != nil { return ctxerr.Wrap(ctx, err, "enqueuing job to make android app unavailable") } @@ -1073,7 +1072,7 @@ func (svc *Service) GetSoftwareInstallDetails(ctx context.Context, installUUID s if err != nil { // We log the error but continue to return the details without the signed URL because orbit can still // try to download the installer via Fleet server. - level.Error(svc.logger).Log("msg", "error getting software installer URL; check CloudFront configuration", "err", err) + svc.logger.ErrorContext(ctx, "error getting software installer URL; check CloudFront configuration", "err", err) } else { details.SoftwareInstallerURL = installerURL } @@ -1395,8 +1394,7 @@ func (svc *Service) InstallVPPAppPostValidation(ctx context.Context, host *fleet } if len(assets) == 0 { - level.Debug(svc.logger).Log( - "msg", "trying to assign VPP asset to host", + svc.logger.DebugContext(ctx, "trying to assign VPP asset to host", "adam_id", vppApp.AdamID, "host_serial", host.HardwareSerial, ) @@ -2046,8 +2044,7 @@ func (svc *Service) BatchSetSoftwareInstallers( return "", ctxerr.Wrapf(ctx, err, "failed to set key as %s", batchSetProcessing) } - svc.logger.Log( - "msg", "software batch start", + svc.logger.InfoContext(ctx, "software batch start", "request_uuid", requestUUID, "team_id", teamID, "payloads", len(payloads), @@ -2141,10 +2138,10 @@ func (svc *Service) softwareBatchUpload( "status", status, "took", time.Since(start), ) - logger.Log("msg", "software batch done") + logger.InfoContext(ctx, "software batch done") // Give 10m for the client to read the result (it overrides the previos expiration time). if err := svc.keyValueStore.Set(ctx, batchSoftwarePrefix+requestUUID, status, 10*time.Minute); err != nil { - logger.Log("msg", "failed to set result", "err", err) + logger.ErrorContext(ctx, "failed to set result", "err", err) } }(time.Now()) @@ -2879,7 +2876,7 @@ func UpgradeCodeMigration( ctx context.Context, ds fleet.Datastore, softwareInstallStore fleet.SoftwareInstallerStore, - logger *logging.Logger, + logger *slog.Logger, ) error { // Find MSI installers without upgrade_code idMap, err := ds.GetMSIInstallersWithoutUpgradeCode(ctx) @@ -2901,7 +2898,7 @@ func UpgradeCodeMigration( return ctxerr.Wrap(ctx, err, "checking if installer exists") } if !exists { - level.Warn(logger).Log("msg", "software installer not found in store", "software_installer_id", id, "storage_id", storageID) + logger.WarnContext(ctx, "software installer not found in store", "software_installer_id", id, "storage_id", storageID) upgradeCodesByStorageID[storageID] = "" // set to empty string to avoid duplicating work continue } @@ -2915,21 +2912,21 @@ func UpgradeCodeMigration( tfr, err := fleet.NewTempFileReader(installer, nil) _ = installer.Close() if err != nil { - level.Warn(logger).Log("msg", "extracting metadata from installer", "software_installer_id", id, "storage_id", storageID, "err", - err) + logger.WarnContext(ctx, "extracting metadata from installer", + "software_installer_id", id, "storage_id", storageID, "err", err) upgradeCodesByStorageID[storageID] = "" continue } meta, err := file.ExtractInstallerMetadata(tfr) _ = tfr.Close() // best-effort closing and deleting of temp file if err != nil { - level.Warn(logger).Log("msg", "extracting metadata from installer", "software_installer_id", id, "storage_id", storageID, "err", - err) + logger.WarnContext(ctx, "extracting metadata from installer", + "software_installer_id", id, "storage_id", storageID, "err", err) upgradeCodesByStorageID[storageID] = "" continue } if meta.UpgradeCode == "" { - level.Debug(logger).Log("msg", "no upgrade code found in metadata", "software_installer_id", id, "storage_id", storageID) + logger.DebugContext(ctx, "no upgrade code found in metadata", "software_installer_id", id, "storage_id", storageID) } // fall through since we're going to set the upgrade code even if it's blank upgradeCodesByStorageID[storageID] = meta.UpgradeCode @@ -2938,7 +2935,7 @@ func UpgradeCodeMigration( if upgradeCode, hasParsedUpgradeCode := upgradeCodesByStorageID[storageID]; hasParsedUpgradeCode && upgradeCode != "" { // Update the upgrade_code of the software package if we have one if err := ds.UpdateInstallerUpgradeCode(ctx, id, upgradeCode); err != nil { - level.Warn(logger).Log("msg", "failed to update upgrade code", "software_installer_id", id, "error", err) + logger.WarnContext(ctx, "failed to update upgrade code", "software_installer_id", id, "error", err) continue } } @@ -2951,7 +2948,7 @@ func UninstallSoftwareMigration( ctx context.Context, ds fleet.Datastore, softwareInstallStore fleet.SoftwareInstallerStore, - logger *logging.Logger, + logger *slog.Logger, ) error { // Find software installers that should have their uninstall script populated idMap, err := ds.GetSoftwareInstallersPendingUninstallScriptPopulation(ctx) @@ -2970,7 +2967,7 @@ func UninstallSoftwareMigration( return ctxerr.Wrap(ctx, err, "checking if installer exists") } if !exists { - level.Warn(logger).Log("msg", "software installer not found in store", "software_installer_id", id, "storage_id", storageID) + logger.WarnContext(ctx, "software installer not found in store", "software_installer_id", id, "storage_id", storageID) continue } @@ -2983,23 +2980,23 @@ func UninstallSoftwareMigration( tfr, err := fleet.NewTempFileReader(installer, nil) _ = installer.Close() if err != nil { - level.Warn(logger).Log("msg", "extracting metadata from installer", "software_installer_id", id, "storage_id", storageID, "err", - err) + logger.WarnContext(ctx, "extracting metadata from installer", + "software_installer_id", id, "storage_id", storageID, "err", err) continue } meta, err := file.ExtractInstallerMetadata(tfr) _ = tfr.Close() // best-effort closing and deleting of temp file if err != nil { - level.Warn(logger).Log("msg", "extracting metadata from installer", "software_installer_id", id, "storage_id", storageID, "err", - err) + logger.WarnContext(ctx, "extracting metadata from installer", + "software_installer_id", id, "storage_id", storageID, "err", err) continue } if len(meta.PackageIDs) == 0 { - level.Warn(logger).Log("msg", "no package_id found in metadata", "software_installer_id", id, "storage_id", storageID) + logger.WarnContext(ctx, "no package_id found in metadata", "software_installer_id", id, "storage_id", storageID) continue } if meta.Extension == "" { - level.Warn(logger).Log("msg", "no extension found in metadata", "software_installer_id", id, "storage_id", storageID) + logger.WarnContext(ctx, "no extension found in metadata", "software_installer_id", id, "storage_id", storageID) continue } payload := fleet.UploadSoftwareInstallerPayload{ diff --git a/ee/server/service/teams.go b/ee/server/service/teams.go index 101d077f27..34d8214364 100644 --- a/ee/server/service/teams.go +++ b/ee/server/service/teams.go @@ -730,7 +730,7 @@ func (svc *Service) DeleteTeam(ctx context.Context, teamID uint) error { if _, err := worker.QueueMacosSetupAssistantJob( ctx, svc.ds, - svc.logger.SlogLogger(), + svc.logger, worker.MacosSetupAssistantTeamDeleted, nil, mdmHostSerials...); err != nil { diff --git a/ee/server/service/testing_utils.go b/ee/server/service/testing_utils.go index d0e7c0376d..b811c56b98 100644 --- a/ee/server/service/testing_utils.go +++ b/ee/server/service/testing_utils.go @@ -61,7 +61,7 @@ func NewTestSCEPServer(t *testing.T) *httptest.Server { } logger := logging.NewNopLogger() e := scepserver.MakeServerEndpoints(svc) - scepHandler := scepserver.MakeHTTPHandler(e, svc, logger) + scepHandler := scepserver.MakeHTTPHandler(e, svc, logger.SlogLogger()) r := mux.NewRouter() r.Handle("/scep", scepHandler) server := httptest.NewServer(r) diff --git a/ee/server/service/vpp.go b/ee/server/service/vpp.go index c4974153f4..2083fb23be 100644 --- a/ee/server/service/vpp.go +++ b/ee/server/service/vpp.go @@ -439,7 +439,7 @@ func (svc *Service) BatchAssociateVPPApps(ctx context.Context, teamName string, if len(androidHostPoliciesToUpdate) > 0 && enterprise != nil { for hostUUID, policyID := range androidHostPoliciesToUpdate { - err := worker.QueueBulkSetAndroidAppsAvailableForHost(ctx, svc.ds, svc.logger.SlogLogger(), hostUUID, policyID, appIDs, enterprise.Name()) + err := worker.QueueBulkSetAndroidAppsAvailableForHost(ctx, svc.ds, svc.logger, hostUUID, policyID, appIDs, enterprise.Name()) if err != nil { return nil, ctxerr.WrapWithData( ctx, @@ -736,7 +736,7 @@ func (svc *Service) AddAppStoreApp(ctx context.Context, teamID *uint, appID flee return 0, ctxerr.Wrap(ctx, err, "writing VPP app to db") } if appID.Platform == fleet.AndroidPlatform { - err := worker.QueueMakeAndroidAppAvailableJob(ctx, svc.ds, svc.logger.SlogLogger(), appID.AdamID, addedApp.AppTeamID, androidEnterpriseName, androidConfigChanged) + err := worker.QueueMakeAndroidAppAvailableJob(ctx, svc.ds, svc.logger, appID.AdamID, addedApp.AppTeamID, androidEnterpriseName, androidConfigChanged) if err != nil { return 0, ctxerr.Wrap(ctx, err, "enqueuing job to make android app available") } @@ -1019,7 +1019,7 @@ func (svc *Service) UpdateAppStoreApp(ctx context.Context, titleID uint, teamID if err != nil { return nil, nil, &fleet.BadRequestError{Message: "Android MDM is not enabled", InternalErr: err} } - err = worker.QueueMakeAndroidAppAvailableJob(ctx, svc.ds, svc.logger.SlogLogger(), appToWrite.AdamID, insertedApp.AppTeamID, enterprise.Name(), androidConfigChanged) + err = worker.QueueMakeAndroidAppAvailableJob(ctx, svc.ds, svc.logger, appToWrite.AdamID, insertedApp.AppTeamID, enterprise.Name(), androidConfigChanged) if err != nil { return nil, nil, ctxerr.Wrap(ctx, err, "enqueuing job to make android app available") } diff --git a/pkg/mdm/mdmtest/apple.go b/pkg/mdm/mdmtest/apple.go index 6a831b4f3c..c06b6a4d61 100644 --- a/pkg/mdm/mdmtest/apple.go +++ b/pkg/mdm/mdmtest/apple.go @@ -1302,8 +1302,8 @@ func newSCEPClient( if err != nil { return nil, err } - endpoints.GetEndpoint = scepserver.EndpointLoggingMiddleware(logger)(endpoints.GetEndpoint) - endpoints.PostEndpoint = scepserver.EndpointLoggingMiddleware(logger)(endpoints.PostEndpoint) + endpoints.GetEndpoint = scepserver.EndpointLoggingMiddleware(logger.SlogLogger())(endpoints.GetEndpoint) + endpoints.PostEndpoint = scepserver.EndpointLoggingMiddleware(logger.SlogLogger())(endpoints.PostEndpoint) return endpoints, nil } diff --git a/server/health/health.go b/server/health/health.go index 91d116a2e9..e796a488ec 100644 --- a/server/health/health.go +++ b/server/health/health.go @@ -2,9 +2,9 @@ package health import ( + "context" + "log/slog" "net/http" - - "github.com/fleetdm/fleet/v4/server/platform/logging" ) // Checker returns an error indicating if a service is in an unhealthy state. @@ -17,7 +17,7 @@ type Checker interface { // Handler responds with either: // 200 OK if the server can successfully communicate with it's backends or // 500 if any of the backends are reporting an issue. -func Handler(logger *logging.Logger, allCheckers map[string]Checker) http.HandlerFunc { +func Handler(logger *slog.Logger, allCheckers map[string]Checker) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { checkers := make(map[string]Checker) checks, ok := r.URL.Query()["check"] @@ -49,11 +49,11 @@ func Handler(logger *logging.Logger, allCheckers map[string]Checker) http.Handle // CheckHealth checks multiple checkers returning false if any of them fail. // CheckHealth logs the reason a checker fails. -func CheckHealth(logger *logging.Logger, checkers map[string]Checker) bool { +func CheckHealth(logger *slog.Logger, checkers map[string]Checker) bool { healthy := true for name, hc := range checkers { if err := hc.HealthCheck(); err != nil { - logger.With("component", "healthz").Log("err", err, "health-checker", name) + logger.With("component", "healthz").WarnContext(context.TODO(), "health check failed", "err", err, "health-checker", name) healthy = false continue } diff --git a/server/health/health_test.go b/server/health/health_test.go index 3ceb73bd06..38a5024193 100644 --- a/server/health/health_test.go +++ b/server/health/health_test.go @@ -2,11 +2,11 @@ package health import ( "errors" + "log/slog" "net/http" "net/http/httptest" "testing" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -17,13 +17,13 @@ func TestCheckHealth(t *testing.T) { "pass": Nop(), } - healthy := CheckHealth(logging.NewNopLogger(), checkers) + healthy := CheckHealth(slog.New(slog.DiscardHandler), checkers) require.False(t, healthy) checkers = map[string]Checker{ "pass": Nop(), } - healthy = CheckHealth(logging.NewNopLogger(), checkers) + healthy = CheckHealth(slog.New(slog.DiscardHandler), checkers) require.True(t, healthy) } @@ -34,7 +34,7 @@ func (c fail) HealthCheck() error { } func TestHealthzHandler(t *testing.T) { - logger := logging.NewNopLogger() + logger := slog.New(slog.DiscardHandler) failCheck := healthcheckFunc(func() error { return errors.New("health check failed") }) diff --git a/server/launcher/launcher.go b/server/launcher/launcher.go index ee3274519b..d5f7fd6e41 100644 --- a/server/launcher/launcher.go +++ b/server/launcher/launcher.go @@ -12,12 +12,12 @@ import ( "encoding/json" "errors" "fmt" + "log/slog" "github.com/fleetdm/fleet/v4/server/contexts/ctxerr" "github.com/fleetdm/fleet/v4/server/contexts/host" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/health" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/kolide/launcher/pkg/service" "github.com/osquery/osquery-go/plugin/distributed" "github.com/osquery/osquery-go/plugin/logger" @@ -26,7 +26,7 @@ import ( // launcherWrapper wraps the TLS interface. type launcherWrapper struct { tls fleet.OsqueryService - logger *logging.Logger + logger *slog.Logger healthCheckers map[string]health.Checker } diff --git a/server/launcher/launcher_test.go b/server/launcher/launcher_test.go index 9e858c8c52..c509679c77 100644 --- a/server/launcher/launcher_test.go +++ b/server/launcher/launcher_test.go @@ -3,11 +3,11 @@ package launcher import ( "context" "encoding/json" + "log/slog" "testing" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/health" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/service/mock" "github.com/kolide/launcher/pkg/service" "github.com/osquery/osquery-go/plugin/distributed" @@ -93,7 +93,7 @@ func newTestService(t *testing.T) (*launcherWrapper, *mock.TLSService) { tls := newTLSService(t) launcher := &launcherWrapper{ tls: tls, - logger: logging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), healthCheckers: map[string]health.Checker{ "noop": health.Nop(), }, diff --git a/server/launcher/server.go b/server/launcher/server.go index 53476dd7e7..4718da0afe 100644 --- a/server/launcher/server.go +++ b/server/launcher/server.go @@ -2,6 +2,7 @@ package launcher import ( + "log/slog" "net/http" "strings" @@ -23,10 +24,11 @@ type Handler struct { // New creates a gRPC server to handle remote requests from launcher. func New( tls fleet.OsqueryService, - logger *logging.Logger, + logger *slog.Logger, grpcServer *grpc.Server, healthCheckers map[string]health.Checker, ) *Handler { + kitLogger := logging.NewLogger(logger) var svc launcher.KolideService { svc = &launcherWrapper{ @@ -34,10 +36,10 @@ func New( logger: logger, healthCheckers: healthCheckers, } - svc = launcher.LoggingMiddleware(logger)(svc) + svc = launcher.LoggingMiddleware(kitLogger)(svc) } endpoints := launcher.MakeServerEndpoints(svc) - server := launcher.NewGRPCServer(endpoints, logger) + server := launcher.NewGRPCServer(endpoints, kitLogger) launcher.RegisterGRPCServer(grpcServer, server) return &Handler{grpcServer} } diff --git a/server/mdm/lifecycle/lifecycle.go b/server/mdm/lifecycle/lifecycle.go index 4ed2d3eda9..5b80c56d2f 100644 --- a/server/mdm/lifecycle/lifecycle.go +++ b/server/mdm/lifecycle/lifecycle.go @@ -2,15 +2,14 @@ package mdmlifecycle import ( "context" + "log/slog" "github.com/fleetdm/fleet/v4/server/contexts/ctxerr" "github.com/fleetdm/fleet/v4/server/contexts/license" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/mdm/nanomdm/mdm" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/ptr" "github.com/fleetdm/fleet/v4/server/worker" - "github.com/go-kit/log/level" ) // HostAction is a supported MDM lifecycle action that can be performed on a @@ -52,7 +51,7 @@ type HostOptions struct { // HostLifecycle manages MDM host lifecycle actions type HostLifecycle struct { ds fleet.Datastore - logger *logging.Logger + logger *slog.Logger newActivityFunc NewActivityFunc } @@ -62,7 +61,7 @@ type HostLifecycle struct { type NewActivityFunc func(ctx context.Context, user *fleet.User, details fleet.ActivityDetails) error // New creates a new HostLifecycle struct -func New(ds fleet.Datastore, logger *logging.Logger, newActivityFn NewActivityFunc) *HostLifecycle { +func New(ds fleet.Datastore, logger *slog.Logger, newActivityFn NewActivityFunc) *HostLifecycle { return &HostLifecycle{ ds: ds, logger: logger, @@ -194,17 +193,17 @@ func (t *HostLifecycle) turnOnApple(ctx context.Context, opts HostOptions) error nanoEnroll.TokenUpdateTally != 1 { // something unexpected, so we skip the turn on // and log the details for debugging - keyvals := []interface{}{"msg", "skipping turn on darwin", "host_uuid", opts.UUID} + attrs := []slog.Attr{slog.String("host_uuid", opts.UUID)} if nanoEnroll == nil { - keyvals = append(keyvals, "nano_enroll", "nil") + attrs = append(attrs, slog.String("nano_enroll", "nil")) } else { - keyvals = append(keyvals, - "enabled", nanoEnroll.Enabled, - "type", nanoEnroll.Type, - "token_update_tally", nanoEnroll.TokenUpdateTally, + attrs = append(attrs, + slog.Bool("enabled", nanoEnroll.Enabled), + slog.String("type", nanoEnroll.Type), + slog.Int("token_update_tally", nanoEnroll.TokenUpdateTally), ) } - level.Info(t.logger).Log(keyvals...) + t.logger.LogAttrs(ctx, slog.LevelInfo, "skipping turn on darwin", attrs...) return nil } @@ -241,11 +240,11 @@ func (t *HostLifecycle) turnOnApple(ctx context.Context, opts HostOptions) error // TODO: improve this to not enqueue the job if a host that is // assigned in ABM is manually enrolling for some reason. if info.DEPAssignedToFleet || info.InstalledFromDEP { - level.Info(t.logger).Log("msg", "queueing post-enroll task for newly enrolled DEP device", "host_uuid", opts.UUID) + t.logger.InfoContext(ctx, "queueing post-enroll task for newly enrolled DEP device", "host_uuid", opts.UUID) err := worker.QueueAppleMDMJob( ctx, t.ds, - t.logger.SlogLogger(), + t.logger, worker.AppleMDMPostDEPEnrollmentTask, opts.UUID, opts.Platform, @@ -259,11 +258,11 @@ func (t *HostLifecycle) turnOnApple(ctx context.Context, opts HostOptions) error // manual MDM enrollments if !info.InstalledFromDEP { - level.Info(t.logger).Log("msg", "queueing post-enroll task for manual enrolled device", "host_uuid", opts.UUID) + t.logger.InfoContext(ctx, "queueing post-enroll task for manual enrolled device", "host_uuid", opts.UUID) if err := worker.QueueAppleMDMJob( ctx, t.ds, - t.logger.SlogLogger(), + t.logger, worker.AppleMDMPostManualEnrollmentTask, opts.UUID, opts.Platform, @@ -329,7 +328,7 @@ func (t *HostLifecycle) restorePendingDEPHost(ctx context.Context, host *fleet.H return ctxerr.Wrap(ctx, err, "restore pending dep host") } - if _, err := worker.QueueMacosSetupAssistantJob(ctx, t.ds, t.logger.SlogLogger(), + if _, err := worker.QueueMacosSetupAssistantJob(ctx, t.ds, t.logger, worker.MacosSetupAssistantHostsTransferred, tmID, host.HardwareSerial); err != nil { return ctxerr.Wrap(ctx, err, "queue macos setup assistant update profile job") } @@ -366,11 +365,8 @@ func (t *HostLifecycle) getDefaultTeamForABMToken(ctx context.Context, host *fle } if !exists { - level.Info(t.logger).Log( - "msg", - "unable to find default team assigned to abm token, mdm devices won't be assigned to a team", - "team_id", - abmDefaultTeamID, + t.logger.InfoContext(ctx, "unable to find default team assigned to abm token, mdm devices won't be assigned to a team", + "team_id", abmDefaultTeamID, ) return nil, nil } diff --git a/server/mdm/lifecycle/lifecycle_test.go b/server/mdm/lifecycle/lifecycle_test.go index 0e60f48804..6daea12547 100644 --- a/server/mdm/lifecycle/lifecycle_test.go +++ b/server/mdm/lifecycle/lifecycle_test.go @@ -2,11 +2,11 @@ package mdmlifecycle import ( "context" + "log/slog" "testing" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/mock" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/stretchr/testify/require" ) @@ -16,7 +16,7 @@ func nopNewActivity(ctx context.Context, user *fleet.User, details fleet.Activit func TestDoUnsupportedParams(t *testing.T) { ds := new(mock.Store) - lc := New(ds, logging.NewNopLogger(), nopNewActivity) + lc := New(ds, slog.New(slog.DiscardHandler), nopNewActivity) err := lc.Do(context.Background(), HostOptions{}) require.ErrorContains(t, err, "unsupported platform") @@ -33,7 +33,7 @@ func TestDoUnsupportedParams(t *testing.T) { func TestDoParamValidation(t *testing.T) { ds := new(mock.Store) - lf := New(ds, logging.NewNopLogger(), nopNewActivity) + lf := New(ds, slog.New(slog.DiscardHandler), nopNewActivity) ctx := context.Background() cases := []struct { diff --git a/server/mdm/scep/client/client.go b/server/mdm/scep/client/client.go index dc63cda6a5..2c05faa0ee 100644 --- a/server/mdm/scep/client/client.go +++ b/server/mdm/scep/client/client.go @@ -1,10 +1,10 @@ package scepclient import ( + "log/slog" "time" scepserver "github.com/fleetdm/fleet/v4/server/mdm/scep/server" - "github.com/fleetdm/fleet/v4/server/platform/logging" ) // Client is a SCEP Client @@ -47,7 +47,7 @@ func WithTimeout(timeout *time.Duration) Option { // New creates a SCEP Client. func New( serverURL string, - logger *logging.Logger, + logger *slog.Logger, opts ...Option, ) (Client, error) { var co clientOpts diff --git a/server/mdm/scep/cmd/scepclient/scepclient.go b/server/mdm/scep/cmd/scepclient/scepclient.go index f521e56a1e..eeaa657c82 100644 --- a/server/mdm/scep/cmd/scepclient/scepclient.go +++ b/server/mdm/scep/cmd/scepclient/scepclient.go @@ -10,6 +10,7 @@ import ( "flag" "fmt" "io/ioutil" + "log/slog" "net/url" "os" "path/filepath" @@ -53,12 +54,12 @@ type runCfg struct { func run(cfg runCfg) error { ctx := context.Background() - var logger *logging.Logger + var logger *slog.Logger { if strings.ToLower(cfg.logfmt) == "json" { - logger = logging.NewLogger(logging.NewSlogLogger(logging.Options{Output: os.Stderr, JSON: true, Debug: cfg.debug})) + logger = logging.NewSlogLogger(logging.Options{Output: os.Stderr, JSON: true, Debug: cfg.debug}) } else { - logger = logging.NewLogger(logging.NewSlogLogger(logging.Options{Output: os.Stderr, Debug: cfg.debug})) + logger = logging.NewSlogLogger(logging.Options{Output: os.Stderr, Debug: cfg.debug}) } } lginfo := logger @@ -159,7 +160,7 @@ func run(cfg runCfg) error { } } - msg, err := scep.NewCSRRequest(csr, tmpl, scep.WithLogger(logger), scep.WithCertsSelector(cfg.caCertsSelector)) + msg, err := scep.NewCSRRequest(csr, tmpl, scep.WithLogger(logging.NewLogger(logger)), scep.WithCertsSelector(cfg.caCertsSelector)) if err != nil { return errors.Join(err, errors.New("creating csr pkiMessage")) } @@ -175,7 +176,7 @@ func run(cfg runCfg) error { return errors.Join(err, fmt.Errorf("PKIOperation for %s", msgType)) } - respMsg, err = scep.ParsePKIMessage(respBytes, scep.WithLogger(logger), scep.WithCACerts(caCerts)) + respMsg, err = scep.ParsePKIMessage(respBytes, scep.WithLogger(logging.NewLogger(logger)), scep.WithCACerts(caCerts)) if err != nil { return errors.Join(err, fmt.Errorf("parsing pkiMessage response %s", msgType)) } @@ -184,11 +185,11 @@ func run(cfg runCfg) error { case scep.FAILURE: return fmt.Errorf("%s request failed, failInfo: %s", msgType, respMsg.FailInfo) case scep.PENDING: - lginfo.Log("pkiStatus", "PENDING", "msg", "sleeping for 30 seconds, then trying again.") + lginfo.InfoContext(ctx, "sleeping for 30 seconds, then trying again", "pkiStatus", "PENDING") time.Sleep(30 * time.Second) continue } - lginfo.Log("pkiStatus", "SUCCESS", "msg", "server returned a certificate.") + lginfo.InfoContext(ctx, "server returned a certificate", "pkiStatus", "SUCCESS") break // on scep.SUCCESS } @@ -212,13 +213,13 @@ func run(cfg runCfg) error { } // logCerts logs the count, number, RDN, and fingerprint of certs to logger -func logCerts(logger *logging.Logger, certs []*x509.Certificate) { - logger.Log("msg", "cacertlist", "count", len(certs)) +func logCerts(logger *slog.Logger, certs []*x509.Certificate) { + ctx := context.TODO() + logger.InfoContext(ctx, "cacertlist", "count", len(certs)) for i, cert := range certs { h := fingerprintHashType.New() h.Write(cert.Raw) - logger.Log( - "msg", "cacertlist", + logger.InfoContext(ctx, "cacertlist", "number", i, "rdn", cert.Subject.ToRDNSequence().String(), "hash_type", fingerprintHashType.String(), diff --git a/server/mdm/scep/cmd/scepserver/scepserver.go b/server/mdm/scep/cmd/scepserver/scepserver.go index 5c774cc520..ee256cdaf4 100644 --- a/server/mdm/scep/cmd/scepserver/scepserver.go +++ b/server/mdm/scep/cmd/scepserver/scepserver.go @@ -1,12 +1,14 @@ package main import ( + "context" "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/pem" "flag" "fmt" + "log/slog" "net/http" "os" "os/signal" @@ -84,40 +86,41 @@ func main() { httpAddr = ":" + *flPort } - var logger *logging.Logger + var logger *slog.Logger { if *flLogJSON { - logger = logging.NewLogger(logging.NewSlogLogger(logging.Options{Output: os.Stderr, JSON: true, Debug: *flDebug, AddSource: true})) + logger = logging.NewSlogLogger(logging.Options{Output: os.Stderr, JSON: true, Debug: *flDebug, AddSource: true}) } else { - logger = logging.NewLogger(logging.NewSlogLogger(logging.Options{Output: os.Stderr, Debug: *flDebug, AddSource: true})) + logger = logging.NewSlogLogger(logging.Options{Output: os.Stderr, Debug: *flDebug, AddSource: true}) } } lginfo := logger + ctx := context.TODO() var err error var depot scepdepot.Depot // cert storage { depot, err = file.NewFileDepot(*flDepotPath) if err != nil { - lginfo.Log("err", err) + lginfo.ErrorContext(ctx, "failed to create depot", "err", err) os.Exit(1) } } allowRenewal, err := strconv.Atoi(*flClAllowRenewal) if err != nil { - lginfo.Log("err", err, "msg", "No valid number for allowed renewal time") + lginfo.ErrorContext(ctx, "No valid number for allowed renewal time", "err", err) os.Exit(1) } clientValidity, err := strconv.Atoi(*flClDuration) if err != nil { - lginfo.Log("err", err, "msg", "No valid number for client cert validity") + lginfo.ErrorContext(ctx, "No valid number for client cert validity", "err", err) os.Exit(1) } var csrVerifier csrverifier.CSRVerifier if *flCSRVerifierExec > "" { executableCSRVerifier, err := executablecsrverifier.New(*flCSRVerifierExec, lginfo) if err != nil { - lginfo.Log("err", err, "msg", "Could not instantiate CSR verifier") + lginfo.ErrorContext(ctx, "Could not instantiate CSR verifier", "err", err) os.Exit(1) } csrVerifier = executableCSRVerifier @@ -127,11 +130,11 @@ func main() { { crts, key, err := depot.CA([]byte(*flCAPass)) if err != nil { - lginfo.Log("err", err) + lginfo.ErrorContext(ctx, "failed to load CA", "err", err) os.Exit(1) } if len(crts) < 1 { - lginfo.Log("err", "missing CA certificate") + lginfo.ErrorContext(ctx, "missing CA certificate") os.Exit(1) } signerOpts := []scepdepot.Option{ @@ -151,7 +154,7 @@ func main() { } svc, err = scepserver.NewService(crts[0], key, signer, scepserver.WithLogger(logger)) if err != nil { - lginfo.Log("err", err) + lginfo.ErrorContext(ctx, "failed to create SCEP service", "err", err) os.Exit(1) } svc = scepserver.NewLoggingService(lginfo.With("component", "scep_service"), svc) @@ -171,7 +174,7 @@ func main() { // start http server errs := make(chan error, 2) go func() { - lginfo.Log("transport", "http", "address", httpAddr, "msg", "listening") + lginfo.InfoContext(ctx, "listening", "transport", "http", "address", httpAddr) errs <- http.ListenAndServe(httpAddr, h) //nolint:gosec }() go func() { @@ -180,7 +183,7 @@ func main() { errs <- fmt.Errorf("%s", <-c) }() - lginfo.Log("terminated", <-errs) + lginfo.InfoContext(ctx, "terminated", "err", <-errs) } func caMain(cmd *flag.FlagSet) int { diff --git a/server/mdm/scep/csrverifier/executable/csrverifier.go b/server/mdm/scep/csrverifier/executable/csrverifier.go index ae5317743d..9a95f5df4b 100644 --- a/server/mdm/scep/csrverifier/executable/csrverifier.go +++ b/server/mdm/scep/csrverifier/executable/csrverifier.go @@ -2,11 +2,11 @@ package executablecsrverifier import ( + "context" "errors" + "log/slog" "os" "os/exec" - - "github.com/fleetdm/fleet/v4/server/platform/logging" ) const ( @@ -16,7 +16,7 @@ const ( ) // New creates a executablecsrverifier.ExecutableCSRVerifier. -func New(path string, logger *logging.Logger) (*ExecutableCSRVerifier, error) { +func New(path string, logger *slog.Logger) (*ExecutableCSRVerifier, error) { fileInfo, err := os.Stat(path) if err != nil { return nil, err @@ -41,7 +41,7 @@ func New(path string, logger *logging.Logger) (*ExecutableCSRVerifier, error) { // In any other cases, the CSR is considered invalid. type ExecutableCSRVerifier struct { executable string - logger *logging.Logger + logger *slog.Logger } func (v *ExecutableCSRVerifier) Verify(data []byte) (bool, error) { @@ -59,7 +59,7 @@ func (v *ExecutableCSRVerifier) Verify(data []byte) (bool, error) { err = cmd.Run() if err != nil { - v.logger.Log("err", err) + v.logger.ErrorContext(context.TODO(), "CSR verification failed", "err", err) // mask the executable error return false, nil } diff --git a/server/mdm/scep/server/endpoint.go b/server/mdm/scep/server/endpoint.go index 1d4e0ac21e..933f781e1e 100644 --- a/server/mdm/scep/server/endpoint.go +++ b/server/mdm/scep/server/endpoint.go @@ -7,6 +7,7 @@ import ( "crypto/x509" "errors" "fmt" + "log/slog" "net/url" "os" "strings" @@ -14,7 +15,6 @@ import ( "time" "github.com/fleetdm/fleet/v4/pkg/fleethttp" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/go-kit/kit/endpoint" httptransport "github.com/go-kit/kit/transport/http" ) @@ -275,18 +275,18 @@ func (r SCEPResponse) scepOperation() string { return r.operation } // EndpointLoggingMiddleware returns an endpoint middleware that logs the // duration of each invocation, and the resulting error, if any. -func EndpointLoggingMiddleware(logger *logging.Logger) endpoint.Middleware { +func EndpointLoggingMiddleware(logger *slog.Logger) endpoint.Middleware { return func(next endpoint.Endpoint) endpoint.Endpoint { - return func(ctx context.Context, request interface{}) (response interface{}, err error) { - var keyvals []interface{} - // check if this is a scep endpoint, if it is, append the method to the log. + return func(ctx context.Context, request any) (response any, err error) { + var attrs []slog.Attr if oper, ok := request.(interface { scepOperation() string }); ok { - keyvals = append(keyvals, "op", oper.scepOperation()) + attrs = append(attrs, slog.String("op", oper.scepOperation())) } defer func(begin time.Time) { - logger.Log(append(keyvals, "error", err, "took", time.Since(begin))...) + attrs = append(attrs, slog.Any("error", err), slog.Duration("took", time.Since(begin))) + logger.LogAttrs(ctx, slog.LevelInfo, "scep endpoint", attrs...) }(time.Now()) return next(ctx, request) } diff --git a/server/mdm/scep/server/service.go b/server/mdm/scep/server/service.go index 212f58b325..bcb47eb7f7 100644 --- a/server/mdm/scep/server/service.go +++ b/server/mdm/scep/server/service.go @@ -5,6 +5,7 @@ import ( "crypto/rsa" "crypto/x509" "errors" + "log/slog" "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/smallstep/scep" @@ -88,7 +89,7 @@ type service struct { signer CSRSignerContext /// info logging is implemented in the service middleware layer. - debugLogger *logging.Logger + debugLogger *slog.Logger } const DefaultCACaps = "Renewal\nSHA-1\nSHA-256\nAES\nDES3\nSCEPStandard\nPOSTPKIOperation" @@ -115,7 +116,7 @@ func (svc *service) PKIOperation(ctx context.Context, data []byte) ([]byte, erro if len(data) == 0 { return nil, &BadRequestError{Message: "missing data for PKIOperation"} } - msg, err := scep.ParsePKIMessage(data, scep.WithLogger(svc.debugLogger)) + msg, err := scep.ParsePKIMessage(data, scep.WithLogger(logging.NewLogger(svc.debugLogger))) if err != nil { return nil, err } @@ -128,7 +129,7 @@ func (svc *service) PKIOperation(ctx context.Context, data []byte) ([]byte, erro err = errors.New("no signed certificate") } if err != nil { - svc.debugLogger.Log("msg", "failed to sign CSR", "err", err) + svc.debugLogger.ErrorContext(ctx, "failed to sign CSR", "err", err) certRep, err := msg.Fail(svc.crt, svc.key, scep.BadRequest) return certRep.Raw, err } @@ -146,7 +147,7 @@ type ServiceOption func(*service) error // WithLogger configures a logger for the SCEP Service. // By default, a no-op logger is used. -func WithLogger(logger *logging.Logger) ServiceOption { +func WithLogger(logger *slog.Logger) ServiceOption { return func(s *service) error { s.debugLogger = logger return nil @@ -167,7 +168,7 @@ func NewService(crt *x509.Certificate, key *rsa.PrivateKey, signer CSRSignerCont crt: crt, key: key, signer: signer, - debugLogger: logging.NewNopLogger(), + debugLogger: slog.New(slog.DiscardHandler), } for _, opt := range opts { if err := opt(s); err != nil { diff --git a/server/mdm/scep/server/service_logging.go b/server/mdm/scep/server/service_logging.go index 121fe9143a..ba8980c5fd 100644 --- a/server/mdm/scep/server/service_logging.go +++ b/server/mdm/scep/server/service_logging.go @@ -2,25 +2,23 @@ package scepserver import ( "context" + "log/slog" "time" - - "github.com/fleetdm/fleet/v4/server/platform/logging" ) type loggingService struct { - logger *logging.Logger + logger *slog.Logger Service } // NewLoggingService creates adds logging to the SCEP service -func NewLoggingService(logger *logging.Logger, s Service) Service { +func NewLoggingService(logger *slog.Logger, s Service) Service { return &loggingService{logger, s} } func (mw *loggingService) GetCACaps(ctx context.Context) (caps []byte, err error) { defer func(begin time.Time) { - _ = mw.logger.Log( - "method", "GetCACaps", + mw.logger.InfoContext(ctx, "GetCACaps", "err", err, "took", time.Since(begin), ) @@ -31,8 +29,7 @@ func (mw *loggingService) GetCACaps(ctx context.Context) (caps []byte, err error func (mw *loggingService) GetCACert(ctx context.Context, message string) (cert []byte, certNum int, err error) { defer func(begin time.Time) { - _ = mw.logger.Log( - "method", "GetCACert", + mw.logger.InfoContext(ctx, "GetCACert", "message", message, "err", err, "took", time.Since(begin), @@ -44,8 +41,7 @@ func (mw *loggingService) GetCACert(ctx context.Context, message string) (cert [ func (mw *loggingService) PKIOperation(ctx context.Context, data []byte) (certRep []byte, err error) { defer func(begin time.Time) { - _ = mw.logger.Log( - "method", "PKIOperation", + mw.logger.InfoContext(ctx, "PKIOperation", "err", err, "took", time.Since(begin), ) diff --git a/server/mdm/scep/server/transport.go b/server/mdm/scep/server/transport.go index e752d774d7..42c6301808 100644 --- a/server/mdm/scep/server/transport.go +++ b/server/mdm/scep/server/transport.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "io" + "log/slog" "net/http" "net/url" @@ -17,10 +18,11 @@ import ( "github.com/groob/finalizer/logutil" ) -func MakeHTTPHandler(e *Endpoints, svc Service, logger *logging.Logger) http.Handler { +func MakeHTTPHandler(e *Endpoints, svc Service, logger *slog.Logger) http.Handler { + kitLogger := logging.NewLogger(logger) opts := []kithttp.ServerOption{ - kithttp.ServerErrorLogger(logger), - kithttp.ServerFinalizer(logutil.NewHTTPLogger(logger).LoggingFinalizer), + kithttp.ServerErrorLogger(kitLogger), + kithttp.ServerFinalizer(logutil.NewHTTPLogger(kitLogger).LoggingFinalizer), } r := mux.NewRouter() @@ -40,10 +42,11 @@ func MakeHTTPHandler(e *Endpoints, svc Service, logger *logging.Logger) http.Han return r } -func MakeHTTPHandlerWithIdentifier(e *Endpoints, rootPath string, logger *logging.Logger) http.Handler { +func MakeHTTPHandlerWithIdentifier(e *Endpoints, rootPath string, logger *slog.Logger) http.Handler { + kitLogger := logging.NewLogger(logger) opts := []kithttp.ServerOption{ - kithttp.ServerErrorHandler(transport.NewLogErrorHandler(logger)), - kithttp.ServerFinalizer(logutil.NewHTTPLogger(logger).LoggingFinalizer), + kithttp.ServerErrorHandler(transport.NewLogErrorHandler(kitLogger)), + kithttp.ServerFinalizer(logutil.NewHTTPLogger(kitLogger).LoggingFinalizer), } r := mux.NewRouter() diff --git a/server/mdm/scep/server/transport_test.go b/server/mdm/scep/server/transport_test.go index 92e8b387f8..d2a77dc55b 100644 --- a/server/mdm/scep/server/transport_test.go +++ b/server/mdm/scep/server/transport_test.go @@ -6,6 +6,7 @@ import ( "crypto/x509" "encoding/base64" "io/ioutil" + "log/slog" "net/http" "net/http/httptest" "os" @@ -15,7 +16,6 @@ import ( "github.com/fleetdm/fleet/v4/server/mdm/scep/depot" filedepot "github.com/fleetdm/fleet/v4/server/mdm/scep/depot/file" scepserver "github.com/fleetdm/fleet/v4/server/mdm/scep/server" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/gorilla/mux" ) @@ -239,9 +239,9 @@ func newServer(t *testing.T, opts ...scepserver.ServiceOption) (*httptest.Server t.Fatal(err) } } - logger := logging.NewNopLogger() + slogLogger := slog.New(slog.DiscardHandler) e := scepserver.MakeServerEndpoints(svc) - scepHandler := scepserver.MakeHTTPHandler(e, svc, logger) + scepHandler := scepserver.MakeHTTPHandler(e, svc, slogLogger) r := mux.NewRouter() r.Handle("/scep", scepHandler) server := httptest.NewServer(r) diff --git a/server/service/apple_mdm.go b/server/service/apple_mdm.go index 2c14297add..266b748542 100644 --- a/server/service/apple_mdm.go +++ b/server/service/apple_mdm.go @@ -12,6 +12,7 @@ import ( "errors" "fmt" "io" + "log/slog" "mime/multipart" "net/http" "net/url" @@ -31,7 +32,6 @@ import ( "github.com/fleetdm/fleet/v4/pkg/optjson" "github.com/fleetdm/fleet/v4/server" platform_http "github.com/fleetdm/fleet/v4/server/platform/http" - platformlogging "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/authz" "github.com/fleetdm/fleet/v4/server/config" @@ -3316,7 +3316,7 @@ func (svc *Service) MDMAppleDisableFileVaultAndEscrow(ctx context.Context, teamI type MDMAppleCheckinAndCommandService struct { ds fleet.Datastore - logger *platformlogging.Logger + logger *slog.Logger commander *apple_mdm.MDMAppleCommander vppInstaller fleet.AppleMDMVPPInstaller mdmLifecycle *mdmlifecycle.HostLifecycle @@ -3331,7 +3331,7 @@ func NewMDMAppleCheckinAndCommandService( commander *apple_mdm.MDMAppleCommander, vppInstaller fleet.AppleMDMVPPInstaller, isPremium bool, - logger *platformlogging.Logger, + logger *slog.Logger, keyValueStore fleet.KeyValueStore, newActivityFn mdmlifecycle.NewActivityFunc, ) *MDMAppleCheckinAndCommandService { @@ -4703,7 +4703,7 @@ func mdmAppleDeliveryStatusFromCommandStatus(cmdStatus string) *fleet.MDMDeliver // This profile will be installed to all hosts in the team (or "no team",) but it // will only be used by hosts that have a fleetd installation without an enroll // secret and fleet URL (mainly DEP enrolled hosts). -func ensureFleetProfiles(ctx context.Context, ds fleet.Datastore, logger *platformlogging.Logger, signingCertDER []byte) error { +func ensureFleetProfiles(ctx context.Context, ds fleet.Datastore, logger *slog.Logger, signingCertDER []byte) error { appCfg, err := ds.AppConfig(ctx) if err != nil { return ctxerr.Wrap(ctx, err, "fetching app config") @@ -4742,10 +4742,10 @@ func ensureFleetProfiles(ctx context.Context, ds fleet.Datastore, logger *platfo msg += fmt.Sprintf("team_id %d doesn't have an enroll secret, ", *es.TeamID) } if globalSecret == "" { - logger.Log("err", msg+"no global enroll secret found, skipping the creation of a com.fleetdm.fleetd.config profile") + logger.WarnContext(ctx, msg+"no global enroll secret found, skipping the creation of a com.fleetdm.fleetd.config profile") continue } - logger.Log("err", msg+"using a global enroll secret for com.fleetdm.fleetd.config profile") + logger.WarnContext(ctx, msg+"using a global enroll secret for com.fleetdm.fleetd.config profile") es.Secret = globalSecret } @@ -4785,7 +4785,7 @@ func SendPushesToPendingDevices( ctx context.Context, ds fleet.Datastore, commander *apple_mdm.MDMAppleCommander, - logger *platformlogging.Logger, + logger *slog.Logger, ) error { enrollmentIDs, err := ds.GetEnrollmentIDsWithPendingMDMAppleCommands(ctx) if err != nil { @@ -4814,7 +4814,7 @@ func ReconcileAppleDeclarations( ctx context.Context, ds fleet.Datastore, commander *apple_mdm.MDMAppleCommander, - logger *platformlogging.Logger, + logger *slog.Logger, ) error { appConfig, err := ds.AppConfig(ctx) if err != nil { @@ -4884,7 +4884,7 @@ func ReconcileAppleProfiles( ctx context.Context, ds fleet.Datastore, commander *apple_mdm.MDMAppleCommander, - logger *platformlogging.Logger, + logger *slog.Logger, ) error { appConfig, err := ds.AppConfig(ctx) if err != nil { @@ -4911,7 +4911,7 @@ func ReconcileAppleProfiles( } if err := ensureFleetProfiles(ctx, ds, logger, block.Bytes); err != nil { - logger.Log("err", "unable to ensure a fleetd configuration profiles are in place", "details", err) + logger.ErrorContext(ctx, "unable to ensure a fleetd configuration profiles are in place", "details", err) } // retrieve the profiles to install/remove. @@ -5319,7 +5319,7 @@ func ReconcileAppleProfiles( func findProfilesWithSecrets( ctx context.Context, - logger *platformlogging.Logger, + logger *slog.Logger, installTargets map[string]*cmdTarget, profileContents map[string]mobileconfig.Mobileconfig, ) (map[string]struct{}, error) { @@ -5345,7 +5345,7 @@ func preprocessProfileContents( ds fleet.Datastore, scepConfig fleet.SCEPConfigService, digiCertService fleet.DigiCertService, - logger *platformlogging.Logger, + logger *slog.Logger, targets map[string]*cmdTarget, profileContents map[string]mobileconfig.Mobileconfig, hostProfilesToInstallMap map[hostProfileUUID]*fleet.MDMAppleBulkUpsertHostProfilePayload, @@ -5610,7 +5610,7 @@ func preprocessProfileContents( hostContents = profiles.ReplaceFleetVariableInXML(fleetVarSCEPRenewalIDRegexp, hostContents, fleetRenewalID) case strings.HasPrefix(fleetVar, string(fleet.FleetVarCustomSCEPChallengePrefix)): - replacedContents, replacedVariable, err := profiles.ReplaceCustomSCEPChallengeVariable(ctx, logger.SlogLogger(), fleetVar, customSCEPCAs, hostContents) + replacedContents, replacedVariable, err := profiles.ReplaceCustomSCEPChallengeVariable(ctx, logger, fleetVar, customSCEPCAs, hostContents) if err != nil { return ctxerr.Wrap(ctx, err, "replacing custom SCEP challenge variable") } @@ -5620,7 +5620,7 @@ func preprocessProfileContents( hostContents = replacedContents case strings.HasPrefix(fleetVar, string(fleet.FleetVarCustomSCEPProxyURLPrefix)): - replacedContents, managedCertificate, replacedVariable, err := profiles.ReplaceCustomSCEPProxyURLVariable(ctx, logger.SlogLogger(), ds, appConfig, fleetVar, customSCEPCAs, hostContents, hostUUID, profUUID) + replacedContents, managedCertificate, replacedVariable, err := profiles.ReplaceCustomSCEPProxyURLVariable(ctx, logger, ds, appConfig, fleetVar, customSCEPCAs, hostContents, hostUUID, profUUID) if err != nil { return ctxerr.Wrap(ctx, err, "replacing custom SCEP proxy URL variable") } @@ -6092,7 +6092,7 @@ const maxCertsRenewalPerRun = 100 func RenewSCEPCertificates( ctx context.Context, - logger *platformlogging.Logger, + logger *slog.Logger, ds fleet.Datastore, config *config.FleetConfig, commander *apple_mdm.MDMAppleCommander, @@ -6278,7 +6278,7 @@ func renewSCEPWithProfile( ctx context.Context, ds fleet.Datastore, commander *apple_mdm.MDMAppleCommander, - logger *platformlogging.Logger, + logger *slog.Logger, assocs []fleet.SCEPIdentityAssociation, profile []byte, ) error { @@ -6292,7 +6292,7 @@ func renewSCEPWithProfile( // single duplicated UUID prevents _all_ the commands from // being enqueued. if _, ok := duplicateUUIDCheck[assoc.HostUUID]; ok { - logger.Log("inf", "duplicated host UUID while renewing associations", "host_uuid", assoc.HostUUID) + logger.InfoContext(ctx, "duplicated host UUID while renewing associations", "host_uuid", assoc.HostUUID) continue } @@ -6316,10 +6316,10 @@ func renewSCEPWithProfile( // [1]: https://developer.apple.com/documentation/devicemanagement/declarative_management_checkin type MDMAppleDDMService struct { ds fleet.Datastore - logger *platformlogging.Logger + logger *slog.Logger } -func NewMDMAppleDDMService(ds fleet.Datastore, logger *platformlogging.Logger) *MDMAppleDDMService { +func NewMDMAppleDDMService(ds fleet.Datastore, logger *slog.Logger) *MDMAppleDDMService { return &MDMAppleDDMService{ ds: ds, logger: logger, @@ -7246,10 +7246,10 @@ func (svc *Service) MDMAppleProcessOTAEnrollment( // EnsureMDMAppleServiceDiscovery checks if the service discovery URL is set up correctly with Apple // and assigns it if necessary. -func EnsureMDMAppleServiceDiscovery(ctx context.Context, ds fleet.Datastore, depStorage storage.AllDEPStorage, logger *platformlogging.Logger, +func EnsureMDMAppleServiceDiscovery(ctx context.Context, ds fleet.Datastore, depStorage storage.AllDEPStorage, logger *slog.Logger, urlPrefix string, ) error { - depSvc := apple_mdm.NewDEPService(ds, depStorage, logger.SlogLogger()) + depSvc := apple_mdm.NewDEPService(ds, depStorage, logger) ac, err := ds.AppConfig(ctx) if err != nil { diff --git a/server/service/apple_mdm_cmd_results.go b/server/service/apple_mdm_cmd_results.go index b8562d9460..b5744eee2a 100644 --- a/server/service/apple_mdm_cmd_results.go +++ b/server/service/apple_mdm_cmd_results.go @@ -3,6 +3,7 @@ package service import ( "context" "fmt" + "log/slog" "strings" "time" @@ -11,7 +12,6 @@ import ( apple_mdm "github.com/fleetdm/fleet/v4/server/mdm/apple" mdmlifecycle "github.com/fleetdm/fleet/v4/server/mdm/lifecycle" "github.com/fleetdm/fleet/v4/server/mdm/nanomdm/mdm" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/worker" "github.com/micromdm/plist" ) @@ -63,7 +63,7 @@ func NewInstalledApplicationListResult(ctx context.Context, rawResult []byte, uu func NewInstalledApplicationListResultsHandler( ds fleet.Datastore, commander *apple_mdm.MDMAppleCommander, - logger *logging.Logger, + logger *slog.Logger, verifyTimeout, verifyRequestDelay time.Duration, newActivityFn mdmlifecycle.NewActivityFunc, ) fleet.MDMCommandResultsHandler { @@ -250,7 +250,7 @@ func NewInstalledApplicationListResultsHandler( // Queue a job to verify the VPP install. return ctxerr.Wrap( ctx, - worker.QueueVPPInstallVerificationJob(ctx, ds, logger.SlogLogger(), verifyRequestDelay, + worker.QueueVPPInstallVerificationJob(ctx, ds, logger, verifyRequestDelay, installedAppResult.HostUUID(), installedAppResult.UUID(), requireXcodeSpecialCase), "InstalledApplicationList handler: queueing vpp install verification job", ) @@ -332,7 +332,7 @@ func NewDeviceLocationResult(result *mdm.CommandResults, hostID uint) (DeviceLoc func NewDeviceLocationResultsHandler( ds fleet.Datastore, commander *apple_mdm.MDMAppleCommander, - logger *logging.Logger, + logger *slog.Logger, ) fleet.MDMCommandResultsHandler { return func(ctx context.Context, commandResults fleet.MDMCommandResults) error { deviceLocResult, ok := commandResults.(DeviceLocationResult) diff --git a/server/service/apple_mdm_ddm_test.go b/server/service/apple_mdm_ddm_test.go index 2eaaa8793e..6a337c293d 100644 --- a/server/service/apple_mdm_ddm_test.go +++ b/server/service/apple_mdm_ddm_test.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "log/slog" "os" "testing" "time" @@ -11,7 +12,6 @@ import ( "github.com/fleetdm/fleet/v4/server/datastore/mysql" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/mdm/nanomdm/mdm" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/ptr" "github.com/jmoiron/sqlx" "github.com/stretchr/testify/require" @@ -20,10 +20,9 @@ import ( func TestDeclarativeManagement_DeclarationItems(t *testing.T) { ctx := t.Context() ds := mysql.CreateMySQLDS(t) - logger := logging.NewLogfmtLogger(os.Stdout) ddmService := MDMAppleDDMService{ ds: ds, - logger: logger, + logger: slog.New(slog.NewTextHandler(os.Stdout, nil)), } // Helper function to create a host diff --git a/server/service/apple_mdm_test.go b/server/service/apple_mdm_test.go index 7a73328529..9a6f769826 100644 --- a/server/service/apple_mdm_test.go +++ b/server/service/apple_mdm_test.go @@ -15,6 +15,7 @@ import ( "encoding/pem" "errors" "fmt" + "log/slog" "math/big" "net/http" "net/http/httptest" @@ -49,7 +50,6 @@ import ( mdmmock "github.com/fleetdm/fleet/v4/server/mock/mdm" nanodep_mock "github.com/fleetdm/fleet/v4/server/mock/nanodep" scep_mock "github.com/fleetdm/fleet/v4/server/mock/scep" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/ptr" "github.com/fleetdm/fleet/v4/server/service/redis_key_value" "github.com/fleetdm/fleet/v4/server/test" @@ -104,7 +104,7 @@ func setupAppleMDMService(t *testing.T, license *fleet.LicenseInfo) (fleet.Servi mdmStorage, mdmStorage, pushFactory, - NewNanoMDMLogger(logging.NewJSONLogger(os.Stdout)), + NewNanoMDMLogger(slog.New(slog.NewJSONHandler(os.Stdout, nil))), ) opts := &TestServerOpts{ @@ -1190,12 +1190,12 @@ func TestMDMCommandAuthz(t *testing.T) { func TestMDMAuthenticateManualEnrollment(t *testing.T) { ds := new(mock.Store) - mdmLifecycle := mdmlifecycle.New(ds, logging.NewNopLogger(), func(_ context.Context, _ *fleet.User, _ fleet.ActivityDetails) error { return nil }) + mdmLifecycle := mdmlifecycle.New(ds, slog.New(slog.DiscardHandler), func(_ context.Context, _ *fleet.User, _ fleet.ActivityDetails) error { return nil }) svc := MDMAppleCheckinAndCommandService{ ds: ds, mdmLifecycle: mdmLifecycle, keyValueStore: redis_key_value.New(redistest.NopRedis()), - logger: logging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), } ctx := context.Background() uuid, serial, model := "ABC-DEF-GHI", "XYZABC", "MacBookPro 16,1" @@ -1240,12 +1240,12 @@ func TestMDMAuthenticateManualEnrollment(t *testing.T) { func TestMDMAuthenticateADE(t *testing.T) { ds := new(mock.Store) - mdmLifecycle := mdmlifecycle.New(ds, logging.NewNopLogger(), func(_ context.Context, _ *fleet.User, _ fleet.ActivityDetails) error { return nil }) + mdmLifecycle := mdmlifecycle.New(ds, slog.New(slog.DiscardHandler), func(_ context.Context, _ *fleet.User, _ fleet.ActivityDetails) error { return nil }) svc := MDMAppleCheckinAndCommandService{ ds: ds, mdmLifecycle: mdmLifecycle, keyValueStore: redis_key_value.New(redistest.NopRedis()), - logger: logging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), } ctx := context.Background() uuid, serial, model := "ABC-DEF-GHI", "XYZABC", "MacBookPro 16,1" @@ -1291,14 +1291,14 @@ func TestMDMAuthenticateADE(t *testing.T) { func TestMDMAuthenticateSCEPRenewal(t *testing.T) { ds := new(mock.Store) var newActivityInvoked bool - mdmLifecycle := mdmlifecycle.New(ds, logging.NewNopLogger(), func(_ context.Context, _ *fleet.User, _ fleet.ActivityDetails) error { + mdmLifecycle := mdmlifecycle.New(ds, slog.New(slog.DiscardHandler), func(_ context.Context, _ *fleet.User, _ fleet.ActivityDetails) error { newActivityInvoked = true return nil }) svc := MDMAppleCheckinAndCommandService{ ds: ds, mdmLifecycle: mdmLifecycle, - logger: logging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), } ctx := context.Background() uuid, serial, model := "ABC-DEF-GHI", "XYZABC", "MacBookPro 16,1" @@ -1400,12 +1400,12 @@ func TestMDMTokenUpdate(t *testing.T) { mdmStorage, mdmStorage, pushFactory, - NewNanoMDMLogger(logging.NewJSONLogger(os.Stdout)), + NewNanoMDMLogger(slog.New(slog.NewJSONHandler(os.Stdout, nil))), ) cmdr := apple_mdm.NewMDMAppleCommander(mdmStorage, pusher) uuid, serial, model, wantTeamID := "ABC-DEF-GHI", "XYZABC", "MacBookPro 16,1", uint(12) var newActivityFuncInvoked bool - mdmLifecycle := mdmlifecycle.New(ds, logging.NewNopLogger(), func(_ context.Context, user *fleet.User, activity fleet.ActivityDetails) error { + mdmLifecycle := mdmlifecycle.New(ds, slog.New(slog.DiscardHandler), func(_ context.Context, user *fleet.User, activity fleet.ActivityDetails) error { newActivityFuncInvoked = true a, ok := activity.(*fleet.ActivityTypeMDMEnrolled) require.True(t, ok) @@ -1423,7 +1423,7 @@ func TestMDMTokenUpdate(t *testing.T) { ds: ds, mdmLifecycle: mdmLifecycle, commander: cmdr, - logger: logging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), } ds.AppConfigFunc = func(context.Context) (*fleet.AppConfig, error) { @@ -1586,15 +1586,15 @@ func TestMDMTokenUpdateIOS(t *testing.T) { mdmStorage, mdmStorage, pushFactory, - NewNanoMDMLogger(logging.NewJSONLogger(os.Stdout)), + NewNanoMDMLogger(slog.New(slog.NewJSONHandler(os.Stdout, nil))), ) cmdr := apple_mdm.NewMDMAppleCommander(mdmStorage, pusher) - mdmLifecycle := mdmlifecycle.New(ds, logging.NewNopLogger(), func(_ context.Context, _ *fleet.User, _ fleet.ActivityDetails) error { return nil }) + mdmLifecycle := mdmlifecycle.New(ds, slog.New(slog.DiscardHandler), func(_ context.Context, _ *fleet.User, _ fleet.ActivityDetails) error { return nil }) svc := MDMAppleCheckinAndCommandService{ ds: ds, mdmLifecycle: mdmLifecycle, commander: cmdr, - logger: logging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), } uuid, serial, model, wantTeamID := "ABC-DEF-GHI", "XYZABC", "MacBookPro 16,1", uint(12) @@ -1741,12 +1741,12 @@ func TestMDMTokenUpdateIOS(t *testing.T) { func TestMDMCheckout(t *testing.T) { ds := new(mock.Store) - mdmLifecycle := mdmlifecycle.New(ds, logging.NewNopLogger(), func(_ context.Context, _ *fleet.User, _ fleet.ActivityDetails) error { return nil }) + mdmLifecycle := mdmlifecycle.New(ds, slog.New(slog.DiscardHandler), func(_ context.Context, _ *fleet.User, _ fleet.ActivityDetails) error { return nil }) var newActivityFuncInvoked bool svc := MDMAppleCheckinAndCommandService{ ds: ds, mdmLifecycle: mdmLifecycle, - logger: logging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), } ctx := context.Background() uuid, serial, installedFromDEP, displayName, platform := "ABC-DEF-GHI", "XYZABC", true, "Test's MacBook", "darwin" @@ -1888,7 +1888,7 @@ func TestMDMCommandAndReportResultsProfileHandling(t *testing.T) { for i, c := range cases { t.Run(fmt.Sprintf("%s%s-%d", c.requestType, c.status, i), func(t *testing.T) { ds := new(mock.Store) - svc := MDMAppleCheckinAndCommandService{ds: ds, logger: logging.NewNopLogger()} + svc := MDMAppleCheckinAndCommandService{ds: ds, logger: slog.New(slog.DiscardHandler)} ds.GetMDMAppleCommandRequestTypeFunc = func(ctx context.Context, targetCmd string) (string, error) { require.Equal(t, commandUUID, targetCmd) return c.requestType, nil @@ -2635,7 +2635,7 @@ func TestMDMAppleReconcileAppleProfiles(t *testing.T) { mdmStorage, mdmStorage, pushFactory, - NewNanoMDMLogger(logging.NewNopLogger()), + NewNanoMDMLogger(slog.New(slog.DiscardHandler)), ) mdmConfig := config.MDMConfig{ AppleSCEPCert: "./testdata/server.pem", @@ -2983,7 +2983,7 @@ func TestMDMAppleReconcileAppleProfiles(t *testing.T) { failedCount++ require.Len(t, payload, 0) } - err := ReconcileAppleProfiles(ctx, ds, cmdr, logging.NewNopLogger()) + err := ReconcileAppleProfiles(ctx, ds, cmdr, slog.New(slog.DiscardHandler)) require.NoError(t, err) require.Equal(t, 1, failedCount) checkAndReset(t, true, &ds.ListMDMAppleProfilesToInstallAndRemoveFuncInvoked) @@ -3030,7 +3030,7 @@ func TestMDMAppleReconcileAppleProfiles(t *testing.T) { } enqueueFailForOp = fleet.MDMOperationTypeRemove - err := ReconcileAppleProfiles(ctx, ds, cmdr, logging.NewNopLogger()) + err := ReconcileAppleProfiles(ctx, ds, cmdr, slog.New(slog.DiscardHandler)) require.NoError(t, err) require.Equal(t, 1, failedCount) checkAndReset(t, true, &ds.ListMDMAppleProfilesToInstallAndRemoveFuncInvoked) @@ -3103,7 +3103,7 @@ func TestMDMAppleReconcileAppleProfiles(t *testing.T) { } enqueueFailForOp = fleet.MDMOperationTypeInstall - err := ReconcileAppleProfiles(ctx, ds, cmdr, logging.NewNopLogger()) + err := ReconcileAppleProfiles(ctx, ds, cmdr, slog.New(slog.DiscardHandler)) require.NoError(t, err) require.Equal(t, 1, failedCount) checkAndReset(t, true, &ds.ListMDMAppleProfilesToInstallAndRemoveFuncInvoked) @@ -3277,7 +3277,7 @@ func TestMDMAppleReconcileAppleProfiles(t *testing.T) { contents1 = originalContents1 expectedContents1 = originalExpectedContents1 }) - err := ReconcileAppleProfiles(ctx, ds, cmdr, logging.NewNopLogger()) + err := ReconcileAppleProfiles(ctx, ds, cmdr, slog.New(slog.DiscardHandler)) require.NoError(t, err) assert.Equal(t, 2, upsertCount) // checkAndReset(t, true, &ds.GetAllCertificateAuthoritiesFuncInvoked) @@ -3305,7 +3305,7 @@ func TestMDMAppleReconcileAppleProfiles(t *testing.T) { ds.GetHostEmailsFunc = func(ctx context.Context, hostUUID string, source string) ([]string, error) { return nil, errors.New("GetHostEmailsFuncError") } - err := ReconcileAppleProfiles(ctx, ds, cmdr, logging.NewNopLogger()) + err := ReconcileAppleProfiles(ctx, ds, cmdr, slog.New(slog.DiscardHandler)) assert.ErrorContains(t, err, "GetHostEmailsFuncError") // checkAndReset(t, true, &ds.GetAllCertificateAuthoritiesFuncInvoked) checkAndReset(t, true, &ds.ListMDMAppleProfilesToInstallAndRemoveFuncInvoked) @@ -3367,7 +3367,7 @@ func TestMDMAppleReconcileAppleProfiles(t *testing.T) { hostUUIDs = append(hostUUIDs, p.HostUUID) } - err := ReconcileAppleProfiles(ctx, ds, cmdr, logging.NewNopLogger()) + err := ReconcileAppleProfiles(ctx, ds, cmdr, slog.New(slog.DiscardHandler)) require.NoError(t, err) assert.Empty(t, hostUUIDs, "all host+profile combinations should be updated") require.Equal(t, 5, failedCount, "number of profiles with bad content") @@ -3383,7 +3383,7 @@ func TestMDMAppleReconcileAppleProfiles(t *testing.T) { func TestPreprocessProfileContents(t *testing.T) { ctx := context.Background() - logger := logging.NewNopLogger() + logger := slog.New(slog.DiscardHandler) appCfg := &fleet.AppConfig{} appCfg.ServerSettings.ServerURL = "https://test.example.com" appCfg.MDM.EnabledAndConfigured = true @@ -3878,7 +3878,7 @@ func TestEnsureFleetdConfig(t *testing.T) { testError := errors.New("test error") testURL := "https://example.com" testTeamName := "test-team" - logger := logging.NewNopLogger() + logger := slog.New(slog.DiscardHandler) mdmConfig := config.MDMConfig{ AppleSCEPCert: "./testdata/server.pem", AppleSCEPKey: "./testdata/server.key", @@ -4349,10 +4349,10 @@ func generateCertWithAPNsTopic() ([]byte, []byte, error) { return certPEM, keyPEM, nil } -func setupTest(t *testing.T) (context.Context, *logging.Logger, *mock.Store, *config.FleetConfig, *mdmmock.MDMAppleStore, +func setupTest(t *testing.T) (context.Context, *slog.Logger, *mock.Store, *config.FleetConfig, *mdmmock.MDMAppleStore, *apple_mdm.MDMAppleCommander) { ctx := context.Background() - logger := logging.NewNopLogger() + logger := slog.New(slog.DiscardHandler) cfg := config.TestConfig() ds := new(mock.Store) mdmStorage := &mdmmock.MDMAppleStore{} @@ -4748,7 +4748,7 @@ func TestMDMCommandAndReportResultsIOSIPadOSRefetch(t *testing.T) { lostModeCommandUUID := uuid.NewString() ds := new(mock.Store) - svc := MDMAppleCheckinAndCommandService{ds: ds, logger: logging.NewNopLogger()} + svc := MDMAppleCheckinAndCommandService{ds: ds, logger: slog.New(slog.DiscardHandler)} ds.HostByIdentifierFunc = func(ctx context.Context, identifier string) (*fleet.Host, error) { return &fleet.Host{ @@ -5062,7 +5062,7 @@ func TestNeedsOSUpdateForDEPEnrollment(t *testing.T) { return tt.platform, &tt.appleOSUpdateSettings, tt.returnedErr } - svc := &Service{ds: ds, logger: logging.NewNopLogger()} + svc := &Service{ds: ds, logger: slog.New(slog.DiscardHandler)} t.Run(tt.name, func(t *testing.T) { result, err := svc.needsOSUpdateForDEPEnrollment(ctx, tt.appleMachineInfo) @@ -5409,7 +5409,7 @@ func TestCheckMDMAppleEnrollmentWithMinimumOSVersion(t *testing.T) { func TestPreprocessProfileContentsEndUserIDP(t *testing.T) { ctx := context.Background() - logger := logging.NewNopLogger() + logger := slog.New(slog.DiscardHandler) appCfg := &fleet.AppConfig{} appCfg.ServerSettings.ServerURL = "https://test.example.com" appCfg.MDM.EnabledAndConfigured = true diff --git a/server/service/async/async.go b/server/service/async/async.go index 5e71851cae..c4f474ff3a 100644 --- a/server/service/async/async.go +++ b/server/service/async/async.go @@ -3,6 +3,7 @@ package async import ( "context" "fmt" + "log/slog" "time" "github.com/WatchBeam/clock" @@ -10,8 +11,6 @@ import ( "github.com/fleetdm/fleet/v4/server/contexts/ctxerr" "github.com/fleetdm/fleet/v4/server/datastore/redis" "github.com/fleetdm/fleet/v4/server/fleet" - "github.com/fleetdm/fleet/v4/server/platform/logging" - "github.com/go-kit/log/level" redigo "github.com/gomodule/redigo/redis" ) @@ -54,9 +53,9 @@ func NewTask(ds fleet.Datastore, pool fleet.RedisPool, clck clock.Clock, fleetCo // Collect runs the various collectors as distinct background goroutines if // async processing is enabled. Each collector will stop processing when ctx // is done. -func (t *Task) StartCollectors(ctx context.Context, logger *logging.Logger) { +func (t *Task) StartCollectors(ctx context.Context, logger *slog.Logger) { collectorErrHandler := func(name string, err error) { - level.Error(logger).Log("err", fmt.Sprintf("%s collector", name), "details", err) + logger.ErrorContext(ctx, fmt.Sprintf("%s collector", name), "err", err) ctxerr.Handle(ctx, err) } @@ -68,7 +67,7 @@ func (t *Task) StartCollectors(ctx context.Context, logger *logging.Logger) { } for task, cfg := range t.taskConfigs { if !cfg.Enabled { - level.Debug(logger).Log("task", "async disabled, not starting collector", "name", task) + logger.DebugContext(ctx, "async disabled, not starting collector", "name", task) continue } @@ -84,7 +83,7 @@ func (t *Task) StartCollectors(ctx context.Context, logger *logging.Logger) { errHandler: collectorErrHandler, } go coll.Start(ctx) - level.Debug(logger).Log("task", "async enabled, starting collectors", "name", task, "interval", cfg.CollectInterval, "jitter", cfg.CollectMaxJitterPercent) + logger.DebugContext(ctx, "async enabled, starting collectors", "name", task, "interval", cfg.CollectInterval, "jitter", cfg.CollectMaxJitterPercent) if cfg.CollectLogStatsInterval > 0 { go func() { @@ -93,7 +92,7 @@ func (t *Task) StartCollectors(ctx context.Context, logger *logging.Logger) { select { case <-tick: stats := coll.ReadStats() - level.Debug(logger).Log("stats", fmt.Sprintf("%#v", stats), "name", coll.name) + logger.DebugContext(ctx, "collector stats", "stats", fmt.Sprintf("%#v", stats), "name", coll.name) case <-ctx.Done(): return } diff --git a/server/service/certificates.go b/server/service/certificates.go index 487ec4590f..d44e8d3bd6 100644 --- a/server/service/certificates.go +++ b/server/service/certificates.go @@ -12,7 +12,6 @@ import ( "github.com/fleetdm/fleet/v4/server/contexts/ctxerr" hostctx "github.com/fleetdm/fleet/v4/server/contexts/host" "github.com/fleetdm/fleet/v4/server/fleet" - "github.com/go-kit/kit/log/level" ) // Certificate template name validation constants @@ -678,7 +677,7 @@ func (svc *Service) UpdateCertificateStatus(ctx context.Context, update *fleet.C } if record.OperationType != update.OperationType { - level.Info(svc.logger).Log("msg", "ignoring certificate status update for different operation type", "host_uuid", host.UUID, "certificate_template_id", update.CertificateTemplateID, "current_operation_type", record.OperationType, "new_operation_type", update.OperationType) + svc.logger.InfoContext(ctx, "ignoring certificate status update for different operation type", "host_uuid", host.UUID, "certificate_template_id", update.CertificateTemplateID, "current_operation_type", record.OperationType, "new_operation_type", update.OperationType) return nil } @@ -690,7 +689,7 @@ func (svc *Service) UpdateCertificateStatus(ctx context.Context, update *fleet.C } if record.Status != fleet.CertificateTemplateDelivered { - level.Info(svc.logger).Log("msg", "ignoring certificate status update for non-delivered certificate", "host_uuid", host.UUID, "certificate_template_id", update.CertificateTemplateID, "current_status", record.Status, "new_status", update.Status) + svc.logger.InfoContext(ctx, "ignoring certificate status update for non-delivered certificate", "host_uuid", host.UUID, "certificate_template_id", update.CertificateTemplateID, "current_status", record.Status, "new_status", update.Status) return nil } diff --git a/server/service/conditional_access_microsoft.go b/server/service/conditional_access_microsoft.go index 15caf6a09b..20d30be349 100644 --- a/server/service/conditional_access_microsoft.go +++ b/server/service/conditional_access_microsoft.go @@ -201,7 +201,7 @@ func (svc *Service) ConditionalAccessMicrosoftDelete(ctx context.Context) error if fleet.IsNotFound(err) { // In case there's an issue on the Proxy database we want to make sure to // allow deleting the integration in Fleet, so we continue. - svc.logger.Log("msg", "delete returned not found, continuing...") + svc.logger.WarnContext(ctx, "delete returned not found, continuing...") } else { return ctxerr.Wrap(ctx, err, "failed to delete the integration on the proxy") } diff --git a/server/service/devices_url_auth_test.go b/server/service/devices_url_auth_test.go index fdf0840644..3695b76b7e 100644 --- a/server/service/devices_url_auth_test.go +++ b/server/service/devices_url_auth_test.go @@ -2,12 +2,12 @@ package service import ( "context" + "log/slog" "testing" "time" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/mock" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/stretchr/testify/require" ) @@ -20,7 +20,7 @@ func TestAuthenticatedDeviceFallbackAuth(t *testing.T) { return &fleet.AppConfig{}, nil } - middleware := authenticatedDevice(svc, logging.NewNopLogger(), func(ctx context.Context, request any) (any, error) { + middleware := authenticatedDevice(svc, slog.New(slog.DiscardHandler), func(ctx context.Context, request any) (any, error) { return "success", nil }) diff --git a/server/service/endpoint_campaigns.go b/server/service/endpoint_campaigns.go index 77780242ae..0027f63d22 100644 --- a/server/service/endpoint_campaigns.go +++ b/server/service/endpoint_campaigns.go @@ -3,6 +3,7 @@ package service import ( "context" "encoding/json" + "log/slog" "net/http" "regexp" "strings" @@ -12,7 +13,6 @@ import ( "github.com/fleetdm/fleet/v4/server/contexts/viewer" "github.com/fleetdm/fleet/v4/server/fleet" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/websocket" gws "github.com/gorilla/websocket" "github.com/igm/sockjs-go/v3/sockjs" @@ -24,7 +24,7 @@ import ( var reVersion = regexp.MustCompile(`\{fleetversion:\(\?:([^\}\)]+)\)\}`) -func makeStreamDistributedQueryCampaignResultsHandler(config config.ServerConfig, svc fleet.Service, logger *logging.Logger) func(string) http.Handler { +func makeStreamDistributedQueryCampaignResultsHandler(config config.ServerConfig, svc fleet.Service, logger *slog.Logger) func(string) http.Handler { opt := sockjs.DefaultOptions opt.Websocket = true opt.RawWebsocket = true @@ -61,7 +61,7 @@ func makeStreamDistributedQueryCampaignResultsHandler(config config.ServerConfig conn := &websocket.Conn{Session: session} defer func() { if p := recover(); p != nil { - logger.Log("err", p, "msg", "panic in result handler") + logger.ErrorContext(context.TODO(), "panic in result handler", "err", p) conn.WriteJSONError("panic in result handler") //nolint:errcheck } session.Close(0, "none") @@ -70,14 +70,14 @@ func makeStreamDistributedQueryCampaignResultsHandler(config config.ServerConfig // Receive the auth bearer token token, err := conn.ReadAuthToken() if err != nil { - logger.Log("err", err, "msg", "failed to read auth token") + logger.ErrorContext(context.TODO(), "failed to read auth token", "err", err) return } // Authenticate with the token vc, err := auth.AuthViewer(context.Background(), string(token), svc) if err != nil || !vc.CanPerformActions() { - logger.Log("err", err, "msg", "unauthorized viewer") + logger.ErrorContext(context.TODO(), "unauthorized viewer", "err", err) conn.WriteJSONError("unauthorized") //nolint:errcheck return } @@ -86,12 +86,12 @@ func makeStreamDistributedQueryCampaignResultsHandler(config config.ServerConfig msg, err := conn.ReadJSONMessage() if err != nil { - logger.Log("err", err, "msg", "reading select_campaign JSON") + logger.ErrorContext(ctx, "reading select_campaign JSON", "err", err) conn.WriteJSONError("error reading select_campaign") //nolint:errcheck return } if msg.Type != "select_campaign" { - logger.Log("err", "unexpected msg type, expected select_campaign", "msg-type", msg.Type) + logger.ErrorContext(ctx, "unexpected msg type, expected select_campaign", "msg-type", msg.Type) conn.WriteJSONError("expected select_campaign") //nolint:errcheck return } @@ -101,12 +101,12 @@ func makeStreamDistributedQueryCampaignResultsHandler(config config.ServerConfig } err = json.Unmarshal(*(msg.Data.(*json.RawMessage)), &info) if err != nil { - logger.Log("err", err, "msg", "unmarshaling select_campaign data") + logger.ErrorContext(ctx, "unmarshaling select_campaign data", "err", err) conn.WriteJSONError("error unmarshaling select_campaign data") //nolint:errcheck return } if info.CampaignID == 0 { - logger.Log("err", "campaign ID not set") + logger.ErrorContext(ctx, "campaign ID not set") conn.WriteJSONError("0 is not a valid campaign ID") //nolint:errcheck return } diff --git a/server/service/endpoint_middleware.go b/server/service/endpoint_middleware.go index 33cc769767..cf9fa979df 100644 --- a/server/service/endpoint_middleware.go +++ b/server/service/endpoint_middleware.go @@ -4,7 +4,7 @@ import ( "context" "encoding/json" "errors" - "fmt" + "log/slog" "net/http" "strconv" "strings" @@ -13,10 +13,8 @@ import ( "github.com/fleetdm/fleet/v4/server/contexts/ctxerr" "github.com/fleetdm/fleet/v4/server/contexts/logging" "github.com/fleetdm/fleet/v4/server/fleet" - platformlogging "github.com/fleetdm/fleet/v4/server/platform/logging" middleware_log "github.com/fleetdm/fleet/v4/server/service/middleware/log" kithttp "github.com/go-kit/kit/transport/http" - "github.com/go-kit/log/level" authz_ctx "github.com/fleetdm/fleet/v4/server/contexts/authz" hostctx "github.com/fleetdm/fleet/v4/server/contexts/host" @@ -40,13 +38,13 @@ func extractCertSerialFromHeader(ctx context.Context, r *http.Request) context.C return certserial.NewContext(ctx, serial) } -func logJSON(logger *platformlogging.Logger, v any, key string) { +func logJSON(ctx context.Context, logger *slog.Logger, v any, key string) { jsonV, err := json.Marshal(v) if err != nil { - level.Debug(logger).Log("err", fmt.Errorf("marshaling %s for debug: %w", key, err)) + logger.DebugContext(ctx, "error marshaling for debug", "key", key, "err", err) return } - level.Debug(logger).Log(key, string(jsonV)) + logger.DebugContext(ctx, "debug JSON", key, string(jsonV)) } // instrumentHostLogger adds host ID, IP information, and extras to the context logger. @@ -66,7 +64,7 @@ func instrumentHostLogger(ctx context.Context, hostID uint, extras ...interface{ // authenticatedDevice checks the validity of the device auth token // provided in the request, and attaches the corresponding host to the // context for the request. -func authenticatedDevice(svc fleet.Service, logger *platformlogging.Logger, next endpoint.Endpoint) endpoint.Endpoint { +func authenticatedDevice(svc fleet.Service, logger *slog.Logger, next endpoint.Endpoint) endpoint.Endpoint { authDeviceFunc := func(ctx context.Context, request interface{}) (interface{}, error) { identifier, err := getDeviceAuthToken(request) if err != nil { @@ -101,7 +99,7 @@ func authenticatedDevice(svc fleet.Service, logger *platformlogging.Logger, next hlogger := logger.With("host_id", host.ID) if debug { - logJSON(hlogger, request, "request") + logJSON(ctx, hlogger, request, "request") } ctx = hostctx.NewContext(ctx, host) @@ -120,7 +118,7 @@ func authenticatedDevice(svc fleet.Service, logger *platformlogging.Logger, next } if debug { - logJSON(hlogger, request, "response") + logJSON(ctx, hlogger, resp, "response") } return resp, nil } @@ -137,7 +135,7 @@ func getDeviceAuthToken(r interface{}) (string, error) { // authenticatedHost wraps an endpoint, checks the validity of the node_key // provided in the request, and attaches the corresponding osquery host to the // context for the request -func authenticatedHost(svc fleet.Service, logger *platformlogging.Logger, next endpoint.Endpoint) endpoint.Endpoint { +func authenticatedHost(svc fleet.Service, logger *slog.Logger, next endpoint.Endpoint) endpoint.Endpoint { authHostFunc := func(ctx context.Context, request interface{}) (interface{}, error) { nodeKey, err := getNodeKey(request) if err != nil { @@ -152,7 +150,7 @@ func authenticatedHost(svc fleet.Service, logger *platformlogging.Logger, next e hlogger := logger.With("host_id", host.ID) if debug { - logJSON(hlogger, request, "request") + logJSON(ctx, hlogger, request, "request") } ctx = hostctx.NewContext(ctx, host) @@ -171,7 +169,7 @@ func authenticatedHost(svc fleet.Service, logger *platformlogging.Logger, next e } if debug { - logJSON(hlogger, resp, "response") + logJSON(ctx, hlogger, resp, "response") } return resp, nil } @@ -180,7 +178,7 @@ func authenticatedHost(svc fleet.Service, logger *platformlogging.Logger, next e func authenticatedOrbitHost( svc fleet.Service, - logger *platformlogging.Logger, + logger *slog.Logger, next endpoint.Endpoint, orbitNodeKeyGetter func(context.Context, interface{}) (string, error), ) endpoint.Endpoint { @@ -198,7 +196,7 @@ func authenticatedOrbitHost( hlogger := logger.With("host_id", host.ID) if debug { - logJSON(hlogger, request, "request") + logJSON(ctx, hlogger, request, "request") } ctx = hostctx.NewContext(ctx, host) @@ -217,7 +215,7 @@ func authenticatedOrbitHost( } if debug { - logJSON(hlogger, resp, "response") + logJSON(ctx, hlogger, resp, "response") } return resp, nil } diff --git a/server/service/endpoint_middleware_test.go b/server/service/endpoint_middleware_test.go index 5bf4f1663f..7761703866 100644 --- a/server/service/endpoint_middleware_test.go +++ b/server/service/endpoint_middleware_test.go @@ -3,13 +3,13 @@ package service import ( "context" "errors" + "log/slog" "testing" hostctx "github.com/fleetdm/fleet/v4/server/contexts/host" "github.com/fleetdm/fleet/v4/server/contexts/viewer" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/mock" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/ptr" "github.com/fleetdm/fleet/v4/server/service/middleware/auth" "github.com/stretchr/testify/assert" @@ -155,7 +155,7 @@ func TestAuthenticatedHost(t *testing.T) { endpoint := authenticatedHost( svc, - logging.NewNopLogger(), + slog.New(slog.DiscardHandler), func(ctx context.Context, request interface{}) (interface{}, error) { host, ok := hostctx.FromContext(ctx) assert.True(t, ok) diff --git a/server/service/endpoint_setup.go b/server/service/endpoint_setup.go index 2af76cc1ff..86ede23ce1 100644 --- a/server/service/endpoint_setup.go +++ b/server/service/endpoint_setup.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "io" + "log/slog" "net/http" "os" "path/filepath" @@ -15,10 +16,8 @@ import ( "github.com/fleetdm/fleet/v4/pkg/spec" "github.com/fleetdm/fleet/v4/server/contexts/ctxerr" "github.com/fleetdm/fleet/v4/server/fleet" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/ptr" "github.com/go-kit/kit/endpoint" - "github.com/go-kit/log/level" ) const ( @@ -46,8 +45,8 @@ type applyGroupFunc func(context.Context, *spec.Group) error func (r setupResponse) Error() error { return r.Err } -func makeSetupEndpoint(svc fleet.Service, logger *logging.Logger) endpoint.Endpoint { - return func(ctx context.Context, request interface{}) (interface{}, error) { +func makeSetupEndpoint(svc fleet.Service, logger *slog.Logger) endpoint.Endpoint { + return func(ctx context.Context, request any) (any, error) { req := request.(setupRequest) config := &fleet.AppConfig{} if req.OrgInfo != nil { @@ -89,7 +88,7 @@ func makeSetupEndpoint(svc fleet.Service, logger *logging.Logger) endpoint.Endpo var token *string _, session, err := svc.Login(ctx, *req.Admin.Email, *req.Admin.Password, false) if err != nil { - level.Debug(logger).Log("endpoint", "setup", "op", "login", "err", err) + logger.DebugContext(ctx, "setup login", "endpoint", "setup", "op", "login", "err", err) } else { token = &session.Key @@ -104,11 +103,11 @@ func makeSetupEndpoint(svc fleet.Service, logger *logging.Logger) endpoint.Endpo NewClient, nil, // No mock ApplyGroup for production code ); err != nil { - level.Debug(logger).Log("endpoint", "setup", "op", "applyStarterLibrary", "err", err) + logger.DebugContext(ctx, "setup apply starter library", "endpoint", "setup", "op", "applyStarterLibrary", "err", err) // Continue even if there's an error applying the starter library } } else { - level.Debug(logger).Log("endpoint", "setup", "msg", "Skipping starter library application due to missing server URL") + logger.DebugContext(ctx, "Skipping starter library application due to missing server URL", "endpoint", "setup") } } @@ -129,13 +128,13 @@ func ApplyStarterLibrary( ctx context.Context, serverURL string, token string, - logger *logging.Logger, + logger *slog.Logger, httpClientFactory func(opts ...fleethttp.ClientOpt) *http.Client, clientFactory func(serverURL string, insecureSkipVerify bool, rootCA, urlPrefix string, options ...ClientOption) (*Client, error), // For testing only - if provided, this function will be used instead of client.ApplyGroup mockApplyGroup func(ctx context.Context, specs *spec.Group) error, ) error { - level.Debug(logger).Log("msg", "Applying starter library") + logger.DebugContext(ctx, "Applying starter library") // Create a request with context for downloading the starter library req, err := http.NewRequestWithContext(ctx, http.MethodGet, starterLibraryURL, nil) @@ -167,7 +166,7 @@ func ApplyStarterLibrary( } defer os.RemoveAll(tempDir) // Clean up the temporary directory when done - level.Debug(logger).Log("msg", "Created temporary directory for scripts", "path", tempDir) + logger.DebugContext(ctx, "Created temporary directory for scripts", "path", tempDir) // Parse the YAML content into specs specs, err := spec.GroupFromBytes(buf) @@ -177,7 +176,7 @@ func ApplyStarterLibrary( // Find all script references in the YAML and download them scriptNames := ExtractScriptNames(specs) - level.Debug(logger).Log("msg", "Found script references in starter library", "count", len(scriptNames)) + logger.DebugContext(ctx, "Found script references in starter library", "count", len(scriptNames)) // Download scripts and update references in specs if len(scriptNames) > 0 { @@ -197,11 +196,11 @@ func ApplyStarterLibrary( // Always check if license is free and skip teams for free licenses appConfig, err := client.GetAppConfig() if err != nil { - level.Debug(logger).Log("msg", "Error getting app config", "err", err) + logger.DebugContext(ctx, "Error getting app config", "err", err) // Continue even if there's an error getting the app config } else if appConfig.License == nil || !appConfig.License.IsPremium() { // Remove teams from specs to avoid applying them - level.Debug(logger).Log("msg", "Free license detected, skipping teams and team-related content in starter library") + logger.DebugContext(ctx, "Free license detected, skipping teams and team-related content in starter library") specs.Teams = nil // Filter out policies that reference teams @@ -262,7 +261,7 @@ func ApplyStarterLibrary( return fmt.Errorf("failed to apply starter library: %w", err) } - level.Debug(logger).Log("msg", "Starter library applied successfully") + logger.DebugContext(ctx, "Starter library applied successfully") return nil } @@ -292,7 +291,7 @@ func ExtractScriptNames(specs *spec.Group) []string { } // DownloadAndUpdateScripts downloads scripts from URLs and updates the specs to reference local files -func DownloadAndUpdateScripts(ctx context.Context, specs *spec.Group, scriptNames []string, tempDir string, logger *logging.Logger) error { +func DownloadAndUpdateScripts(ctx context.Context, specs *spec.Group, scriptNames []string, tempDir string, logger *slog.Logger) error { // Create a single HTTP client to be reused for all requests httpClient := fleethttp.NewClient(fleethttp.WithTimeout(5 * time.Second)) @@ -317,7 +316,7 @@ func DownloadAndUpdateScripts(ctx context.Context, specs *spec.Group, scriptName } scriptURL := fmt.Sprintf("%s/%s", scriptsBaseURL, scriptName) - level.Debug(logger).Log("msg", "Downloading script", "name", scriptName, "url", scriptURL, "local_path", localPath) + logger.DebugContext(ctx, "Downloading script", "name", scriptName, "url", scriptURL, "local_path", localPath) // Create the request with context req, err := http.NewRequestWithContext(ctx, http.MethodGet, scriptURL, nil) @@ -416,7 +415,7 @@ func DownloadAndUpdateScripts(ctx context.Context, specs *spec.Group, scriptName // Marshal back to JSON updatedTeamRaw, err := json.Marshal(teamData) if err != nil { - level.Debug(logger).Log("msg", "Failed to marshal updated team data", "err", err) + logger.DebugContext(ctx, "Failed to marshal updated team data", "err", err) continue } diff --git a/server/service/endpoint_setup_test.go b/server/service/endpoint_setup_test.go index 734bc03f24..59fe435d90 100644 --- a/server/service/endpoint_setup_test.go +++ b/server/service/endpoint_setup_test.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "io" + "log/slog" "net/http" "net/http/httptest" "net/url" @@ -18,7 +19,6 @@ import ( "github.com/fleetdm/fleet/v4/pkg/fleethttp" "github.com/fleetdm/fleet/v4/pkg/spec" "github.com/fleetdm/fleet/v4/server/fleet" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -191,7 +191,7 @@ func TestDownloadAndUpdateScripts(t *testing.T) { } // Call the actual production function - err = DownloadAndUpdateScripts(context.Background(), specs, tt.scriptNames, tempDir, logging.NewNopLogger()) + err = DownloadAndUpdateScripts(context.Background(), specs, tt.scriptNames, tempDir, slog.New(slog.DiscardHandler)) require.NoError(t, err) // Verify the scripts were downloaded @@ -288,7 +288,7 @@ func TestDownloadAndUpdateScriptsWithInvalidPaths(t *testing.T) { } // Call the actual production function - err = DownloadAndUpdateScripts(context.Background(), specs, tt.scriptNames, tempDir, logging.NewNopLogger()) + err = DownloadAndUpdateScripts(context.Background(), specs, tt.scriptNames, tempDir, slog.New(slog.DiscardHandler)) require.Error(t, err) assert.Contains(t, err.Error(), tt.errorMsg) }) @@ -411,7 +411,7 @@ func TestDownloadAndUpdateScriptsTimeout(t *testing.T) { defer cancel() // Call the actual production function - err = DownloadAndUpdateScripts(ctx, specs, scriptNames, tempDir, logging.NewNopLogger()) + err = DownloadAndUpdateScripts(ctx, specs, scriptNames, tempDir, slog.New(slog.DiscardHandler)) if tt.expectError { require.Error(t, err) @@ -478,7 +478,7 @@ func TestApplyStarterLibraryWithMockClient(t *testing.T) { context.Background(), "https://example.com", "test-token", - logging.NewNopLogger(), + slog.New(slog.DiscardHandler), httpClientFactory, clientFactory, mockApplyGroup, @@ -560,7 +560,7 @@ func TestApplyStarterLibraryWithMalformedYAML(t *testing.T) { context.Background(), "https://example.com", "test-token", - logging.NewNopLogger(), + slog.New(slog.DiscardHandler), httpClientFactory, clientFactory, mockApplyGroup, @@ -666,7 +666,7 @@ func TestApplyStarterLibraryWithFreeLicense(t *testing.T) { context.Background(), "https://example.com", "test-token", - logging.NewNopLogger(), + slog.New(slog.DiscardHandler), httpClientFactory, clientFactory, mockApplyGroup, diff --git a/server/service/endpoint_utils.go b/server/service/endpoint_utils.go index 2067655456..68e8d35b1a 100644 --- a/server/service/endpoint_utils.go +++ b/server/service/endpoint_utils.go @@ -200,7 +200,7 @@ func badRequestf(format string, a ...any) error { } } -func newDeviceAuthenticatedEndpointer(svc fleet.Service, logger *platform_logging.Logger, opts []kithttp.ServerOption, r *mux.Router, +func newDeviceAuthenticatedEndpointer(svc fleet.Service, logger *slog.Logger, opts []kithttp.ServerOption, r *mux.Router, versions ...string, ) *eu.CommonEndpointer[handlerFunc] { // Extract certificate serial from X-Client-Cert-Serial header for certificate-based auth @@ -225,7 +225,7 @@ func newDeviceAuthenticatedEndpointer(svc fleet.Service, logger *platform_loggin } } -func newHostAuthenticatedEndpointer(svc fleet.Service, logger *platform_logging.Logger, opts []kithttp.ServerOption, r *mux.Router, +func newHostAuthenticatedEndpointer(svc fleet.Service, logger *slog.Logger, opts []kithttp.ServerOption, r *mux.Router, versions ...string, ) *eu.CommonEndpointer[handlerFunc] { return &eu.CommonEndpointer[handlerFunc]{ @@ -245,7 +245,7 @@ func newHostAuthenticatedEndpointer(svc fleet.Service, logger *platform_logging. func androidAuthenticatedEndpointer( svc fleet.Service, - logger *platform_logging.Logger, + logger *slog.Logger, opts []kithttp.ServerOption, r *mux.Router, versions ...string, @@ -270,7 +270,7 @@ func androidAuthenticatedEndpointer( } } -func newOrbitAuthenticatedEndpointer(svc fleet.Service, logger *platform_logging.Logger, opts []kithttp.ServerOption, r *mux.Router, +func newOrbitAuthenticatedEndpointer(svc fleet.Service, logger *slog.Logger, opts []kithttp.ServerOption, r *mux.Router, versions ...string, ) *eu.CommonEndpointer[handlerFunc] { // Inject the fleet.Capabilities header to the response for Orbit hosts diff --git a/server/service/frontend.go b/server/service/frontend.go index c32abe70cf..c7c120ed25 100644 --- a/server/service/frontend.go +++ b/server/service/frontend.go @@ -1,9 +1,11 @@ package service import ( + "context" "fmt" "html/template" "io" + "log/slog" "net/http" "net/url" @@ -12,7 +14,6 @@ import ( "github.com/fleetdm/fleet/v4/server/bindata" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/platform/endpointer" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/klauspost/compress/gzhttp" ) @@ -25,9 +26,9 @@ func newBinaryFileSystem(root string) *assetfs.AssetFS { } } -func ServeFrontend(urlPrefix string, sandbox bool, logger *logging.Logger) http.Handler { - herr := func(w http.ResponseWriter, err string) { - logger.Log("err", err) +func ServeFrontend(urlPrefix string, sandbox bool, logger *slog.Logger) http.Handler { + herr := func(ctx context.Context, w http.ResponseWriter, err string) { + logger.ErrorContext(ctx, err) http.Error(w, err, http.StatusInternalServerError) } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -42,19 +43,20 @@ func ServeFrontend(urlPrefix string, sandbox bool, logger *logging.Logger) http. } fs := newBinaryFileSystem("/frontend") + ctx := r.Context() file, err := fs.Open("templates/react.tmpl") if err != nil { - herr(w, "load react template: "+err.Error()) + herr(ctx, w, "load react template: "+err.Error()) return } data, err := io.ReadAll(file) if err != nil { - herr(w, "read bindata file: "+err.Error()) + herr(ctx, w, "read bindata file: "+err.Error()) return } t, err := template.New("react").Parse(string(data)) if err != nil { - herr(w, "create react template: "+err.Error()) + herr(ctx, w, "create react template: "+err.Error()) return } serverType := "on-premise" @@ -68,7 +70,7 @@ func ServeFrontend(urlPrefix string, sandbox bool, logger *logging.Logger) http. URLPrefix: urlPrefix, ServerType: serverType, }); err != nil { - herr(w, "execute react template: "+err.Error()) + herr(ctx, w, "execute react template: "+err.Error()) return } }) @@ -80,35 +82,36 @@ func ServeEndUserEnrollOTA( svc fleet.Service, urlPrefix string, ds fleet.Datastore, - logger *logging.Logger, + logger *slog.Logger, ) http.Handler { - herr := func(w http.ResponseWriter, err string) { - logger.Log("err", err) + herr := func(ctx context.Context, w http.ResponseWriter, err string) { + logger.ErrorContext(ctx, err) http.Error(w, err, http.StatusInternalServerError) } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { endpointer.WriteBrowserSecurityHeaders(w) - setupRequired, err := svc.SetupRequired(r.Context()) + ctx := r.Context() + setupRequired, err := svc.SetupRequired(ctx) if err != nil { - herr(w, "setup required err: "+err.Error()) + herr(ctx, w, "setup required err: "+err.Error()) return } if setupRequired { - herr(w, "fleet instance not setup") + herr(ctx, w, "fleet instance not setup") return } appCfg, err := ds.AppConfig(r.Context()) if err != nil { - herr(w, "load appconfig err: "+err.Error()) + herr(ctx, w, "load appconfig err: "+err.Error()) return } errorMsg := r.URL.Query().Get("error") if errorMsg != "" { if err := renderEnrollPage(w, appCfg, urlPrefix, "", errorMsg); err != nil { - herr(w, err.Error()) + herr(ctx, w, err.Error()) } return } @@ -116,7 +119,7 @@ func ServeEndUserEnrollOTA( enrollSecret := r.URL.Query().Get("enroll_secret") if enrollSecret == "" { if err := renderEnrollPage(w, appCfg, urlPrefix, "", "This URL is invalid. : Enroll secret is invalid. Please contact your IT admin."); err != nil { - herr(w, err.Error()) + herr(ctx, w, err.Error()) } return } @@ -124,7 +127,7 @@ func ServeEndUserEnrollOTA( authRequired, err := shared_mdm.RequiresEnrollOTAAuthentication(r.Context(), ds, enrollSecret, appCfg.MDM.MacOSSetup.EnableEndUserAuthentication) if err != nil { - herr(w, "check if authentication is required err: "+err.Error()) + herr(ctx, w, "check if authentication is required err: "+err.Error()) return } @@ -148,7 +151,7 @@ func ServeEndUserEnrollOTA( // IdP authentication has not been completed yet, initiate it by // redirecting to the configured IdP provider. if err := initiateOTAEnrollSSO(svc, w, r, enrollSecret); err != nil { - herr(w, "initiate IdP SSO authentication err: "+err.Error()) + herr(ctx, w, "initiate IdP SSO authentication err: "+err.Error()) return } return @@ -159,7 +162,7 @@ func ServeEndUserEnrollOTA( // been successfully completed (we have a cookie with the IdP account // reference). if err := renderEnrollPage(w, appCfg, urlPrefix, enrollSecret, ""); err != nil { - herr(w, err.Error()) + herr(ctx, w, err.Error()) return } }) diff --git a/server/service/frontend_test.go b/server/service/frontend_test.go index ef1f85e8fe..612af89676 100644 --- a/server/service/frontend_test.go +++ b/server/service/frontend_test.go @@ -5,6 +5,7 @@ import ( "context" "fmt" "io" + "log/slog" "net/http" "net/http/httptest" "os" @@ -12,7 +13,6 @@ import ( "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/mock" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -21,7 +21,7 @@ func TestServeFrontend(t *testing.T) { if !hasBuildTag("full") { t.Skip("This test requires running with -tags full") } - logger := logging.NewLogfmtLogger(os.Stdout) + logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) h := ServeFrontend("", false, logger) ts := httptest.NewServer(h) t.Cleanup(func() { @@ -79,7 +79,7 @@ func TestServeEndUserEnrollOTA(t *testing.T) { appCfg.MDM.EnabledAndConfigured = enabled appCfg.MDM.AndroidEnabledAndConfigured = enabled - logger := logging.NewLogfmtLogger(os.Stdout) + logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) h := ServeEndUserEnrollOTA(svc, "", ds, logger) ts := httptest.NewServer(h) t.Cleanup(func() { diff --git a/server/service/handler.go b/server/service/handler.go index 5916195ead..731423e522 100644 --- a/server/service/handler.go +++ b/server/service/handler.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "log/slog" "net/http" "os" "regexp" @@ -37,7 +38,6 @@ import ( "github.com/fleetdm/fleet/v4/server/service/middleware/otel" "github.com/docker/go-units" - "github.com/fleetdm/fleet/v4/server/platform/logging" kithttp "github.com/go-kit/kit/transport/http" "github.com/gorilla/mux" "github.com/klauspost/compress/gzhttp" @@ -102,7 +102,7 @@ func setCarveStoreInRequestContext(carveStore fleet.CarveStore) kithttp.RequestF func MakeHandler( svc fleet.Service, config config.FleetConfig, - logger *logging.Logger, + logger *slog.Logger, limitStore throttled.GCRAStore, redisPool fleet.RedisPool, carveStore fleet.CarveStore, @@ -127,11 +127,11 @@ func MakeHandler( endpointer.LogDeprecatedPathAlias, // log deprecation warning for deprecated URL path aliases setCarveStoreInRequestContext(carveStore), ), - kithttp.ServerErrorHandler(&endpointer.ErrorHandler{Logger: logger.SlogLogger()}), + kithttp.ServerErrorHandler(&endpointer.ErrorHandler{Logger: logger}), kithttp.ServerErrorEncoder(fleetErrorEncoder), kithttp.ServerAfter( kithttp.SetContentType("application/json; charset=utf-8"), - log.LogRequestEnd(logger.SlogLogger()), + log.LogRequestEnd(logger), checkLicenseExpiration(svc), ), } @@ -278,7 +278,7 @@ const ( ) func attachFleetAPIRoutes(r *mux.Router, svc fleet.Service, config config.FleetConfig, - logger *logging.Logger, limitStore throttled.GCRAStore, redisPool fleet.RedisPool, opts []kithttp.ServerOption, + logger *slog.Logger, limitStore throttled.GCRAStore, redisPool fleet.RedisPool, opts []kithttp.ServerOption, extra extraHandlerOpts, ) { apiVersions := []string{"v1", "2022-04"} @@ -872,7 +872,7 @@ func attachFleetAPIRoutes(r *mux.Router, svc fleet.Service, config config.FleetC deviceIPAllowedConsecutiveFailingRequestsTimeWindow, deviceIPBanTime, ) - errorLimiter := ratelimit.NewErrorMiddleware(ipBanner).Limit(logger.SlogLogger()) + errorLimiter := ratelimit.NewErrorMiddleware(ipBanner).Limit(logger) // Device-authenticated endpoints. de := newDeviceAuthenticatedEndpointer(svc, logger, opts, r, apiVersions...) @@ -1102,7 +1102,7 @@ func attachFleetAPIRoutes(r *mux.Router, svc fleet.Service, config config.FleetC // WithSetup is an http middleware that checks if setup procedures have been completed. // If setup hasn't been completed it serves the API with a setup middleware. // If the server is already configured, the default API handler is exposed. -func WithSetup(svc fleet.Service, logger *logging.Logger, next http.Handler) http.HandlerFunc { +func WithSetup(svc fleet.Service, logger *slog.Logger, next http.Handler) http.HandlerFunc { rxOsquery := regexp.MustCompile(`^/api/[^/]+/osquery`) return func(w http.ResponseWriter, r *http.Request) { configRouter := http.NewServeMux() @@ -1121,9 +1121,10 @@ func WithSetup(svc fleet.Service, logger *logging.Logger, next http.Handler) htt next.ServeHTTP(w, r) return } - requireSetup, err := svc.SetupRequired(context.Background()) + ctx := r.Context() + requireSetup, err := svc.SetupRequired(ctx) if err != nil { - logger.Log("msg", "fetching setup info from db", "err", err) + logger.ErrorContext(ctx, "fetching setup info from db", "err", err) w.WriteHeader(http.StatusInternalServerError) return } @@ -1137,7 +1138,7 @@ func WithSetup(svc fleet.Service, logger *logging.Logger, next http.Handler) htt // RedirectLoginToSetup detects if the setup endpoint should be used. If setup is required it redirect all // frontend urls to /setup, otherwise the frontend router is used. -func RedirectLoginToSetup(svc fleet.Service, logger *logging.Logger, next http.Handler, urlPrefix string) http.HandlerFunc { +func RedirectLoginToSetup(svc fleet.Service, logger *slog.Logger, next http.Handler, urlPrefix string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { redirect := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/setup" { @@ -1149,9 +1150,10 @@ func RedirectLoginToSetup(svc fleet.Service, logger *logging.Logger, next http.H http.Redirect(w, r, newURL.String(), http.StatusTemporaryRedirect) }) - setupRequired, err := svc.SetupRequired(context.Background()) + ctx := r.Context() + setupRequired, err := svc.SetupRequired(ctx) if err != nil { - logger.Log("msg", "fetching setupinfo from db", "err", err) + logger.ErrorContext(ctx, "fetching setupinfo from db", "err", err) w.WriteHeader(http.StatusInternalServerError) return } @@ -1165,7 +1167,7 @@ func RedirectLoginToSetup(svc fleet.Service, logger *logging.Logger, next http.H // RedirectSetupToLogin forces the /setup path to be redirected to login. This middleware is used after // the app has been setup. -func RedirectSetupToLogin(svc fleet.Service, logger *logging.Logger, next http.Handler, urlPrefix string) http.HandlerFunc { +func RedirectSetupToLogin(svc fleet.Service, logger *slog.Logger, next http.Handler, urlPrefix string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/setup" { newURL := r.URL @@ -1184,7 +1186,7 @@ func RegisterAppleMDMProtocolServices( scepConfig config.MDMConfig, mdmStorage fleet.MDMAppleStore, scepStorage scep_depot.Depot, - logger *logging.Logger, + logger *slog.Logger, checkinAndCommandService nanomdm_service.CheckinAndCommandService, ddmService nanomdm_service.DeclarativeManagement, profileService nanomdm_service.ProfileService, @@ -1205,19 +1207,20 @@ func RegisterAppleMDMProtocolServices( func registerMDMServiceDiscovery( mux *http.ServeMux, - logger *logging.Logger, + logger *slog.Logger, serverURLPrefix string, fleetConfig config.FleetConfig, ) error { serviceDiscoveryLogger := logger.With("component", "mdm-apple-service-discovery") fullMDMEnrollmentURL := fmt.Sprintf("%s%s", serverURLPrefix, apple_mdm.AccountDrivenEnrollPath) serviceDiscoveryHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - serviceDiscoveryLogger.Log("msg", "serving MDM service discovery response", "url", fullMDMEnrollmentURL) + ctx := r.Context() + serviceDiscoveryLogger.InfoContext(ctx, "serving MDM service discovery response", "url", fullMDMEnrollmentURL) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) _, err := fmt.Fprintf(w, `{"Servers":[{"Version": "mdm-byod", "BaseURL": "%s"}]}`, fullMDMEnrollmentURL) if err != nil { - serviceDiscoveryLogger.Log("err", "error writing service discovery response", "err", err) + serviceDiscoveryLogger.ErrorContext(ctx, "error writing service discovery response", "err", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) } }) @@ -1232,7 +1235,7 @@ func registerSCEP( scepConfig config.MDMConfig, scepStorage scep_depot.Depot, mdmStorage fleet.MDMAppleStore, - logger *logging.Logger, + logger *slog.Logger, fleetConfig config.FleetConfig, ) error { var signer scepserver.CSRSignerContext = scepserver.SignCSRAdapter(scep_depot.NewSigner( @@ -1253,11 +1256,11 @@ func registerSCEP( logger.With("component", "mdm-apple-scep"), ) - scepLogger := logger.With("component", "http-mdm-apple-scep") + scepSlogLogger := logger.With("component", "http-mdm-apple-scep") e := scepserver.MakeServerEndpoints(scepService) - e.GetEndpoint = scepserver.EndpointLoggingMiddleware(scepLogger)(e.GetEndpoint) - e.PostEndpoint = scepserver.EndpointLoggingMiddleware(scepLogger)(e.PostEndpoint) - scepHandler := scepserver.MakeHTTPHandler(e, scepService, scepLogger) + e.GetEndpoint = scepserver.EndpointLoggingMiddleware(scepSlogLogger)(e.GetEndpoint) + e.PostEndpoint = scepserver.EndpointLoggingMiddleware(scepSlogLogger)(e.PostEndpoint) + scepHandler := scepserver.MakeHTTPHandler(e, scepService, scepSlogLogger) mux.Handle(apple_mdm.SCEPPath, otel.WrapHandler(scepHandler, apple_mdm.SCEPPath, fleetConfig)) return nil } @@ -1265,7 +1268,7 @@ func registerSCEP( func RegisterSCEPProxy( rootMux *http.ServeMux, ds fleet.Datastore, - logger *logging.Logger, + logger *slog.Logger, timeout *time.Duration, fleetConfig *config.FleetConfig, ) error { @@ -1277,11 +1280,11 @@ func RegisterSCEPProxy( logger.With("component", "scep-proxy-service"), timeout, ) - scepLogger := logger.With("component", "http-scep-proxy") + scepProxySlogLogger := logger.With("component", "http-scep-proxy") e := scepserver.MakeServerEndpointsWithIdentifier(scepService) - e.GetEndpoint = scepserver.EndpointLoggingMiddleware(scepLogger)(e.GetEndpoint) - e.PostEndpoint = scepserver.EndpointLoggingMiddleware(scepLogger)(e.PostEndpoint) - scepHandler := scepserver.MakeHTTPHandlerWithIdentifier(e, apple_mdm.SCEPProxyPath, scepLogger) + e.GetEndpoint = scepserver.EndpointLoggingMiddleware(scepProxySlogLogger)(e.GetEndpoint) + e.PostEndpoint = scepserver.EndpointLoggingMiddleware(scepProxySlogLogger)(e.PostEndpoint) + scepHandler := scepserver.MakeHTTPHandlerWithIdentifier(e, apple_mdm.SCEPProxyPath, scepProxySlogLogger) // Not using OTEL dynamic wrapper so as not to expose {identifier} in the span name scepHandler = otel.WrapHandler(scepHandler, apple_mdm.SCEPProxyPath, *fleetConfig) rootMux.Handle(apple_mdm.SCEPProxyPath, scepHandler) @@ -1290,10 +1293,10 @@ func RegisterSCEPProxy( // NanoMDMLogger is a logger adapter for nanomdm. type NanoMDMLogger struct { - logger *logging.Logger + logger *slog.Logger } -func NewNanoMDMLogger(logger *logging.Logger) *NanoMDMLogger { +func NewNanoMDMLogger(logger *slog.Logger) *NanoMDMLogger { return &NanoMDMLogger{ logger: logger, } @@ -1320,7 +1323,7 @@ func registerMDM( checkinAndCommandService nanomdm_service.CheckinAndCommandService, ddmService nanomdm_service.DeclarativeManagement, profileService nanomdm_service.ProfileService, - logger *logging.Logger, + logger *slog.Logger, fleetConfig config.FleetConfig, ) error { certVerifier := mdmcrypto.NewSCEPVerifier(mdmStorage) @@ -1357,7 +1360,7 @@ func registerMDM( return nil } -func WithMDMEnrollmentMiddleware(svc fleet.Service, logger *logging.Logger, next http.Handler) http.HandlerFunc { +func WithMDMEnrollmentMiddleware(svc fleet.Service, logger *slog.Logger, next http.Handler) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/mdm/sso" && r.URL.Path != "/account_driven_enroll/sso" { // TODO: redirects for non-SSO config web url? diff --git a/server/service/handler_test.go b/server/service/handler_test.go index e3d56a4157..c74cf065cd 100644 --- a/server/service/handler_test.go +++ b/server/service/handler_test.go @@ -4,6 +4,7 @@ import ( "bufio" "context" "fmt" + "log/slog" "net/http" "net/http/httptest" "regexp" @@ -16,7 +17,6 @@ import ( "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/mock" "github.com/fleetdm/fleet/v4/server/platform/endpointer" - "github.com/fleetdm/fleet/v4/server/platform/logging" kithttp "github.com/go-kit/kit/transport/http" "github.com/gorilla/mux" "github.com/prometheus/client_golang/prometheus" @@ -31,7 +31,7 @@ func TestAPIRoutesConflicts(t *testing.T) { svc, _ := newTestService(t, ds, nil, nil) limitStore, _ := memstore.New(0) cfg := config.TestConfig() - h := MakeHandler(svc, cfg, logging.NewNopLogger(), limitStore, nil, nil, nil) + h := MakeHandler(svc, cfg, slog.New(slog.DiscardHandler), limitStore, nil, nil, nil) router := h.(*mux.Router) type testCase struct { @@ -85,7 +85,7 @@ func TestAPIRoutesMetrics(t *testing.T) { svc, _ := newTestService(t, ds, nil, nil) limitStore, _ := memstore.New(0) - h := MakeHandler(svc, config.TestConfig(), logging.NewNopLogger(), limitStore, nil, nil, nil) + h := MakeHandler(svc, config.TestConfig(), slog.New(slog.DiscardHandler), limitStore, nil, nil, nil) router := h.(*mux.Router) // replace all handlers with mocks, and collect the requests to make to each diff --git a/server/service/hosts.go b/server/service/hosts.go index c1ecf2549f..75024a0d58 100644 --- a/server/service/hosts.go +++ b/server/service/hosts.go @@ -1222,7 +1222,7 @@ func (svc *Service) AddHostsToTeam(ctx context.Context, teamID *uint, hostIDs [] if _, err := worker.QueueMacosSetupAssistantJob( ctx, svc.ds, - svc.logger.SlogLogger(), + svc.logger, worker.MacosSetupAssistantHostsTransferred, teamID, serials...); err != nil { @@ -1242,7 +1242,7 @@ func (svc *Service) AddHostsToTeam(ctx context.Context, teamID *uint, hostIDs [] return ctxerr.Wrap(ctx, err, "get android enterprise") } - if err := worker.QueueBulkSetAndroidAppsAvailableForHosts(ctx, svc.ds, svc.logger.SlogLogger(), androidUUIDs, enterprise.Name()); err != nil { + if err := worker.QueueBulkSetAndroidAppsAvailableForHosts(ctx, svc.ds, svc.logger, androidUUIDs, enterprise.Name()); err != nil { return ctxerr.Wrap(ctx, err, "queue bulk set available android apps for hosts job") } } @@ -1376,7 +1376,7 @@ func (svc *Service) AddHostsToTeamByFilter(ctx context.Context, teamID *uint, fi if _, err := worker.QueueMacosSetupAssistantJob( ctx, svc.ds, - svc.logger.SlogLogger(), + svc.logger, worker.MacosSetupAssistantHostsTransferred, teamID, serials...); err != nil { diff --git a/server/service/hosts_test.go b/server/service/hosts_test.go index 62aac0a35c..35a4aeefb3 100644 --- a/server/service/hosts_test.go +++ b/server/service/hosts_test.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "iter" + "log/slog" "net/http" "net/http/httptest" "strconv" @@ -31,7 +32,6 @@ import ( "github.com/fleetdm/fleet/v4/server/mdm/apple/mobileconfig" "github.com/fleetdm/fleet/v4/server/mdm/nanodep/tokenpki" "github.com/fleetdm/fleet/v4/server/mock" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/ptr" "github.com/fleetdm/fleet/v4/server/test" "github.com/jmoiron/sqlx" @@ -3316,7 +3316,7 @@ func TestBulkOperationFilterValidation(t *testing.T) { func TestSetDiskEncryptionNotifications(t *testing.T) { ds := new(mock.Store) ctx := context.Background() - svc := &Service{ds: ds, logger: logging.NewNopLogger()} + svc := &Service{ds: ds, logger: slog.New(slog.DiscardHandler)} tests := []struct { name string diff --git a/server/service/integration_enterprise_test.go b/server/service/integration_enterprise_test.go index c3fd94abdf..6cb0830e59 100644 --- a/server/service/integration_enterprise_test.go +++ b/server/service/integration_enterprise_test.go @@ -12669,7 +12669,7 @@ func (s *integrationEnterpriseTestSuite) TestSoftwareInstallerUploadDownloadAndD logger := logging.NewLogfmtLogger(os.Stderr) // Run the migration when nothing is to be done - err = eeservice.UninstallSoftwareMigration(context.Background(), s.ds, s.softwareInstallStore, logger) + err = eeservice.UninstallSoftwareMigration(context.Background(), s.ds, s.softwareInstallStore, logger.SlogLogger()) require.NoError(t, err) // check the software installer @@ -12707,7 +12707,7 @@ func (s *integrationEnterpriseTestSuite) TestSoftwareInstallerUploadDownloadAndD assert.Equal(t, "exit 1", respTitle.SoftwareTitle.SoftwarePackage.UninstallScript) // Run the migration - err = eeservice.UninstallSoftwareMigration(context.Background(), s.ds, s.softwareInstallStore, logger) + err = eeservice.UninstallSoftwareMigration(context.Background(), s.ds, s.softwareInstallStore, logger.SlogLogger()) require.NoError(t, err) // Check package ID and extension @@ -12740,7 +12740,7 @@ func (s *integrationEnterpriseTestSuite) TestSoftwareInstallerUploadDownloadAndD assert.Equal(t, uninstallScript, respTitle.SoftwareTitle.SoftwarePackage.UninstallScript) // Running the migration again causes no issues. - err = eeservice.UninstallSoftwareMigration(context.Background(), s.ds, s.softwareInstallStore, logger) + err = eeservice.UninstallSoftwareMigration(context.Background(), s.ds, s.softwareInstallStore, logger.SlogLogger()) require.NoError(t, err) // Update DB by clearing package ids and swapping extension to one we skip @@ -12753,7 +12753,7 @@ func (s *integrationEnterpriseTestSuite) TestSoftwareInstallerUploadDownloadAndD }) // Running the migration again causes no issues. - err = eeservice.UninstallSoftwareMigration(context.Background(), s.ds, s.softwareInstallStore, logger) + err = eeservice.UninstallSoftwareMigration(context.Background(), s.ds, s.softwareInstallStore, logger.SlogLogger()) require.NoError(t, err) // Package ID and extension should not have been modified diff --git a/server/service/integration_mdm_ddm_test.go b/server/service/integration_mdm_ddm_test.go index 318b85e84c..0de7d946ae 100644 --- a/server/service/integration_mdm_ddm_test.go +++ b/server/service/integration_mdm_ddm_test.go @@ -845,7 +845,7 @@ func (s *integrationMDMTestSuite) TestAppleDDMReconciliation() { require.Nil(t, hostResp.Host.MDM.Profiles) // trigger the reconciler, no error - err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger) + err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) // declarativeManagement command is not sent. @@ -856,7 +856,7 @@ func (s *integrationMDMTestSuite) TestAppleDDMReconciliation() { addDeclaration("I2", 0, nil) // reconcile again, this time new declarations were added - err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger) + err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) // TODO: check command is pending @@ -865,7 +865,7 @@ func (s *integrationMDMTestSuite) TestAppleDDMReconciliation() { checkDDMSync(device) // reconcile again, commands for the uploaded declarations are already sent - err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger) + err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) // no new commands are sent checkNoCommands(device) @@ -873,7 +873,7 @@ func (s *integrationMDMTestSuite) TestAppleDDMReconciliation() { // delete a declaration deleteDeclaration(d1UUID) // reconcile again - err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger) + err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) // a DDM sync is triggered checkDDMSync(device) @@ -881,7 +881,7 @@ func (s *integrationMDMTestSuite) TestAppleDDMReconciliation() { // add a new host _, deviceTwo := createHostThenEnrollMDM(s.ds, s.server.URL, t) // reconcile again - err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger) + err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) // DDM sync is triggered only for the new host checkNoCommands(device) @@ -892,7 +892,7 @@ func (s *integrationMDMTestSuite) TestAppleDDMReconciliation() { addHostsToTeamRequest{TeamID: &team.ID, HostIDs: []uint{mdmHost.ID}}, http.StatusOK) // reconcile - err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger) + err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) // DDM sync is triggered only for the transferred host @@ -901,7 +901,7 @@ func (s *integrationMDMTestSuite) TestAppleDDMReconciliation() { checkNoCommands(deviceTwo) // reconcile - err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger) + err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) // nobody receives commands this time checkNoCommands(device) @@ -912,7 +912,7 @@ func (s *integrationMDMTestSuite) TestAppleDDMReconciliation() { addDeclaration("I2", team.ID, nil) // reconcile - err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger) + err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) // DDM sync is triggered for the host in the team checkDDMSync(device) @@ -924,7 +924,7 @@ func (s *integrationMDMTestSuite) TestAppleDDMReconciliation() { addHostsToTeamRequest{TeamID: &team.ID, HostIDs: []uint{mdmHostThree.ID}}, http.StatusOK) // reconcile - err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger) + err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) // DDM sync is triggered only for the new host checkNoCommands(device) @@ -932,7 +932,7 @@ func (s *integrationMDMTestSuite) TestAppleDDMReconciliation() { checkDDMSync(deviceThree) // no new commands after another reconciliation - err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger) + err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) checkNoCommands(device) checkNoCommands(deviceTwo) @@ -957,7 +957,7 @@ func (s *integrationMDMTestSuite) TestAppleDDMReconciliation() { addDeclaration("I3", team.ID, []string{label.Name}) // reconcile - err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger) + err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) // DDM sync is triggered only for the host with the label checkNoCommands(device) @@ -989,7 +989,7 @@ func (s *integrationMDMTestSuite) TestAppleDDMStatusReport() { s.Do("POST", "/api/v1/fleet/mdm/profiles/batch", batchSetMDMProfilesRequest{Profiles: declarations}, http.StatusNoContent) // reconcile profiles - err := ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger) + err := ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) // declarations are ("install", "pending") after the cron run @@ -1084,7 +1084,7 @@ func (s *integrationMDMTestSuite) TestAppleDDMStatusReport() { s.Do("POST", "/api/v1/fleet/mdm/profiles/batch", batchSetMDMProfilesRequest{Profiles: declarations}, http.StatusNoContent) // reconcile profiles - err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger) + err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) assertHostDeclarations(mdmHost.UUID, []*fleet.MDMAppleHostDeclaration{ {Identifier: "I1", Status: &fleet.MDMDeliveryVerified, OperationType: fleet.MDMOperationTypeInstall}, @@ -1139,7 +1139,7 @@ func (s *integrationMDMTestSuite) TestDDMUnsupportedDevice() { s.Do("POST", "/api/v1/fleet/mdm/profiles/batch", batchSetMDMProfilesRequest{Profiles: declarations}, http.StatusNoContent) // reconcile declarations - err := ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger) + err := ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) // declaration is pending @@ -1232,7 +1232,7 @@ func (s *integrationMDMTestSuite) TestDDMTransactionRecording() { s.Do("POST", "/api/v1/fleet/mdm/profiles/batch", batchSetMDMProfilesRequest{Profiles: declarations}, http.StatusNoContent) // reconcile declarations - err := ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger) + err := ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) _, mdmDevice := createHostThenEnrollMDM(s.ds, s.server.URL, t) @@ -1263,7 +1263,7 @@ func (s *integrationMDMTestSuite) TestDDMTransactionRecording() { // a second device requests tokens _, mdmDeviceTwo := createHostThenEnrollMDM(s.ds, s.server.URL, t) - err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger) + err = ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) _, err = mdmDeviceTwo.DeclarativeManagement("tokens") diff --git a/server/service/integration_mdm_lifecycle_test.go b/server/service/integration_mdm_lifecycle_test.go index 6646a38db9..e4e91e6e73 100644 --- a/server/service/integration_mdm_lifecycle_test.go +++ b/server/service/integration_mdm_lifecycle_test.go @@ -923,7 +923,7 @@ func (s *integrationMDMTestSuite) TestLifecycleSCEPCertExpiration() { logger := logging.NewJSONLogger(os.Stdout) // run without expired certs, no command enqueued - err = RenewSCEPCertificates(ctx, logger, s.ds, &fleetCfg, s.mdmCommander) + err = RenewSCEPCertificates(ctx, logger.SlogLogger(), s.ds, &fleetCfg, s.mdmCommander) require.NoError(t, err) cmd, err := manualEnrolledDevice.Idle() require.NoError(t, err) @@ -960,7 +960,7 @@ func (s *integrationMDMTestSuite) TestLifecycleSCEPCertExpiration() { expireCerts() // generate a new config here so we can manipulate the certs. - err = RenewSCEPCertificates(ctx, logger, s.ds, &fleetCfg, s.mdmCommander) + err = RenewSCEPCertificates(ctx, logger.SlogLogger(), s.ds, &fleetCfg, s.mdmCommander) require.NoError(t, err) checkRenewCertCommand := func(device *mdmtest.TestAppleMDMClient, enrollRef string, wantProfile string, wantManagedAppleID string) { @@ -1013,12 +1013,12 @@ func (s *integrationMDMTestSuite) TestLifecycleSCEPCertExpiration() { // set the env var, and run the cron t.Setenv("FLEET_SILENT_MIGRATION_ENROLLMENT_PROFILE", base64.StdEncoding.EncodeToString([]byte(""))) - err = RenewSCEPCertificates(ctx, logger, s.ds, &fleetCfg, s.mdmCommander) + err = RenewSCEPCertificates(ctx, logger.SlogLogger(), s.ds, &fleetCfg, s.mdmCommander) require.NoError(t, err) checkRenewCertCommand(migratedDevice, "", "", "") // another cron run shouldn't enqueue more commands - err = RenewSCEPCertificates(ctx, logger, s.ds, &fleetCfg, s.mdmCommander) + err = RenewSCEPCertificates(ctx, logger.SlogLogger(), s.ds, &fleetCfg, s.mdmCommander) require.NoError(t, err) cmd, err = manualEnrolledDevice.Idle() @@ -1085,7 +1085,7 @@ func (s *integrationMDMTestSuite) TestLifecycleSCEPCertExpiration() { } resp := deleteHostsResponse{} s.DoJSON("POST", "/api/latest/fleet/hosts/delete", req, http.StatusOK, &resp) - err = RenewSCEPCertificates(ctx, logger, s.ds, &fleetCfg, s.mdmCommander) + err = RenewSCEPCertificates(ctx, logger.SlogLogger(), s.ds, &fleetCfg, s.mdmCommander) require.NoError(t, err) checkRenewCertCommand(automaticEnrolledDevice, "", "", "") checkRenewCertCommand(automaticEnrolledDeviceWithRef, "foo", "", "") @@ -1141,7 +1141,7 @@ func (s *integrationMDMTestSuite) TestLifecycleSCEPCertExpiration() { require.False(t, renewCmdUUID.Valid) // running cron enqueues the renew command - err = RenewSCEPCertificates(ctx, logger, s.ds, &fleetCfg, s.mdmCommander) + err = RenewSCEPCertificates(ctx, logger.SlogLogger(), s.ds, &fleetCfg, s.mdmCommander) require.NoError(t, err) // we now have a renew command uuid @@ -1165,7 +1165,7 @@ func (s *integrationMDMTestSuite) TestLifecycleSCEPCertExpiration() { require.Nil(t, cmd) // error doesn't trigger new command immediately // running cron again doesn't change anything if the renew command failed - err = RenewSCEPCertificates(ctx, logger, s.ds, &fleetCfg, s.mdmCommander) + err = RenewSCEPCertificates(ctx, logger.SlogLogger(), s.ds, &fleetCfg, s.mdmCommander) require.NoError(t, err) cmd, err = iPadMdmDevice.Idle() require.NoError(t, err) @@ -1189,7 +1189,7 @@ func (s *integrationMDMTestSuite) TestLifecycleSCEPCertExpiration() { require.Empty(t, getEnrollRef(iPadMdmDevice.UUID)) // running cron again doesn't change anything until refetch is done - err = RenewSCEPCertificates(ctx, logger, s.ds, &fleetCfg, s.mdmCommander) + err = RenewSCEPCertificates(ctx, logger.SlogLogger(), s.ds, &fleetCfg, s.mdmCommander) require.NoError(t, err) cmd, err = iPadMdmDevice.Idle() require.NoError(t, err) @@ -1238,7 +1238,7 @@ func (s *integrationMDMTestSuite) TestLifecycleSCEPCertExpiration() { }) // now run renewal cron to issue new command - err = RenewSCEPCertificates(ctx, logger, s.ds, &fleetCfg, s.mdmCommander) + err = RenewSCEPCertificates(ctx, logger.SlogLogger(), s.ds, &fleetCfg, s.mdmCommander) require.NoError(t, err) renewCmdUUID = getRenewCmdUUID(iPadMdmDevice.UUID) diff --git a/server/service/integration_mdm_profiles_test.go b/server/service/integration_mdm_profiles_test.go index 74a7731145..37e660d3de 100644 --- a/server/service/integration_mdm_profiles_test.go +++ b/server/service/integration_mdm_profiles_test.go @@ -521,7 +521,7 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() { declUUID := resp.ProfileUUID checkDDMSync := func(d *mdmtest.TestAppleMDMClient) { - require.NoError(t, ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger)) + require.NoError(t, ReconcileAppleDeclarations(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger())) cmd, err := d.Idle() require.NoError(t, err) require.NotNil(t, cmd) @@ -5345,7 +5345,7 @@ func (s *integrationMDMTestSuite) TestMDMBatchSetProfilesKeepsReservedNames() { if len(secrets) == 0 { require.NoError(t, s.ds.ApplyEnrollSecrets(ctx, nil, []*fleet.EnrollSecret{{Secret: t.Name()}})) } - require.NoError(t, ReconcileAppleProfiles(ctx, s.ds, s.mdmCommander, s.logger)) + require.NoError(t, ReconcileAppleProfiles(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger())) // turn on disk encryption and os updates s.DoJSON("PATCH", "/api/latest/fleet/config", json.RawMessage(`{ @@ -5425,7 +5425,7 @@ func (s *integrationMDMTestSuite) TestMDMBatchSetProfilesKeepsReservedNames() { require.Equal(t, "13.3.8", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value) require.Equal(t, true, tmResp.Team.Config.MDM.MacOSUpdates.UpdateNewHosts.Value) - require.NoError(t, ReconcileAppleProfiles(ctx, s.ds, s.mdmCommander, s.logger)) + require.NoError(t, ReconcileAppleProfiles(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger())) checkMacProfs(&tmResp.Team.ID, servermdm.ListFleetReservedMacOSProfileNames()...) checkWinProfs(&tmResp.Team.ID, servermdm.ListFleetReservedWindowsProfileNames()...) diff --git a/server/service/integration_mdm_test.go b/server/service/integration_mdm_test.go index e9047dbde1..d1bcd7d1dd 100644 --- a/server/service/integration_mdm_test.go +++ b/server/service/integration_mdm_test.go @@ -210,7 +210,7 @@ func (s *integrationMDMTestSuite) SetupSuite() { mdmStorage, mdmStorage, pushFactory, - NewNanoMDMLogger(pushLog), + NewNanoMDMLogger(pushLog.SlogLogger()), ) mdmCommander := apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPushService) s.redisPool = redistest.SetupRedis(s.T(), "zz", false, false, false) @@ -293,7 +293,7 @@ func (s *integrationMDMTestSuite) SetupSuite() { bootstrapPackageStore = s3.SetupTestBootstrapPackageStore(s.T(), "integration-tests", "") } scepTimeout := ptr.Duration(10 * time.Second) - s.scepConfig = eeservice.NewSCEPConfigService(serverLogger, scepTimeout).(*eeservice.SCEPConfigService) + s.scepConfig = eeservice.NewSCEPConfigService(serverLogger.SlogLogger(), scepTimeout).(*eeservice.SCEPConfigService) // Create a software title icon store iconDir := s.T().TempDir() @@ -337,7 +337,7 @@ func (s *integrationMDMTestSuite) SetupSuite() { s.onProfileJobDone() }() } - err = ReconcileAppleProfiles(ctx, ds, mdmCommander, logger) + err = ReconcileAppleProfiles(ctx, ds, mdmCommander, logger.SlogLogger()) require.NoError(s.T(), err) return err }), @@ -350,7 +350,7 @@ func (s *integrationMDMTestSuite) SetupSuite() { s.onProfileJobDone() }() } - err = ReconcileAppleDeclarations(ctx, ds, mdmCommander, logger) + err = ReconcileAppleDeclarations(ctx, ds, mdmCommander, logger.SlogLogger()) require.NoError(s.T(), err) return err }), @@ -11664,7 +11664,7 @@ func (s *integrationMDMTestSuite) TestSilentMigrationGotchas() { fleetCfg := config.TestConfig() config.SetTestMDMConfig(s.T(), &fleetCfg, cert, key, "") logger := logging.NewJSONLogger(os.Stdout) - err = RenewSCEPCertificates(ctx, logger, s.ds, &fleetCfg, s.mdmCommander) + err = RenewSCEPCertificates(ctx, logger.SlogLogger(), s.ds, &fleetCfg, s.mdmCommander) require.NoError(t, err) // no new commands were enqueued @@ -11724,13 +11724,13 @@ func (s *integrationMDMTestSuite) TestAPNsPushCron() { } // trigger the reconciliation schedule - err := ReconcileAppleProfiles(ctx, s.ds, s.mdmCommander, s.logger) + err := ReconcileAppleProfiles(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) require.Len(t, recordedPushes, 1) recordedPushes = nil // triggering the schedule again doesn't send any more pushes - err = ReconcileAppleProfiles(ctx, s.ds, s.mdmCommander, s.logger) + err = ReconcileAppleProfiles(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) require.Len(t, recordedPushes, 0) recordedPushes = nil @@ -11738,7 +11738,7 @@ func (s *integrationMDMTestSuite) TestAPNsPushCron() { // the cron to trigger pushes sends a new push request each time it // runs if there are pending commands for i := 0; i < 3; i++ { - err := SendPushesToPendingDevices(ctx, s.ds, s.mdmCommander, s.logger) + err := SendPushesToPendingDevices(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) require.Len(t, recordedPushes, 1) recordedPushes = nil @@ -11754,7 +11754,7 @@ func (s *integrationMDMTestSuite) TestAPNsPushCron() { } // no more pushes are enqueued - err = SendPushesToPendingDevices(ctx, s.ds, s.mdmCommander, s.logger) + err = SendPushesToPendingDevices(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) require.Len(t, recordedPushes, 0) } @@ -11785,7 +11785,7 @@ func (s *integrationMDMTestSuite) TestAPNsPushWithNotNow() { } // trigger the reconciliation schedule - err := ReconcileAppleProfiles(ctx, s.ds, s.mdmCommander, s.logger) + err := ReconcileAppleProfiles(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) require.Len(t, recordedPushes, 1) recordedPushes = nil @@ -11806,13 +11806,13 @@ func (s *integrationMDMTestSuite) TestAPNsPushWithNotNow() { }}, http.StatusNoContent) // trigger the reconciliation schedule - err = ReconcileAppleProfiles(ctx, s.ds, s.mdmCommander, s.logger) + err = ReconcileAppleProfiles(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) require.Len(t, recordedPushes, 1) recordedPushes = nil // The cron to trigger pushes sends a new push request each time it runs. - err = SendPushesToPendingDevices(ctx, s.ds, s.mdmCommander, s.logger) + err = SendPushesToPendingDevices(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) require.Len(t, recordedPushes, 1) recordedPushes = nil @@ -11826,7 +11826,7 @@ func (s *integrationMDMTestSuite) TestAPNsPushWithNotNow() { assert.Nil(t, cmd) // A 'NotNow' command will not trigger a new push. Device is expected to check in again when conditions change. - err = ReconcileAppleProfiles(ctx, s.ds, s.mdmCommander, s.logger) + err = ReconcileAppleProfiles(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) require.Len(t, recordedPushes, 0) recordedPushes = nil @@ -11840,7 +11840,7 @@ func (s *integrationMDMTestSuite) TestAPNsPushWithNotNow() { assert.Nil(t, cmd) // no more pushes are enqueued - err = SendPushesToPendingDevices(ctx, s.ds, s.mdmCommander, s.logger) + err = SendPushesToPendingDevices(ctx, s.ds, s.mdmCommander, s.logger.SlogLogger()) require.NoError(t, err) assert.Zero(t, recordedPushes) } diff --git a/server/service/integrationtest/scep_server/scep.go b/server/service/integrationtest/scep_server/scep.go index 387d470575..f1b72454b1 100644 --- a/server/service/integrationtest/scep_server/scep.go +++ b/server/service/integrationtest/scep_server/scep.go @@ -65,7 +65,7 @@ func StartTestSCEPServer(t *testing.T) *httptest.Server { } logger := logging.NewNopLogger() e := scepserver.MakeServerEndpoints(svc) - scepHandler := scepserver.MakeHTTPHandler(e, svc, logger) + scepHandler := scepserver.MakeHTTPHandler(e, svc, logger.SlogLogger()) r := mux.NewRouter() r.Handle("/scep", scepHandler) server = httptest.NewServer(r) diff --git a/server/service/mdm_scep.go b/server/service/mdm_scep.go index ea923c72d2..492a5c0c2a 100644 --- a/server/service/mdm_scep.go +++ b/server/service/mdm_scep.go @@ -4,6 +4,7 @@ import ( "context" "crypto/rsa" "errors" + "log/slog" "github.com/fleetdm/fleet/v4/server/contexts/ctxerr" "github.com/fleetdm/fleet/v4/server/fleet" @@ -23,7 +24,7 @@ type service struct { signer scepserver.CSRSignerContext /// info logging is implemented in the service middleware layer. - debugLogger *logging.Logger + debugLogger *slog.Logger ds fleet.MDMAssetRetriever } @@ -45,7 +46,7 @@ func (svc *service) PKIOperation(ctx context.Context, data []byte) ([]byte, erro if len(data) == 0 { return nil, &fleet.BadRequestError{Message: "missing data for PKIOperation"} } - msg, err := scep.ParsePKIMessage(data, scep.WithLogger(svc.debugLogger)) + msg, err := scep.ParsePKIMessage(data, scep.WithLogger(logging.NewLogger(svc.debugLogger))) if err != nil { return nil, err } @@ -69,7 +70,7 @@ func (svc *service) PKIOperation(ctx context.Context, data []byte) ([]byte, erro err = errors.New("no signed certificate") } if err != nil { - svc.debugLogger.Log("msg", "failed to sign CSR", "err", err) + svc.debugLogger.ErrorContext(ctx, "failed to sign CSR", "err", err) certRep, err := msg.Fail(cert.Leaf, pk, scep.BadRequest) return certRep.Raw, err } @@ -83,10 +84,10 @@ func (svc *service) GetNextCACert(ctx context.Context) ([]byte, error) { } // NewService creates a new scep service -func NewSCEPService(ds fleet.MDMAssetRetriever, signer scepserver.CSRSignerContext, logger *logging.Logger) scepserver.Service { +func NewSCEPService(ds fleet.MDMAssetRetriever, signer scepserver.CSRSignerContext, logger *slog.Logger) scepserver.Service { return &service{ signer: signer, - debugLogger: logging.NewNopLogger(), + debugLogger: slog.New(slog.DiscardHandler), ds: ds, } } diff --git a/server/service/orbit.go b/server/service/orbit.go index d7d9416923..2e21fcfdf3 100644 --- a/server/service/orbit.go +++ b/server/service/orbit.go @@ -640,7 +640,7 @@ func (svc *Service) processReleaseDeviceForOldFleetd(ctx context.Context, host * } // Enroll reference arg is not used in the release device task, passing empty string. - if err := worker.QueueAppleMDMJob(ctx, svc.ds, svc.logger.SlogLogger(), worker.AppleMDMPostDEPReleaseDeviceTask, + if err := worker.QueueAppleMDMJob(ctx, svc.ds, svc.logger, worker.AppleMDMPostDEPReleaseDeviceTask, host.UUID, host.Platform, host.TeamID, "", false, false, bootstrapCmdUUID, acctConfigCmdUUID); err != nil { return ctxerr.Wrap(ctx, err, "queue Apple Post-DEP release device job") } @@ -1192,7 +1192,7 @@ func (svc *Service) SetOrUpdateDiskEncryptionKey(ctx context.Context, encryption } // Only archive the key if disk encryption is enabled for this host (team/globally) - if !osquery_utils.IsDiskEncryptionEnabledForHost(ctx, svc.logger.SlogLogger(), svc.ds, host) { + if !osquery_utils.IsDiskEncryptionEnabledForHost(ctx, svc.logger, svc.ds, host) { svc.logger.DebugContext(ctx, "skipping key archival, disk encryption not enabled for host team/globally", "host_id", host.ID, @@ -1300,7 +1300,7 @@ func (svc *Service) EscrowLUKSData(ctx context.Context, passphrase string, salt } // Only archive the key if disk encryption is enabled for this host (team/globally) - if !osquery_utils.IsDiskEncryptionEnabledForHost(ctx, svc.logger.SlogLogger(), svc.ds, host) { + if !osquery_utils.IsDiskEncryptionEnabledForHost(ctx, svc.logger, svc.ds, host) { svc.logger.DebugContext(ctx, "skipping LUKS key archival, disk encryption not enabled for host team/globally", "host_id", host.ID, diff --git a/server/service/orbit_test.go b/server/service/orbit_test.go index 559b7bd49f..b4ad6031a2 100644 --- a/server/service/orbit_test.go +++ b/server/service/orbit_test.go @@ -5,6 +5,7 @@ import ( "database/sql" "encoding/json" "errors" + "log/slog" "testing" "github.com/fleetdm/fleet/v4/pkg/optjson" @@ -13,7 +14,6 @@ import ( "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/mdm" "github.com/fleetdm/fleet/v4/server/mock" - logging "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/ptr" "github.com/fleetdm/fleet/v4/server/test" "github.com/stretchr/testify/require" @@ -695,7 +695,7 @@ func TestGetSoftwareInstallDetails(t *testing.T) { func TestShouldRetrySoftwareInstall(t *testing.T) { svc := &Service{ - logger: logging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), } ctx := context.Background() @@ -742,7 +742,7 @@ func TestRetrySoftwareInstall(t *testing.T) { ds := new(mock.Store) svc := &Service{ ds: ds, - logger: logging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), } ctx := context.Background() @@ -788,7 +788,7 @@ func TestGetSoftwareInstallerAttemptNumber(t *testing.T) { ds := new(mock.Store) svc := &Service{ ds: ds, - logger: logging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), } ctx := context.Background() host := &fleet.Host{ID: 1} diff --git a/server/service/osquery.go b/server/service/osquery.go index 1d9e548ede..a02e127ad8 100644 --- a/server/service/osquery.go +++ b/server/service/osquery.go @@ -26,14 +26,12 @@ import ( "github.com/fleetdm/fleet/v4/server/contexts/license" "github.com/fleetdm/fleet/v4/server/contexts/logging" "github.com/fleetdm/fleet/v4/server/fleet" - platformlogging "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/ptr" "github.com/fleetdm/fleet/v4/server/pubsub" "github.com/fleetdm/fleet/v4/server/service/conditional_access_microsoft_proxy" "github.com/fleetdm/fleet/v4/server/service/contract" "github.com/fleetdm/fleet/v4/server/service/osquery_utils" kithttp "github.com/go-kit/kit/transport/http" - "github.com/go-kit/log/level" "github.com/spf13/cast" "golang.org/x/exp/slices" ) @@ -137,7 +135,7 @@ func (svc *Service) EnrollOsquery(ctx context.Context, enrollSecret, hostIdentif return "", newOsqueryErrorWithInvalidNode("generate node key failed: " + err.Error()) } - hostIdentifier = getHostIdentifier(svc.logger, svc.config.Osquery.HostIdentifier, hostIdentifier, hostDetails) + hostIdentifier = getHostIdentifier(ctx, svc.logger, svc.config.Osquery.HostIdentifier, hostIdentifier, hostDetails) canEnroll, err := svc.enrollHostLimiter.CanEnrollNewHost(ctx) if err != nil { return "", newOsqueryErrorWithInvalidNode("can enroll host check failed: " + err.Error()) @@ -172,7 +170,7 @@ func (svc *Service) EnrollOsquery(ctx context.Context, enrollSecret, hostIdentif if err != nil { // Log error but continue enrollment (fail-open approach). If Redis is unavailable, // enrollment proceeds without sticky behavior rather than blocking. - level.Error(svc.logger).Log("msg", "failed to get sticky enrollment", "err", err, "host_uuid", hardwareUUID) + svc.logger.ErrorContext(ctx, "failed to get sticky enrollment", "err", err, "host_uuid", hardwareUUID) } } @@ -208,21 +206,21 @@ func (svc *Service) EnrollOsquery(ctx context.Context, enrollSecret, hostIdentif ) save := false if r, ok := hostDetails["os_version"]; ok { - err := detailQueries["os_version"].IngestFunc(ctx, svc.logger.SlogLogger(), host, []map[string]string{r}) + err := detailQueries["os_version"].IngestFunc(ctx, svc.logger, host, []map[string]string{r}) if err != nil { return "", ctxerr.Wrap(ctx, err, "Ingesting os_version") } save = true } if r, ok := hostDetails["osquery_info"]; ok { - err := detailQueries["osquery_info"].IngestFunc(ctx, svc.logger.SlogLogger(), host, []map[string]string{r}) + err := detailQueries["osquery_info"].IngestFunc(ctx, svc.logger, host, []map[string]string{r}) if err != nil { return "", ctxerr.Wrap(ctx, err, "Ingesting osquery_info") } save = true } if r, ok := hostDetails["system_info"]; ok { - err := detailQueries["system_info"].IngestFunc(ctx, svc.logger.SlogLogger(), host, []map[string]string{r}) + err := detailQueries["system_info"].IngestFunc(ctx, svc.logger, host, []map[string]string{r}) if err != nil { return "", ctxerr.Wrap(ctx, err, "Ingesting system_info") } @@ -249,17 +247,16 @@ func (svc *Service) serialUpdateHost(host *fleet.Host) { defer func() { atomic.AddInt64(&counter, -1) }() - level.Debug(svc.logger).Log("background", newVal) - ctx, cancelFunc := context.WithTimeout(context.Background(), 30*time.Second) defer cancelFunc() + svc.logger.DebugContext(ctx, "serial update host background", "background", newVal) err := svc.ds.SerialUpdateHost(ctx, host) if err != nil { - level.Error(svc.logger).Log("background-err", err) + svc.logger.ErrorContext(ctx, "serial update host background error", "err", err) } } -func getHostIdentifier(logger *platformlogging.Logger, identifierOption, providedIdentifier string, details map[string](map[string]string)) string { +func getHostIdentifier(ctx context.Context, logger *slog.Logger, identifierOption, providedIdentifier string, details map[string](map[string]string)) string { switch identifierOption { case "provided": // Use the host identifier already provided in the request. @@ -268,14 +265,12 @@ func getHostIdentifier(logger *platformlogging.Logger, identifierOption, provide case "instance": r, ok := details["osquery_info"] if !ok { //nolint:gocritic // ignore ifElseChain - level.Info(logger).Log( - "msg", "could not get host identifier", + logger.InfoContext(ctx, "could not get host identifier", "reason", "missing osquery_info", "identifier", "instance", ) } else if r["instance_id"] == "" { - level.Info(logger).Log( - "msg", "could not get host identifier", + logger.InfoContext(ctx, "could not get host identifier", "reason", "missing instance_id in osquery_info", "identifier", "instance", ) @@ -286,14 +281,12 @@ func getHostIdentifier(logger *platformlogging.Logger, identifierOption, provide case "uuid": r, ok := details["osquery_info"] if !ok { //nolint:gocritic // ignore ifElseChain - level.Info(logger).Log( - "msg", "could not get host identifier", + logger.InfoContext(ctx, "could not get host identifier", "reason", "missing osquery_info", "identifier", "uuid", ) } else if r["uuid"] == "" { - level.Info(logger).Log( - "msg", "could not get host identifier", + logger.InfoContext(ctx, "could not get host identifier", "reason", "missing instance_id in osquery_info", "identifier", "uuid", ) @@ -304,14 +297,12 @@ func getHostIdentifier(logger *platformlogging.Logger, identifierOption, provide case "hostname": r, ok := details["system_info"] if !ok { //nolint:gocritic // ignore ifElseChain - level.Info(logger).Log( - "msg", "could not get host identifier", + logger.InfoContext(ctx, "could not get host identifier", "reason", "missing system_info", "identifier", "hostname", ) } else if r["hostname"] == "" { - level.Info(logger).Log( - "msg", "could not get host identifier", + logger.InfoContext(ctx, "could not get host identifier", "reason", "missing instance_id in system_info", "identifier", "hostname", ) @@ -327,10 +318,9 @@ func getHostIdentifier(logger *platformlogging.Logger, identifierOption, provide } func (svc *Service) debugEnabledForHost(ctx context.Context, id uint) bool { - hlogger := svc.logger.With("host-id", id) ac, err := svc.ds.AppConfig(ctx) if err != nil { - level.Debug(hlogger).Log("err", ctxerr.Wrap(ctx, err, "getting app config for host debug")) + svc.logger.DebugContext(ctx, "getting app config for host debug", "host-id", id, "err", ctxerr.Wrap(ctx, err, "getting app config for host debug")) return false } @@ -659,7 +649,7 @@ func (svc *Service) GetDistributedQueries(ctx context.Context) (queries map[stri // If the live query store fails to fetch queries we still want the hosts // to receive all the other queries (details, policies, labels, etc.), // thus we just log the error. - level.Error(svc.logger).Log("op", "QueriesForHost", "err", err) + svc.logger.ErrorContext(ctx, "QueriesForHost", "err", err) } else { for name, query := range liveQueries { queries[hostDistributedQueryPrefix+name] = query @@ -777,7 +767,7 @@ func (svc *Service) detailQueriesForHost(ctx context.Context, host *fleet.Host) queryName := hostDetailQueryPrefix + name if query.QueryFunc != nil && query.Query == "" { - query, ok := query.QueryFunc(ctx, svc.logger.SlogLogger(), host, svc.ds) + query, ok := query.QueryFunc(ctx, svc.logger, host, svc.ds) if !ok { continue } @@ -820,8 +810,7 @@ func (svc *Service) hostRequiresConditionalAccessMicrosoftIngestion(ctx context. conditionalAccessConfigured, conditionalAccessEnabledForTeam, err := svc.conditionalAccessConfiguredAndEnabledForTeam(ctx, host.TeamID) if err != nil { - level.Error(svc.logger).Log( - "msg", "load conditional access configured and enabled, skipping ingestion", + svc.logger.ErrorContext(ctx, "load conditional access configured and enabled, skipping ingestion", "host_id", host.ID, "err", err, ) @@ -837,7 +826,7 @@ func (svc *Service) shouldUpdate(lastUpdated time.Time, interval time.Duration, if svc.jitterH[interval] == nil { svc.jitterH[interval] = newJitterHashTable(int(int64(svc.config.Osquery.MaxJitterPercent) * int64(interval.Minutes()) / 100.0)) - level.Debug(svc.logger).Log("jitter", "created", "bucketCount", svc.jitterH[interval].bucketCount) + svc.logger.DebugContext(context.TODO(), "jitter table created", "bucketCount", svc.jitterH[interval].bucketCount) } jitter := svc.jitterH[interval].jitterForHost(hostID) @@ -914,7 +903,7 @@ func (svc *Service) policyQueriesForHost(ctx context.Context, host *fleet.Host) return nil, false, ctxerr.Wrap(ctx, err, "check if host is in setup experience") } if hostRunningSetupExperience { - level.Debug(svc.logger).Log("msg", "skipping policy queries for host in setup experience", "host_id", host.ID) + svc.logger.DebugContext(ctx, "skipping policy queries for host in setup experience", "host_id", host.ID) return nil, false, nil } policyQueries, err = svc.ds.PolicyQueriesForHost(ctx, host) @@ -1095,7 +1084,7 @@ func (svc *Service) SubmitDistributedQueryResults( svc.maybeDebugHost(ctx, host, results, statuses, messages, stats) - preProcessSoftwareResults(ctx, host, results, statuses, messages, osquery_utils.SoftwareOverrideQueries, svc.logger.SlogLogger()) + preProcessSoftwareResults(ctx, host, results, statuses, messages, osquery_utils.SoftwareOverrideQueries, svc.logger) var hostWithoutPolicies bool for query, rows := range results { @@ -1110,13 +1099,13 @@ func (svc *Service) SubmitDistributedQueryResults( status, ok := statuses[query] failed := ok && status != fleet.StatusOK if failed && messages[query] != "" && !noSuchTableRegexp.MatchString(messages[query]) { - ll := level.Debug(svc.logger) + logLevel := slog.LevelDebug // We'd like to log these as warning for troubleshooting and improving of distributed queries. // We have multiple feature requests filed to expose this information in the UI, including https://github.com/fleetdm/fleet/issues/18004 if messages[query] == "distributed query is denylisted" { - ll = level.Warn(svc.logger) + logLevel = slog.LevelWarn } - ll.Log("query", query, "message", messages[query], "hostID", host.ID) + svc.logger.Log(ctx, logLevel, "distributed query failed", "query", query, "message", messages[query], "hostID", host.ID) } queryStats := stats[query] @@ -1151,7 +1140,7 @@ func (svc *Service) SubmitDistributedQueryResults( } for labelID := range labelResults { if _, ok := hostLabelQueries[fmt.Sprint(labelID)]; !ok { - level.Debug(svc.logger).Log("msg", "clearing result for inapplicable label", "labelID", labelID, "hostID", host.ID) + svc.logger.DebugContext(ctx, "clearing result for inapplicable label", "labelID", labelID, "hostID", host.ID) labelResults[labelID] = ptr.Bool(false) } } @@ -1260,7 +1249,7 @@ func (svc *Service) SubmitDistributedQueryResults( } refetchCriticalCleared := refetchCriticalSet && host.RefetchCriticalQueriesUntil == nil if refetchCriticalSet { - level.Debug(svc.logger).Log("msg", "refetch critical status on submit distributed query results", "host_id", host.ID, "refetch_requested", refetchRequested, "refetch_critical_queries_until", host.RefetchCriticalQueriesUntil, "refetch_critical_cleared", refetchCriticalCleared) + svc.logger.DebugContext(ctx, "refetch critical status on submit distributed query results", "host_id", host.ID, "refetch_requested", refetchRequested, "refetch_critical_queries_until", host.RefetchCriticalQueriesUntil, "refetch_critical_cleared", refetchCriticalCleared) } if refetchRequested || detailUpdated || refetchCriticalCleared { @@ -1287,8 +1276,7 @@ func (svc *Service) SubmitDistributedQueryResults( HostDisplayName: host.DisplayName(), }, ); err != nil { - level.Error(svc.logger).Log( - "msg", "record fleet disk encryption key escrowed activity", + svc.logger.ErrorContext(ctx, "record fleet disk encryption key escrowed activity", "err", err, ) } @@ -1303,7 +1291,7 @@ func processCalendarPolicies( appConfig *fleet.AppConfig, host *fleet.Host, policyResults map[uint]*bool, - logger *platformlogging.Logger, + logger *slog.Logger, ) error { if len(appConfig.Integrations.GoogleCalendar) == 0 || host.TeamID == nil { return nil @@ -1332,9 +1320,9 @@ func processCalendarPolicies( now := time.Now() if now.Before(calendarEvent.StartTime) { - level.Warn(logger).Log("msg", "results came too early", "now", now, "start_time", calendarEvent.StartTime) + logger.WarnContext(ctx, "results came too early", "now", now, "start_time", calendarEvent.StartTime) if err = ds.UpdateHostCalendarWebhookStatus(context.Background(), host.ID, fleet.CalendarWebhookStatusError); err != nil { - level.Error(logger).Log("msg", "mark webhook as errored early", "err", err) + logger.ErrorContext(ctx, "mark webhook as errored early", "err", err) } return nil } @@ -1345,9 +1333,9 @@ func processCalendarPolicies( const allowedTimeRelativeToEndTime = 5 * time.Minute // up to 5 minutes after the end_time to allow for short (0-time) event times if now.After(calendarEvent.EndTime.Add(allowedTimeRelativeToEndTime)) { - level.Warn(logger).Log("msg", "results came too late", "now", now, "end_time", calendarEvent.EndTime) + logger.WarnContext(ctx, "results came too late", "now", now, "end_time", calendarEvent.EndTime) if err = ds.UpdateHostCalendarWebhookStatus(context.Background(), host.ID, fleet.CalendarWebhookStatusError); err != nil { - level.Error(logger).Log("msg", "mark webhook as errored late", "err", err) + logger.ErrorContext(ctx, "mark webhook as errored late", "err", err) } return nil } @@ -1373,15 +1361,15 @@ func processCalendarPolicies( if err := fleet.FireCalendarWebhook( team.Config.Integrations.GoogleCalendar.WebhookURL, host.ID, host.HardwareSerial, host.DisplayName(), failingCalendarPolicies, "", - logger.SlogLogger(), + logger, ); err != nil { var statusCoder kithttp.StatusCoder if errors.As(err, &statusCoder) && statusCoder.StatusCode() == http.StatusTooManyRequests { - level.Debug(logger).Log("msg", "fire webhook", "err", err) + logger.DebugContext(ctx, "fire webhook", "err", err) if err := ds.UpdateHostCalendarWebhookStatus( context.Background(), host.ID, fleet.CalendarWebhookStatusRetry, ); err != nil { - level.Error(logger).Log("msg", "mark fired webhook as retry", "err", err) + logger.ErrorContext(ctx, "mark fired webhook as retry", "err", err) } return err } @@ -1392,11 +1380,11 @@ func processCalendarPolicies( ) nextStatus := fleet.CalendarWebhookStatusSent if err != nil { - level.Error(logger).Log("msg", "fire webhook", "err", err) + logger.ErrorContext(ctx, "fire webhook", "err", err) nextStatus = fleet.CalendarWebhookStatusError } if err := ds.UpdateHostCalendarWebhookStatus(context.Background(), host.ID, nextStatus); err != nil { - level.Error(logger).Log("msg", fmt.Sprintf("mark fired webhook as %v", nextStatus), "err", err) + logger.ErrorContext(ctx, fmt.Sprintf("mark fired webhook as %v", nextStatus), "err", err) } }() @@ -1769,13 +1757,13 @@ func (svc *Service) directIngestDetailQuery(ctx context.Context, host *fleet.Hos return false, newOsqueryError("unknown detail query " + name) } if query.DirectIngestFunc != nil { - err = query.DirectIngestFunc(ctx, svc.logger.SlogLogger(), host, svc.ds, rows) + err = query.DirectIngestFunc(ctx, svc.logger, host, svc.ds, rows) if err != nil { return false, newOsqueryError(fmt.Sprintf("ingesting query %s: %s", name, err.Error())) } return true, nil } else if query.DirectTaskIngestFunc != nil { - err = query.DirectTaskIngestFunc(ctx, svc.logger.SlogLogger(), host, svc.task, rows) + err = query.DirectTaskIngestFunc(ctx, svc.logger, host, svc.task, rows) if err != nil { return false, newOsqueryError(fmt.Sprintf("ingesting query %s: %s", name, err.Error())) } @@ -1930,7 +1918,7 @@ func (svc *Service) ingestDetailQuery(ctx context.Context, host *fleet.Host, nam } if query.IngestFunc != nil { - err = query.IngestFunc(ctx, svc.logger.SlogLogger(), host, rows) + err = query.IngestFunc(ctx, svc.logger, host, rows) if err != nil { return newOsqueryError(fmt.Sprintf("ingesting query %s: %s", name, err.Error())) } @@ -2071,7 +2059,7 @@ func (svc *Service) processSoftwareForNewlyFailingPolicies( "software_installer_platform", installerMetadata.Platform, ) if fleet.PlatformFromHost(hostPlatform) != installerMetadata.Platform { - level.Debug(logger).Log("msg", "installer platform does not match host platform") + logger.DebugContext(ctx, "installer platform does not match host platform") continue } scoped, err := svc.ds.IsSoftwareInstallerLabelScoped(ctx, failingPolicyWithInstaller.InstallerID, hostID) @@ -2082,7 +2070,7 @@ func (svc *Service) processSoftwareForNewlyFailingPolicies( // NOTE: we update the policy status here to stop it from showing up as "failed" in the // host details. incomingPolicyResults[failingPolicyWithInstaller.ID] = nil - level.Debug(logger).Log("msg", "not marking policy as failed since software is out of scope for host") + logger.DebugContext(ctx, "not marking policy as failed since software is out of scope for host") continue } hostLastInstall, err := svc.ds.GetHostLastInstallData(ctx, hostID, installerMetadata.InstallerID) @@ -2094,8 +2082,7 @@ func (svc *Service) processSoftwareForNewlyFailingPolicies( *hostLastInstall.Status == fleet.SoftwareInstallPending { // There's a pending install for this host and installer, // thus we do not queue another install request. - level.Debug(svc.logger).Log( - "msg", "found pending install request for this host and installer", + logger.DebugContext(ctx, "found pending install request for this host and installer", "pending_execution_id", hostLastInstall.ExecutionID, ) continue @@ -2117,8 +2104,7 @@ func (svc *Service) processSoftwareForNewlyFailingPolicies( hostID, installerMetadata.InstallerID, ) } - level.Debug(logger).Log( - "msg", "install request sent", + logger.DebugContext(ctx, "install request sent", "install_uuid", installUUID, ) } @@ -2231,17 +2217,14 @@ func (svc *Service) processVPPForNewlyFailingPolicies( ) if _, hasPendingInstall := pendingAppInstalls[failingPolicyWithVPP.AdamID]; hasPendingInstall { - level.Debug(svc.logger).Log( - "msg", "install of app is already pending", - ) + logger.DebugContext(ctx, "install of app is already pending") continue } vppMetadata, err := svc.ds.GetVPPAppMetadataByAdamIDPlatformTeamID(ctx, failingPolicyWithVPP.AdamID, failingPolicyWithVPP.Platform, host.TeamID) if err != nil { - level.Error(svc.logger).Log( - "msg", "failed to get VPP metadata", - "error", err, + logger.ErrorContext(ctx, "failed to get VPP metadata", + "err", err, ) continue } @@ -2255,7 +2238,7 @@ func (svc *Service) processVPPForNewlyFailingPolicies( // NOTE: we update the policy status here to stop it from showing up as "failed" in the // host details. incomingPolicyResults[failingPolicyWithVPP.ID] = nil - level.Debug(logger).Log("msg", "not marking policy as failed since vpp app is out of scope for host") + logger.DebugContext(ctx, "not marking policy as failed since vpp app is out of scope for host") continue } @@ -2264,14 +2247,13 @@ func (svc *Service) processVPPForNewlyFailingPolicies( PolicyID: &policyID, }) if err != nil { - level.Error(svc.logger).Log( - "msg", "failed to get install VPP app", - "error", err, + logger.ErrorContext(ctx, "failed to get install VPP app", + "err", err, ) continue } - level.Debug(logger).Log("msg", "vpp install request sent", "command_uuid", commandUUID) + logger.DebugContext(ctx, "vpp install request sent", "command_uuid", commandUUID) } return nil @@ -2393,7 +2375,7 @@ func (svc *Service) processScriptsForNewlyFailingPolicies( return ctxerr.Wrap(ctx, err, "list host pending script executions") } if len(allScriptsExecutionPending) > maxPendingScripts { - level.Warn(logger).Log("msg", "too many scripts pending for host") + logger.WarnContext(ctx, "too many scripts pending for host") return nil } @@ -2401,7 +2383,7 @@ func (svc *Service) processScriptsForNewlyFailingPolicies( hostPlatform := fleet.PlatformFromHost(hostPlatform) if (hostPlatform == "windows" && strings.HasSuffix(scriptMetadata.Name, ".sh")) || (hostPlatform != "windows" && strings.HasSuffix(scriptMetadata.Name, ".ps1")) { - level.Info(logger).Log("msg", "script type does not match host platform") + logger.InfoContext(ctx, "script type does not match host platform") continue } @@ -2411,7 +2393,7 @@ func (svc *Service) processScriptsForNewlyFailingPolicies( scriptTeamID = *scriptMetadata.TeamID } if policyTeamID != scriptTeamID { // this should not happen - level.Error(logger).Log("msg", "script team does not match host team") + logger.ErrorContext(ctx, "script team does not match host team") continue } @@ -2420,7 +2402,7 @@ func (svc *Service) processScriptsForNewlyFailingPolicies( return ctxerr.Wrap(ctx, err, "check whether script is pending execution") } if scriptIsAlreadyPending { - level.Debug(logger).Log("msg", "script is already pending on host") + logger.DebugContext(ctx, "script is already pending on host") continue } @@ -2446,8 +2428,7 @@ func (svc *Service) processScriptsForNewlyFailingPolicies( ) } - level.Debug(logger).Log( - "msg", "script run request sent", + logger.DebugContext(ctx, "script run request sent", "execution_id", scriptResult.ExecutionID, ) } @@ -2591,16 +2572,15 @@ func (svc *Service) setHostConditionalAccessAsync( ) { go func() { logger := svc.logger.With( - "msg", "set host conditional access", "host_id", hostID, "managed", managed, "compliant", compliant, ) start := time.Now() if err := svc.setHostConditionalAccess(hostID, hostConditionalAccessStatus, managed, compliant); err != nil { - level.Error(logger).Log("took", time.Since(start), "err", err) + logger.ErrorContext(context.TODO(), "set host conditional access", "took", time.Since(start), "err", err) } - level.Debug(logger).Log("took", time.Since(start)) + logger.DebugContext(context.TODO(), "set host conditional access", "took", time.Since(start)) }() } @@ -2621,12 +2601,11 @@ func (svc *Service) setHostConditionalAccess( return ctxerr.Wrap(ctx, err, "get integration") } logger := svc.logger.With( - "msg", "set compliance status", "host_id", hostID, "managed", managed, "compliant", compliant, ) - level.Debug(logger).Log() + logger.DebugContext(ctx, "set compliance status") response, err := svc.conditionalAccessMicrosoftProxy.SetComplianceStatus(ctx, integration.TenantID, integration.ProxyServerSecret, @@ -2647,24 +2626,23 @@ func (svc *Service) setHostConditionalAccess( const ( timeout = 1 * time.Minute ) - level.Debug(logger).Log("msg", "set compliance status message sent") + logger.DebugContext(ctx, "set compliance status message sent") startTime := time.Now() for range time.Tick(conditionalAccessSetWaitTime) { if time.Since(startTime) > timeout { return ctxerr.Errorf(ctx, "timeout waiting for message after %s", time.Since(startTime)) } - level.Debug(logger).Log("msg", "get compliance status message wait") + logger.DebugContext(ctx, "get compliance status message wait") messageStatus, err := svc.conditionalAccessMicrosoftProxy.GetMessageStatus(ctx, integration.TenantID, integration.ProxyServerSecret, response.MessageID, ) if err != nil { // Retry again in case of network or transient errors. - level.Info(logger).Log("msg", "get message status, retrying", "err", err) + logger.InfoContext(ctx, "get message status, retrying", "err", err) continue } if messageStatus.Status == conditional_access_microsoft_proxy.MessageStatusCompleted { - level.Debug(logger).Log( - "msg", "set device compliance status completed", + logger.DebugContext(ctx, "set device compliance status completed", "took", time.Since(startTime), ) break @@ -2673,8 +2651,7 @@ func (svc *Service) setHostConditionalAccess( if messageStatus.Detail != nil { detail = *messageStatus.Detail } - level.Info(logger).Log( - "msg", "get message status, retrying", + logger.InfoContext(ctx, "get message status, retrying", "status", messageStatus.Status, "detail", detail, ) @@ -2698,11 +2675,11 @@ func (svc *Service) maybeDebugHost( if svc.debugEnabledForHost(ctx, host.ID) { hlogger := svc.logger.With("host-id", host.ID) - logJSON(hlogger, host, "host") - logJSON(hlogger, results, "results") - logJSON(hlogger, statuses, "statuses") - logJSON(hlogger, messages, "messages") - logJSON(hlogger, stats, "stats") + logJSON(ctx, hlogger, host, "host") + logJSON(ctx, hlogger, results, "results") + logJSON(ctx, hlogger, statuses, "statuses") + logJSON(ctx, hlogger, messages, "messages") + logJSON(ctx, hlogger, stats, "stats") } } @@ -2778,7 +2755,7 @@ func (svc *Service) preProcessOsqueryResults( for _, raw := range osqueryResults { var result *fleet.ScheduledQueryResult if err := json.Unmarshal(raw, &result); err != nil { - level.Debug(svc.logger).Log("msg", "unmarshalling result", "err", err, "result", lograw(raw)) + svc.logger.DebugContext(ctx, "unmarshalling result", "err", err, "result", lograw(raw)) // Note that if err != nil we have two scenarios: // - result == nil: which means the result could not be unmarshalled, e.g. not JSON. // - result != nil: which means that the result was (partially) unmarshalled but some specific @@ -2787,7 +2764,7 @@ func (svc *Service) preProcessOsqueryResults( // In both scenarios we want to add `result` to `unmarshaledResults`. } else if result != nil && result.QueryName == "" { // If the unmarshaled result doesn't have a "name" field then we ignore the result. - level.Debug(svc.logger).Log("msg", "missing name field", "result", lograw(raw)) + svc.logger.DebugContext(ctx, "missing name field", "result", lograw(raw)) result = nil } unmarshaledResults = append(unmarshaledResults, result) @@ -2810,7 +2787,7 @@ func (svc *Service) preProcessOsqueryResults( continue } if err != nil { - level.Debug(svc.logger).Log("msg", "querying name and team ID from result", "err", err) + svc.logger.DebugContext(ctx, "querying name and team ID from result", "err", err) continue } @@ -2818,7 +2795,7 @@ func (svc *Service) preProcessOsqueryResults( if !foundQuery { query, err := svc.ds.QueryByName(ctx, teamID, queryName) if err != nil { - level.Debug(svc.logger).Log("msg", "loading query by name", "err", err, "team", teamID, "name", queryName) + svc.logger.DebugContext(ctx, "loading query by name", "err", err, "team", teamID, "name", queryName) continue } queriesDBData[queryResult.QueryName] = query @@ -2827,7 +2804,7 @@ func (svc *Service) preProcessOsqueryResults( updatedResult, err := addQueryIDToLogResult(ctx, osqueryResults[i], existingQuery.ID) if err != nil { - level.Debug(svc.logger).Log("msg", "inserting query id into query result", "err", err, "query_id", existingQuery.ID) + svc.logger.DebugContext(ctx, "inserting query id into query result", "err", err, "query_id", existingQuery.ID) continue } @@ -2880,7 +2857,7 @@ func (svc *Service) SubmitResultLogs(ctx context.Context, logs []json.RawMessage var queryReportsDisabled bool appConfig, err := svc.ds.AppConfig(ctx) if err != nil { - level.Error(svc.logger).Log("msg", "getting app config", "err", err) + svc.logger.ErrorContext(ctx, "getting app config", "err", err) // If we fail to load the app config we assume the flag to be disabled // to not perform extra processing in that scenario. queryReportsDisabled = true @@ -2964,7 +2941,7 @@ func (svc *Service) saveResultLogsToQueryReports( host, ok := hostctx.FromContext(ctx) if !ok { - level.Error(svc.logger).Log("err", "getting host from context") + svc.logger.ErrorContext(ctx, "getting host from context") return } @@ -2986,7 +2963,7 @@ func (svc *Service) saveResultLogsToQueryReports( var err error queryResultCounts, err = svc.liveQueryStore.GetQueryResultsCounts(queryIDs) if err != nil { - level.Error(svc.logger).Log("msg", "get result counts for queries", "err", err) + svc.logger.ErrorContext(ctx, "get result counts for queries", "err", err) return } } @@ -3026,7 +3003,7 @@ func (svc *Service) saveResultLogsToQueryReports( var rowsAdded int var err error if rowsAdded, err = svc.overwriteResultRows(ctx, result, dbQuery.ID, host.ID, maxQueryReportRows); err != nil { - level.Error(svc.logger).Log("msg", "overwrite results", "err", err, "query_id", dbQuery.ID, "host_id", host.ID) + svc.logger.ErrorContext(ctx, "overwrite results", "err", err, "query_id", dbQuery.ID, "host_id", host.ID) continue } @@ -3038,7 +3015,7 @@ func (svc *Service) saveResultLogsToQueryReports( if svc.liveQueryStore != nil && len(rowsAddedByQuery) > 0 { if err := svc.liveQueryStore.IncrQueryResultsCounts(rowsAddedByQuery); err != nil { // Log but don't fail - the inserts succeeded, counter is just a heuristic - level.Debug(svc.logger).Log("msg", "incr query results counts in redis", "err", err) + svc.logger.DebugContext(ctx, "incr query results counts in redis", "err", err) } } } diff --git a/server/service/osquery_test.go b/server/service/osquery_test.go index d9910906c6..94c1a0ced1 100644 --- a/server/service/osquery_test.go +++ b/server/service/osquery_test.go @@ -1249,7 +1249,7 @@ func TestHostDetailQueries(t *testing.T) { svc := &Service{ clock: mockClock, - logger: platformlogging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), config: config.TestConfig(), ds: ds, jitterMu: new(sync.Mutex), @@ -2292,7 +2292,7 @@ func TestMDMQueries(t *testing.T) { ds := new(mock.Store) svc := &Service{ clock: clock.NewMockClock(), - logger: platformlogging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), config: config.TestConfig(), ds: ds, jitterMu: new(sync.Mutex), @@ -2580,7 +2580,7 @@ func TestIngestDistributedQueryParseIdError(t *testing.T) { ds: ds, resultStore: rs, liveQueryStore: lq, - logger: platformlogging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), clock: mockClock, } @@ -2599,7 +2599,7 @@ func TestIngestDistributedQueryOrphanedCampaignLoadError(t *testing.T) { ds: ds, resultStore: rs, liveQueryStore: lq, - logger: platformlogging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), clock: mockClock, } @@ -2625,7 +2625,7 @@ func TestIngestDistributedQueryOrphanedCampaignWaitListener(t *testing.T) { ds: ds, resultStore: rs, liveQueryStore: lq, - logger: platformlogging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), clock: mockClock, } @@ -2658,7 +2658,7 @@ func TestIngestDistributedQueryOrphanedCloseError(t *testing.T) { ds: ds, resultStore: rs, liveQueryStore: lq, - logger: platformlogging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), clock: mockClock, } @@ -2694,7 +2694,7 @@ func TestIngestDistributedQueryOrphanedStopError(t *testing.T) { ds: ds, resultStore: rs, liveQueryStore: lq, - logger: platformlogging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), clock: mockClock, } @@ -2731,7 +2731,7 @@ func TestIngestDistributedQueryOrphanedStop(t *testing.T) { ds: ds, resultStore: rs, liveQueryStore: lq, - logger: platformlogging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), clock: mockClock, } @@ -2769,7 +2769,7 @@ func TestIngestDistributedQueryRecordCompletionError(t *testing.T) { ds: ds, resultStore: rs, liveQueryStore: lq, - logger: platformlogging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), clock: mockClock, } @@ -2800,7 +2800,7 @@ func TestIngestDistributedQuery(t *testing.T) { ds: ds, resultStore: rs, liveQueryStore: lq, - logger: platformlogging.NewNopLogger(), + logger: slog.New(slog.DiscardHandler), clock: mockClock, } @@ -3076,14 +3076,14 @@ func TestGetHostIdentifier(t *testing.T) { {identifierOption: "hostname", providedIdentifier: "foobar", details: details, expected: "foohost"}, {identifierOption: "provided", providedIdentifier: "foobar", details: details, expected: "foobar"}, } - logger := platformlogging.NewNopLogger() + logger := slog.New(slog.DiscardHandler) for _, tt := range testCases { t.Run("", func(t *testing.T) { if tt.shouldPanic { assert.Panics( t, - func() { getHostIdentifier(logger, tt.identifierOption, tt.providedIdentifier, tt.details) }, + func() { getHostIdentifier(t.Context(), logger, tt.identifierOption, tt.providedIdentifier, tt.details) }, ) return } @@ -3091,7 +3091,7 @@ func TestGetHostIdentifier(t *testing.T) { assert.Equal( t, tt.expected, - getHostIdentifier(logger, tt.identifierOption, tt.providedIdentifier, tt.details), + getHostIdentifier(t.Context(), logger, tt.identifierOption, tt.providedIdentifier, tt.details), ) }) } diff --git a/server/service/service.go b/server/service/service.go index 8f8d9b53d9..0a1f548f74 100644 --- a/server/service/service.go +++ b/server/service/service.go @@ -6,6 +6,7 @@ import ( "context" "fmt" "html/template" + "log/slog" "sync" "time" @@ -20,7 +21,6 @@ import ( nanodep_storage "github.com/fleetdm/fleet/v4/server/mdm/nanodep/storage" nanomdm_push "github.com/fleetdm/fleet/v4/server/mdm/nanomdm/push" nanomdm_storage "github.com/fleetdm/fleet/v4/server/mdm/nanomdm/storage" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/service/async" "github.com/fleetdm/fleet/v4/server/service/conditional_access_microsoft_proxy" "github.com/fleetdm/fleet/v4/server/sso" @@ -35,7 +35,7 @@ type Service struct { carveStore fleet.CarveStore resultStore fleet.QueryResultStore liveQueryStore fleet.LiveQueryStore - logger *logging.Logger + logger *slog.Logger config config.FleetConfig clock clock.Clock @@ -129,7 +129,7 @@ func NewService( ds fleet.Datastore, task *async.Task, resultStore fleet.QueryResultStore, - logger *logging.Logger, + logger *slog.Logger, osqueryLogger *OsqueryLogger, config config.FleetConfig, mailService fleet.MailService, diff --git a/server/service/service_campaign_test.go b/server/service/service_campaign_test.go index c43854ed54..0d2dfd801c 100644 --- a/server/service/service_campaign_test.go +++ b/server/service/service_campaign_test.go @@ -3,6 +3,7 @@ package service import ( "context" "crypto/tls" + "log/slog" "math/rand" "net/http" "net/http/httptest" @@ -19,7 +20,6 @@ import ( "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/live_query/live_query_mock" "github.com/fleetdm/fleet/v4/server/mock" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/ptr" "github.com/fleetdm/fleet/v4/server/pubsub" ws "github.com/fleetdm/fleet/v4/server/websocket" @@ -91,7 +91,7 @@ func TestStreamCampaignResultsClosesReditOnWSClose(t *testing.T) { _, err := svc.NewDistributedQueryCampaign(viewerCtx, q, nil, fleet.HostTargets{HostIDs: []uint{2}, LabelIDs: []uint{1}}) require.NoError(t, err) - pathHandler := makeStreamDistributedQueryCampaignResultsHandler(config.TestConfig().Server, svc, logging.NewNopLogger()) + pathHandler := makeStreamDistributedQueryCampaignResultsHandler(config.TestConfig().Server, svc, slog.New(slog.DiscardHandler)) s := httptest.NewServer(pathHandler("/api/latest/fleet/results/")) defer s.Close() // Convert http://127.0.0.1 to ws://127.0.0.1 diff --git a/server/service/service_campaigns.go b/server/service/service_campaigns.go index 82c636ddd6..23cfa17ab0 100644 --- a/server/service/service_campaigns.go +++ b/server/service/service_campaigns.go @@ -5,6 +5,7 @@ import ( "database/sql" "errors" "fmt" + "log/slog" "time" "github.com/fleetdm/fleet/v4/server/authz" @@ -12,9 +13,7 @@ import ( "github.com/fleetdm/fleet/v4/server/contexts/logging" "github.com/fleetdm/fleet/v4/server/contexts/viewer" "github.com/fleetdm/fleet/v4/server/fleet" - platformlogging "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/websocket" - "github.com/go-kit/log/level" "github.com/igm/sockjs-go/v3/sockjs" ) @@ -61,14 +60,14 @@ func (svc Service) StreamCampaignResults(ctx context.Context, conn *websocket.Co // read results is the same user that initiated the query. This means the observer check already // happened with the actual value for this query. if err := svc.authz.Authorize(ctx, &fleet.TargetedQuery{Query: &fleet.Query{ObserverCanRun: true}}, fleet.ActionRun); err != nil { - level.Info(logger).Log("err", "stream results authorization failed") + logger.InfoContext(ctx, "stream results authorization failed") conn.WriteJSONError(authz.ForbiddenErrorMessage) //nolint:errcheck return } vc, ok := viewer.FromContext(ctx) if !ok { - level.Info(logger).Log("err", "stream results viewer missing") + logger.InfoContext(ctx, "stream results viewer missing") conn.WriteJSONError(authz.ForbiddenErrorMessage) //nolint:errcheck return } @@ -113,8 +112,7 @@ func (svc Service) StreamCampaignResults(ctx context.Context, conn *websocket.Co // Ensure the same user is opening to read results as initiated the query if campaign.UserID != vc.User.ID { - level.Info(logger).Log( - "err", "campaign user ID does not match", + logger.InfoContext(ctx, "campaign user ID does not match", "expected", campaign.UserID, "got", vc.User.ID, ) @@ -139,7 +137,7 @@ func (svc Service) StreamCampaignResults(ctx context.Context, conn *websocket.Co // to cleanup the campaign. ctx := context.WithoutCancel(ctx) if err := svc.CompleteCampaign(ctx, campaign); err != nil { - level.Error(logger).Log("msg", "complete campaign (async)", "err", err) + logger.ErrorContext(ctx, "complete campaign (async)", "err", err) } }() @@ -209,7 +207,7 @@ func (svc Service) StreamCampaignResults(ctx context.Context, conn *websocket.Co } if err := updateStatus(); err != nil { - _ = logger.Log("msg", "error updating status", "err", err) + logger.ErrorContext(ctx, "error updating status", "err", err) return } @@ -223,7 +221,7 @@ func (svc Service) StreamCampaignResults(ctx context.Context, conn *websocket.Co perfStatsTracker := statsTracker{} perfStatsTracker.saveStats, err = svc.ds.IsSavedQuery(ctx, campaign.QueryID) if err != nil { - level.Error(logger).Log("msg", "error checking saved query", "query.id", campaign.QueryID, "err", err) + logger.ErrorContext(ctx, "error checking saved query", "query.id", campaign.QueryID, "err", err) perfStatsTracker.saveStats = false } // We aggregate stats and add activity at the end. Using context without cancel for precaution. @@ -263,7 +261,7 @@ func (svc Service) StreamCampaignResults(ctx context.Context, conn *websocket.Co return } if err != nil { - _ = level.Error(logger).Log("msg", "error writing to channel", "err", err) + logger.ErrorContext(ctx, "error writing to channel", "err", err) } if res.Error == nil { // Fleet considers a host-reported error to be neither a "result" nor "no result" @@ -277,9 +275,9 @@ func (svc Service) StreamCampaignResults(ctx context.Context, conn *websocket.Co } status.ActualResults++ case error: - level.Error(logger).Log("msg", "received error from pubsub channel", "err", res) + logger.ErrorContext(ctx, "received error from pubsub channel", "err", res) if err := conn.WriteJSONError("pubsub error: " + res.Error()); err != nil { - logger.Log("msg", "failed to write pubsub error", "err", err) + logger.ErrorContext(ctx, "failed to write pubsub error", "err", err) } } @@ -291,7 +289,7 @@ func (svc Service) StreamCampaignResults(ctx context.Context, conn *websocket.Co } // Update status if err := updateStatus(); err != nil { - level.Error(logger).Log("msg", "error updating status", "err", err) + logger.ErrorContext(ctx, "error updating status", "err", err) return } if status.ActualResults == status.ExpectedResults { @@ -305,7 +303,7 @@ func (svc Service) StreamCampaignResults(ctx context.Context, conn *websocket.Co // addLiveQueryActivity adds live query activity to the activity feed, including the updated aggregated stats func (svc Service) addLiveQueryActivity( - ctx context.Context, targetsCount uint, queryID uint, logger *platformlogging.Logger, + ctx context.Context, targetsCount uint, queryID uint, logger *slog.Logger, ) { activityData := fleet.ActivityTypeLiveQuery{ TargetsCount: targetsCount, @@ -313,7 +311,7 @@ func (svc Service) addLiveQueryActivity( // Query returns SQL, name, and aggregated stats q, err := svc.ds.Query(ctx, queryID) if err != nil { - level.Error(logger).Log("msg", "error getting query", "id", queryID, "err", err) + logger.ErrorContext(ctx, "error getting query", "id", queryID, "err", err) } else { activityData.QuerySQL = q.Query if q.Saved { @@ -326,7 +324,7 @@ func (svc Service) addLiveQueryActivity( authz.UserFromContext(ctx), activityData, ); err != nil { - level.Error(logger).Log("msg", "error creating activity for live query", "err", err) + logger.ErrorContext(ctx, "error creating activity for live query", "err", err) } } @@ -353,7 +351,7 @@ var ( ) func (svc Service) updateStats( - ctx context.Context, queryID uint, logger *platformlogging.Logger, tracker *statsTracker, aggregateStats bool, + ctx context.Context, queryID uint, logger *slog.Logger, tracker *statsTracker, aggregateStats bool, ) { // If we are not saving stats if tracker == nil || !tracker.saveStats || @@ -370,7 +368,7 @@ func (svc Service) updateStats( } currentStats, err := svc.ds.GetLiveQueryStats(ctx, queryID, hostIDs) if err != nil { - level.Error(logger).Log("msg", "error getting current live query stats", "err", err) + logger.ErrorContext(ctx, "error getting current live query stats", "err", err) tracker.saveStats = false return } @@ -416,7 +414,7 @@ func (svc Service) updateStats( // Insert/overwrite updated stats err = svc.ds.UpdateLiveQueryStats(ctx, queryID, currentStats) if err != nil { - level.Error(logger).Log("msg", "error updating live query stats", "err", err) + logger.ErrorContext(ctx, "error updating live query stats", "err", err) tracker.saveStats = false return } @@ -462,20 +460,20 @@ func (svc Service) updateStats( select { case err := <-done: if err != nil { - level.Error(logger).Log("msg", "error syncing replica to master", "err", err) + logger.ErrorContext(ctx, "error syncing replica to master", "err", err) tracker.saveStats = false return } case <-time.After(5 * time.Second): stop <- struct{}{} - level.Error(logger).Log("msg", "replica sync timeout: replica did not catch up to the master in 5 seconds") + logger.ErrorContext(ctx, "replica sync timeout: replica did not catch up to the master in 5 seconds") // We proceed with the aggregation even if the replica is not in sync. } } err := svc.ds.CalculateAggregatedPerfStatsPercentiles(ctx, fleet.AggregatedStatsTypeScheduledQuery, queryID) if err != nil { - level.Error(logger).Log("msg", "error aggregating performance stats", "err", err) + logger.ErrorContext(ctx, "error aggregating performance stats", "err", err) tracker.saveStats = false return } diff --git a/server/service/software_installers_test.go b/server/service/software_installers_test.go index a659cb7faf..9a764a816f 100644 --- a/server/service/software_installers_test.go +++ b/server/service/software_installers_test.go @@ -2,6 +2,7 @@ package service import ( "context" + "log/slog" "path/filepath" "testing" "time" @@ -12,7 +13,6 @@ import ( "github.com/fleetdm/fleet/v4/server/datastore/filesystem" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/mock" - "github.com/fleetdm/fleet/v4/server/platform/logging" "github.com/fleetdm/fleet/v4/server/ptr" "github.com/fleetdm/fleet/v4/server/test" "github.com/jmoiron/sqlx" @@ -188,7 +188,7 @@ func TestUpgradeCodeMigration(t *testing.T) { return nil } - require.NoError(t, eeservice.UpgradeCodeMigration(ctx, ds, softwareInstallStore, logging.NewNopLogger())) + require.NoError(t, eeservice.UpgradeCodeMigration(ctx, ds, softwareInstallStore, slog.New(slog.DiscardHandler))) require.True(t, ds.UpdateInstallerUpgradeCodeFuncInvoked) require.Len(t, updatedInstallerIDs, 2) } diff --git a/server/service/testing_utils.go b/server/service/testing_utils.go index 986187c385..d4d988ad63 100644 --- a/server/service/testing_utils.go +++ b/server/service/testing_utils.go @@ -90,9 +90,9 @@ func newTestServiceWithConfig(t *testing.T, ds fleet.Datastore, fleetConfig conf depStorage nanodep_storage.AllDEPStorage = &nanodep_mock.Storage{} mailer fleet.MailService = &mockMailService{SendEmailFn: func(e fleet.Email) error { return nil }} c clock.Clock = clock.C - scepConfigService = eeservice.NewSCEPConfigService(logger, nil) - digiCertService = digicert.NewService(digicert.WithLogger(logger)) - estCAService = est.NewService(est.WithLogger(logger)) + scepConfigService = eeservice.NewSCEPConfigService(logger.SlogLogger(), nil) + digiCertService = digicert.NewService(digicert.WithLogger(logger.SlogLogger())) + estCAService = est.NewService(est.WithLogger(logger.SlogLogger())) conditionalAccessMicrosoftProxy ConditionalAccessMicrosoftProxy mdmStorage fleet.MDMAppleStore @@ -218,7 +218,7 @@ func newTestServiceWithConfig(t *testing.T, ds fleet.Datastore, fleetConfig conf ds, task, rs, - logger, + logger.SlogLogger(), osqlogger, fleetConfig, mailer, @@ -262,7 +262,7 @@ func newTestServiceWithConfig(t *testing.T, ds fleet.Datastore, fleetConfig conf svc, err = eeservice.NewService( svc, ds, - logger, + logger.SlogLogger(), fleetConfig, mailer, c, @@ -527,19 +527,19 @@ func RunServerForTestsWithServiceWithDS(t *testing.T, ctx context.Context, ds fl commander := apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPusher) if mdmStorage != nil && scepStorage != nil { vppInstaller := svc.(fleet.AppleMDMVPPInstaller) - checkInAndCommand := NewMDMAppleCheckinAndCommandService(ds, commander, vppInstaller, opts[0].License.IsPremium(), logger, redis_key_value.New(redisPool), svc.NewActivity) - checkInAndCommand.RegisterResultsHandler("InstalledApplicationList", NewInstalledApplicationListResultsHandler(ds, commander, logger, cfg.Server.VPPVerifyTimeout, cfg.Server.VPPVerifyRequestDelay, svc.NewActivity)) - checkInAndCommand.RegisterResultsHandler(fleet.DeviceLocationCmdName, NewDeviceLocationResultsHandler(ds, commander, logger)) + checkInAndCommand := NewMDMAppleCheckinAndCommandService(ds, commander, vppInstaller, opts[0].License.IsPremium(), logger.SlogLogger(), redis_key_value.New(redisPool), svc.NewActivity) + checkInAndCommand.RegisterResultsHandler("InstalledApplicationList", NewInstalledApplicationListResultsHandler(ds, commander, logger.SlogLogger(), cfg.Server.VPPVerifyTimeout, cfg.Server.VPPVerifyRequestDelay, svc.NewActivity)) + checkInAndCommand.RegisterResultsHandler(fleet.DeviceLocationCmdName, NewDeviceLocationResultsHandler(ds, commander, logger.SlogLogger())) err := RegisterAppleMDMProtocolServices( rootMux, cfg.MDM, mdmStorage, scepStorage, - logger, + logger.SlogLogger(), checkInAndCommand, &MDMAppleDDMService{ ds: ds, - logger: logger, + logger: logger.SlogLogger(), }, commander, "https://test-url.com", @@ -559,7 +559,7 @@ func RunServerForTestsWithServiceWithDS(t *testing.T, ctx context.Context, ds fl err := RegisterSCEPProxy( rootMux, ds, - logger, + logger.SlogLogger(), timeout, &cfg, ) @@ -568,7 +568,7 @@ func RunServerForTestsWithServiceWithDS(t *testing.T, ctx context.Context, ds fl } if len(opts) > 0 && opts[0].WithDEPWebview { - frontendHandler := WithMDMEnrollmentMiddleware(svc, logger, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + frontendHandler := WithMDMEnrollmentMiddleware(svc, logger.SlogLogger(), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // do nothing and return 200 w.WriteHeader(http.StatusOK) })) @@ -583,20 +583,20 @@ func RunServerForTestsWithServiceWithDS(t *testing.T, ctx context.Context, ds fl extra = append(extra, WithLoginRateLimit(throttled.PerMin(1000))) if len(opts) > 0 && opts[0].HostIdentity != nil { - require.NoError(t, hostidentity.RegisterSCEP(rootMux, opts[0].HostIdentity.SCEPStorage, ds, logger, &cfg)) + require.NoError(t, hostidentity.RegisterSCEP(rootMux, opts[0].HostIdentity.SCEPStorage, ds, logger.SlogLogger(), &cfg)) var httpSigVerifier func(http.Handler) http.Handler httpSigVerifier, err := httpsig.Middleware(ds, opts[0].HostIdentity.RequireHTTPMessageSignature, - logger.With("component", "http-sig-verifier")) + logger.With("component", "http-sig-verifier").SlogLogger()) require.NoError(t, err) extra = append(extra, WithHTTPSigVerifier(httpSigVerifier)) } if len(opts) > 0 && opts[0].ConditionalAccess != nil { - require.NoError(t, condaccess.RegisterSCEP(ctx, rootMux, opts[0].ConditionalAccess.SCEPStorage, ds, logger, &cfg)) - require.NoError(t, condaccess.RegisterIdP(rootMux, ds, logger, &cfg)) + require.NoError(t, condaccess.RegisterSCEP(ctx, rootMux, opts[0].ConditionalAccess.SCEPStorage, ds, logger.SlogLogger(), &cfg)) + require.NoError(t, condaccess.RegisterIdP(rootMux, ds, logger.SlogLogger(), &cfg)) } var carveStore fleet.CarveStore = ds // In tests, we use MySQL as storage for carves. - apiHandler := MakeHandler(svc, cfg, logger, limitStore, redisPool, carveStore, featureRoutes, extra...) + apiHandler := MakeHandler(svc, cfg, logger.SlogLogger(), limitStore, redisPool, carveStore, featureRoutes, extra...) rootMux.Handle("/api/", apiHandler) var errHandler *errorstore.Handler ctxErrHandler := ctxerr.FromContext(ctx) @@ -605,7 +605,7 @@ func RunServerForTestsWithServiceWithDS(t *testing.T, ctx context.Context, ds fl } debugHandler := MakeDebugHandler(svc, cfg, logger.SlogLogger(), errHandler, ds) rootMux.Handle("/debug/", debugHandler) - rootMux.Handle("/enroll", ServeEndUserEnrollOTA(svc, "", ds, logger)) + rootMux.Handle("/enroll", ServeEndUserEnrollOTA(svc, "", ds, logger.SlogLogger())) if len(opts) > 0 && opts[0].EnableSCIM { require.NoError(t, scim.RegisterSCIM(rootMux, ds, svc, logger.SlogLogger(), &cfg)) diff --git a/tools/mdm/apple/apnspush/main.go b/tools/mdm/apple/apnspush/main.go index 5603c0192b..24b0d4b726 100644 --- a/tools/mdm/apple/apnspush/main.go +++ b/tools/mdm/apple/apnspush/main.go @@ -87,7 +87,7 @@ func main() { })), nil })) - nanoMDMLogger := service.NewNanoMDMLogger(logger.With("component", "apple-mdm-push")) + nanoMDMLogger := service.NewNanoMDMLogger(logger.With("component", "apple-mdm-push").SlogLogger()) pusher := nanomdm_pushsvc.New(mdmStorage, mdmStorage, pushProviderFactory, nanoMDMLogger) res, err := pusher.Push(context.Background(), hostUUIDs) if err != nil {