├── .github ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── build-and-publish.yml │ ├── build-and-test.yml │ └── snyk-test.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Examples ├── Example.HealthChecks.AspNetCore.ResponseWriter │ ├── Controllers │ │ └── WeatherForecastController.cs │ ├── Example.HealthChecks.AspNetCore.ResponseWriter.csproj │ ├── Program.cs │ ├── Startup.cs │ ├── WeatherForecast.cs │ ├── appsettings.Development.json │ └── appsettings.json ├── Example.HealthChecks.AspNetCore │ ├── Controllers │ │ └── WeatherForecastController.cs │ ├── Example.HealthChecks.AspNetCore.csproj │ ├── Program.cs │ ├── Startup.cs │ ├── WeatherForecast.cs │ ├── appsettings.Development.json │ └── appsettings.json └── Example.HealthChecks.Client │ ├── Example.HealthChecks.Client.csproj │ └── Program.cs ├── LICENSE.md ├── README.md ├── RockLib.HealthChecks.All.sln ├── RockLib.HealthChecks.AspNetCore.ResponseWriter ├── .editorconfig ├── CHANGELOG.md ├── Directory.Build.props ├── RockLib.HealthChecks.AspNetCore.ResponseWriter.csproj ├── RockLib.HealthChecks.AspNetCore.ResponseWriter.sln └── RockLibHealthChecks.cs ├── RockLib.HealthChecks.AspNetCore ├── .editorconfig ├── CHANGELOG.md ├── Checks │ └── HttpStatsHealthCheck.cs ├── Collector │ ├── CollectorOptions.cs │ ├── HealthMetricCollector.cs │ ├── HealthMetricCollectorExtensions.cs │ ├── HealthMetricCollectorFactory.cs │ └── HttpResponseCollector.cs ├── Directory.Build.props ├── HealthCheckMiddleware.cs ├── HealthCheckMiddlewareExtensions.cs ├── IResponseFormatter.cs ├── NewtonsoftJsonResponseFormatter.cs ├── RockLib.HealthChecks.AspNetCore.csproj └── RockLib.HealthChecks.AspNetCore.sln ├── RockLib.HealthChecks.Client ├── .editorconfig ├── CHANGELOG.md ├── Directory.Build.props ├── HealthCheckResult.cs ├── HealthCheckResultJsonConverter.cs ├── HealthResponse.cs ├── HealthStatus.cs ├── NullableAttributes.cs ├── RockLib.HealthChecks.Client.csproj └── RockLib.HealthChecks.Client.sln ├── RockLib.HealthChecks.HttpModule ├── .editorconfig ├── CHANGELOG.md ├── Directory.Build.props ├── HealthCheckHttpModule.cs ├── RockLib.HealthChecks.HttpModule.csproj └── RockLib.HealthChecks.HttpModule.sln ├── RockLib.HealthChecks.WebApi ├── .editorconfig ├── CHANGELOG.md ├── Directory.Build.props ├── HealthCheckHandler.cs ├── HealthCheckHandlerExtensions.cs ├── RockLib.HealthChecks.WebApi.csproj └── RockLib.HealthChecks.WebApi.sln ├── RockLib.HealthChecks ├── .editorconfig ├── AssemblyAttributes.cs ├── CHANGELOG.md ├── DependencyInjection │ ├── DependencyInjectionExtensions.cs │ ├── HealthCheckRegistration.cs │ ├── HealthCheckRunnerBuilder.cs │ ├── HealthCheckRunnerOptions.cs │ ├── IHealthCheckRunnerBuilder.cs │ └── IHealthCheckRunnerOptions.cs ├── Directory.Build.props ├── HealthCheck.cs ├── HealthCheckExtensions.cs ├── HealthCheckResult.cs ├── HealthCheckRunner.cs ├── HealthResponse.cs ├── HealthStatus.cs ├── IHealthCheck.cs ├── IHealthCheckRunner.cs ├── IHealthResponseCustomizer.cs ├── NullableAttributes.cs ├── RockLib.HealthChecks.csproj ├── RockLib.HealthChecks.sln ├── SingleResultHealthCheck.cs └── System │ ├── DependencyInjectionExtensions.cs │ ├── DiskDriveHealthCheck.cs │ ├── ProcessUptimeHealthCheck.cs │ └── SystemUptimeHealthCheck.cs ├── Tests ├── RockLib.HealthChecks.AspNetCore.ResponseWriter.Tests │ ├── .editorconfig │ ├── Directory.Build.props │ ├── ResponseWriterTests.cs │ └── RockLib.HealthChecks.AspNetCore.ResponseWriter.Tests.csproj ├── RockLib.HealthChecks.AspNetCore.Tests │ ├── .editorconfig │ ├── AssemblySettings.cs │ ├── Checks │ │ └── HttpStatsHealthCheckTests.cs │ ├── Collector │ │ ├── HealthMetricCollectorExtensionsTests.cs │ │ ├── HealthMetricCollectorFactoryTests.cs │ │ ├── HealthMetricCollectorTests.cs │ │ └── HttpResponseCollectorTests.cs │ ├── Directory.Build.props │ ├── HealthCheckMiddlewareExtensionsTests.cs │ ├── HealthCheckMiddlewareTests.cs │ ├── NewtonsoftJsonResponseFormatterTests.cs │ └── RockLib.HealthChecks.AspNetCore.Tests.csproj ├── RockLib.HealthChecks.Client.Tests │ ├── .editorconfig │ ├── AssemblySettings.cs │ ├── DeserializeTests.cs │ ├── Directory.Build.props │ └── RockLib.HealthChecks.Client.Tests.csproj ├── RockLib.HealthChecks.HttpModule.Tests │ ├── .editorconfig │ ├── AssemblySettings.cs │ ├── Directory.Build.props │ ├── HealthCheckHttpModuleTests.cs │ └── RockLib.HealthChecks.HttpModule.Tests.csproj ├── RockLib.HealthChecks.Tests │ ├── .editorconfig │ ├── AssemblySettings.cs │ ├── Directory.Build.props │ ├── HealthCheckExtensionsTests.cs │ ├── HealthCheckResultTests.cs │ ├── HealthCheckRunnerTests.cs │ ├── HealthResponseTests.cs │ ├── RockLib.HealthChecks.Tests.csproj │ └── SingleResultHealthCheckTests.cs └── RockLib.HealthChecks.WebApi.Tests │ ├── .editorconfig │ ├── AssemblySettings.cs │ ├── Directory.Build.props │ ├── HealthCheckHandlerExtensionsTests.cs │ ├── HealthCheckHandlerTests.cs │ └── RockLib.HealthChecks.WebApi.Tests.csproj ├── docs ├── AspNetCore.md ├── ConfigureAppSettings.md ├── ConfigureNet451AndAbove.md ├── ConfigureNet45AndBelow.md ├── CustomHealthCheck.md ├── DiskDriveHealthCheck.md ├── GettingStarted.md ├── HttpModule.md ├── HttpStatsHealthCheck.md ├── InstantiateRunner.md ├── ManualHealthChecks.md ├── ProcessUptimeHealthCheck.md ├── ResponseWriter.md ├── SystemUptimeHealthCheck.md └── WebApi.md └── icon.png /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | 12 | 13 | ## Type of change: 14 | 15 | 1. Non-functional change (e.g. documentation changes, removing unused `using` directives, renaming local variables, etc) 16 | 2. Bug fix (non-breaking change that fixes an issue) 17 | 3. New feature (non-breaking change that adds functionality) 18 | 4. Breaking change (fix or feature that could cause existing functionality to not work as expected) 19 | 20 | ## Checklist: 21 | 22 | - Have you reviewed your own code? Do you understand every change? 23 | - Are you following the [contributing guidelines](../blob/main/CONTRIBUTING.md)? 24 | - Have you added tests that prove your fix is effective or that this feature works? 25 | - New and existing unit tests pass locally with these changes? 26 | - Have you made corresponding changes to the documentation? 27 | - Will this change require an update to an example project? (if so, create an issue and link to it) 28 | 29 | --- 30 | 31 | _[Reviewer guidelines](../blob/main/CONTRIBUTING.md#reviewing-changes)_ 32 | -------------------------------------------------------------------------------- /.github/workflows/build-and-publish.yml: -------------------------------------------------------------------------------- 1 | name: Build and Publish 2 | 3 | #################################################################################################### 4 | ## WORKFLOW TRIGGER 5 | #################################################################################################### 6 | on: 7 | # Workflow will run when a release is published. 8 | release: 9 | types: [ released, prereleased ] 10 | 11 | #################################################################################################### 12 | ## WORKFLOW JOBS 13 | #################################################################################################### 14 | jobs: 15 | # Calls the shared build-and-publish workflow. 16 | call_build_and_publish: 17 | name: Call build-and-publish workflow 18 | uses: RockLib/RockLib.Workflows/.github/workflows/build-and-publish.yml@main 19 | secrets: inherit 20 | -------------------------------------------------------------------------------- /.github/workflows/build-and-test.yml: -------------------------------------------------------------------------------- 1 | name: Run Unit Test 2 | 3 | #################################################################################################### 4 | ## WORKFLOW TRIGGER 5 | #################################################################################################### 6 | on: 7 | # Workflow will run on pull requests to the main branch. 8 | pull_request: 9 | branches: [ main ] 10 | 11 | #################################################################################################### 12 | ## WORKFLOW JOBS 13 | #################################################################################################### 14 | jobs: 15 | # Calls the shared unit-test workflow. 16 | call_unit_test: 17 | name: Call unit-test workflow 18 | uses: RockLib/RockLib.Workflows/.github/workflows/unit-test.yml@main 19 | secrets: inherit 20 | -------------------------------------------------------------------------------- /.github/workflows/snyk-test.yml: -------------------------------------------------------------------------------- 1 | name: Run Snyk Test 2 | 3 | #################################################################################################### 4 | ## WORKFLOW TRIGGER 5 | #################################################################################################### 6 | on: 7 | # Workflow will run after unit-test is completed. 8 | workflow_run: 9 | workflows: [ Run Unit Test ] 10 | types: [ completed ] 11 | 12 | #################################################################################################### 13 | ## WORKFLOW JOBS 14 | #################################################################################################### 15 | jobs: 16 | # Calls the shared snyk-test workflow. 17 | call_snyk_test: 18 | name: Call snyk-test workflow 19 | uses: RockLib/RockLib.Workflows/.github/workflows/snyk-test.yml@main 20 | secrets: inherit 21 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at RockLibSupport@quickenloans.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /Examples/Example.HealthChecks.AspNetCore.ResponseWriter/Controllers/WeatherForecastController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace Example.HealthChecks.AspNetCore.ResponseWriter.Controllers 9 | { 10 | [ApiController] 11 | [Route("[controller]")] 12 | public class WeatherForecastController : ControllerBase 13 | { 14 | private static readonly string[] Summaries = new[] 15 | { 16 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" 17 | }; 18 | 19 | private readonly ILogger _logger; 20 | 21 | public WeatherForecastController(ILogger logger) 22 | { 23 | _logger = logger; 24 | } 25 | 26 | [HttpGet] 27 | public IEnumerable Get() 28 | { 29 | var rng = new Random(); 30 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast 31 | { 32 | Date = DateTime.Now.AddDays(index), 33 | TemperatureC = rng.Next(-20, 55), 34 | Summary = Summaries[rng.Next(Summaries.Length)] 35 | }) 36 | .ToArray(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Examples/Example.HealthChecks.AspNetCore.ResponseWriter/Example.HealthChecks.AspNetCore.ResponseWriter.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net8.0 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Examples/Example.HealthChecks.AspNetCore.ResponseWriter/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.Hosting; 4 | using Microsoft.Extensions.Logging; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Threading.Tasks; 9 | 10 | namespace Example.HealthChecks.AspNetCore.ResponseWriter 11 | { 12 | public class Program 13 | { 14 | public static void Main(string[] args) 15 | { 16 | CreateHostBuilder(args).Build().Run(); 17 | } 18 | 19 | public static IHostBuilder CreateHostBuilder(string[] args) => 20 | Host.CreateDefaultBuilder(args) 21 | .ConfigureWebHostDefaults(webBuilder => 22 | { 23 | webBuilder.UseStartup(); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Examples/Example.HealthChecks.AspNetCore.ResponseWriter/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Diagnostics.HealthChecks; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.Extensions.Configuration; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Microsoft.Extensions.Hosting; 7 | using RockLib.HealthChecks.AspNetCore.ResponseWriter; 8 | 9 | namespace Example.HealthChecks.AspNetCore.ResponseWriter 10 | { 11 | public class Startup 12 | { 13 | public Startup(IConfiguration configuration) 14 | { 15 | Configuration = configuration; 16 | 17 | // Set health checks options. 18 | RockLibHealthChecks.Indent = true; 19 | } 20 | 21 | public IConfiguration Configuration { get; } 22 | 23 | public void ConfigureServices(IServiceCollection services) 24 | { 25 | services.AddControllers(); 26 | 27 | // Add health check service to the service collection. 28 | services.AddHealthChecks() 29 | .AddDiskStorageHealthCheck(options => options.AddDrive("C:\\", 309646), "disk:space"); 30 | } 31 | 32 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 33 | { 34 | if (env.IsDevelopment()) 35 | { 36 | app.UseDeveloperExceptionPage(); 37 | } 38 | 39 | app.UseHttpsRedirection(); 40 | 41 | app.UseRouting(); 42 | 43 | app.UseAuthorization(); 44 | 45 | // Add health checks endpoint to the pipeline before the call to UseEndpoints. 46 | app.UseHealthChecks("/health", new HealthCheckOptions 47 | { 48 | // To write health check responses in the rfc format, set the response writer of 49 | // the health check options. 50 | ResponseWriter = RockLibHealthChecks.ResponseWriter 51 | }); 52 | 53 | app.UseEndpoints(endpoints => 54 | { 55 | endpoints.MapControllers(); 56 | }); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Examples/Example.HealthChecks.AspNetCore.ResponseWriter/WeatherForecast.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Example.HealthChecks.AspNetCore.ResponseWriter 4 | { 5 | public class WeatherForecast 6 | { 7 | public DateTime Date { get; set; } 8 | 9 | public int TemperatureC { get; set; } 10 | 11 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); 12 | 13 | public string Summary { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Examples/Example.HealthChecks.AspNetCore.ResponseWriter/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Examples/Example.HealthChecks.AspNetCore.ResponseWriter/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /Examples/Example.HealthChecks.AspNetCore/Controllers/WeatherForecastController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace Example.HealthChecks.AspNetCore.Controllers 9 | { 10 | [ApiController] 11 | [Route("[controller]")] 12 | public class WeatherForecastController : ControllerBase 13 | { 14 | private static readonly string[] Summaries = new[] 15 | { 16 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" 17 | }; 18 | 19 | private readonly ILogger _logger; 20 | 21 | public WeatherForecastController(ILogger logger) 22 | { 23 | _logger = logger; 24 | } 25 | 26 | [HttpGet] 27 | public IEnumerable Get() 28 | { 29 | var rng = new Random(); 30 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast 31 | { 32 | Date = DateTime.Now.AddDays(index), 33 | TemperatureC = rng.Next(-20, 55), 34 | Summary = Summaries[rng.Next(Summaries.Length)] 35 | }) 36 | .ToArray(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Examples/Example.HealthChecks.AspNetCore/Example.HealthChecks.AspNetCore.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net8.0 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Examples/Example.HealthChecks.AspNetCore/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.Hosting; 4 | using Microsoft.Extensions.Logging; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Threading.Tasks; 9 | 10 | namespace Example.HealthChecks.AspNetCore 11 | { 12 | public class Program 13 | { 14 | public static void Main(string[] args) 15 | { 16 | CreateHostBuilder(args).Build().Run(); 17 | } 18 | 19 | public static IHostBuilder CreateHostBuilder(string[] args) => 20 | Host.CreateDefaultBuilder(args) 21 | .ConfigureWebHostDefaults(webBuilder => 22 | { 23 | webBuilder.UseStartup(); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Examples/Example.HealthChecks.AspNetCore/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Hosting; 6 | using Newtonsoft.Json; 7 | using RockLib.HealthChecks.AspNetCore; 8 | using RockLib.HealthChecks.DependencyInjection; 9 | using RockLib.HealthChecks.System; 10 | 11 | namespace Example.HealthChecks.AspNetCore 12 | { 13 | public class Startup 14 | { 15 | public Startup(IConfiguration configuration) 16 | { 17 | Configuration = configuration; 18 | } 19 | 20 | public IConfiguration Configuration { get; } 21 | 22 | public void ConfigureServices(IServiceCollection services) 23 | { 24 | services.AddControllers(); 25 | 26 | // This application defines its health check runner in its appsettings.json, so 27 | // a health check runner should *not* be added to the service collection. To define an 28 | // equivalent health check runner programmatically: 29 | /* 30 | services.AddHealthCheckRunner(options => 31 | { 32 | options.Version = "1"; 33 | options.ServiceId = "c0c4b71f-d540-4515-8a87-5a4ae5ca4c55"; 34 | options.Description = "My Application"; 35 | }) 36 | .AddProcessUptimeHealthCheck() 37 | .AddDiskDriveHealthCheck(warnGigabytes: 10, failGigabytes: 1, driveName: "C:\\"); 38 | */ 39 | } 40 | 41 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 42 | { 43 | if (env.IsDevelopment()) 44 | { 45 | app.UseDeveloperExceptionPage(); 46 | } 47 | 48 | app.UseHttpsRedirection(); 49 | 50 | app.UseRouting(); 51 | 52 | app.UseAuthorization(); 53 | 54 | // Add health checks endpoint to the pipeline before the call to UseEndpoints. 55 | app.UseRockLibHealthChecks(formatter: new NewtonsoftJsonResponseFormatter(Formatting.Indented)); 56 | 57 | app.UseEndpoints(endpoints => 58 | { 59 | endpoints.MapControllers(); 60 | }); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Examples/Example.HealthChecks.AspNetCore/WeatherForecast.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Example.HealthChecks.AspNetCore 4 | { 5 | public class WeatherForecast 6 | { 7 | public DateTime Date { get; set; } 8 | 9 | public int TemperatureC { get; set; } 10 | 11 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); 12 | 13 | public string Summary { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Examples/Example.HealthChecks.AspNetCore/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Examples/Example.HealthChecks.AspNetCore/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*", 10 | 11 | "RockLib.HealthChecks": { 12 | "version": "1", 13 | "serviceId": "c0c4b71f-d540-4515-8a87-5a4ae5ca4c55", 14 | "description": "My Application", 15 | "healthChecks": [ 16 | { 17 | "type": "RockLib.HealthChecks.System.ProcessUptimeHealthCheck, RockLib.HealthChecks" 18 | }, 19 | { 20 | "type": "RockLib.HealthChecks.System.DiskDriveHealthCheck, RockLib.HealthChecks", 21 | "value": { 22 | "warnGigabytes": 10, 23 | "failGigabytes": 1, 24 | "driveName": "C:\\" 25 | } 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Examples/Example.HealthChecks.Client/Example.HealthChecks.Client.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Examples/Example.HealthChecks.Client/Program.cs: -------------------------------------------------------------------------------- 1 | using RockLib.HealthChecks.Client; 2 | using System; 3 | using System.Net.Http; 4 | using System.Net.Http.Json; 5 | using System.Threading.Tasks; 6 | 7 | namespace Example.HealthChecks.Client 8 | { 9 | class Program 10 | { 11 | static async Task Main(string[] args) 12 | { 13 | using var httpClient = new HttpClient(); 14 | 15 | Console.Write("Press any key when ready to send health request . . ."); 16 | Console.ReadKey(true); 17 | Console.WriteLine(); 18 | Console.WriteLine(); 19 | 20 | // Note: This example is designed to make a request to the 21 | // Example.HealthChecks.AspNetCore example. 22 | var httpResponse = await httpClient.GetAsync("https://localhost:5001/health"); 23 | 24 | // Deserialize the request content into a HealthResponse object. Note that the 25 | // ReadFromJsonAsync extension method comes from the System.Net.Http.Json package. 26 | var healthResponse = await httpResponse.Content.ReadFromJsonAsync(); 27 | 28 | // Use the HealthResponse object. 29 | Console.WriteLine($"Overall health check status: {healthResponse.Status}"); 30 | Console.WriteLine($"Number of health checks performed: {healthResponse.Checks.Count}"); 31 | foreach (var healthCheck in healthResponse.Checks) 32 | foreach (var healthCheckResult in healthCheck.Value) 33 | Console.WriteLine($"Health check '{healthCheck.Key}': {healthCheckResult.ObservedValue} {healthCheckResult.ObservedUnit}"); 34 | 35 | Console.WriteLine(); 36 | Console.Write("Press any key to exit . . ."); 37 | Console.ReadKey(true); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (C) 2019-2021 Rocket Mortgage 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RockLib.HealthChecks 2 | 3 | *An implementation of the draft health check RFC located at https://inadarei.github.io/rfc-healthcheck/.* 4 | 5 | --- 6 | 7 | - [Getting started](docs/GettingStarted.md) 8 | - How to: 9 | - [Manually perform health checks](docs/ManualHealthChecks.md) 10 | - [Add RockLib.HealthChecks to an ASP.NET Core application](docs/AspNetCore.md) 11 | - [Add RockLib.HealthChecks to an ASP.NET WebApi application](docs/WebApi.md) 12 | - [Add RockLib.HealthChecks to an ASP.NET application via HttpModule](docs/HttpModule.md) 13 | - [Format the output of Microsoft.Extensions.Diagnostics.HealthChecks in the draft RFC format](docs/ResponseWriter.md) 14 | - [Instantiate health check runners](docs/InstantiateRunner.md) 15 | - [Configure an application with appsettings.json](docs/ConfigureAppSettings.md) 16 | - [Configure a .NET Framework application (4.5 or below) with app.config/web.config](docs/ConfigureNet45AndBelow.md) 17 | - [Configure a .NET Framework application (4.5.1 or above) with app.config/web.config](docs/ConfigureNet451AndAbove.md) 18 | - [Create custom health checks](docs/CustomHealthCheck.md) 19 | - Existing Health Checks: 20 | - System 21 | - [DiskDriveHealthCheck](docs/DiskDriveHealthCheck.md) 22 | - A health check that monitors the amount of available free space on disk. 23 | - [ProcessUptimeHealthCheck](docs/ProcessUptimeHealthCheck.md) 24 | - A health check that records the uptime of the current process. Always passes. 25 | - [SystemUptimeHealthCheck](docs/SystemUptimeHealthCheck.md) 26 | - A health check that records the uptime of the system. Always passes. 27 | - Downstream Services 28 | - [HttpStatsHealthCheck](docs/HttpStatsHealthCheck.md) 29 | - A health check that monitors HTTP calls to downstream systems and reports on outcomes. 30 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.AspNetCore.ResponseWriter/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | 6 | [*.cs] 7 | # Styling 8 | indent_style = space 9 | indent_size = 4 10 | csharp_indent_case_contents = true 11 | csharp_indent_switch_labels = true 12 | csharp_new_line_before_catch = true 13 | csharp_new_line_before_else = true 14 | csharp_new_line_before_finally = true 15 | csharp_new_line_before_members_in_anonymous_types = false 16 | csharp_new_line_before_members_in_object_initializers = false 17 | csharp_new_line_before_open_brace = methods, control_blocks, types, properties, lambdas, accessors, object_collection_array_initializers 18 | csharp_new_line_between_query_expression_clauses = true 19 | csharp_prefer_braces = false:suggestion 20 | csharp_prefer_simple_default_expression = true:suggestion 21 | csharp_preferred_modifier_order = public,private,internal,protected,static,readonly,async,override,sealed:suggestion 22 | csharp_preserve_single_line_blocks = true 23 | csharp_preserve_single_line_statements = true 24 | csharp_space_after_cast = false 25 | csharp_space_after_colon_in_inheritance_clause = true 26 | csharp_space_after_keywords_in_control_flow_statements = true 27 | csharp_space_before_colon_in_inheritance_clause = true 28 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 29 | csharp_space_between_method_call_name_and_opening_parenthesis = false 30 | csharp_space_between_method_call_parameter_list_parentheses = false 31 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 32 | csharp_space_between_method_declaration_parameter_list_parentheses = false 33 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 34 | csharp_style_expression_bodied_accessors = true:suggestion 35 | csharp_style_expression_bodied_constructors = false:suggestion 36 | csharp_style_expression_bodied_methods = false:suggestion 37 | csharp_style_expression_bodied_properties = true:suggestion 38 | csharp_style_inlined_variable_declaration = true:suggestion 39 | csharp_style_var_elsewhere = true:suggestion 40 | csharp_style_var_for_built_in_types = true:suggestion 41 | csharp_style_var_when_type_is_apparent = true:suggestion 42 | dotnet_sort_system_directives_first = false 43 | dotnet_style_explicit_tuple_names = true:suggestion 44 | dotnet_style_object_initializer = true:suggestion 45 | csharp_style_pattern_local_over_anonymous_function = false:suggestion 46 | dotnet_style_predefined_type_for_member_access = true:suggestion 47 | dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion 48 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 49 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 50 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion 51 | dotnet_style_qualification_for_field = false:suggestion 52 | dotnet_style_qualification_for_method = false:suggestion 53 | dotnet_style_qualification_for_property = false:suggestion 54 | 55 | 56 | # Analyzer Configuration 57 | # These are rules we want to either ignore or have set as suggestion or info 58 | 59 | # CA1014: Mark assemblies with CLSCompliant 60 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1014 61 | dotnet_diagnostic.CA1014.severity = none 62 | 63 | # CA1725: Parameter names should match base declaration 64 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1725 65 | dotnet_diagnostic.CA1725.severity = suggestion 66 | 67 | # CA2227: Collection properties should be read only 68 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2227 69 | dotnet_diagnostic.CA2227.severity = suggestion 70 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.AspNetCore.ResponseWriter/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # RockLib.HealthChecks.AspNetCore.ResponseWriter Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## 4.0.0 - 2025-02-05 9 | 10 | #### Changed 11 | - Finalized 4.0.0 release. 12 | - RockLib.HealthChecks.4.0.0-alpha.1 -> RockLib.HealthChecks.4.0.0 13 | 14 | ## 4.0.0-alpha.1 - 2025-02-05 15 | 16 | #### Changed 17 | - RockLib.HealthChecks.3.0.2 -> RockLib.HealthChecks.4.0.0-alpha.1 18 | 19 | ## 3.0.2 - 2024-11-05 20 | 21 | #### Changed 22 | - RockLib.HealthChecks.3.0.1 -> RockLib.HealthChecks.3.0.2 to fix vulnerability 23 | 24 | ## 3.0.1 - 2024-07-16 25 | 26 | #### Changed 27 | - RockLib.HealthChecks.3.0.0 -> RockLib.HealthChecks.3.0.1 to fix vulnerability 28 | 29 | ## 3.0.0 - 2024-03-04 30 | 31 | #### Changed 32 | - Removed netcoreapp3.1 from supported targets. 33 | - Added net8.0 to supported targets. 34 | - Updated package references. 35 | 36 | ## 3.0.0-alpha.1 - 2024-02-27 37 | 38 | #### Changed 39 | - Removed netcoreapp3.1 from supported targets from test project. 40 | - Added net8.0 to supported targets to test project. 41 | - Updated package references in test project. 42 | 43 | ## 2.0.0-alpha.2 - 2023-03-01 44 | 45 | #### Changed 46 | - Updated RockLib.HealthChecks dependency to 2.0.1. 47 | 48 | ## 2.0.0-alpha.1 - 2022-12-15 49 | 50 | #### Added 51 | - Added `.editorconfig` and `Directory.Build.props` files to ensure consistency. 52 | 53 | #### Changed 54 | - Supported targets: net6.0, netcoreapp3.1, and net48. 55 | - As the package now uses nullable reference types, some method parameters now specify if they can accept nullable values. 56 | 57 | ## 1.1.2 - 2021-08-13 58 | 59 | #### Changed 60 | 61 | - Changes "Quicken Loans" to "Rocket Mortgage". 62 | - Updates RockLib.HealthChecks to latest version, [1.3.9](https://github.com/RockLib/RockLib.HealthChecks/blob/main/RockLib.HealthChecks/CHANGELOG.md#139---2021-08-13). 63 | 64 | ## 1.1.1 - 2021-05-10 65 | 66 | #### Added 67 | 68 | - Adds SourceLink to nuget package. 69 | 70 | #### Changed 71 | 72 | - Updates RockLib.HealthChecks package to latest version, which includes SourceLink. 73 | 74 | ---- 75 | 76 | **Note:** Release notes in the above format are not available for earlier versions of 77 | RockLib.HealthChecks.AspNetCore.ResponseWriter. What follows below are the original release notes. 78 | 79 | ---- 80 | 81 | ## 1.1.0 82 | 83 | Adds the ability to hide the exception or description/output when mapping a Microsoft HealthReportEntry to a RockLib HealthCheckResult. 84 | 85 | ## 1.0.4 86 | 87 | Updates RockLib.HealthChecks dependency, adding missing functionality for the net5.0 target. 88 | 89 | ## 1.0.3 90 | 91 | Adds net5.0 target and updates dependencies. 92 | 93 | ## 1.0.2 94 | 95 | Adds icon to project and nuget package. 96 | 97 | ## 1.0.1 98 | 99 | Updates to align with nuget conventions. 100 | 101 | ## 1.0.0 102 | 103 | Initial release. 104 | 105 | ## 1.0.0-rc1 106 | 107 | Initial release candidate. 108 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.AspNetCore.ResponseWriter/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | 6 | all 7 | Rocket Mortgage 8 | Copyright 2025 (c) Rocket Mortgage. All rights reserved. 9 | latest 10 | enable 11 | net8.0;net48 12 | NU1603,NU1701 13 | true 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.AspNetCore.ResponseWriter/RockLib.HealthChecks.AspNetCore.ResponseWriter.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Embedded 4 | A ResponseWriter for Microsoft.Extensions.Diagnostics.HealthChecks that writes in the format described by https://inadarei.github.io/rfc-healthcheck/. 5 | True 6 | True 7 | icon.png 8 | RockLib.HealthChecks.AspNetCore.ResponseWriter 9 | LICENSE.md 10 | https://github.com/RockLib/RockLib.HealthChecks 11 | A changelog is available at https://github.com/RockLib/RockLib.HealthChecks/blob/main/RockLib.HealthChecks.AspNetCore.ResponseWriter/CHANGELOG.md. 12 | false 13 | rocklib health checks aspnetcore responsewriter 14 | 4.0.0 15 | True 16 | 4.0.0 17 | 18 | 19 | bin\$(Configuration)\$(TargetFramework)\$(PackageId).xml 20 | 21 | 22 | true 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.AspNetCore.ResponseWriter/RockLib.HealthChecks.AspNetCore.ResponseWriter.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.33110.190 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RockLib.HealthChecks.AspNetCore.ResponseWriter", "RockLib.HealthChecks.AspNetCore.ResponseWriter.csproj", "{482209AA-CA19-40B1-9D32-083CC50C2B88}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RockLib.HealthChecks.AspNetCore.ResponseWriter.Tests", "..\Tests\RockLib.HealthChecks.AspNetCore.ResponseWriter.Tests\RockLib.HealthChecks.AspNetCore.ResponseWriter.Tests.csproj", "{04532804-CCFE-40BA-B93D-5634222F4F50}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {482209AA-CA19-40B1-9D32-083CC50C2B88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {482209AA-CA19-40B1-9D32-083CC50C2B88}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {482209AA-CA19-40B1-9D32-083CC50C2B88}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {482209AA-CA19-40B1-9D32-083CC50C2B88}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {04532804-CCFE-40BA-B93D-5634222F4F50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {04532804-CCFE-40BA-B93D-5634222F4F50}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {04532804-CCFE-40BA-B93D-5634222F4F50}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {04532804-CCFE-40BA-B93D-5634222F4F50}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {9BD2137B-45A2-4572-9151-93471F4F7CC9} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.AspNetCore/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | 6 | [*.cs] 7 | # Styling 8 | indent_style = space 9 | indent_size = 4 10 | csharp_indent_case_contents = true 11 | csharp_indent_switch_labels = true 12 | csharp_new_line_before_catch = true 13 | csharp_new_line_before_else = true 14 | csharp_new_line_before_finally = true 15 | csharp_new_line_before_members_in_anonymous_types = false 16 | csharp_new_line_before_members_in_object_initializers = false 17 | csharp_new_line_before_open_brace = methods, control_blocks, types, properties, lambdas, accessors, object_collection_array_initializers 18 | csharp_new_line_between_query_expression_clauses = true 19 | csharp_prefer_braces = false:suggestion 20 | csharp_prefer_simple_default_expression = true:suggestion 21 | csharp_preferred_modifier_order = public,private,internal,protected,static,readonly,async,override,sealed:suggestion 22 | csharp_preserve_single_line_blocks = true 23 | csharp_preserve_single_line_statements = true 24 | csharp_space_after_cast = false 25 | csharp_space_after_colon_in_inheritance_clause = true 26 | csharp_space_after_keywords_in_control_flow_statements = true 27 | csharp_space_before_colon_in_inheritance_clause = true 28 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 29 | csharp_space_between_method_call_name_and_opening_parenthesis = false 30 | csharp_space_between_method_call_parameter_list_parentheses = false 31 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 32 | csharp_space_between_method_declaration_parameter_list_parentheses = false 33 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 34 | csharp_style_expression_bodied_accessors = true:suggestion 35 | csharp_style_expression_bodied_constructors = false:suggestion 36 | csharp_style_expression_bodied_methods = false:suggestion 37 | csharp_style_expression_bodied_properties = true:suggestion 38 | csharp_style_inlined_variable_declaration = true:suggestion 39 | csharp_style_var_elsewhere = true:suggestion 40 | csharp_style_var_for_built_in_types = true:suggestion 41 | csharp_style_var_when_type_is_apparent = true:suggestion 42 | dotnet_sort_system_directives_first = false 43 | dotnet_style_explicit_tuple_names = true:suggestion 44 | dotnet_style_object_initializer = true:suggestion 45 | csharp_style_pattern_local_over_anonymous_function = false:suggestion 46 | dotnet_style_predefined_type_for_member_access = true:suggestion 47 | dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion 48 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 49 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 50 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion 51 | dotnet_style_qualification_for_field = false:suggestion 52 | dotnet_style_qualification_for_method = false:suggestion 53 | dotnet_style_qualification_for_property = false:suggestion 54 | 55 | 56 | # Analyzer Configuration 57 | # These are rules we want to either ignore or have set as suggestion or info 58 | 59 | # CA1014: Mark assemblies with CLSCompliant 60 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1014 61 | dotnet_diagnostic.CA1014.severity = none 62 | 63 | # CA1725: Parameter names should match base declaration 64 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1725 65 | dotnet_diagnostic.CA1725.severity = suggestion 66 | 67 | # CA2227: Collection properties should be read only 68 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2227 69 | dotnet_diagnostic.CA2227.severity = suggestion 70 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.AspNetCore/Collector/CollectorOptions.cs: -------------------------------------------------------------------------------- 1 | namespace RockLib.HealthChecks.AspNetCore.Collector; 2 | 3 | /// 4 | /// Options for configuring a . 5 | /// 6 | /// Intended to be reused in other IMetricCollector implementations. 7 | public record CollectorOptions 8 | { 9 | /// 10 | /// The name of the collector. Defaults to . 11 | /// 12 | /// Use http host name (e.g. "myapp.foc.zone") if collecting http client response codes. 13 | public string Name { get; set; } = string.Empty; 14 | 15 | /// 16 | /// number of samples to keep in the collector. Defaults to 100. 17 | /// 18 | public int? Samples { get; set; } 19 | 20 | /// 21 | /// warning threshold for the collector. Defaults to 0.9. 22 | /// 23 | public double? WarningThreshold { get; set; } 24 | 25 | /// 26 | /// error threshold for the collector. Defaults to 0.75. 27 | /// 28 | public double? ErrorThreshold { get; set; } 29 | } -------------------------------------------------------------------------------- /RockLib.HealthChecks.AspNetCore/Collector/HealthMetricCollector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading; 4 | 5 | namespace RockLib.HealthChecks.AspNetCore.Collector; 6 | 7 | /// 8 | /// Interface definition for a health metric collectors. "health metrics" not to be confused with "application metrics" (e.g. OTEL/Dynatrace). 9 | /// 10 | /// 11 | public interface IHealthMetricCollector 12 | { 13 | /// 14 | /// Add a new metric to the collector. 15 | /// 16 | /// 17 | void Collect(int outcome); 18 | 19 | /// 20 | /// Retrieve the metrics from the collector. 21 | /// 22 | /// 23 | /// 24 | int[] GetMetrics(Func? predicate = null); 25 | 26 | /// 27 | /// Retrieve the number of impressions from the collector. 28 | /// 29 | long GetImpressionCount(); 30 | } 31 | 32 | /// 33 | /// A simple implementation of that stores metrics in a fixed-size array. 34 | /// The fixed-size array is used as a circular buffer - "only store the N most-recent metrics". 35 | /// 36 | public class HealthMetricCollector : IHealthMetricCollector 37 | { 38 | private long _impressionCount; 39 | private readonly int[] _metrics; 40 | private readonly int _size; 41 | 42 | /// 43 | /// Implementation of that stores integer metrics in a fixed-size array. 44 | /// 45 | /// how large to make the array 46 | public HealthMetricCollector(int size) 47 | { 48 | _metrics = new int[size]; 49 | _size = size; 50 | } 51 | 52 | /// 53 | /// see 54 | /// 55 | /// the integer outcome to put into the array. 56 | public void Collect(int outcome) 57 | { 58 | var idx = Interlocked.Increment(ref _impressionCount) % _size; 59 | _metrics[idx] = outcome; 60 | } 61 | 62 | /// 63 | /// see 64 | /// 65 | /// Func used to collate matching entries 66 | /// an int[] of entries matching the predicate 67 | public int[] GetMetrics(Func? predicate = null) 68 | { 69 | return _metrics.Where(predicate ?? (x => x != 0)).ToArray(); 70 | } 71 | 72 | /// 73 | /// see 74 | /// 75 | /// 76 | public long GetImpressionCount() 77 | { 78 | return _impressionCount; 79 | } 80 | } -------------------------------------------------------------------------------- /RockLib.HealthChecks.AspNetCore/Collector/HealthMetricCollectorExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace RockLib.HealthChecks.AspNetCore.Collector; 4 | 5 | /// 6 | /// IHealthMetricCollector extensions. 7 | /// 8 | public static class HealthMetricCollectorExtensions 9 | { 10 | /// 11 | /// Return a count of the metrics that match the predicate. 12 | /// 13 | /// 14 | /// 15 | /// 16 | public static int GetCount(this IHealthMetricCollector collector, Func predicate) 17 | { 18 | return collector?.GetMetrics(predicate).Length ?? 0; 19 | } 20 | } -------------------------------------------------------------------------------- /RockLib.HealthChecks.AspNetCore/Collector/HealthMetricCollectorFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace RockLib.HealthChecks.AspNetCore.Collector; 4 | 5 | /// 6 | /// Interface definition for the container of collectors. We use this to manage the lifecycle of collectors. 7 | /// 8 | /// factory is Singleton at runtime 9 | /// 10 | public interface IHealthMetricCollectorFactory 11 | { 12 | /// 13 | /// used by the health check middleware to right-size collectors (by name) 14 | /// 15 | /// 16 | /// 17 | internal void ConfigureCollector(string name, int? samples = null); 18 | 19 | /// 20 | /// Returns a handle to a collector by name 21 | /// 22 | /// 23 | /// 24 | public IHealthMetricCollector LeaseCollector(string? name); 25 | 26 | /// 27 | /// Returns all collectors held by the factory 28 | /// 29 | /// 30 | public Dictionary GetCollectors(); 31 | 32 | /// 33 | /// Override the default sample size for new collectors 34 | /// 35 | /// 36 | public void SetDefaultSampleSize(int? samples); 37 | } 38 | 39 | /// 40 | /// A factory for accessing instances. The factory holds the collectors and manages their lifecycle. 41 | /// 42 | public class HealthMetricCollectorFactory : IHealthMetricCollectorFactory 43 | { 44 | private readonly Dictionary _collectors; 45 | private int _defaultSamples = 100; 46 | 47 | /// 48 | /// Default constructor - typically used by the DI container 49 | /// 50 | public HealthMetricCollectorFactory() 51 | { 52 | _collectors = new Dictionary(); 53 | } 54 | 55 | /// 56 | /// Obtain a collector by name. 57 | /// If the collector does not exist it's created (w/size=100). 58 | /// 59 | /// 60 | /// 61 | public IHealthMetricCollector LeaseCollector(string? name) 62 | { 63 | name ??= string.Empty; 64 | if (_collectors.TryGetValue(name, out var value)) return value; 65 | 66 | value = new HealthMetricCollector(_defaultSamples); 67 | _collectors[name] = value; 68 | return value; 69 | } 70 | 71 | /// 72 | /// Exposes all collectors held by the factory 73 | /// 74 | /// 75 | public Dictionary GetCollectors() 76 | { 77 | return _collectors; 78 | } 79 | 80 | /// 81 | /// Set the default sample size for all collectors (w/o explicit size). 82 | /// 83 | /// 84 | public void SetDefaultSampleSize(int? samples) 85 | { 86 | _defaultSamples = samples ?? _defaultSamples; 87 | } 88 | 89 | /// 90 | /// Configure a collector by name with the given sample size. 91 | /// 92 | /// 93 | /// 94 | public void ConfigureCollector(string name, int? samples = null) 95 | { 96 | _collectors[name] = new HealthMetricCollector(samples ?? _defaultSamples); 97 | } 98 | } -------------------------------------------------------------------------------- /RockLib.HealthChecks.AspNetCore/Collector/HttpResponseCollector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | 6 | namespace RockLib.HealthChecks.AspNetCore.Collector; 7 | 8 | /// 9 | /// A delegating handler that collects the status code of the response from an HTTP request. 10 | /// 11 | /// Added to the HttpClient pipeline to collect response status codes. 12 | public class HttpResponseCollector : DelegatingHandler 13 | { 14 | private readonly IHealthMetricCollectorFactory _factory; 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// 20 | public HttpResponseCollector(IHealthMetricCollectorFactory factory) 21 | { 22 | _factory = factory; 23 | } 24 | 25 | /// 26 | /// Sends an HTTP request to the inner handler to send to the server as an asynchronous operation. 27 | /// Records the status code of the response in the for the host of the request. 28 | /// 29 | /// 30 | /// 31 | /// 32 | protected async override Task SendAsync(HttpRequestMessage request, 33 | CancellationToken cancellationToken) 34 | { 35 | #if NET6_0_OR_GREATER 36 | ArgumentNullException.ThrowIfNull(request); 37 | #else 38 | if (request is null) { throw new ArgumentNullException(nameof(request)); } 39 | #endif 40 | var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false); 41 | _factory.LeaseCollector(request.RequestUri?.Host).Collect((int)response.StatusCode); 42 | return response; 43 | } 44 | } -------------------------------------------------------------------------------- /RockLib.HealthChecks.AspNetCore/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | 6 | all 7 | Rocket Mortgage 8 | Copyright 2025 (c) Rocket Mortgage. All rights reserved. 9 | latest 10 | enable 11 | net8.0;net48 12 | NU1603,NU1701 13 | true 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.AspNetCore/HealthCheckMiddlewareExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.Extensions.Hosting; 4 | using System; 5 | using System.Linq; 6 | 7 | namespace RockLib.HealthChecks.AspNetCore; 8 | 9 | /// 10 | /// Extensions for using RockLib.HealthChecks with ASP.NET Core middleware. 11 | /// 12 | public static class HealthCheckMiddlewareExtensions 13 | { 14 | /// 15 | /// Adds a terminal to the application. 16 | /// 17 | /// The application builder. 18 | /// 19 | /// The name of the health runner that will perform health checks for the health endpoint. 20 | /// 21 | /// The route of the health endpoint. 22 | /// 23 | /// The responsible for formatting health responses for the middleware's HTTP response body. 24 | /// 25 | /// The application builder. 26 | public static IApplicationBuilder UseRockLibHealthChecks(this IApplicationBuilder builder, 27 | string healthCheckRunnerName = "", string route = "/health", IResponseFormatter? formatter = null) 28 | { 29 | #if NET6_0_OR_GREATER 30 | ArgumentNullException.ThrowIfNull(builder); 31 | ArgumentNullException.ThrowIfNull(healthCheckRunnerName); 32 | ArgumentNullException.ThrowIfNull(route); 33 | #else 34 | if (builder is null) { throw new ArgumentNullException(nameof(builder)); } 35 | if (healthCheckRunnerName is null) { throw new ArgumentNullException(nameof(healthCheckRunnerName)); } 36 | if (route is null) { throw new ArgumentNullException(nameof(route)); } 37 | #endif 38 | 39 | var path = new PathString($"/{route.Trim('/')}"); 40 | 41 | return builder.Map(path, appBuilder => 42 | appBuilder.UseMiddleware(healthCheckRunnerName, formatter ?? NewtonsoftJsonResponseFormatter.DefaultInstance)); 43 | } 44 | 45 | /// 46 | /// Exposes a means for health check dependencies to be integrated into the application. 47 | /// 48 | /// the application builder 49 | /// The application builder. 50 | public static IHostApplicationBuilder ConfigureRockLibHealthChecks(this IHostApplicationBuilder builder) 51 | { 52 | #if NET6_0_OR_GREATER 53 | ArgumentNullException.ThrowIfNull(builder); 54 | #else 55 | if (builder is null) { throw new ArgumentNullException(nameof(builder)); } 56 | #endif 57 | 58 | var config = builder.Configuration.GetSection("RockLib.HealthChecks"); 59 | var checks = config.GetSection("healthChecks").GetChildren().ToArray(); 60 | foreach (var checkCfg in checks) 61 | { 62 | var typeStr = checkCfg["type"]; 63 | if (string.IsNullOrWhiteSpace(typeStr)) continue; 64 | 65 | Type.GetType(typeStr)?.GetMethod("Configure")?.Invoke(null, [builder]); 66 | Console.WriteLine($"Configured health check: {typeStr}"); 67 | } 68 | 69 | return builder; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.AspNetCore/IResponseFormatter.cs: -------------------------------------------------------------------------------- 1 | namespace RockLib.HealthChecks.AspNetCore; 2 | 3 | /// 4 | /// Defines an object that formats objects. 5 | /// 6 | public interface IResponseFormatter 7 | { 8 | /// 9 | /// Formats the specified . 10 | /// 11 | /// The to format. 12 | /// The formatted . 13 | string Format(HealthResponse healthResponse); 14 | } 15 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.AspNetCore/NewtonsoftJsonResponseFormatter.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | 4 | namespace RockLib.HealthChecks.AspNetCore; 5 | 6 | /// 7 | /// An implementation of that formats health responses as draft 8 | /// RFC compliant JSON using Newtonsoft.Json. 9 | /// 10 | public class NewtonsoftJsonResponseFormatter : IResponseFormatter 11 | { 12 | internal static readonly NewtonsoftJsonResponseFormatter DefaultInstance = new NewtonsoftJsonResponseFormatter(); 13 | 14 | /// 15 | /// Initializes a new instance of the class. 16 | /// 17 | /// The formatting options. 18 | /// The JSON serializer settings. 19 | public NewtonsoftJsonResponseFormatter(Formatting formatting = Formatting.None, JsonSerializerSettings? settings = null) 20 | { 21 | if (!Enum.IsDefined(typeof(Formatting), formatting)) 22 | { 23 | throw new ArgumentOutOfRangeException(nameof(formatting)); 24 | } 25 | 26 | Formatting = formatting; 27 | Settings = settings; 28 | } 29 | 30 | /// 31 | /// Gets the formatting options. 32 | /// 33 | public Formatting Formatting { get; } 34 | 35 | /// 36 | /// Gets the JSON serializer settings. 37 | /// 38 | public JsonSerializerSettings? Settings { get; } 39 | 40 | /// 41 | /// Formats the specified as draft RFC compliant JSON. 42 | /// 43 | /// The to format. 44 | /// The formatted . 45 | public string Format(HealthResponse healthResponse) 46 | { 47 | #if NET6_0_OR_GREATER 48 | ArgumentNullException.ThrowIfNull(healthResponse); 49 | #else 50 | if (healthResponse is null) { throw new ArgumentNullException(nameof(healthResponse)); } 51 | #endif 52 | 53 | return JsonConvert.SerializeObject(healthResponse, typeof(HealthResponse), Formatting, Settings); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.AspNetCore/RockLib.HealthChecks.AspNetCore.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Embedded 4 | A simple set of .NET Core Middleware extensions for adding Health Checks to your web application. 5 | True 6 | True 7 | icon.png 8 | RockLib.HealthChecks.AspNetCore 9 | LICENSE.md 10 | https://github.com/RockLib/RockLib.HealthChecks 11 | A changelog is available at https://github.com/RockLib/RockLib.HealthChecks/blob/main/RockLib.HealthChecks.AspNetCore/CHANGELOG.md. 12 | false 13 | rocklib health checks aspnetcore middleware 14 | 5.0.0 15 | True 16 | 5.0.0 17 | 18 | 19 | bin\$(Configuration)\$(TargetFramework)\$(PackageId).xml 20 | 21 | 22 | true 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.AspNetCore/RockLib.HealthChecks.AspNetCore.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.33110.190 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RockLib.HealthChecks.AspNetCore", "RockLib.HealthChecks.AspNetCore.csproj", "{2374AEAA-E75B-4C25-9CC0-54E214D1F772}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B551CDB9-DDCF-45A8-85EF-51EEB96E92DD}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RockLib.HealthChecks.AspNetCore.Tests", "..\Tests\RockLib.HealthChecks.AspNetCore.Tests\RockLib.HealthChecks.AspNetCore.Tests.csproj", "{3B860C82-1B81-4E13-A1A7-1C690A19E138}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {2374AEAA-E75B-4C25-9CC0-54E214D1F772}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {2374AEAA-E75B-4C25-9CC0-54E214D1F772}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {2374AEAA-E75B-4C25-9CC0-54E214D1F772}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {2374AEAA-E75B-4C25-9CC0-54E214D1F772}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {3B860C82-1B81-4E13-A1A7-1C690A19E138}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {3B860C82-1B81-4E13-A1A7-1C690A19E138}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {3B860C82-1B81-4E13-A1A7-1C690A19E138}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {3B860C82-1B81-4E13-A1A7-1C690A19E138}.Release|Any CPU.Build.0 = Release|Any CPU 26 | EndGlobalSection 27 | GlobalSection(SolutionProperties) = preSolution 28 | HideSolutionNode = FALSE 29 | EndGlobalSection 30 | GlobalSection(ExtensibilityGlobals) = postSolution 31 | SolutionGuid = {9BD2137B-45A2-4572-9151-93471F4F7CC9} 32 | EndGlobalSection 33 | EndGlobal 34 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.Client/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | 6 | [*.cs] 7 | # Styling 8 | indent_style = space 9 | indent_size = 4 10 | csharp_indent_case_contents = true 11 | csharp_indent_switch_labels = true 12 | csharp_new_line_before_catch = true 13 | csharp_new_line_before_else = true 14 | csharp_new_line_before_finally = true 15 | csharp_new_line_before_members_in_anonymous_types = false 16 | csharp_new_line_before_members_in_object_initializers = false 17 | csharp_new_line_before_open_brace = methods, control_blocks, types, properties, lambdas, accessors, object_collection_array_initializers 18 | csharp_new_line_between_query_expression_clauses = true 19 | csharp_prefer_braces = false:suggestion 20 | csharp_prefer_simple_default_expression = true:suggestion 21 | csharp_preferred_modifier_order = public,private,internal,protected,static,readonly,async,override,sealed:suggestion 22 | csharp_preserve_single_line_blocks = true 23 | csharp_preserve_single_line_statements = true 24 | csharp_space_after_cast = false 25 | csharp_space_after_colon_in_inheritance_clause = true 26 | csharp_space_after_keywords_in_control_flow_statements = true 27 | csharp_space_before_colon_in_inheritance_clause = true 28 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 29 | csharp_space_between_method_call_name_and_opening_parenthesis = false 30 | csharp_space_between_method_call_parameter_list_parentheses = false 31 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 32 | csharp_space_between_method_declaration_parameter_list_parentheses = false 33 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 34 | csharp_style_expression_bodied_accessors = true:suggestion 35 | csharp_style_expression_bodied_constructors = false:suggestion 36 | csharp_style_expression_bodied_methods = false:suggestion 37 | csharp_style_expression_bodied_properties = true:suggestion 38 | csharp_style_inlined_variable_declaration = true:suggestion 39 | csharp_style_var_elsewhere = true:suggestion 40 | csharp_style_var_for_built_in_types = true:suggestion 41 | csharp_style_var_when_type_is_apparent = true:suggestion 42 | dotnet_sort_system_directives_first = false 43 | dotnet_style_explicit_tuple_names = true:suggestion 44 | dotnet_style_object_initializer = true:suggestion 45 | csharp_style_pattern_local_over_anonymous_function = false:suggestion 46 | dotnet_style_predefined_type_for_member_access = true:suggestion 47 | dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion 48 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 49 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 50 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion 51 | dotnet_style_qualification_for_field = false:suggestion 52 | dotnet_style_qualification_for_method = false:suggestion 53 | dotnet_style_qualification_for_property = false:suggestion 54 | 55 | 56 | # Analyzer Configuration 57 | # These are rules we want to either ignore or have set as suggestion or info 58 | 59 | # CA1014: Mark assemblies with CLSCompliant 60 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1014 61 | dotnet_diagnostic.CA1014.severity = none 62 | 63 | # CA1725: Parameter names should match base declaration 64 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1725 65 | dotnet_diagnostic.CA1725.severity = suggestion 66 | 67 | # CA2227: Collection properties should be read only 68 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2227 69 | dotnet_diagnostic.CA2227.severity = suggestion 70 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.Client/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # RockLib.HealthChecks.Client Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## 3.0.0 - 2025-02-05 9 | 10 | #### Changed 11 | - Finalized 3.0.0 version 12 | 13 | ## 3.0.0-alpha.1 - 2025-02-05 14 | 15 | #### Changed 16 | - Removed .NET 6 as a target framework 17 | 18 | ## 2.0.2 - 2024-10-10 19 | 20 | #### Changed 21 | System.Text.Json.8.0.4 -> System.Text.Json.8.0.5 to fix vulnerability 22 | 23 | ## 2.0.1 - 2024-07-16 24 | 25 | #### Changed 26 | System.Text.Json.8.0.2 -> System.Text.Json.8.0.4 to fix vulnerability 27 | 28 | ## 2.0.0 - 2024-03-04 29 | 30 | #### Changed 31 | - Removed netcoreapp3.1 from supported targets. 32 | - Added net8.0 to supported targets. 33 | - Updated package references. 34 | 35 | ## 2.0.0-alpha.1 - 2024-02-29 36 | 37 | #### Changed 38 | - Removed netcoreapp3.1 from supported targets from test project. 39 | - Added net8.0 to supported targets to test project. 40 | - Updated package references in test project. 41 | 42 | ## 1.0.0 - 2022-03-03 43 | 44 | #### Added 45 | - Added `.editorconfig` and `Directory.Build.props` files to ensure consistency. 46 | 47 | #### Changed 48 | - Supported targets: net6.0, netcoreapp3.1, and net48. 49 | - As the package now uses nullable reference types, some method parameters now specify if they can accept nullable values. 50 | 51 | ## 1.0.0-alpha03 - 2021-08-13 52 | 53 | #### Changed 54 | 55 | - Changes "Quicken Loans" to "Rocket Mortgage". 56 | 57 | ## 1.0.0-alpha02 - 2021-05-10 58 | 59 | #### Added 60 | 61 | - Adds SourceLink to nuget package. 62 | 63 | #### Changed 64 | 65 | - Updates System.Text.Json package to latest version. 66 | 67 | ---- 68 | 69 | **Note:** Release notes in the above format are not available for earlier versions of 70 | RockLib.HealthChecks.Client. What follows below are the original release notes. 71 | 72 | ---- 73 | 74 | ## 1.0.0-alpha01 75 | 76 | Initial prerelease. 77 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.Client/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | 6 | all 7 | Rocket Mortgage 8 | Copyright 2025 (c) Rocket Mortgage. All rights reserved. 9 | latest 10 | enable 11 | net8.0;net48 12 | NU1603,NU1701 13 | true 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.Client/HealthCheckResultJsonConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text.Json; 4 | using System.Text.Json.Serialization; 5 | 6 | namespace RockLib.HealthChecks.Client 7 | { 8 | /// 9 | /// A implementation for deserializing types from json. 10 | /// 11 | public class HealthCheckResultJsonConverter : JsonConverter 12 | { 13 | /// 14 | public override HealthCheckResult Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 15 | { 16 | if (reader.TokenType != JsonTokenType.StartObject) 17 | { 18 | throw new JsonException($"JsonTokenType was of type {reader.TokenType}, only objects are supported"); 19 | } 20 | 21 | var result = new HealthCheckResult(); 22 | while (reader.Read()) 23 | { 24 | if (reader.TokenType == JsonTokenType.EndObject) 25 | { 26 | return result; 27 | } 28 | 29 | if (reader.TokenType != JsonTokenType.PropertyName) 30 | { 31 | throw new JsonException("JsonTokenType was not PropertyName"); 32 | } 33 | 34 | var propertyName = reader.GetString()!; 35 | 36 | if (string.IsNullOrWhiteSpace(propertyName)) 37 | { 38 | throw new JsonException("Failed to get property name"); 39 | } 40 | 41 | reader.Read(); 42 | 43 | result.Add(propertyName, ExtractValue(ref reader, options)); 44 | } 45 | 46 | return result; 47 | } 48 | 49 | /// 50 | public override void Write(Utf8JsonWriter writer, HealthCheckResult value, JsonSerializerOptions options) 51 | { 52 | JsonSerializer.Serialize(writer, value, options); 53 | } 54 | 55 | private object? ExtractValue(ref Utf8JsonReader reader, JsonSerializerOptions options) 56 | { 57 | switch (reader.TokenType) 58 | { 59 | case JsonTokenType.String: 60 | if (reader.TryGetDateTime(out var date)) 61 | { 62 | return date; 63 | } 64 | return reader.GetString(); 65 | case JsonTokenType.False: 66 | return false; 67 | case JsonTokenType.True: 68 | return true; 69 | case JsonTokenType.Null: 70 | return null; 71 | case JsonTokenType.Number: 72 | if (reader.TryGetInt64(out var result)) 73 | { 74 | return result; 75 | } 76 | return reader.GetDecimal(); 77 | case JsonTokenType.StartObject: 78 | return Read(ref reader, null!, options); 79 | case JsonTokenType.StartArray: 80 | var list = new List(); 81 | while (reader.Read() && reader.TokenType != JsonTokenType.EndArray) 82 | { 83 | list.Add(ExtractValue(ref reader, options)); 84 | } 85 | return list; 86 | default: 87 | throw new JsonException($"'{reader.TokenType}' is not supported"); 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.Client/HealthResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace RockLib.HealthChecks.Client 5 | { 6 | /// 7 | /// Represents the response from a service to a health request. 8 | /// 9 | public class HealthResponse 10 | { 11 | /// 12 | /// Gets or sets whether the service status is acceptable or not. 13 | /// 14 | [JsonConverter(typeof(JsonStringEnumConverter))] 15 | [JsonPropertyName("status")] 16 | public HealthStatus Status { get; set; } 17 | 18 | /// 19 | /// Gets or sets the public version of the service. 20 | /// 21 | [JsonPropertyName("version")] 22 | public string? Version { get; set; } 23 | 24 | /// 25 | /// Gets or sets the "release version" or "release ID" of the service. 26 | /// 27 | [JsonPropertyName("releaseId")] 28 | public string? ReleaseId { get; set; } 29 | 30 | /// 31 | /// Gets or sets a list of notes relevant to current state of health. 32 | /// 33 | [JsonPropertyName("notes")] 34 | #pragma warning disable CA1002 // Do not expose generic lists 35 | public List? Notes { get; set; } 36 | #pragma warning restore CA1002 // Do not expose generic lists 37 | 38 | /// 39 | /// Gets or sets the raw error output, in case of or states. This field SHOULD be omitted for 41 | /// state. 42 | /// 43 | [JsonPropertyName("output")] 44 | public string? Output { get; set; } 45 | 46 | /// 47 | /// Gets or sets a unique identifier of the service, in the application scope. 48 | /// 49 | [JsonPropertyName("serviceId")] 50 | public string? ServiceId { get; set; } 51 | 52 | /// 53 | /// Gets or sets a human-friendly description of the service. 54 | /// 55 | [JsonPropertyName("description")] 56 | public string? Description { get; set; } 57 | 58 | /// 59 | /// Gets the health check results of the logical downstream dependencies and sub-components of the 60 | /// service according the component name and measurement name of the health check result. 61 | /// 62 | [JsonPropertyName("checks")] 63 | public Dictionary>? Checks { get; set; } 64 | 65 | /// 66 | /// Gets or sets a dictionary containing link relations and URIs [RFC3986] for external links that 67 | /// MAY contain more information about the health of the endpoint. All values of this object SHALL 68 | /// be URIs. Keys MAY also be URIs. Per web-linking standards [RFC8288] a link relationship SHOULD 69 | /// either be a common/registered one or be indicated as a URI, to avoid name clashes. If a 'self' 70 | /// link is provided, it MAY be used by clients to check health via HTTP response code. 71 | /// 72 | [JsonPropertyName("links")] 73 | public Dictionary? Links { get; set; } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.Client/HealthStatus.cs: -------------------------------------------------------------------------------- 1 | namespace RockLib.HealthChecks.Client 2 | { 3 | /// 4 | /// Defines the values for the health status of a service or component. 5 | /// 6 | public enum HealthStatus 7 | { 8 | /// 9 | /// The service or component is healthy. 10 | /// 11 | Pass = 0, 12 | 13 | /// 14 | /// The service or component is healthy, with concerns. 15 | /// 16 | Warn = 1, 17 | 18 | /// 19 | /// The service or component is unhealthy. 20 | /// 21 | Fail = 2 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.Client/NullableAttributes.cs: -------------------------------------------------------------------------------- 1 | #if NET48 2 | // This code is copied from https://source.dot.net/#System.Private.CoreLib/NullableAttributes.cs 3 | // and is only used for .NET 4.8 4 | using System; 5 | 6 | namespace System.Diagnostics.CodeAnalysis 7 | { 8 | /// 9 | /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. 10 | /// 11 | [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] 12 | public sealed class MaybeNullWhenAttribute : Attribute 13 | { 14 | /// Initializes the attribute with the specified return value condition. 15 | /// 16 | /// The return value condition. If the method returns this value, the associated parameter may be null. 17 | /// 18 | public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; 19 | 20 | /// Gets the return value condition. 21 | public bool ReturnValue { get; } 22 | } 23 | } 24 | #endif -------------------------------------------------------------------------------- /RockLib.HealthChecks.Client/RockLib.HealthChecks.Client.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Embedded 4 | A set of POCOs used to deserialize the RockLib.HealthChecks response. 5 | True 6 | True 7 | icon.png 8 | RockLib.HealthChecks.Client 9 | LICENSE.md 10 | https://github.com/RockLib/RockLib.HealthChecks 11 | false 12 | A changelog is available at https://github.com/RockLib/RockLib.HealthChecks/blob/main/RockLib.HealthChecks.Client/CHANGELOG.md. 13 | rocklib health checks client 14 | 3.0.0 15 | True 16 | 3.0.0 17 | 18 | 19 | bin\$(Configuration)\$(TargetFramework)\$(PackageId).xml 20 | 21 | 22 | true 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.Client/RockLib.HealthChecks.Client.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29001.49 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RockLib.HealthChecks.Client", "RockLib.HealthChecks.Client.csproj", "{2868E92B-CC2B-4D4A-B62D-B324A8E484C0}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RockLib.HealthChecks.Client.Tests", "..\Tests\RockLib.HealthChecks.Client.Tests\RockLib.HealthChecks.Client.Tests.csproj", "{0E738824-8F16-4102-9876-9FC528F25240}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {2868E92B-CC2B-4D4A-B62D-B324A8E484C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {2868E92B-CC2B-4D4A-B62D-B324A8E484C0}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {2868E92B-CC2B-4D4A-B62D-B324A8E484C0}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {2868E92B-CC2B-4D4A-B62D-B324A8E484C0}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {0E738824-8F16-4102-9876-9FC528F25240}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {0E738824-8F16-4102-9876-9FC528F25240}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {0E738824-8F16-4102-9876-9FC528F25240}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {0E738824-8F16-4102-9876-9FC528F25240}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {9BD2137B-45A2-4572-9151-93471F4F7CC9} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.HttpModule/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | 6 | [*.cs] 7 | # Styling 8 | indent_style = space 9 | indent_size = 4 10 | csharp_indent_case_contents = true 11 | csharp_indent_switch_labels = true 12 | csharp_new_line_before_catch = true 13 | csharp_new_line_before_else = true 14 | csharp_new_line_before_finally = true 15 | csharp_new_line_before_members_in_anonymous_types = false 16 | csharp_new_line_before_members_in_object_initializers = false 17 | csharp_new_line_before_open_brace = methods, control_blocks, types, properties, lambdas, accessors, object_collection_array_initializers 18 | csharp_new_line_between_query_expression_clauses = true 19 | csharp_prefer_braces = false:suggestion 20 | csharp_prefer_simple_default_expression = true:suggestion 21 | csharp_preferred_modifier_order = public,private,internal,protected,static,readonly,async,override,sealed:suggestion 22 | csharp_preserve_single_line_blocks = true 23 | csharp_preserve_single_line_statements = true 24 | csharp_space_after_cast = false 25 | csharp_space_after_colon_in_inheritance_clause = true 26 | csharp_space_after_keywords_in_control_flow_statements = true 27 | csharp_space_before_colon_in_inheritance_clause = true 28 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 29 | csharp_space_between_method_call_name_and_opening_parenthesis = false 30 | csharp_space_between_method_call_parameter_list_parentheses = false 31 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 32 | csharp_space_between_method_declaration_parameter_list_parentheses = false 33 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 34 | csharp_style_expression_bodied_accessors = true:suggestion 35 | csharp_style_expression_bodied_constructors = false:suggestion 36 | csharp_style_expression_bodied_methods = false:suggestion 37 | csharp_style_expression_bodied_properties = true:suggestion 38 | csharp_style_inlined_variable_declaration = true:suggestion 39 | csharp_style_var_elsewhere = true:suggestion 40 | csharp_style_var_for_built_in_types = true:suggestion 41 | csharp_style_var_when_type_is_apparent = true:suggestion 42 | dotnet_sort_system_directives_first = false 43 | dotnet_style_explicit_tuple_names = true:suggestion 44 | dotnet_style_object_initializer = true:suggestion 45 | csharp_style_pattern_local_over_anonymous_function = false:suggestion 46 | dotnet_style_predefined_type_for_member_access = true:suggestion 47 | dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion 48 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 49 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 50 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion 51 | dotnet_style_qualification_for_field = false:suggestion 52 | dotnet_style_qualification_for_method = false:suggestion 53 | dotnet_style_qualification_for_property = false:suggestion 54 | 55 | 56 | # Analyzer Configuration 57 | # These are rules we want to either ignore or have set as suggestion or info 58 | 59 | # CA1014: Mark assemblies with CLSCompliant 60 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1014 61 | dotnet_diagnostic.CA1014.severity = none 62 | 63 | # CA1725: Parameter names should match base declaration 64 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1725 65 | dotnet_diagnostic.CA1725.severity = suggestion 66 | 67 | # CA2227: Collection properties should be read only 68 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2227 69 | dotnet_diagnostic.CA2227.severity = suggestion 70 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.HttpModule/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # RockLib.HealthChecks.HttpModule Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## 3.0.0 - 2025-02-05 9 | 10 | #### Changed 11 | - Finalized 3.0.0 version 12 | - RockLib.HealthChecks.4.0.0-alpha.1 -> RockLib.HealthChecks.4.0.0 13 | 14 | ## 3.0.0-alpha.1 - 2025-02-05 15 | 16 | #### Changed 17 | - RockLib.HealthChecks.3.0.2 -> RockLib.HealthChecks.4.0.0-alpha.1 18 | 19 | ## 2.0.2 - 2024-11-05 20 | 21 | #### Changed 22 | - RockLib.HealthChecks.3.0.1 -> RockLib.HealthChecks.3.0.2 to fix vulnerability 23 | 24 | ## 2.0.1 - 2024-07-16 25 | 26 | #### Changed 27 | - RockLib.HealthChecks.2.0.1 -> RockLib.HealthChecks.3.0.1 to fix vulnerability 28 | 29 | ## 2.0.0 - 2024-03-04 30 | 31 | #### Changed 32 | - Removed netcoreapp3.1 from supported targets. 33 | - Added net8.0 to supported targets. 34 | - Updated package references. 35 | 36 | ## 2.0.0-alpha.2 - 2023-03-02 37 | 38 | #### Changed 39 | - Added a null check for the context and disabled warnings about catching general exceptions. 40 | - Updated RockLib.HealthChecks dependency to 2.0.1. 41 | 42 | ## 2.0.0-alpha.1 - 2022-12-15 43 | 44 | #### Added 45 | - Added `.editorconfig` and `Directory.Build.props` files to ensure consistency. 46 | 47 | #### Changed 48 | - Supported targets: net48. 49 | - As the package now uses nullable reference types, some method parameters now specify if they can accept nullable values. 50 | 51 | ## 1.0.5 - 2021-08-13 52 | 53 | #### Changed 54 | 55 | - Changes "Quicken Loans" to "Rocket Mortgage". 56 | - Updates RockLib.HealthChecks to latest version, [1.3.9](https://github.com/RockLib/RockLib.HealthChecks/blob/main/RockLib.HealthChecks/CHANGELOG.md#139---2021-08-13). 57 | 58 | ## 1.0.4 - 2021-05-10 59 | 60 | #### Added 61 | 62 | - Adds SourceLink to nuget package. 63 | 64 | #### Changed 65 | 66 | - Updates RockLib.HealthChecks package to latest version, which includes SourceLink. 67 | 68 | ---- 69 | 70 | **Note:** Release notes in the above format are not available for earlier versions of 71 | RockLib.HealthChecks.HttpModule. What follows below are the original release notes. 72 | 73 | ---- 74 | 75 | ## 1.0.3 76 | 77 | Updates dependencies. 78 | 79 | ## 1.0.2 80 | 81 | Adds icon to project and nuget package. 82 | 83 | ## 1.0.1 84 | 85 | Updates to align with nuget conventions. 86 | 87 | ## 1.0.0 88 | 89 | Initial release. 90 | 91 | ## 1.0.0-rc1 92 | 93 | Initial release candidate. 94 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.HttpModule/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | all 4 | Rocket Mortgage 5 | Copyright 2025 (c) Rocket Mortgage. All rights reserved. 6 | true 7 | latest 8 | enable 9 | NU1603,NU1701 10 | true 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | 17 | 18 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.HttpModule/RockLib.HealthChecks.HttpModule.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Embedded 4 | A simple HTTP Module you can add to a web application for running Health Checks. 5 | True 6 | True 7 | icon.png 8 | RockLib.HealthChecks.HttpModule 9 | LICENSE.md 10 | https://github.com/RockLib/RockLib.HealthChecks 11 | A changelog is available at https://github.com/RockLib/RockLib.HealthChecks/blob/main/RockLib.HealthChecks.HttpModule/CHANGELOG.md. 12 | false 13 | rocklib health checks httpmodule 14 | 3.0.0 15 | True 16 | 20 | net48 21 | 3.0.0 22 | 23 | 24 | bin\$(Configuration)\$(TargetFramework)\$(PackageId).xml 25 | 26 | 27 | true 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.HttpModule/RockLib.HealthChecks.HttpModule.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.33110.190 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RockLib.HealthChecks.HttpModule", "RockLib.HealthChecks.HttpModule.csproj", "{482209AA-CA19-40B1-9D32-083CC50C2B88}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RockLib.HealthChecks.HttpModule.Tests", "..\Tests\RockLib.HealthChecks.HttpModule.Tests\RockLib.HealthChecks.HttpModule.Tests.csproj", "{3E5A4216-4F09-461D-9AB3-E6713E3C1225}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {482209AA-CA19-40B1-9D32-083CC50C2B88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {482209AA-CA19-40B1-9D32-083CC50C2B88}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {482209AA-CA19-40B1-9D32-083CC50C2B88}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {482209AA-CA19-40B1-9D32-083CC50C2B88}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {3E5A4216-4F09-461D-9AB3-E6713E3C1225}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {3E5A4216-4F09-461D-9AB3-E6713E3C1225}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {3E5A4216-4F09-461D-9AB3-E6713E3C1225}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {3E5A4216-4F09-461D-9AB3-E6713E3C1225}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {9BD2137B-45A2-4572-9151-93471F4F7CC9} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.WebApi/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | 6 | [*.cs] 7 | # Styling 8 | indent_style = space 9 | indent_size = 4 10 | csharp_indent_case_contents = true 11 | csharp_indent_switch_labels = true 12 | csharp_new_line_before_catch = true 13 | csharp_new_line_before_else = true 14 | csharp_new_line_before_finally = true 15 | csharp_new_line_before_members_in_anonymous_types = false 16 | csharp_new_line_before_members_in_object_initializers = false 17 | csharp_new_line_before_open_brace = methods, control_blocks, types, properties, lambdas, accessors, object_collection_array_initializers 18 | csharp_new_line_between_query_expression_clauses = true 19 | csharp_prefer_braces = false:suggestion 20 | csharp_prefer_simple_default_expression = true:suggestion 21 | csharp_preferred_modifier_order = public,private,internal,protected,static,readonly,async,override,sealed:suggestion 22 | csharp_preserve_single_line_blocks = true 23 | csharp_preserve_single_line_statements = true 24 | csharp_space_after_cast = false 25 | csharp_space_after_colon_in_inheritance_clause = true 26 | csharp_space_after_keywords_in_control_flow_statements = true 27 | csharp_space_before_colon_in_inheritance_clause = true 28 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 29 | csharp_space_between_method_call_name_and_opening_parenthesis = false 30 | csharp_space_between_method_call_parameter_list_parentheses = false 31 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 32 | csharp_space_between_method_declaration_parameter_list_parentheses = false 33 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 34 | csharp_style_expression_bodied_accessors = true:suggestion 35 | csharp_style_expression_bodied_constructors = false:suggestion 36 | csharp_style_expression_bodied_methods = false:suggestion 37 | csharp_style_expression_bodied_properties = true:suggestion 38 | csharp_style_inlined_variable_declaration = true:suggestion 39 | csharp_style_var_elsewhere = true:suggestion 40 | csharp_style_var_for_built_in_types = true:suggestion 41 | csharp_style_var_when_type_is_apparent = true:suggestion 42 | dotnet_sort_system_directives_first = false 43 | dotnet_style_explicit_tuple_names = true:suggestion 44 | dotnet_style_object_initializer = true:suggestion 45 | csharp_style_pattern_local_over_anonymous_function = false:suggestion 46 | dotnet_style_predefined_type_for_member_access = true:suggestion 47 | dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion 48 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 49 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 50 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion 51 | dotnet_style_qualification_for_field = false:suggestion 52 | dotnet_style_qualification_for_method = false:suggestion 53 | dotnet_style_qualification_for_property = false:suggestion 54 | 55 | 56 | # Analyzer Configuration 57 | # These are rules we want to either ignore or have set as suggestion or info 58 | 59 | # CA1014: Mark assemblies with CLSCompliant 60 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1014 61 | dotnet_diagnostic.CA1014.severity = none 62 | 63 | # CA1725: Parameter names should match base declaration 64 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1725 65 | dotnet_diagnostic.CA1725.severity = suggestion 66 | 67 | # CA2227: Collection properties should be read only 68 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2227 69 | dotnet_diagnostic.CA2227.severity = suggestion 70 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.WebApi/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # RockLib.HealthChecks.WebApi Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## 4.0.0 - 2025-02-05 9 | 10 | #### Changed 11 | - Finalized 4.0.0 vesion 12 | - RockLib.HealthChecks.4.0.0-alpha.1 -> RockLib.HealthChecks.4.0.0 13 | 14 | ## 4.0.0-alpha.1 - 2025-02-05 15 | 16 | #### Changed 17 | - RockLib.HealthChecks.3.0.2 -> RockLib.HealthChecks.4.0.0-alpha.1 18 | 19 | ## 3.0.2 - 2024-11-05 20 | 21 | #### Changed 22 | - RockLib.HealthChecks.3.0.1 -> RockLib.HealthChecks.3.0.2 to fix vulnerability 23 | 24 | ## 3.0.1 - 2024-07-16 25 | 26 | #### Changed 27 | - RockLib.HealthChecks.3.0.0 -> RockLib.HealthChecks.3.0.1 to fix vulnerability 28 | 29 | ## 3.0.0 - 2024-03-04 30 | 31 | #### Changed 32 | - Removed netcoreapp3.1 from supported targets. 33 | - Added net8.0 to supported targets. 34 | - Updated package references. 35 | 36 | ## 3.0.0-alpha.1 - 2024-02-29 37 | 38 | #### Changed 39 | - Removed netcoreapp3.1 from supported targets from test project. 40 | - Added net8.0 to supported targets to test project. 41 | - Updated package references in test project. 42 | 43 | ## 2.0.0-alpha.2 - 2023-03-02 44 | 45 | #### Changed 46 | - Updated RockLib.HealthChecks dependency to 2.0.1. 47 | 48 | ## 2.0.0-alpha.1 - 2022-12-14 49 | 50 | #### Added 51 | - Added `.editorconfig` and `Directory.Build.props` files to ensure consistency. 52 | 53 | #### Changed 54 | - Supported targets: net6.0, netcoreapp3.1, and net48. 55 | - As the package now uses nullable reference types, some method parameters now specify if they can accept nullable values. 56 | 57 | ## 1.0.5 - 2021-08-13 58 | 59 | #### Changed 60 | 61 | - Changes "Quicken Loans" to "Rocket Mortgage". 62 | - Updates RockLib.HealthChecks to latest version, [1.3.9](https://github.com/RockLib/RockLib.HealthChecks/blob/main/RockLib.HealthChecks/CHANGELOG.md#139---2021-08-13). 63 | 64 | ## 1.0.4 - 2021-05-10 65 | 66 | #### Added 67 | 68 | - Adds SourceLink to nuget package. 69 | 70 | #### Changed 71 | 72 | - Updates RockLib.HealthChecks package to latest version, which includes SourceLink. 73 | 74 | ---- 75 | 76 | **Note:** Release notes in the above format are not available for earlier versions of 77 | RockLib.HealthChecks.WebApi. What follows below are the original release notes. 78 | 79 | ---- 80 | 81 | ## 1.0.3 82 | 83 | Updates dependencies. 84 | 85 | ## 1.0.2 86 | 87 | Adds icon to project and nuget package. 88 | 89 | ## 1.0.1 90 | 91 | Updates to align with nuget conventions. 92 | 93 | ## 1.0.0 94 | 95 | Initial release. 96 | 97 | ## 1.0.0-rc1 98 | 99 | Initial release candidate. 100 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.WebApi/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | 6 | all 7 | Rocket Mortgage 8 | Copyright 2024 (c) Rocket Mortgage. All rights reserved. 9 | latest 10 | enable 11 | net8.0;net48 12 | NU1603,NU1701 13 | true 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.WebApi/HealthCheckHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Net.Http; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace RockLib.HealthChecks.WebApi; 9 | 10 | /// 11 | /// A message handler for running health checks. 12 | /// 13 | public sealed class HealthCheckHandler : HttpMessageHandler 14 | { 15 | private readonly IHealthCheckRunner _healthCheckRunner; 16 | private readonly bool _indent; 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | /// 22 | /// The that evaluates the health of the service. 23 | /// 24 | /// Whether to indent the JSON output. 25 | public HealthCheckHandler(IHealthCheckRunner healthCheckRunner, bool indent) 26 | { 27 | _healthCheckRunner = healthCheckRunner ?? throw new ArgumentNullException(nameof(healthCheckRunner)); 28 | _indent = indent; 29 | } 30 | 31 | /// 32 | protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 33 | { 34 | var healthCheckResponse = await _healthCheckRunner.RunAsync(cancellationToken).ConfigureAwait(false); 35 | 36 | var response = new HttpResponseMessage 37 | { 38 | StatusCode = (HttpStatusCode)healthCheckResponse.StatusCode, 39 | Content = new StringContent(healthCheckResponse.Serialize(_indent), Encoding.UTF8, healthCheckResponse.ContentType) 40 | }; 41 | 42 | return response; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.WebApi/HealthCheckHandlerExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Web.Http; 4 | 5 | namespace RockLib.HealthChecks.WebApi; 6 | 7 | /// 8 | /// Extensions for adding a RockLib.HealthChecks route to a route collection. 9 | /// 10 | public static class HealthCheckHandlerExtensions 11 | { 12 | private static int _routeIndex = -1; 13 | 14 | /// 15 | /// Adds a health check route to the route collection. 16 | /// 17 | /// The route collection. 18 | /// 19 | /// The name of the to use. If or not provided, 20 | /// the default value of the method is used. 21 | /// 22 | /// The route of the health endpoint. 23 | /// Whether to indent the JSON output. 24 | public static void MapHealthRoute(this HttpRouteCollection routes, 25 | string? healthCheckRunnerName = null, string route = "/health", bool indent = false) 26 | => routes.MapHealthRoute(HealthCheck.GetRunner(healthCheckRunnerName)!, route, indent); 27 | 28 | 29 | /// 30 | /// Adds a health check route to the route collection. 31 | /// 32 | /// The route collection. 33 | /// 34 | /// The to use. If , 35 | /// the value of the method is used. 36 | /// 37 | /// The route of the health endpoint. 38 | /// Whether to indent the JSON output. 39 | public static void MapHealthRoute(this HttpRouteCollection routes, 40 | IHealthCheckRunner healthCheckRunner, string route = "/health", bool indent = false) 41 | { 42 | #if NET6_0_OR_GREATER 43 | ArgumentNullException.ThrowIfNull(routes); 44 | #else 45 | if (routes is null) { throw new ArgumentNullException(nameof(routes)); } 46 | #endif 47 | 48 | if (string.IsNullOrWhiteSpace(route)) 49 | { 50 | throw new ArgumentException("The route parameter has to contain a value.", nameof(route)); 51 | } 52 | 53 | healthCheckRunner ??= HealthCheck.GetRunner()!; 54 | route = route.Trim('/'); 55 | 56 | var routeIndex = Interlocked.Increment(ref _routeIndex); 57 | var routeName = routeIndex < 1 ? "HealthApi" : $"HealthApi-{routeIndex}"; 58 | 59 | #pragma warning disable CA2000 // Dispose objects before losing scope 60 | routes.MapHttpRoute(routeName, route, null, null, new HealthCheckHandler(healthCheckRunner, indent)); 61 | #pragma warning restore CA2000 // Dispose objects before losing scope 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.WebApi/RockLib.HealthChecks.WebApi.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Embedded 4 | A simple set of .NET Core Middleware extensions for adding Health Checks to your web application. 5 | True 6 | True 7 | RockLib.HealthChecks.WebApi 8 | LICENSE.md 9 | https://github.com/RockLib/RockLib.HealthChecks 10 | A changelog is available at https://github.com/RockLib/RockLib.HealthChecks/blob/main/RockLib.HealthChecks.WebApi/CHANGELOG.md. 11 | false 12 | rocklib health checks webapi 13 | 4.0.0 14 | icon.png 15 | True 16 | 4.0.0 17 | 18 | 19 | bin\$(Configuration)\$(TargetFramework)\$(PackageId).xml 20 | 21 | 22 | true 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /RockLib.HealthChecks.WebApi/RockLib.HealthChecks.WebApi.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.33110.190 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RockLib.HealthChecks.WebApi", "RockLib.HealthChecks.WebApi.csproj", "{2374AEAA-E75B-4C25-9CC0-54E214D1F772}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RockLib.HealthChecks.WebApi.Tests", "..\Tests\RockLib.HealthChecks.WebApi.Tests\RockLib.HealthChecks.WebApi.Tests.csproj", "{C795F3E4-A4AF-46EE-8FB4-17C677F865B6}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {2374AEAA-E75B-4C25-9CC0-54E214D1F772}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {2374AEAA-E75B-4C25-9CC0-54E214D1F772}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {2374AEAA-E75B-4C25-9CC0-54E214D1F772}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {2374AEAA-E75B-4C25-9CC0-54E214D1F772}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {C795F3E4-A4AF-46EE-8FB4-17C677F865B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {C795F3E4-A4AF-46EE-8FB4-17C677F865B6}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {C795F3E4-A4AF-46EE-8FB4-17C677F865B6}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {C795F3E4-A4AF-46EE-8FB4-17C677F865B6}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {9BD2137B-45A2-4572-9151-93471F4F7CC9} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /RockLib.HealthChecks/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | 6 | [*.cs] 7 | # Styling 8 | indent_style = space 9 | indent_size = 4 10 | csharp_indent_case_contents = true 11 | csharp_indent_switch_labels = true 12 | csharp_new_line_before_catch = true 13 | csharp_new_line_before_else = true 14 | csharp_new_line_before_finally = true 15 | csharp_new_line_before_members_in_anonymous_types = false 16 | csharp_new_line_before_members_in_object_initializers = false 17 | csharp_new_line_before_open_brace = methods, control_blocks, types, properties, lambdas, accessors, object_collection_array_initializers 18 | csharp_new_line_between_query_expression_clauses = true 19 | csharp_prefer_braces = false:suggestion 20 | csharp_prefer_simple_default_expression = true:suggestion 21 | csharp_preferred_modifier_order = public,private,internal,protected,static,readonly,async,override,sealed:suggestion 22 | csharp_preserve_single_line_blocks = true 23 | csharp_preserve_single_line_statements = true 24 | csharp_space_after_cast = false 25 | csharp_space_after_colon_in_inheritance_clause = true 26 | csharp_space_after_keywords_in_control_flow_statements = true 27 | csharp_space_before_colon_in_inheritance_clause = true 28 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 29 | csharp_space_between_method_call_name_and_opening_parenthesis = false 30 | csharp_space_between_method_call_parameter_list_parentheses = false 31 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 32 | csharp_space_between_method_declaration_parameter_list_parentheses = false 33 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 34 | csharp_style_expression_bodied_accessors = true:suggestion 35 | csharp_style_expression_bodied_constructors = false:suggestion 36 | csharp_style_expression_bodied_methods = false:suggestion 37 | csharp_style_expression_bodied_properties = true:suggestion 38 | csharp_style_inlined_variable_declaration = true:suggestion 39 | csharp_style_var_elsewhere = true:suggestion 40 | csharp_style_var_for_built_in_types = true:suggestion 41 | csharp_style_var_when_type_is_apparent = true:suggestion 42 | dotnet_sort_system_directives_first = false 43 | dotnet_style_explicit_tuple_names = true:suggestion 44 | dotnet_style_object_initializer = true:suggestion 45 | csharp_style_pattern_local_over_anonymous_function = false:suggestion 46 | dotnet_style_predefined_type_for_member_access = true:suggestion 47 | dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion 48 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 49 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 50 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion 51 | dotnet_style_qualification_for_field = false:suggestion 52 | dotnet_style_qualification_for_method = false:suggestion 53 | dotnet_style_qualification_for_property = false:suggestion 54 | 55 | 56 | # Analyzer Configuration 57 | # These are rules we want to either ignore or have set as suggestion or info 58 | 59 | # CA1014: Mark assemblies with CLSCompliant 60 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1014 61 | dotnet_diagnostic.CA1014.severity = none 62 | 63 | # CA1725: Parameter names should match base declaration 64 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1725 65 | dotnet_diagnostic.CA1725.severity = suggestion 66 | 67 | # CA2227: Collection properties should be read only 68 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2227 69 | dotnet_diagnostic.CA2227.severity = suggestion 70 | -------------------------------------------------------------------------------- /RockLib.HealthChecks/AssemblyAttributes.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("RockLib.HealthChecks.Tests")] -------------------------------------------------------------------------------- /RockLib.HealthChecks/DependencyInjection/HealthCheckRegistration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace RockLib.HealthChecks.DependencyInjection 4 | { 5 | /// 6 | /// Represents a method that creates an . 7 | /// 8 | /// 9 | /// The that resolves dependencies necessary for the creation of the 10 | /// . 11 | /// 12 | /// An . 13 | public delegate IHealthCheck HealthCheckRegistration(IServiceProvider serviceProvider); 14 | 15 | } -------------------------------------------------------------------------------- /RockLib.HealthChecks/DependencyInjection/IHealthCheckRunnerBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace RockLib.HealthChecks.DependencyInjection 2 | { 3 | /// 4 | /// A builder used to register health checks. 5 | /// 6 | public interface IHealthCheckRunnerBuilder 7 | { 8 | /// 9 | /// Adds a health check registration delegate to the builder. 10 | /// 11 | /// The health check registration delegate. 12 | IHealthCheckRunnerBuilder AddHealthCheck(HealthCheckRegistration registration); 13 | } 14 | } -------------------------------------------------------------------------------- /RockLib.HealthChecks/DependencyInjection/IHealthCheckRunnerOptions.cs: -------------------------------------------------------------------------------- 1 | namespace RockLib.HealthChecks.DependencyInjection 2 | { 3 | /// 4 | /// Defines the editable settings for creating an instance of . 5 | /// 6 | public interface IHealthCheckRunnerOptions 7 | { 8 | /// 9 | /// Gets or sets the human-friendly description of the service. 10 | /// 11 | string? Description { get; set; } 12 | 13 | /// 14 | /// Gets or sets the unique identifier of the service, in the application scope. 15 | /// 16 | string? ServiceId { get; set; } 17 | 18 | /// 19 | /// Gets or sets the public version of the service. 20 | /// 21 | string? Version { get; set; } 22 | 23 | /// 24 | /// Gets or sets the "release version" or "release ID" of the service. 25 | /// 26 | string? ReleaseId { get; set; } 27 | 28 | /// 29 | /// Gets or sets the that customizes each 30 | /// object returned by the health check runner. 31 | /// 32 | IHealthResponseCustomizer? ResponseCustomizer { get; set; } 33 | 34 | /// 35 | /// Gets or sets the HTTP content type of responses created by the health check runner. Must not 36 | /// have a null or empty value. 37 | /// 38 | string ContentType { get; set; } 39 | 40 | /// 41 | /// Gets or sets the HTTP status code of responses created by the health check runner that have a 42 | /// status of . Must have a value in the 200-399 range. 43 | /// 44 | int PassStatusCode { get; set; } 45 | 46 | /// 47 | /// Gets or sets the HTTP status code of responses created by the health check runner that have a 48 | /// status of . Must have a value in the 200-399 range. 49 | /// 50 | int WarnStatusCode { get; set; } 51 | 52 | /// 53 | /// Gets or sets the HTTP status code of responses created by the health check runner that have a 54 | /// status of . Must have a value in the 400-599 range. 55 | /// 56 | int FailStatusCode { get; set; } 57 | 58 | /// 59 | /// Gets or sets the for the that is 60 | /// returned because an has thrown an exception. 61 | /// 62 | HealthStatus? UncaughtExceptionStatus { get; set; } 63 | } 64 | } -------------------------------------------------------------------------------- /RockLib.HealthChecks/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | all 4 | Rocket Mortgage 5 | Copyright 2025 (c) Rocket Mortgage. All rights reserved. 6 | latest 7 | enable 8 | net8.0;net48 9 | NU1603,NU1701 10 | true 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | 17 | 18 | -------------------------------------------------------------------------------- /RockLib.HealthChecks/HealthStatus.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Converters; 3 | using System.Runtime.Serialization; 4 | 5 | namespace RockLib.HealthChecks 6 | { 7 | /// 8 | /// Defines the values for the health status of a service or component. 9 | /// 10 | [JsonConverter(typeof(StringEnumConverter))] 11 | public enum HealthStatus 12 | { 13 | /// 14 | /// The service or component is healthy. 15 | /// 16 | [EnumMember(Value = "pass")] 17 | Pass = 0, 18 | 19 | /// 20 | /// The service or component is healthy, with concerns. 21 | /// 22 | [EnumMember(Value = "warn")] 23 | Warn = 1, 24 | 25 | /// 26 | /// The service or component is unhealthy. 27 | /// 28 | [EnumMember(Value = "fail")] 29 | Fail = 2 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /RockLib.HealthChecks/IHealthCheck.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace RockLib.HealthChecks 6 | { 7 | /// 8 | /// Defines an object that checks the health of a logical downstream dependency or sub-component of 9 | /// a service. 10 | /// 11 | public interface IHealthCheck 12 | { 13 | /// 14 | /// Gets the name of the logical downstream dependency or sub-component of a service. Must not 15 | /// contain a colon. 16 | /// 17 | string? ComponentName { get; } 18 | 19 | /// 20 | /// Gets the name of the measurement that the status is reported for. Must not contain a colon. 21 | /// 22 | string? MeasurementName { get; } 23 | 24 | /// 25 | /// Gets the type of the component. 26 | /// 27 | string? ComponentType { get; } 28 | 29 | /// 30 | /// Gets a unique identifier of an instance of a specific sub-component/dependency of a service. 31 | /// 32 | string? ComponentId { get; } 33 | 34 | /// 35 | /// Check the health of the sub-component/dependency asynchronously. 36 | /// 37 | /// 38 | /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. 39 | /// 40 | /// 41 | /// A task list of results with details on the component's health representing the asynchronous 42 | /// operation. 43 | /// 44 | Task> CheckAsync(CancellationToken cancellationToken = default); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /RockLib.HealthChecks/IHealthCheckRunner.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using RockLib.Configuration.ObjectFactory; 4 | 5 | namespace RockLib.HealthChecks 6 | { 7 | /// 8 | /// Defines an object that checks the health of a service. 9 | /// 10 | [DefaultType(typeof(HealthCheckRunner))] 11 | public interface IHealthCheckRunner 12 | { 13 | /// 14 | /// Gets the optional name of the runner. 15 | /// 16 | string? Name { get; } 17 | 18 | /// 19 | /// Gets the human-friendly description of the service. 20 | /// 21 | string? Description { get; } 22 | 23 | /// 24 | /// Gets the unique identifier of the service, in the application scope. 25 | /// 26 | string? ServiceId { get; } 27 | 28 | /// 29 | /// Gets the public version of the service. 30 | /// 31 | string? Version { get; } 32 | 33 | /// 34 | /// Gets the "release version" or "release ID" of the service. 35 | /// 36 | string? ReleaseId { get; } 37 | 38 | /// 39 | /// Gets the HTTP content type of responses created by this health check runner. Must not 40 | /// have a null or empty value. 41 | /// 42 | string ContentType { get; } 43 | 44 | /// 45 | /// Gets the HTTP status code of responses created by this health check runner that have a 46 | /// status of . Must have a value in the 200-399 range. 47 | /// 48 | int PassStatusCode { get; } 49 | 50 | /// 51 | /// Gets the HTTP status code of responses created by this health check runner that have a 52 | /// status of . Must have a value in the 200-399 range. 53 | /// 54 | int WarnStatusCode { get; } 55 | 56 | /// 57 | /// Gets the HTTP status code of responses created by this health check runner that have a 58 | /// status of . Must have a value in the 400-599 range. 59 | /// 60 | int FailStatusCode { get; } 61 | 62 | /// 63 | /// Runs the health checks asynchronously. 64 | /// 65 | /// 66 | /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. 67 | /// 68 | /// 69 | /// A task healh response representing the asynchronous operation. 70 | /// 71 | Task RunAsync(CancellationToken cancellationToken = default); 72 | } 73 | } -------------------------------------------------------------------------------- /RockLib.HealthChecks/IHealthResponseCustomizer.cs: -------------------------------------------------------------------------------- 1 | namespace RockLib.HealthChecks 2 | { 3 | /// 4 | /// Defines an object that customizes existing objects. 5 | /// 6 | public interface IHealthResponseCustomizer 7 | { 8 | /// 9 | /// Customize the values of the given object. 10 | /// 11 | /// The object to be customized. 12 | /// 13 | /// Consider modifying the values of the , , , , and properties when implementing 16 | /// this method. 17 | /// 18 | void CustomizeResponse(HealthResponse response); 19 | } 20 | } -------------------------------------------------------------------------------- /RockLib.HealthChecks/NullableAttributes.cs: -------------------------------------------------------------------------------- 1 | #if NET48 2 | // This code is copied from https://source.dot.net/#System.Private.CoreLib/NullableAttributes.cs 3 | // and is only used for .NET 4.8 4 | using System; 5 | 6 | namespace System.Diagnostics.CodeAnalysis 7 | { 8 | /// 9 | /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. 10 | /// 11 | [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] 12 | public sealed class MaybeNullWhenAttribute : Attribute 13 | { 14 | /// Initializes the attribute with the specified return value condition. 15 | /// 16 | /// The return value condition. If the method returns this value, the associated parameter may be null. 17 | /// 18 | public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; 19 | 20 | /// Gets the return value condition. 21 | public bool ReturnValue { get; } 22 | } 23 | } 24 | #endif -------------------------------------------------------------------------------- /RockLib.HealthChecks/RockLib.HealthChecks.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Embedded 4 | An implementation of the draft health check RFC located at https://inadarei.github.io/rfc-healthcheck/. 5 | True 6 | True 7 | RockLib.HealthChecks 8 | LICENSE.md 9 | https://github.com/RockLib/RockLib.HealthChecks 10 | false 11 | A changelog is available at https://github.com/RockLib/RockLib.HealthChecks/blob/main/RockLib.HealthChecks/CHANGELOG.md. 12 | rocklib health checks 13 | 4.0.0 14 | icon.png 15 | True 16 | 4.0.0 17 | 18 | 19 | bin\$(Configuration)\$(TargetFramework)\$(PackageId).xml 20 | 21 | 22 | true 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /RockLib.HealthChecks/RockLib.HealthChecks.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29001.49 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RockLib.HealthChecks", "RockLib.HealthChecks.csproj", "{9A19103F-16F7-4668-BE54-9A1E7A4F7556}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RockLib.HealthChecks.Tests", "..\Tests\RockLib.HealthChecks.Tests\RockLib.HealthChecks.Tests.csproj", "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {9A19103F-16F7-4668-BE54-9A1E7A4F7556}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {9A19103F-16F7-4668-BE54-9A1E7A4F7556}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {9A19103F-16F7-4668-BE54-9A1E7A4F7556}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {9A19103F-16F7-4668-BE54-9A1E7A4F7556}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {9BD2137B-45A2-4572-9151-93471F4F7CC9} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /RockLib.HealthChecks/System/ProcessUptimeHealthCheck.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Diagnostics; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace RockLib.HealthChecks.System 8 | { 9 | /// 10 | /// A health check that records the uptime of the current process. Always passes. 11 | /// 12 | public class ProcessUptimeHealthCheck : SingleResultHealthCheck 13 | { 14 | private readonly DateTime _currentProcessStartTime; 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// 20 | /// The name of the logical downstream dependency or sub-component of a service. Defaults to 'process'. 21 | /// Must not contain a colon. 22 | /// 23 | /// 24 | /// The name of the measurement that the status is reported for. Defaults to 'uptime'. Must not 25 | /// contain a colon. 26 | /// 27 | /// The type of the component. Defaults to 'system'. 28 | /// 29 | /// A unique identifier of an instance of a specific sub-component/dependency of a service. 30 | /// 31 | public ProcessUptimeHealthCheck(string componentName = "process", string measurementName = "uptime", 32 | string componentType = "system", string? componentId = null) 33 | : base(componentName, measurementName, componentType, componentId) 34 | { 35 | try 36 | { 37 | _currentProcessStartTime = Process.GetCurrentProcess().StartTime; 38 | } 39 | catch(Exception ex) when (ex is NotSupportedException || ex is InvalidOperationException || ex is Win32Exception) 40 | { 41 | _currentProcessStartTime = DateTime.Now; 42 | } 43 | } 44 | 45 | /// 46 | protected override Task CheckAsync(HealthCheckResult result, CancellationToken cancellationToken) 47 | { 48 | #if NET6_0_OR_GREATER 49 | ArgumentNullException.ThrowIfNull(result); 50 | #else 51 | if (result is null) { throw new ArgumentNullException(nameof(result)); } 52 | #endif 53 | 54 | SetResult(result); 55 | return Task.CompletedTask; 56 | } 57 | 58 | private void SetResult(HealthCheckResult result) 59 | { 60 | result.Status = HealthStatus.Pass; 61 | result.ObservedValue = (DateTime.Now - _currentProcessStartTime).TotalSeconds; 62 | result.ObservedUnit = "s"; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /RockLib.HealthChecks/System/SystemUptimeHealthCheck.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | 6 | namespace RockLib.HealthChecks.System 7 | { 8 | /// 9 | /// A health check that records the uptime of the system. Always passes. 10 | /// 11 | public class SystemUptimeHealthCheck : SingleResultHealthCheck 12 | { 13 | private static readonly double _stopwatchFrequency = Stopwatch.Frequency; 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// 19 | /// The name of the logical downstream dependency or sub-component of a service. Defaults to 'system'. 20 | /// Must not contain a colon. 21 | /// 22 | /// 23 | /// The name of the measurement that the status is reported for. Defaults to 'uptime'. Must not 24 | /// contain a colon. 25 | /// 26 | /// The type of the component. Defaults to 'system'. 27 | /// 28 | /// A unique identifier of an instance of a specific sub-component/dependency of a service. 29 | /// 30 | public SystemUptimeHealthCheck(string componentName = "system", string measurementName = "uptime", 31 | string componentType = "system", string? componentId = null) 32 | : base(componentName, measurementName, componentType, componentId) 33 | { 34 | } 35 | 36 | /// 37 | protected override Task CheckAsync(HealthCheckResult result, CancellationToken cancellationToken) 38 | { 39 | #if NET6_0_OR_GREATER 40 | ArgumentNullException.ThrowIfNull(result); 41 | #else 42 | if (result is null) { throw new ArgumentNullException(nameof(result)); } 43 | #endif 44 | 45 | SetResult(result); 46 | return Task.CompletedTask; 47 | } 48 | 49 | private static void SetResult(HealthCheckResult result) 50 | { 51 | result.Status = HealthStatus.Pass; 52 | result.ObservedValue = Stopwatch.GetTimestamp() / _stopwatchFrequency; 53 | result.ObservedUnit = "s"; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.AspNetCore.ResponseWriter.Tests/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | 6 | all 7 | Rocket Mortgage 8 | Copyright 2025 (c) Rocket Mortgage. All rights reserved. 9 | latest 10 | enable 11 | net8.0;net48 12 | NU1603,NU1701,CA2007 13 | true 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.AspNetCore.ResponseWriter.Tests/RockLib.HealthChecks.AspNetCore.ResponseWriter.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.AspNetCore.Tests/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | 6 | [*.cs] 7 | # Styling 8 | indent_style = space 9 | indent_size = 4 10 | csharp_indent_case_contents = true 11 | csharp_indent_switch_labels = true 12 | csharp_new_line_before_catch = true 13 | csharp_new_line_before_else = true 14 | csharp_new_line_before_finally = true 15 | csharp_new_line_before_members_in_anonymous_types = false 16 | csharp_new_line_before_members_in_object_initializers = false 17 | csharp_new_line_before_open_brace = methods, control_blocks, types, properties, lambdas, accessors, object_collection_array_initializers 18 | csharp_new_line_between_query_expression_clauses = true 19 | csharp_prefer_braces = false:suggestion 20 | csharp_prefer_simple_default_expression = true:suggestion 21 | csharp_preferred_modifier_order = public,private,internal,protected,static,readonly,async,override,sealed:suggestion 22 | csharp_preserve_single_line_blocks = true 23 | csharp_preserve_single_line_statements = true 24 | csharp_space_after_cast = false 25 | csharp_space_after_colon_in_inheritance_clause = true 26 | csharp_space_after_keywords_in_control_flow_statements = true 27 | csharp_space_before_colon_in_inheritance_clause = true 28 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 29 | csharp_space_between_method_call_name_and_opening_parenthesis = false 30 | csharp_space_between_method_call_parameter_list_parentheses = false 31 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 32 | csharp_space_between_method_declaration_parameter_list_parentheses = false 33 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 34 | csharp_style_expression_bodied_accessors = true:suggestion 35 | csharp_style_expression_bodied_constructors = false:suggestion 36 | csharp_style_expression_bodied_methods = false:suggestion 37 | csharp_style_expression_bodied_properties = true:suggestion 38 | csharp_style_inlined_variable_declaration = true:suggestion 39 | csharp_style_var_elsewhere = true:suggestion 40 | csharp_style_var_for_built_in_types = true:suggestion 41 | csharp_style_var_when_type_is_apparent = true:suggestion 42 | dotnet_sort_system_directives_first = false 43 | dotnet_style_explicit_tuple_names = true:suggestion 44 | dotnet_style_object_initializer = true:suggestion 45 | csharp_style_pattern_local_over_anonymous_function = false:suggestion 46 | dotnet_style_predefined_type_for_member_access = true:suggestion 47 | dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion 48 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 49 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 50 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion 51 | dotnet_style_qualification_for_field = false:suggestion 52 | dotnet_style_qualification_for_method = false:suggestion 53 | dotnet_style_qualification_for_property = false:suggestion 54 | 55 | 56 | # Analyzer Configuration 57 | # These are rules we want to either ignore or have set as suggestion or info 58 | 59 | # CA1014: Mark assemblies with CLSCompliant 60 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1014 61 | dotnet_diagnostic.CA1014.severity = none 62 | 63 | # CA1725: Parameter names should match base declaration 64 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1725 65 | dotnet_diagnostic.CA1725.severity = suggestion 66 | 67 | # CA2227: Collection properties should be read only 68 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2227 69 | dotnet_diagnostic.CA2227.severity = suggestion 70 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.AspNetCore.Tests/AssemblySettings.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | [assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly)] -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.AspNetCore.Tests/Collector/HealthMetricCollectorExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | using RockLib.HealthChecks.AspNetCore.Collector; 2 | using Xunit; 3 | 4 | namespace RockLib.HealthChecks.AspNetCore.Tests.Collector; 5 | 6 | public class HealthMetricCollectorExtensionsTests 7 | { 8 | [Fact] 9 | public void GetCountReturnsArraySizeWhenAllTrue() 10 | { 11 | var collector = new HealthMetricCollector(3); 12 | Assert.Equal(3, collector.GetCount(_ => true)); 13 | } 14 | [Fact] 15 | public void GetCountReturnsCorrectCount() 16 | { 17 | var collector = new HealthMetricCollector(3); 18 | collector.Collect(1); 19 | collector.Collect(2); 20 | collector.Collect(3); 21 | Assert.Equal(2, collector.GetCount(x => x > 1)); 22 | } 23 | } -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.AspNetCore.Tests/Collector/HealthMetricCollectorFactoryTests.cs: -------------------------------------------------------------------------------- 1 | using RockLib.HealthChecks.AspNetCore.Collector; 2 | using Xunit; 3 | 4 | namespace RockLib.HealthChecks.AspNetCore.Tests.Collector; 5 | 6 | public class HealthMetricCollectorFactoryTests 7 | { 8 | [Fact] 9 | public void ConfigureCollectorCreatesNewCollectorsDynamically() 10 | { 11 | var factory = new HealthMetricCollectorFactory(); 12 | factory.ConfigureCollector("foo", 10); 13 | factory.ConfigureCollector("bar", 20); 14 | factory.ConfigureCollector("foo", 30); // overwrite 15 | factory.ConfigureCollector("baz"); 16 | 17 | var collectors = factory.GetCollectors(); 18 | Assert.Equal(3, collectors.Count); 19 | Assert.NotNull(collectors["foo"]); 20 | Assert.NotNull(collectors["bar"]); 21 | Assert.NotNull(collectors["baz"]); 22 | } 23 | 24 | [Fact] 25 | public void LeaseCollectorCreatesWithDefaultSize() 26 | { 27 | var factory = new HealthMetricCollectorFactory(); 28 | var collector = factory.LeaseCollector(null!); 29 | Assert.NotNull(collector); 30 | Assert.Equal(100, collector.GetMetrics(_ => true).Length); 31 | } 32 | 33 | [Fact] 34 | public void LeaseCollectorSupportsSizeOverride() 35 | { 36 | var factory = new HealthMetricCollectorFactory(); 37 | factory.SetDefaultSampleSize(50); 38 | var collector = factory.LeaseCollector(null!); 39 | Assert.NotNull(collector); 40 | Assert.Equal(50, collector.GetMetrics(_ => true).Length); 41 | } 42 | 43 | [Fact] 44 | public void LeaseCollectorSupportsSizeFallback() 45 | { 46 | var factory = new HealthMetricCollectorFactory(); 47 | factory.SetDefaultSampleSize(null); 48 | var collector = factory.LeaseCollector(null!); 49 | Assert.NotNull(collector); 50 | Assert.Equal(100, collector.GetMetrics(_ => true).Length); 51 | } 52 | 53 | [Fact] 54 | public void LeaseCollectorReturnsTheSameInstanceByName() 55 | { 56 | var factory = new HealthMetricCollectorFactory(); 57 | var collector1 = factory.LeaseCollector("foo"); 58 | var collector2 = factory.LeaseCollector("foo"); 59 | Assert.Same(collector1, collector2); 60 | } 61 | } -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.AspNetCore.Tests/Collector/HealthMetricCollectorTests.cs: -------------------------------------------------------------------------------- 1 | using RockLib.HealthChecks.AspNetCore.Collector; 2 | using System.Diagnostics; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using Xunit; 6 | 7 | namespace RockLib.HealthChecks.AspNetCore.Tests.Collector; 8 | 9 | public class HealthMetricCollectorTests 10 | { 11 | [Fact] 12 | public void HealthMetricCollectorCollects() 13 | { 14 | var collector = new HealthMetricCollector(3); 15 | collector.Collect(1); 16 | collector.Collect(2); 17 | collector.Collect(3); 18 | var arr = new[] { 3, 1, 2 }; 19 | Assert.Equal(arr, collector.GetMetrics()); 20 | 21 | // begin overwriting 22 | collector.Collect(4); 23 | collector.Collect(5); 24 | arr = [3, 4, 5]; 25 | Assert.Equal(arr, collector.GetMetrics()); 26 | } 27 | 28 | [Fact] 29 | public void HealthMetricCollectorGetMetricsReturnsOnlyMatches() 30 | { 31 | var collector = new HealthMetricCollector(3); 32 | collector.Collect(1); 33 | collector.Collect(2); 34 | collector.Collect(3); 35 | var arr = new[] { 3 }; 36 | Assert.Equal(arr, collector.GetMetrics(x => x > 2)); 37 | } 38 | 39 | [Fact] 40 | public void HealthMetricCollectorGetMetricsReturnsEmptyIfNoMatch() 41 | { 42 | var collector = new HealthMetricCollector(3); 43 | Assert.Equal([], collector.GetMetrics(x => x == 4)); 44 | } 45 | 46 | /// 47 | /// This test is the antithesis of the next test. It proves that the collector requires thread safety. 48 | /// If this test ever starts failing we may no longer need to use Interlocked.Increment in the Collect method. 49 | /// 50 | [Fact] 51 | public void ProofCollectorRequiresThreadSafety() 52 | { 53 | var collector = new HealthMetricCollector(3); 54 | 55 | var stopwatch = new Stopwatch(); 56 | stopwatch.Start(); 57 | var cnt = 0; 58 | var res = Parallel.For(0, 10, _ => 59 | { 60 | while (stopwatch.ElapsedMilliseconds < 1000) 61 | { 62 | collector.Collect(1); 63 | ++cnt; // unsafe; being accessed by multiple threads at once 64 | } 65 | }); 66 | stopwatch.Stop(); 67 | Assert.True(res.IsCompleted); 68 | Assert.True(cnt < collector.GetImpressionCount()); 69 | } 70 | 71 | [Fact] 72 | public void HealthMetricCollectorIsThreadSafe() 73 | { 74 | var collector = new HealthMetricCollector(3); 75 | 76 | var stopwatch = new Stopwatch(); 77 | stopwatch.Start(); 78 | var cnt = 0; 79 | var res = Parallel.For(0, 100, _ => 80 | { 81 | while (stopwatch.ElapsedMilliseconds < 2500) 82 | { 83 | collector.Collect(1); 84 | Interlocked.Increment(ref cnt); // safe; leverages a locking mechanism 85 | } 86 | }); 87 | stopwatch.Stop(); 88 | Assert.True(res.IsCompleted); 89 | Assert.Equal(collector.GetImpressionCount(), cnt); 90 | } 91 | } -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.AspNetCore.Tests/Collector/HttpResponseCollectorTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using Moq.Protected; 3 | using RockLib.HealthChecks.AspNetCore.Collector; 4 | using System; 5 | using System.Net; 6 | using System.Net.Http; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | using Xunit; 10 | 11 | namespace RockLib.HealthChecks.AspNetCore.Tests.Collector; 12 | 13 | public class HttpResponseCollectorTests 14 | { 15 | [Fact] 16 | public async Task SendAsyncThrowsIfRequestIsNull() 17 | { 18 | using var handler = new HttpResponseCollector(new HealthMetricCollectorFactory()); 19 | using var client = new HttpClient(handler); 20 | 21 | await Assert.ThrowsAsync(() => client.SendAsync(null!)); 22 | } 23 | 24 | [Fact] 25 | public async Task SendAsyncCollectsOutcome() 26 | { 27 | var factory = new HealthMetricCollectorFactory(); 28 | using var handler = new HttpResponseCollector(factory); 29 | using var request = new HttpRequestMessage(HttpMethod.Get, "http://example.com"); 30 | 31 | var upstreamHandler = new Mock(); 32 | handler.InnerHandler = upstreamHandler.Object; 33 | 34 | using var mockedResponse = new HttpResponseMessage(HttpStatusCode.NoContent); 35 | 36 | upstreamHandler.Protected() 37 | .Setup>("SendAsync", request, ItExpr.IsAny()) 38 | .ReturnsAsync(mockedResponse); 39 | 40 | //Act 41 | using var client = new HttpClient(handler); 42 | var actualResponse = await client.SendAsync(request); 43 | 44 | //check that internal call to SendAsync was only Once and with proper request object 45 | upstreamHandler.Protected() 46 | .Verify("SendAsync", Times.Once(), request, ItExpr.IsAny()); 47 | 48 | Assert.Equal(HttpStatusCode.NoContent, actualResponse.StatusCode); 49 | var collector = factory.LeaseCollector("example.com"); 50 | Assert.Single(collector.GetMetrics(x => x == (int)HttpStatusCode.NoContent)); 51 | } 52 | } -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.AspNetCore.Tests/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | 6 | all 7 | Rocket Mortgage 8 | Copyright 2025 (c) Rocket Mortgage. All rights reserved. 9 | latest 10 | enable 11 | net8.0;net48 12 | NU1603,NU1701,CA2007 13 | true 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.AspNetCore.Tests/HealthCheckMiddlewareExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Hosting; 5 | using Moq; 6 | using RockLib.HealthChecks.AspNetCore.Collector; 7 | using System; 8 | using System.Collections.Generic; 9 | using Xunit; 10 | 11 | namespace RockLib.HealthChecks.AspNetCore.Tests; 12 | 13 | public static class HealthCheckMiddlewareExtensionsTests 14 | { 15 | [Fact] 16 | public static void UseRockLibHealthChecksWithNullBuilder() => 17 | Assert.Throws(() => (null as IApplicationBuilder)!.UseRockLibHealthChecks()); 18 | 19 | [Fact] 20 | public static void UseRockLibHealthChecksWithNullName() => 21 | Assert.Throws(() => Mock.Of().UseRockLibHealthChecks(healthCheckRunnerName: null!)); 22 | 23 | [Fact] 24 | public static void UseRockLibHealthChecksWithNullRoute() => 25 | Assert.Throws(() => Mock.Of().UseRockLibHealthChecks(route: null!)); 26 | 27 | [Fact] 28 | public static void ConfigureRockLibHealthChecksRequiresBuilder() => 29 | Assert.Throws(() => (null as IHostApplicationBuilder)!.ConfigureRockLibHealthChecks()); 30 | 31 | [Fact] 32 | public static void ConfigureRockLibHealthChecksWithNoHealthChecks() 33 | { 34 | // no config here - not even a RockLib.HealthChecks section 35 | IConfiguration cfg = new ConfigurationBuilder().Build(); 36 | 37 | var builder = new Mock(); 38 | builder.Setup(b => b.Configuration.GetSection("RockLib.HealthChecks")) 39 | .Returns(cfg.GetSection("RockLib.HealthChecks")); // returns an empty section 40 | 41 | builder.Object.ConfigureRockLibHealthChecks(); 42 | 43 | // verify the config was attempted (implying the loader did not crash) 44 | builder.Verify(b => b.Configuration.GetSection("RockLib.HealthChecks"), Times.Once); 45 | } 46 | 47 | [Fact] 48 | public static void ConfigureRockLibHealthChecksWithMultipleHealthChecks() 49 | { 50 | var inMemorySettings = new Dictionary 51 | { 52 | { "RockLib.HealthChecks:healthChecks", "[]" }, 53 | { "RockLib.HealthChecks:healthChecks:0:type", "thisIsNotARealType" }, // should be overlooked gracefully 54 | { "RockLib.HealthChecks:healthChecks:1:type", "RockLib.HealthChecks.AspNetCore.Checks.HttpStatsHealthCheck, RockLib.HealthChecks.AspNetCore" } 55 | }; 56 | IConfiguration config = new ConfigurationBuilder().AddInMemoryCollection(inMemorySettings).Build(); 57 | 58 | var builder = new Mock(); 59 | builder.Setup(b => b.Configuration.GetSection("RockLib.HealthChecks")) 60 | .Returns(config.GetSection("RockLib.HealthChecks")); 61 | 62 | // configure the builder with services 63 | var svcCollection = new ServiceCollection(); 64 | builder.Setup(b => b.Services).Returns(svcCollection); 65 | 66 | // act 67 | builder.Object.ConfigureRockLibHealthChecks(); 68 | 69 | // assert the configuration was read and the services were added 70 | builder.Verify(b => b.Configuration.GetSection("RockLib.HealthChecks"), Times.Once); 71 | Assert.Contains(svcCollection, sd => sd.ServiceType == typeof(IHealthMetricCollectorFactory)); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.AspNetCore.Tests/HealthCheckMiddlewareTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Moq; 3 | using System; 4 | using System.IO; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using Xunit; 8 | 9 | namespace RockLib.HealthChecks.AspNetCore.Tests; 10 | 11 | public static class HealthCheckMiddlewareTests 12 | { 13 | [Fact] 14 | public static void CreateWithNullRunner() => 15 | Assert.Throws(() => new HealthCheckMiddleware(new RequestDelegate(context => Task.CompletedTask), null!)); 16 | 17 | [Fact] 18 | public static async Task InvokeAsync() 19 | { 20 | var response = new HealthResponse() { StatusCode = 200, ContentType = "Custom" }; 21 | var responseStream = new MemoryStream(); 22 | 23 | var runner = new Mock(MockBehavior.Strict); 24 | runner.Setup(_ => _.RunAsync(It.IsAny())).Returns(Task.FromResult(response)); 25 | 26 | var statusCode = 0; 27 | var contentType = ""; 28 | 29 | var contextResponse = new Mock(MockBehavior.Strict); 30 | contextResponse.SetupSet(_ => _.StatusCode = It.IsAny()).Callback(_ => statusCode = _); 31 | contextResponse.SetupSet(_ => _.ContentType = It.IsAny()).Callback(_ => contentType = _); 32 | contextResponse.SetupGet(_ => _.Body).Returns(responseStream); 33 | 34 | var context = new Mock(MockBehavior.Strict); 35 | context.SetupGet(_ => _.Response).Returns(contextResponse.Object); 36 | context.SetupGet(_ => _.RequestAborted).Returns(new CancellationToken()); 37 | 38 | var middleware = new HealthCheckMiddleware(new RequestDelegate(context => Task.CompletedTask), runner.Object); 39 | await middleware.InvokeAsync(context.Object); 40 | 41 | Assert.Equal(200, statusCode); 42 | Assert.Equal("Custom", contentType); 43 | Assert.True(responseStream.Length > 0); 44 | 45 | context.VerifyAll(); 46 | contextResponse.VerifyAll(); 47 | runner.VerifyAll(); 48 | } 49 | 50 | [Fact] 51 | public static async Task InvokeAsyncWithNullContext() => 52 | await Assert.ThrowsAsync( 53 | async () => await new HealthCheckMiddleware(new RequestDelegate(context => Task.CompletedTask), Mock.Of()) 54 | .InvokeAsync(null!)); 55 | } 56 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.AspNetCore.Tests/NewtonsoftJsonResponseFormatterTests.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using Xunit; 4 | 5 | namespace RockLib.HealthChecks.AspNetCore.Tests; 6 | 7 | public static class NewtonsoftJsonResponseFormatterTests 8 | { 9 | [Fact] 10 | public static void CreateWithNoResults() 11 | { 12 | var formatter = new NewtonsoftJsonResponseFormatter(); 13 | var result = formatter.Format(new HealthResponse()); 14 | 15 | Assert.Equal("{\"status\":\"pass\"}", result); 16 | } 17 | 18 | [Fact] 19 | public static void CreateWithResults() 20 | { 21 | var formatter = new NewtonsoftJsonResponseFormatter(); 22 | var result = formatter.Format( 23 | new HealthResponse(new[] 24 | { 25 | new HealthCheckResult { Status = HealthStatus.Pass }, 26 | new HealthCheckResult { Status = HealthStatus.Fail } 27 | })); 28 | 29 | Assert.Equal("{\"status\":\"fail\",\"checks\":{\"\":[{\"status\":\"pass\"},{\"status\":\"fail\"}]}}", result); 30 | } 31 | 32 | [Fact] 33 | public static void CreateWithFormatting() 34 | { 35 | var formatter = new NewtonsoftJsonResponseFormatter(Formatting.Indented); 36 | var result = formatter.Format(new HealthResponse()); 37 | 38 | Assert.Equal($"{{{Environment.NewLine} \"status\": \"pass\"{Environment.NewLine}}}", result); 39 | } 40 | 41 | [Fact] 42 | public static void CreateWithSettings() 43 | { 44 | #pragma warning disable CA2326 // Do not use TypeNameHandling values other than None 45 | var formatter = new NewtonsoftJsonResponseFormatter(settings: new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Objects }); 46 | #pragma warning restore CA2326 // Do not use TypeNameHandling values other than None 47 | var result = formatter.Format(new HealthResponse()); 48 | 49 | Assert.Equal("{\"$type\":\"RockLib.HealthChecks.HealthResponse, RockLib.HealthChecks\",\"status\":\"pass\"}", result); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.AspNetCore.Tests/RockLib.HealthChecks.AspNetCore.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | false 4 | 5 | 6 | 7 | 8 | 9 | 10 | all 11 | runtime; build; native; contentfiles; analyzers; buildtransitive 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.Client.Tests/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | 6 | [*.cs] 7 | # Styling 8 | indent_style = space 9 | indent_size = 4 10 | csharp_indent_case_contents = true 11 | csharp_indent_switch_labels = true 12 | csharp_new_line_before_catch = true 13 | csharp_new_line_before_else = true 14 | csharp_new_line_before_finally = true 15 | csharp_new_line_before_members_in_anonymous_types = false 16 | csharp_new_line_before_members_in_object_initializers = false 17 | csharp_new_line_before_open_brace = methods, control_blocks, types, properties, lambdas, accessors, object_collection_array_initializers 18 | csharp_new_line_between_query_expression_clauses = true 19 | csharp_prefer_braces = false:suggestion 20 | csharp_prefer_simple_default_expression = true:suggestion 21 | csharp_preferred_modifier_order = public,private,internal,protected,static,readonly,async,override,sealed:suggestion 22 | csharp_preserve_single_line_blocks = true 23 | csharp_preserve_single_line_statements = true 24 | csharp_space_after_cast = false 25 | csharp_space_after_colon_in_inheritance_clause = true 26 | csharp_space_after_keywords_in_control_flow_statements = true 27 | csharp_space_before_colon_in_inheritance_clause = true 28 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 29 | csharp_space_between_method_call_name_and_opening_parenthesis = false 30 | csharp_space_between_method_call_parameter_list_parentheses = false 31 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 32 | csharp_space_between_method_declaration_parameter_list_parentheses = false 33 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 34 | csharp_style_expression_bodied_accessors = true:suggestion 35 | csharp_style_expression_bodied_constructors = false:suggestion 36 | csharp_style_expression_bodied_methods = false:suggestion 37 | csharp_style_expression_bodied_properties = true:suggestion 38 | csharp_style_inlined_variable_declaration = true:suggestion 39 | csharp_style_var_elsewhere = true:suggestion 40 | csharp_style_var_for_built_in_types = true:suggestion 41 | csharp_style_var_when_type_is_apparent = true:suggestion 42 | dotnet_sort_system_directives_first = false 43 | dotnet_style_explicit_tuple_names = true:suggestion 44 | dotnet_style_object_initializer = true:suggestion 45 | csharp_style_pattern_local_over_anonymous_function = false:suggestion 46 | dotnet_style_predefined_type_for_member_access = true:suggestion 47 | dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion 48 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 49 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 50 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion 51 | dotnet_style_qualification_for_field = false:suggestion 52 | dotnet_style_qualification_for_method = false:suggestion 53 | dotnet_style_qualification_for_property = false:suggestion 54 | 55 | 56 | # Analyzer Configuration 57 | # These are rules we want to either ignore or have set as suggestion or info 58 | 59 | # CA1014: Mark assemblies with CLSCompliant 60 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1014 61 | dotnet_diagnostic.CA1014.severity = none 62 | 63 | # CA1725: Parameter names should match base declaration 64 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1725 65 | dotnet_diagnostic.CA1725.severity = suggestion 66 | 67 | # CA2227: Collection properties should be read only 68 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2227 69 | dotnet_diagnostic.CA2227.severity = suggestion 70 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.Client.Tests/AssemblySettings.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | [assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly)] -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.Client.Tests/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | 6 | all 7 | Rocket Mortgage 8 | Copyright 2025 (c) Rocket Mortgage. All rights reserved. 9 | latest 10 | enable 11 | net8.0;net48 12 | NU1603,NU1701 13 | true 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.Client.Tests/RockLib.HealthChecks.Client.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | false 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | all 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | 15 | 16 | all 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.HttpModule.Tests/AssemblySettings.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | [assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly)] -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.HttpModule.Tests/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | AllEnabledByDefault 4 | Rocket Mortgage 5 | Copyright 2022 (c) Rocket Mortgage. All rights reserved. 6 | true 7 | latest 8 | enable 9 | NU1603,NU1701 10 | true 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | 17 | 18 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.HttpModule.Tests/HealthCheckHttpModuleTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web; 3 | using Xunit; 4 | 5 | namespace RockLib.HealthChecks.HttpModule.Tests; 6 | 7 | public static class HealthCheckHttpModuleTests 8 | { 9 | [Fact] 10 | public static void SetRoute() 11 | { 12 | HealthCheckHttpModule.Route = "/diagnostics"; 13 | Assert.Equal("diagnostics", HealthCheckHttpModule.Route); 14 | } 15 | 16 | [Fact] 17 | public static void SetRouteWithNullValue() => 18 | Assert.Throws(() => HealthCheckHttpModule.Route = null!); 19 | 20 | [Fact] 21 | public static void SetRouteWithEmptyValue() => 22 | Assert.Throws(() => HealthCheckHttpModule.Route = string.Empty); 23 | 24 | [Fact] 25 | public static void Init() 26 | { 27 | var application = new HttpApplication(); 28 | var module = new HealthCheckHttpModule(); 29 | module.Init(application); 30 | } 31 | } -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.HttpModule.Tests/RockLib.HealthChecks.HttpModule.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | false 4 | net48 5 | 6 | 7 | 8 | 9 | 10 | 11 | all 12 | runtime; build; native; contentfiles; analyzers; buildtransitive 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.Tests/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | 6 | [*.cs] 7 | # Styling 8 | indent_style = space 9 | indent_size = 4 10 | csharp_indent_case_contents = true 11 | csharp_indent_switch_labels = true 12 | csharp_new_line_before_catch = true 13 | csharp_new_line_before_else = true 14 | csharp_new_line_before_finally = true 15 | csharp_new_line_before_members_in_anonymous_types = false 16 | csharp_new_line_before_members_in_object_initializers = false 17 | csharp_new_line_before_open_brace = methods, control_blocks, types, properties, lambdas, accessors, object_collection_array_initializers 18 | csharp_new_line_between_query_expression_clauses = true 19 | csharp_prefer_braces = false:suggestion 20 | csharp_prefer_simple_default_expression = true:suggestion 21 | csharp_preferred_modifier_order = public,private,internal,protected,static,readonly,async,override,sealed:suggestion 22 | csharp_preserve_single_line_blocks = true 23 | csharp_preserve_single_line_statements = true 24 | csharp_space_after_cast = false 25 | csharp_space_after_colon_in_inheritance_clause = true 26 | csharp_space_after_keywords_in_control_flow_statements = true 27 | csharp_space_before_colon_in_inheritance_clause = true 28 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 29 | csharp_space_between_method_call_name_and_opening_parenthesis = false 30 | csharp_space_between_method_call_parameter_list_parentheses = false 31 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 32 | csharp_space_between_method_declaration_parameter_list_parentheses = false 33 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 34 | csharp_style_expression_bodied_accessors = true:suggestion 35 | csharp_style_expression_bodied_constructors = false:suggestion 36 | csharp_style_expression_bodied_methods = false:suggestion 37 | csharp_style_expression_bodied_properties = true:suggestion 38 | csharp_style_inlined_variable_declaration = true:suggestion 39 | csharp_style_var_elsewhere = true:suggestion 40 | csharp_style_var_for_built_in_types = true:suggestion 41 | csharp_style_var_when_type_is_apparent = true:suggestion 42 | dotnet_sort_system_directives_first = false 43 | dotnet_style_explicit_tuple_names = true:suggestion 44 | dotnet_style_object_initializer = true:suggestion 45 | csharp_style_pattern_local_over_anonymous_function = false:suggestion 46 | dotnet_style_predefined_type_for_member_access = true:suggestion 47 | dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion 48 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 49 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 50 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion 51 | dotnet_style_qualification_for_field = false:suggestion 52 | dotnet_style_qualification_for_method = false:suggestion 53 | dotnet_style_qualification_for_property = false:suggestion 54 | 55 | 56 | # Analyzer Configuration 57 | # These are rules we want to either ignore or have set as suggestion or info 58 | 59 | # CA1014: Mark assemblies with CLSCompliant 60 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1014 61 | dotnet_diagnostic.CA1014.severity = none 62 | 63 | # CA1725: Parameter names should match base declaration 64 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1725 65 | dotnet_diagnostic.CA1725.severity = suggestion 66 | 67 | # CA2227: Collection properties should be read only 68 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2227 69 | dotnet_diagnostic.CA2227.severity = suggestion 70 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.Tests/AssemblySettings.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | [assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly)] -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.Tests/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | all 4 | Rocket Mortgage 5 | Copyright 2025 (c) Rocket Mortgage. All rights reserved. 6 | latest 7 | enable 8 | net8.0;net48 9 | NU1603,NU1701,CA1861 10 | true 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | 17 | 18 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.Tests/RockLib.HealthChecks.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | false 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | all 12 | runtime; build; native; contentfiles; analyzers; buildtransitive 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.Tests/SingleResultHealthCheckTests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using Xunit; 8 | 9 | namespace RockLib.HealthChecks.Tests 10 | { 11 | public class SingleResultHealthCheckTests 12 | { 13 | [Fact] 14 | public void ConstructorSetsProperties() 15 | { 16 | var healthCheck = new TestHealthCheck("FakeComponentName", "FakeMeasurementName", "FakeComponentType", "FakeComponentId"); 17 | 18 | healthCheck.ComponentName.Should().Be("FakeComponentName"); 19 | healthCheck.MeasurementName.Should().Be("FakeMeasurementName"); 20 | healthCheck.ComponentType.Should().Be("FakeComponentType"); 21 | healthCheck.ComponentId.Should().Be("FakeComponentId"); 22 | } 23 | 24 | [Fact] 25 | public async Task CheckAsyncReturnsOneResult() 26 | { 27 | var healthCheck = new TestHealthCheck(); 28 | 29 | var result = await healthCheck.CheckAsync().ConfigureAwait(true); 30 | 31 | result.Should().HaveCount(1); 32 | result[0]["fake"].Should().Be(true); 33 | } 34 | 35 | private sealed class TestHealthCheck : SingleResultHealthCheck 36 | { 37 | public TestHealthCheck(string? componentName = null, string? measurementName = null, string? componentType = null, string? componentId = null) 38 | : base(componentName, measurementName, componentType, componentId) { } 39 | 40 | protected override Task CheckAsync(HealthCheckResult result, CancellationToken cancellationToken) 41 | { 42 | result["fake"] = true; 43 | return Task.CompletedTask; 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.WebApi.Tests/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | 6 | [*.cs] 7 | # Styling 8 | indent_style = space 9 | indent_size = 4 10 | csharp_indent_case_contents = true 11 | csharp_indent_switch_labels = true 12 | csharp_new_line_before_catch = true 13 | csharp_new_line_before_else = true 14 | csharp_new_line_before_finally = true 15 | csharp_new_line_before_members_in_anonymous_types = false 16 | csharp_new_line_before_members_in_object_initializers = false 17 | csharp_new_line_before_open_brace = methods, control_blocks, types, properties, lambdas, accessors, object_collection_array_initializers 18 | csharp_new_line_between_query_expression_clauses = true 19 | csharp_prefer_braces = false:suggestion 20 | csharp_prefer_simple_default_expression = true:suggestion 21 | csharp_preferred_modifier_order = public,private,internal,protected,static,readonly,async,override,sealed:suggestion 22 | csharp_preserve_single_line_blocks = true 23 | csharp_preserve_single_line_statements = true 24 | csharp_space_after_cast = false 25 | csharp_space_after_colon_in_inheritance_clause = true 26 | csharp_space_after_keywords_in_control_flow_statements = true 27 | csharp_space_before_colon_in_inheritance_clause = true 28 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 29 | csharp_space_between_method_call_name_and_opening_parenthesis = false 30 | csharp_space_between_method_call_parameter_list_parentheses = false 31 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 32 | csharp_space_between_method_declaration_parameter_list_parentheses = false 33 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 34 | csharp_style_expression_bodied_accessors = true:suggestion 35 | csharp_style_expression_bodied_constructors = false:suggestion 36 | csharp_style_expression_bodied_methods = false:suggestion 37 | csharp_style_expression_bodied_properties = true:suggestion 38 | csharp_style_inlined_variable_declaration = true:suggestion 39 | csharp_style_var_elsewhere = true:suggestion 40 | csharp_style_var_for_built_in_types = true:suggestion 41 | csharp_style_var_when_type_is_apparent = true:suggestion 42 | dotnet_sort_system_directives_first = false 43 | dotnet_style_explicit_tuple_names = true:suggestion 44 | dotnet_style_object_initializer = true:suggestion 45 | csharp_style_pattern_local_over_anonymous_function = false:suggestion 46 | dotnet_style_predefined_type_for_member_access = true:suggestion 47 | dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion 48 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 49 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 50 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion 51 | dotnet_style_qualification_for_field = false:suggestion 52 | dotnet_style_qualification_for_method = false:suggestion 53 | dotnet_style_qualification_for_property = false:suggestion 54 | 55 | 56 | # Analyzer Configuration 57 | # These are rules we want to either ignore or have set as suggestion or info 58 | 59 | # CA1014: Mark assemblies with CLSCompliant 60 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1014 61 | dotnet_diagnostic.CA1014.severity = none 62 | 63 | # CA1725: Parameter names should match base declaration 64 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1725 65 | dotnet_diagnostic.CA1725.severity = suggestion 66 | 67 | # CA2227: Collection properties should be read only 68 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2227 69 | dotnet_diagnostic.CA2227.severity = suggestion 70 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.WebApi.Tests/AssemblySettings.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | [assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly)] -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.WebApi.Tests/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | 6 | AllEnabledByDefault 7 | Rocket Mortgage 8 | Copyright 2022 (c) Rocket Mortgage. All rights reserved. 9 | latest 10 | enable 11 | net6.0;netcoreapp3.1;net48 12 | NU1603,NU1701 13 | true 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.WebApi.Tests/HealthCheckHandlerExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using System; 3 | using System.Web.Http; 4 | using Xunit; 5 | 6 | namespace RockLib.HealthChecks.WebApi.Tests; 7 | 8 | public static class HealthCheckHandlerExtensionsTests 9 | { 10 | [Fact] 11 | public static void MapHealthRoute() 12 | { 13 | using var routes = new HttpRouteCollection(); 14 | routes.MapHealthRoute(Mock.Of()); 15 | 16 | Assert.Multiple( 17 | () => Assert.Single(routes), 18 | () => Assert.IsType(routes["HealthApi"].Handler) 19 | ); 20 | } 21 | 22 | [Fact] 23 | public static void MapHealthRouteWhenRoutesIsNull() => 24 | Assert.Throws( 25 | () => (null as HttpRouteCollection)!.MapHealthRoute(Mock.Of())); 26 | 27 | [Fact] 28 | public static void MapHealthRouteWhenRouteIsNull() 29 | { 30 | using var routes = new HttpRouteCollection(); 31 | Assert.Throws( 32 | () => routes.MapHealthRoute(Mock.Of(), route: null!)); 33 | } 34 | 35 | [Fact] 36 | public static void MapHealthRouteWhenRouteIsEmpty() 37 | { 38 | using var routes = new HttpRouteCollection(); 39 | Assert.Throws( 40 | () => routes.MapHealthRoute(Mock.Of(), route: string.Empty)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.WebApi.Tests/HealthCheckHandlerTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using System; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using Xunit; 8 | 9 | namespace RockLib.HealthChecks.WebApi.Tests; 10 | 11 | public static class HealthCheckHandlerTests 12 | { 13 | [Fact] 14 | public static void CreateWithNullRunner() => 15 | Assert.Throws(() => new HealthCheckHandler(null!, true)); 16 | 17 | [Fact] 18 | public static async Task SendAsync() 19 | { 20 | var response = new HealthResponse() { StatusCode = (int)HttpStatusCode.OK, ContentType = "text/json" }; 21 | var runner = new Mock(MockBehavior.Strict); 22 | runner.Setup(_ => _.RunAsync(It.IsAny())).Returns(Task.FromResult(response)); 23 | 24 | using var handler = new HealthCheckHandler(runner.Object, true); 25 | using var client = new HttpClient(handler) { BaseAddress = new("http://localhost") }; 26 | 27 | var clientResponse = await client.GetAsync(new Uri("http://localhost/health")).ConfigureAwait(false); 28 | 29 | Assert.Multiple( 30 | () => Assert.Equal(HttpStatusCode.OK, clientResponse.StatusCode), 31 | async () => Assert.Equal("", await clientResponse.Content.ReadAsStringAsync().ConfigureAwait(false)) 32 | ); 33 | 34 | runner.VerifyAll(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Tests/RockLib.HealthChecks.WebApi.Tests/RockLib.HealthChecks.WebApi.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | false 4 | 5 | 6 | 7 | 8 | 9 | 10 | all 11 | runtime; build; native; contentfiles; analyzers; buildtransitive 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/AspNetCore.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | sidebar_label: 'Add to an ASP.NET Core application' 4 | --- 5 | 6 | # How to add RockLib.HealthChecks to an ASP.NET Core application 7 | 8 | To add a health endpoint to an ASP.NET Core application, use the RockLib.HealthChecks.AspNetCore nuget package. This package adds the `UseRockLibHealthChecks` extension method on the `IApplicationBuilder` used in the `Startup` class. 9 | 10 | ```csharp 11 | public class Startup 12 | { 13 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 14 | { 15 | app.UseRockLibHealthChecks(); 16 | } 17 | } 18 | ``` 19 | 20 | This is generally set up in the Program.cs. 21 | 22 | ```csharp 23 | public class Program 24 | { 25 | public static void Main(string[] args) 26 | { 27 | CreateWebHostBuilder(args).Build().Run(); 28 | } 29 | 30 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 31 | WebHost.CreateDefaultBuilder(args) 32 | .UseStartup(); 33 | } 34 | ``` 35 | 36 | There are two versions of the `UseRockLibHealthChecks` method. One takes the name of the `HealthCheckRunner` that should be loaded from config and the other takes a `HealthCheckRunner` directly. 37 | 38 | ## Named HealthCheckRunner from config 39 | 40 | Parameter | Default Value | Description 41 | ---------------------- | --------------------------------- | ----------- 42 | builder | Required | The application builder. 43 | healthCheckRunnerName | `null` | The name of the `IHealthCheckRunner` to use. If `null` or not provided, the default value of the `HealthCheck.GetRunner` method is used. 44 | route | `/health` | The route of the health endpoint. 45 | formatter | `NewtonsoftJsonResponseFormatter` | The `IResponseFormatter` responsible for formatting health responses for the middleware's HTTP response body. 46 | 47 | 48 | ## Direct HealthCheckRunner 49 | 50 | Parameter | Default Value | Description 51 | ---------------------- | --------------------------------- | ----------- 52 | builder | Required | The application builder. 53 | healthCheckRunner | Required | The `IHealthCheckRunner` to use. If `null`, the default value of the `HealthCheck.GetRunner` method is used. 54 | route | `/health` | The route of the health endpoint. 55 | formatter | `NewtonsoftJsonResponseFormatter` | The `IResponseFormatter` responsible for formatting health responses for the middleware's HTTP response body. 56 | -------------------------------------------------------------------------------- /docs/ConfigureAppSettings.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 8 3 | sidebar_label: 'Configure with appsettings.json' 4 | --- 5 | 6 | # How to configure with appsettings.json 7 | 8 | Applications and libraries referencing RockLib.HealthChecks and targeting .NET Core, .NET Standard, or .NET Framework 4.5.1 and above can be configured with `appsettings.json`. The static `HealthCheck.Runners` property is defined by default by the "RockLib.HealthChecks" sub-section of the `Config.Root` property (from the `RockLib.Configuration` package). 9 | 10 | --- 11 | 12 | In this example, a health check runner is defined with one health check of type `ProcessUptimeHealthCheck`. Since no name is given, it is considered the default runner and can be retrieved by calling `HealthCheck.GetRunner()`. 13 | 14 | ```json 15 | { 16 | "RockLib.HealthChecks": { 17 | "Description": "Example health check", 18 | "HealthChecks": { "type": "RockLib.HealthChecks.System.ProcessUptimeHealthCheck, RockLib.HealthChecks" } 19 | } 20 | } 21 | ``` 22 | 23 | --- 24 | 25 | This health check runner has more than one health check. 26 | 27 | ```json 28 | { 29 | "RockLib.HealthChecks": { 30 | "Description": "Another example health check", 31 | "HealthChecks": [ 32 | { 33 | "type": "RockLib.HealthChecks.System.DiskDriveHealthCheck, RockLib.HealthChecks", 34 | "value": { 35 | "WarnGigabytes": "30", 36 | "FailGigabytes": "5" 37 | } 38 | }, 39 | { "type": "RockLib.HealthChecks.System.SystemUptimeHealthCheck, RockLib.HealthChecks" } 40 | ] 41 | } 42 | } 43 | ``` 44 | 45 | --- 46 | 47 | This example has multiple runners defined. The first one can be retrieved by calling `HealthCheck.GetRunner("EmptyRunner")` and the second one (since it is the default runner) by calling `HealthCheck.GetRunner()`. 48 | 49 | ```json 50 | { 51 | "RockLib.HealthChecks": [ 52 | { 53 | "Name": "EmptyRunner", 54 | "Description": "Empty health check runner, always passes." 55 | }, 56 | { 57 | "Description": "Full health check runner", 58 | "HealthChecks": [ 59 | { "type": "RockLib.HealthChecks.System.ProcessUptimeHealthCheck, RockLib.HealthChecks" } 60 | { "type": "RockLib.HealthChecks.System.DiskDriveHealthCheck, RockLib.HealthChecks" } 61 | { "type": "RockLib.HealthChecks.System.SystemUptimeHealthCheck, RockLib.HealthChecks" } 62 | ] 63 | } 64 | ] 65 | } 66 | ``` 67 | -------------------------------------------------------------------------------- /docs/ConfigureNet451AndAbove.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 10 3 | sidebar_label: 'Configure for .NET Framework 4.5.1 and above' 4 | --- 5 | 6 | # How to configure for .NET Framework 4.5.1 and above 7 | 8 | Applications and libraries referencing RockLib.HealthChecks and targeting .NET Framework 4.5.1 and above can be configured with `app.config` or `web.config` (though they can still be configured with appsetting.json or any other configuration provider). The static `HealthCheck.Runners` property is defined by default by the "RockLib.HealthChecks" sub-section of the `Config.Root` property from the `RockLib.Configuration` (from the `RockLib.Configuration` package). 9 | 10 | Like any custom configuration section, it must be declared in the `` element, as follows. The rest of the examples in this document assume that the `RockLib.HealthChecks` section has been declared as follows. 11 | 12 | ```xml 13 | 14 | 15 |
16 | 17 | 18 | ``` 19 | 20 | --- 21 | 22 | In this example, a health check runner is defined with one health check of type `ProcessUptimeHealthCheck`. Since no name is given, it is considered the default runner and can be retrieved by calling `HealthCheck.GetRunner()`. 23 | 24 | ```xml 25 | 26 | 27 | 28 | 29 | 30 | ``` 31 | 32 | --- 33 | 34 | This health check runner has more than one health check. 35 | 36 | ```xml 37 | 38 | 39 | 40 | 42 | 43 | 44 | 45 | 46 | ``` 47 | 48 | --- 49 | 50 | This example has multiple runners defined. The first one can be retrieved by calling `HealthCheck.GetRunner("EmptyRunner")` and the second one (since it is the default runner) by calling `HealthCheck.GetRunner()`. 51 | 52 | ```xml 53 | 54 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | ``` 63 | -------------------------------------------------------------------------------- /docs/ConfigureNet45AndBelow.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 9 3 | sidebar_label: 'Configure for .NET Framework 4.5 and below' 4 | --- 5 | 6 | # How to configure for .NET Framework 4.5 and below 7 | 8 | Applications and libraries referencing RockLib.HealthChecks and targeting .NET Framework 4.5.1 and above can be configured with `app.config` or `web.config`. The static `HealthCheck.Runners` property is defined by default by the "rockLib.healthChecks" section from `ConfigurationManager` as type `RockLibHealthChecksSection` by calling its `CreateRunners` method. 9 | 10 | Like any custom configuration section, it must be declared in the `` element, as follows. The rest of the examples in this document assume that the `rockLib.healthChecks` section has been declared as follows. 11 | 12 | ```xml 13 | 14 | 15 |
16 | 17 | 18 | ``` 19 | 20 | --- 21 | 22 | In this example, a health check runner is defined with one health check of type `ProcessUptimeHealthCheck`. Since no name is given, it is considered the default runner and can be retrieved by calling `HealthCheck.GetRunner()`. 23 | 24 | ```xml 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | ``` 35 | 36 | --- 37 | 38 | This health check runner has more than one health check. 39 | 40 | ```xml 41 | 42 | 43 | 44 | 45 | 48 | 49 | 50 | 51 | 52 | 53 | ``` 54 | 55 | --- 56 | 57 | This example has multiple runners defined. The first one can be retrieved by calling `HealthCheck.GetRunner("EmptyRunner")` and the second one (since it is the default runner) by calling `HealthCheck.GetRunner()`. 58 | 59 | ```xml 60 | 61 | 62 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | ``` 74 | -------------------------------------------------------------------------------- /docs/CustomHealthCheck.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 11 3 | sidebar_label: 'Create custom health checks' 4 | --- 5 | 6 | # How to create custom health checks 7 | 8 | To create a custom health check, either implement the `IHealthCheck` interface or inherit from the `SingleResultHealthCheck` abstract class. 9 | 10 | For custom health checks that generate a single result, inherit from `SingleResultHealthCheck`, override the `CheckAsync` method, and optionally specify parameters for the base constructor. 11 | 12 | ```csharp 13 | public class MyHealthCheck : SingleResultHealthCheck 14 | { 15 | public MyHealthCheck() 16 | : base(componentName: "my", measurementName: "healthCheck", 17 | componentType: "example", componentId: "2d458535-c9a8-45be-91c2-dfd30b7a093e") 18 | { 19 | } 20 | 21 | protected override Task CheckAsync(HealthCheckResult result, CancellationToken cancellationToken) 22 | { 23 | // TODO: Perform the actual health check, setting the Status property accordingly. 24 | result.Status = HealthStatus.Pass; 25 | return Task.CompletedTask; 26 | } 27 | } 28 | ``` 29 | 30 | --- 31 | 32 | For custom health checks that generate multiple results, implement the `IHealthCheck` interface directly. 33 | 34 | ```csharp 35 | public class AnotherHealthCheck : IHealthCheck 36 | { 37 | public AnotherHealthCheck(string componentName = "another", string measurementName = "healthCheck", 38 | string componentType = "example", string componentId = "224ee0cd-e838-4ea9-95af-2bd31dc42850") 39 | { 40 | ComponentName = componentName; 41 | MeasurementName = measurementName; 42 | ComponentType = componentType; 43 | ComponentId = componentId; 44 | } 45 | 46 | public string ComponentName { get; } 47 | public string MeasurementName { get; } 48 | public string ComponentType { get; } 49 | public string ComponentId { get; } 50 | 51 | public async Task> CheckAsync(CancellationToken cancellationToken = default(CancellationToken)) 52 | { 53 | var results = new List(); 54 | 55 | var result1 = this.CreateHealthCheckResult(); 56 | result1.Status = HealthStatus.Pass; 57 | results.Add(result1); 58 | 59 | var result2 = this.CreateHealthCheckResult(); 60 | result2.Status = HealthStatus.Warn; 61 | result2.Output = "This message should describe why the status is Warn."; 62 | results.Add(result2); 63 | 64 | return results; 65 | } 66 | } 67 | ``` 68 | 69 | ## .NET Framework 3.5 and 4.0 70 | 71 | In .NET Framework 4.0 and below, there is no support for `async` methods, so the `IHealthCheck` interface and `SingleResultHealthCheck` abstract class have synchronous methods instead. Here is the signatures of the synchronous methods: 72 | 73 | ```csharp 74 | public interface IHealthCheck 75 | { 76 | IList Check(); 77 | } 78 | 79 | public abstract class SingleResultHealthCheck : IHealthCheck 80 | { 81 | protected abstract void Check(HealthCheckResult result); 82 | } 83 | ``` 84 | -------------------------------------------------------------------------------- /docs/DiskDriveHealthCheck.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 12 3 | sidebar_label: 'Disk Drive Health Check' 4 | --- 5 | 6 | # DiskDriveHealthCheck 7 | 8 | This health check monitors the amount of available free space on disk. If a disk's available free space is below `WarnGigabytes`, results will have a status of `Warn`. If below `FailGigabytes`, results will have a status of `Fail`. 9 | 10 | None of its constructor's parameters are required. 11 | 12 | Parameter | Default Value | Description 13 | ------------------ | ---------------------- | ----------- 14 | warnGigabytes | `5` | The the lowest allowable level of available free space in gigabytes, below which results in a `Warn` status. 15 | failGigabytes | `0.5` | The the lowest allowable level of available free space in gigabytes, below which results in a `Fail` status. 16 | driveName | `"*"` | The name of the drive on which to check the available free space. The expected format for the C drive is `"C:\"` (for Windows). The wildcard `"*"` can be used to return results from all drives. 17 | componentName | `"diskDrive"` | The name of the logical downstream dependency or sub-component of a service. Must not contain a colon. 18 | measurementName | `"availableFreeSpace"` | The name of the measurement that the status is reported for. Must not contain a colon. 19 | componentType | `"system"` | The type of the component. 20 | componentId | `null` | A unique identifier of an instance of a specific sub-component/dependency of a service. 21 | -------------------------------------------------------------------------------- /docs/GettingStarted.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Getting Started 6 | 7 | In this tutorial, we will be building a web application that has a basic health check. 8 | 9 | --- 10 | 11 | Create a ASP.NET Core 2.2 (or above) web application named "HealthCheckTutorial". 12 | 13 | --- 14 | 15 | Add a nuget reference for "RockLib.HealthChecks.AspNetCore" the project. 16 | 17 | --- 18 | 19 | Add a new JSON file to the project named 'appsettings.json'. Set its 'Copy to Output Directory' setting to 'Copy if newer'. Add the following configuration: 20 | 21 | ```json 22 | { 23 | "RockLib.HealthChecks": { 24 | "version": "1", 25 | "serviceId": "3390b579-d076-4610-a9bd-7d1a5af893f9", 26 | "description": "my health check", 27 | "healthChecks": { 28 | "type": "RockLib.HealthChecks.System.ProcessUptimeHealthCheck, RockLib.HealthChecks" 29 | } 30 | } 31 | } 32 | ``` 33 | 34 | --- 35 | 36 | Edit the `Startup.cs` file as follows: 37 | 38 | ```csharp 39 | using Microsoft.AspNetCore.Builder; 40 | using Microsoft.AspNetCore.Hosting; 41 | using RockLib.HealthChecks.AspNetCore; 42 | 43 | namespace HealthCheckTutorial 44 | { 45 | public class Startup 46 | { 47 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 48 | { 49 | app.UseRockLibHealthChecks(); 50 | } 51 | } 52 | } 53 | ``` 54 | 55 | --- 56 | 57 | In the project properties 'Debug' section, set the relative url to 'health'. 58 | 59 | --- 60 | 61 | Start the app. It should open a web browser and navigate to the health end point with the following output: 62 | 63 | ```json 64 | { 65 | "status": "pass", 66 | "version": "1", 67 | "serviceId": "3390b579-d076-4610-a9bd-7d1a5af893f9", 68 | "description": "my health check", 69 | "checks": { 70 | "process:uptime": [ 71 | { 72 | "observedValue": 5.0565182, 73 | "observedUnit": "s", 74 | "status": "pass", 75 | "componentType": "system", 76 | "time": "2019-10-18T15:50:20.0340741Z" 77 | } 78 | ] 79 | } 80 | } 81 | ``` 82 | -------------------------------------------------------------------------------- /docs/HttpModule.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 5 3 | sidebar_label: 'Add to an ASP.NET application via HttpModule' 4 | --- 5 | 6 | # How to add RockLib.HealthChecks to an ASP.NET application via HttpModule 7 | 8 | To add a health endpoint to an ASP.NET application via HttpModule, use the RockLib.HealthChecks.HttpModule nuget package. This package adds the `HealthCheckHttpModule` HTTP module. This can be wired up in the web.config. 9 | 10 | ```xml 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ``` 19 | 20 | Since the HTTP module doesn't have use a method to wire up, configuration is handled with static parameters on the `HealthCheckHttpModule` class. 21 | 22 | Property | Default Value | Description 23 | ---------------------- | ------------------ | ----------- 24 | HealthCheckRunnerName | `null` | Gets or sets the name of the `IHealthCheckRunner`. 25 | Route | `health` | Gets or sets the route of the health endpoint. 26 | Indent | `false` | Gets or sets a value indicating whether to indent the JSON output. 27 | 28 | This can be done in the composition root. One example is the 'Global.asax.cs'. 29 | 30 | ```csharp 31 | public class Global : System.Web.HttpApplication 32 | { 33 | protected void Application_Start(object sender, EventArgs e) 34 | { 35 | HealthCheckHttpModule.HealthCheckRunnerName = "MyRunner"; 36 | HealthCheckHttpModule.Route = "/CustomHealthRoute"; 37 | HealthCheckHttpModule.Indent = true; 38 | 39 | // More startup stuff here 40 | } 41 | } 42 | ``` -------------------------------------------------------------------------------- /docs/HttpStatsHealthCheck.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | sidebar_label: 'Metrics (HTTP) Health Check' 4 | --- 5 | 6 | # HttpStatsHealthCheck 7 | 8 | This health check monitors actual (live) HTTP calls to downstream systems to collect response status codes, and reports their outcomes. If the number of failed calls (StatusCode >= 400) is 9 | below `WarnThreshold`, results will have a status of `Warn`. If below `FailThreshold`, results will have a status of `Fail`. 10 | 11 | 12 | In your Startup.cs file, add the following code to `ConfigureServices`: 13 | ```csharp 14 | builder.ConfigureRockLibHealthChecks(); 15 | ``` 16 | The above is in addition to `app.UseRockLibHealthChecks();`, in the `Configure` method. 17 | 18 | 19 | Parameter | Default Value | Description 20 | ------------------ |---------------| ----------- 21 | warningThreshold | `"0.9"` | The lowest percentage of HTTP status codes >=400, below which results in a `Warn` status. 22 | errorThreshold | `"0.75"` | The lowest percentage of HTTP status codes >=400, below which results in a `Fail` status. 23 | samples | `100` | The number of sample data points to keep. Collection is done using a sliding window - e.g. "the 100 most recent". 24 | minimumSamples | `1` | The minimum number of samples to collect before evaluating the health check. If the number of samples is less than this value, the health check will return `Warn`.
This number must be smaller than `samples`. 25 | collectors | `"[]"` | An explicit list of collector thresholds. If not provided, the default values (above) will be used. 26 | collector->Name | `""` | The http host name of the downstream system (to bind the settings to). 27 | 28 | Note: A collector is created for each http host name regardless. The above settings are only necessary if you want to override the default sample size or thresholds. 29 | 30 | 31 | Example appsettings.json: 32 | 33 | ```json 34 | { 35 | "RockLib.HealthChecks": { 36 | "healthChecks": [ 37 | { 38 | "type": "RockLib.HealthChecks.AspNetCore.Checks.HttpStatsHealthCheck, RockLib.HealthChecks.AspNetCore", 39 | "value": { 40 | "warningThreshold": ".98", 41 | "errorThreshold": ".95", 42 | "samples": 500, 43 | "minimumSamples": 10, 44 | "collectors": [ 45 | { 46 | "Name": "www.google.com", 47 | "samples": 50, 48 | "warningThreshold": ".80", 49 | "errorThreshold": ".70" 50 | } 51 | ] 52 | } 53 | } 54 | ] 55 | } 56 | } 57 | ``` 58 | -------------------------------------------------------------------------------- /docs/InstantiateRunner.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 7 3 | sidebar_label: 'Instantiate a health check runner' 4 | --- 5 | 6 | # How to instantiate a health check runner 7 | 8 | A `HealthCheckRunner` object can be instantiated directly with its constructor. 9 | 10 | Parameter | Default Value | Description 11 | ------------------ | --------------------------- | ----------- 12 | healthChecks | `null` | The collection of `IHealthCheck` objects to be checked by this runner. 13 | name | `null` | The name of the runner. 14 | description | `null` | The human-friendly description of the service. 15 | serviceId | `null` | The unique identifier of the service, in the application scope. 16 | version | `null` | The public version of the service. 17 | releaseId | `null` | The "release version" or "release ID" of the service. 18 | responseCustomizer | `null` | The `IHealthResponseCustomizer` that customizes each `HealthResponse` object returned by this runner. 19 | contentType | `"application/health+json"` | The HTTP content type of responses created by this health check runner. Must not have a null or empty value. 20 | passStatusCode | `200` | The HTTP status code of responses created by this health check runner that have a status of `Pass`. Must have a value in the 200-399 range. 21 | warnStatusCode | `200` | The HTTP status code of responses created by this health check runner that have a status of `Warn`. Must have a value in the 200-399 range. 22 | failStatusCode | `503` | The HTTP status code of responses created by this health check runner that have a status of `Fail`. Must have a value in the 400-599 range. 23 | 24 | --- 25 | 26 | This example creates an empty runner - one that always passes. 27 | 28 | ```csharp 29 | IHealthCheckRunner runner = new HealthCheckRunner(); 30 | ``` 31 | 32 | --- 33 | 34 | This example creates a runner with multiple health checks: 35 | 36 | ```csharp 37 | IHealthCheckRunner runner = new HealthCheckRunner( 38 | healthChecks: new IHealthCheck[] 39 | { 40 | new DiskDriveHealthCheck(warnGigabytes: 30, failGigabytes: 5), 41 | new SystemUptimeHealthCheck() 42 | }, 43 | description: "Example"); 44 | ``` 45 | -------------------------------------------------------------------------------- /docs/ManualHealthChecks.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | sidebar_label: 'Manually perform health checks' 4 | --- 5 | 6 | # How to manually perform health checks 7 | 8 | The simplest way to manually run a set of health checks is to call `RunAsync` method on a `HealthCheckRunner`. A runner can be instantiated manually, see [here](InstantiateRunner.md), or it can loaded from config by using the static `HealthChecks.GetRunner` method. 9 | 10 | Example MVC Controller: 11 | 12 | ```csharp 13 | public class HealthController : Controller 14 | { 15 | public async Task Index() 16 | { 17 | var healthCheckResponse = await HealthCheck.GetRunner().RunAsync(); 18 | 19 | Response.StatusCode = healthCheckResponse.StatusCode; 20 | 21 | return Content(healthCheckResponse.Serialize(true), healthCheckResponse.ContentType); 22 | } 23 | } 24 | ``` 25 | 26 | Example appsettings.json: 27 | 28 | ```json 29 | { 30 | "RockLib.HealthChecks": { 31 | "version": "1", 32 | "serviceId": "3390b579-d076-4610-a9bd-7d1a5af893f9", 33 | "description": "my health check", 34 | "healthChecks": { 35 | "type": "RockLib.HealthChecks.System.ProcessUptimeHealthCheck, RockLib.HealthChecks" 36 | } 37 | } 38 | } 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/ProcessUptimeHealthCheck.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 13 3 | sidebar_label: 'Process Up time HealthCheck' 4 | --- 5 | 6 | # ProcessUptimeHealthCheck 7 | 8 | This health check records the uptime of the current process. Results will alwas have a status of `Pass`. 9 | 10 | None of its constructor's parameters are required. 11 | 12 | Parameter | Default Value | Description 13 | ------------------ | ---------------------- | ----------- 14 | componentName | `"process"` | The name of the logical downstream dependency or sub-component of a service. Must not contain a colon. 15 | measurementName | `"uptime"` | The name of the measurement that the status is reported for. Must not contain a colon. 16 | componentType | `"system"` | The type of the component. 17 | componentId | `null` | A unique identifier of an instance of a specific sub-component/dependency of a service. 18 | -------------------------------------------------------------------------------- /docs/ResponseWriter.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 6 3 | sidebar_label: 'Format the output' 4 | --- 5 | 6 | # How to format the output of Microsoft.Extensions.Diagnostics.HealthChecks in the draft RFC format 7 | 8 | To format the output of Microsoft.Extensions.Diagnostics.HealthChecks in the draft RFC format, use the RockLib.HealthChecks.AspNetCore.ResponseWriter nuget package. This package adds the `RockLibHealthChecks.ResponseWriter` that can be set as the `Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckOptions.ResponseWriter`. This will map the `HealthReport` into a `RockLib.HealthChecks.HealthResponse`. 9 | 10 | ```csharp 11 | public class Startup 12 | { 13 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 14 | { 15 | app.UseHealthChecks("/health", new HealthCheckOptions 16 | { 17 | ResponseWriter = RockLibHealthChecks.ResponseWriter 18 | }); 19 | } 20 | } 21 | ``` 22 | 23 | This is generally set up in the Program.cs. 24 | 25 | ```csharp 26 | public class Program 27 | { 28 | public static void Main(string[] args) 29 | { 30 | CreateWebHostBuilder(args).Build().Run(); 31 | } 32 | 33 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 34 | WebHost.CreateDefaultBuilder(args) 35 | .UseStartup(); 36 | } 37 | ``` 38 | 39 | Since the response writer doesn't have a way to pass in the usual RockLib options, configuration is handled with static parameters on the `RockLibHealthChecks` class. 40 | 41 | Property | Default Value | Description 42 | ---------------------- | ------------------ | ----------- 43 | Indent | `false` | Gets or sets a value indicating whether the `ResponseWriter` delegate will indent its JSON output. 44 | HideOutputs | `false` | Gets or sets a value indicating whether the `ResponseWriter` delegate will hide the output property in its JSON output. 45 | HideExceptions | `false` | Gets or sets a value indicating whether the `ResponseWriter` delegate will hide the exception property in its JSON output. 46 | 47 | This can be done in the 'Startup.cs' 48 | 49 | ```csharp 50 | public class Startup 51 | { 52 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 53 | { 54 | RockLibHealthChecks.Indent = true; 55 | RockLibHealthChecks.HideOutputs = true; 56 | RockLibHealthChecks.HideExceptions = true; 57 | 58 | app.UseHealthChecks("/health", new HealthCheckOptions 59 | { 60 | ResponseWriter = RockLibHealthChecks.ResponseWriter 61 | }); 62 | } 63 | } 64 | ``` -------------------------------------------------------------------------------- /docs/SystemUptimeHealthCheck.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 14 3 | sidebar_label: 'SystemUptime HealthCheck' 4 | --- 5 | 6 | # SystemUptimeHealthCheck 7 | 8 | This health check records the uptime of the system. Results will always have a status of `Pass`. 9 | 10 | None of its constructor's parameters are required. 11 | 12 | Parameter | Default Value | Description 13 | ------------------ | ---------------------- | ----------- 14 | componentName | `"system"` | The name of the logical downstream dependency or sub-component of a service. Must not contain a colon. 15 | measurementName | `"uptime"` | The name of the measurement that the status is reported for. Must not contain a colon. 16 | componentType | `"system"` | The type of the component. 17 | componentId | `null` | A unique identifier of an instance of a specific sub-component/dependency of a service. 18 | -------------------------------------------------------------------------------- /docs/WebApi.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 4 3 | sidebar_label: 'Add to an ASP.NET WebApi application' 4 | --- 5 | 6 | # How to add RockLib.HealthChecks to an ASP.NET WebApi application 7 | 8 | To add a health endpoint to an ASP.NET WebApi application, use the RockLib.HealthChecks.WebApi nuget package. This package adds the `MapHealthRoute` extension method on the `HttpRoutesCollection` used in the `WebApiConfig` class. 9 | 10 | ```csharp 11 | public static class WebApiConfig 12 | { 13 | public static void Register(HttpConfiguration config) 14 | { 15 | config.Routes.MapHealthRoute(); 16 | } 17 | } 18 | ``` 19 | 20 | This is generally set up in the Global.aspx.cs. 21 | 22 | ```csharp 23 | public class WebApiApplication : System.Web.HttpApplication 24 | { 25 | protected void Application_Start() 26 | { 27 | GlobalConfiguration.Configure(WebApiConfig.Register); 28 | } 29 | } 30 | ``` 31 | 32 | There are two versions of the `MapHealthRoute` method. One takes the name of the `HealthCheckRunner` that should be loaded from config and the other takes a `HealthCheckRunner` directly. 33 | 34 | ## Named HealthCheckRunner from config 35 | 36 | Parameter | Default Value | Description 37 | ---------------------- | ------------------ | ----------- 38 | routes | Required | The route collection. 39 | healthCheckRunnerName | `null` | The name of the `IHealthCheckRunner` to use. If `null` or not provided, the default value of the `HealthCheck.GetRunner` method is used. 40 | route | `/health` | The route of the health endpoint. 41 | indent | `false` | Whether to indent the JSON output. 42 | 43 | 44 | ## Direct HealthCheckRunner 45 | 46 | Parameter | Default Value | Description 47 | ---------------------- | ------------------ | ----------- 48 | routes | Required | The route collection. 49 | healthCheckRunner | Required | The `IHealthCheckRunner` to use. If `null`, the default value of the `HealthCheck.GetRunner` method is used. 50 | route | `/health` | The route of the health endpoint. 51 | indent | `false` | Whether to indent the JSON output. 52 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RockLib/RockLib.HealthChecks/548c67974dda399a4fc6dd366251489165c26862/icon.png --------------------------------------------------------------------------------