Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Flow.Launcher.Core/Plugin/PluginManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -277,13 +277,15 @@ public static async Task InitializePluginsAsync(IResultUpdateRegister register)
{
// If this plugin is already disabled, do not show error message again
// Or else it will be shown every time
PublicApi.Instance.LogDebug(ClassName, $"Skipped init for <{pair.Metadata.Name}> due to error");
if (PublicApi.Instance.GetLogLevel() == LOGLEVEL.DEBUG)
PublicApi.Instance.LogDebug(ClassName, $"Skipped init for <{pair.Metadata.Name}> due to error");
}
else
{
pair.Metadata.Disabled = true;
pair.Metadata.HomeDisabled = true;
PublicApi.Instance.LogDebug(ClassName, $"Disable plugin <{pair.Metadata.Name}> because init failed");
if (PublicApi.Instance.GetLogLevel() == LOGLEVEL.DEBUG)
PublicApi.Instance.LogDebug(ClassName, $"Disable plugin <{pair.Metadata.Name}> because init failed");
}

// Even if the plugin cannot be initialized, we still need to add it in all plugin list so that
Expand Down
3 changes: 2 additions & 1 deletion Flow.Launcher.Core/Plugin/PluginsLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ private static List<PluginPair> DotNetPlugins(List<PluginMetadata> source)
});

metadata.InitTime += milliseconds;
PublicApi.Instance.LogDebug(ClassName, $"Constructor cost for <{metadata.Name}> is <{metadata.InitTime}ms>");
if (PublicApi.Instance.GetLogLevel() == LOGLEVEL.DEBUG)
PublicApi.Instance.LogDebug(ClassName, $"Constructor cost for <{metadata.Name}> is <{metadata.InitTime}ms>");
}

if (erroredPlugins.Count > 0)
Expand Down
33 changes: 22 additions & 11 deletions Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,22 +173,22 @@
}
if (!_locationChangeHook.IsNull)
{
PInvoke.UnhookWinEvent(_locationChangeHook);

Check warning on line 176 in Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`PInvoke` is not a recognized word. (unrecognized-spelling)
_locationChangeHook = HWINEVENTHOOK.Null;
}
if (!_destroyChangeHook.IsNull)
{
PInvoke.UnhookWinEvent(_destroyChangeHook);

Check warning on line 181 in Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`PInvoke` is not a recognized word. (unrecognized-spelling)
_destroyChangeHook = HWINEVENTHOOK.Null;
}
if (!_hideChangeHook.IsNull)
{
PInvoke.UnhookWinEvent(_hideChangeHook);

Check warning on line 186 in Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`PInvoke` is not a recognized word. (unrecognized-spelling)
_hideChangeHook = HWINEVENTHOOK.Null;
}
if (!_dialogEndChangeHook.IsNull)
{
PInvoke.UnhookWinEvent(_dialogEndChangeHook);

Check warning on line 191 in Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`PInvoke` is not a recognized word. (unrecognized-spelling)
_dialogEndChangeHook = HWINEVENTHOOK.Null;
}

Expand Down Expand Up @@ -329,7 +329,7 @@
if (PublicApi.Instance.PluginModified(explorer.Metadata.ID) || // Plugin is modified
explorer.Metadata.Disabled) continue; // Plugin is disabled

var explorerWindow = explorer.Plugin.CheckExplorerWindow(hWnd);

