insight/src/Agent/Insight.Agent/Services/EventService.cs

170 lines
6 KiB
C#
Raw Normal View History

2023-09-21 22:10:55 +02:00
using Insight.Agent.Network;
2023-11-17 17:12:41 +01:00
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
2023-09-21 18:58:32 +02:00
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Diagnostics.Eventing.Reader;
using System.Runtime.Versioning;
using System.Threading.Channels;
using Vaitr.Network;
2023-11-17 17:12:41 +01:00
using static Insight.Domain.Network.Agent.Messages.Event;
2023-09-21 18:58:32 +02:00
using EventLevel = System.Diagnostics.Tracing.EventLevel;
2023-09-21 22:10:55 +02:00
namespace Insight.Agent.Services;
[SupportedOSPlatform("windows")]
internal class EventService : BackgroundService
2023-09-21 18:58:32 +02:00
{
2023-09-21 22:10:55 +02:00
private readonly Channel<Event> _queue;
private readonly ISessionPool<AgentSession, IMessage> _pool;
private readonly ILogger<EventService> _logger;
public EventService(ISessionPool<AgentSession, IMessage> pool, ILogger<EventService> logger)
2023-09-21 18:58:32 +02:00
{
2023-09-21 22:10:55 +02:00
_pool = pool;
_logger = logger;
2023-09-21 18:58:32 +02:00
2023-09-21 22:10:55 +02:00
_queue = Channel.CreateBounded<Event>(new BoundedChannelOptions(1000)
2023-09-21 18:58:32 +02:00
{
2023-09-21 22:10:55 +02:00
SingleReader = true,
SingleWriter = true,
AllowSynchronousContinuations = false,
FullMode = BoundedChannelFullMode.DropOldest
});
}
2023-09-21 18:58:32 +02:00
2023-09-21 22:10:55 +02:00
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
_logger.LogTrace("ExecuteAsync");
2023-09-21 18:58:32 +02:00
2023-09-21 22:10:55 +02:00
while (cancellationToken.IsCancellationRequested is false)
2023-09-21 18:58:32 +02:00
{
2023-09-21 22:10:55 +02:00
try
2023-09-21 18:58:32 +02:00
{
2023-09-21 22:10:55 +02:00
var tasks = new List<Task>
2023-09-21 18:58:32 +02:00
{
2023-09-21 22:10:55 +02:00
HandleQueueAsync(cancellationToken),
WatchAsync("Application", "*", cancellationToken),
WatchAsync("Security", "*", cancellationToken),
WatchAsync("System", "*", cancellationToken),
WatchAsync("Microsoft-Windows-PrintService/Admin", "*", cancellationToken),
WatchAsync("Microsoft-Windows-TaskScheduler/Operational", "*", cancellationToken),
WatchAsync("Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational", "*", cancellationToken),
WatchAsync("Microsoft-Windows-TerminalServices-LocalSessionManager/Operational", "*", cancellationToken),
WatchAsync("Microsoft-Windows-TerminalServices-RDPClient/Operational", "*", cancellationToken),
WatchAsync("Microsoft-Windows-SmbClient/Connectivity", "*", cancellationToken),
WatchAsync("Microsoft-Windows-SmbClient/Security", "*", cancellationToken),
WatchAsync("Microsoft-Windows-SMBServer/Security", "*", cancellationToken),
WatchAsync("Microsoft-Windows-StorageSpaces-Driver/Operational", "*", cancellationToken),
WatchAsync("Microsoft-Windows-Diagnostics-Performance/Operational", "*", cancellationToken)
};
await Task.WhenAll(tasks);
}
catch (OperationCanceledException) { }
catch (Exception ex)
{
_logger.LogError("{ex}", ex);
2023-09-21 18:58:32 +02:00
}
}
2023-09-21 22:10:55 +02:00
}
private async Task WatchAsync(string path, string query, CancellationToken cancellationToken)
{
var config = new EventLogConfiguration(path);
if (config is null) return;
if (config.IsEnabled is false)
{
config.IsEnabled = true;
config.SaveChanges();
}
var watcher = new EventLogWatcher(new EventLogQuery(path, PathType.LogName, query)
{
TolerateQueryErrors = true,
Session = EventLogSession.GlobalSession
});
try
{
watcher.EventRecordWritten += new EventHandler<EventRecordWrittenEventArgs>(OnEvent);
watcher.Enabled = true;
using var semaphore = new SemaphoreSlim(0, 1);
await semaphore.WaitAsync(cancellationToken);
}
catch (Exception) { }
finally
{
watcher.EventRecordWritten -= new EventHandler<EventRecordWrittenEventArgs>(OnEvent);
watcher.Enabled = false;
watcher?.Dispose();
}
}
2023-09-21 18:58:32 +02:00
2023-09-21 22:10:55 +02:00
private async Task HandleQueueAsync(CancellationToken cancellationToken)
{
while (await _queue.Reader.WaitToReadAsync(cancellationToken))
2023-09-21 18:58:32 +02:00
{
2023-09-21 22:10:55 +02:00
var session = _pool.FirstOrDefault();
2023-09-21 18:58:32 +02:00
2023-09-21 22:10:55 +02:00
if (session.Value is null)
2023-09-21 18:58:32 +02:00
{
2023-09-21 22:10:55 +02:00
await Task.Delay(10000, cancellationToken);
continue;
2023-09-21 18:58:32 +02:00
}
2023-09-21 22:10:55 +02:00
if (_queue.Reader.TryRead(out var item) is false)
2023-09-21 18:58:32 +02:00
{
2023-09-21 22:10:55 +02:00
await Task.Delay(1000, cancellationToken);
continue;
}
2023-09-21 18:58:32 +02:00
try
{
2023-09-21 22:10:55 +02:00
await session.Value.SendAsync(item, cancellationToken);
2023-09-21 18:58:32 +02:00
}
2023-09-21 22:10:55 +02:00
catch (OperationCanceledException) { }
catch (Exception ex)
2023-09-21 18:58:32 +02:00
{
2023-09-21 22:10:55 +02:00
_logger.LogError("{ex}", ex);
await Task.Delay(10000, cancellationToken);
2023-09-21 18:58:32 +02:00
}
}
2023-09-21 22:10:55 +02:00
}
2023-09-21 18:58:32 +02:00
2023-09-21 22:10:55 +02:00
private void OnEvent(object? sender, EventRecordWrittenEventArgs e)
{
if (e is null || e.EventRecord is null) return;
2023-09-21 18:58:32 +02:00
2023-09-21 22:10:55 +02:00
try
2023-09-21 18:58:32 +02:00
{
2023-09-21 22:10:55 +02:00
var @event = new Event
{
Timestamp = e?.EventRecord?.TimeCreated,
EventId = e?.EventRecord?.Id,
Source = e?.EventRecord?.ProviderName,
Category = e?.EventRecord?.LogName,
Task = e?.EventRecord?.TaskDisplayName,
Message = e?.EventRecord?.FormatDescription(),
};
if (e?.EventRecord?.Level is not null)
2023-09-21 18:58:32 +02:00
{
2023-09-21 22:10:55 +02:00
@event.Status = (EventLevel)Convert.ToInt32(e?.EventRecord?.Level) switch
2023-09-21 18:58:32 +02:00
{
2023-09-21 22:10:55 +02:00
EventLevel.Informational => StatusType.Information,
EventLevel.Warning => StatusType.Warning,
EventLevel.Error => StatusType.Error,
EventLevel.Critical => StatusType.Critical,
_ => StatusType.Information,
2023-09-21 18:58:32 +02:00
};
}
2023-09-21 22:10:55 +02:00
_queue.Writer.WriteAsync(@event, default);
2023-09-21 18:58:32 +02:00
}
2023-09-21 22:10:55 +02:00
catch (Exception) { } // app crash
2023-09-21 18:58:32 +02:00
}
}