Skip to content

Commit

Permalink
Add OC.HealthChecks.Abstractions, and health Checks options to show d…
Browse files Browse the repository at this point in the history
…etails (#13590)

Co-authored-by: Zoltán Lehóczky <zoltan.lehoczky@lombiq.com>
  • Loading branch information
hishamco and Piedone committed Apr 21, 2024
1 parent fcd8266 commit 5db4793
Show file tree
Hide file tree
Showing 14 changed files with 187 additions and 26 deletions.
7 changes: 7 additions & 0 deletions OrchardCore.sln
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Notifications.C
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Notifications", "src\OrchardCore.Modules\OrchardCore.Notifications\OrchardCore.Notifications.csproj", "{19594A96-A033-4820-820B-C6186D00D507}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchardCore.HealthChecks.Abstractions", "src\OrchardCore\OrchardCore.HealthChecks.Abstractions\OrchardCore.HealthChecks.Abstractions.csproj", "{91CED599-45B1-474D-A7F2-231BF857A5F2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Seo.Abstractions", "src\OrchardCore\OrchardCore.Seo.Abstractions\OrchardCore.Seo.Abstractions.csproj", "{C61CC748-39BD-4900-9FEE-A2483259573D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Sms.Abstractions", "src\OrchardCore\OrchardCore.Sms.Abstractions\OrchardCore.Sms.Abstractions.csproj", "{2D93F509-1FB3-4E22-92F0-588D0EFBA921}"
Expand Down Expand Up @@ -1334,6 +1336,10 @@ Global
{19594A96-A033-4820-820B-C6186D00D507}.Debug|Any CPU.Build.0 = Debug|Any CPU
{19594A96-A033-4820-820B-C6186D00D507}.Release|Any CPU.ActiveCfg = Release|Any CPU
{19594A96-A033-4820-820B-C6186D00D507}.Release|Any CPU.Build.0 = Release|Any CPU
{91CED599-45B1-474D-A7F2-231BF857A5F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91CED599-45B1-474D-A7F2-231BF857A5F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91CED599-45B1-474D-A7F2-231BF857A5F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91CED599-45B1-474D-A7F2-231BF857A5F2}.Release|Any CPU.Build.0 = Release|Any CPU
{C61CC748-39BD-4900-9FEE-A2483259573D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C61CC748-39BD-4900-9FEE-A2483259573D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C61CC748-39BD-4900-9FEE-A2483259573D}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -1605,6 +1611,7 @@ Global
{307AA9CB-D62E-4E30-B715-53E3BF535D94} = {F23AC6C2-DE44-4699-999D-3C478EF3D691}
{2A6E7DF9-E417-42F8-94F7-0060E252E4D6} = {F23AC6C2-DE44-4699-999D-3C478EF3D691}
{19594A96-A033-4820-820B-C6186D00D507} = {A066395F-6F73-45DC-B5A6-B4E306110DCE}
{91CED599-45B1-474D-A7F2-231BF857A5F2} = {F23AC6C2-DE44-4699-999D-3C478EF3D691}
{C61CC748-39BD-4900-9FEE-A2483259573D} = {F23AC6C2-DE44-4699-999D-3C478EF3D691}
{2D93F509-1FB3-4E22-92F0-588D0EFBA921} = {F23AC6C2-DE44-4699-999D-3C478EF3D691}
{CBF6DB53-FD0C-47F8-9E60-A1D247ACFD05} = {A066395F-6F73-45DC-B5A6-B4E306110DCE}
Expand Down
3 changes: 2 additions & 1 deletion src/OrchardCore.Cms.Web/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,8 @@
// "DisableNotificationHtmlBodySanitizer": false
//},
//"OrchardCore_HealthChecks": {
// "Url": "/health/live"
// "Url": "/health/live",
// "ShowDetails": true
//},
//"OrchardCore_Email_Smtp": {
// "DefaultSender": "",
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace OrchardCore.HealthChecks.Models;

/// <summary>
/// Represents a health check entry for each health provider that could be displayed in the <see cref="HealthCheckResponse"/>.
/// </summary>
public class HealthCheckEntry
{
/// <summary>
/// Gets or sets the health check name.
/// </summary>
public string Name { get; set; }

/// <summary>
/// Gets or sets the health check status.
/// </summary>
public string Status { get; set; }

/// <summary>
/// Gets or sets the health check description.
/// </summary>
public string Description { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;

namespace OrchardCore.HealthChecks.Models;

/// <summary>
/// Represents a health check response to be displayed in the JSON result when the health checks endpoint hit.
/// </summary>
public class HealthCheckResponse
{
/// <summary>
/// Gets or sets the overall health checks status.
/// </summary>
public string Status { get; set; }

/// <summary>
/// Gets or sets the overall health checks duration.
/// </summary>
public TimeSpan Duration { get; set; }

/// <summary>
/// Gets or sets the health check entries.
/// </summary>
public IEnumerable<HealthCheckEntry> HealthChecks { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\OrchardCore\OrchardCore.HealthChecks.Abstractions\OrchardCore.HealthChecks.Abstractions.csproj" />
<ProjectReference Include="..\..\OrchardCore\OrchardCore.Module.Targets\OrchardCore.Module.Targets.csproj" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Linq;
using System.Net.Mime;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using OrchardCore.HealthChecks.Models;

namespace OrchardCore.HealthChecks.Services;

public class DefaultHealthChecksResponseWriter : IHealthChecksResponseWriter
{
public async Task WriteResponseAsync(HttpContext context, HealthReport report)
{
var response = new HealthCheckResponse
{
Status = report.Status.ToString(),
Duration = report.TotalDuration,
HealthChecks = report.Entries.Select(item => new HealthCheckEntry
{
Name = item.Key,
Status = item.Value.Status.ToString(),
Description = item.Value.Description
})
};

context.Response.ContentType = MediaTypeNames.Application.Json;

await context.Response.WriteAsync(JsonSerializer.Serialize(response));
}
}
37 changes: 31 additions & 6 deletions src/OrchardCore.Modules/OrchardCore.HealthChecks/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Options;
using OrchardCore.Environment.Shell.Configuration;
using OrchardCore.HealthChecks.Services;
using OrchardCore.Modules;

namespace OrchardCore.HealthChecks
Expand All @@ -17,17 +21,38 @@ public Startup(IShellConfiguration shellConfiguration)
_shellConfiguration = shellConfiguration;
}

public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider)
public override void ConfigureServices(IServiceCollection services)
{
var healthCheckOptions = serviceProvider.GetService<IOptions<HealthChecksOptions>>().Value;
services.AddScoped<IHealthChecksResponseWriter, DefaultHealthChecksResponseWriter>();
services.AddHealthChecks();

routes.MapHealthChecks(healthCheckOptions.Url);
services.Configure<HealthChecksOptions>(_shellConfiguration.GetSection("OrchardCore_HealthChecks"));
}

public override void ConfigureServices(IServiceCollection services)
public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider)
{
services.AddHealthChecks();
services.Configure<HealthChecksOptions>(_shellConfiguration.GetSection("OrchardCore_HealthChecks"));
var healthChecksOptions = serviceProvider.GetService<IOptions<HealthChecksOptions>>().Value;

if (healthChecksOptions.ShowDetails)
{
var healthChecksResponseWriter = serviceProvider.GetService<IHealthChecksResponseWriter>();

app.UseHealthChecks(healthChecksOptions.Url, new HealthCheckOptions
{
AllowCachingResponses = false,
ResultStatusCodes =
{
[HealthStatus.Healthy] = StatusCodes.Status200OK,
[HealthStatus.Degraded] = StatusCodes.Status200OK,
[HealthStatus.Unhealthy] = StatusCodes.Status200OK
},
ResponseWriter = healthChecksResponseWriter.WriteResponseAsync
});
}
else
{
app.UseHealthChecks(healthChecksOptions.Url);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ namespace OrchardCore.Redis.HealthChecks;
[RequireFeatures("OrchardCore.HealthChecks")]
public class Startup : StartupBase
{
// The order of this startup configuration should be greater than zero to register the Redis check early,
// so the health check can be reported alongside with other health checks in the system.
public override int Order => 100;

public override void ConfigureServices(IServiceCollection services)
{
services
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ public RedisDatabaseFactory(IHostApplicationLifetime lifetime, ILogger<RedisData
catch (Exception e)
{
_logger.LogError(e, "Unable to connect to Redis.");
throw;
return null;
}
})).Value;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace OrchardCore.HealthChecks;

/// <summary>
/// Represents options for health checks.
/// </summary>
public class HealthChecksOptions
{
/// <summary>
/// Gets or sets the health check URL. Default to "/health/live".
/// </summary>
public string Url { get; set; } = "/health/live";

/// <summary>
/// Gets or sets a value indicating whether to show the detailed information (name, status and description) for the checks dependency or not. Defaults to <see langword="false"/>.
/// </summary>
public bool ShowDetails { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<RootNamespace>OrchardCore.HealthChecks</RootNamespace>
<!-- NuGet properties-->
<Title>OrchardCore Health Chekcs Abstractions</Title>
<Description>
$(OCCMSDescription)

Abstractions for health checks
</Description>
<PackageTags>$(PackageTags) OrchardCore Framework Health Checks Abstractions</PackageTags>
</PropertyGroup>

<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Diagnostics.HealthChecks;

namespace OrchardCore.HealthChecks.Services;

public interface IHealthChecksResponseWriter
{
Task WriteResponseAsync(HttpContext context, HealthReport report);
}
21 changes: 20 additions & 1 deletion src/docs/reference/modules/HealthChecks/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Health Check (`OrchardCore.HealthChecks`)
# Health Checks (`OrchardCore.HealthChecks`)

This module enables the health checks feature from ASP.NET Core.

Expand All @@ -9,3 +9,22 @@ The health check endpoint is available at `/health/live` for each tenant that n
## Extending health checks

More information about health checks in ASP.NET Core can be found here: <https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks>

## Health Checks Configuration

The following configurations are available and can be customized:

```json
"OrchardCore_HealthChecks": {
"Url": "/health/live",
"ShowDetails": true
},
```

The supported extensions described as following:

| Extension | Description |
| --- | --- |
| `Url` | The relative URL of the health checks endpoint |
| `ShowDetails` | Whether or not to display a detailed information about each health check provider registered in the system, this including: name, description and status. |

0 comments on commit 5db4793

Please sign in to comment.