Files
ServerManagementUtils/robin/Services/MonitoringService.cs
T
Alexandru-Victor Macocian 69fd4bfb62 Setup Robin base files
Setup base files for Robin monitoring service
2025-11-27 17:37:28 +01:00

128 lines
4.0 KiB
C#

using System.Extensions.Core;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Robin.Options;
namespace Robin.Services;
public sealed class MonitoringService(
IOptions<MonitorOptions> options,
ILogger<MonitoringService> logger
) : IHostedLifecycleService
{
private readonly MonitorOptions options = options.Value;
private readonly ILogger<MonitoringService> logger = logger;
private readonly List<FileSystemWatcher> watchers = [];
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task StartedAsync(CancellationToken cancellationToken) =>
this.MonitorFiles(cancellationToken);
public Task StartingAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task StoppedAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task StoppingAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public async Task MonitorFiles(CancellationToken cancellationToken)
{
var scopedLogger = this.logger.CreateScopedLogger();
scopedLogger.LogDebug(
"Starting file monitoring service. Parsing provided paths {paths}",
string.Join(", ", this.options.Paths)
);
var expandedPaths = ExpandPaths(this.options.Paths);
scopedLogger.LogInformation(
"Monitoring the following files: {files}",
string.Join(", ", expandedPaths)
);
foreach (var filePath in expandedPaths)
{
var watcher = CreateWatcher(filePath);
if (watcher is null)
{
scopedLogger.LogWarning("Failed to watch file: {file}", filePath);
continue;
}
this.watchers.Add(watcher);
scopedLogger.LogDebug("Watching file: {file}", filePath);
}
}
private FileSystemWatcher? CreateWatcher(string filePath)
{
var scpoedLogger = this.logger.CreateScopedLogger();
var directory = Path.GetDirectoryName(filePath);
var fileName = Path.GetFileName(filePath);
if (directory is null || fileName is null)
{
scpoedLogger.LogWarning("Invalid file path: {filePath}", filePath);
return default;
}
var watcher = new FileSystemWatcher(directory, fileName)
{
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size,
EnableRaisingEvents = true,
};
watcher.Changed += this.OnFileChanged;
watcher.Error += this.OnWatcherError;
return watcher;
}
private void OnFileChanged(object sender, FileSystemEventArgs e)
{
var scopedLogger = this.logger.CreateScopedLogger();
scopedLogger.LogDebug("File changed: {file}", e.FullPath);
// TODO:: Read changes and push to Elastic
}
private void OnWatcherError(object sender, ErrorEventArgs e)
{
var scopedLogger = this.logger.CreateScopedLogger();
scopedLogger.LogError(e.GetException(), "Watcher error");
}
public void Dispose()
{
foreach (var watcher in this.watchers)
{
watcher.Changed -= this.OnFileChanged;
watcher.Error -= this.OnWatcherError;
watcher.Dispose();
}
this.watchers.Clear();
}
private static List<string> ExpandPaths(List<string>? patterns)
{
if (patterns is null || patterns.Count == 0)
{
return [];
}
var results = new List<string>();
foreach (var pattern in patterns)
{
var directory = Path.GetDirectoryName(pattern);
var filePattern = Path.GetFileName(pattern);
if (string.IsNullOrEmpty(directory) || !Directory.Exists(directory))
{
continue;
}
results.AddRange(Directory.GetFiles(directory, filePattern));
}
return results;
}
}