feat: 格式化健康检查邮件

This commit is contained in:
Argo Zhang 2020-02-24 00:16:38 +08:00
parent 9fe03299a4
commit 8c38717f73
No known key found for this signature in database
GPG Key ID: 152E398953DDF19F
7 changed files with 224 additions and 11 deletions

View File

@ -6,7 +6,7 @@
<ItemGroup>
<PackageReference Include="Bootstrap.Security.DataAccess" Version="3.1.1" />
<PackageReference Include="Bootstrap.Security.Mvc" Version="3.1.1" />
<PackageReference Include="Bootstrap.Security.Mvc" Version="3.1.2-beta01" />
<PackageReference Include="Longbow" Version="3.1.0" />
<PackageReference Include="Longbow.AlipayAuth" Version="3.1.0" />
<PackageReference Include="Longbow.Cache" Version="3.1.2-beta-02" />

View File

@ -6,7 +6,7 @@
<ItemGroup>
<PackageReference Include="Bootstrap.Security.DataAccess" Version="3.1.1" />
<PackageReference Include="Bootstrap.Security.Mvc" Version="3.1.1" />
<PackageReference Include="Bootstrap.Security.Mvc" Version="3.1.2-beta01" />
<PackageReference Include="Longbow" Version="3.1.0" />
<PackageReference Include="Longbow.Cache" Version="3.1.2-beta-02" />
<PackageReference Include="Longbow.Data" Version="3.1.0" />

View File

@ -1,7 +1,12 @@
using Bootstrap.Client.Extensions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using System;
using System.IO;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace Bootstrap.Client.Controllers.Api
@ -30,12 +35,13 @@ namespace Bootstrap.Client.Controllers.Api
/// 邮件发送健康检查方法
/// </summary>
/// <param name="config"></param>
/// <param name="env"></param>
/// <param name="message"></param>
/// <returns></returns>
[HttpPost]
public async Task<bool> Healths([FromServices]IConfiguration config, [FromBody]string message)
public async Task<bool> Healths([FromServices]IConfiguration config, [FromServices]IWebHostEnvironment env, [FromBody]string message)
{
return await SendMailAsync(config, "Healths Report", message);
return await SendMailAsync(config, "Healths Report", message.FormatHealths(env.WebRootPath));
}
/// <summary>

View File

@ -1,9 +1,12 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
@ -22,6 +25,70 @@ namespace Bootstrap.Client.Extensions
message.Push();
return Task.FromResult(true);
}
/// <summary>
/// 格式化
/// </summary>
/// <param name="message"></param>
/// <param name="webRootPath"></param>
/// <returns></returns>
public static string FormatHealths(this string message, string webRootPath)
{
var cate = new Dictionary<string, string>()
{
["db"] = "数据库",
["file"] = "组件文件",
["mem"] = "内存",
["Gitee"] = "Gitee 接口",
["gc"] = "垃圾回收器",
["dotnet-runtime"] = "运行时",
["environment"] = "环境变量"
};
var state = new Dictionary<string, string>()
{
{ "0", "不健康" },
{ "1", "亚健康" },
{ "2", "健康" }
};
var styleFile = System.IO.File.ReadAllText(Path.Combine(webRootPath, "html\\healths.html".ReplaceOSPlatformPath()));
var itemTemplate = System.IO.File.ReadAllText(Path.Combine(webRootPath, "html\\item.html".ReplaceOSPlatformPath()));
var trTemplate = "<tr><td>{0}</td><td>{1}</td></tr>";
var sb = new StringBuilder();
sb.Append(styleFile);
var root = JsonDocument.Parse(message).RootElement;
var items = root.GetProperty("Keys").EnumerateArray();
foreach (var item in items)
{
var itemName = item.GetString();
// 通过 itemName 读取检查项明细内容
var data = root.GetProperty("Report").GetProperty("Entries").GetProperty(itemName);
var rowData = new StringBuilder();
foreach (var row in data.GetProperty("Data").EnumerateObject())
{
rowData.AppendFormat(trTemplate, row.Name, row.Value.GetRawText().Replace("\\r\\n", "<br>").Replace("\\n", "<br>"));
}
sb.Append(string.Format(itemTemplate, cate[itemName], data.GetProperty("Duration").GetString(), state[data.GetProperty("Status").GetRawText()], rowData.ToString()));
}
return sb.ToString();
}
}
/// <summary>
/// 消息格式枚举
/// </summary>
public enum MessageFormat
{
/// <summary>
/// 程序异常
/// </summary>
Exception,
/// <summary>
/// 健康检查结果
/// </summary>
Healths
}
/// <summary>
@ -120,16 +187,19 @@ namespace Bootstrap.Client.Extensions
{
var content = new StringBuilder();
SmtpClient? sender = null;
string from = "";
string to = "";
string title = "";
MailMessage? mail = null;
foreach (var msg in messages)
{
if (mail == null)
{
mail = new MailMessage(msg.From, msg.To)
{
Subject = msg.Title,
IsBodyHtml = true
};
}
if (sender == null)
{
from = msg.From;
to = msg.To;
title = msg.Title;
sender = new SmtpClient(msg.Host)
{
Credentials = new NetworkCredential(msg.From, msg.Password),
@ -141,7 +211,11 @@ namespace Bootstrap.Client.Extensions
// 合并消息
content.AppendLine(msg.Message);
}
if (sender != null) await sender.SendMailAsync(from, to, title, content.ToString());
if (sender != null && mail != null)
{
mail.Body = content.ToString();
await sender.SendMailAsync(mail);
}
}
}
}

