Skip to content

slog migration: platform/mysql and related logic - #40072

Merged
getvictor merged 2 commits into
mainfrom
victor/40054-platform-mysql
Feb 19, 2026
Merged

slog migration: platform/mysql and related logic#40072
getvictor merged 2 commits into
mainfrom
victor/40054-platform-mysql

Conversation

@getvictor

@getvictor getvictor commented Feb 18, 2026

Copy link
Copy Markdown
Member

Related issue: Resolves #40054

Checklist for submitter

  • Changes file added for user-visible changes in changes/, orbit/changes/ or ee/fleetd-chrome/changes.
    • already included in previous PR

Testing

  • Added/updated automated tests
  • QA'd all new/changed functionality manually

Summary by CodeRabbit

  • Refactor
    • Standardized logging infrastructure across the database and storage layers for improved consistency and maintainability.

@getvictor
getvictor requested a review from Copilot February 18, 2026 21:57
@getvictor

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Feb 18, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Continues the slog migration by updating platform/mysql (and related datastore/MDM call sites) to use log/slog loggers instead of go-kit loggers, including transaction helpers and SCEP/MDM storage integrations.

Changes:

  • Switch platform/mysql transaction helpers and connector factory signatures to *slog.Logger and update internal logging calls.
  • Update datastore and NanoMDM MySQL storage integrations to pass *slog.Logger (mostly via ds.logger.SlogLogger() / discard slog loggers in tests).
  • Add a small adapter in the standalone NanoMDM CLI to bridge a nanolib/log.Logger into a *slog.Logger.

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
server/platform/mysql/testing_utils/testing_utils.go Update truncate helper signature to accept *slog.Logger.
server/platform/mysql/retry_test.go Migrate tests to use slog.New(slog.DiscardHandler) instead of go-kit nop logger.
server/platform/mysql/retry.go Change WithRetryTxx to accept *slog.Logger and migrate panic-rollback logging.
server/platform/mysql/common.go Change connector factory + WithTxx/WithReadOnlyTxx to *slog.Logger; update connection retry logging to slog.
server/mdm/nanomdm/storage/mysql/queue.go Remove nanolib/go-kit logging adapter and pass slog logger directly into retry helper.
server/mdm/nanomdm/storage/mysql/mysql.go Convert NanoMDM MySQL storage logger usage to slog (InfoContext/ErrorContext), update options API.
server/mdm/nanomdm/cli/cli.go Bridge nanolib logger to slog via a custom slog.Handler for mysql storage config.
server/datastore/mysql/testing_utils.go Pass ds.logger.SlogLogger() into platform mysql test truncate helper.
server/datastore/mysql/rdsauth/connector.go Update IAM connector factory signature to accept *slog.Logger.
server/datastore/mysql/policies.go Update internal helpers to pass *slog.Logger into retry helper where needed.
server/datastore/mysql/nanomdm_storage_test.go Use discard slog logger in NanoMDM storage tests.
server/datastore/mysql/nanomdm_storage.go Update NanoMDM storage wiring to use slog logger and pass into nanomdm mysql storage.
server/datastore/mysql/mysql.go Update NewHostIdentitySCEPDepot signature to accept *slog.Logger; pass slog loggers to tx helpers.
server/datastore/mysql/host_identity_scep.go Pass ds.logger.SlogLogger() into retry helper.
server/datastore/mysql/android_mysql.go Pass ds.logger.SlogLogger() into retry/tx helpers.
server/datastore/mysql/android_enterprise_test.go Update truncate helper call to pass ds.logger.SlogLogger().
server/datastore/mysql/android_device_test.go Update truncate helper call to pass ds.logger.SlogLogger().
server/activity/internal/testutils/testutils.go Update truncate helper call to use discard slog logger.
ee/server/service/hostidentity/depot/depot.go Change depot logger type to *slog.Logger and migrate log call to slog.
ee/server/integrationtest/hostidentity/suite.go Update to pass logger.SlogLogger().With(...) to host identity depot.
cmd/fleet/serve.go Update to pass logger.SlogLogger().With(...) to host identity depot.
Comments suppressed due to low confidence (1)

