Skip to content

Commit

Permalink
Merge pull request #30 from MadL1me/release/8.2.0
Browse files Browse the repository at this point in the history
Add observability - tracing and prometheus collector
  • Loading branch information
MadL1me authored May 31, 2024
2 parents 1568602 + 1b7278b commit df4a3ec
Show file tree
Hide file tree
Showing 19 changed files with 341 additions and 24 deletions.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
TEST_PROJ_NAME=MyProject
TEMPL_DOTNET_NAME=aspnext
NUGET_FILE=Aspnext.Template.8.1.0.nupkg
NUGET_FILE=Aspnext.Template.8.2.0.nupkg
NUGET_API_KEY=<YOUR_NUGET_API_KEY>
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[![Dotnet foundation](https://img.shields.io/badge/-.NET%20Template-blueviolet)](https://dotnetfoundation.org/)
![Version](https://img.shields.io/badge/version-8.1.0-blue)
[![Nuget package](https://img.shields.io/badge/Nuget%20-Package-red)](https://www.nuget.org/packages/Aspnext.Template/8.1.0)
![Version](https://img.shields.io/badge/version-8.2.0-blue)
[![Nuget package](https://img.shields.io/badge/Nuget%20-Package-red)](https://www.nuget.org/packages/Aspnext.Template/8.2.0)

# <img width="35" alt="Asset 1@2x" src="https://github.com/MadL1me/aspnet-awesome-templates/assets/46647517/e81a904e-6b5a-4d25-8ed4-5630d495b045"> AspNext

Expand All @@ -17,7 +17,7 @@ If you don't want to use it, you can start with __main__ template like this:
1. Install template:

```sh
dotnet new install Aspnext.Template::8.1.0
dotnet new install Aspnext.Template::8.2.0
```

2. Create template with dotnet new:
Expand Down
2 changes: 1 addition & 1 deletion src/template/Aspnext.Template.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<PackageType>Template</PackageType>
<PackageVersion>8.1.0</PackageVersion>
<PackageVersion>8.2.0</PackageVersion>
<PackageId>Aspnext.Template</PackageId>
<Title>ASP.NET 8 awesome SPA template</Title>
<Authors>Ilya Klimenko (MadL1me)</Authors>
Expand Down
8 changes: 4 additions & 4 deletions src/template/Template/.template.config/dotnetcli.host.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
{
"$schema": "http://json.schemastore.org/dotnetcli.host",
"symbolInfo": {
"AddSwaggerSupport": {
"longName": "swagger",
"shortName": "sw"
},
"AddDatabase": {
"longName": "database",
"shortName": "db"
Expand All @@ -13,6 +9,10 @@
"longName": "examples",
"shortName": "e"
},
"AddObservability": {
"longName": "observability",
"shortName": "o"
},
"AddZitadelAuth": {
"longName": "auth"
}
Expand Down
17 changes: 17 additions & 0 deletions src/template/Template/.template.config/template.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@
"datatype": "bool",
"defaultValue": "true"
},
"AddObservability": {
"type": "parameter",
"description": "Adds OpenTelemetry tracing and metrics support with docker compose",
"datatype": "bool",
"defaultValue": "true"
},
"UsePostgreSql": {
"type": "computed",
"value": "(AddDatabase == \"pgsql\")"
Expand All @@ -67,6 +73,17 @@
"infra/docker-compose-zitadel.yaml",
"src/Infrastructure/AspnextTemplate.Infrastructure.Zitadel/**"
]
},
{
"condition": "(!AddObservability)",
"exclude": [
"infra/docker-compose-grafana.yaml",
"infra/docker-compose-jaeger.yaml",
"infra/docker-compose-prometheus.yaml",
"infra/prometheus.yaml",
"src/Infrastructure/AspnextTemplate.Infrastructure.Observability",
"src/AspnextTemplate.Domain/Observability/**"
]
}
]
}
Expand Down
18 changes: 18 additions & 0 deletions src/template/Template/AspnextTemplate.sln
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".config", ".config", "{DF2D
infra\docker-compose-postgres.yaml = infra\docker-compose-postgres.yaml
infra\docker-compose-app.yaml = infra\docker-compose-app.yaml
infra\docker-compose-zitadel.yaml = infra\docker-compose-zitadel.yaml
infra\docker-compose-prometheus.yaml = infra\docker-compose-prometheus.yaml
infra\docker-compose-jaeger.yaml = infra\docker-compose-jaeger.yaml
infra\prometheus.yml = infra\prometheus.yml
infra\docker-compose-grafana.yaml = infra\docker-compose-grafana.yaml
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspnextTemplate", "src\AspnextTemplate.Api\AspnextTemplate.Api.csproj", "{94618EED-2AEA-44A5-AC03-9A3B9AC0DBC4}"
Expand All @@ -25,6 +29,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Infrastructure", "Infrastru
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspnextTemplate.Infrastructure.Zitadel", "src\Infrastructure\AspnextTemplate.Infrastructure.Zitadel\AspnextTemplate.Infrastructure.Zitadel.csproj", "{A142CFBD-9B0E-4B10-8A16-7404886A3DC3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspnextTemplate.Domain", "src\AspnextTemplate.Domain\AspnextTemplate.Domain.csproj", "{61833C02-5273-4A5D-A7CC-1DD695D35475}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspnextTemplate.Infrastructure.Observability", "src\Infrastructure\AspnextTemplate.Infrastructure.Observability\AspnextTemplate.Infrastructure.Observability.csproj", "{2480637A-E46B-4338-995C-18574CD4118A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -42,10 +50,20 @@ Global
{A142CFBD-9B0E-4B10-8A16-7404886A3DC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A142CFBD-9B0E-4B10-8A16-7404886A3DC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A142CFBD-9B0E-4B10-8A16-7404886A3DC3}.Release|Any CPU.Build.0 = Release|Any CPU
{61833C02-5273-4A5D-A7CC-1DD695D35475}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{61833C02-5273-4A5D-A7CC-1DD695D35475}.Debug|Any CPU.Build.0 = Debug|Any CPU
{61833C02-5273-4A5D-A7CC-1DD695D35475}.Release|Any CPU.ActiveCfg = Release|Any CPU
{61833C02-5273-4A5D-A7CC-1DD695D35475}.Release|Any CPU.Build.0 = Release|Any CPU
{2480637A-E46B-4338-995C-18574CD4118A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2480637A-E46B-4338-995C-18574CD4118A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2480637A-E46B-4338-995C-18574CD4118A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2480637A-E46B-4338-995C-18574CD4118A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{94618EED-2AEA-44A5-AC03-9A3B9AC0DBC4} = {D3BD39A8-2835-4B2A-8E74-A3E59B387D36}
{3E0E9C11-D112-41DF-8029-57F996829E87} = {D3BD39A8-2835-4B2A-8E74-A3E59B387D36}
{A142CFBD-9B0E-4B10-8A16-7404886A3DC3} = {3E0E9C11-D112-41DF-8029-57F996829E87}
{61833C02-5273-4A5D-A7CC-1DD695D35475} = {D3BD39A8-2835-4B2A-8E74-A3E59B387D36}
{2480637A-E46B-4338-995C-18574CD4118A} = {3E0E9C11-D112-41DF-8029-57F996829E87}
EndGlobalSection
EndGlobal
24 changes: 15 additions & 9 deletions src/template/Template/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,15 @@ DB_TASK = run_db
HOME := $(shell echo $$HOME)
PASSWORD := YOUR_PASSWORD # Replace with actual password

.PHONY: init init_frontend init_backend init_db init_certs run_backend $(DB_TASK) run_frontend run_auth run
.PHONY: init init_frontend init_backend init_db init_certs run_backend $(DB_TASK) run_frontend run_auth run \
run_tracing run_metrics run_grafana

init: init_frontend init_backend init_certs init_db

init_backend:
@echo "Initialize the back-end project"
cd AspnextTemplate && dotnet restore && docker compose build

//#if (UsePostgreSql)
init_db:
@echo "Initialize the database"
cd infra && docker compose --file docker-compose-postgres.yaml up -d
//#endif

init_certs:
@echo "Generate self-signed certificates"
dotnet dev-certs https -ep $(HOME)/.aspnet/https/AspnextTemplate.pfx -p $(PASSWORD)
Expand All @@ -32,13 +27,24 @@ run_backend: $(DB_TASK)
//#if (UsePostgreSql)
run_db:
@echo "Run the database"
cd infra && docker compose --file docker-compose-postgres.yaml up -d
docker compose --file infra/docker-compose-postgres.yaml up -d
//#endif

//#if (AddZitadelAuth)
run_auth:
@echo "Run Zitadel identity provider"
cd infra && docker compose --file docker-compose-zitadel.yaml up -d
docker compose --file infra/docker-compose-zitadel.yaml up -d
//#endif

//#if (AddObservability)
run_tracing:
docker compose --file infra/docker-compose-jaeger.yaml up -d

run_metrics:
docker compose --file infra/docker-compose-prometheus.yaml up -d

run_grafana:
docker compose --file infra/docker-compose-grafana.yaml up -d
//#endif

run: run_backend
Expand Down
21 changes: 21 additions & 0 deletions src/template/Template/infra/docker-compose-grafana.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
version: '3.7'

services:
grafana:
image: grafana/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
restart: always
ports:
- 3000:3000
volumes:
- grafana-data:/var/lib/grafana
networks:
- localconnect

volumes:
grafana-data: {}

networks:
localconnect:

44 changes: 44 additions & 0 deletions src/template/Template/infra/docker-compose-jaeger.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
version: '3.7'

# To run a specific version of Jaeger, use environment variable, e.g.:
# JAEGER_VERSION=1.52 docker compose up

services:
jaeger:
image: jaegertracing/all-in-one:${JAEGER_VERSION:-latest}
ports:
- "16686:16686"
- "4318:4318"
- 5775:5775/udp
- 6831:6831/udp
- 6832:6832/udp
- 5778:5778
- 16686:16686
- 14250:14250
- 14268:14268
- 14269:14269
- 4317:4317
- 4318:4318
- 9411:9411
environment:
- LOG_LEVEL=debug
networks:
- jaeger-example
hotrod:
image: jaegertracing/example-hotrod:${JAEGER_VERSION:-latest}
# To run the latest trunk build, find the tag at Docker Hub and use the line below
# https://hub.docker.com/r/jaegertracing/example-hotrod-snapshot/tags
#image: jaegertracing/example-hotrod-snapshot:0ab8f2fcb12ff0d10830c1ee3bb52b745522db6c
ports:
- "8085:8085"
- "8083:8083"
command: ["all"]
environment:
- OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4318
networks:
- jaeger-example
depends_on:
- jaeger

networks:
jaeger-example:
16 changes: 16 additions & 0 deletions src/template/Template/infra/docker-compose-prometheus.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version: '3.7'

services:
prometheus:
image: prom/prometheus
restart: always
ports:
- 9090:9090
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
networks:
- localconnect

networks:
localconnect:

15 changes: 15 additions & 0 deletions src/template/Template/infra/prometheus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
global:
scrape_interval: 10s # By default, scrape targets every 5 seconds.

# Attach these labels to any time series or alerts when communicating with
# external systems (federation, remote storage, Alertmanager).
# external_labels:
# monitor: 'nats-openrmf-server'

# A scrape configuration containing exactly one endpoint to scrape:
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: 'localhost-read-prometheus'
# metrics_path defaults to '/metrics'
static_configs:
- targets: ['host.docker.internal:5214']
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
Expand All @@ -19,8 +19,13 @@
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />
</ItemGroup>
<!--#endif -->
<ItemGroup>
<ProjectReference Include="..\Infrastructure\AspnextTemplate.Infrastructure.Zitadel\AspnextTemplate.Infrastructure.Zitadel.csproj" />
</ItemGroup>
<!--#if (AddZitadelAuth)-->
<ProjectReference Include="..\Infrastructure\AspnextTemplate.Infrastructure.Zitadel\AspnextTemplate.Infrastructure.Zitadel.csproj" />
<!--#endif -->
<!--#if (AddObservability)-->
<ProjectReference Include="..\Infrastructure\AspnextTemplate.Infrastructure.Observability\AspnextTemplate.Infrastructure.Observability.csproj" />
<!--#endif -->
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
using System.Security.Claims;
#endif
using Microsoft.AspNetCore.Mvc;
#if (AddObservability)
using AspnextTemplate.Domain.Observability;
using OpenTelemetry.Trace;
#endif

namespace AspnextTemplate.Api.Controllers;

Expand All @@ -23,10 +27,21 @@ public class ExampleController : ControllerBase
private static readonly string[] Names = { "John", "Albert", "Mark " };

private readonly ILogger<ExampleController> _logger;
#if (AddObservability)
private readonly Tracer _tracer;
private readonly IMetricsProvider _metricsProvider;
#endif

public ExampleController(ILogger<ExampleController> logger)
// In this controller we're using service provider just for convinience and
// ease of template development
// In real controllers, inject interfaces directly.
public ExampleController(IServiceProvider serviceProvider)
{
_logger = logger;
_logger = serviceProvider.GetService<ILogger<ExampleController>>() ?? throw new ArgumentNullException();
#if (AddObservability)
_tracer = serviceProvider.GetService<Tracer>() ?? throw new ArgumentNullException();
_metricsProvider = serviceProvider.GetService<IMetricsProvider>() ?? throw new ArgumentNullException();
#endif
}

// Example of synchronous Http.Get request pipeline with users/{userId} route
Expand Down Expand Up @@ -55,16 +70,21 @@ public async Task<IActionResult> UpdateUser([FromBody] ExampleUserDto userDto) /
// custom status code returns with data
return StatusCode(StatusCodes.Status200OK, new { Value1 = true, Value2 = "Yay!"});
}

#if (AddZitadelAuth)
#region Zitadel

// Endpoint without auth
[HttpPost("non-authorize")]
public object NonAuthorize() => Result();

// Goes to Introspect endpoint of Zitadel to validate token
[HttpPost("introspect/valid")]
[Authorize(AuthenticationSchemes = AuthConstants.Schema)]
public object IntrospectValidToken() => Result();

// Authorization by custom PolicyNam
// Authorization by custom PolicyName
// For this example, Role should be exact name to be passed
[HttpPost("introspect/requires-role")]
[Authorize(Policy = AuthConstants.SomePolicyName)]
public object IntrospectRequiresRole() => Result();
Expand All @@ -81,5 +101,32 @@ public async Task<IActionResult> UpdateUser([FromBody] ExampleUserDto userDto) /
IsInUserRole = User.IsInRole("User"),
InChargeRole = User.IsInRole("charge"),
};

#endregion
#endif

#if (AddObservability)
// Showcase of tracing and metrics in action
[HttpPost("observe")]
public object ObserveAndTrace()
{
using var span = _tracer.StartActiveSpan("Observe-Parent");

using (var child1 = _tracer.StartActiveSpan("child1"))
{
child1.SetAttribute("test", "some value");
_logger.LogInformation("child1 trace information");
}

using (var child2 = _tracer.StartActiveSpan("child2"))
{
child2.SetAttribute("test", "another value");
_logger.LogInformation("child2 trace information");
}

_metricsProvider.IncTestMetric(12345);

return Ok();
}
#endif
}
Loading

0 comments on commit df4a3ec

Please sign in to comment.