From 133cf0b12ec975b3b53e371e9a762066231bdbb9 Mon Sep 17 00:00:00 2001 From: Robin-Manuel Thiel Date: Mon, 27 Nov 2023 12:21:58 +0100 Subject: [PATCH 1/4] [FEATURE] Add Health Checks --- README.md | 37 ++++++++++++++++++- .../Startup/StartupExtensions.cs | 6 ++- src/Wemogy.AspNet/Startup/StartupOptions.cs | 1 + 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1bc9d42..fd3af63 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,10 @@ public Startup(IConfiguration configuration) _options = new StartupOptions(); + // Middleware + _options + .AddMiddleware(); + // Add Swagger _options .AddOpenApi("v1") @@ -29,7 +33,8 @@ public Startup(IConfiguration configuration) // Add Monitoring _options - .AddMonitoring(Configuration["ServiceName"], Configuration["ServiceVersion"]) + .AddMonitoring() + .WithMeter(Observability.Meter.Name) .WithApplicationInsights(Configuration["AzureApplicationInsightsConnectionString"]) .WithPrometheus(); } @@ -102,7 +107,7 @@ Make sure to register the Meter at Startup. ```csharp var options = new StartupOptions(); options - .AddMonitoring(Configuration["ServiceName"], Configuration["ServiceVersion"]) + .AddMonitoring() .WithMeter(Observability.Meter.Name) // ... ``` @@ -114,3 +119,31 @@ Observability.Pings.Add(1); Observability.PingDelay.Record(new Random().Next(50, 100)); ``` + +## Health Checks + +The library automatically includes a health check endpoint at `/healthz`, which checks the basic health of the service. + +You can add additional health checks to the default setup. + +- Inline Health Checks +- Custom Health Checks, that implement the IHealthCheck interface +- [Database Health Checks](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-6.0#database-probe) +- [Entity Framework Core DbContext probes](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-6.0#entity-framework-core-dbcontext-probe) + +```csharp +public void ConfigureServices(IServiceCollection services) +{ + services.AddDefaultSetup(_options); + + // Health Checks + services + .AddHealthChecks() + .AddCheck("MyHealthCheck", () => HealthCheckResult.Healthy("Everything is fine.") + .AddCheck("MyOtherHealthCheck", MyHealthChecker) // Implement IHealthCheck + .AddSqlServer("") + .AddDbContextCheck()); + + // ... +} +``` diff --git a/src/Wemogy.AspNet/Startup/StartupExtensions.cs b/src/Wemogy.AspNet/Startup/StartupExtensions.cs index 51ce0ee..302e82f 100644 --- a/src/Wemogy.AspNet/Startup/StartupExtensions.cs +++ b/src/Wemogy.AspNet/Startup/StartupExtensions.cs @@ -56,6 +56,8 @@ public static void AddDefaultSetup(this IServiceCollection serviceCollection, St serviceCollection.AddDefaultControllers(options.DaprEnvironment != null, options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes); + serviceCollection.AddHealthChecks(); + serviceCollection.AddDefaultRouting(); } @@ -120,9 +122,9 @@ public static void UseDefaultSetup(this IApplicationBuilder applicationBuilder, { applicationBuilder.UseEndpoints(endpoints => { - // Register endpoints for Dapr PubSub subscription information - endpoints.MapSubscribeHandler(); + endpoints.MapSubscribeHandler(); // Register endpoints for Dapr PubSub endpoints.MapControllers(); + endpoints.MapHealthChecks("/healthz"); }); } else diff --git a/src/Wemogy.AspNet/Startup/StartupOptions.cs b/src/Wemogy.AspNet/Startup/StartupOptions.cs index 309679c..3674f24 100644 --- a/src/Wemogy.AspNet/Startup/StartupOptions.cs +++ b/src/Wemogy.AspNet/Startup/StartupOptions.cs @@ -15,6 +15,7 @@ public class StartupOptions internal MonitoringEnvironment? MonitoringEnvironment { get; private set; } internal DaprEnvironment? DaprEnvironment { get; private set; } internal HashSet Middlewares { get; private set; } + internal HashSet HealthChecks { get; private set; } /// /// Sets the property for all contollers. From ed569377fd100aac37cb5d1cd6cdf300fe2a6d9c Mon Sep 17 00:00:00 2001 From: Robin-Manuel Thiel Date: Mon, 27 Nov 2023 12:27:18 +0100 Subject: [PATCH 2/4] Fix build --- README.md | 2 +- src/Wemogy.AspNet/Startup/StartupOptions.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index fd3af63..b109d84 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ public void ConfigureServices(IServiceCollection services) .AddCheck("MyHealthCheck", () => HealthCheckResult.Healthy("Everything is fine.") .AddCheck("MyOtherHealthCheck", MyHealthChecker) // Implement IHealthCheck .AddSqlServer("") - .AddDbContextCheck()); + .AddDbContextCheck(); // ... } diff --git a/src/Wemogy.AspNet/Startup/StartupOptions.cs b/src/Wemogy.AspNet/Startup/StartupOptions.cs index 3674f24..309679c 100644 --- a/src/Wemogy.AspNet/Startup/StartupOptions.cs +++ b/src/Wemogy.AspNet/Startup/StartupOptions.cs @@ -15,7 +15,6 @@ public class StartupOptions internal MonitoringEnvironment? MonitoringEnvironment { get; private set; } internal DaprEnvironment? DaprEnvironment { get; private set; } internal HashSet Middlewares { get; private set; } - internal HashSet HealthChecks { get; private set; } /// /// Sets the property for all contollers. From 0ebb4122777600fdfecf977e03d11bce157d6a38 Mon Sep 17 00:00:00 2001 From: Robin-Manuel Thiel Date: Mon, 27 Nov 2023 22:40:03 +0100 Subject: [PATCH 3/4] Add Builder Function for HealthChecks --- README.md | 21 +++++++------------ .../Startup/StartupExtensions.cs | 4 +++- src/Wemogy.AspNet/Startup/StartupOptions.cs | 8 +++++++ 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index b109d84..a8df1e1 100644 --- a/README.md +++ b/README.md @@ -132,18 +132,11 @@ You can add additional health checks to the default setup. - [Entity Framework Core DbContext probes](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-6.0#entity-framework-core-dbcontext-probe) ```csharp -public void ConfigureServices(IServiceCollection services) -{ - services.AddDefaultSetup(_options); - - // Health Checks - services - .AddHealthChecks() - .AddCheck("MyHealthCheck", () => HealthCheckResult.Healthy("Everything is fine.") - .AddCheck("MyOtherHealthCheck", MyHealthChecker) // Implement IHealthCheck - .AddSqlServer("") - .AddDbContextCheck(); - - // ... -} +_options.ConfigureHealthChecks(builder => { + builder + .AddCheck("MyHealthCheck", () => HealthCheckResult.Healthy("Everything is fine.") + .AddCheck("MyOtherHealthCheck", MyHealthChecker) // Implement IHealthCheck + .AddSqlServer("") + .AddDbContextCheck(); +}); ``` diff --git a/src/Wemogy.AspNet/Startup/StartupExtensions.cs b/src/Wemogy.AspNet/Startup/StartupExtensions.cs index 302e82f..c4b7bb7 100644 --- a/src/Wemogy.AspNet/Startup/StartupExtensions.cs +++ b/src/Wemogy.AspNet/Startup/StartupExtensions.cs @@ -56,7 +56,9 @@ public static void AddDefaultSetup(this IServiceCollection serviceCollection, St serviceCollection.AddDefaultControllers(options.DaprEnvironment != null, options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes); - serviceCollection.AddHealthChecks(); + // Health checks + var healthChecksBuilder = serviceCollection.AddHealthChecks(); + options.ConfigureHealthCheckBuilder?.Invoke(healthChecksBuilder); serviceCollection.AddDefaultRouting(); } diff --git a/src/Wemogy.AspNet/Startup/StartupOptions.cs b/src/Wemogy.AspNet/Startup/StartupOptions.cs index 309679c..c9e6f6b 100644 --- a/src/Wemogy.AspNet/Startup/StartupOptions.cs +++ b/src/Wemogy.AspNet/Startup/StartupOptions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Reflection; +using Microsoft.Extensions.DependencyInjection; using Wemogy.AspNet.Dapr; using Wemogy.AspNet.Monitoring; using Wemogy.AspNet.Swagger; @@ -15,6 +16,7 @@ public class StartupOptions internal MonitoringEnvironment? MonitoringEnvironment { get; private set; } internal DaprEnvironment? DaprEnvironment { get; private set; } internal HashSet Middlewares { get; private set; } + internal Action? ConfigureHealthCheckBuilder { get; private set; } /// /// Sets the property for all contollers. @@ -68,4 +70,10 @@ public StartupOptions AddMiddleware() Middlewares.Add(typeof(TMiddleware)); return this; } + + public StartupOptions ConfigureHealthChecks(Action configure) + { + ConfigureHealthCheckBuilder = configure; + return this; + } } From ada056ccc0d5e980ecec1d5ad45b176b51601d81 Mon Sep 17 00:00:00 2001 From: Robin-Manuel Thiel Date: Mon, 27 Nov 2023 23:50:13 +0100 Subject: [PATCH 4/4] Add ActivitiySource to Monitoring for Tracing Spans --- README.md | 25 +++++++++++++++++++ .../Monitoring/MonitoringExtensions.cs | 5 ++++ src/Wemogy.AspNet/Wemogy.AspNet.csproj | 2 +- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a8df1e1..6424033 100644 --- a/README.md +++ b/README.md @@ -87,12 +87,16 @@ We use Open Telemetry to provide monitoring for your application. The library pr Every project should have a `Observability.cs` class, which is responsible for defining the Meters. ```csharp +using System.Diagnostics; using System.Diagnostics.Metrics; using System.Reflection; using OpenTelemetry.Metrics; public class Observability { + // Define a default ActivitySource + public static readonly ActivitySource DefaultActivities = new ActivitySource("ServiceName"); + // Define a default Meter with name and version public static readonly Meter Meter = new("ServiceName", Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "0.0.0"); @@ -108,6 +112,7 @@ Make sure to register the Meter at Startup. var options = new StartupOptions(); options .AddMonitoring() + .WithActivitySource(Observability.DefaultActivities.Name) .WithMeter(Observability.Meter.Name) // ... ``` @@ -120,6 +125,26 @@ Observability.Pings.Add(1); Observability.PingDelay.Record(new Random().Next(50, 100)); ``` +Use Activities in your Code to create sections of code that can be traced. + +```csharp +using (var fistActivity = Observability.DefaultActivities.StartActivity("First section")) +{ + fistActivity.AddTag("date", DateTime.UtcNow.ToString()); + fistActivity.AddTag("section", "first"); + Thread.Sleep(100); // Do work + fistActivity.Stop(); +}; + +using (var secondActivity = Observability.DefaultActivities.StartActivity("Second section")) +{ + secondActivity.AddTag("date", DateTime.UtcNow.ToString()); + secondActivity.AddTag("section", "second"); + Thread.Sleep(200); // Do work + secondActivity.Stop(); +}; +``` + ## Health Checks The library automatically includes a health check endpoint at `/healthz`, which checks the basic health of the service. diff --git a/src/Wemogy.AspNet/Monitoring/MonitoringExtensions.cs b/src/Wemogy.AspNet/Monitoring/MonitoringExtensions.cs index f31651a..2f2acec 100644 --- a/src/Wemogy.AspNet/Monitoring/MonitoringExtensions.cs +++ b/src/Wemogy.AspNet/Monitoring/MonitoringExtensions.cs @@ -47,6 +47,11 @@ public static IServiceCollection AddDefaultMonitoring( builder.AddAspNetCoreInstrumentation(); builder.AddEntityFrameworkCoreInstrumentation(); + foreach (var activitySourceName in environment.ActivitySourceNames) + { + builder.AddSource(activitySourceName); + } + if (environment.UseOtlpExporter) { builder.AddOtlpExporter(options => diff --git a/src/Wemogy.AspNet/Wemogy.AspNet.csproj b/src/Wemogy.AspNet/Wemogy.AspNet.csproj index cbac5e0..c0e9fa9 100644 --- a/src/Wemogy.AspNet/Wemogy.AspNet.csproj +++ b/src/Wemogy.AspNet/Wemogy.AspNet.csproj @@ -42,7 +42,7 @@ - +