Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Add Health Checks #48

Merged
merged 4 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 53 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ public Startup(IConfiguration configuration)

_options = new StartupOptions();

// Middleware
_options
.AddMiddleware<ApiExceptionFilter>();

// Add Swagger
_options
.AddOpenApi("v1")
Expand All @@ -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();
}
Expand Down Expand Up @@ -82,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");

Expand All @@ -102,7 +111,8 @@ Make sure to register the Meter at Startup.
```csharp
var options = new StartupOptions();
options
.AddMonitoring(Configuration["ServiceName"], Configuration["ServiceVersion"])
.AddMonitoring()
.WithActivitySource(Observability.DefaultActivities.Name)
.WithMeter(Observability.Meter.Name)
// ...
```
Expand All @@ -114,3 +124,44 @@ 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.

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
_options.ConfigureHealthChecks(builder => {
builder
.AddCheck("MyHealthCheck", () => HealthCheckResult.Healthy("Everything is fine.")
.AddCheck("MyOtherHealthCheck", MyHealthChecker) // Implement IHealthCheck
.AddSqlServer("<MY_CONNECTION_STRING>")
.AddDbContextCheck<SampleDbContext>();
});
```
5 changes: 5 additions & 0 deletions src/Wemogy.AspNet/Monitoring/MonitoringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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 =>
Expand Down
8 changes: 6 additions & 2 deletions src/Wemogy.AspNet/Startup/StartupExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ public static void AddDefaultSetup(this IServiceCollection serviceCollection, St

serviceCollection.AddDefaultControllers(options.DaprEnvironment != null, options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes);

// Health checks
var healthChecksBuilder = serviceCollection.AddHealthChecks();
options.ConfigureHealthCheckBuilder?.Invoke(healthChecksBuilder);

serviceCollection.AddDefaultRouting();
}

Expand Down Expand Up @@ -120,9 +124,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
Expand Down
8 changes: 8 additions & 0 deletions src/Wemogy.AspNet/Startup/StartupOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -15,6 +16,7 @@ public class StartupOptions
internal MonitoringEnvironment? MonitoringEnvironment { get; private set; }
internal DaprEnvironment? DaprEnvironment { get; private set; }
internal HashSet<Type> Middlewares { get; private set; }
internal Action<IHealthChecksBuilder>? ConfigureHealthCheckBuilder { get; private set; }

/// <summary>
/// Sets the <see cref="Microsoft.AspNetCore.Mvc.MvcOptions.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes"/> property for all contollers.
Expand Down Expand Up @@ -68,4 +70,10 @@ public StartupOptions AddMiddleware<TMiddleware>()
Middlewares.Add(typeof(TMiddleware));
return this;
}

public StartupOptions ConfigureHealthChecks(Action<IHealthChecksBuilder> configure)
{
ConfigureHealthCheckBuilder = configure;
return this;
}
}
2 changes: 1 addition & 1 deletion src/Wemogy.AspNet/Wemogy.AspNet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<PackageReference Include="RestSharp" Version="107.3.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="6.4.0" />
<PackageReference Include="Wemogy.Core" Version="3.1.1" />
<PackageReference Include="Wemogy.Core" Version="3.1.2" />
<PackageReference Include="Dapr.AspNetCore" Version="1.10.0" />
</ItemGroup>
</Project>
Loading