透前一篇: Health Checks 監控 SQL Server, WebAPI 與 Redis 健康狀態, 你大概已經知道如何監控不同的服務,但總會懷疑為什麼只能取的整體的狀態態,我們能不能看到每一個服務的狀態呢? 答案是肯定的,本篇文章將簡單介紹如何自訂 Health Checks Response,讓所有的服務運作情況一目了然!


那有美美的圖形介面給老闆看? 答案是有的,在下一篇:ASP.NET Core Health Checks UI 圖形化介面呈現服務健康狀態 會詳細說明。






HealthChecks 內有個 HealthReport 物件存有整體狀態(Status)、整體執行時間 (TotalDuration) 與相依服務的狀態 (HealthReportEntry)。每一個 Entry 內有各自的資料(Data)、狀態(Status)、執行時間(Duration)、標籤(Tags)、例外(Exception)、描述(Description)。我們先建立自訂 Response,如下列程式碼:



namespace HealthCheckDemo.Messages
{
public class HealthCheckResponse
{
public string Status { get; set; }
public string TotalDuration { get; set; }
public DependencyService[] DependencyServices { get; set; }
}
public class DependencyService
{
public string Key { get; set; }
public string Status { get; set; }
public string Duration { get; set; }
public string Tags { get; set; }
public string Exception { get; set; }
}
}




在 Startup.cs 內新增一個方法 CreateHealthCheckResponse,內容如下:


private Task CreateHealthCheckResponse(HttpContext httpContext, HealthReport result)
{
httpContext.Response.ContentType = "application/json";
var response = new HealthCheckResponse()
{
Status = result.Status.ToString(),
TotalDuration = result.TotalDuration.TotalSeconds.ToString("0:0.00"),
DependencyServices = result.Entries.Select(service => new DependencyService()
{
Key = service.Key,
Duration = service.Value.Duration.TotalSeconds.ToString("0:0.00"),
Exception = service.Value.Exception?.Message,
Status = service.Value.Status.ToString(),
Tags = string.Join(",", service.Value.Tags?.ToArray())
}).ToArray()
};
return httpContext.Response.WriteAsync(JsonConvert.SerializeObject(response, Formatting.Indented));
}




回到 Startup.cs 的 Configure 方法,加上剛剛自訂 HealthCheck Response,更改程式碼如下:





整體程式碼樣貌如下:


using HealthCheckDemo.Messages;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace HealthCheckDemo
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
var redisString = "";
services.AddDistributedRedisCache(options =>
{
options.InstanceName = "";
options.Configuration = redisString;
});
var connectionString = Configuration.GetConnectionString("BloggingDatabase");
var weatherServiceUri = "https://localhost:44385";
services.AddHealthChecks()
.AddSqlServer(connectionString)
.AddRedis(redisString)
.AddUrlGroup(new Uri($"{weatherServiceUri}/weatherforecast"), "Weather API Health Check", HealthStatus.Degraded, timeout: new System.TimeSpan(0,0,3));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHealthChecks("/health", new HealthCheckOptions()
{
ResponseWriter = CreateHealthCheckResponse
});
});
}
private Task CreateHealthCheckResponse(HttpContext httpContext, HealthReport result)
{
httpContext.Response.ContentType = "application/json";
var response = new HealthCheckResponse()
{
Status = result.Status.ToString(),
TotalDuration = result.TotalDuration.TotalSeconds.ToString("0:0.00"),
DependencyServices = result.Entries.Select(service => new DependencyService()
{
Key = service.Key,
Duration = service.Value.Duration.TotalSeconds.ToString("0:0.00"),
Exception = service.Value.Exception?.Message,
Status = service.Value.Status.ToString(),
Tags = string.Join(",", service.Value.Tags?.ToArray())
}).ToArray()
};
return httpContext.Response.WriteAsync(JsonConvert.SerializeObject(response, Formatting.Indented));
}
}
}
view raw Startup.cs hosted with ❤ by GitHub




接下來執行,即可看見每一個服務結果。




若您的團隊已經有既有的監控系統,您可以自己客製 CreateHealthCheckResponse,以符合監控服務需求。倘若有相關管理人員進行監控,你可以在下一篇學習如何產生圖形化介面,方便閱讀。