Check warning on line 332 in Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`Wnd` is not a recognized word. (unrecognized-spelling)
if (explorerWindow != null)
{
_dialogJumpExplorers[explorer] = explorerWindow;
Expand Down Expand Up @@ -536,7 +536,8 @@
// Handle window based on its type
if (isDialogWindow)
{
Log.Debug(ClassName, $"Dialog Window: {hwnd}");
if (Log.LogLevel == LOGLEVEL.DEBUG)
Log.Debug(ClassName, $"Dialog Window: {hwnd}");
// Navigate to path
if (_settings.AutoDialogJump)
{
Expand Down Expand Up @@ -580,12 +581,14 @@
// Dialog jump window
else if (hwnd == _mainWindowHandle)
{
Log.Debug(ClassName, $"Main Window: {hwnd}");
if (Log.LogLevel == LOGLEVEL.DEBUG)
Log.Debug(ClassName, $"Main Window: {hwnd}");
}
// Other window
else
{
Log.Debug(ClassName, $"Other Window: {hwnd}");
if (Log.LogLevel == LOGLEVEL.DEBUG)
Log.Debug(ClassName, $"Other Window: {hwnd}");
var dialogWindowExist = false;
lock (_dialogWindowLock)
{
Expand Down Expand Up @@ -613,7 +616,8 @@
var explorerWindow = explorer.Plugin.CheckExplorerWindow(hwnd);
if (explorerWindow != null)
{
Log.Debug(ClassName, $"Explorer window: {hwnd}");
if (Log.LogLevel == LOGLEVEL.DEBUG)
Log.Debug(ClassName, $"Explorer window: {hwnd}");
_dialogJumpExplorers[explorer] = explorerWindow;
_lastExplorer = explorer;
break;
Expand Down Expand Up @@ -703,7 +707,8 @@
{
if (_dialogWindow != null && _dialogWindow.Handle == hwnd)
{
Log.Debug(ClassName, $"Destory dialog: {hwnd}");
if (Log.LogLevel == LOGLEVEL.DEBUG)
Log.Debug(ClassName, $"Destory dialog: {hwnd}");
_dialogWindow = null;
dialogWindowExist = true;
}
Expand Down Expand Up @@ -734,7 +739,8 @@
{
if (_dialogWindow != null && _dialogWindow.Handle == hwnd)
{
Log.Debug(ClassName, $"Hide dialog: {hwnd}");
if (Log.LogLevel == LOGLEVEL.DEBUG)
Log.Debug(ClassName, $"Hide dialog: {hwnd}");
_dialogWindow = null;
dialogWindowExist = true;
}
Expand Down Expand Up @@ -765,7 +771,8 @@
{
if (_dialogWindow != null && _dialogWindow.Handle == hwnd)
{
Log.Debug(ClassName, $"End dialog: {hwnd}");
if (Log.LogLevel == LOGLEVEL.DEBUG)
Log.Debug(ClassName, $"End dialog: {hwnd}");
_dialogWindow = null;
dialogWindowExist = true;
}
Expand Down Expand Up @@ -955,15 +962,18 @@
switch (_settings.DialogJumpFileResultBehaviour)
{
case DialogJumpFileResultBehaviours.FullPath:
Log.Debug(ClassName, $"File Jump FullPath: {path}");
if (Log.LogLevel == LOGLEVEL.DEBUG)
Log.Debug(ClassName, $"File Jump FullPath: {path}");
result = FileJump(path, dialog);
break;
case DialogJumpFileResultBehaviours.FullPathOpen:
Log.Debug(ClassName, $"File Jump FullPathOpen: {path}");
if (Log.LogLevel == LOGLEVEL.DEBUG)
Log.Debug(ClassName, $"File Jump FullPathOpen: {path}");
result = FileJump(path, dialog, openFile: true);
break;
case DialogJumpFileResultBehaviours.Directory:
Log.Debug(ClassName, $"File Jump Directory (Auto: {auto}): {path}");
if (Log.LogLevel == LOGLEVEL.DEBUG)
Log.Debug(ClassName, $"File Jump Directory (Auto: {auto}): {path}");
result = DirJump(Path.GetDirectoryName(path), dialog, auto);
break;
default:
Expand All @@ -972,7 +982,8 @@
}
else
{
Log.Debug(ClassName, $"Dir Jump: {path}");
if (Log.LogLevel == LOGLEVEL.DEBUG)
Log.Debug(ClassName, $"Dir Jump: {path}");
result = DirJump(path, dialog, auto);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Threading;
using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Plugin;
Expand Down Expand Up @@ -60,7 +60,7 @@

// Is it a Windows Save or Save As file dialog?
fileEditor = PInvoke.GetDlgItem(handle, 0x0000);
if (fileEditor != HWND.Null && GetClassName(fileEditor) == "DUIViewWndClassName") return DialogType.SaveOrSaveAs;

Check warning on line 63 in Flow.Launcher.Infrastructure/DialogJump/Models/WindowsDialog.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`Wnd` is not a recognized word. (unrecognized-spelling)

return DialogType.Others;
}
Expand Down Expand Up @@ -125,7 +125,8 @@
{
Handle = handle;
_dialogType = dialogType;
Log.Debug(ClassName, $"File dialog type: {dialogType}");
if (Log.LogLevel == LOGLEVEL.DEBUG)
Log.Debug(ClassName, $"File dialog type: {dialogType}");
}

#endregion
Expand Down Expand Up @@ -259,7 +260,7 @@
else
{
// Get the handle of the file name editor of Save / SaveAs file dialog
_fileEditor = PInvoke.GetDlgItem(new(Handle), 0x0000); // DUIViewWndClassName

Check warning on line 263 in Flow.Launcher.Infrastructure/DialogJump/Models/WindowsDialog.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`Wnd` is not a recognized word. (unrecognized-spelling)
_fileEditor = PInvoke.GetDlgItem(_fileEditor, 0x0000); // DirectUIHWND
_fileEditor = PInvoke.GetDlgItem(_fileEditor, 0x0000); // FloatNotifySink
_fileEditor = PInvoke.GetDlgItem(_fileEditor, 0x0000); // ComboBox
Expand Down
18 changes: 12 additions & 6 deletions Flow.Launcher.Infrastructure/Http/Http.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Threading.Tasks;
using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
using JetBrains.Annotations;

namespace Flow.Launcher.Infrastructure.Http
Expand All @@ -21,8 +22,8 @@
static Http()
{
// need to be added so it would work on a win10 machine
ServicePointManager.Expect100Continue = true;

Check warning on line 25 in Flow.Launcher.Infrastructure/Http/Http.cs

View workflow job for this annotation

GitHub Actions / build

'ServicePointManager' is obsolete: 'WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead. Settings on ServicePointManager no longer affect SslStream or HttpClient.' (https://aka.ms/dotnet-warnings/SYSLIB0014)
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls

Check warning on line 26 in Flow.Launcher.Infrastructure/Http/Http.cs

View workflow job for this annotation

GitHub Actions / build

'ServicePointManager' is obsolete: 'WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead. Settings on ServicePointManager no longer affect SslStream or HttpClient.' (https://aka.ms/dotnet-warnings/SYSLIB0014)
| SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

client.DefaultRequestHeaders.Add("User-Agent", UserAgent);
Expand Down Expand Up @@ -146,7 +147,8 @@
/// <returns>The Http result as string. Null if cancellation requested</returns>
public static Task<string> GetAsync([NotNull] string url, CancellationToken token = default)
{
Log.Debug(ClassName, $"Url <{url}>");
if (Log.LogLevel == LOGLEVEL.DEBUG)
Log.Debug(ClassName, $"Url <{url}>");
return GetAsync(new Uri(url), token);
}

Expand All @@ -158,7 +160,8 @@
/// <returns>The Http result as string. Null if cancellation requested</returns>
public static async Task<string> GetAsync([NotNull] Uri url, CancellationToken token = default)
{
Log.Debug(ClassName, $"Url <{url}>");
if (Log.LogLevel == LOGLEVEL.DEBUG)
Copy link
Member

Choose a reason for hiding this comment

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

I think instead of putting these if statements all over, should just embed it in the Log.Debug call, so when debug is only logged if the current level is debug.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think instead of putting these if statements all over, should just embed it in the Log.Debug call, so when debug is only logged if the current level is debug.

Since we add new API function GetLogLevel, I think we should also keep the same style in other places.

Copy link
Member

Choose a reason for hiding this comment

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

What I mean is it's unnecessary to require check log level before logging debug, it is explicit enough that when log debug, it will only log when the log level is set to it. Shouldn't have the need to check log level first, otherwise it might as well just be any output method with a check log level to only output if log is debug.

Copy link
Member

Choose a reason for hiding this comment

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

This looks like already the case as we are passing the log level to the logger, so the log level check is redundant. Can you test please:

private static void LogInternal(LogLevel level, string className, string message, [CallerMemberName] string methodName = "")
{
var classNameWithMethod = CheckClassAndMessageAndReturnFullClassWithMethod(className, message, methodName);
var logger = LogManager.GetLogger(classNameWithMethod);
logger.Log(level, message);
}

Copy link
Member Author

Choose a reason for hiding this comment

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

This looks like already the case as we are passing the log level to the logger, so the log level check is redundant. Can you test please:

private static void LogInternal(LogLevel level, string className, string message, [CallerMemberName] string methodName = "")
{
var classNameWithMethod = CheckClassAndMessageAndReturnFullClassWithMethod(className, message, methodName);
var logger = LogManager.GetLogger(classNameWithMethod);
logger.Log(level, message);
}

Understood. We can check the log level in Debug function but I think that is not enough.

Take App.API.LogDebug(ClassName, $"Start query with ActionKeyword <{query.ActionKeyword}> and TrimmedQuery <{query.TrimmedQuery}>"); for example, if we check log level in Debug function, the strings of $"Start query with ActionKeyword <{query.ActionKeyword}> and TrimmedQuery <{query.TrimmedQuery}>" is constructed which can consume plenty of memory since this strings is different during each time. So I think we should check the log level before calling LogDebug function

Copy link
Member

@jjw24 jjw24 Dec 3, 2025

Choose a reason for hiding this comment

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

Yes we can have the check for those two plus this one App.API.LogDebug(ClassName, $"Valid <{plugins.Count}> plugins: {string.Join(" ", plugins.Select(x => $"<{x.Metadata.Name}>"))}");, the others are simple string constructions.

Log.Debug(ClassName, $"Url <{url}>");
using var response = await client.GetAsync(url, token);
var content = await response.Content.ReadAsStringAsync(token);
if (response.StatusCode != HttpStatusCode.OK)
Expand Down Expand Up @@ -189,7 +192,8 @@
public static async Task<Stream> GetStreamAsync([NotNull] Uri url,
CancellationToken token = default)
{
Log.Debug(ClassName, $"Url <{url}>");
if (Log.LogLevel == LOGLEVEL.DEBUG)
Log.Debug(ClassName, $"Url <{url}>");
return await client.GetStreamAsync(url, token);
}

Expand All @@ -200,12 +204,13 @@
public static async Task<HttpResponseMessage> GetResponseAsync([NotNull] Uri url, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
CancellationToken token = default)
{
Log.Debug(ClassName, $"Url <{url}>");
if (Log.LogLevel == LOGLEVEL.DEBUG)
Log.Debug(ClassName, $"Url <{url}>");
return await client.GetAsync(url, completionOption, token);
}

/// <summary>
/// Asynchrously send an HTTP request.

Check warning on line 213 in Flow.Launcher.Infrastructure/Http/Http.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`Asynchrously` is not a recognized word. (unrecognized-spelling)
/// </summary>
public static async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead, CancellationToken token = default)
{
Expand All @@ -223,10 +228,11 @@
{
try
{
Log.Debug(ClassName, $"Url <{url}>");
if (Log.LogLevel == LOGLEVEL.DEBUG)
Log.Debug(ClassName, $"Url <{url}>");
return await client.GetStringAsync(url, token);
}
catch (System.Exception e)
catch
{
return string.Empty;
}
Expand Down
38 changes: 18 additions & 20 deletions Flow.Launcher.Infrastructure/Logger/Log.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
using NLog;
using NLog.Config;
using NLog.Targets;
Expand All @@ -15,6 +16,8 @@ public static class Log
public const string DirectoryName = Constant.Logs;

public static string CurrentLogDirectory { get; }

public static LOGLEVEL LogLevel { get; private set; } = LOGLEVEL.DEBUG;

static Log()
{
Expand Down Expand Up @@ -48,12 +51,12 @@ static Log()
configuration.AddTarget("file", fileTargetASyncWrapper);
configuration.AddTarget("debug", debugTarget);

var fileRule = new LoggingRule("*", LogLevel.Debug, fileTargetASyncWrapper)
var fileRule = new LoggingRule("*", NLog.LogLevel.Debug, fileTargetASyncWrapper)
{
RuleName = "file"
};
#if DEBUG
var debugRule = new LoggingRule("*", LogLevel.Debug, debugTarget)
var debugRule = new LoggingRule("*", NLog.LogLevel.Debug, debugTarget)
{
RuleName = "debug"
};
Expand All @@ -65,22 +68,25 @@ static Log()

public static void SetLogLevel(LOGLEVEL level)
{
LogLevel = level;

var rule = LogManager.Configuration.FindRuleByName("file");

var nlogLevel = level switch
{
LOGLEVEL.NONE => LogLevel.Off,
LOGLEVEL.ERROR => LogLevel.Error,
LOGLEVEL.DEBUG => LogLevel.Debug,
_ => LogLevel.Info
LOGLEVEL.NONE => NLog.LogLevel.Off,
LOGLEVEL.ERROR => NLog.LogLevel.Error,
LOGLEVEL.DEBUG => NLog.LogLevel.Debug,
_ => NLog.LogLevel.Info
};

rule.SetLoggingLevels(nlogLevel, LogLevel.Fatal);
rule.SetLoggingLevels(nlogLevel, NLog.LogLevel.Fatal);

LogManager.ReconfigExistingLoggers();

// We can't log Info when level is set to Error or None, so we use Debug
Debug(nameof(Logger), $"Using log level: {level}.");
if (LogLevel == LOGLEVEL.DEBUG)
Debug(nameof(Logger), $"Using log level: {level}.");
}

private static void LogFaultyFormat(string message)
Expand Down Expand Up @@ -135,7 +141,7 @@ private static void ExceptionInternal(string classAndMethod, string message, Sys

public static void Error(string className, string message, [CallerMemberName] string methodName = "")
{
LogInternal(LogLevel.Error, className, message, methodName);
LogInternal(NLog.LogLevel.Error, className, message, methodName);
}

private static void LogInternal(LogLevel level, string className, string message, [CallerMemberName] string methodName = "")
Expand All @@ -149,25 +155,17 @@ private static void LogInternal(LogLevel level, string className, string message

public static void Debug(string className, string message, [CallerMemberName] string methodName = "")
{
LogInternal(LogLevel.Debug, className, message, methodName);
LogInternal(NLog.LogLevel.Debug, className, message, methodName);
}

public static void Info(string className, string message, [CallerMemberName] string methodName = "")
{
LogInternal(LogLevel.Info, className, message, methodName);
LogInternal(NLog.LogLevel.Info, className, message, methodName);
}

public static void Warn(string className, string message, [CallerMemberName] string methodName = "")
{
LogInternal(LogLevel.Warn, className, message, methodName);
LogInternal(NLog.LogLevel.Warn, className, message, methodName);
}
}

public enum LOGLEVEL
{
NONE,
ERROR,
INFO,
DEBUG
}
}
7 changes: 5 additions & 2 deletions Flow.Launcher.Infrastructure/Stopwatch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Plugin;

namespace Flow.Launcher.Infrastructure
{
Expand All @@ -17,7 +18,8 @@ public static long Debug(string className, string message, Action action, [Calle
action();
stopWatch.Stop();
var milliseconds = stopWatch.ElapsedMilliseconds;
Log.Debug(className, $"{message} <{milliseconds}ms>", methodName);
if (Log.LogLevel == LOGLEVEL.DEBUG)
Log.Debug(className, $"{message} <{milliseconds}ms>", methodName);
return milliseconds;
}

Expand All @@ -31,7 +33,8 @@ public static async Task<long> DebugAsync(string className, string message, Func
await action();
stopWatch.Stop();
var milliseconds = stopWatch.ElapsedMilliseconds;
Log.Debug(className, $"{message} <{milliseconds}ms>", methodName);
if (Log.LogLevel == LOGLEVEL.DEBUG)
Log.Debug(className, $"{message} <{milliseconds}ms>", methodName);
return milliseconds;
}

Expand Down
6 changes: 6 additions & 0 deletions Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -637,5 +637,11 @@ public interface IPublicAPI
/// </summary>
/// <returns></returns>
string GetLogDirectory();

/// <summary>
/// Get the current log level of Flow Launcher.
/// </summary>
/// <returns></returns>
LOGLEVEL GetLogLevel();
}
}
27 changes: 27 additions & 0 deletions Flow.Launcher.Plugin/LogLevel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace Flow.Launcher.Plugin;

/// <summary>
/// Log level enum used in Flow
/// </summary>
public enum LOGLEVEL
{
/// <summary>
/// No log will be produced
/// </summary>
NONE,

/// <summary>
/// Only error log will be produced
/// </summary>
ERROR,

/// <summary>
/// Info and error log will be produced
/// </summary>
INFO,

/// <summary>
/// Debug, info and error log will be produced
/// </summary>
DEBUG
}
6 changes: 4 additions & 2 deletions Flow.Launcher/PublicAPIInstance.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Specialized;
Expand Down Expand Up @@ -52,7 +52,7 @@ public class PublicAPIInstance : IPublicAPI, IRemovable
private Updater _updater;
private Updater Updater => _updater ??= Ioc.Default.GetRequiredService<Updater>();

private readonly object _saveSettingsLock = new();
private readonly Lock _saveSettingsLock = new();

#region Constructor

Expand Down Expand Up @@ -623,6 +623,8 @@ public event ActualApplicationThemeChangedEventHandler ActualApplicationThemeCha

public string GetLogDirectory() => DataLocation.VersionLogDirectory;

public LOGLEVEL GetLogLevel() => Log.LogLevel;

#endregion

#region Private Methods
Expand Down
Loading
Loading