Skip to content
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
3 changes: 3 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.2" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.15.1" />
<PackageVersion Include="Serilog" Version="4.3.0" />
<PackageVersion Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageVersion Include="Serilog.Extensions.Logging" Version="9.0.2" />
<PackageVersion Include="Serilog.Sinks.Console" Version="6.1.1" />
<PackageVersion Include="BenchmarkDotNet" Version="0.15.8" />
<PackageVersion Include="Bogus" Version="35.6.5" />
<PackageVersion Include="NBomber" Version="6.1.2" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.11" />
<PackageVersion Include="coverlet.collector" Version="10.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="Serilog.Sinks.OpenTelemetry" Version="4.2.0" />
<PackageVersion Include="Testcontainers.MsSql" Version="4.9.0" />
<PackageVersion Include="xunit" Version="2.9.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
Expand Down
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@
### Prerequisites

- [.NET 9 SDK](https://dotnet.microsoft.com/download/dotnet/9.0)
- [Docker](https://www.docker.com/) (for Prometheus and Grafana)
- [Docker](https://www.docker.com/) (for Prometheus, Loki, and Grafana)

### Start Prometheus and Grafana
### Start the Observability Stack

The API exports metrics via OpenTelemetry's OTLP exporter directly to Prometheus. Before starting the API, bring up the observability stack with Docker Compose:
The API exports metrics via OpenTelemetry's OTLP exporter to Prometheus and ships structured logs via Serilog's OpenTelemetry sink to Loki. Before starting the API, bring up the observability stack with Docker Compose:

```bash
docker-compose up -d
Expand All @@ -58,21 +58,28 @@ This starts:
| Service | URL |
| --- | --- |
| Prometheus | http://localhost:5431 |
| Loki | http://localhost:3100 |
| Grafana | http://localhost:3000 |

Prometheus is configured with `--web.enable-otlp-receiver` so it accepts OTLP pushes from the API. The scrape interval is set to 15 s globally (10 s for the Prometheus self-scrape job).
- **Prometheus** is configured with `--web.enable-otlp-receiver` so it accepts OTLP pushes from the API. The scrape interval is set to 15 s globally (10 s for the Prometheus self-scrape job).
- **Loki** listens on port `3100` and accepts logs over the OTLP HTTP endpoint (`/otlp`). Logs are stored on the local filesystem.

### Start the API

```bash
dotnet run --project TournamentAPI
```

The API will push metrics to Prometheus automatically once running.
The API will push metrics to Prometheus and logs to Loki automatically once running.

### Grafana

Open `http://localhost:3000`, log in with the default credentials (`admin` / `admin`), and add Prometheus (`http://prometheus:9090`) as a data source to build dashboards from the collected metrics.
Open `http://localhost:3000`, log in with the default credentials (`admin` / `admin`), and add the following data sources to build dashboards:

| Data source | URL |
| --- | --- |
| Prometheus | `http://prometheus:9090` |
| Loki | `http://loki:3100` |

---

Expand Down
113 changes: 112 additions & 1 deletion TournamentAPI.Benchmarks/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@
"resolved": "2.3.0",
"contentHash": "2ap/rYmjtzCOT8hxrnEW/QeiOt+paD8iRrIcdKX0cxVwWLFa1e+JDBNeECakmccXrSFeBQuu5AV8SNkipFMMMw=="
},
"Google.Protobuf": {
"type": "Transitive",
"resolved": "3.30.1",
"contentHash": "HeWXDQBabQn/sCGicbeLJ0HMunknfC4FdLrOQOsaMJHcpqx3HVIpyyJqTrqJlWnza870twhOb+rBcaTiC/TlNA=="
},
"GreenDonut": {
"type": "Transitive",
"resolved": "15.1.15",
Expand Down Expand Up @@ -138,6 +143,28 @@
"resolved": "15.1.15",
"contentHash": "zKYnY8NMsZvQSY3Mdwtkivu4K/uMCSSjAB9YDiXV54mDwehnYVlFzMTX9MzB34+f8menzcZ8Ko/tqzlhKSt8Sw=="
},
"Grpc.Core.Api": {
"type": "Transitive",
"resolved": "2.70.0",
"contentHash": "66UotvWcSIq41oiQhLWcQACyKPM4umxXNiht5DQTLZJfNwEswWOcS7Z0xIEHyNIBE7ZpjotH22bEjTkvhPxmVw=="
},
"Grpc.Net.Client": {
"type": "Transitive",
"resolved": "2.70.0",
"contentHash": "xNv0FFCVJa5S1beUtye82WFCxKThuE1jbN8DO1x1Rj8VSIWXLBUmfSID5a1fGzsU2R/EMfwPoWclJ2RMfQuGXw==",
"dependencies": {
"Grpc.Net.Common": "2.70.0",
"Microsoft.Extensions.Logging.Abstractions": "6.0.0"
}
},
"Grpc.Net.Common": {
"type": "Transitive",
"resolved": "2.70.0",
"contentHash": "rBdEUMyCwa+iB8mqC6JKyPbj3SBHHkReJj/yy/XKJI63GcG6w9DJMMGTVcYHqq4Ci2W4m0HT4jt2pFfFscar8g==",
"dependencies": {
"Grpc.Core.Api": "2.70.0"
}
},
"HotChocolate": {
"type": "Transitive",
"resolved": "15.1.15",
Expand Down Expand Up @@ -1168,6 +1195,52 @@
"resolved": "3.2.4",
"contentHash": "I5qFifWw/gaTQT52MhzjZpkm/JPlfjSeO/DTZJjO7+hTKI+0aGRgOgZ3NN6D96dDuuqbIAZSeA5RimtHjqrA2A=="
},
"Serilog.Extensions.Hosting": {
"type": "Transitive",
"resolved": "9.0.0",
"contentHash": "u2TRxuxbjvTAldQn7uaAwePkWxTHIqlgjelekBtilAGL5sYyF3+65NWctN4UrwwGLsDC7c3Vz3HnOlu+PcoxXg==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0",
"Microsoft.Extensions.Hosting.Abstractions": "9.0.0",
"Microsoft.Extensions.Logging.Abstractions": "9.0.0",
"Serilog": "4.2.0",
"Serilog.Extensions.Logging": "9.0.0"
}
},
"Serilog.Formatting.Compact": {
"type": "Transitive",
"resolved": "3.0.0",
"contentHash": "wQsv14w9cqlfB5FX2MZpNsTawckN4a8dryuNGbebB/3Nh1pXnROHZov3swtu3Nj5oNG7Ba+xdu7Et/ulAUPanQ==",
"dependencies": {
"Serilog": "4.0.0"
}
},
"Serilog.Settings.Configuration": {
"type": "Transitive",
"resolved": "9.0.0",
"contentHash": "4/Et4Cqwa+F88l5SeFeNZ4c4Z6dEAIKbu3MaQb2Zz9F/g27T5a3wvfMcmCOaAiACjfUb4A6wrlTVfyYUZk3RRQ==",
"dependencies": {
"Microsoft.Extensions.Configuration.Binder": "9.0.0",
"Microsoft.Extensions.DependencyModel": "9.0.0",
"Serilog": "4.2.0"
}
},
"Serilog.Sinks.Debug": {
"type": "Transitive",
"resolved": "3.0.0",
"contentHash": "4BzXcdrgRX7wde9PmHuYd9U6YqycCC28hhpKonK7hx0wb19eiuRj16fPcPSVp0o/Y1ipJuNLYQ00R3q2Zs8FDA==",
"dependencies": {
"Serilog": "4.0.0"
}
},
"Serilog.Sinks.File": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "lxjg89Y8gJMmFxVkbZ+qDgjl+T4yC5F7WSLTvA+5q0R04tfKVLRL/EHpYoJ/MEQd2EeCKDuylBIVnAYMotmh2A==",
"dependencies": {
"Serilog": "4.0.0"
}
},
"System.Buffers": {
"type": "Transitive",
"resolved": "4.6.0",
Expand Down Expand Up @@ -1361,7 +1434,9 @@
"OpenTelemetry.Instrumentation.AspNetCore": "[1.15.2, )",
"OpenTelemetry.Instrumentation.Http": "[1.15.1, )",
"Serilog": "[4.3.0, )",
"Serilog.Sinks.Console": "[6.1.1, )"
"Serilog.AspNetCore": "[9.0.0, )",
"Serilog.Sinks.Console": "[6.1.1, )",
"Serilog.Sinks.OpenTelemetry": "[4.2.0, )"
}
},
"tournamentapi.shared": {
Expand Down Expand Up @@ -1557,6 +1632,31 @@
"resolved": "4.3.0",
"contentHash": "+cDryFR0GRhsGOnZSKwaDzRRl4MupvJ42FhCE4zhQRVanX0Jpg6WuCBk59OVhVDPmab1bB+nRykAnykYELA9qQ=="
},
"Serilog.AspNetCore": {
"type": "CentralTransitive",
"requested": "[9.0.0, )",
"resolved": "9.0.0",
"contentHash": "JslDajPlBsn3Pww1554flJFTqROvK9zz9jONNQgn0D8Lx2Trw8L0A8/n6zEQK1DAZWXrJwiVLw8cnTR3YFuYsg==",
"dependencies": {
"Serilog": "4.2.0",
"Serilog.Extensions.Hosting": "9.0.0",
"Serilog.Formatting.Compact": "3.0.0",
"Serilog.Settings.Configuration": "9.0.0",
"Serilog.Sinks.Console": "6.0.0",
"Serilog.Sinks.Debug": "3.0.0",
"Serilog.Sinks.File": "6.0.0"
}
},
"Serilog.Extensions.Logging": {
"type": "CentralTransitive",
"requested": "[9.0.2, )",
"resolved": "9.0.0",
"contentHash": "NwSSYqPJeKNzl5AuXVHpGbr6PkZJFlNa14CdIebVjK3k/76kYj/mz5kiTRNVSsSaxM8kAIa1kpy/qyT9E4npRQ==",
"dependencies": {
"Microsoft.Extensions.Logging": "9.0.0",
"Serilog": "4.2.0"
}
},
"Serilog.Sinks.Console": {
"type": "CentralTransitive",
"requested": "[6.1.1, )",
Expand All @@ -1565,6 +1665,17 @@
"dependencies": {
"Serilog": "4.0.0"
}
},
"Serilog.Sinks.OpenTelemetry": {
"type": "CentralTransitive",
"requested": "[4.2.0, )",
"resolved": "4.2.0",
"contentHash": "PzMCyE5G19tjr5IZEi5qg+4UU5QrxBEoBEMu/hhYybTrGKXqUDiSGWKZNUDBgelaVKqLADlsmlJVyKce5SyPrg==",
"dependencies": {
"Google.Protobuf": "3.30.1",
"Grpc.Net.Client": "2.70.0",
"Serilog": "4.2.0"
}
}
}
}
Expand Down
113 changes: 112 additions & 1 deletion TournamentAPI.IntegrationTests/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@
"Docker.DotNet.Enhanced": "3.130.0"
}
},
"Google.Protobuf": {
"type": "Transitive",
"resolved": "3.30.1",
"contentHash": "HeWXDQBabQn/sCGicbeLJ0HMunknfC4FdLrOQOsaMJHcpqx3HVIpyyJqTrqJlWnza870twhOb+rBcaTiC/TlNA=="
},
"GreenDonut": {
"type": "Transitive",
"resolved": "15.1.15",
Expand Down Expand Up @@ -168,6 +173,28 @@
"resolved": "15.1.15",
"contentHash": "zKYnY8NMsZvQSY3Mdwtkivu4K/uMCSSjAB9YDiXV54mDwehnYVlFzMTX9MzB34+f8menzcZ8Ko/tqzlhKSt8Sw=="
},
"Grpc.Core.Api": {
"type": "Transitive",
"resolved": "2.70.0",
"contentHash": "66UotvWcSIq41oiQhLWcQACyKPM4umxXNiht5DQTLZJfNwEswWOcS7Z0xIEHyNIBE7ZpjotH22bEjTkvhPxmVw=="
},
"Grpc.Net.Client": {
"type": "Transitive",
"resolved": "2.70.0",
"contentHash": "xNv0FFCVJa5S1beUtye82WFCxKThuE1jbN8DO1x1Rj8VSIWXLBUmfSID5a1fGzsU2R/EMfwPoWclJ2RMfQuGXw==",
"dependencies": {
"Grpc.Net.Common": "2.70.0",
"Microsoft.Extensions.Logging.Abstractions": "6.0.0"
}
},
"Grpc.Net.Common": {
"type": "Transitive",
"resolved": "2.70.0",
"contentHash": "rBdEUMyCwa+iB8mqC6JKyPbj3SBHHkReJj/yy/XKJI63GcG6w9DJMMGTVcYHqq4Ci2W4m0HT4jt2pFfFscar8g==",
"dependencies": {
"Grpc.Core.Api": "2.70.0"
}
},
"HotChocolate": {
"type": "Transitive",
"resolved": "15.1.15",
Expand Down Expand Up @@ -1146,6 +1173,52 @@
"OpenTelemetry.Api": "1.15.3"
}
},
"Serilog.Extensions.Hosting": {
"type": "Transitive",
"resolved": "9.0.0",
"contentHash": "u2TRxuxbjvTAldQn7uaAwePkWxTHIqlgjelekBtilAGL5sYyF3+65NWctN4UrwwGLsDC7c3Vz3HnOlu+PcoxXg==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0",
"Microsoft.Extensions.Hosting.Abstractions": "9.0.0",
"Microsoft.Extensions.Logging.Abstractions": "9.0.0",
"Serilog": "4.2.0",
"Serilog.Extensions.Logging": "9.0.0"
}
},
"Serilog.Formatting.Compact": {
"type": "Transitive",
"resolved": "3.0.0",
"contentHash": "wQsv14w9cqlfB5FX2MZpNsTawckN4a8dryuNGbebB/3Nh1pXnROHZov3swtu3Nj5oNG7Ba+xdu7Et/ulAUPanQ==",
"dependencies": {
"Serilog": "4.0.0"
}
},
"Serilog.Settings.Configuration": {
"type": "Transitive",
"resolved": "9.0.0",
"contentHash": "4/Et4Cqwa+F88l5SeFeNZ4c4Z6dEAIKbu3MaQb2Zz9F/g27T5a3wvfMcmCOaAiACjfUb4A6wrlTVfyYUZk3RRQ==",
"dependencies": {
"Microsoft.Extensions.Configuration.Binder": "9.0.0",
"Microsoft.Extensions.DependencyModel": "9.0.0",
"Serilog": "4.2.0"
}
},
"Serilog.Sinks.Debug": {
"type": "Transitive",
"resolved": "3.0.0",
"contentHash": "4BzXcdrgRX7wde9PmHuYd9U6YqycCC28hhpKonK7hx0wb19eiuRj16fPcPSVp0o/Y1ipJuNLYQ00R3q2Zs8FDA==",
"dependencies": {
"Serilog": "4.0.0"
}
},
"Serilog.Sinks.File": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "lxjg89Y8gJMmFxVkbZ+qDgjl+T4yC5F7WSLTvA+5q0R04tfKVLRL/EHpYoJ/MEQd2EeCKDuylBIVnAYMotmh2A==",
"dependencies": {
"Serilog": "4.0.0"
}
},
"SharpZipLib": {
"type": "Transitive",
"resolved": "1.4.2",
Expand Down Expand Up @@ -1377,7 +1450,9 @@
"OpenTelemetry.Instrumentation.AspNetCore": "[1.15.2, )",
"OpenTelemetry.Instrumentation.Http": "[1.15.1, )",
"Serilog": "[4.3.0, )",
"Serilog.Sinks.Console": "[6.1.1, )"
"Serilog.AspNetCore": "[9.0.0, )",
"Serilog.Sinks.Console": "[6.1.1, )",
"Serilog.Sinks.OpenTelemetry": "[4.2.0, )"
}
},
"tournamentapi.shared": {
Expand Down Expand Up @@ -1573,6 +1648,31 @@
"resolved": "4.3.0",
"contentHash": "+cDryFR0GRhsGOnZSKwaDzRRl4MupvJ42FhCE4zhQRVanX0Jpg6WuCBk59OVhVDPmab1bB+nRykAnykYELA9qQ=="
},
"Serilog.AspNetCore": {
"type": "CentralTransitive",
"requested": "[9.0.0, )",
"resolved": "9.0.0",
"contentHash": "JslDajPlBsn3Pww1554flJFTqROvK9zz9jONNQgn0D8Lx2Trw8L0A8/n6zEQK1DAZWXrJwiVLw8cnTR3YFuYsg==",
"dependencies": {
"Serilog": "4.2.0",
"Serilog.Extensions.Hosting": "9.0.0",
"Serilog.Formatting.Compact": "3.0.0",
"Serilog.Settings.Configuration": "9.0.0",
"Serilog.Sinks.Console": "6.0.0",
"Serilog.Sinks.Debug": "3.0.0",
"Serilog.Sinks.File": "6.0.0"
}
},
"Serilog.Extensions.Logging": {
"type": "CentralTransitive",
"requested": "[9.0.2, )",
"resolved": "9.0.0",
"contentHash": "NwSSYqPJeKNzl5AuXVHpGbr6PkZJFlNa14CdIebVjK3k/76kYj/mz5kiTRNVSsSaxM8kAIa1kpy/qyT9E4npRQ==",
"dependencies": {
"Microsoft.Extensions.Logging": "9.0.0",
"Serilog": "4.2.0"
}
},
"Serilog.Sinks.Console": {
"type": "CentralTransitive",
"requested": "[6.1.1, )",
Expand All @@ -1581,6 +1681,17 @@
"dependencies": {
"Serilog": "4.0.0"
}
},
"Serilog.Sinks.OpenTelemetry": {
"type": "CentralTransitive",
"requested": "[4.2.0, )",
"resolved": "4.2.0",
"contentHash": "PzMCyE5G19tjr5IZEi5qg+4UU5QrxBEoBEMu/hhYybTrGKXqUDiSGWKZNUDBgelaVKqLADlsmlJVyKce5SyPrg==",
"dependencies": {
"Google.Protobuf": "3.30.1",
"Grpc.Net.Client": "2.70.0",
"Serilog": "4.2.0"
}
}
}
}
Expand Down
Loading
Loading