Improve logging: Make sure it's easy to notice when the software starts and stops and which software instance is doing so.
MODIFY
WalletWasabi.Backend/Program.cs
WalletWasabi.Backend/Program.cs
@@ -27,6 +27,8 @@ namespace WalletWasabi.Backend
try
{
Logger.InitializeDefaults(Path.Combine(Global.DataDir, "Logs.txt"));
+ Logger.LogStarting("Wasabi Backend");
+
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
var configFilePath = Path.Combine(Global.DataDir, "Config.json");
@@ -105,6 +107,7 @@ namespace WalletWasabi.Backend
{
Logger.LogCritical<Program>(ex);
}
+ // Note: Don't do finally here. Dispose in Startup.cs.
}
private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)

MODIFY
WalletWasabi.Backend/Startup.cs
WalletWasabi.Backend/Startup.cs
@@ -108,6 +108,8 @@ namespace WalletWasabi.Backend
Global.DisconnectDisposeNullLocalNode();
Logger.LogInfo<Startup>("LocalNode is disposed.");
}
+
+ Logger.LogInfo($"Wasabi Backend stopped gracefully.", Logger.InstanceGuid.ToString());
}
}
}

MODIFY
WalletWasabi.Gui/CommandLine/Daemon.cs
WalletWasabi.Gui/CommandLine/Daemon.cs
@@ -108,6 +108,7 @@ namespace WalletWasabi.Gui.CommandLine
Logger.Modes.Add(LogMode.Console);
Logger.Modes.Add(LogMode.Debug);
}
+ Logger.LogStarting("Wasabi");
KeyManager keyManager = null;
if (walletName != null)

MODIFY
WalletWasabi.Gui/Program.cs
WalletWasabi.Gui/Program.cs
@@ -64,6 +64,8 @@ namespace WalletWasabi.Gui
await Global.DisposeAsync();
AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException;
TaskScheduler.UnobservedTaskException -= TaskScheduler_UnobservedTaskException;
+
+ Logger.LogInfo($"Wasabi stopped gracefully.", Logger.InstanceGuid.ToString());
}
}

MODIFY
WalletWasabi/Logging/Logger.cs
WalletWasabi/Logging/Logger.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
+using System.Text;
namespace WalletWasabi.Logging
{
@@ -24,6 +25,12 @@ namespace WalletWasabi.Logging
public static string FileEntryEncryptionPassword { get; private set; } = null;
+ /// <summary>
+ /// You can use it to identify which software instance created a log entry.
+ /// It gets created automatically, but you have to use it manually.
+ /// </summary>
+ public static Guid InstanceGuid { get; } = Guid.NewGuid();
+
private static int _loggingFailedCount = 0;
private static readonly object Lock = new object();
@@ -112,7 +119,7 @@ namespace WalletWasabi.Logging
#region GeneralLoggingMethods
- private static void Log(LogLevel level, string message, string category)
+ private static void Log(LogLevel level, string message, string category, int newLinesBefore = 0, bool insertNewLinesLogFileOnlyMode = true)
{
try
{
@@ -129,22 +136,36 @@ namespace WalletWasabi.Logging
message = string.IsNullOrWhiteSpace(message) ? "" : message;
category = string.IsNullOrWhiteSpace(category) ? "" : category;
- var finalLogMessage = "";
+ var messageBuilder = new StringBuilder();
+
if (message != "" && category != "") // If none of them empty.
{
- finalLogMessage = $"{DateTime.UtcNow.ToLocalTime():yyyy-MM-dd HH:mm:ss} {level.ToString().ToUpperInvariant()} {category}: {message}{EntrySeparator}";
+ messageBuilder.Append($"{DateTime.UtcNow.ToLocalTime():yyyy-MM-dd HH:mm:ss} {level.ToString().ToUpperInvariant()} {category}: {message}{EntrySeparator}");
}
else if (message == "" && category != "") // If only the message is empty.
{
- finalLogMessage = $"{DateTime.UtcNow.ToLocalTime():yyyy-MM-dd HH:mm:ss} {level.ToString().ToUpperInvariant()} {category}{EntrySeparator}";
+ messageBuilder.Append($"{DateTime.UtcNow.ToLocalTime():yyyy-MM-dd HH:mm:ss} {level.ToString().ToUpperInvariant()} {category}{EntrySeparator}");
}
else if (message != "" && category == "") // If only the category is empty.
{
- finalLogMessage = $"{DateTime.UtcNow.ToLocalTime():yyyy-MM-dd HH:mm:ss} {level.ToString().ToUpperInvariant()}: {message}{EntrySeparator}";
+ messageBuilder.Append($"{DateTime.UtcNow.ToLocalTime():yyyy-MM-dd HH:mm:ss} {level.ToString().ToUpperInvariant()}: {message}{EntrySeparator}");
}
else // if (message == "" && category == "") // If both empty. It probably never happens though.
{
- finalLogMessage = $"{DateTime.UtcNow.ToLocalTime():yyyy-MM-dd HH:mm:ss} {level.ToString().ToUpperInvariant()}{EntrySeparator}";
+ messageBuilder.Append($"{DateTime.UtcNow.ToLocalTime():yyyy-MM-dd HH:mm:ss} {level.ToString().ToUpperInvariant()}{EntrySeparator}");
+ }
+
+ var finalMessage = messageBuilder.ToString();
+
+ for (int i = 0; i < newLinesBefore; i++)
+ {
+ messageBuilder.Insert(0, Environment.NewLine);
+ }
+
+ var finalFileMessage = messageBuilder.ToString();
+ if (!insertNewLinesLogFileOnlyMode)
+ {
+ finalMessage = finalFileMessage;
}
lock (Lock)
@@ -169,14 +190,14 @@ namespace WalletWasabi.Logging
}
Console.ForegroundColor = color;
- Console.Write(finalLogMessage);
+ Console.Write(finalMessage);
Console.ResetColor();
}
}
if (Modes.Contains(LogMode.Console))
{
- Debug.Write(finalLogMessage);
+ Debug.Write(finalMessage);
}
if (!Modes.Contains(LogMode.File)) return;
@@ -195,14 +216,14 @@ namespace WalletWasabi.Logging
if (FileEntryEncryptionPassword != null)
{
// take the separator down and add a comma (not base64)
- var replacedSeparatorWithCommaMessage = finalLogMessage.Substring(0, finalLogMessage.Length - EntrySeparator.Length);
+ var replacedSeparatorWithCommaMessage = finalFileMessage.Substring(0, finalFileMessage.Length - EntrySeparator.Length);
var encryptedLogMessage = StringCipher.Encrypt(replacedSeparatorWithCommaMessage, FileEntryEncryptionPassword) + ',';
File.AppendAllText(FilePath, encryptedLogMessage);
}
else
{
- File.AppendAllText(FilePath, finalLogMessage);
+ File.AppendAllText(FilePath, finalFileMessage);
}
}
}
@@ -364,6 +385,12 @@ namespace WalletWasabi.Logging
#region InfoLoggingMethods
+ /// <summary>
+ /// Logs software start with category InstanceGuid and insert three newlines.
+ /// </summary>
+ /// <param name="appName">The name of the app.</param>
+ public static void LogStarting(string appName) => Log(LogLevel.Info, $"{appName} is starting...", category: InstanceGuid.ToString(), newLinesBefore: 3, insertNewLinesLogFileOnlyMode: true);
+
/// <summary>
/// For tracking the general flow of the application.
/// These logs typically have some long-term value.

Improve logging: Make sure it's easy to notice when the software starts and stops and which software instance is doing so.