public async Task ReportAsync(ReportState state, string slackChannel, string slackSecret, bool restoreCommandSlackOnlyOnError, string slackTitle) { if (string.IsNullOrWhiteSpace(slackChannel) || string.IsNullOrWhiteSpace(slackSecret)) { return; } if (restoreCommandSlackOnlyOnError && !state.Status.HasFlag(ReportStatus.Warning) && !state.Status.HasFlag(ReportStatus.Error)) { return; } string shell = SlackShell(state); var bucket = GetBucketName(state, slackTitle); var msgRoot = new SlackMessage { Channel = slackChannel, Text = $"{shell} *{bucket}* : {state.Restored.Count}/{state.TotalProcessed} db in {state.TotalTime.HumanizedTimeSpan()}", }; var response = await _slackClient.SendSlackMessageAsync(msgRoot, slackSecret); var subMsg = new SlackMessage { Channel = slackChannel, Text = $"Details for {bucket}", ThreadTs = response.Ts, Attachments = new List <Attachment>() }; int fullRestored = 0; int diffRestored = 0; int logRestored = 0; int dropped = 0; foreach (var ri in state.Restored) { fullRestored += ri.StatsFullRestored; diffRestored += ri.StatsDiffRestored; logRestored += ri.StatsLogRestored; dropped += ri.StatsDropped; } var restored = new List <string>(); if (fullRestored != 0) { restored.Add(fullRestored + " FULL"); } if (diffRestored != 0) { restored.Add(diffRestored + " DIFF"); } if (logRestored != 0) { restored.Add(logRestored + " LOG"); } if (dropped != 0) { restored.Add(dropped + " DROPs"); } subMsg.Attachments.Add(new Attachment { Color = AlertLevel.Info.ToSlackColor(), Title = $"Details :", Fields = new[] { new Field { Value = $"AVG : {(state.AvgRpo != null ? state.AvgRpo.Value.HumanizedTimeSpan() : "none")}", Short = true }, new Field { Value = $"Processed in : {state.TotalTime.HumanizedTimeSpan()}", Short = true }, new Field { Value = $" MAX : {(state.MaxRpo != null ? state.MaxRpo.Value.HumanizedTimeSpan() : "none")}", Short = true }, new Field { Value = $"Mode : {state.Mode}", Short = true }, new Field { Value = string.Join(", ", restored), Short = true }, new Field { Value = $"{state.Restored.Count}/{state.TotalProcessed} restored successfully", Short = true } } }); if (state.RpoOutliers.Count != 0) { subMsg.Attachments.Add(new Attachment { Color = AlertLevel.Warning.ToSlackColor(), Title = $"RPO Outliers :", Fields = state.RpoOutliers.Select(b => new Field { Title = b.Name, Value = b.Rpo.HumanizedTimeSpan(), Short = true }).ToArray() }); } if (state.DuplicatesExcluded.Count != 0) { subMsg.Attachments.Add(new Attachment { Color = AlertLevel.Warning.ToSlackColor(), Title = $"Duplicated databases :", Fields = state.DuplicatesExcluded.Select(b => new Field { Title = b.count + " x " + b.name, Value = "Excluding : " + Environment.NewLine + string.Join(Environment.NewLine, b.excluded.Select(i => i.FullName)), Short = false }).ToArray() }); } if (state.BackupNotFoundDbExists.Count != 0) { subMsg.Attachments.Add(new Attachment { Color = AlertLevel.Warning.ToSlackColor(), Title = $"Database exists but no backup found :", Fields = state.BackupNotFoundDbExists.Select(b => new Field { Value = b.Name, Short = true }).ToArray() }); } if (state.MissingFull.Count != 0) { subMsg.Attachments.Add(new Attachment { Color = AlertLevel.Info.ToSlackColor(), Title = $"Source folder exists but no backup found :", Fields = state.MissingFull .GroupBy(i => i.Path?.Root.Name ?? "") .Select(i => new Field { Title = i.Key + " :", Value = string.Join(Environment.NewLine, i.Select(k => k.Path.Name)), Short = false }).ToArray() }); } if (state.MissingFullMoreThan24Hours.Count != 0) { subMsg.Attachments.Add(new Attachment { Color = AlertLevel.Warning.ToSlackColor(), Title = $"Source folder exists for more than 24h but no backup found :", Fields = state.MissingFullMoreThan24Hours .GroupBy(i => i.Path?.Root.Name ?? "") .Select(i => new Field { Title = i.Key + " :", Value = string.Join(Environment.NewLine, i.Select(k => k.Path.Name)), Short = false }).ToArray() }); } if (state.Errors.Count != 0) { subMsg.Attachments.Add(new Attachment { Color = AlertLevel.Error.ToSlackColor(), Title = $"Exception while restoring :", Fields = state.Errors .GroupBy(i => i.Item?.BaseDirectoryInfo?.Root.Name ?? "") .Select(i => new Field { Title = i.Key + " :", Value = string.Join(Environment.NewLine, i.Select(k => k.Item.Name + ": " + k.Error)), Short = false }).ToArray() }); } if (state.IntegrityErrors.Any()) { subMsg.Attachments.Add(new Attachment { Color = AlertLevel.Error.ToSlackColor(), Title = $"DBCC CHECKDB Error :", Fields = state.IntegrityErrors .Select(i => new Field { Title = i.Key + " :", Value = string.Join(Environment.NewLine, i.Value), Short = false }).ToArray() }); } await _slackClient.SendSlackMessageAsync(subMsg, slackSecret); }