feat(ops): OpenTelemetry traces + metrics (RECOMMENDATIONS #5)
CI / backend (pull_request) Successful in 53s
CI / frontend (pull_request) Successful in 13s
CI / format (pull_request) Successful in 51s
CI / db-tests (pull_request) Successful in 54s
Security / secrets (pull_request) Successful in 4s
Security / dependencies (pull_request) Successful in 1m1s
CI / backend (pull_request) Successful in 53s
CI / frontend (pull_request) Successful in 13s
CI / format (pull_request) Successful in 51s
CI / db-tests (pull_request) Successful in 54s
Security / secrets (pull_request) Successful in 4s
Security / dependencies (pull_request) Successful in 1m1s
ASP.NET Core, outbound HttpClient (Gmail/Ollama), and Npgsql instrumentation with an OTLP exporter that activates ONLY when Otel:Endpoint / OTEL_EXPORTER_OTLP_ENDPOINT is configured — zero overhead otherwise. Logs remain on Serilog. Adds a compose 'observability' profile running grafana/otel-lgtm (Grafana+Tempo+Prometheus+Loki in one container, loopback :3000) with a documented one-line enablement. 55/55 tests; vuln + format gates clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -67,6 +67,8 @@ services:
|
|||||||
Ai__Mode: ${AI_MODE:-Disabled}
|
Ai__Mode: ${AI_MODE:-Disabled}
|
||||||
# Points at the compose 'ollama' service when the ai profile is up; harmless otherwise.
|
# Points at the compose 'ollama' service when the ai profile is up; harmless otherwise.
|
||||||
Ai__OllamaBaseUrl: ${OLLAMA_BASE_URL:-http://ollama:11434}
|
Ai__OllamaBaseUrl: ${OLLAMA_BASE_URL:-http://ollama:11434}
|
||||||
|
# OTLP export activates only when set (e.g. http://lgtm:4317 with the observability profile).
|
||||||
|
OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_ENDPOINT:-}
|
||||||
# Dev mode shows the dev banner and caps the initial sync. Set DEV_MODE=true
|
# Dev mode shows the dev banner and caps the initial sync. Set DEV_MODE=true
|
||||||
# and MAX_MESSAGES=1000 in deploy/.env to exercise it in this Docker setup.
|
# and MAX_MESSAGES=1000 in deploy/.env to exercise it in this Docker setup.
|
||||||
App__DevMode: ${DEV_MODE:-false}
|
App__DevMode: ${DEV_MODE:-false}
|
||||||
@@ -109,6 +111,16 @@ services:
|
|||||||
# count: all
|
# count: all
|
||||||
# capabilities: [gpu]
|
# capabilities: [gpu]
|
||||||
|
|
||||||
|
# Observability (RECOMMENDATIONS #5): all-in-one Grafana+Tempo+Prometheus+Loki.
|
||||||
|
# Enable with: docker compose --profile observability up -d
|
||||||
|
# then set OTEL_ENDPOINT=http://lgtm:4317 in deploy/.env and restart the api.
|
||||||
|
# Grafana UI: http://localhost:3000 (admin/admin on first run).
|
||||||
|
lgtm:
|
||||||
|
image: grafana/otel-lgtm
|
||||||
|
profiles: ["observability"]
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:3000:3000"
|
||||||
|
|
||||||
# Optional reverse proxy. Enable with: docker compose --profile proxy up
|
# Optional reverse proxy. Enable with: docker compose --profile proxy up
|
||||||
nginx:
|
nginx:
|
||||||
image: nginx:alpine
|
image: nginx:alpine
|
||||||
|
|||||||
@@ -15,6 +15,11 @@
|
|||||||
<PackageReference Include="Asp.Versioning.Mvc" Version="8.1.0" />
|
<PackageReference Include="Asp.Versioning.Mvc" Version="8.1.0" />
|
||||||
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" />
|
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" />
|
||||||
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
|
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
|
||||||
|
<PackageReference Include="Npgsql.OpenTelemetry" Version="10.0.3" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.16.0" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.16.0" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.16.0" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.16.0" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
|
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ using Microsoft.AspNetCore.HttpOverrides;
|
|||||||
using Microsoft.AspNetCore.RateLimiting;
|
using Microsoft.AspNetCore.RateLimiting;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Npgsql;
|
||||||
|
using OpenTelemetry.Metrics;
|
||||||
|
using OpenTelemetry.Resources;
|
||||||
|
using OpenTelemetry.Trace;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
@@ -122,6 +126,28 @@ builder.Services.AddAuthentication(options =>
|
|||||||
|
|
||||||
builder.Services.AddAuthorization();
|
builder.Services.AddAuthorization();
|
||||||
|
|
||||||
|
// RECOMMENDATIONS #5: OpenTelemetry traces + metrics (ASP.NET, outbound HTTP, Npgsql).
|
||||||
|
// The OTLP exporter only activates when Otel:Endpoint (or the standard
|
||||||
|
// OTEL_EXPORTER_OTLP_ENDPOINT env var) is configured — zero overhead otherwise.
|
||||||
|
// Logs stay on Serilog. Pair with the compose "observability" profile (grafana/otel-lgtm).
|
||||||
|
var otlpEndpoint = builder.Configuration["Otel:Endpoint"]
|
||||||
|
?? Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT");
|
||||||
|
if (!string.IsNullOrWhiteSpace(otlpEndpoint))
|
||||||
|
{
|
||||||
|
builder.Services.AddOpenTelemetry()
|
||||||
|
.ConfigureResource(r => r.AddService("inboxintel-api"))
|
||||||
|
.WithTracing(t => t
|
||||||
|
.AddAspNetCoreInstrumentation()
|
||||||
|
.AddHttpClientInstrumentation()
|
||||||
|
.AddNpgsql()
|
||||||
|
.AddOtlpExporter(o => o.Endpoint = new Uri(otlpEndpoint)))
|
||||||
|
.WithMetrics(m => m
|
||||||
|
.AddAspNetCoreInstrumentation()
|
||||||
|
.AddHttpClientInstrumentation()
|
||||||
|
.AddNpgsqlInstrumentation()
|
||||||
|
.AddOtlpExporter(o => o.Endpoint = new Uri(otlpEndpoint)));
|
||||||
|
}
|
||||||
|
|
||||||
builder.Services.AddApiVersioning(o =>
|
builder.Services.AddApiVersioning(o =>
|
||||||
{
|
{
|
||||||
o.DefaultApiVersion = new ApiVersion(1, 0);
|
o.DefaultApiVersion = new ApiVersion(1, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user