Skip to content

Commit

Permalink
Merge pull request #175 from hamed-shirbandi/feat-174-add-metrics-usi…
Browse files Browse the repository at this point in the history
…ng-prometheus

Add metrics using prometheus
  • Loading branch information
hamed-shirbandi authored Oct 24, 2023
2 parents 3379065 + 63d203e commit 9596062
Show file tree
Hide file tree
Showing 42 changed files with 257 additions and 100 deletions.
23 changes: 9 additions & 14 deletions .github/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,12 @@


<p align="left">

[![build and test](https://github.com/hamed-shirbandi/TaskoMask/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/hamed-shirbandi/TaskoMask/actions/workflows/ci.yml)
[![Mutation testing](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fhamed-shirbandi%2FTaskoMask%2Fmaster)](https://dashboard.stryker-mutator.io/reports/github.com/hamed-shirbandi/TaskoMask/master)
<a href="https://github.com/hamed-shirbandi/TaskoMask/issues">
<img alt="GitHub issues" src="https://img.shields.io/github/issues/hamed-shirbandi/TaskoMask">
</a>
<a href="http://taskomask.ir">
<img src="https://img.shields.io/website?url=http://taskomask.ir">
</a>
<a href="https://github.com/hamed-shirbandi/TaskoMask/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/hamed-shirbandi/TaskoMask">
</a>
<a href="https://github.com/hamed-shirbandi/TaskoMask/graphs/contributors">
<img src="https://img.shields.io/github/contributors/hamed-shirbandi/TaskoMask">
</a>
<a href="https://github.com/hamed-shirbandi/TaskoMask/issues"><img alt="GitHub issues" src="https://img.shields.io/github/issues/hamed-shirbandi/TaskoMask"></a>
<a href="http://taskomask.ir"> <img src="https://img.shields.io/website?url=http://taskomask.ir"></a>
<a href="https://github.com/hamed-shirbandi/TaskoMask/blob/master/LICENSE"><img src="https://img.shields.io/github/license/hamed-shirbandi/TaskoMask"></a>
<a href="https://github.com/hamed-shirbandi/TaskoMask/graphs/contributors"><img src="https://img.shields.io/github/contributors/hamed-shirbandi/TaskoMask"></a>
</p>

[TaskoMask](https://github.com/hamed-shirbandi/TaskoMask/wiki/User-Guide-Documentation) is an open-source task management system built on the .Net framework. The primary objective of this project is to demonstrate the practical application of advanced software development concepts such as DDD (Domain-Driven Design), TDD (Test-Driven Development), BDD (Behavior-Driven Development), and Microservices.
Expand Down Expand Up @@ -72,7 +63,7 @@ Here is a comprehensive list of the patterns, principles, approaches, and method
- [Service discovery](https://microservices.io/patterns/3rd-party-registration.html) : Kubernetes - Consul
- [Circuit Breaker](https://microservices.io/patterns/reliability/circuit-breaker.html) : Polly
- [Log aggregation](https://microservices.io/patterns/observability/application-logging.html) : Serilog - Seq
- [Application metrics](https://microservices.io/patterns/observability/application-metrics.html) : Opentelemetry-dotnet - Prometheus
- [Application metrics](https://microservices.io/patterns/observability/application-metrics.html) : prometheus-net
- [Distributed tracing](https://microservices.io/patterns/observability/distributed-tracing.html) : Opentelemetry-dotnet - Jaeger
- [Health check API](https://microservices.io/patterns/observability/health-check-api.html) : AspNetCore.HealthChecks
- [IDP](https://en.wikipedia.org/wiki/Identity_provider) : DuendeSoftware IdentityServer
Expand Down Expand Up @@ -159,6 +150,8 @@ Here is a comprehensive list of the tools and technologies we have employed to i
- ASP.NET Identity
- MongoDB
- Redis
- Entity Framework
- SQL
- [Ocelot](https://ocelot.readthedocs.io/) : .NET core API Gateway
- [DuendeSoftware IdentityServer](https://docs.duendesoftware.com/identityserver/v6) : OpenID Connect and OAuth 2.x framework for ASP.NET Core
- [MassTransit](https://masstransit-project.com/) : a framework on top of message transports such as RabbitMQ
Expand All @@ -176,6 +169,7 @@ Here is a comprehensive list of the tools and technologies we have employed to i
- [Swagger](https://www.nuget.org/packages/Swashbuckle.AspNetCore) : expose Swagger JSON endpoints from APIs
- [Serilog](https://serilog.net/) : provides diagnostic logging
- [AspNetCore.HealthChecks](https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks) : ASP.NET Core Health Check
- [prometheus-net](https://github.com/prometheus-net/prometheus-net) : .NET library to instrument your code with Prometheus metrics
- [MvcPagedList.Core](https://www.nuget.org/packages/MvcPagedList.Core/) : easily paging in ASP.NET Core MVC
- [EasyCaching](https://github.com/dotnetcore/EasyCaching) : caching library
- [stryker-net](https://github.com/stryker-mutator/stryker-net): Mutation testing for .NET
Expand Down Expand Up @@ -257,6 +251,7 @@ This project is authored by [Hamed Shirbandi](https://github.com/hamed-shirbandi


* ### Oct, 2023
- [x] Instrument with Prometheus metrics
- [x] Implement build system using nuke
- [x] Implement Mutation Testing using Stryker
- [x] Integrate CI with nuke and stryker
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Prometheus;
using TaskoMask.BuildingBlocks.Web.MVC.Configuration.Metric;
using TaskoMask.BuildingBlocks.Web.MVC.Services.AuthenticatedUser;

namespace TaskoMask.BuildingBlocks.Web.MVC.Configuration
Expand All @@ -17,7 +20,7 @@ public static class MvcConfiguration
/// <summary>
///
/// </summary>
public static void AddMvcPreConfigured(this IServiceCollection services)
public static void AddMvcPreConfigured(this IServiceCollection services, IConfiguration configuration)
{
if (services == null) throw new ArgumentNullException(nameof(services));

Expand All @@ -28,14 +31,16 @@ public static void AddMvcPreConfigured(this IServiceCollection services)
services.AddAuthenticatedUserService();

services.AddWebServerOptions();

services.AddMetrics(configuration);
}



/// <summary>
///
/// </summary>
public static void UseMvcPreConfigured(this IApplicationBuilder app , IWebHostEnvironment env)
public static void UseMvcPreConfigured(this IApplicationBuilder app , IWebHostEnvironment env, IConfiguration configuration)
{
if (app == null) throw new ArgumentNullException(nameof(app));

Expand All @@ -51,6 +56,8 @@ public static void UseMvcPreConfigured(this IApplicationBuilder app , IWebHostEn

app.UseRouting();

app.UseMetrics(configuration);

app.UseAuthentication();

app.UseAuthorization();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using TaskoMask.BuildingBlocks.Web.MVC.Configuration.Metric;
using TaskoMask.BuildingBlocks.Web.MVC.Services.AuthenticatedUser;

namespace TaskoMask.BuildingBlocks.Web.MVC.Configuration
Expand All @@ -16,7 +18,7 @@ public static class RazorPagesConfiguration
/// <summary>
///
/// </summary>
public static void AddRazorPagesPreConfigured(this IServiceCollection services)
public static void AddRazorPagesPreConfigured(this IServiceCollection services, IConfiguration configuration)
{
if (services == null) throw new ArgumentNullException(nameof(services));

Expand All @@ -27,22 +29,28 @@ public static void AddRazorPagesPreConfigured(this IServiceCollection services)
services.AddHttpContextAccessor();

services.AddAuthenticatedUserService();

services.AddMetrics(configuration);
}



/// <summary>
///
/// </summary>
public static void UseRazorPagesPreConfigured(this IApplicationBuilder app, IWebHostEnvironment env)
public static void UseRazorPagesPreConfigured(this IApplicationBuilder app, IWebHostEnvironment env, IConfiguration configuration)
{
if (app == null) throw new ArgumentNullException(nameof(app));

if (env.IsDevelopment())
app.UseDeveloperExceptionPage();

app.UseStaticFiles();

app.UseRouting();

app.UseMetrics(configuration);

app.UseAuthorization();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using MonoApi.Services.Afrr.Activations.Api.Helpers;
using TaskoMask.BuildingBlocks.Web.MVC.Configuration.Captcha;
using TaskoMask.BuildingBlocks.Web.MVC.Configuration.Jwt;
using TaskoMask.BuildingBlocks.Web.MVC.Configuration.Metric;
using TaskoMask.BuildingBlocks.Web.MVC.Configuration.Swagger;
using TaskoMask.BuildingBlocks.Web.MVC.Services.AuthenticatedUser;

Expand Down Expand Up @@ -41,14 +43,16 @@ public static void AddWebApiPreConfigured(this IServiceCollection services, ICon
services.AddJwtAuthentication(configuration);

services.AddCors();

services.AddMetrics(configuration);
}



/// <summary>
///
/// </summary>
public static void UseWebApiPreConfigured(this IApplicationBuilder app, IWebHostEnvironment env)
public static void UseWebApiPreConfigured(this IApplicationBuilder app, IWebHostEnvironment env,IConfiguration configuration)
{
if (app == null) throw new ArgumentNullException(nameof(app));

Expand All @@ -69,6 +73,8 @@ public static void UseWebApiPreConfigured(this IApplicationBuilder app, IWebHost
.AllowAnyMethod()
.AllowAnyHeader());

app.UseMetrics(configuration);

app.UseAuthentication();

app.UseAuthorization();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Prometheus;

namespace TaskoMask.BuildingBlocks.Web.MVC.Configuration.Metric
{
public static class MetricConfiguration
{
public static void AddMetrics(this IServiceCollection services, IConfiguration configuration)
{
var metricOptions = configuration.GetSection("Metric").Get<MetricOptions>();

//It starts the metrics exporter as a background service using a stand alone kestrel
if (metricOptions.StandAloneKestrelServerEnabled)
{
services.AddMetricServer(options =>
{
options.Port = metricOptions.Port;
options.Url = metricOptions.Url;
options.Hostname = metricOptions.Hostname;
});
}

//Inject IMetricFactory to be used in application objects instead of coupling their implementation with Metrics
services.AddSingleton<IMetricFactory>(Metrics.DefaultFactory);
}

public static void UseMetrics(this IApplicationBuilder app, IConfiguration configuration)
{
var metricOptions = configuration.GetSection("Metric").Get<MetricOptions>();

//If kestrel server is not enabled then use current app server
if (!metricOptions.StandAloneKestrelServerEnabled)
app.UseMetricServer(metricOptions.Port, metricOptions.Url);

if (metricOptions.HttpMetricsEnabled)
{
app.UseHttpMetrics(options =>
{
options.AddCustomLabel("host", context => context.Request.Host.Host);
});
}

if (metricOptions.SuppressDefaultMetrics)
Metrics.SuppressDefaultMetrics();
}
}
}
35 changes: 35 additions & 0 deletions src/1-BuildingBlocks/Web.MVC/Configuration/Metric/MetricOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace TaskoMask.BuildingBlocks.Web.MVC.Configuration.Metric
{
public class MetricOptions
{
/// <summary>
/// Set it to true if you want to run the metrics on a stand alone kestrel server
/// </summary>
public bool StandAloneKestrelServerEnabled { get; set; }
public ushort Port { get; set; }
public string Url { get; set; }

/// <summary>
/// It is used when StandAloneKestrelServerEnabled is true.
/// Will listen for requests using this hostname. "+" indicates listen on all hostnames.
/// By setting this to "localhost", you can easily prevent access from remote systems.-
/// </summary>
public string Hostname { get; set; }

/// <summary>
/// Set it to true if you want to use the built-in metrics for http requests.
/// The metrics are:
/// Number of HTTP requests in progress.
/// Total number of received HTTP requests.
/// Duration of HTTP requests.
/// </summary>
public bool HttpMetricsEnabled { get; set; }


/// <summary>
/// The library enables various default metrics and integrations by default.
/// If these default metrics are not desirable, set SuppressDefaultMetrics to true.
/// </summary>
public bool SuppressDefaultMetrics { get; set; }
}
}
1 change: 1 addition & 0 deletions src/1-BuildingBlocks/Web.MVC/Web.MVC.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<PackageReference Include="Serilog.Sinks.Seq" Version="5.1.1" />
<PackageReference Include="Grpc.AspNetCore" Version="2.49.0" />
<PackageReference Include="Grpc.Net.Client" Version="2.49.0" />
<PackageReference Include="prometheus-net.AspNetCore" Version="8.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Infrastructure\Infrastructure.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using TaskoMask.Services.Boards.Read.Api.Infrastructure.DI;
using Microsoft.AspNetCore.Builder;
using TaskoMask.BuildingBlocks.Web.Grpc.Configuration;
using Microsoft.Extensions.Configuration;

namespace TaskoMask.Services.Boards.Read.Api.Configuration
{
Expand Down Expand Up @@ -35,12 +36,12 @@ public static WebApplication ConfigureServices(this WebApplicationBuilder builde
/// <summary>
///
/// </summary>
public static WebApplication ConfigurePipeline(this WebApplication app)
public static WebApplication ConfigurePipeline(this WebApplication app, IConfiguration configuration)
{

app.UseSerilogRequestLogging();

app.UseWebApiPreConfigured(app.Environment);
app.UseWebApiPreConfigured(app.Environment, configuration);

app.Services.InitialDatabase();

Expand Down
2 changes: 1 addition & 1 deletion src/2-Services/Boards/Api/Boards.Read.Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@

var builder = WebApplication.CreateBuilder(args);

var app = builder.ConfigureServices().ConfigurePipeline();
var app = builder.ConfigureServices().ConfigurePipeline(builder.Configuration);

app.Run();
10 changes: 9 additions & 1 deletion src/2-Services/Boards/Api/Boards.Read.Api/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@
"UserName": "guest",
"Password": "guest"
},
"Metric": {
"StandAloneKestrelServerEnabled": false,
"Port": 5025,
"Url": "/metrics",
"Hostname": "+",
"HttpMetricsEnabled": true,
"SuppressDefaultMetrics": false
},
"Caching": {
"CacheTimeInMinutes": 60,
"Enabled": true
Expand All @@ -30,7 +38,7 @@
"IncludeXmlComments": "TaskoMask.Services.Boards.Read.Api.xml,TaskoMask.BuildingBlocks.Contracts.xml"
},
"Url": {
"Owner-Read-Service": "https://localhost:5021",
"Owner-Read-Service": "https://localhost:5021"
},
"AllowedHosts": "*",
"Serilog": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using TaskoMask.Services.Boards.Write.Api.Infrastructure.CrossCutting.DI;
using TaskoMask.Services.Boards.Write.Api.Infrastructure.Data.DbContext;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;

namespace TaskoMask.Services.Boards.Write.Api.Configuration
{
Expand All @@ -30,12 +31,12 @@ public static WebApplication ConfigureServices(this WebApplicationBuilder builde
/// <summary>
///
/// </summary>
public static WebApplication ConfigurePipeline(this WebApplication app)
public static WebApplication ConfigurePipeline(this WebApplication app, IConfiguration configuration)
{

app.UseSerilogRequestLogging();

app.UseWebApiPreConfigured(app.Environment);
app.UseWebApiPreConfigured(app.Environment, configuration);

app.Services.InitialDatabasesAndSeedEssentialData();

Expand Down
2 changes: 1 addition & 1 deletion src/2-Services/Boards/Api/Boards.Write.Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

var builder = WebApplication.CreateBuilder(args);

var app = builder.ConfigureServices().ConfigurePipeline();
var app = builder.ConfigureServices().ConfigurePipeline(builder.Configuration);

app.Run();
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"dotnetRunMessages": true,
"applicationUrl": "https://localhost:5023;http://localhost:5022"
},
"Docker (1)": {
"Docker": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/",
Expand Down
Loading

0 comments on commit 9596062

Please sign in to comment.