2
0
mirror of https://github.com/9ParsonsB/Pulsar.git synced 2025-07-01 08:23:42 -04:00

Add event-based LogMonitor state changes to better handle batch reads (#59)

* Add event-based LogMonitor state changes to better handle batch reads

Pre-reading hackily used read-all to suppress notifications. But that broke some assumptions about what read-all meant. Furthermore, the Core UI told plugins about read-all rather than the log monitor telling them -- which is really what should be telling them.

To address these concerns, LogMonitor now provides an event that both the PluginCore and PluginEventHandler listens to or tracking logging state allowing more granular information about the activities of LogMonitor, including distinguishing between ReadAll and Pre-read batches. Plugins no longer need to track if LogMonitor is in batch-read mode or not -- PluginCore now provides it. 

I've also converted all built-in plugins to use the new event-based system. The old system is marked deprecated and will go away once other known contributed plugins have converted to the new system.

* Change LogMonitorState enum to [Flags], drop 'None' state

As requested, and did associated simplifications and cleanup that followed.
This commit is contained in:
F K
2022-03-03 15:09:49 -05:00
committed by GitHub
parent 7c54d6dd65
commit 4f4ba88878
9 changed files with 150 additions and 43 deletions

View File

@ -4,7 +4,6 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text.Json.Serialization;
using Observatory.Framework;
using Observatory.Framework.Files;
@ -34,6 +33,7 @@ namespace Observatory
currentLine = new();
journalTypes = JournalReader.PopulateEventClasses();
InitializeWatchers(string.Empty);
SetLogMonitorState(LogMonitorState.Idle);
}
#endregion
@ -50,7 +50,7 @@ namespace Observatory
}
journalWatcher.EnableRaisingEvents = true;
statusWatcher.EnableRaisingEvents = true;
monitoring = true;
SetLogMonitorState(LogMonitorState.Realtime);
JournalPoke();
}
@ -58,7 +58,7 @@ namespace Observatory
{
journalWatcher.EnableRaisingEvents = false;
statusWatcher.EnableRaisingEvents = false;
monitoring = false;
SetLogMonitorState(LogMonitorState.Idle);
}
public void ChangeWatchedDirectory(string path)
@ -70,12 +70,13 @@ namespace Observatory
public bool IsMonitoring()
{
return monitoring;
return (currentState & LogMonitorState.Realtime) == LogMonitorState.Realtime;
}
// TODO(fredjk_gh): Remove?
public bool ReadAllInProgress()
{
return readall;
return LogMonitorStateChangedEventArgs.IsBatchRead(currentState);
}
public void ReadAllJournals()
@ -87,7 +88,8 @@ namespace Observatory
{
// Prevent pre-reading when starting monitoring after reading all.
firstStartMonitor = false;
readall = true;
SetLogMonitorState(currentState | LogMonitorState.Batch);
DirectoryInfo logDirectory = GetJournalFolder(path);
var files = logDirectory.GetFiles("Journal.????????????.??.log");
var readErrors = new List<(Exception ex, string file, string line)>();
@ -98,13 +100,15 @@ namespace Observatory
}
ReportErrors(readErrors);
readall = false;
SetLogMonitorState(currentState & ~LogMonitorState.Batch);
}
public void PrereadJournals()
{
if (!Properties.Core.Default.TryPrimeSystemContextOnStartMonitor) return;
SetLogMonitorState(currentState | LogMonitorState.PreRead);
DirectoryInfo logDirectory = GetJournalFolder(Properties.Core.Default.JournalFolder);
var files = logDirectory.GetFiles("Journal.????????????.??.log");
@ -156,15 +160,16 @@ namespace Observatory
linesToRead = lastSystemLines;
}
readall = true;
ReportErrors(ProcessLines(linesToRead, "Pre-read"));
readall = false;
SetLogMonitorState(currentState & ~LogMonitorState.PreRead);
}
#endregion
#region Public Events
public event EventHandler<LogMonitorStateChangedEventArgs> LogMonitorStateChanged;
public event EventHandler<JournalEventArgs> JournalEntry;
public event EventHandler<JournalEventArgs> StatusUpdate;
@ -177,14 +182,27 @@ namespace Observatory
private FileSystemWatcher statusWatcher;
private Dictionary<string, Type> journalTypes;
private Dictionary<string, int> currentLine;
private LogMonitorState currentState = LogMonitorState.Idle; // Change via #SetLogMonitorState
private bool monitoring = false;
private bool readall = false;
private bool firstStartMonitor = true;
#endregion
#region Private Methods
private void SetLogMonitorState(LogMonitorState newState)
{
var oldState = currentState;
currentState = newState;
LogMonitorStateChanged?.Invoke(this, new LogMonitorStateChangedEventArgs
{
PreviousState = oldState,
NewState = newState
});;
System.Diagnostics.Debug.WriteLine("LogMonitor State change: {0} -> {1}", oldState, newState);
}
private void InitializeWatchers(string path)
{
DirectoryInfo logDirectory = GetJournalFolder(path);

View File

@ -11,6 +11,7 @@ namespace Observatory.PluginManagement
private readonly NativeVoice NativeVoice;
private readonly NativePopup NativePopup;
private LogMonitorState currentLogMonitorState = LogMonitorState.Idle;
public PluginCore()
{
@ -18,6 +19,11 @@ namespace Observatory.PluginManagement
NativePopup = new();
}
internal void OnLogMonitorStateChanged(object sender, LogMonitorStateChangedEventArgs e)
{
currentLogMonitorState = e.NewState;
}
public string Version => System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString();
public Status GetStatus()
@ -34,7 +40,7 @@ namespace Observatory.PluginManagement
{
var guid = Guid.Empty;
if (!LogMonitor.GetInstance.ReadAllInProgress())
if (!IsLogMonitorBatchReading)
{
if (notificationArgs.Rendering.HasFlag(NotificationRendering.PluginNotifier))
{
@ -63,7 +69,7 @@ namespace Observatory.PluginManagement
public void UpdateNotification(Guid id, NotificationArgs notificationArgs)
{
if (!LogMonitor.GetInstance.ReadAllInProgress())
if (!IsLogMonitorBatchReading)
{
if (notificationArgs.Rendering.HasFlag(NotificationRendering.PluginNotifier))
@ -134,6 +140,16 @@ namespace Observatory.PluginManagement
get => Observatory.HttpClient.Client;
}
public LogMonitorState CurrentLogMonitorState
{
get => currentLogMonitorState;
}
public bool IsLogMonitorBatchReading
{
get => LogMonitorStateChangedEventArgs.IsBatchRead(currentLogMonitorState);
}
public event EventHandler<NotificationArgs> Notification;
}
}

View File

@ -61,6 +61,21 @@ namespace Observatory.PluginManagement
}
}
internal void OnLogMonitorStateChanged(object sender, LogMonitorStateChangedEventArgs e)
{
foreach (var worker in observatoryWorkers)
{
try
{
worker.LogMonitorStateChanged(e);
}
catch (Exception ex)
{
RecordError(ex, worker.Name, "LogMonitorStateChanged event");
}
}
}
public void OnNotificationEvent(object source, NotificationArgs notificationArgs)
{
foreach (var notifier in observatoryNotifiers)

View File

@ -46,8 +46,10 @@ namespace Observatory.PluginManagement
logMonitor.JournalEntry += pluginHandler.OnJournalEvent;
logMonitor.StatusUpdate += pluginHandler.OnStatusUpdate;
logMonitor.LogMonitorStateChanged += pluginHandler.OnLogMonitorStateChanged;
var core = new PluginCore();
logMonitor.LogMonitorStateChanged += core.OnLogMonitorStateChanged;
List<IObservatoryPlugin> errorPlugins = new();

View File

@ -65,8 +65,10 @@ namespace Observatory.UI.ViewModels
public void ReadAll()
{
// TODO(fredjk_gh): remove.
SetWorkerReadAllState(true);
LogMonitor.GetInstance.ReadAllJournals();
// TODO(fredjk_gh): remove.
SetWorkerReadAllState(false);
}
@ -82,8 +84,10 @@ namespace Observatory.UI.ViewModels
else
{
// HACK: Find a better way of suppressing notifications when pre-reading.
// TODO(fredjk_gh): remove.
SetWorkerReadAllState(true);
logMonitor.Start();
// TODO(fredjk_gh): remove.
SetWorkerReadAllState(false);
ToggleButtonText = "Stop Monitor";
}
@ -138,6 +142,7 @@ namespace Observatory.UI.ViewModels
get { return tabs; }
}
// TODO(fredjk_gh): remove.
private void SetWorkerReadAllState(bool isReadingAll)
{
foreach (var worker in workers)