Skip to content

Conversation

@snakefoot
Copy link
Contributor

@snakefoot snakefoot commented Aug 30, 2025

See also: #5978

@coderabbitai
Copy link

coderabbitai bot commented Aug 30, 2025

Walkthrough

Adds an archiveCleanupReason string propagated into old-archive deletion calls and logs, threads the new reason parameter through archive handlers by changing DeleteOldArchiveFile signatures and call sites, adds early-exit paths when no files match, and expands deletion exception handling and retry/logging paths; preserves overall cleanup control flow.

Changes

Cohort / File(s) Summary
Core handler (signature, logging, cleanup control)
src/NLog/Targets/FileArchiveHandlers/BaseFileArchiveHandler.cs
Adds directory-exists and empty-wildcard early exits; computes fileWildcardStartIndex/fileWildcardEndIndex, startup-aware maxArchiveFiles, and archiveCleanupReason; passes reason into deletion calls; updates deletion log to include reason; changes DeleteOldArchiveFile signature to (string filepath, string archiveCleanupReason); expands exception handling and retry logic.
Legacy filename handler callsites
src/NLog/Targets/FileArchiveHandlers/LegacyArchiveFileNameHandler.cs
Replaces single-arg DeleteOldArchiveFile calls with two-arg form (examples: "Truncate Active File"), preserving retry and FileShare adjustments; method signature updated to accept the reason parameter.
Rolling startup cleanup
src/NLog/Targets/FileArchiveHandlers/RollingArchiveFileHandler.cs
Startup deletion path now calls DeleteOldArchiveFile(fullPath, "DeleteOldFileOnStartup=true") (two-arg), matching the new signature; remaining logic unchanged.
Zero-file handler reason wiring
src/NLog/Targets/FileArchiveHandlers/ZeroFileArchiveHandler.cs
Computes archiveCleanupReason (e.g., "ArchiveOldFileOnStartup=true" or "MaxArchiveFiles={N}") and calls DeleteOldArchiveFile(newFilePath, archiveCleanupReason) instead of single-arg overload; flow otherwise unchanged.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor App
  participant Base as BaseFileArchiveHandler
  participant FS as FileSystem

  App->>Base: CleanupOldArchives()
  rect rgba(230,240,255,0.5)
    note over Base: Determine archiveCleanupReason\n(e.g., MaxArchiveDays/MaxArchiveFiles or startup flags)
  end
  loop for each candidate file
    Base->>FS: DeleteOldArchiveFile(path, archiveCleanupReason)
    alt success
      FS-->>Base: true
      Base->>App: Log deletion with reason
    else failure
      FS-->>Base: false
      Base->>App: Handle failure (retry/adjust logging)
    end
  end
Loading
sequenceDiagram
  autonumber
  actor App
  participant Rolling as RollingArchiveFileHandler
  participant FS as FileSystem

  App->>Rolling: RollToInitialSequenceNumber(startup)
  alt DeleteOldFileOnStartup=true
    Rolling->>FS: DeleteOldArchiveFile(fullPath, "DeleteOldFileOnStartup=true")
    FS-->>Rolling: result
  else no startup deletion
    Rolling-->>App: continue
  end
  Rolling-->>App: return 0
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I nudged old logs from the burrow with care,
Labeled each farewell with a tidy affair.
“Startup” or “max” — a reason to keep,
Hopping old bytes gently into sleep.
A carrot for cleanup, quiet and fair. 🥕🐇


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 or @coderabbit 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 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.

@snakefoot snakefoot force-pushed the filetarget_cleanup_reason branch 2 times, most recently from 3a57813 to 00134e3 Compare August 30, 2025 14:19
Copy link

@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 (5)
src/NLog/Targets/FileArchiveHandlers/BaseFileArchiveHandler.cs (2)

88-91: Reason string can misrepresent actual policy; include both and use effective max count

Currently logs "MaxArchiveFiles" even when both MaxArchiveFiles and MaxArchiveDays are configured, and it ignores the effective maxArchiveFiles value (after startup adjustments). Prefer composing the reason from the active/effective settings.

