From ab0803272ecab8fd76729fa6f56b001574dd78b2 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Mon, 19 Jan 2026 16:25:02 +0100 Subject: [PATCH] Do Pandoc logging only once --- app/MindWork AI Studio/Tools/Pandoc.cs | 59 ++++++--- .../Tools/PandocProcessBuilder.cs | 120 +++++++++++------- 2 files changed, 118 insertions(+), 61 deletions(-) diff --git a/app/MindWork AI Studio/Tools/Pandoc.cs b/app/MindWork AI Studio/Tools/Pandoc.cs index dba5be66..d14203ea 100644 --- a/app/MindWork AI Studio/Tools/Pandoc.cs +++ b/app/MindWork AI Studio/Tools/Pandoc.cs @@ -26,6 +26,11 @@ public static partial class Pandoc private static readonly Version MINIMUM_REQUIRED_VERSION = new (3, 7, 0, 2); private static readonly Version FALLBACK_VERSION = new (3, 7, 0, 2); + /// + /// Tracks whether the first availability check log has been written to avoid log spam on repeated calls. + /// + private static bool HAS_LOGGED_AVAILABILITY_CHECK_ONCE; + /// /// Prepares a Pandoc process by using the Pandoc process builder. /// @@ -41,18 +46,26 @@ public static partial class Pandoc /// True, if pandoc is available and the minimum required version is met, else false. public static async Task CheckAvailabilityAsync(RustService rustService, bool showMessages = true, bool showSuccessMessage = true) { + // + // Determine if we should log (only on the first call): + // + var shouldLog = !HAS_LOGGED_AVAILABILITY_CHECK_ONCE; + try { var preparedProcess = await PreparePandocProcess().AddArgument("--version").BuildAsync(rustService); - LOG.LogDebug("Checking Pandoc availability using executable: '{Executable}' (IsLocal: {IsLocal}).", preparedProcess.StartInfo.FileName, preparedProcess.IsLocal); + if (shouldLog) + LOG.LogInformation("Checking Pandoc availability using executable: '{Executable}' (IsLocal: {IsLocal}).", preparedProcess.StartInfo.FileName, preparedProcess.IsLocal); using var process = Process.Start(preparedProcess.StartInfo); if (process == null) { if (showMessages) - await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Help, TB("Was not able to check the Pandoc installation."))); + await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Help, TB("Was not able to check the Pandoc installation."))); - LOG.LogInformation("The Pandoc process was not started, it was null. Executable path: '{Executable}'.", preparedProcess.StartInfo.FileName); + if (shouldLog) + LOG.LogError("The Pandoc process was not started, it was null. Executable path: '{Executable}'.", preparedProcess.StartInfo.FileName); + return new(false, TB("Was not able to check the Pandoc installation."), false, string.Empty, preparedProcess.IsLocal); } @@ -68,9 +81,11 @@ public static partial class Pandoc if (process.ExitCode != 0) { if (showMessages) - await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Error, TB("Pandoc is not available on the system or the process had issues."))); + await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Error, TB("Pandoc is not available on the system or the process had issues."))); - LOG.LogError("The Pandoc process exited with code {ProcessExitCode}. Error output: '{ErrorText}'", process.ExitCode, error); + if (shouldLog) + LOG.LogError("The Pandoc process exited with code {ProcessExitCode}. Error output: '{ErrorText}'", process.ExitCode, error); + return new(false, TB("Pandoc is not available on the system or the process had issues."), false, string.Empty, preparedProcess.IsLocal); } @@ -78,39 +93,51 @@ public static partial class Pandoc if (!versionMatch.Success) { if (showMessages) - await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Terminal, TB("Was not able to validate the Pandoc installation."))); + await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Terminal, TB("Was not able to validate the Pandoc installation."))); + + if (shouldLog) + LOG.LogError("Pandoc --version returned an invalid format: '{Output}'.", output); - LOG.LogError("Pandoc --version returned an invalid format: {Output}", output); return new(false, TB("Was not able to validate the Pandoc installation."), false, string.Empty, preparedProcess.IsLocal); } - + var versions = versionMatch.Groups[1].Value; var installedVersion = Version.Parse(versions); var installedVersionString = installedVersion.ToString(); - + if (installedVersion >= MINIMUM_REQUIRED_VERSION) { if (showMessages && showSuccessMessage) await MessageBus.INSTANCE.SendSuccess(new(Icons.Material.Filled.CheckCircle, string.Format(TB("Pandoc v{0} is installed."), installedVersionString))); - - LOG.LogInformation("Pandoc v{0} is installed and matches the required version (v{1})", installedVersionString, MINIMUM_REQUIRED_VERSION.ToString()); + + if (shouldLog) + LOG.LogInformation("Pandoc v{0} is installed and matches the required version (v{1}).", installedVersionString, MINIMUM_REQUIRED_VERSION.ToString()); + return new(true, string.Empty, true, installedVersionString, preparedProcess.IsLocal); } - + if (showMessages) - await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Build, string.Format(TB("Pandoc v{0} is installed, but it doesn't match the required version (v{1})."), installedVersionString, MINIMUM_REQUIRED_VERSION.ToString()))); + await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Build, string.Format(TB("Pandoc v{0} is installed, but it doesn't match the required version (v{1})."), installedVersionString, MINIMUM_REQUIRED_VERSION.ToString()))); + + if (shouldLog) + LOG.LogWarning("Pandoc v{0} is installed, but it does not match the required version (v{1}).", installedVersionString, MINIMUM_REQUIRED_VERSION.ToString()); - LOG.LogWarning("Pandoc v{0} is installed, but it does not match the required version (v{1})", installedVersionString, MINIMUM_REQUIRED_VERSION.ToString()); return new(true, string.Format(TB("Pandoc v{0} is installed, but it does not match the required version (v{1})."), installedVersionString, MINIMUM_REQUIRED_VERSION.ToString()), false, installedVersionString, preparedProcess.IsLocal); } catch (Exception e) { if (showMessages) - await MessageBus.INSTANCE.SendError(new (@Icons.Material.Filled.AppsOutage, TB("It seems that Pandoc is not installed."))); + await MessageBus.INSTANCE.SendError(new(@Icons.Material.Filled.AppsOutage, TB("It seems that Pandoc is not installed."))); - LOG.LogError(e, "Pandoc availability check failed. This usually means Pandoc is not installed or not in the system PATH."); + if(shouldLog) + LOG.LogError(e, "Pandoc availability check failed. This usually means Pandoc is not installed or not in the system PATH."); + return new(false, TB("It seems that Pandoc is not installed."), false, string.Empty, false); } + finally + { + HAS_LOGGED_AVAILABILITY_CHECK_ONCE = true; + } } /// diff --git a/app/MindWork AI Studio/Tools/PandocProcessBuilder.cs b/app/MindWork AI Studio/Tools/PandocProcessBuilder.cs index 0b856486..3265351f 100644 --- a/app/MindWork AI Studio/Tools/PandocProcessBuilder.cs +++ b/app/MindWork AI Studio/Tools/PandocProcessBuilder.cs @@ -16,6 +16,9 @@ public sealed class PandocProcessBuilder private static readonly RID CPU_ARCHITECTURE = META_DATA_ARCH.Architecture.ToRID(); private static readonly ILogger LOGGER = Program.LOGGER_FACTORY.CreateLogger(nameof(PandocProcessBuilder)); + // Tracks whether the first log has been written to avoid log spam on repeated calls: + private static bool HAS_LOGGED_ONCE; + private string? providedInputFile; private string? providedOutputFile; private string? providedInputFormat; @@ -113,67 +116,94 @@ public sealed class PandocProcessBuilder private static async Task PandocExecutablePath(RustService rustService) { // - // First, we try to find the pandoc executable in the data directory. - // Any local installation should be preferred over the system-wide installation. + // Determine if we should log (only on the first call): // - var localInstallationRootDirectory = await Pandoc.GetPandocDataFolder(rustService); + var shouldLog = !HAS_LOGGED_ONCE; - // - // Check if the data directory path is valid: - // - if (string.IsNullOrWhiteSpace(localInstallationRootDirectory)) - LOGGER.LogWarning("The local data directory path is empty or null. Cannot search for local Pandoc installation."); - - else if (!Directory.Exists(localInstallationRootDirectory)) - LOGGER.LogWarning("The local Pandoc installation directory does not exist: '{LocalInstallationRootDirectory}'.", localInstallationRootDirectory); - - else + try { // - // The directory exists, search for the pandoc executable: + // First, we try to find the pandoc executable in the data directory. + // Any local installation should be preferred over the system-wide installation. // - var executableName = PandocExecutableName; - LOGGER.LogDebug("Searching for Pandoc executable '{ExecutableName}' in: '{LocalInstallationRootDirectory}'.", executableName, localInstallationRootDirectory); + var localInstallationRootDirectory = await Pandoc.GetPandocDataFolder(rustService); - try + // + // Check if the data directory path is valid: + // + if (string.IsNullOrWhiteSpace(localInstallationRootDirectory)) + { + if (shouldLog) + LOGGER.LogWarning("The local data directory path is empty or null. Cannot search for local Pandoc installation."); + } + else if (!Directory.Exists(localInstallationRootDirectory)) + { + if (shouldLog) + LOGGER.LogWarning("The local Pandoc installation directory does not exist: '{LocalInstallationRootDirectory}'.", localInstallationRootDirectory); + } + else { // - // First, check the root directory itself: + // The directory exists, search for the pandoc executable: // - var rootExecutablePath = Path.Combine(localInstallationRootDirectory, executableName); - if (File.Exists(rootExecutablePath)) - { - LOGGER.LogInformation("Found local Pandoc installation at the root path: '{Path}'.", rootExecutablePath); - return new(rootExecutablePath, true); - } + var executableName = PandocExecutableName; + if (shouldLog) + LOGGER.LogInformation("Searching for Pandoc executable '{ExecutableName}' in: '{LocalInstallationRootDirectory}'.", executableName, localInstallationRootDirectory); - // - // Then, search all subdirectories: - // - var subdirectories = Directory.GetDirectories(localInstallationRootDirectory, "*", SearchOption.AllDirectories); - foreach (var subdirectory in subdirectories) + try { - var pandocPath = Path.Combine(subdirectory, executableName); - if (File.Exists(pandocPath)) + // + // First, check the root directory itself: + // + var rootExecutablePath = Path.Combine(localInstallationRootDirectory, executableName); + if (File.Exists(rootExecutablePath)) { - LOGGER.LogInformation("Found local Pandoc installation at: '{Path}'.", pandocPath); - return new(pandocPath, true); + if (shouldLog) + LOGGER.LogInformation("Found local Pandoc installation at the root path: '{Path}'.", rootExecutablePath); + + HAS_LOGGED_ONCE = true; + return new(rootExecutablePath, true); } + + // + // Then, search all subdirectories: + // + var subdirectories = Directory.GetDirectories(localInstallationRootDirectory, "*", SearchOption.AllDirectories); + foreach (var subdirectory in subdirectories) + { + var pandocPath = Path.Combine(subdirectory, executableName); + if (File.Exists(pandocPath)) + { + if (shouldLog) + LOGGER.LogInformation("Found local Pandoc installation at: '{Path}'.", pandocPath); + + HAS_LOGGED_ONCE = true; + return new(pandocPath, true); + } + } + + if (shouldLog) + LOGGER.LogWarning("No Pandoc executable found in local installation directory or its subdirectories."); } + catch (Exception ex) + { + if (shouldLog) + LOGGER.LogWarning(ex, "Error while searching for a local Pandoc installation in: '{LocalInstallationRootDirectory}'.", localInstallationRootDirectory); + } + } - LOGGER.LogWarning("No Pandoc executable found in local installation directory or its subdirectories."); - } - catch (Exception ex) - { - LOGGER.LogWarning(ex, "Error while searching for a local Pandoc installation in: '{LocalInstallationRootDirectory}'.", localInstallationRootDirectory); - } + // + // When no local installation was found, we assume that the pandoc executable is in the system PATH: + // + if (shouldLog) + LOGGER.LogWarning("Falling back to system PATH for the Pandoc executable: '{ExecutableName}'.", PandocExecutableName); + + return new(PandocExecutableName, false); + } + finally + { + HAS_LOGGED_ONCE = true; } - - // - // When no local installation was found, we assume that the pandoc executable is in the system PATH: - // - LOGGER.LogWarning("Falling back to system PATH for the Pandoc executable: '{ExecutableName}'.", PandocExecutableName); - return new(PandocExecutableName, false); } ///