ee/server/service/hostidentity/depot/depot.go:48

  • NewHostIdentitySCEPDepot accepts a *slog.Logger but doesn’t validate it. If a nil logger is passed, methods like Put will panic when calling d.logger.InfoContext. Consider either rejecting nil early (panic/return error) or defaulting to a no-op slog logger (e.g., slog.New(slog.DiscardHandler)) to make this API safer.
func NewHostIdentitySCEPDepot(db *sqlx.DB, ds fleet.Datastore, logger *slog.Logger, cfg *config.FleetConfig) (*HostIdentitySCEPDepot, error) {
	if err := db.Ping(); err != nil {
		return nil, err
	}
	return &HostIdentitySCEPDepot{
		db:     db,
		ds:     ds,
		logger: logger,
		config: cfg,
	}, nil

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread server/mdm/nanomdm/cli/cli.go
Comment thread server/activity/internal/testutils/testutils.go Outdated
@coderabbitai

coderabbitai Bot commented Feb 18, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This pull request implements a widespread migration from the go-kit/log framework to the standard Go slog logging package across multiple components. The changes systematically replace log.Logger type parameters with *slog.Logger, update function signatures in constructors and helper functions, remove go-kit/log imports in favor of log/slog, and convert logging calls from .Log() syntax to slog methods like .InfoContext() and .ErrorContext(). Affected areas include the Host Identity SCEP depot, NanoMDM storage, datastore MySQL layer, policy management, RDS authentication, transaction handling, and testing utilities. Control flow and error handling paths remain unchanged.

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The PR description is incomplete and lacks critical required sections including related issue context, database migrations checklist, and input validation details. Complete the PR description by filling out all applicable checklist items, particularly sections on database migrations, testing verification, and any relevant configuration or GitOps considerations. Reference issue #40054 properly and confirm the migration scope.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR addresses the slog migration objective from linked issue #40054, transitioning multiple logging components from go-kit/log to slog throughout platform/mysql and related packages.
Out of Scope Changes check ✅ Passed All changes are within scope of the slog migration: logger type transitions, import updates, and related call-site adjustments across platform/mysql, datastore, MDM, and server packages.
Title check ✅ Passed The title 'slog migration: platform/mysql and related logic' accurately summarizes the primary change: migrating the platform/mysql package and related components from go-kit/log to slog.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch victor/40054-platform-mysql

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (7)
server/mdm/nanomdm/cli/cli.go (2)

180-181: WithGroup silently drops the group name — add a comment.

The current implementation ignores the name argument with no explanation. Per the slog.Handler contract, callers expect attributes to be nested under the group name. Since nanolib has no grouping concept, this is an acceptable limitation, but it should be documented to prevent future confusion.

📝 Suggested doc comment
 func (h *nanoLibSlogHandler) WithGroup(_ string) slog.Handler {
+	// nanolib/log has no concept of attribute groups; groups are silently dropped.
 	return h
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/mdm/nanomdm/cli/cli.go` around lines 180 - 181, The WithGroup method
on nanoLibSlogHandler currently ignores the provided group name; update the
function nanoLibSlogHandler.WithGroup to include a clear doc comment stating
that nanolib does not support attribute grouping and therefore the name argument
is intentionally dropped (i.e., the method returns the same handler), so callers
understand this limitation rather than assuming a bug; keep the implementation
unchanged but add the explanatory comment directly above the WithGroup method.

155-171: slog.LevelWarn and slog.LevelError silently downgrade to nanolib Info.

The condition r.Level >= slog.LevelInfo is always true for Warn (4), Error (8), and Info (0), so all three levels are forwarded to h.logger.Info(). Operational error messages from the MySQL storage (e.g. rollback failures, batch-update errors) will therefore appear in the CLI output as Info, making them harder to triage.

Consider emitting the slog level as a key-value attribute so severity is preserved even within nanolib's two-level model:

♻️ Suggested refinement
+	kvs = append(kvs, "level", r.Level.String())
 	if r.Level >= slog.LevelInfo {
 		h.logger.Info(kvs...)
 	} else {
 		h.logger.Debug(kvs...)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/mdm/nanomdm/cli/cli.go` around lines 155 - 171, In
nanoLibSlogHandler.Handle, the current condition (r.Level >= slog.LevelInfo)
always evaluates true for Warn and Error and thus downgrades severity; change
the routing threshold to compare against slog.LevelWarn (so Warn and Error map
to h.logger.Info while lower levels go to h.logger.Debug) and also append the
original slog level as a key-value pair (e.g., key "slog.level" with value
r.Level.String() or r.Level) into the kvs slice before logging so the original
severity is preserved even though nanolib only has Info/Debug; update references
to h.logger.Info and h.logger.Debug accordingly in the function
nanoLibSlogHandler.Handle.
server/activity/internal/testutils/testutils.go (1)

51-51: tdb.Logger is already initialized as a discard logger — reuse it instead of allocating a second one.

♻️ Proposed fix
-	mysql_testing_utils.TruncateTables(t, tdb.DB, slog.New(slog.DiscardHandler), nil, "host_activities", "activities", "hosts", "users")
+	mysql_testing_utils.TruncateTables(t, tdb.DB, tdb.Logger, nil, "host_activities", "activities", "hosts", "users")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/activity/internal/testutils/testutils.go` at line 51, The call to
mysql_testing_utils.TruncateTables creates a new discard logger instead of
reusing the already-initialized tdb.Logger; update the TruncateTables invocation
in testutils.go to pass tdb.Logger (instead of slog.New(slog.DiscardHandler)) so
the existing discard logger is reused when calling
mysql_testing_utils.TruncateTables(t, tdb.DB, ..., nil, "host_activities",
"activities", "hosts", "users").
cmd/fleet/serve.go (1)

1505-1514: Asymmetric logger APIs on adjacent depot creation calls — expected but worth tracking.

Line 1505 now passes logger.SlogLogger().With(...) (*slog.Logger) to NewHostIdentitySCEPDepot, while Line 1514 still passes logger.With(...) (go-kit log.Logger) to NewConditionalAccessSCEPDepot. This is expected since NewConditionalAccessSCEPDepot isn't migrated in this PR, but the two calls should be aligned once condaccess is migrated.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/fleet/serve.go` around lines 1505 - 1514, Adjacent depot constructors use
different logger types: NewHostIdentitySCEPDepot is passed
logger.SlogLogger().With(...) (a *slog.Logger) while
NewConditionalAccessSCEPDepot is still passed logger.With(...) (go-kit
log.Logger). When migrating Conditional Access to the slog API, update the call
to NewConditionalAccessSCEPDepot to use logger.SlogLogger().With("component",
"conditional-access-scep-depot") so both depots accept the same slog.Logger type
(or, if keeping go-kit for both, change the host identity call to use
logger.With). Ensure the chosen logger type matches the constructor signature of
NewConditionalAccessSCEPDepot (or update that constructor) and keep the
"component" field identical.
server/datastore/mysql/rdsauth/connector.go (1)

73-99: Connector.logger is stored but never referenced in Connect() or Driver().

The field is carried through the migration but has no active usage. Consider either removing it (and dropping the logger parameter from NewConnectorFactory's returned closure) until it's actually needed, or adding a comment indicating its intended future use.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/datastore/mysql/rdsauth/connector.go` around lines 73 - 99,
Connector.logger is declared on type Connector but never used in Connect() or
Driver(); either remove the logger field and drop the logger parameter from the
NewConnectorFactory closure/constructor that creates *Connector, or leave the
field and add a short TODO comment on Connector.logger explaining it's reserved
for future instrumentation/metrics so linters/reviewers know it's intentional;
update the Connector struct and the factory/constructor (and any calls that pass
logger) to keep signatures consistent, and ensure Connector.Connect and
Connector.Driver reflect the chosen change.
server/platform/mysql/common.go (1)

104-113: Connection retry logging uses context.Background() — acceptable but consider threading context through NewDB.

NewDB doesn't receive a context.Context, so context.Background() is the only option. This is fine for now, but if NewDB is ever refactored to accept a context (e.g., for cancellation during startup), this log call should be updated.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/platform/mysql/common.go` around lines 104 - 113, The retry loop in
NewDB currently calls opts.Logger.SlogLogger().WarnContext with
context.Background(), which prevents propagation of caller cancellation or
deadlines; update NewDB to accept a context.Context parameter (e.g., func
NewDB(ctx context.Context, opts ...)) and thread that ctx into the retry loop,
replacing context.Background() with the passed ctx when calling
opts.Logger.SlogLogger().WarnContext and when sleeping/returning so that
connection attempts respect cancellation and deadlines.
server/datastore/mysql/mysql.go (1)

186-194: Inconsistent migration: NewConditionalAccessSCEPDepot still uses log.Logger.

NewHostIdentitySCEPDepot (line 186) has been migrated to *slog.Logger, but the adjacent NewConditionalAccessSCEPDepot (line 192) still takes log.Logger. This creates an inconsistency in the public API surface of Datastore. Consider migrating both in this PR for consistency, or leave a TODO to track it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/datastore/mysql/mysql.go` around lines 186 - 194, The two Datastore
constructors are inconsistent: NewHostIdentitySCEPDepot uses *slog.Logger while
NewConditionalAccessSCEPDepot still accepts log.Logger; change
NewConditionalAccessSCEPDepot's logger parameter to *slog.Logger and update its
call to condaccessdepot.NewConditionalAccessSCEPDepot to pass the *slog.Logger,
and then update the condaccessdepot.NewConditionalAccessSCEPDepot signature (and
any call sites) to accept *slog.Logger instead of log.Logger; ensure imports are
updated and run tests or build to catch remaining references, or alternatively
add a TODO noting the mismatch if you prefer deferring the full migration.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@cmd/fleet/serve.go`:
- Around line 1505-1514: Adjacent depot constructors use different logger types:
NewHostIdentitySCEPDepot is passed logger.SlogLogger().With(...) (a
*slog.Logger) while NewConditionalAccessSCEPDepot is still passed
logger.With(...) (go-kit log.Logger). When migrating Conditional Access to the
slog API, update the call to NewConditionalAccessSCEPDepot to use
logger.SlogLogger().With("component", "conditional-access-scep-depot") so both
depots accept the same slog.Logger type (or, if keeping go-kit for both, change
the host identity call to use logger.With). Ensure the chosen logger type
matches the constructor signature of NewConditionalAccessSCEPDepot (or update
that constructor) and keep the "component" field identical.

In `@server/activity/internal/testutils/testutils.go`:
- Line 51: The call to mysql_testing_utils.TruncateTables creates a new discard
logger instead of reusing the already-initialized tdb.Logger; update the
TruncateTables invocation in testutils.go to pass tdb.Logger (instead of
slog.New(slog.DiscardHandler)) so the existing discard logger is reused when
calling mysql_testing_utils.TruncateTables(t, tdb.DB, ..., nil,
"host_activities", "activities", "hosts", "users").

In `@server/datastore/mysql/mysql.go`:
- Around line 186-194: The two Datastore constructors are inconsistent:
NewHostIdentitySCEPDepot uses *slog.Logger while NewConditionalAccessSCEPDepot
still accepts log.Logger; change NewConditionalAccessSCEPDepot's logger
parameter to *slog.Logger and update its call to
condaccessdepot.NewConditionalAccessSCEPDepot to pass the *slog.Logger, and then
update the condaccessdepot.NewConditionalAccessSCEPDepot signature (and any call
sites) to accept *slog.Logger instead of log.Logger; ensure imports are updated
and run tests or build to catch remaining references, or alternatively add a
TODO noting the mismatch if you prefer deferring the full migration.

In `@server/datastore/mysql/rdsauth/connector.go`:
- Around line 73-99: Connector.logger is declared on type Connector but never
used in Connect() or Driver(); either remove the logger field and drop the
logger parameter from the NewConnectorFactory closure/constructor that creates
*Connector, or leave the field and add a short TODO comment on Connector.logger
explaining it's reserved for future instrumentation/metrics so linters/reviewers
know it's intentional; update the Connector struct and the factory/constructor
(and any calls that pass logger) to keep signatures consistent, and ensure
Connector.Connect and Connector.Driver reflect the chosen change.

In `@server/mdm/nanomdm/cli/cli.go`:
- Around line 180-181: The WithGroup method on nanoLibSlogHandler currently
ignores the provided group name; update the function
nanoLibSlogHandler.WithGroup to include a clear doc comment stating that nanolib
does not support attribute grouping and therefore the name argument is
intentionally dropped (i.e., the method returns the same handler), so callers
understand this limitation rather than assuming a bug; keep the implementation
unchanged but add the explanatory comment directly above the WithGroup method.
- Around line 155-171: In nanoLibSlogHandler.Handle, the current condition
(r.Level >= slog.LevelInfo) always evaluates true for Warn and Error and thus
downgrades severity; change the routing threshold to compare against
slog.LevelWarn (so Warn and Error map to h.logger.Info while lower levels go to
h.logger.Debug) and also append the original slog level as a key-value pair
(e.g., key "slog.level" with value r.Level.String() or r.Level) into the kvs
slice before logging so the original severity is preserved even though nanolib
only has Info/Debug; update references to h.logger.Info and h.logger.Debug
accordingly in the function nanoLibSlogHandler.Handle.

In `@server/platform/mysql/common.go`:
- Around line 104-113: The retry loop in NewDB currently calls
opts.Logger.SlogLogger().WarnContext with context.Background(), which prevents
propagation of caller cancellation or deadlines; update NewDB to accept a
context.Context parameter (e.g., func NewDB(ctx context.Context, opts ...)) and
thread that ctx into the retry loop, replacing context.Background() with the
passed ctx when calling opts.Logger.SlogLogger().WarnContext and when
sleeping/returning so that connection attempts respect cancellation and
deadlines.

@getvictor getvictor changed the title Transition platform/mysql to slog and related logic. slog migration: platform/mysql and related logic Feb 18, 2026
@getvictor
getvictor marked this pull request as ready for review February 18, 2026 22:39
@getvictor
getvictor requested a review from a team as a code owner February 18, 2026 22:39
@codecov

codecov Bot commented Feb 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 48.48485% with 34 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.29%. Comparing base (3a0e2d8) to head (18d3b07).
⚠️ Report is 24 commits behind head on main.

Files with missing lines Patch % Lines
server/mdm/nanomdm/cli/cli.go 0.00% 25 Missing ⚠️
server/mdm/nanomdm/storage/mysql/mysql.go 62.50% 3 Missing ⚠️
server/datastore/mysql/rdsauth/connector.go 0.00% 2 Missing ⚠️
server/platform/mysql/common.go 66.66% 2 Missing ⚠️
cmd/fleet/serve.go 0.00% 1 Missing ⚠️
server/datastore/mysql/android_mysql.go 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #40072      +/-   ##
==========================================
+ Coverage   65.55%   66.29%   +0.73%     
==========================================
  Files        2255     2443     +188     
  Lines      178307   195803   +17496     
  Branches     8608     8608              
==========================================
+ Hits       116894   129801   +12907     
- Misses      50340    54250    +3910     
- Partials    11073    11752     +679     
Flag Coverage Δ
backend 68.09% <48.48%> (+0.65%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

rowsAffected, _ := result.RowsAffected()
if rowsAffected > 0 {
d.logger.Log("msg", "revoked existing host identity certificate", "name", name)
d.logger.InfoContext(context.Background(), "revoked existing host identity certificate", "name", name)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As a side note, we should eventually update these calls to use a consistent context provided by the caller, though that's out of scope for this.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I agree and good catch. This is code we brought over from a 3rd party library, so it'll need some changes.

@getvictor
getvictor merged commit 6b3bb8a into main Feb 19, 2026
45 checks passed
@getvictor
getvictor deleted the victor/40054-platform-mysql branch February 19, 2026 14:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

slog migration (2)

3 participants