Merge pull request #458 from dotnet-maestro-bot/merge/release/2.2-to-master
[automated] Merge branch 'release/2.2' => 'master'
This commit is contained in:
commit
0973a723fe
|
|
@ -6,6 +6,8 @@ using Microsoft.AspNetCore.Hosting;
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace HealthChecksSample
|
||||
{
|
||||
|
|
@ -45,23 +47,16 @@ namespace HealthChecksSample
|
|||
|
||||
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>");
|
||||
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,68 +0,0 @@
|
|||
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");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ 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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="$(MicrosoftAspNetCoreStaticFilesPackageVersion)" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -48,12 +48,7 @@ namespace HealthChecksSample
|
|||
|
||||
|
||||
// The readiness check uses all of the registered health checks (default)
|
||||
app.UseHealthChecks("/health/ready", new HealthCheckOptions()
|
||||
{
|
||||
// This sample is using detailed status to make more apparent which checks are being run - any
|
||||
// output format will work with liveness and readiness checks.
|
||||
ResponseWriter = HealthCheckResponseWriters.WriteDetailedJson,
|
||||
});
|
||||
app.UseHealthChecks("/health/ready");
|
||||
|
||||
// The liveness check uses an 'identity' health check that always returns healty
|
||||
app.UseHealthChecks("/health/live", new HealthCheckOptions()
|
||||
|
|
@ -63,10 +58,6 @@ namespace HealthChecksSample
|
|||
{
|
||||
"identity",
|
||||
},
|
||||
|
||||
// This sample is using detailed status to make more apparent which checks are being run - any
|
||||
// output format will work with liveness and readiness checks.
|
||||
ResponseWriter = HealthCheckResponseWriters.WriteDetailedJson,
|
||||
});
|
||||
|
||||
app.Run(async (context) =>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ namespace HealthChecksSample
|
|||
{
|
||||
{ "", typeof(BasicStartup) },
|
||||
{ "basic", typeof(BasicStartup) },
|
||||
{ "detailed", typeof(DetailedStatusStartup) },
|
||||
{ "writer", typeof(CustomWriterStartup) },
|
||||
{ "liveness", typeof(LivenessProbeStartup) },
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,7 +20,13 @@ namespace Microsoft.AspNetCore.Builder
|
|||
/// <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"/>.
|
||||
/// <para>
|
||||
/// This method will use <see cref="MapExtensions.Map(IApplicationBuilder, PathString, Action{IApplicationBuilder})"/> to
|
||||
/// listen to health checks requests on the specified URL path.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The health check middleware will use default settings from <see cref="IOptions{HealthCheckOptions}"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static IApplicationBuilder UseHealthChecks(this IApplicationBuilder app, PathString path)
|
||||
{
|
||||
|
|
@ -44,6 +50,12 @@ namespace Microsoft.AspNetCore.Builder
|
|||
/// <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>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method will use <see cref="MapExtensions.Map(IApplicationBuilder, PathString, Action{IApplicationBuilder})"/> to
|
||||
/// listen to health checks requests on the specified URL path.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static IApplicationBuilder UseHealthChecks(this IApplicationBuilder app, PathString path, HealthCheckOptions options)
|
||||
{
|
||||
if (app == null)
|
||||
|
|
|
|||
|
|
@ -1,56 +1,18 @@
|
|||
// 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
|
||||
internal 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,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Description>ASP.NET Core middleware for returning the results of Health Checks in the application</Description>
|
||||
|
|
@ -16,7 +16,6 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="$(MicrosoftAspNetCoreHttpAbstractionsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="$(MicrosoftExtensionsOptionsPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
// 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 Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
|
||||
|
|
@ -37,22 +35,6 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
|
|||
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());
|
||||
|
|
@ -63,20 +45,6 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
|
|||
[Fact]
|
||||
public async Task LivenessProbeStartup_Liveness()
|
||||
{
|
||||
var expectedJson = JsonConvert.SerializeObject(new
|
||||
{
|
||||
status = "Healthy",
|
||||
results = new
|
||||
{
|
||||
identity = new
|
||||
{
|
||||
status = "Healthy",
|
||||
description = "",
|
||||
data = new { }
|
||||
},
|
||||
},
|
||||
}, Formatting.Indented);
|
||||
|
||||
var builder = new WebHostBuilder()
|
||||
.UseStartup<HealthChecksSample.LivenessProbeStartup>();
|
||||
|
||||
|
|
@ -85,33 +53,13 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
|
|||
|
||||
var response = await client.GetAsync("/health/live");
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("application/json", response.Content.Headers.ContentType.ToString());
|
||||
Assert.Equal(expectedJson, await response.Content.ReadAsStringAsync());
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
Assert.Equal("Healthy", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LivenessProbeStartup_Readiness()
|
||||
{
|
||||
var expectedJson = JsonConvert.SerializeObject(new
|
||||
{
|
||||
status = "Unhealthy",
|
||||
results = new
|
||||
{
|
||||
identity = new
|
||||
{
|
||||
status = "Healthy",
|
||||
description = "",
|
||||
data = new { }
|
||||
},
|
||||
slow_dependency = new
|
||||
{
|
||||
status = "Unhealthy",
|
||||
description = "Dependency is still initializing",
|
||||
data = new { }
|
||||
},
|
||||
},
|
||||
}, Formatting.Indented);
|
||||
|
||||
var builder = new WebHostBuilder()
|
||||
.UseStartup<HealthChecksSample.LivenessProbeStartup>();
|
||||
|
||||
|
|
@ -120,8 +68,8 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
|
|||
|
||||
var response = await client.GetAsync("/health/ready");
|
||||
Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
|
||||
Assert.Equal("application/json", response.Content.Headers.ContentType.ToString());
|
||||
Assert.Equal(expectedJson, await response.Content.ReadAsStringAsync());
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
Assert.Equal("Unhealthy", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using System.Net;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.TestHost;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
|
|
@ -201,94 +202,40 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DetailedJsonReturnsEmptyHealthyResponseIfNoHealthChecksRegistered()
|
||||
{
|
||||
var expectedJson = JsonConvert.SerializeObject(new
|
||||
{
|
||||
status = "Healthy",
|
||||
results = new { }
|
||||
}, Formatting.Indented);
|
||||
|
||||
var builder = new WebHostBuilder()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseHealthChecks("/health", new HealthCheckOptions()
|
||||
{
|
||||
ResponseWriter = HealthCheckResponseWriters.WriteDetailedJson,
|
||||
});
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddHealthChecks();
|
||||
});
|
||||
var server = new TestServer(builder);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/health");
|
||||
|
||||
var result = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(expectedJson, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DetailedJsonReturnsResultsFromHealthChecks()
|
||||
public async Task CanUseCustomWriter()
|
||||
{
|
||||
var expectedJson = JsonConvert.SerializeObject(new
|
||||
{
|
||||
status = "Unhealthy",
|
||||
results = new
|
||||
{
|
||||
Foo = new
|
||||
{
|
||||
status = "Healthy",
|
||||
description = "Good to go!",
|
||||
data = new { }
|
||||
},
|
||||
Bar = new
|
||||
{
|
||||
status = "Degraded",
|
||||
description = "Feeling a bit off.",
|
||||
data = new { someUsefulAttribute = 42 }
|
||||
},
|
||||
Baz = new
|
||||
{
|
||||
status = "Unhealthy",
|
||||
description = "Not feeling good at all",
|
||||
data = new { }
|
||||
},
|
||||
Boz = new
|
||||
{
|
||||
status = "Unhealthy",
|
||||
description = string.Empty,
|
||||
data = new { }
|
||||
},
|
||||
},
|
||||
}, Formatting.Indented);
|
||||
});
|
||||
|
||||
var builder = new WebHostBuilder()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseHealthChecks("/health", new HealthCheckOptions()
|
||||
{
|
||||
ResponseWriter = HealthCheckResponseWriters.WriteDetailedJson,
|
||||
ResponseWriter = (c, r) =>
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(new { status = r.Status.ToString(), });
|
||||
c.Response.ContentType = "application/json";
|
||||
return c.Response.WriteAsync(json);
|
||||
},
|
||||
});
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddHealthChecks()
|
||||
.AddCheck("Foo", () => Task.FromResult(HealthCheckResult.Healthy("Good to go!")))
|
||||
.AddCheck("Bar", () => Task.FromResult(HealthCheckResult.Degraded("Feeling a bit off.", new Dictionary<string, object>()
|
||||
{
|
||||
{ "someUsefulAttribute", 42 }
|
||||
})))
|
||||
.AddCheck("Baz", () => Task.FromResult(HealthCheckResult.Unhealthy("Not feeling good at all", new Exception("Bad times"))))
|
||||
.AddCheck("Boz", () => Task.FromResult(HealthCheckResult.Unhealthy(new Exception("Very bad times"))));
|
||||
.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("application/json", response.Content.Headers.ContentType.ToString());
|
||||
|
||||
var result = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(expectedJson, result);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue