透前一篇: 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)); | |
} | |
} | |
} |
接下來執行,即可看見每一個服務結果。
若您的團隊已經有既有的監控系統,您可以自己客製 CreateHealthCheckResponse,以符合監控服務需求。倘若有相關管理人員進行監控,你可以在下一篇學習如何產生圖形化介面,方便閱讀。
0 留言