From 26fa4534a212b6948bc5074be77dc61fb12d0d26 Mon Sep 17 00:00:00 2001 From: laurentiu021 Date: Thu, 11 Jun 2026 13:43:16 +0300 Subject: [PATCH] refactor: use [GeneratedRegex] and SearchValues on log hot paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two .NET 10 idiom modernizations on hot/testable paths, behavior unchanged: - LogService is now a static partial class; the constant fallback user-path pattern is source-generated via [GeneratedRegex] (FallbackUserPathRegex) instead of new Regex(..., Compiled) โ€” build-time compiled, no runtime IL emit, AOT-friendly. The dynamic interpolated branch (built from the real user-profile dir) stays a runtime Regex since it can't be source-generated. - EventLogService.FirstLine hoists a static SearchValues for the \r\n scan and uses span IndexOfAny, removing the per-call char[] allocation on a path that runs once per projected event record (thousands per query). Both regex patterns and the FirstLine result are byte-identical to before. --- SysManager/SysManager/Services/EventLogService.cs | 7 ++++++- SysManager/SysManager/Services/LogService.cs | 10 +++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/SysManager/SysManager/Services/EventLogService.cs b/SysManager/SysManager/Services/EventLogService.cs index 33f5a93..6e70581 100644 --- a/SysManager/SysManager/Services/EventLogService.cs +++ b/SysManager/SysManager/Services/EventLogService.cs @@ -2,6 +2,7 @@ // Author: laurentiu021 ยท https://github.com/laurentiu021/SystemManager // License: MIT +using System.Buffers; using System.Diagnostics.Eventing.Reader; using SysManager.Models; @@ -113,10 +114,14 @@ private static string SafeFormatMessage(EventRecord rec) catch (InvalidOperationException) { return "(message not available)"; } } + // Hoisted so the newline scan in FirstLine โ€” run once per projected event + // record, potentially thousands per query โ€” doesn't allocate a char[] per call. + private static readonly SearchValues Newlines = SearchValues.Create("\r\n"); + private static string FirstLine(string s) { if (string.IsNullOrEmpty(s)) return ""; - var i = s.IndexOfAny(new[] { '\r', '\n' }); + var i = s.AsSpan().IndexOfAny(Newlines); return (i < 0 ? s : s[..i]).Trim(); } diff --git a/SysManager/SysManager/Services/LogService.cs b/SysManager/SysManager/Services/LogService.cs index e5a5a9b..cd6167e 100644 --- a/SysManager/SysManager/Services/LogService.cs +++ b/SysManager/SysManager/Services/LogService.cs @@ -9,7 +9,7 @@ namespace SysManager.Services; -public static class LogService +public static partial class LogService { public static Logger? Logger { get; private set; } @@ -33,10 +33,14 @@ private static Regex BuildUserPathRegex() return new Regex($@"(?i)({escaped})[^\\]+", RegexOptions.Compiled); } } - // Fallback: match any drive letter followed by \Users\ - return new Regex(@"(?i)([A-Z]:\\Users\\)[^\\]+", RegexOptions.Compiled); + // Fallback: match any drive letter followed by \Users\. + // This branch is a constant pattern, so it is source-generated. + return FallbackUserPathRegex(); } + [GeneratedRegex(@"(?i)([A-Z]:\\Users\\)[^\\]+")] + private static partial Regex FallbackUserPathRegex(); + public static void Init() { Directory.CreateDirectory(LogDir);