-                    var archiveCleanupReason = (_fileTarget.MaxArchiveFiles < 0 && _fileTarget.MaxArchiveDays > 0) ? $"MaxArchiveDays={_fileTarget.MaxArchiveDays}" : $"MaxArchiveFiles={_fileTarget.MaxArchiveFiles}";
-                    if (initialFileOpen && _fileTarget.DeleteOldFileOnStartup)
-                        archiveCleanupReason = "DeleteOldFileOnStartup=true";
+                    var archiveCleanupReason = (_fileTarget.MaxArchiveFiles < 0 && _fileTarget.MaxArchiveDays > 0)
+                        ? $"MaxArchiveDays={_fileTarget.MaxArchiveDays}"
+                        : $"MaxArchiveFiles={maxArchiveFiles}"; // reflect effective count
+                    if (_fileTarget.MaxArchiveFiles >= 0 && _fileTarget.MaxArchiveDays > 0)
+                        archiveCleanupReason = $"MaxArchiveFiles={maxArchiveFiles}, MaxArchiveDays={_fileTarget.MaxArchiveDays}";
+                    if (initialFileOpen && _fileTarget.DeleteOldFileOnStartup)
+                        archiveCleanupReason = "DeleteOldFileOnStartup=true";

332-373: Echo reason on failures for better diagnostics

Include archiveCleanupReason in the exception paths as well.

-                    InternalLogger.Debug(ex, "{0}: Failed to delete old file as directory not found: '{1}'", _fileTarget, filepath);
+                    InternalLogger.Debug(ex, "{0}: Failed to delete old file as directory not found (Reason: {1}): '{2}'", _fileTarget, archiveCleanupReason, filepath);
...
-                    InternalLogger.Debug(ex, "{0}: Failed to delete old file as file not found: '{1}'", _fileTarget, filepath);
+                    InternalLogger.Debug(ex, "{0}: Failed to delete old file as file not found (Reason: {1}): '{2}'", _fileTarget, archiveCleanupReason, filepath);
...
-                    InternalLogger.Debug(ex, "{0}: Failed to delete old file, maybe file is locked: '{1}'", _fileTarget, filepath);
+                    InternalLogger.Debug(ex, "{0}: Failed to delete old file, maybe file is locked (Reason: {1}): '{2}'", _fileTarget, archiveCleanupReason, filepath);
...
-                    InternalLogger.Warn(ex, "{0}: Failed to delete old archive file: '{1}'.", _fileTarget, filepath);
+                    InternalLogger.Warn(ex, "{0}: Failed to delete old archive file (Reason: {1}): '{2}'.", _fileTarget, archiveCleanupReason, filepath);
src/NLog/Targets/FileArchiveHandlers/ZeroFileArchiveHandler.cs (1)

81-83: Reason label here is about retention, but action is “reset/truncate active file”

Optional: make the reason reflect the action when not on startup, e.g., “Reset Active File”, for clearer logs.

-                    var archiveCleanupReason = (_fileTarget.MaxArchiveFiles < 0 && _fileTarget.ArchiveOldFileOnStartup) ? "ArchiveOldFileOnStartup=true" : $"MaxArchiveFiles={_fileTarget.MaxArchiveFiles}";
+                    var archiveCleanupReason = (_fileTarget.MaxArchiveFiles < 0 && _fileTarget.ArchiveOldFileOnStartup)
+                        ? "ArchiveOldFileOnStartup=true"
+                        : "Reset Active File";
src/NLog/Targets/FileArchiveHandlers/RollingArchiveFileHandler.cs (1)

121-121: LGTM; consider a shared constant for the reason token

To avoid typos across files, extract "DeleteOldFileOnStartup=true" into a private const or a static helper.

Example:

private const string ReasonDeleteOldOnStartup = "DeleteOldFileOnStartup=true";
src/NLog/Targets/FileArchiveHandlers/LegacyArchiveFileNameHandler.cs (1)

228-239: Unify terminology: BirthTime vs CreationTime; deduplicate the reason string

Comments reference CreationTime; the reason says “BirthTime”. Use one term consistently and avoid duplicating the literal.

-                if (!DeleteOldArchiveFile(newFilePath, "Reset File BirthTime"))
+                if (!DeleteOldArchiveFile(newFilePath, "Reset File CreationTime"))
...
-            DeleteOldArchiveFile(newFilePath, "Reset File BirthTime"); // Attempt to delete file to reset File-Creation-Time
+            DeleteOldArchiveFile(newFilePath, "Reset File CreationTime"); // Attempt to delete file to reset File-Creation-Time