View File

@ -0,0 +1,49 @@
<style>
.header {
display: flex;
font-weight: 700;
}
.header span:first-child {
flex: 1 1 auto;
}
.header span:nth-child(2) {
min-width: 200px;
}
table {
border-collapse: collapse;
width: 100%;
background-color: #fff;
font-size: 14px;
margin-bottom: 45px;
line-height: 1.5em;
}
th {
text-align: left;
white-space: nowrap;
font-weight: 700;
border-bottom: 1px solid #dcdfe6;
padding: 15px;
max-width: 250px;
}
td {
color: #606266;
}
td,
td {
border-bottom: 1px solid #dcdfe6;
padding: 15px;
max-width: 250px;
}
td:first-child,
th:first-child {
padding-left: 10px;
}
</style>
<h2>健康检查结果</h2>

View File

@ -0,0 +1,16 @@
<div class="header">
<span>{0}</span>
<span>耗时: {1}</span>
<span>状态: {2}</span>
</div>
<table>
<thead>
<tr>
<th>检查项</th>
<th>检查值</th>
</tr>
</thead>
<tbody>
{3}
</tbody>
</table>

View File

@ -0,0 +1,68 @@
<style>
.header {
display: flex;
font-weight: 700;
}
.header span:first-child {
flex: 1 1 auto;
}
.header span:nth-child(2) {
min-width: 200px;
}
table {
border-collapse: collapse;
width: 100%;
background-color: #fff;
font-size: 14px;
margin-bottom: 45px;
line-height: 1.5em;
}
th {
text-align: left;
white-space: nowrap;
font-weight: 700;
border-bottom: 1px solid #dcdfe6;
padding: 15px;
max-width: 250px;
}
td {
color: #606266;
}
td,
td {
border-bottom: 1px solid #dcdfe6;
padding: 15px;
max-width: 250px;
}
td:first-child,
th:first-child {
padding-left: 10px;
}
</style>
<h2>健康检查结果</h2>
<div class="header">
<span>数据库</span>
<span>耗时: 00:00:00.0068991</span>
<span>状态: 健康</span>
</div>
<table>
<thead>
<tr>
<th>检查项</th>
<th>检查值</th>
</tr>
</thead>
<tbody>
<tr>
<td>ConnectionString</td>
<td>"Data Source=BootstrapAdmin.db;"</td>
</tr>
</tbody>
</table>