using System; using System.Linq; using System.Diagnostics; using Microsoft.Extensions.Logging; using Sockeye.Util; using Sockeye.Models; using Microsoft.EntityFrameworkCore; //using StackExchange.Profiling; namespace Sockeye.Biz { /// /// called by Generator to gather server metrics and insert in db /// internal static class CoreJobMetricsSnapshot { private static ILogger log = Sockeye.Util.ApplicationLogging.CreateLogger("CoreJobMetricsSnapshot"); private static TimeSpan tsDataRetention = new TimeSpan(365, 0, 0, 0, 0);//one year private static Process _process = Process.GetCurrentProcess(); private static TimeSpan _oldCPUTime = TimeSpan.Zero; private static DateTime _lastMMSnapshot = DateTime.UtcNow.Subtract(new TimeSpan(1, 1, 1, 1, 1));//ensure it captures on a fresh boot; private static DateTime _lastDDSnapshot = DateTime.UtcNow.Subtract(new TimeSpan(1, 1, 1, 1, 1));//ensure it captures on a fresh boot; private static double _cpu = 0; #if (DEBUG) private static TimeSpan tsMMFrequency = new TimeSpan(0, 5, 0); private static TimeSpan tsDDFrequency = new TimeSpan(24, 0, 0); #else private static TimeSpan tsMMFrequency = new TimeSpan(0, 5, 0); private static TimeSpan tsDDFrequency = new TimeSpan(24, 0, 0);//changed to 12 hours from 24 due to weird issue not gathering like it should diagnosis #endif //////////////////////////////////////////////////////////////////////////////////////////////// // // public static void DoWork() { if (DateUtil.IsAfterDuration(_lastMMSnapshot, tsMMFrequency)) { ///////////////////////////////////////////// //ONE MINUTE SNAPS // log.LogDebug("MM metrics snapshot"); var now = DateTime.UtcNow; _process.Refresh(); //CPU var cpuElapsedTime = now.Subtract(_lastMMSnapshot).TotalMilliseconds; var newCPUTime = _process.TotalProcessorTime; var elapsedCPU = (newCPUTime - _oldCPUTime).TotalMilliseconds; _cpu = elapsedCPU * 100 / Environment.ProcessorCount / cpuElapsedTime; _oldCPUTime = newCPUTime; //MEMORY // The memory occupied by objects. var Allocated = GC.GetTotalMemory(false);//bigint // The working set includes both shared and private data. The shared data includes the pages that contain all the // instructions that the process executes, including instructions in the process modules and the system libraries. var WorkingSet = _process.WorkingSet64;//bigint // The value returned by this property represents the current size of memory used by the process, in bytes, that // cannot be shared with other processes. var PrivateBytes = _process.PrivateMemorySize64;//bigint //NOTE: CPU percentage is *our* process cpu percentage over timeframe of last captured avg //So it does *not* show the entire server cpu load, only for RAVEN. //Overall, server stats need to be captured / viewed independently (digital ocean control panel for example or windows task manager) var CPU = _cpu;// double precision //In some cases the first snapshot taken after a reboot //is a huge number way beyond 100 which fucks up the charts //likely due to the algorithm above and new values but not worth looking into atm if (CPU > 100) { CPU = 0; } using (AyContext ct = ServiceProviderProvider.DBContext) { //write to db MetricMM mm = new MetricMM(Allocated, WorkingSet, PrivateBytes, CPU); ct.MetricMM.Add(mm); ct.SaveChanges(); } _lastMMSnapshot = now; } ///////////////////////////////////////////// //ONCE A DAY SNAPS AND CLEANUP // if (DateUtil.IsAfterDuration(_lastDDSnapshot, tsDDFrequency)) { #if (DEBUG) log.LogInformation($"DD metrics snapshot, _lastDDSnapshot:{_lastDDSnapshot}, tsDDFrequency:{tsDDFrequency}"); #endif log.LogDebug("DD metrics snapshot"); var now = DateTime.UtcNow; //FILES ON DISK var UtilFilesInfo = FileUtil.GetBackupFolderSizeInfo(); var AttachmentFilesInfo = FileUtil.GetAttachmentFolderSizeInfo(); //Available space long UtilityFilesAvailableSpace = 0; try { UtilityFilesAvailableSpace = FileUtil.BackupFilesDriveAvailableSpace(); } catch (Exception ex) { log.LogError(ex, "Metrics::FileUtil::UtilityFilesDriveAvailableSpace error getting available space"); } long AttachmentFilesAvailableSpace = 0; try { AttachmentFilesAvailableSpace = FileUtil.AttachmentFilesDriveAvailableSpace(); } catch (Exception ex) { log.LogError(ex, "Metrics::FileUtil::AttachmentFilesDriveAvailableSpace error getting available space"); } using (AyContext ct = ServiceProviderProvider.DBContext) { //DB total size long DBTotalSize = 0; using (var command = ct.Database.GetDbConnection().CreateCommand()) { command.CommandText = "select pg_database_size(current_database());"; ct.Database.OpenConnection(); using (var dr = command.ExecuteReader()) { if (dr.HasRows) { DBTotalSize = dr.Read() ? dr.GetInt64(0) : 0; } ct.Database.CloseConnection(); } } //write to db MetricDD dd = new MetricDD() { AttachmentFileSize = AttachmentFilesInfo.SizeWithChildren, AttachmentFileCount = AttachmentFilesInfo.FileCountWithChildren, AttachmentFilesAvailableSpace = AttachmentFilesAvailableSpace, UtilityFileSize = UtilFilesInfo.SizeWithChildren, UtilityFileCount = UtilFilesInfo.FileCountWithChildren, UtilityFilesAvailableSpace = UtilityFilesAvailableSpace, DBTotalSize = DBTotalSize }; ct.MetricDD.Add(dd); ct.SaveChanges(); } ///////////////////////////////// //CLEAR OLD ENTRIES // DateTime ClearDate = DateTime.UtcNow - tsDataRetention; using (AyContext ct = ServiceProviderProvider.DBContext) { ct.Database.ExecuteSqlInterpolated($"delete from ametricmm where t < {ClearDate.ToUniversalTime()}"); ct.Database.ExecuteSqlInterpolated($"delete from ametricdd where t < {ClearDate.ToUniversalTime()}"); } _lastDDSnapshot = now; } //---- } ///////////////////////////////////////////////////////////////////// }//eoc }//eons