Optionally:

// near class top
private const string ReasonResetCreationTime = "Reset File CreationTime";
// and use ReasonResetCreationTime in both places
📜 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 13018d2 and 00134e3.

📒 Files selected for processing (4)
  • src/NLog/Targets/FileArchiveHandlers/BaseFileArchiveHandler.cs (2 hunks)
  • src/NLog/Targets/FileArchiveHandlers/LegacyArchiveFileNameHandler.cs (2 hunks)
  • src/NLog/Targets/FileArchiveHandlers/RollingArchiveFileHandler.cs (1 hunks)
  • src/NLog/Targets/FileArchiveHandlers/ZeroFileArchiveHandler.cs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
src/NLog/Targets/FileArchiveHandlers/LegacyArchiveFileNameHandler.cs (1)
src/NLog/Targets/FileArchiveHandlers/BaseFileArchiveHandler.cs (1)
  • DeleteOldArchiveFile (332-373)
src/NLog/Targets/FileArchiveHandlers/BaseFileArchiveHandler.cs (1)
src/NLog.Targets.ConcurrentFile/ConcurrentFileTarget.cs (1)
  • DeleteOldArchiveFile (1380-1405)
src/NLog/Targets/FileArchiveHandlers/ZeroFileArchiveHandler.cs (2)
src/NLog/Targets/FileArchiveHandlers/BaseFileArchiveHandler.cs (1)
  • DeleteOldArchiveFile (332-373)
src/NLog.Targets.ConcurrentFile/ConcurrentFileTarget.cs (1)
  • DeleteOldArchiveFile (1380-1405)
src/NLog/Targets/FileArchiveHandlers/RollingArchiveFileHandler.cs (1)
src/NLog/Targets/FileArchiveHandlers/BaseFileArchiveHandler.cs (1)
  • DeleteOldArchiveFile (332-373)
🔇 Additional comments (2)
src/NLog/Targets/FileArchiveHandlers/BaseFileArchiveHandler.cs (2)

96-96: Good: reason plumbed into deletion call

Passing archiveCleanupReason through improves traceability without altering behavior.


52-60: Signature change ripple check passed Verified no one-argument DeleteOldArchiveFile calls remain outside src/NLog.Targets.ConcurrentFile.

@snakefoot snakefoot force-pushed the filetarget_cleanup_reason branch 4 times, most recently from 7f5d06f to ba3923b Compare August 30, 2025 15:22
@pull-request-size pull-request-size bot added size/M and removed size/S labels Aug 30, 2025
@snakefoot snakefoot force-pushed the filetarget_cleanup_reason branch from ba3923b to 575e7f5 Compare August 30, 2025 15:25
Copy link

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/NLog/Targets/FileArchiveHandlers/BaseFileArchiveHandler.cs (1)

332-373: Include archiveCleanupReason in all DeleteOldArchiveFile calls
Replace the single-argument calls in src/NLog.Targets.ConcurrentFile/ConcurrentFileTarget.cs with the two-arg overload—update at lines 1325, 1341, 1413, 1626, 1633, 1670 and 2369 to pass a meaningful archiveCleanupReason.

🧹 Nitpick comments (4)
src/NLog/Targets/FileArchiveHandlers/BaseFileArchiveHandler.cs (4)

81-88: Guard against negative wildcard index when wildCardContainsSeqNo=true.
If fileWildcard lacks '', IndexOf returns -1; passing this into the seq-no scan can crash when wildCardContainsSeqNo=true. Recommend clamping usage to only when a '' is present, and clarifying the variable name.

Apply:

-                int fileWildcardStartIndex = fileWildcard.IndexOf('*');
-                int fileWildcardEndIndex = fileWildcard.Length - fileWildcardStartIndex;
+                int fileWildcardStartIndex = fileWildcard.IndexOf('*');
+                int fileWildcardEndIndex = (fileWildcardStartIndex >= 0) ? (fileWildcard.Length - fileWildcardStartIndex) : -1;
                 var maxArchiveFiles = _fileTarget.MaxArchiveFiles;
