Skip to content

feat: migrate logger generics#186

Merged
ReneWerner87 merged 1 commit into
masterfrom
codex/2025-08-24-11-48-42
Aug 24, 2025
Merged

feat: migrate logger generics#186
ReneWerner87 merged 1 commit into
masterfrom
codex/2025-08-24-11-48-42

Conversation

@ReneWerner87
Copy link
Copy Markdown
Member

@ReneWerner87 ReneWerner87 commented Aug 24, 2025

Summary

  • add migration to update logger interfaces and functions for generics
  • register migration and cover with tests

Testing

  • make lint
  • make test

https://chatgpt.com/codex/tasks/task_e_68aaf8dd7e6c8326b772dab0107af213

Summary by CodeRabbit

  • New Features
    • The migration tool now automatically updates projects to use generic logger APIs during supported version upgrades (2.x to <4.0). It converts existing logger types and functions to their generic equivalents and provides clear progress output during migration.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Aug 24, 2025

Walkthrough

Adds a new v3 migration (MigrateLoggerGenerics) that rewrites legacy logger APIs to their generic forms and registers it in the migrations list for versions >=2.0.0-0 and <4.0.0-0. Includes unit tests validating replacements and migration output.

Changes

Cohort / File(s) Summary
Migration list update
cmd/internal/migrations/lists.go
Inserts MigrateLoggerGenerics into the v3 migration sequence between MigrateLoggerTags and MigrateStaticRoutes for range >=2.0.0-0 and <4.0.0-0.
New migration implementation
cmd/internal/migrations/v3/logger_generics.go
Adds MigrateLoggerGenerics: regex-based replacements for AllLogger→AllLogger[any], ConfigurableLogger→ConfigurableLogger[any], DefaultLogger()→DefaultLoggerany, SetLogger(→SetLogger[any](, LoggerToWriter(→LoggerToWriter[any](; uses internal.ChangeFileContent; logs on change.
Tests
cmd/internal/migrations/v3/logger_generics_test.go
Introduces unit test that creates sample Go code, runs the migration command, asserts generic replacements and presence of "Migrating logger generics" in output.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Dev as Developer
  participant CLI as CLI Command
  participant Mig as DoMigration
  participant V3 as MigrateLoggerGenerics
  participant FS as Filesystem

  Dev->>CLI: run migrate (v3 range)
  CLI->>Mig: DoMigration(curr, target)
  Mig->>Mig: Check version constraints
  alt In range
    Mig->>V3: Call MigrateLoggerGenerics(cmd, cwd, curr, target)
    V3->>FS: internal.ChangeFileContent(cwd, regex replacements)
    alt Changes applied
      V3-->>CLI: print "Migrating logger generics"
      V3-->>Mig: nil
    else No changes
      V3-->>Mig: nil
    end
  else Out of range
    Mig-->>CLI: skip
  end
  CLI-->>Dev: exit (success or error)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

✏️ Feature

Poem

Thump-thump go my paws on keys so sleek,
I nudge old logs to speak in generic squeak.
AllLogger hops to AllLogger[any], neat!
Configurable too—what a tidy feat.
With twitches and regex, I tidy the trail,
Carrots for tests—green lights prevail! 🥕🐇

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/2025-08-24-11-48-42

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or @coderabbitai title anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @ReneWerner87, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a new migration script designed to update existing logger interfaces and functions to support Go generics. This ensures compatibility with newer Go features and standardizes logger usage across the codebase, making the logging system more flexible and type-safe.

Highlights

  • New Migration Added: A new migration, MigrateLoggerGenerics, has been integrated into the v3 migration list, ensuring it runs as part of the update process.
  • Logger Generics Migration Logic: A dedicated migration script has been added to automatically update logger function calls (e.g., AllLogger, DefaultLogger, SetLogger, LoggerToWriter) by appending [any] to them, adapting them for generic usage.
  • Comprehensive Testing: A new test file has been added to thoroughly validate the MigrateLoggerGenerics function, ensuring its correctness and reliability in transforming logger calls.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request adds a migration script to update logger interfaces and functions to use generics, along with corresponding tests. The changes are well-structured and the new migration is correctly registered. I have one suggestion to improve the implementation of the migration script by following Go's best practices for regular expression handling, which will also enhance code readability.

Comment on lines +13 to +37
func MigrateLoggerGenerics(cmd *cobra.Command, cwd string, _, _ *semver.Version) error {
reAllLogger := regexp.MustCompile(`(\w+)\.AllLogger([^\w\[]|$)`)
reConfigurableLogger := regexp.MustCompile(`(\w+)\.ConfigurableLogger([^\w\[]|$)`)
reDefaultLogger := regexp.MustCompile(`(\w+)\.DefaultLogger\(\)`)
reSetLogger := regexp.MustCompile(`(\w+)\.SetLogger\(`)
reLoggerToWriter := regexp.MustCompile(`(\w+)\.LoggerToWriter\(`)

changed, err := internal.ChangeFileContent(cwd, func(content string) string {
content = reAllLogger.ReplaceAllString(content, `$1.AllLogger[any]$2`)
content = reConfigurableLogger.ReplaceAllString(content, `$1.ConfigurableLogger[any]$2`)
content = reDefaultLogger.ReplaceAllString(content, `$1.DefaultLogger[any]()`)
content = reSetLogger.ReplaceAllString(content, `$1.SetLogger[any](`)
content = reLoggerToWriter.ReplaceAllString(content, `$1.LoggerToWriter[any](`)
return content
})
if err != nil {
return fmt.Errorf("failed to migrate logger generics: %w", err)
}
if !changed {
return nil
}

cmd.Println("Migrating logger generics")
return nil
}
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.

medium

For performance and to follow Go best practices, regular expressions should be compiled only once. You can define them as package-level variables using regexp.MustCompile. This avoids recompiling them every time MigrateLoggerGenerics is called. While the performance impact is likely negligible in this command-line tool context, this change improves code structure and adheres to common Go idioms.

var (
	reAllLogger          = regexp.MustCompile("(\\w+)\\.AllLogger([^\\w\\[]|$)")
	reConfigurableLogger = regexp.MustCompile("(\\w+)\\.ConfigurableLogger([^\\w\\[]|$)")
	reDefaultLogger      = regexp.MustCompile("(\\w+)\\.DefaultLogger\\(\\)")
	reSetLogger          = regexp.MustCompile("(\\w+)\\.SetLogger\\(")
	reLoggerToWriter     = regexp.MustCompile("(\\w+)\\.LoggerToWriter\\(")
)

func MigrateLoggerGenerics(cmd *cobra.Command, cwd string, _, _ *semver.Version) error {
	changed, err := internal.ChangeFileContent(cwd, func(content string) string {
		content = reAllLogger.ReplaceAllString(content, "$1.AllLogger[any]$2")
		content = reConfigurableLogger.ReplaceAllString(content, "$1.ConfigurableLogger[any]$2")
		content = reDefaultLogger.ReplaceAllString(content, "$1.DefaultLogger[any]()")
		content = reSetLogger.ReplaceAllString(content, "$1.SetLogger[any](")
		content = reLoggerToWriter.ReplaceAllString(content, "$1.LoggerToWriter[any](")
		return content
	})
	if err != nil {
		return fmt.Errorf("failed to migrate logger generics: %w", err)
	}
	if !changed {
		return nil
	}

	cmd.Println("Migrating logger generics")
	return nil
}

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (8)
cmd/internal/migrations/v3/logger_generics.go (5)

13-19: Scope regex to Fiber log imports to avoid false positives.

The current patterns match any pkg alias (e.g., foo.SetLogger().) That risks unintended rewrites for unrelated packages. Consider detecting the aliases used for github.com/gofiber/fiber/v2/log (and v3/log) from the file’s import list and restrict replacements to those aliases.

Apply this diff to make replacements alias-aware with a safe fallback:

 func MigrateLoggerGenerics(cmd *cobra.Command, cwd string, _, _ *semver.Version) error {
-	reAllLogger := regexp.MustCompile(`(\w+)\.AllLogger([^\w\[]|$)`)
-	reConfigurableLogger := regexp.MustCompile(`(\w+)\.ConfigurableLogger([^\w\[]|$)`)
-	reDefaultLogger := regexp.MustCompile(`(\w+)\.DefaultLogger\(\)`)
-	reSetLogger := regexp.MustCompile(`(\w+)\.SetLogger\(`)
-	reLoggerToWriter := regexp.MustCompile(`(\w+)\.LoggerToWriter\(`)
+	// Fallback patterns (any alias) in case we cannot resolve import aliases.
+	fallbackAllLogger := regexp.MustCompile(`(\w+)\.AllLogger([^\w\[]|$)`)
+	fallbackConfigurableLogger := regexp.MustCompile(`(\w+)\.ConfigurableLogger([^\w\[]|$)`)
+	fallbackDefaultLogger := regexp.MustCompile(`(\w+)\.DefaultLogger\s*\(\)`)
+	fallbackSetLogger := regexp.MustCompile(`(\w+)\.SetLogger\s*\(`)
+	fallbackLoggerToWriter := regexp.MustCompile(`(\w+)\.LoggerToWriter\s*\(`)
 
 	changed, err := internal.ChangeFileContent(cwd, func(content string) string {
-		content = reAllLogger.ReplaceAllString(content, `$1.AllLogger[any]$2`)
-		content = reConfigurableLogger.ReplaceAllString(content, `$1.ConfigurableLogger[any]$2`)
-		content = reDefaultLogger.ReplaceAllString(content, `$1.DefaultLogger[any]()`)
-		content = reSetLogger.ReplaceAllString(content, `$1.SetLogger[any](`)
-		content = reLoggerToWriter.ReplaceAllString(content, `$1.LoggerToWriter[any](`)
+		// Detect aliases for Fiber's log package from imports; support v2 and v3 paths.
+		importRE := regexp.MustCompile(`(?m)^\s*(?:([\w_]+)\s+)?\"github\.com/gofiber/fiber/v(2|3)/log\"`)
+		matches := importRE.FindAllStringSubmatch(content, -1)
+		var aliases []string
+		for _, m := range matches {
+			alias := m[1]
+			if alias == "" {
+				alias = "log" // default alias if none is specified
+			}
+			aliases = append(aliases, regexp.QuoteMeta(alias))
+		}
+
+		// Compile alias-scoped regexes when we have at least one alias; else use fallbacks.
+		if len(aliases) > 0 {
+			pkgs := strings.Join(aliases, "|")
+			reAllLogger := regexp.MustCompile(`\b(` + pkgs + `)\.AllLogger([^\w\[]|$)`)
+			reConfigurableLogger := regexp.MustCompile(`\b(` + pkgs + `)\.ConfigurableLogger([^\w\[]|$)`)
+			reDefaultLogger := regexp.MustCompile(`\b(` + pkgs + `)\.DefaultLogger\s*\(\)`)
+			reSetLogger := regexp.MustCompile(`\b(` + pkgs + `)\.SetLogger\s*\(`)
+			reLoggerToWriter := regexp.MustCompile(`\b(` + pkgs + `)\.LoggerToWriter\s*\(`)
+
+			content = reAllLogger.ReplaceAllString(content, `$1.AllLogger[any]$2`)
+			content = reConfigurableLogger.ReplaceAllString(content, `$1.ConfigurableLogger[any]$2`)
+			content = reDefaultLogger.ReplaceAllString(content, `$1.DefaultLogger[any]()`)
+			content = reSetLogger.ReplaceAllString(content, `$1.SetLogger[any](`)
+			content = reLoggerToWriter.ReplaceAllString(content, `$1.LoggerToWriter[any](`)
+		} else {
+			// Fallback: apply broad patterns.
+			content = fallbackAllLogger.ReplaceAllString(content, `$1.AllLogger[any]$2`)
+			content = fallbackConfigurableLogger.ReplaceAllString(content, `$1.ConfigurableLogger[any]$2`)
+			content = fallbackDefaultLogger.ReplaceAllString(content, `$1.DefaultLogger[any]()`)
+			content = fallbackSetLogger.ReplaceAllString(content, `$1.SetLogger[any](`)
+			content = fallbackLoggerToWriter.ReplaceAllString(content, `$1.LoggerToWriter[any](`)
+		}
 		return content
 	})

Note: This also tolerates optional whitespace before parentheses.


16-18: Allow optional whitespace before parentheses in call patterns.

Go permits spaces between the identifier and the call parens (e.g., DefaultLogger ()) even if it’s uncommon. Making the regex tolerant avoids missing those cases.

Apply the focused tweak (already included above), or minimally:

-reDefaultLogger := regexp.MustCompile(`(\w+)\.DefaultLogger\(\)`)
-reSetLogger := regexp.MustCompile(`(\w+)\.SetLogger\(`)
-reLoggerToWriter := regexp.MustCompile(`(\w+)\.LoggerToWriter\(`)
+reDefaultLogger := regexp.MustCompile(`(\w+)\.DefaultLogger\s*\(\)`)
+reSetLogger := regexp.MustCompile(`(\w+)\.SetLogger\s*\(`)
+reLoggerToWriter := regexp.MustCompile(`(\w+)\.LoggerToWriter\s*\(`)

21-26: Idempotency guard is good; consider documenting regex intent.

The [^\w\[] guard prevents double-applying when generics are already present. Consider a brief comment explaining that, so future maintainers don’t “simplify” it and reintroduce double-rewrite risk.

Example:

- content = reAllLogger.ReplaceAllString(content, `$1.AllLogger[any]$2`)
+ // Guard ensures we don't match when `[...]` already follows the symbol.
+ content = reAllLogger.ReplaceAllString(content, `$1.AllLogger[any]$2`)

35-36: Print once per changed file set (optional).

Printing a single “Migrating logger generics” message is fine. If you later change this to report per-file, consider prefixing with file paths for easier diffing. No change needed now.


13-37: Optional micro: compile once at package scope.

Compiling regexes per run is fine here, but if this migration scales across many files in large repos, moving stable patterns to package scope can shave overhead. Low priority.

cmd/internal/migrations/v3/logger_generics_test.go (3)

21-33: Good coverage of primary replacements; consider adding “already generic” cases.

Add a second file (or inline content) that already uses AllLogger[any], ConfigurableLogger[any], DefaultLoggerany, etc., and assert that no changes are made and nothing is printed. This verifies idempotency and the [^\w\[] regex guard.

Proposed additional test:

 func Test_MigrateLoggerGenerics(t *testing.T) {
@@
 }
 
+func Test_MigrateLoggerGenerics_NoChanges_Idempotent(t *testing.T) {
+	t.Parallel()
+	dir, err := os.MkdirTemp("", "mloggenericstest-idem")
+	require.NoError(t, err)
+	defer func() { require.NoError(t, os.RemoveAll(dir)) }()
+
+	_ = writeTempFile(t, dir, `package main
+import fiberlog "github.com/gofiber/fiber/v2/log"
+var _ fiberlog.AllLogger[any] = (*struct{})(nil)
+var _ fiberlog.ConfigurableLogger[any] = (*struct{})(nil)
+func main() {
+    l := fiberlog.DefaultLogger[any]()
+    fiberlog.SetLogger[any](l)
+    _ = fiberlog.LoggerToWriter[any](l, fiberlog.LevelInfo)
+}`)
+
+	var buf bytes.Buffer
+	cmd := newCmd(&buf)
+	require.NoError(t, v3.MigrateLoggerGenerics(cmd, dir, nil, nil))
+	assert.Empty(t, buf.String(), "expected no output when no changes are needed")
+}

21-33: Optional: guard against false positives by adding a counter-example.

If you adopt alias scoping in the migration, add a control case with a different package exposing SetLogger that must not be rewritten.

Example snippet to include in the same test setup:

_ = writeTempFile(t, dir, `package main
import zap "go.uber.org/zap"
func main() {
    _ = zap.NewExample() // ensure another import exists
    // simulate some other lib: foo.SetLogger(...) should remain unchanged
    foo.SetLogger(nil)
}`)

Then assert the file still contains "foo.SetLogger(" after migration.


34-47: Assertion mix is fine; prefer require on invariants.

Where a failed assertion would make subsequent checks meaningless (e.g., readFile success, presence of “Migrating logger generics”), using require.* improves signal. Minor.

Possible tweaks:

-assert.Contains(t, content, "DefaultLogger[any]()")
+require.Contains(t, content, "DefaultLogger[any]()")
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6fe75c7 and 248931d.

📒 Files selected for processing (3)
  • cmd/internal/migrations/lists.go (1 hunks)
  • cmd/internal/migrations/v3/logger_generics.go (1 hunks)
  • cmd/internal/migrations/v3/logger_generics_test.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
cmd/internal/migrations/lists.go (1)
cmd/internal/migrations/v3/logger_generics.go (1)
  • MigrateLoggerGenerics (13-37)
cmd/internal/migrations/v3/logger_generics_test.go (1)
cmd/internal/migrations/v3/logger_generics.go (1)
  • MigrateLoggerGenerics (13-37)
cmd/internal/migrations/v3/logger_generics.go (1)
cmd/internal/helpers.go (1)
  • ChangeFileContent (38-79)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build (1.25.x, macos-13)
🔇 Additional comments (2)
cmd/internal/migrations/lists.go (2)

45-47: Wire-up looks correct; order makes sense next to other logger migrations.

Placing MigrateLoggerGenerics right after MigrateLoggerTags and before MigrateStaticRoutes aligns it with related logger changes and should minimize surprises from subsequent rewrites.


33-79: Migration ordering validated
A search through cmd/internal/migrations/v3/generic_helpers.go shows that MigrateGenericHelpers only targets ParamsInt and QueryInt patterns—there are no logger-related regexes—so MigrateLoggerGenerics remains the correct next step in lists.go. No action required.

@ReneWerner87 ReneWerner87 merged commit 287db05 into master Aug 24, 2025
13 checks passed
@ReneWerner87 ReneWerner87 deleted the codex/2025-08-24-11-48-42 branch August 24, 2025 11:56
@ReneWerner87 ReneWerner87 added the ✏️ Feature New feature or request label Aug 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codex ✏️ Feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant