Scoped rules with their own context (a Windows server, a synthetic check) that produce the same findings and outcomes as the instance rules; missing data is "ikke målbar" with the collector's reason. Thresholds are settings (SQLInsight:Servers, SQLInsight:SyntheticChecks). - Sustained CPU, low memory (share and MB), paging with low memory, commit charge. - Free disk space and "fuld om ca. N dage" forecasts. - Stopped automatic services (minus those that stop by design, and a grace period after a restart) and watched services that must run. - Windows event log groups: important kinds at once, ordinary errors when they repeat, capped per server; sample messages are sensitive. - Unexpected restart (Kernel-Power 41, EventLog 6008, BugCheck), optional uptime. - Scheduled tasks that failed or did not run as planned. - Synthetic checks failing (twice in a row), "svarer ikke, selv om tjenesten kører", slow answers, TLS certificates about to expire. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
106 lines
4.6 KiB
C#
106 lines
4.6 KiB
C#
using SQLInsight.Core.Collection;
|
|
using SQLInsight.Core.Servers;
|
|
|
|
namespace SQLInsight.Rules.Servers;
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
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();
|
|
|
|
/// <summary>A server not restarted for more than this many days is a (low) finding: it most likely lacks Windows updates. 0: off.</summary>
|
|
public int UptimeDays { get; set; }
|
|
}
|
|
|
|
public sealed class CpuThresholds
|
|
{
|
|
/// <summary>Average CPU at or above this (percent) …</summary>
|
|
public double HighPercent { get; set; } = 90;
|
|
|
|
/// <summary>… for this many minutes is a finding (SQLI-WIN-001).</summary>
|
|
public int SustainedMinutes { get; set; } = 15;
|
|
}
|
|
|
|
public sealed class MemoryThresholds
|
|
{
|
|
/// <summary>Available memory below this share (percent) …</summary>
|
|
public double AvailablePercent { get; set; } = 5;
|
|
|
|
/// <summary>… 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.</summary>
|
|
public double AvailableMegabytes { get; set; } = 1024;
|
|
|
|
/// <summary>Hard page faults per second above this, while memory is low, is paging (SQLI-WIN-003).</summary>
|
|
public double PagesPerSecond { get; set; } = 1000;
|
|
|
|
/// <summary>Committed memory at or above this share of the commit limit (percent) is a finding (SQLI-WIN-004).</summary>
|
|
public double CommitPercent { get; set; } = 90;
|
|
}
|
|
|
|
public sealed class DiskThresholds
|
|
{
|
|
/// <summary>Free space below this (percent) is a finding (SQLI-WIN-005) …</summary>
|
|
public double FreePercent { get; set; } = 10;
|
|
|
|
/// <summary>… High below this …</summary>
|
|
public double CriticalFreePercent { get; set; } = 5;
|
|
|
|
/// <summary>… unless there is at least this much free (GB): a big volume with a small share free can be fine.</summary>
|
|
public double EnoughFreeGigabytes { get; set; } = 50;
|
|
|
|
/// <summary>A volume forecast to be full within this many days is a finding (SQLI-WIN-006); within 7 days High, 2 days Critical.</summary>
|
|
public int ForecastDays { get; set; } = 30;
|
|
|
|
/// <summary>How many days of SQLInsight's own samples the forecast is computed from.</summary>
|
|
public int ForecastHistoryDays { get; set; } = 14;
|
|
}
|
|
|
|
public sealed class ServiceThresholds
|
|
{
|
|
/// <summary>
|
|
/// 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 *.
|
|
/// </summary>
|
|
public IList<string> Ignore { get; } = [];
|
|
|
|
/// <summary>Right after a restart services are still starting: no finding for this many minutes.</summary>
|
|
public int StartupGraceMinutes { get; set; } = 15;
|
|
}
|
|
|
|
public sealed class EventLogThresholds
|
|
{
|
|
/// <summary>An ordinary error must repeat this many times in 24 hours before it is a finding; the important kinds count at once.</summary>
|
|
public int RepeatThreshold { get; set; } = 5;
|
|
|
|
/// <summary>Events left out as noise, in addition to the built-in list: "Kilde:id", "Kilde" or "Kilde*".</summary>
|
|
public IList<string> Ignore { get; } = [];
|
|
|
|
/// <summary>At most this many event findings per server, most important first.</summary>
|
|
public int MaxFindings { get; set; } = 15;
|
|
}
|
|
|
|
public sealed class TaskThresholds
|
|
{
|
|
/// <summary>Also watch Microsoft's own tasks (\Microsoft\…). Off: there are hundreds, and their failures are rarely yours.</summary>
|
|
public bool IncludeMicrosoftTasks { get; set; }
|
|
|
|
/// <summary>A task whose next run time is more than this many minutes in the past has not run as planned (SQLI-WIN-013).</summary>
|
|
public int LateMinutes { get; set; } = 60;
|
|
|
|
/// <summary>Tasks never watched (path\name, or a prefix ending in *).</summary>
|
|
public IList<string> Ignore { get; } = [];
|
|
}
|
|
|
|
/// <summary>What the Windows server rules see: the server, the latest data per area, and the thresholds.</summary>
|
|
public sealed record ServerRuleContext(ServerIdentity Server, DateTimeOffset Now, CollectedData Data, ServerRuleSettings Settings)
|
|
{
|
|
/// <summary>The interval performance samples are taken at, for "sustained" averages.</summary>
|
|
public TimeSpan PerformanceInterval { get; init; } = ServerArea.DefaultInterval(ServerArea.Performance);
|
|
}
|