@@
-                foreach (var cleanupFileInfo in FileInfoDateTime.CleanupFiles(fileInfos, maxArchiveFiles, _fileTarget.MaxArchiveDays, fileWildcardStartIndex, fileWildcardEndIndex, excludeFileName, wildCardContainsSeqNo))
+                var containsSeqNo = wildCardContainsSeqNo && fileWildcardStartIndex >= 0;
+                foreach (var cleanupFileInfo in FileInfoDateTime.CleanupFiles(fileInfos, maxArchiveFiles, _fileTarget.MaxArchiveDays, fileWildcardStartIndex, fileWildcardEndIndex, excludeFileName, containsSeqNo))

Optional: rename fileWildcardEndIndex to fileWildcardSuffixLength for clarity.

Also applies to: 94-95


89-92: Reason string can mislead when both retention limits are set.
When both MaxArchiveFiles and MaxArchiveDays are configured, deletions may be age-driven but the reason logs “MaxArchiveFiles=…”. Prefer a neutral, explicit reason that includes both settings.

-                var archiveCleanupReason = (_fileTarget.MaxArchiveFiles < 0 && _fileTarget.MaxArchiveDays > 0) ? $"MaxArchiveDays={_fileTarget.MaxArchiveDays}" : $"MaxArchiveFiles={_fileTarget.MaxArchiveFiles}";
+                var archiveCleanupReason = $"Retention(MaxArchiveFiles={_fileTarget.MaxArchiveFiles}, MaxArchiveDays={_fileTarget.MaxArchiveDays})";
                 if (initialFileOpen && _fileTarget.DeleteOldFileOnStartup)
                     archiveCleanupReason = "DeleteOldFileOnStartup=true";

93-98: Return true only if deletion actually succeeded.
Currently sets oldFilesDeleted=true before attempting deletion, so transient failures still report success.

-                bool oldFilesDeleted = false;
+                bool oldFilesDeleted = false;
                 foreach (var cleanupFileInfo in FileInfoDateTime.CleanupFiles(fileInfos, maxArchiveFiles, _fileTarget.MaxArchiveDays, fileWildcardStartIndex, fileWildcardEndIndex, excludeFileName, wildCardContainsSeqNo))
                 {
-                    oldFilesDeleted = true;
-                    DeleteOldArchiveFile(cleanupFileInfo.FullName, archiveCleanupReason);
+                    oldFilesDeleted |= DeleteOldArchiveFile(cleanupFileInfo.FullName, archiveCleanupReason);
                 }
 
                 return oldFilesDeleted;

Also applies to: 100-100


332-373: Tweak log messages; include attempt count and reason on failures.
Improves diagnosability while preserving behavior.

-                    InternalLogger.Info("{0}: {1} deleting old archive file: '{2}'.", _fileTarget, archiveCleanupReason, filepath);
+                    InternalLogger.Info("{0}: Deleting old archive file due to {1}: '{2}'.", _fileTarget, archiveCleanupReason, filepath);
@@
-                    InternalLogger.Debug(ex, "{0}: Failed to delete old file as directory not found: '{1}'", _fileTarget, filepath);
+                    InternalLogger.Debug(ex, "{0}: Failed to delete old file due to {1} (directory not found): '{2}'", _fileTarget, archiveCleanupReason, filepath);
@@
-                    InternalLogger.Debug(ex, "{0}: Failed to delete old file as file not found: '{1}'", _fileTarget, filepath);
+                    InternalLogger.Debug(ex, "{0}: Failed to delete old file due to {1} (file not found): '{2}'", _fileTarget, archiveCleanupReason, filepath);
@@
-                    InternalLogger.Debug(ex, "{0}: Failed to delete old file, maybe file is locked: '{1}'", _fileTarget, filepath);
+                    InternalLogger.Debug(ex, "{0}: Attempt {1}/3 failed to delete old file (maybe locked) due to {2}: '{3}'", _fileTarget, i, archiveCleanupReason, filepath);
@@
-                    InternalLogger.Warn(ex, "{0}: Failed to delete old archive file: '{1}'.", _fileTarget, filepath);
+                    InternalLogger.Warn(ex, "{0}: Failed to delete old archive file due to {1}: '{2}'.", _fileTarget, archiveCleanupReason, filepath);
📜 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 00134e3 and ba3923b.

