17 using System.Collections.Generic;
19 using System.Threading;
20 using Newtonsoft.Json;
34 private TextWriter _succeededDataRequestsWriter;
35 private TextWriter _failedDataRequestsWriter;
37 private long _succeededDataRequestsCount;
38 private long _failedDataRequestsCount;
40 private long _succeededUniverseDataRequestsCount;
41 private long _failedUniverseDataRequestsCount;
43 private readonly List<double> _requestRates =
new();
44 private long _prevRequestsCount;
45 private DateTime _lastRequestRateCalculationTime;
47 private Thread _requestRateCalculationThread;
48 private CancellationTokenSource _cancellationTokenSource;
50 private readonly
string _succeededDataRequestsFileName;
51 private readonly
string _failedDataRequestsFileName;
52 private readonly
string _resultsDestinationFolder;
54 private readonly
object _threadLock =
new();
62 _succeededDataRequestsFileName = GetFilePath(
"succeeded-data-requests.txt");
63 _failedDataRequestsFileName = GetFilePath(
"failed-data-requests.txt");
78 if (e.
Path.Contains(
"map_files", StringComparison.OrdinalIgnoreCase) ||
79 e.
Path.Contains(
"factor_files", StringComparison.OrdinalIgnoreCase))
85 var isUniverseData = path.Contains(
"coarse", StringComparison.OrdinalIgnoreCase) ||
86 path.Contains(
"universe", StringComparison.OrdinalIgnoreCase);
90 WriteLineToFile(_succeededDataRequestsWriter, path, _succeededDataRequestsFileName);
91 Interlocked.Increment(ref _succeededDataRequestsCount);
94 Interlocked.Increment(ref _succeededUniverseDataRequestsCount);
99 WriteLineToFile(_failedDataRequestsWriter, path, _failedDataRequestsFileName);
100 Interlocked.Increment(ref _failedDataRequestsCount);
103 Interlocked.Increment(ref _failedUniverseDataRequestsCount);
106 if (Logging.Log.DebuggingEnabled)
108 Logging.Log.Debug($
"DataMonitor.OnNewDataRequest(): Data from {path} could not be fetched, error: {e.ErrorMessage}");
118 if (_exited || _requestRateCalculationThread ==
null)
124 _requestRateCalculationThread.StopSafely(TimeSpan.FromSeconds(5), _cancellationTokenSource);
125 _succeededDataRequestsWriter?.Close();
126 _failedDataRequestsWriter?.Close();
128 StoreDataMonitorReport(GenerateReport());
130 _succeededDataRequestsWriter.DisposeSafely();
131 _failedDataRequestsWriter.DisposeSafely();
132 _cancellationTokenSource.DisposeSafely();
159 private void Initialize()
161 if (_requestRateCalculationThread !=
null)
167 if (_requestRateCalculationThread !=
null)
172 _succeededDataRequestsWriter = OpenStream(_succeededDataRequestsFileName);
173 _failedDataRequestsWriter = OpenStream(_failedDataRequestsFileName);
175 _cancellationTokenSource =
new CancellationTokenSource();
177 _requestRateCalculationThread =
new Thread(() =>
179 while (!_cancellationTokenSource.Token.WaitHandle.WaitOne(3000))
181 ComputeFileRequestFrequency();
184 { IsBackground =
true };
185 _requestRateCalculationThread.Start();
189 private DataMonitorReport GenerateReport()
191 var report =
new DataMonitorReport(_succeededDataRequestsCount,
192 _failedDataRequestsCount,
193 _succeededUniverseDataRequestsCount,
194 _failedUniverseDataRequestsCount,
197 Logging.Log.Trace($
"DataMonitor.GenerateReport():{Environment.NewLine}" +
198 $
"DATA USAGE:: Total data requests {report.TotalRequestsCount}{Environment.NewLine}" +
199 $
"DATA USAGE:: Succeeded data requests {report.SucceededDataRequestsCount}{Environment.NewLine}" +
200 $
"DATA USAGE:: Failed data requests {report.FailedDataRequestsCount}{Environment.NewLine}" +
201 $
"DATA USAGE:: Failed data requests percentage {report.FailedDataRequestsPercentage}%{Environment.NewLine}" +
202 $
"DATA USAGE:: Total universe data requests {report.TotalUniverseDataRequestsCount}{Environment.NewLine}" +
203 $
"DATA USAGE:: Succeeded universe data requests {report.SucceededUniverseDataRequestsCount}{Environment.NewLine}" +
204 $
"DATA USAGE:: Failed universe data requests {report.FailedUniverseDataRequestsCount}{Environment.NewLine}" +
205 $
"DATA USAGE:: Failed universe data requests percentage {report.FailedUniverseDataRequestsPercentage}%");
210 private void ComputeFileRequestFrequency()
212 var requestsCount = _succeededDataRequestsCount + _failedDataRequestsCount;
214 if (_lastRequestRateCalculationTime ==
default)
218 _lastRequestRateCalculationTime = DateTime.UtcNow;
219 _prevRequestsCount = requestsCount;
223 var requestsCountDelta = requestsCount - _prevRequestsCount;
224 var now = DateTime.UtcNow;
225 var timeDelta = now - _lastRequestRateCalculationTime;
227 _requestRates.Add(Math.Round(requestsCountDelta / timeDelta.TotalSeconds));
228 _prevRequestsCount = requestsCount;
229 _lastRequestRateCalculationTime = now;
236 private void StoreDataMonitorReport(DataMonitorReport report)
243 var path = GetFilePath(
"data-monitor-report.json");
244 var data = JsonConvert.SerializeObject(report, Formatting.None);
245 File.WriteAllText(path, data);
248 private string GetFilePath(
string filename)
250 var baseFilename = Path.GetFileNameWithoutExtension(filename);
251 var timestamp = DateTime.UtcNow.ToStringInvariant(
"yyyyMMddHHmmssfff");
252 var extension = Path.GetExtension(filename);
253 return Path.Combine(_resultsDestinationFolder, $
"{baseFilename}-{timestamp}{extension}");
256 private static TextWriter OpenStream(
string filename)
258 var writer =
new StreamWriter(filename);
259 return TextWriter.Synchronized(writer);
262 private static void WriteLineToFile(TextWriter writer,
string line,
string filename)
266 writer.WriteLine(line);
268 catch (IOException exception)
270 Logging.Log.Error($
"DataMonitor.OnNewDataRequest(): Failed to write to file {filename}: {exception.Message}");