Mercurial > servermonitor
view ServerMonitor/Objects/Checks/Check.cs @ 15:23f2e0da1094
- Fix the last execution status being lost after a check is edited.
- Add comments.
author | Brad Greco <brad@bgreco.net> |
---|---|
date | Mon, 22 Apr 2019 21:11:27 -0400 |
parents | 052aa62cb42a |
children | 7626b099aefd |
line wrap: on
line source
using System; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Xml.Serialization; namespace ServerMonitorApp { /*public enum CheckType { Command }*/ public enum CheckStatus { Success, Information, Warning, Error, Running, Disabled, } public abstract class Check { private static Type[] _checkTypes; public static Type[] CheckTypes { get { return _checkTypes ?? (_checkTypes = typeof(Check).Assembly.GetTypes() .Where(t => t.IsSubclassOf(typeof(Check))) .OrderBy(t => t.GetAttribute<DisplayWeightAttribute>()?.DisplayWeight).ToArray()); } } public int Id { get; set; } public string Name { get; set; } /*public CheckType Type { get; set; }*/ public int Timeout { get; set; } public bool Enabled { get; set; } public Schedule Schedule { get; set; } public DateTime LastRunTime { get; set; } public DateTime LastScheduledRunTime { get; set; } public DateTime NextRunTime { get; set; } public string LastMessage { get; set; } public CheckStatus Status { get; set; } public CheckStatus LastRunStatus { get; set; } public CheckStatus FailStatus { get; set; } public int MaxConsecutiveFailures { get; set; } [XmlIgnore] public int ConsecutiveFailures { get; set; } [XmlIgnore] public Server Server { get; set; } public Check() { FailStatus = CheckStatus.Error; } public override string ToString() { return Name; } public virtual string Validate(bool saving = true) { string message = string.Empty; if (Name.IsNullOrEmpty() && saving) message += "Name cannot be blank." + Environment.NewLine; return message; } public async Task<CheckResult> ExecuteAsync(CancellationToken token = default(CancellationToken), bool update = true) { if (token.IsCancellationRequested) return null; CheckResult result; DateTime startTime = DateTime.Now; try { Task<CheckResult> checkTask = ExecuteCheckAsync(token); try { if (await Task.WhenAny(checkTask, Task.Delay(Timeout, token)) == checkTask) { result = await checkTask; } else { result = Fail("Timed out."); } } catch (TaskCanceledException) { return null; } } catch (Exception e) { result = Fail(e.GetBaseException().Message); } result.StartTime = startTime; result.EndTime = DateTime.Now; // If a check is executed from the CheckForm, we don't want to update the status or log the event. if (update) { Status = result.CheckStatus; LastRunStatus = result.CheckStatus; LastMessage = result.Message; LastRunTime = result.EndTime; } return result; } public CheckResult Pass(string message) { return new CheckResult(this, CheckStatus.Success, message); } public CheckResult Fail(string message) { return new CheckResult(this, FailStatus, message); } protected CheckResult Fail(Exception e) { return new CheckResult(this, FailStatus, e.GetBaseException().Message); } protected CheckResult GetIntResult(int expectedValue, int resultValue, string description) { if (expectedValue == resultValue) return Pass(string.Format("{0}: {1}", description, resultValue)); else return Fail(string.Format("{0}: {1} (expected: {2})", description, resultValue, expectedValue)); } protected CheckResult GetStringResult(MatchType matchType, string expectedPattern, bool useRegex, string resultValue, string description) { bool match; if (useRegex) { if (matchType.In(MatchType.Equals, MatchType.NotEquals)) { if (!expectedPattern.StartsWith("^")) expectedPattern = "^" + expectedPattern; if (!expectedPattern.EndsWith("$")) expectedPattern += "$"; } Regex re = new Regex(expectedPattern, RegexOptions.Singleline); match = re.IsMatch(resultValue); } else { if (matchType.In(MatchType.Equals, MatchType.NotEquals)) { match = expectedPattern == resultValue; } else if (matchType.In(MatchType.Contains, MatchType.NotContains)) { match = resultValue.Contains(expectedPattern); } else { if (decimal.TryParse(expectedPattern, out decimal expectedNumeric) && decimal.TryParse(resultValue, out decimal resultNumeric)) { match = (matchType == MatchType.GreaterThan && resultNumeric > expectedNumeric) || (matchType == MatchType.LessThan && resultNumeric < expectedNumeric); } else { return Fail(string.Format("{0} is not numeric: {1}", description, resultValue)); } } } if (matchType.In(MatchType.Equals, MatchType.Contains)) { if (match) return Pass(string.Format("{0} {1} the pattern: {2}", description, matchType.ToString().ToLower(), expectedPattern)); else return Fail(string.Format("{0} does not {1} the pattern: {2} ({0}: {3})", description, matchType.ToString().ToLower().TrimEnd('s'), expectedPattern, resultValue)); } else if (matchType.In(MatchType.NotEquals, MatchType.NotContains)) { if (match) return Fail(string.Format("{0} {1} the pattern: {2} ({0}: {3})", description, matchType.ToString().ToLower().Replace("not", ""), expectedPattern, resultValue)); else return Pass(string.Format("{0} does not {1} the pattern: {2}", description, matchType.ToString().ToLower().TrimEnd('s').Replace("not", ""), expectedPattern)); } else { if (match) return Pass(string.Format("{0} ({1}) is {2} {3}", description, resultValue, matchType.ToString().ToLower().Replace("than", " than"), expectedPattern)); else return Fail(string.Format("{0} ({1}) is not {2} {3}", description, resultValue, matchType.ToString().ToLower().Replace("than", " than"), expectedPattern)); } } protected CheckResult MergeResults(params CheckResult[] results) { StringBuilder message = new StringBuilder(); bool failed = false; foreach (CheckResult result in results) { if (result == null) continue; if (result.Failed) failed = true; message.AppendLine(result.Message); } return failed ? Fail(message.ToString().Trim()) : Pass(message.ToString().Trim()); } protected abstract Task<CheckResult> ExecuteCheckAsync(CancellationToken token); } }