📒 Files selected for processing (4)
  • src/NLog/Targets/FileArchiveHandlers/BaseFileArchiveHandler.cs (2 hunks)
  • src/NLog/Targets/FileArchiveHandlers/LegacyArchiveFileNameHandler.cs (2 hunks)
  • src/NLog/Targets/FileArchiveHandlers/RollingArchiveFileHandler.cs (1 hunks)
  • src/NLog/Targets/FileArchiveHandlers/ZeroFileArchiveHandler.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/NLog/Targets/FileArchiveHandlers/LegacyArchiveFileNameHandler.cs
  • src/NLog/Targets/FileArchiveHandlers/RollingArchiveFileHandler.cs
  • src/NLog/Targets/FileArchiveHandlers/ZeroFileArchiveHandler.cs
🧰 Additional context used
🧬 Code graph analysis (1)
src/NLog/Targets/FileArchiveHandlers/BaseFileArchiveHandler.cs (1)
src/NLog.Targets.ConcurrentFile/ConcurrentFileTarget.cs (1)
  • DeleteOldArchiveFile (1380-1405)
🔇 Additional comments (1)
src/NLog/Targets/FileArchiveHandlers/BaseFileArchiveHandler.cs (1)

78-80: Good early exit on empty matches.
Avoids unnecessary work when no files are present.

Copy link

@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: 1

🧹 Nitpick comments (6)
src/NLog/Targets/FileArchiveHandlers/BaseFileArchiveHandler.cs (6)

74-77: Fix misleading debug message when directory is missing

The log implies “no files matching wildcard” but this branch is hit because the directory doesn’t exist.

-    InternalLogger.Debug("{0}: Archive Cleanup found no files matching wildcard {1} in directory: {2}", _fileTarget, fileWildcard, fileDirectory);
+    InternalLogger.Debug("{0}: Archive Cleanup skipped; directory does not exist. Wildcard={1}, Directory={2}", _fileTarget, fileWildcard, fileDirectory);

92-95: Log effective cleanup driver

Reason currently logs configured MaxArchiveFiles, not the effective value after adjustments. Consider logging the effective value to aid diagnostics.

-var archiveCleanupReason = (_fileTarget.MaxArchiveFiles < 0 && _fileTarget.MaxArchiveDays > 0) ? $"MaxArchiveDays={_fileTarget.MaxArchiveDays}" : $"MaxArchiveFiles={_fileTarget.MaxArchiveFiles}";
+var archiveCleanupReason = (_fileTarget.MaxArchiveFiles < 0 && _fileTarget.MaxArchiveDays > 0)
+    ? $"MaxArchiveDays={_fileTarget.MaxArchiveDays}"
+    : $"MaxArchiveFiles={maxArchiveFiles}";

341-345: Polish Info log phrasing for readability

Minor wording tweak reads better in logs.

-InternalLogger.Info("{0}: {1} deleting old archive file: '{2}'.", _fileTarget, archiveCleanupReason, filepath);
+InternalLogger.Info("{0}: Deleting old archive file ({1}): '{2}'.", _fileTarget, archiveCleanupReason, filepath);

356-363: Elevate final IO failure to Warn

On the last retry, consider logging Warn (with reason) to surface persistent lock issues.

-                catch (IOException ex)
+                catch (IOException ex)
                 {
-                    InternalLogger.Debug(ex, "{0}: Failed to delete old file, maybe file is locked: '{1}'", _fileTarget, filepath);
+                    var isFinalAttempt = i >= 3;
+                    if (isFinalAttempt)
+                        InternalLogger.Warn(ex, "{0}: Final attempt failed to delete old file ({1}): '{2}'", _fileTarget, archiveCleanupReason, filepath);
+                    else
+                        InternalLogger.Debug(ex, "{0}: Failed to delete old file, maybe file is locked: '{1}'", _fileTarget, filepath);
                     if (!File.Exists(filepath))
                         return true;
-                    if (i >= 3 && ex.MustBeRethrown(_fileTarget))
+                    if (isFinalAttempt && ex.MustBeRethrown(_fileTarget))
                         throw;
                 }

373-375: Optional: add small jitter to retries

Helps reduce thundering-herd on shared paths.

-Thread.Sleep(i * 10);
+Thread.Sleep(i * 10 + ThreadLocalRandom.Next(0, 10));

Additional code (once in the file):

private static class ThreadLocalRandom
{
    private static readonly ThreadLocal<Random> _rng = new ThreadLocal<Random>(() => new Random(unchecked(Environment.TickCount * 31 + Thread.CurrentThread.ManagedThreadId)));
    public static int Next(int min, int max) => _rng.Value!.Next(min, max);
}

