using SQLInsight.Core.Collection; using SQLInsight.Core.Servers; namespace SQLInsight.Rules.Servers; /// /// Thresholds of the Windows server rules (SQLInsight:Servers in the agent's appsettings.json). Not sealed: the agent's /// options add how and how often to collect. /// public class ServerRuleSettings { public CpuThresholds Cpu { get; set; } = new(); public MemoryThresholds Memory { get; set; } = new(); public DiskThresholds Disks { get; set; } = new(); public ServiceThresholds Services { get; set; } = new(); public EventLogThresholds EventLog { get; set; } = new(); public TaskThresholds Tasks { get; set; } = new(); /// A server not restarted for more than this many days is a (low) finding: it most likely lacks Windows updates. 0: off. public int UptimeDays { get; set; } } public sealed class CpuThresholds { /// Average CPU at or above this (percent) … public double HighPercent { get; set; } = 90; /// … for this many minutes is a finding (SQLI-WIN-001). public int SustainedMinutes { get; set; } = 15; } public sealed class MemoryThresholds { /// Available memory below this share (percent) … public double AvailablePercent { get; set; } = 5; /// … and below this many MB is a finding (SQLI-WIN-002). Both, so big SQL Server hosts with little left by design are not flagged. public double AvailableMegabytes { get; set; } = 1024; /// Hard page faults per second above this, while memory is low, is paging (SQLI-WIN-003). public double PagesPerSecond { get; set; } = 1000; /// Committed memory at or above this share of the commit limit (percent) is a finding (SQLI-WIN-004). public double CommitPercent { get; set; } = 90; } public sealed class DiskThresholds { /// Free space below this (percent) is a finding (SQLI-WIN-005) … public double FreePercent { get; set; } = 10; /// … High below this … public double CriticalFreePercent { get; set; } = 5; /// … unless there is at least this much free (GB): a big volume with a small share free can be fine. public double EnoughFreeGigabytes { get; set; } = 50; /// A volume forecast to be full within this many days is a finding (SQLI-WIN-006); within 7 days High, 2 days Critical. public int ForecastDays { get; set; } = 30; /// How many days of SQLInsight's own samples the forecast is computed from. public int ForecastHistoryDays { get; set; } = 14; } public sealed class ServiceThresholds { /// /// Services that may be stopped although they start automatically (they stop by design), in addition to the /// built-in list. Name, or a prefix ending in *. /// public IList Ignore { get; } = []; /// Right after a restart services are still starting: no finding for this many minutes. public int StartupGraceMinutes { get; set; } = 15; /// /// At most this many findings for stopped automatic services per server (SQLI-WIN-007), by name; the rest are named in /// one summary finding. Between 1 and 100. /// public int MaxFindings { get; set; } = 15; } public sealed class EventLogThresholds { /// An ordinary error must repeat this many times in 24 hours before it is a finding; the important kinds count at once. public int RepeatThreshold { get; set; } = 5; /// Events left out as noise, in addition to the built-in list: "Kilde:id", "Kilde" or "Kilde*". public IList Ignore { get; } = []; /// At most this many event findings per server, most important first; the rest are named in one summary finding. Between 1 and 100. public int MaxFindings { get; set; } = 15; /// At most this many events per log are read in one collection; the rest is read next time. public int MaxEventsPerCollection { get; set; } = 2000; } public sealed class TaskThresholds { /// Also watch Microsoft's own tasks (\Microsoft\…). Off: there are hundreds, and their failures are rarely yours. public bool IncludeMicrosoftTasks { get; set; } /// A task whose next run time is more than this many minutes in the past has not run as planned (SQLI-WIN-013). public int LateMinutes { get; set; } = 60; /// At most this many tasks per server are watched (their run information is read one at a time). public int MaxWatched { get; set; } = 50; /// /// Leave out the tasks programs create per user (a user's SID in the name) or to update themselves (OneDrive, Edge, /// Google, User_Feed_Synchronization; ). On by default. /// public bool IgnoreUserAndUpdaterTasks { get; set; } = true; /// Tasks never watched (path\name, or a prefix ending in *). public IList Ignore { get; } = []; /// Whether the task (its full path) is watched: the agent's filter when it reads tasks, and the rules' too. public bool Watches(string fullName) { ArgumentNullException.ThrowIfNull(fullName); return (IncludeMicrosoftTasks || !TaskResults.IsMicrosoftTask(fullName)) && !(IgnoreUserAndUpdaterTasks && TaskResults.IsUserOrUpdaterTask(fullName)) && !WindowsServerRules.Matches(fullName, Ignore); } } /// What the Windows server rules see: the server, the latest data per area, and the thresholds. public sealed record ServerRuleContext(ServerIdentity Server, DateTimeOffset Now, CollectedData Data, ServerRuleSettings Settings) { /// The interval performance samples are taken at, for "sustained" averages. public TimeSpan PerformanceInterval { get; init; } = ServerArea.DefaultInterval(ServerArea.Performance); }