view ServerMonitor/Objects/CheckResult.cs @ 29:f6235dc0a8ec

Add ability to play a sound on check failure.
author Brad Greco <brad@bgreco.net>
date Fri, 14 Jun 2019 21:01:55 -0400
parents 68d7834dc28e
children
line wrap: on
line source

using ServerMonitorApp.Properties;
using System;

namespace ServerMonitorApp
{
    /// <summary>
    /// The result of an executed check.
    /// Contains data about the check's last execution including status, time, and log message.
    /// </summary>
    public class CheckResult
    {
        // The date format to use in log files.
        private const string dateFormat = "yyyy-MM-dd HH:mm:ss.fff";

        /// <summary>The originating check of this check result.</summary>
        public Check Check { get; private set; }

        /// <summary>The result status of the check execution.</summary>
        public CheckStatus CheckStatus { get; private set; }

        /// <summary>The message generated by the check execution.</summary>
        public string Message { get; set; }

        /// <summary>The time the check execution began.</summary>
        public DateTime StartTime { get; set; }

        /// <summary>The time the check execution ended.</summary>
        public DateTime EndTime { get; set; }

        /// <summary>Whether the check execution resulted in success or failure.</summary>
        public bool Failed => CheckStatus.In(CheckStatus.Error, CheckStatus.Warning, CheckStatus.Information);

        /// <summary>Action to perform when the check fails.</summary>
        public FailAction FailAction
        {
            get
            {
                // Use the global preferences for each status to determine the action to take.
                switch (CheckStatus)
                {
                    case CheckStatus.Error: return Settings.Default.ErrorAction;
                    case CheckStatus.Warning: return Settings.Default.WarningAction;
                    case CheckStatus.Information: return Settings.Default.InformationAction;
                    // On success (or any other status), do nothing.
                    default: return FailAction.None;
                }
            }
        }

        /// <summary>Sound to play when the check fails.</summary>
        /// <remarks>
        /// Returns null if no sound should be played.
        /// Returns string.Empty if the Windows default error sound should be played.
        /// Otherwise, returns the path to the custom sound file that should be played.
        /// </remarks>
        public string FailSound
        {
            get
            {
                string setting = null;
                // Use the global preferences for each status to determine the action to take.
                switch (CheckStatus)
                {
                    case CheckStatus.Error: setting = Settings.Default.ErrorSound; break;
                    case CheckStatus.Warning: setting = Settings.Default.WarningSound; break;
                    case CheckStatus.Information: setting = Settings.Default.InformationSound; break;
                    // On success (or any other status), do nothing.
                }
                if (int.TryParse(setting, out int index)) {
                    return index == 0 ? null : string.Empty;
                }
                return setting;
            }
        }

        /// <summary>CheckResult constructor.</summary>
        /// <param name="check">The originating check of this check result.</param>
        /// <param name="status">The result status of the check execution.</param>
        /// <param name="message">The message generated by the check execution.</param>
        public CheckResult(Check check, CheckStatus status, string message)
        {
            Check = check;
            CheckStatus = status;
            Message = message;
        }

        /// <summary>Generates a string representation of the check result that can be logged.</summary>
        /// <returns>A string representation of the check result that can be logged.</returns>
        /// <remarks>
        /// The log string is in the format:
        /// [Check ID] [Start time] [End time] [Check status] [Check output]
        /// 
        /// The check ID is left-padded with zeros to simplify log parsing and filtering by check ID.
        /// Dates are formatted according to the dateFormat defined in this class.
        /// Newlines in check output are escaped so the log string contains no literal newline characters.
        /// </remarks>
        public string ToLogString()
        {
            return string.Format("{0:00000} {1} {2} {3} {4}",
                Check.Id,
                StartTime.ToString(dateFormat),
                EndTime.ToString(dateFormat),
                CheckStatus,
                Message.ConvertNewlines().Replace("\n", "\\n"));
        }

        /// <summary>Parses a log string to create a check result object.</summary>
        /// <param name="check">The originating check for the check result.</param>
        /// <param name="logString">The log string to parse.</param>
        /// <returns>A check result object.</returns>
        public static CheckResult FromLogString(Check check, string logString)
        {
            // The check ID, start time, and end time are fixed in length, so no pattern matching is needed.
            DateTime startTime = DateTime.Parse(logString.Substring(6, 23));
            DateTime endTime = DateTime.Parse(logString.Substring(30, 23));
            // The check status is not fixed in length, but will not contain any spaces.
            // So, the first space following the beginning of the checks status will
            // mark the start of the result message.
            int messageStartPos = logString.IndexOf(' ', 54);
            // Now we know the length of the status token, so we can extract and parse it.
            Enum.TryParse(logString.Substring(54, messageStartPos - 54), out CheckStatus status);
            // Put it all together.
            return new CheckResult(check, status, logString.Substring(messageStartPos + 1)) { StartTime = startTime, EndTime = endTime };
        }
    }
}