347-355: Standardize DeleteOldArchiveFile return values
BaseFileArchiveHandler.DeleteOldArchiveFile returns true on DirectoryNotFound/FileNotFound, whereas ConcurrentFileTarget.DeleteOldArchiveFile returns false in those cases. Align both to use a consistent “true means file no longer exists after attempt” semantic across the repository.

📜 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 ba3923b and 575e7f5.

📒 Files selected for processing (4)
  • src/NLog/Targets/FileArchiveHandlers/BaseFileArchiveHandler.cs (2 hunks)
  • src/NLog/Targets/FileArchiveHandlers/LegacyArchiveFileNameHandler.cs (2 hunks)
  • src/NLog/Targets/FileArchiveHandlers/RollingArchiveFileHandler.cs (1 hunks)
  • src/NLog/Targets/FileArchiveHandlers/ZeroFileArchiveHandler.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/NLog/Targets/FileArchiveHandlers/RollingArchiveFileHandler.cs
  • src/NLog/Targets/FileArchiveHandlers/LegacyArchiveFileNameHandler.cs
  • src/NLog/Targets/FileArchiveHandlers/ZeroFileArchiveHandler.cs
🧰 Additional context used
🧬 Code graph analysis (1)
src/NLog/Targets/FileArchiveHandlers/BaseFileArchiveHandler.cs (1)
src/NLog.Targets.ConcurrentFile/ConcurrentFileTarget.cs (1)
  • DeleteOldArchiveFile (1380-1405)
🔇 Additional comments (3)
src/NLog/Targets/FileArchiveHandlers/BaseFileArchiveHandler.cs (3)

81-83: Early-exit on zero matches — LGTM


96-103: Enumeration-and-continue strategy — LGTM

Best-effort deletion with final boolean summarizing work done is reasonable here.


86-91: Retention logic for MaxArchiveFiles is correct
Existing tests cover initialFileOpen with/without ArchiveOldFileOnStartup, DeleteOldFileOnStartup scenarios and validate MaxArchiveFiles behavior for 0, 1, and >1; no changes required.

Comment on lines +84 to +85
int fileWildcardStartIndex = fileWildcard.IndexOf('*');
int fileWildcardEndIndex = fileWildcard.Length - fileWildcardStartIndex;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Incorrect fileWildcardEndIndex calculation (off-by-one, wrong star)

Using the first '' and not subtracting 1 skews the suffix-length, especially when the pattern contains multiple '', leading to incorrect ExcludeFileName bounds.

-int fileWildcardStartIndex = fileWildcard.IndexOf('*');
-int fileWildcardEndIndex = fileWildcard.Length - fileWildcardStartIndex;
+int fileWildcardStartIndex = fileWildcard.IndexOf('*');
+int lastWildcardIdx = fileWildcard.LastIndexOf('*');
+int fileWildcardEndIndex = lastWildcardIdx >= 0 ? (fileWildcard.Length - lastWildcardIdx - 1) : 0;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
int fileWildcardStartIndex = fileWildcard.IndexOf('*');
int fileWildcardEndIndex = fileWildcard.Length - fileWildcardStartIndex;
int fileWildcardStartIndex = fileWildcard.IndexOf('*');
int lastWildcardIdx = fileWildcard.LastIndexOf('*');
int fileWildcardEndIndex = lastWildcardIdx >= 0
? (fileWildcard.Length - lastWildcardIdx - 1)
: 0;
🤖 Prompt for AI Agents
In src/NLog/Targets/FileArchiveHandlers/BaseFileArchiveHandler.cs around lines
84-85, the code uses fileWildcard.IndexOf('*') and computes fileWildcardEndIndex
as fileWildcard.Length - fileWildcardStartIndex which is off-by-one and uses the
first '*' only; fix by finding the last '*' (use LastIndexOf('*')) and compute
the suffix length as fileWildcard.Length - fileWildcardEndIndex - 1 (or
equivalently fileWildcard.Length - (lastStarIndex + 1)) so ExcludeFileName
bounds are calculated from the correct star position and with the correct
subtraction.

@sonarqubecloud
Copy link

This was referenced Sep 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Improvement on existing feature file-archiving Issues with archiving with the file target file-target size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant