Updating Health Checks for 2.2
A bunch of small changes and updates for 2.2 focused at making our main scenarios more streamlined and focused. Also adds samples for extensibility we support so far. A list of changes: Clearing baselines for these projects. We didn't ship anything in 2.1 so there should be nothing in the baselines. -- The middleware now uses Map for path matching. This makes the actual `HealthCheckMiddleware` more standalone. This will make it easy to use with Dispatcher/Endpoint Routing in the future. This also manifests by removing Path from HealthCheckOptions - the path is an explicit argument to the UseHealthChecks middelware - this streamlines the design for 3.0. -- Added extensibility for customizing the status codes (aspnet/Home#2584) -- Added extensibility for writing the textual output (aspnet/Home#2583) -- Changed the default output to be `text/plain`. The most common use cases for health checks don't include a detailed status. The existing output format is still available as an option.
This commit is contained in:
Родитель
bf839dadf1
Коммит
47f427d5ac
|
@ -16,6 +16,7 @@
|
|||
<MicrosoftEntityFrameworkCoreInMemoryPackageVersion>2.2.0-preview1-34823</MicrosoftEntityFrameworkCoreInMemoryPackageVersion>
|
||||
<MicrosoftEntityFrameworkCoreRelationalPackageVersion>2.2.0-preview1-34823</MicrosoftEntityFrameworkCoreRelationalPackageVersion>
|
||||
<MicrosoftEntityFrameworkCoreSqlServerPackageVersion>2.2.0-preview1-34823</MicrosoftEntityFrameworkCoreSqlServerPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationCommandLinePackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsConfigurationCommandLinePackageVersion>
|
||||
<MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>
|
||||
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsDependencyInjectionPackageVersion>
|
||||
<MicrosoftExtensionsDiagnosticAdapterPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsDiagnosticAdapterPackageVersion>
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace HealthChecksSample
|
||||
{
|
||||
// Pass in `--scenario basic` at the command line to run this sample.
|
||||
public class BasicStartup
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// Registers required services for health checks
|
||||
services.AddHealthChecks();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
||||
{
|
||||
// This will register the health checks middleware at the URL /health.
|
||||
//
|
||||
// By default health checks will return a 200 with 'Healthy'.
|
||||
// - No health checks are registered by default, the app is healthy if it is reachable
|
||||
// - The default response writer writes the HealthCheckStatus as text/plain content
|
||||
//
|
||||
// This is the simplest way to use health checks, it is suitable for systems
|
||||
// that want to check for 'liveness' of an application.
|
||||
app.UseHealthChecks("/health");
|
||||
|
||||
app.Run(async (context) =>
|
||||
{
|
||||
await context.Response.WriteAsync("Go to /health to see the health status");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
|
||||
namespace HealthChecksSample
|
||||
{
|
||||
// Pass in `--scenario writer` at the command line to run this sample.
|
||||
public class CustomWriterStartup
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// Registers required services for health checks
|
||||
services.AddHealthChecks();
|
||||
|
||||
// This is an example of registering a custom health check as a service.
|
||||
// All IHealthCheck services will be available to the health check service and
|
||||
// middleware.
|
||||
//
|
||||
// We recommend registering all health checks as Singleton services.
|
||||
services.AddSingleton<IHealthCheck, GCInfoHealthCheck>();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
||||
{
|
||||
// This will register the health checks middleware at the URL /health
|
||||
//
|
||||
// This example overrides the HealthCheckResponseWriter to write the health
|
||||
// check result in a totally custom way.
|
||||
app.UseHealthChecks("/health", new HealthCheckOptions()
|
||||
{
|
||||
// This custom writer formats the detailed status as an HTML table.
|
||||
ResponseWriter = WriteResponse,
|
||||
});
|
||||
|
||||
app.Run(async (context) =>
|
||||
{
|
||||
await context.Response.WriteAsync("Go to /health to see the health status");
|
||||
});
|
||||
}
|
||||
|
||||
private static Task WriteResponse(HttpContext httpContext, CompositeHealthCheckResult result)
|
||||
{
|
||||
httpContext.Response.ContentType = "text/html";
|
||||
return httpContext.Response.WriteAsync($@"
|
||||
<html>
|
||||
<body>
|
||||
<h1>
|
||||
Everything is {result.Status}
|
||||
</h1>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><td>Name</td><td>Status</td></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{string.Join("", result.Results.Select(kvp => $"<tr><td>{kvp.Key}</td><td>{kvp.Value.Status}</td></tr>"))}
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
|
||||
namespace HealthChecksSample
|
||||
{
|
||||
// Pass in `--scenario detailed` at the command line to run this sample.
|
||||
public class DetailedStatusStartup
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// Registers required services for health checks
|
||||
services
|
||||
.AddHealthChecks()
|
||||
|
||||
// Registers a custom health check, in this case it will execute an
|
||||
// inline delegate.
|
||||
.AddCheck("GC Info", () =>
|
||||
{
|
||||
// This example will report degraded status if the application is using
|
||||
// more than 1gb of memory.
|
||||
//
|
||||
// Additionally we include some GC info in the reported diagnostics.
|
||||
var allocated = GC.GetTotalMemory(forceFullCollection: false);
|
||||
var data = new Dictionary<string, object>()
|
||||
{
|
||||
{ "Allocated", allocated },
|
||||
{ "Gen0Collections", GC.CollectionCount(0) },
|
||||
{ "Gen1Collections", GC.CollectionCount(1) },
|
||||
{ "Gen2Collections", GC.CollectionCount(2) },
|
||||
};
|
||||
|
||||
// Report degraded status if the allocated memory is >= 1gb (in bytes)
|
||||
var status = allocated >= 1024 * 1024 * 1024 ? HealthCheckStatus.Degraded : HealthCheckStatus.Healthy;
|
||||
|
||||
return Task.FromResult(new HealthCheckResult(
|
||||
status,
|
||||
exception: null,
|
||||
description: "reports degraded status if allocated bytes >= 1gb",
|
||||
data: data));
|
||||
});
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
||||
{
|
||||
// This will register the health checks middleware at the URL /health
|
||||
//
|
||||
// This example overrides the ResponseWriter to include a detailed
|
||||
// status as JSON. Use this response writer (or create your own) to include
|
||||
// detailed diagnostic information for use by a monitoring system.
|
||||
app.UseHealthChecks("/health", new HealthCheckOptions()
|
||||
{
|
||||
ResponseWriter = HealthCheckResponseWriters.WriteDetailedJson,
|
||||
});
|
||||
|
||||
app.Run(async (context) =>
|
||||
{
|
||||
await context.Response.WriteAsync("Go to /health to see the health status");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
|
||||
namespace HealthChecksSample
|
||||
{
|
||||
// This is an example of a custom health check that implements IHealthCheck.
|
||||
// This is the same core logic as the DetailedStatusStartup example.
|
||||
// See CustomWriterStartup to see how this is registered.
|
||||
public class GCInfoHealthCheck : IHealthCheck
|
||||
{
|
||||
public string Name { get; } = "GCInfo";
|
||||
|
||||
public Task<HealthCheckResult> CheckHealthAsync(CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
// This example will report degraded status if the application is using
|
||||
// more than 1gb of memory.
|
||||
//
|
||||
// Additionally we include some GC info in the reported diagnostics.
|
||||
var allocated = GC.GetTotalMemory(forceFullCollection: false);
|
||||
var data = new Dictionary<string, object>()
|
||||
{
|
||||
{ "Allocated", allocated },
|
||||
{ "Gen0Collections", GC.CollectionCount(0) },
|
||||
{ "Gen1Collections", GC.CollectionCount(1) },
|
||||
{ "Gen2Collections", GC.CollectionCount(2) },
|
||||
};
|
||||
|
||||
// Report degraded status if the allocated memory is >= 1gb (in bytes)
|
||||
var status = allocated >= 1024 * 1024 * 1024 ? HealthCheckStatus.Degraded : HealthCheckStatus.Healthy;
|
||||
|
||||
return Task.FromResult(new HealthCheckResult(
|
||||
status,
|
||||
exception: null,
|
||||
description: "reports degraded status if allocated bytes >= 1gb",
|
||||
data: data));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<!-- Used in our tests -->
|
||||
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">netcoreapp2.0;net461</TargetFrameworks>
|
||||
<TargetFrameworks Condition="'$(TargetFrameworks)'==''">netcoreapp2.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="$(MicrosoftExtensionsConfigurationCommandLinePackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="$(MicrosoftAspNetCoreStaticFilesPackageVersion)" />
|
||||
|
|
|
@ -1,23 +1,54 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace HealthChecksSample
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
private static readonly Dictionary<string, Type> _scenarios;
|
||||
|
||||
static Program()
|
||||
{
|
||||
_scenarios = new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "", typeof(BasicStartup) },
|
||||
{ "basic", typeof(BasicStartup) },
|
||||
{ "detailed", typeof(DetailedStatusStartup) },
|
||||
{ "writer", typeof(CustomWriterStartup) },
|
||||
};
|
||||
}
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
BuildWebHost(args).Run();
|
||||
}
|
||||
|
||||
public static IWebHost BuildWebHost(string[] args) =>
|
||||
new WebHostBuilder()
|
||||
public static IWebHost BuildWebHost(string[] args)
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.AddEnvironmentVariables(prefix: "ASPNETCORE_")
|
||||
.AddCommandLine(args)
|
||||
.Build();
|
||||
|
||||
var scenario = config["scenario"] ?? string.Empty;
|
||||
if (!_scenarios.TryGetValue(scenario, out var startupType))
|
||||
{
|
||||
startupType = typeof(BasicStartup);
|
||||
}
|
||||
|
||||
return new WebHostBuilder()
|
||||
.UseConfiguration(config)
|
||||
.ConfigureLogging(builder =>
|
||||
{
|
||||
builder.AddConsole();
|
||||
})
|
||||
.UseKestrel()
|
||||
.UseStartup<Startup>()
|
||||
.UseStartup(startupType)
|
||||
.Build();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace HealthChecksSample
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddHealthChecks();
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
||||
{
|
||||
app.UseHealthChecks("/health");
|
||||
|
||||
app.Run(async (context) =>
|
||||
{
|
||||
await context.Response.WriteAsync("Hello World!");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="IApplicationBuilder"/> extension methods for the <see cref="HealthCheckMiddleware"/>.
|
||||
/// </summary>
|
||||
public static class HealthCheckApplicationBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a middleware that provides health check status.
|
||||
/// </summary>
|
||||
/// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
|
||||
/// <param name="path">The path on which to provide health check status.</param>
|
||||
/// <returns>A reference to the <paramref name="app"/> after the operation has completed.</returns>
|
||||
/// <remarks>
|
||||
/// The health check middleware will use default settings other than the provided <paramref name="path"/>.
|
||||
/// </remarks>
|
||||
public static IApplicationBuilder UseHealthChecks(this IApplicationBuilder app, PathString path)
|
||||
{
|
||||
if (app == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(app));
|
||||
}
|
||||
|
||||
if (!path.HasValue)
|
||||
{
|
||||
throw new ArgumentException("A URL path must be provided", nameof(path));
|
||||
}
|
||||
|
||||
return app.Map(path, b => b.UseMiddleware<HealthCheckMiddleware>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a middleware that provides health check status.
|
||||
/// </summary>
|
||||
/// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
|
||||
/// <param name="path">The path on which to provide health check status.</param>
|
||||
/// <param name="options">A <see cref="HealthCheckOptions"/> used to configure the middleware.</param>
|
||||
/// <returns>A reference to the <paramref name="app"/> after the operation has completed.</returns>
|
||||
public static IApplicationBuilder UseHealthChecks(this IApplicationBuilder app, PathString path, HealthCheckOptions options)
|
||||
{
|
||||
if (app == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(app));
|
||||
}
|
||||
|
||||
if (!path.HasValue)
|
||||
{
|
||||
throw new ArgumentException("A URL path must be provided", nameof(path));
|
||||
}
|
||||
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
return app.Map(path, b => b.UseMiddleware<HealthCheckMiddleware>(Options.Create(options)));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="IApplicationBuilder"/> extension methods for the <see cref="HealthCheckMiddleware"/>.
|
||||
/// </summary>
|
||||
public static class HealthCheckAppBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a middleware that provides a REST API for requesting health check status.
|
||||
/// </summary>
|
||||
/// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
|
||||
/// <param name="path">The path on which to provide the API.</param>
|
||||
/// <returns>A reference to the <paramref name="app"/> after the operation has completed.</returns>
|
||||
public static IApplicationBuilder UseHealthChecks(this IApplicationBuilder app, PathString path)
|
||||
{
|
||||
app = app ?? throw new ArgumentNullException(nameof(app));
|
||||
|
||||
return app.UseMiddleware<HealthCheckMiddleware>(Options.Create(new HealthCheckOptions()
|
||||
{
|
||||
Path = path
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,14 +2,10 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
|
||||
{
|
||||
|
@ -19,60 +15,62 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
|
|||
private readonly HealthCheckOptions _healthCheckOptions;
|
||||
private readonly IHealthCheckService _healthCheckService;
|
||||
|
||||
public HealthCheckMiddleware(RequestDelegate next, IOptions<HealthCheckOptions> healthCheckOptions, IHealthCheckService healthCheckService)
|
||||
public HealthCheckMiddleware(
|
||||
RequestDelegate next,
|
||||
IOptions<HealthCheckOptions> healthCheckOptions,
|
||||
IHealthCheckService healthCheckService)
|
||||
{
|
||||
if (next == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(next));
|
||||
}
|
||||
|
||||
if (healthCheckOptions == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(healthCheckOptions));
|
||||
}
|
||||
|
||||
if (healthCheckService == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(healthCheckService));
|
||||
}
|
||||
|
||||
_next = next;
|
||||
_healthCheckOptions = healthCheckOptions.Value;
|
||||
_healthCheckService = healthCheckService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process an individual request.
|
||||
/// Processes a request.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="httpContext"></param>
|
||||
/// <returns></returns>
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
public async Task InvokeAsync(HttpContext httpContext)
|
||||
{
|
||||
if (context.Request.Path == _healthCheckOptions.Path)
|
||||
if (httpContext == null)
|
||||
{
|
||||
// Get results
|
||||
var result = await _healthCheckService.CheckHealthAsync(context.RequestAborted);
|
||||
|
||||
// Map status to response code
|
||||
switch (result.Status)
|
||||
{
|
||||
case HealthCheckStatus.Failed:
|
||||
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
|
||||
break;
|
||||
case HealthCheckStatus.Unhealthy:
|
||||
context.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
|
||||
break;
|
||||
case HealthCheckStatus.Degraded:
|
||||
// Degraded doesn't mean unhealthy so we return 200, but the content will contain more details
|
||||
context.Response.StatusCode = StatusCodes.Status200OK;
|
||||
break;
|
||||
case HealthCheckStatus.Healthy:
|
||||
context.Response.StatusCode = StatusCodes.Status200OK;
|
||||
break;
|
||||
default:
|
||||
// This will only happen when we change HealthCheckStatus and we don't update this.
|
||||
Debug.Fail($"Unrecognized HealthCheckStatus value: {result.Status}");
|
||||
throw new InvalidOperationException($"Unrecognized HealthCheckStatus value: {result.Status}");
|
||||
}
|
||||
|
||||
// Render results to JSON
|
||||
var json = new JObject(
|
||||
new JProperty("status", result.Status.ToString()),
|
||||
new JProperty("results", new JObject(result.Results.Select(pair =>
|
||||
new JProperty(pair.Key, new JObject(
|
||||
new JProperty("status", pair.Value.Status.ToString()),
|
||||
new JProperty("description", pair.Value.Description),
|
||||
new JProperty("data", new JObject(pair.Value.Data.Select(p => new JProperty(p.Key, p.Value))))))))));
|
||||
await context.Response.WriteAsync(json.ToString(Formatting.None));
|
||||
throw new ArgumentNullException(nameof(httpContext));
|
||||
}
|
||||
else
|
||||
|
||||
// Get results
|
||||
var result = await _healthCheckService.CheckHealthAsync(httpContext.RequestAborted);
|
||||
|
||||
// Map status to response code - this is customizable via options.
|
||||
if (!_healthCheckOptions.ResultStatusCodes.TryGetValue(result.Status, out var statusCode))
|
||||
{
|
||||
await _next(context);
|
||||
var message =
|
||||
$"No status code mapping found for {nameof(HealthCheckStatus)} value: {result.Status}." +
|
||||
$"{nameof(HealthCheckOptions)}.{nameof(HealthCheckOptions.ResultStatusCodes)} must contain" +
|
||||
$"an entry for {result.Status}.";
|
||||
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
httpContext.Response.StatusCode = statusCode;
|
||||
|
||||
if (_healthCheckOptions.ResponseWriter != null)
|
||||
{
|
||||
await _healthCheckOptions.ResponseWriter(httpContext, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
|
||||
namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
|
||||
{
|
||||
|
@ -10,9 +14,23 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
|
|||
/// </summary>
|
||||
public class HealthCheckOptions
|
||||
{
|
||||
public IDictionary<HealthCheckStatus, int> ResultStatusCodes { get; } = new Dictionary<HealthCheckStatus, int>()
|
||||
{
|
||||
{ HealthCheckStatus.Healthy, StatusCodes.Status200OK },
|
||||
{ HealthCheckStatus.Degraded, StatusCodes.Status200OK },
|
||||
{ HealthCheckStatus.Unhealthy, StatusCodes.Status503ServiceUnavailable },
|
||||
|
||||
// This means that a health check failed, so 500 is appropriate. This is an error.
|
||||
{ HealthCheckStatus.Failed, StatusCodes.Status500InternalServerError },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path at which the Health Check results will be available.
|
||||
/// Gets or sets a delegate used to write the response.
|
||||
/// </summary>
|
||||
public PathString Path { get; set; }
|
||||
/// <remarks>
|
||||
/// The default value is a delegate that will write a minimal <c>text/plain</c> response with the value
|
||||
/// of <see cref="CompositeHealthCheckResult.Status"/> as a string.
|
||||
/// </remarks>
|
||||
public Func<HttpContext, CompositeHealthCheckResult, Task> ResponseWriter { get; set; } = HealthCheckResponseWriters.WriteMinimalPlaintext;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
|
||||
{
|
||||
public static class HealthCheckResponseWriters
|
||||
{
|
||||
public static Task WriteMinimalPlaintext(HttpContext httpContext, CompositeHealthCheckResult result)
|
||||
{
|
||||
if (httpContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(httpContext));
|
||||
}
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(result));
|
||||
}
|
||||
|
||||
httpContext.Response.ContentType = "text/plain";
|
||||
return httpContext.Response.WriteAsync(result.Status.ToString());
|
||||
}
|
||||
|
||||
public static Task WriteDetailedJson(HttpContext httpContext, CompositeHealthCheckResult result)
|
||||
{
|
||||
if (httpContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(httpContext));
|
||||
}
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(result));
|
||||
}
|
||||
|
||||
httpContext.Response.ContentType = "application/json";
|
||||
|
||||
var json = new JObject(
|
||||
new JProperty("status", result.Status.ToString()),
|
||||
new JProperty("results", new JObject(result.Results.Select(pair =>
|
||||
new JProperty(pair.Key, new JObject(
|
||||
new JProperty("status", pair.Value.Status.ToString()),
|
||||
new JProperty("description", pair.Value.Description),
|
||||
new JProperty("data", new JObject(pair.Value.Data.Select(p => new JProperty(p.Key, p.Value))))))))));
|
||||
return httpContext.Response.WriteAsync(json.ToString(Formatting.Indented));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,115 +1,5 @@
|
|||
{
|
||||
"AssemblyIdentity": "Microsoft.AspNetCore.Diagnostics.HealthChecks, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
|
||||
"Types": [
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckMiddleware",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "InvokeAsync",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "context",
|
||||
"Type": "Microsoft.AspNetCore.Http.HttpContext"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Threading.Tasks.Task",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "next",
|
||||
"Type": "Microsoft.AspNetCore.Http.RequestDelegate"
|
||||
},
|
||||
{
|
||||
"Name": "healthCheckOptions",
|
||||
"Type": "Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckOptions>"
|
||||
},
|
||||
{
|
||||
"Name": "healthCheckService",
|
||||
"Type": "Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheckService"
|
||||
}
|
||||
],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckOptions",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_Path",
|
||||
"Parameters": [],
|
||||
"ReturnType": "Microsoft.AspNetCore.Http.PathString",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_Path",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "Microsoft.AspNetCore.Http.PathString"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Builder.HealthCheckAppBuilderExtensions",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"Abstract": true,
|
||||
"Static": true,
|
||||
"Sealed": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "UseHealthChecks",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "app",
|
||||
"Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder"
|
||||
},
|
||||
{
|
||||
"Name": "path",
|
||||
"Type": "Microsoft.AspNetCore.Http.PathString"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,377 +1,5 @@
|
|||
{
|
||||
"AssemblyIdentity": "Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
|
||||
"Types": [
|
||||
{
|
||||
"Name": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Struct",
|
||||
"Sealed": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_Status",
|
||||
"Parameters": [],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckStatus",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_Exception",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.Exception",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_Description",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_Data",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.Collections.Generic.IReadOnlyDictionary<System.String, System.Object>",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Unhealthy",
|
||||
"Parameters": [],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult",
|
||||
"Static": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Unhealthy",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "description",
|
||||
"Type": "System.String"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult",
|
||||
"Static": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Unhealthy",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "description",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "data",
|
||||
"Type": "System.Collections.Generic.IReadOnlyDictionary<System.String, System.Object>"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult",
|
||||
"Static": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Unhealthy",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "exception",
|
||||
"Type": "System.Exception"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult",
|
||||
"Static": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Unhealthy",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "description",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "exception",
|
||||
"Type": "System.Exception"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult",
|
||||
"Static": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Unhealthy",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "description",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "exception",
|
||||
"Type": "System.Exception"
|
||||
},
|
||||
{
|
||||
"Name": "data",
|
||||
"Type": "System.Collections.Generic.IReadOnlyDictionary<System.String, System.Object>"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult",
|
||||
"Static": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Healthy",
|
||||
"Parameters": [],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult",
|
||||
"Static": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Healthy",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "description",
|
||||
"Type": "System.String"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult",
|
||||
"Static": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Healthy",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "description",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "data",
|
||||
"Type": "System.Collections.Generic.IReadOnlyDictionary<System.String, System.Object>"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult",
|
||||
"Static": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Degraded",
|
||||
"Parameters": [],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult",
|
||||
"Static": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Degraded",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "description",
|
||||
"Type": "System.String"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult",
|
||||
"Static": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Degraded",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "description",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "data",
|
||||
"Type": "System.Collections.Generic.IReadOnlyDictionary<System.String, System.Object>"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult",
|
||||
"Static": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Degraded",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "exception",
|
||||
"Type": "System.Exception"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult",
|
||||
"Static": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Degraded",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "description",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "exception",
|
||||
"Type": "System.Exception"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult",
|
||||
"Static": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Degraded",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "description",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "exception",
|
||||
"Type": "System.Exception"
|
||||
},
|
||||
{
|
||||
"Name": "data",
|
||||
"Type": "System.Collections.Generic.IReadOnlyDictionary<System.String, System.Object>"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult",
|
||||
"Static": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "status",
|
||||
"Type": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckStatus"
|
||||
},
|
||||
{
|
||||
"Name": "exception",
|
||||
"Type": "System.Exception"
|
||||
},
|
||||
{
|
||||
"Name": "description",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "data",
|
||||
"Type": "System.Collections.Generic.IReadOnlyDictionary<System.String, System.Object>"
|
||||
}
|
||||
],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckStatus",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Enumeration",
|
||||
"Sealed": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "Unknown",
|
||||
"Parameters": [],
|
||||
"GenericParameter": [],
|
||||
"Literal": "0"
|
||||
},
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "Failed",
|
||||
"Parameters": [],
|
||||
"GenericParameter": [],
|
||||
"Literal": "1"
|
||||
},
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "Unhealthy",
|
||||
"Parameters": [],
|
||||
"GenericParameter": [],
|
||||
"Literal": "2"
|
||||
},
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "Degraded",
|
||||
"Parameters": [],
|
||||
"GenericParameter": [],
|
||||
"Literal": "3"
|
||||
},
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "Healthy",
|
||||
"Parameters": [],
|
||||
"GenericParameter": [],
|
||||
"Literal": "4"
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Interface",
|
||||
"Abstract": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_Name",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "CheckHealthAsync",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "cancellationToken",
|
||||
"Type": "System.Threading.CancellationToken",
|
||||
"DefaultValue": "default(System.Threading.CancellationToken)"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Threading.Tasks.Task<Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult>",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
}
|
||||
]
|
||||
}
|
|
@ -11,15 +11,10 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
|
|||
/// A simple implementation of <see cref="IHealthCheck"/> which uses a provided delegate to
|
||||
/// implement the check.
|
||||
/// </summary>
|
||||
public class HealthCheck : IHealthCheck
|
||||
public sealed class HealthCheck : IHealthCheck
|
||||
{
|
||||
private readonly Func<CancellationToken, Task<HealthCheckResult>> _check;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the health check, which should indicate the component being checked.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of <see cref="HealthCheck"/> from the specified <paramref name="name"/> and <paramref name="check"/>.
|
||||
/// </summary>
|
||||
|
@ -27,10 +22,15 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
|
|||
/// <param name="check">A delegate which provides the code to execute when the health check is run.</param>
|
||||
public HealthCheck(string name, Func<CancellationToken, Task<HealthCheckResult>> check)
|
||||
{
|
||||
Name = name;
|
||||
_check = check;
|
||||
Name = name ?? throw new ArgumentNullException(nameof(name));
|
||||
_check = check ?? throw new ArgumentNullException(nameof(check));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the health check, which should indicate the component being checked.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Runs the health check, returning the status of the component being checked.
|
||||
/// </summary>
|
||||
|
|
|
@ -22,8 +22,22 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
/// <returns>The <see cref="IHealthChecksBuilder"/>.</returns>
|
||||
public static IHealthChecksBuilder AddCheck(this IHealthChecksBuilder builder, string name, Func<CancellationToken, Task<HealthCheckResult>> check)
|
||||
{
|
||||
builder.Services.AddSingleton<IHealthCheck>(services => new HealthCheck(name, check));
|
||||
return builder;
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
if (name == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(name));
|
||||
}
|
||||
|
||||
if (check == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(check));
|
||||
}
|
||||
|
||||
return builder.AddCheck(new HealthCheck(name, check));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -33,7 +47,46 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
/// <param name="name">The name of the health check, which should indicate the component being checked.</param>
|
||||
/// <param name="check">A delegate which provides the code to execute when the health check is run.</param>
|
||||
/// <returns>The <see cref="IHealthChecksBuilder"/>.</returns>
|
||||
public static IHealthChecksBuilder AddCheck(this IHealthChecksBuilder builder, string name, Func<Task<HealthCheckResult>> check) =>
|
||||
builder.AddCheck(name, _ => check());
|
||||
public static IHealthChecksBuilder AddCheck(this IHealthChecksBuilder builder, string name, Func<Task<HealthCheckResult>> check)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
if (name == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(name));
|
||||
}
|
||||
|
||||
if (check == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(check));
|
||||
}
|
||||
|
||||
return builder.AddCheck(name, _ => check());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new health check with the implementation.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IHealthChecksBuilder"/> to add the check to.</param>
|
||||
/// <param name="check">An <see cref="IHealthCheck"/> implementation.</param>
|
||||
/// <returns>The <see cref="IHealthChecksBuilder"/>.</returns>
|
||||
public static IHealthChecksBuilder AddCheck(this IHealthChecksBuilder builder, IHealthCheck check)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
if (check == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(check));
|
||||
}
|
||||
|
||||
builder.Services.AddSingleton<IHealthCheck>(check);
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,334 +1,5 @@
|
|||
{
|
||||
"AssemblyIdentity": "Microsoft.Extensions.Diagnostics.HealthChecks, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
|
||||
"Types": [
|
||||
{
|
||||
"Name": "Microsoft.Extensions.DependencyInjection.HealthChecksBuilderAddCheckExtensions",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"Abstract": true,
|
||||
"Static": true,
|
||||
"Sealed": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "AddCheck",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "builder",
|
||||
"Type": "Microsoft.Extensions.Diagnostics.HealthChecks.IHealthChecksBuilder"
|
||||
},
|
||||
{
|
||||
"Name": "name",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "check",
|
||||
"Type": "System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task<Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult>>"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.IHealthChecksBuilder",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "AddCheck",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "builder",
|
||||
"Type": "Microsoft.Extensions.Diagnostics.HealthChecks.IHealthChecksBuilder"
|
||||
},
|
||||
{
|
||||
"Name": "name",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "check",
|
||||
"Type": "System.Func<System.Threading.Tasks.Task<Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult>>"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.IHealthChecksBuilder",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.Extensions.DependencyInjection.HealthCheckServiceCollectionExtensions",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"Abstract": true,
|
||||
"Static": true,
|
||||
"Sealed": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "AddHealthChecks",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "services",
|
||||
"Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.IHealthChecksBuilder",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.Extensions.Diagnostics.HealthChecks.CompositeHealthCheckResult",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_Results",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.Collections.Generic.IReadOnlyDictionary<System.String, Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult>",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_Status",
|
||||
"Parameters": [],
|
||||
"ReturnType": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckStatus",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "results",
|
||||
"Type": "System.Collections.Generic.IReadOnlyDictionary<System.String, Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult>"
|
||||
}
|
||||
],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheck",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"ImplementedInterfaces": [
|
||||
"Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck"
|
||||
],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_Name",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Sealed": true,
|
||||
"Virtual": true,
|
||||
"ImplementedInterface": "Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "CheckHealthAsync",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "cancellationToken",
|
||||
"Type": "System.Threading.CancellationToken",
|
||||
"DefaultValue": "default(System.Threading.CancellationToken)"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Threading.Tasks.Task<Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult>",
|
||||
"Sealed": true,
|
||||
"Virtual": true,
|
||||
"ImplementedInterface": "Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "name",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "check",
|
||||
"Type": "System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task<Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult>>"
|
||||
}
|
||||
],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckService",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"ImplementedInterfaces": [
|
||||
"Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheckService"
|
||||
],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_Checks",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.Collections.Generic.IReadOnlyDictionary<System.String, Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck>",
|
||||
"Sealed": true,
|
||||
"Virtual": true,
|
||||
"ImplementedInterface": "Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheckService",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "CheckHealthAsync",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "cancellationToken",
|
||||
"Type": "System.Threading.CancellationToken",
|
||||
"DefaultValue": "default(System.Threading.CancellationToken)"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Threading.Tasks.Task<Microsoft.Extensions.Diagnostics.HealthChecks.CompositeHealthCheckResult>",
|
||||
"Sealed": true,
|
||||
"Virtual": true,
|
||||
"ImplementedInterface": "Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheckService",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "CheckHealthAsync",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "checks",
|
||||
"Type": "System.Collections.Generic.IEnumerable<Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck>"
|
||||
},
|
||||
{
|
||||
"Name": "cancellationToken",
|
||||
"Type": "System.Threading.CancellationToken",
|
||||
"DefaultValue": "default(System.Threading.CancellationToken)"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Threading.Tasks.Task<Microsoft.Extensions.Diagnostics.HealthChecks.CompositeHealthCheckResult>",
|
||||
"Sealed": true,
|
||||
"Virtual": true,
|
||||
"ImplementedInterface": "Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheckService",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "healthChecks",
|
||||
"Type": "System.Collections.Generic.IEnumerable<Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck>"
|
||||
}
|
||||
],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "healthChecks",
|
||||
"Type": "System.Collections.Generic.IEnumerable<Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck>"
|
||||
},
|
||||
{
|
||||
"Name": "logger",
|
||||
"Type": "Microsoft.Extensions.Logging.ILogger<Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckService>"
|
||||
}
|
||||
],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.Extensions.Diagnostics.HealthChecks.IHealthChecksBuilder",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Interface",
|
||||
"Abstract": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_Services",
|
||||
"Parameters": [],
|
||||
"ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheckService",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Interface",
|
||||
"Abstract": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_Checks",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.Collections.Generic.IReadOnlyDictionary<System.String, Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck>",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "CheckHealthAsync",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "cancellationToken",
|
||||
"Type": "System.Threading.CancellationToken",
|
||||
"DefaultValue": "default(System.Threading.CancellationToken)"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Threading.Tasks.Task<Microsoft.Extensions.Diagnostics.HealthChecks.CompositeHealthCheckResult>",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "CheckHealthAsync",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "checks",
|
||||
"Type": "System.Collections.Generic.IEnumerable<Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck>"
|
||||
},
|
||||
{
|
||||
"Name": "cancellationToken",
|
||||
"Type": "System.Threading.CancellationToken",
|
||||
"DefaultValue": "default(System.Threading.CancellationToken)"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Threading.Tasks.Task<Microsoft.Extensions.Diagnostics.HealthChecks.CompositeHealthCheckResult>",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.TestHost;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
|
||||
{
|
||||
public class HealthCheckMiddlewareSampleTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task BasicStartup()
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.UseStartup<HealthChecksSample.BasicStartup>();
|
||||
|
||||
var server = new TestServer(builder);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/health");
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
Assert.Equal("Healthy", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CustomWriterStartup()
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.UseStartup<HealthChecksSample.CustomWriterStartup>();
|
||||
|
||||
var server = new TestServer(builder);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/health");
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("text/html", response.Content.Headers.ContentType.ToString());
|
||||
|
||||
// Ignoring the body since it contains a bunch of statistics
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DetailedStatusStartup()
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.UseStartup<HealthChecksSample.DetailedStatusStartup>();
|
||||
|
||||
var server = new TestServer(builder);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/health");
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("application/json", response.Content.Headers.ContentType.ToString());
|
||||
|
||||
// Ignoring the body since it contains a bunch of statistics
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,10 +17,8 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
|
|||
{
|
||||
public class HealthCheckMiddlewareTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("/frob")]
|
||||
[InlineData("/health/")] // Match is exact, for now at least
|
||||
public async Task IgnoresRequestThatDoesNotMatchPath(string requestPath)
|
||||
[Fact] // Matches based on '.Map'
|
||||
public async Task IgnoresRequestThatDoesNotMatchPath()
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.Configure(app =>
|
||||
|
@ -34,26 +32,190 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
|
|||
var server = new TestServer(builder);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var response = await client.GetAsync(requestPath);
|
||||
var response = await client.GetAsync("/frob");
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/health")]
|
||||
[InlineData("/Health")]
|
||||
[InlineData("/HEALTH")]
|
||||
public async Task ReturnsEmptyHealthyRequestIfNoHealthChecksRegistered(string requestPath)
|
||||
[Fact] // Matches based on '.Map'
|
||||
public async Task MatchIsCaseInsensitive()
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseHealthChecks("/health");
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddHealthChecks();
|
||||
});
|
||||
var server = new TestServer(builder);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/HEALTH");
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ReturnsPlainTextStatus()
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseHealthChecks("/health");
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddHealthChecks();
|
||||
});
|
||||
var server = new TestServer(builder);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/health");
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
Assert.Equal("Healthy", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StatusCodeIs200IfNoChecks()
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseHealthChecks("/health");
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddHealthChecks();
|
||||
});
|
||||
var server = new TestServer(builder);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/health");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
Assert.Equal("Healthy", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task StatusCodeIs200IfAllChecksHealthy()
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseHealthChecks("/health");
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddHealthChecks()
|
||||
.AddCheck("Foo", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")))
|
||||
.AddCheck("Bar", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")))
|
||||
.AddCheck("Baz", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")));
|
||||
});
|
||||
var server = new TestServer(builder);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/health");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
Assert.Equal("Healthy", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StatusCodeIs200IfCheckIsDegraded()
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseHealthChecks("/health");
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddHealthChecks()
|
||||
.AddCheck("Foo", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")))
|
||||
.AddCheck("Bar", () => Task.FromResult(HealthCheckResult.Degraded("Not so great.")))
|
||||
.AddCheck("Baz", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")));
|
||||
});
|
||||
var server = new TestServer(builder);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/health");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
Assert.Equal("Degraded", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StatusCodeIs503IfCheckIsUnhealthy()
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseHealthChecks("/health");
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddHealthChecks()
|
||||
.AddCheck("Foo", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")))
|
||||
.AddCheck("Bar", () => Task.FromResult(HealthCheckResult.Unhealthy("Pretty bad.")))
|
||||
.AddCheck("Baz", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")));
|
||||
});
|
||||
var server = new TestServer(builder);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/health");
|
||||
|
||||
Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
Assert.Equal("Unhealthy", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StatusCodeIs500IfCheckIsFailed()
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseHealthChecks("/health");
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddHealthChecks()
|
||||
.AddCheck("Foo", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")))
|
||||
.AddCheck("Bar", () => Task.FromResult(new HealthCheckResult(HealthCheckStatus.Failed, null, null, null)))
|
||||
.AddCheck("Baz", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")));
|
||||
});
|
||||
var server = new TestServer(builder);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/health");
|
||||
|
||||
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
Assert.Equal("Failed", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DetailedJsonReturnsEmptyHealthyResponseIfNoHealthChecksRegistered()
|
||||
{
|
||||
var expectedJson = JsonConvert.SerializeObject(new
|
||||
{
|
||||
status = "Healthy",
|
||||
results = new { }
|
||||
}, Formatting.None);
|
||||
}, Formatting.Indented);
|
||||
|
||||
var builder = new WebHostBuilder()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseHealthChecks("/health");
|
||||
app.UseHealthChecks("/health", new HealthCheckOptions()
|
||||
{
|
||||
ResponseWriter = HealthCheckResponseWriters.WriteDetailedJson,
|
||||
});
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
|
@ -62,14 +224,14 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
|
|||
var server = new TestServer(builder);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var response = await client.GetAsync(requestPath);
|
||||
var response = await client.GetAsync("/health");
|
||||
|
||||
var result = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(expectedJson, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ReturnsResultsFromHealthChecks()
|
||||
public async Task DetailedJsonReturnsResultsFromHealthChecks()
|
||||
{
|
||||
var expectedJson = JsonConvert.SerializeObject(new
|
||||
{
|
||||
|
@ -101,12 +263,15 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
|
|||
data = new { }
|
||||
},
|
||||
},
|
||||
}, Formatting.None);
|
||||
}, Formatting.Indented);
|
||||
|
||||
var builder = new WebHostBuilder()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseHealthChecks("/health");
|
||||
app.UseHealthChecks("/health", new HealthCheckOptions()
|
||||
{
|
||||
ResponseWriter = HealthCheckResponseWriters.WriteDetailedJson,
|
||||
});
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
|
@ -129,78 +294,15 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StatusCodeIs200IfNoChecks()
|
||||
public async Task NoResponseWriterReturnsEmptyBody()
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseHealthChecks("/health");
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddHealthChecks();
|
||||
});
|
||||
var server = new TestServer(builder);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/health");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StatusCodeIs200IfAllChecksHealthy()
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseHealthChecks("/health");
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddHealthChecks()
|
||||
.AddCheck("Foo", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")))
|
||||
.AddCheck("Bar", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")))
|
||||
.AddCheck("Baz", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")));
|
||||
});
|
||||
var server = new TestServer(builder);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/health");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StatusCodeIs200IfCheckIsDegraded()
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseHealthChecks("/health");
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddHealthChecks()
|
||||
.AddCheck("Foo", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")))
|
||||
.AddCheck("Bar", () => Task.FromResult(HealthCheckResult.Degraded("Not so great.")))
|
||||
.AddCheck("Baz", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")));
|
||||
});
|
||||
var server = new TestServer(builder);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/health");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StatusCodeIs503IfCheckIsUnhealthy()
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseHealthChecks("/health");
|
||||
app.UseHealthChecks("/health", new HealthCheckOptions()
|
||||
{
|
||||
ResponseWriter = null,
|
||||
});
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
|
@ -215,29 +317,34 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
|
|||
var response = await client.GetAsync("/health");
|
||||
|
||||
Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
|
||||
Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StatusCodeIs500IfCheckIsFailed()
|
||||
public async Task CanSetCustomStatusCodes()
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseHealthChecks("/health");
|
||||
app.UseHealthChecks("/health", new HealthCheckOptions()
|
||||
{
|
||||
ResultStatusCodes =
|
||||
{
|
||||
[HealthCheckStatus.Healthy] = 201,
|
||||
}
|
||||
});
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddHealthChecks()
|
||||
.AddCheck("Foo", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")))
|
||||
.AddCheck("Bar", () => Task.FromResult(new HealthCheckResult(HealthCheckStatus.Failed, null, null, null)))
|
||||
.AddCheck("Baz", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")));
|
||||
services.AddHealthChecks();
|
||||
});
|
||||
var server = new TestServer(builder);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/health");
|
||||
|
||||
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
|
||||
Assert.Equal("Healthy", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\samples\HealthChecksSample\HealthChecksSample.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Diagnostics.HealthChecks\Microsoft.AspNetCore.Diagnostics.HealthChecks.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче