17 using System.Collections.Generic;
19 using System.Threading;
20 using Newtonsoft.Json;
33 private TextWriter _succeededDataRequestsWriter;
34 private TextWriter _failedDataRequestsWriter;
36 private long _succeededDataRequestsCount;
37 private long _failedDataRequestsCount;
39 private long _succeededUniverseDataRequestsCount;
40 private long _failedUniverseDataRequestsCount;
42 private readonly List<double> _requestRates =
new();
43 private long _prevRequestsCount;
44 private DateTime _lastRequestRateCalculationTime;
46 private Thread _requestRateCalculationThread;
47 private CancellationTokenSource _cancellationTokenSource;
49 private readonly
string _succeededDataRequestsFileName;
50 private readonly
string _failedDataRequestsFileName;
51 private readonly
string _resultsDestinationFolder;
53 private readonly
object _threadLock =
new();
61 _succeededDataRequestsFileName = GetFilePath(
"succeeded-data-requests.txt");
62 _failedDataRequestsFileName = GetFilePath(
"failed-data-requests.txt");
77 if (e.
Path.Contains(
"map_files", StringComparison.OrdinalIgnoreCase) ||
78 e.
Path.Contains(
"factor_files", StringComparison.OrdinalIgnoreCase))
84 var isUniverseData = path.Contains(
"coarse", StringComparison.OrdinalIgnoreCase) ||
85 path.Contains(
"universe", StringComparison.OrdinalIgnoreCase);
89 WriteLineToFile(_succeededDataRequestsWriter, path, _succeededDataRequestsFileName);
90 Interlocked.Increment(ref _succeededDataRequestsCount);
93 Interlocked.Increment(ref _succeededUniverseDataRequestsCount);
98 WriteLineToFile(_failedDataRequestsWriter, path, _failedDataRequestsFileName);
99 Interlocked.Increment(ref _failedDataRequestsCount);
102 Interlocked.Increment(ref _failedUniverseDataRequestsCount);
105 if (Logging.Log.DebuggingEnabled)
107 Logging.Log.Debug($
"DataMonitor.OnNewDataRequest(): Data from {path} could not be fetched, error: {e.ErrorMessage}");
117 if (_exited || _requestRateCalculationThread ==
null)
123 _requestRateCalculationThread.StopSafely(TimeSpan.FromSeconds(5), _cancellationTokenSource);
124 _succeededDataRequestsWriter?.Close();
125 _failedDataRequestsWriter?.Close();
127 StoreDataMonitorReport(GenerateReport());
129 _succeededDataRequestsWriter.DisposeSafely();
130 _failedDataRequestsWriter.DisposeSafely();
131 _cancellationTokenSource.DisposeSafely();
158 private void Initialize()
160 if (_requestRateCalculationThread !=
null)
166 if (_requestRateCalculationThread !=
null)
171 _succeededDataRequestsWriter = OpenStream(_succeededDataRequestsFileName);
172 _failedDataRequestsWriter = OpenStream(_failedDataRequestsFileName);
174 _cancellationTokenSource =
new CancellationTokenSource();
176 _requestRateCalculationThread =
new Thread(() =>
178 while (!_cancellationTokenSource.Token.WaitHandle.WaitOne(3000))
180 ComputeFileRequestFrequency();
183 { IsBackground =
true };
184 _requestRateCalculationThread.Start();
188 private DataMonitorReport GenerateReport()
190 var report =
new DataMonitorReport(_succeededDataRequestsCount,
191 _failedDataRequestsCount,
192 _succeededUniverseDataRequestsCount,
193 _failedUniverseDataRequestsCount,
196 Logging.Log.Trace($
"DataMonitor.GenerateReport():{Environment.NewLine}" +
197 $
"DATA USAGE:: Total data requests {report.TotalRequestsCount}{Environment.NewLine}" +
198 $
"DATA USAGE:: Succeeded data requests {report.SucceededDataRequestsCount}{Environment.NewLine}" +
199 $
"DATA USAGE:: Failed data requests {report.FailedDataRequestsCount}{Environment.NewLine}" +
200 $
"DATA USAGE:: Failed data requests percentage {report.FailedDataRequestsPercentage}%{Environment.NewLine}" +
201 $
"DATA USAGE:: Total universe data requests {report.TotalUniverseDataRequestsCount}{Environment.NewLine}" +
202 $
"DATA USAGE:: Succeeded universe data requests {report.SucceededUniverseDataRequestsCount}{Environment.NewLine}" +
203 $
"DATA USAGE:: Failed universe data requests {report.FailedUniverseDataRequestsCount}{Environment.NewLine}" +
204 $
"DATA USAGE:: Failed universe data requests percentage {report.FailedUniverseDataRequestsPercentage}%");
209 private void ComputeFileRequestFrequency()
211 var requestsCount = _succeededDataRequestsCount + _failedDataRequestsCount;
213 if (_lastRequestRateCalculationTime ==
default)
217 _lastRequestRateCalculationTime = DateTime.UtcNow;
218 _prevRequestsCount = requestsCount;
222 var requestsCountDelta = requestsCount - _prevRequestsCount;
223 var now = DateTime.UtcNow;
224 var timeDelta = now - _lastRequestRateCalculationTime;
226 _requestRates.Add(Math.Round(requestsCountDelta / timeDelta.TotalSeconds));
227 _prevRequestsCount = requestsCount;
228 _lastRequestRateCalculationTime = now;
235 private void StoreDataMonitorReport(DataMonitorReport report)
242 var path = GetFilePath(
"data-monitor-report.json");
243 var data = JsonConvert.SerializeObject(report, Formatting.None);
244 File.WriteAllText(path, data);
247 private string GetFilePath(
string filename)
249 var baseFilename = Path.GetFileNameWithoutExtension(filename);
250 var timestamp = DateTime.UtcNow.ToStringInvariant(
"yyyyMMddHHmmssfff");
251 var extension = Path.GetExtension(filename);
252 return Path.Combine(_resultsDestinationFolder, $
"{baseFilename}-{timestamp}{extension}");
255 private static TextWriter OpenStream(
string filename)
257 var writer =
new StreamWriter(filename);
258 return TextWriter.Synchronized(writer);
261 private static void WriteLineToFile(TextWriter writer,
string line,
string filename)
265 writer.WriteLine(line);
267 catch (IOException exception)
269 Logging.Log.Error($
"DataMonitor.OnNewDataRequest(): Failed to write to file {filename}: {exception.Message}");