diff --git a/src/Umbraco.Core/Configuration/HealthChecks/BaseNotificationMethodElement.cs b/src/Umbraco.Core/Configuration/HealthChecks/BaseNotificationMethodElement.cs new file mode 100644 index 0000000000..3ef90c6471 --- /dev/null +++ b/src/Umbraco.Core/Configuration/HealthChecks/BaseNotificationMethodElement.cs @@ -0,0 +1,18 @@ +using System.Configuration; + +namespace Umbraco.Core.Configuration.HealthChecks +{ + public abstract class BaseNotificationMethodElement : ConfigurationElement + { + private const string VERBOSITY_KEY = "verbosity"; + + [ConfigurationProperty(VERBOSITY_KEY, IsRequired = true)] + public HealthCheckNotificationVerbosity Verbosity + { + get + { + return ((HealthCheckNotificationVerbosity)(base[VERBOSITY_KEY])); + } + } + } +} diff --git a/src/Umbraco.Core/Configuration/HealthChecks/EmailSettingsElement.cs b/src/Umbraco.Core/Configuration/HealthChecks/EmailSettingsElement.cs index ed58ce1061..d9f8b22738 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/EmailSettingsElement.cs +++ b/src/Umbraco.Core/Configuration/HealthChecks/EmailSettingsElement.cs @@ -2,7 +2,7 @@ namespace Umbraco.Core.Configuration.HealthChecks { - public class EmailSettingsElement : ConfigurationElement + public class EmailSettingsElement : BaseNotificationMethodElement { private const string RECIPIENT_EMAIL_KEY = "recipientEmail"; private const string SUBJECT_KEY = "subject"; diff --git a/src/Umbraco.Core/Configuration/HealthChecks/HealthCheckNotificationVerbosity.cs b/src/Umbraco.Core/Configuration/HealthChecks/HealthCheckNotificationVerbosity.cs new file mode 100644 index 0000000000..6556c19c32 --- /dev/null +++ b/src/Umbraco.Core/Configuration/HealthChecks/HealthCheckNotificationVerbosity.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Core.Configuration.HealthChecks +{ + public enum HealthCheckNotificationVerbosity + { + Summary, + Detailed + } +} diff --git a/src/Umbraco.Core/Configuration/HealthChecks/SlackSettingsElement.cs b/src/Umbraco.Core/Configuration/HealthChecks/SlackSettingsElement.cs index 4b61e1371b..0dbf6673cc 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/SlackSettingsElement.cs +++ b/src/Umbraco.Core/Configuration/HealthChecks/SlackSettingsElement.cs @@ -2,7 +2,7 @@ namespace Umbraco.Core.Configuration.HealthChecks { - public class SlackSettingsElement : ConfigurationElement + public class SlackSettingsElement : BaseNotificationMethodElement { private const string WEBHOOKURL_KEY = "webHookUrl"; private const string CHANNEL_KEY = "channel"; diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 773ace6575..0e0f9235db 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -218,6 +218,8 @@ + + diff --git a/src/Umbraco.Tests/Web/HealthChecks/HealthCheckResultsTests.cs b/src/Umbraco.Tests/Web/HealthChecks/HealthCheckResultsTests.cs index 17a3c86baf..4f61dafd1d 100644 --- a/src/Umbraco.Tests/Web/HealthChecks/HealthCheckResultsTests.cs +++ b/src/Umbraco.Tests/Web/HealthChecks/HealthCheckResultsTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Moq; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Configuration.HealthChecks; using Umbraco.Web.HealthCheck; namespace Umbraco.Tests.Web.HealthChecks @@ -10,6 +11,8 @@ namespace Umbraco.Tests.Web.HealthChecks [TestFixture] public class HealthCheckResultsTests { + #region Stub checks + [HealthCheck("CFD6FC34-59C9-4402-B55F-C8BC96B628A1", "Stub check")] public abstract class StubHealthCheck : HealthCheck { @@ -68,6 +71,8 @@ namespace Umbraco.Tests.Web.HealthChecks } } + #endregion + [Test] public void HealthCheckResults_WithSuccessfulChecks_ReturnsCorrectResultDescription() { @@ -77,9 +82,10 @@ namespace Umbraco.Tests.Web.HealthChecks new StubHealthCheck2(StatusResultType.Success, "Second check was successful"), }; var results = new HealthCheckResults(checks); + Assert.IsTrue(results.AllChecksSuccessful); - var resultAsMarkdown = results.ResultsAsMarkDown(); + var resultAsMarkdown = results.ResultsAsMarkDown(HealthCheckNotificationVerbosity.Summary); Assert.IsTrue(resultAsMarkdown.IndexOf("Checks for 'Stub check 1' all completed succesfully.") > -1); Assert.IsTrue(resultAsMarkdown.IndexOf("Checks for 'Stub check 2' all completed succesfully.") > -1); } @@ -93,9 +99,10 @@ namespace Umbraco.Tests.Web.HealthChecks new StubHealthCheck2(StatusResultType.Error, "Second check was not successful"), }; var results = new HealthCheckResults(checks); + Assert.IsFalse(results.AllChecksSuccessful); - var resultAsMarkdown = results.ResultsAsMarkDown(); + var resultAsMarkdown = results.ResultsAsMarkDown(HealthCheckNotificationVerbosity.Summary); Assert.IsTrue(resultAsMarkdown.IndexOf("Checks for 'Stub check 1' all completed succesfully.") > -1); Assert.IsTrue(resultAsMarkdown.IndexOf("Checks for 'Stub check 2' completed with errors.") > -1); } @@ -110,12 +117,42 @@ namespace Umbraco.Tests.Web.HealthChecks new StubHealthCheck2(StatusResultType.Error, "Second check was not successful"), }; var results = new HealthCheckResults(checks); + Assert.IsFalse(results.AllChecksSuccessful); - var resultAsMarkdown = results.ResultsAsMarkDown(); + var resultAsMarkdown = results.ResultsAsMarkDown(HealthCheckNotificationVerbosity.Summary); Assert.IsTrue(resultAsMarkdown.IndexOf("Checks for 'Stub check 1' all completed succesfully.") > -1); Assert.IsTrue(resultAsMarkdown.IndexOf("Checks for 'Stub check 2' completed with errors.") > -1); Assert.IsTrue(resultAsMarkdown.IndexOf("Checks for 'Stub check 3' completed with errors.") > -1); } + + [Test] + public void HealthCheckResults_WithSummaryVerbosity_ReturnsCorrectResultDescription() + { + var checks = new List + { + new StubHealthCheck1(StatusResultType.Success, "First check was successful"), + new StubHealthCheck2(StatusResultType.Success, "Second check was successful"), + }; + var results = new HealthCheckResults(checks); + + var resultAsMarkdown = results.ResultsAsMarkDown(HealthCheckNotificationVerbosity.Summary); + Assert.IsTrue(resultAsMarkdown.IndexOf("Result: 'Success'\r\n") > -1); + } + + [Test] + public void HealthCheckResults_WithDetailedVerbosity_ReturnsCorrectResultDescription() + { + var checks = new List + { + new StubHealthCheck1(StatusResultType.Success, "First check was successful"), + new StubHealthCheck2(StatusResultType.Success, "Second check was successful"), + }; + var results = new HealthCheckResults(checks); + + var resultAsMarkdown = results.ResultsAsMarkDown(HealthCheckNotificationVerbosity.Detailed); + Assert.IsFalse(resultAsMarkdown.IndexOf("Result: 'Success'\r\n") > -1); + Assert.IsTrue(resultAsMarkdown.IndexOf("Result: 'Success', Message: 'First check was successful'\r\n") > -1); + } } } diff --git a/src/Umbraco.Web.UI/config/HealthChecks.config b/src/Umbraco.Web.UI/config/HealthChecks.config index 09fe120129..a4c4d374fb 100644 --- a/src/Umbraco.Web.UI/config/HealthChecks.config +++ b/src/Umbraco.Web.UI/config/HealthChecks.config @@ -1,23 +1,22 @@ - + - - + + - - - - - + + diff --git a/src/Umbraco.Web/HealthCheck/HealthCheckResults.cs b/src/Umbraco.Web/HealthCheck/HealthCheckResults.cs index b16d12d0fb..a334e9dbb8 100644 --- a/src/Umbraco.Web/HealthCheck/HealthCheckResults.cs +++ b/src/Umbraco.Web/HealthCheck/HealthCheckResults.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using MarkdownSharp; +using Umbraco.Core.Configuration.HealthChecks; using Umbraco.Core.Logging; namespace Umbraco.Web.HealthCheck @@ -72,7 +73,7 @@ namespace Umbraco.Web.HealthCheck } } - internal string ResultsAsMarkDown(bool slackMarkDown = false) + internal string ResultsAsMarkDown(HealthCheckNotificationVerbosity verbosity, bool slackMarkDown = false) { var newItem = "- "; if (slackMarkDown) @@ -105,17 +106,25 @@ namespace Umbraco.Web.HealthCheck foreach (var checkResult in checkResults) { - sb.AppendFormat("\t{0}Result: '{1}', Message: '{2}'{3}", newItem, checkResult.ResultType, SimpleHtmlToMarkDown(checkResult.Message, slackMarkDown), Environment.NewLine); + sb.AppendFormat("\t{0}Result: '{1}'", newItem, checkResult.ResultType); + + // With summary logging, only record details of warnings or errors + if (checkResult.ResultType != StatusResultType.Success || verbosity == HealthCheckNotificationVerbosity.Detailed) + { + sb.AppendFormat(", Message: '{0}'", SimpleHtmlToMarkDown(checkResult.Message, slackMarkDown)); + } + + sb.AppendLine(Environment.NewLine); } } return sb.ToString(); } - internal string ResultsAsHtml() + internal string ResultsAsHtml(HealthCheckNotificationVerbosity verbosity) { var mark = new Markdown(); - var html = mark.Transform(ResultsAsMarkDown()); + var html = mark.Transform(ResultsAsMarkDown(verbosity)); html = ApplyHtmlHighlighting(html); return html; } @@ -130,7 +139,7 @@ namespace Umbraco.Web.HealthCheck private string ApplyHtmlHighlightingForStatus(string html, StatusResultType status, string color) { return html - .Replace("Result: '" + status + "'", "Result " + status + ""); + .Replace("Result: '" + status + "'", "Result: " + status + ""); } private string SimpleHtmlToMarkDown(string html, bool slackMarkDown = false) diff --git a/src/Umbraco.Web/Scheduling/HealthCheckNotifier.cs b/src/Umbraco.Web/Scheduling/HealthCheckNotifier.cs index 08bb3663b1..e0ca48fb8c 100644 --- a/src/Umbraco.Web/Scheduling/HealthCheckNotifier.cs +++ b/src/Umbraco.Web/Scheduling/HealthCheckNotifier.cs @@ -70,25 +70,27 @@ namespace Umbraco.Web.Scheduling results.LogResults(); // Send to email address if configured - if (healthCheckConfig.NotificationSettings.EmailSettings != null && string.IsNullOrEmpty(healthCheckConfig.NotificationSettings.EmailSettings.RecipientEmail) == false) + var emailNotificationSettings = healthCheckConfig.NotificationSettings.EmailSettings; + if (emailNotificationSettings != null && string.IsNullOrEmpty(emailNotificationSettings.RecipientEmail) == false) { using (var client = new SmtpClient()) using (var mailMessage = new MailMessage()) { - mailMessage.To.Add(healthCheckConfig.NotificationSettings.EmailSettings.RecipientEmail); + mailMessage.To.Add(emailNotificationSettings.RecipientEmail); mailMessage.Body = string.Format("

Results of the scheduled Umbraco Health Checks run on {0} at {1} are as follows:

{2}", - DateTime.Now.ToShortDateString(), DateTime.Now.ToShortTimeString(), results.ResultsAsHtml()); - mailMessage.Subject = healthCheckConfig.NotificationSettings.EmailSettings.Subject; + DateTime.Now.ToShortDateString(), DateTime.Now.ToShortTimeString(), results.ResultsAsHtml(emailNotificationSettings.Verbosity)); + mailMessage.Subject = emailNotificationSettings.Subject; mailMessage.IsBodyHtml = true; await client.SendMailAsync(mailMessage); } } - // send Slack Incoming Webhook if configured - if (healthCheckConfig.NotificationSettings.SlackSettings != null && string.IsNullOrEmpty(healthCheckConfig.NotificationSettings.SlackSettings.WebHookUrl) == false) + // Send Slack incoming webhook if configured + var slackNotificationSettings = healthCheckConfig.NotificationSettings.SlackSettings; + if (slackNotificationSettings != null && string.IsNullOrEmpty(slackNotificationSettings.WebHookUrl) == false) { - var slackClient = new SlackClient(healthCheckConfig.NotificationSettings.SlackSettings.WebHookUrl); + var slackClient = new SlackClient(slackNotificationSettings.WebHookUrl); var icon = Emoji.Warning; if (results.AllChecksSuccessful) @@ -98,10 +100,10 @@ namespace Umbraco.Web.Scheduling var slackMessage = new SlackMessage { - Channel = healthCheckConfig.NotificationSettings.SlackSettings.Channel, - Text = results.ResultsAsMarkDown(true), + Channel = slackNotificationSettings.Channel, + Text = results.ResultsAsMarkDown(slackNotificationSettings.Verbosity, true), IconEmoji = icon, - Username = healthCheckConfig.NotificationSettings.SlackSettings.UserName + Username = slackNotificationSettings.UserName }; slackClient.Post(slackMessage); }