diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e227713..ef2037c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -16,7 +16,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: 6.0.x + dotnet-version: 9.x - name: Restore nuget packages cache uses: actions/cache@v4 diff --git a/backend/src/Application/Application.csproj b/backend/src/Application/Application.csproj index 0a23e61..1533cb9 100644 --- a/backend/src/Application/Application.csproj +++ b/backend/src/Application/Application.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable @@ -19,6 +19,7 @@ + diff --git a/backend/src/Application/DependencyInjection.cs b/backend/src/Application/DependencyInjection.cs index 9d12958..741895d 100644 --- a/backend/src/Application/DependencyInjection.cs +++ b/backend/src/Application/DependencyInjection.cs @@ -235,7 +235,8 @@ private static IServiceCollection AddHotChocolate(this IServiceCollection servic .AddType() .AddFiltering() .AddSorting() - .AddProjections(); + .AddProjections() + .AddInstrumentation(); var executingAssembly = Assembly.GetExecutingAssembly(); diff --git a/backend/src/WebAPI/DependencyInjection.cs b/backend/src/WebAPI/DependencyInjection.cs index 1cfef3f..98cade2 100644 --- a/backend/src/WebAPI/DependencyInjection.cs +++ b/backend/src/WebAPI/DependencyInjection.cs @@ -1,4 +1,10 @@ using Application.Options; +using OpenTelemetry.Metrics; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; +using Serilog; +using WebAPI.Options; +using WebAPI.Telemetry; namespace WebAPI; @@ -6,8 +12,8 @@ public static class DependencyInjection { public static IServiceCollection AddWebApiServices(this IServiceCollection services, IConfiguration configuration) { + services.AddApplicationMonitoring(configuration); services.AddHealthChecks(configuration); - return services; } @@ -27,4 +33,56 @@ private static IServiceCollection AddHealthChecks(this IServiceCollection servic return services; } + + private static IServiceCollection AddApplicationMonitoring(this IServiceCollection services, + IConfiguration configuration) + { + var productInfo = configuration + .GetSection(ProductInfo.SectionName) + .Get() ?? new ProductInfo(); + + services.AddSerilog(config => + { + config.ReadFrom.Configuration(configuration); + config.WriteTo.Console(); + config.WriteTo.OpenTelemetry(options => + { + options.ResourceAttributes = new Dictionary + { + { Attributes.ServiceName, productInfo.Name }, + { Attributes.ServiceVersion, productInfo.Version }, + { Attributes.ServiceInstanceId, Program.InstanceId } + }; + }); + }); + + services.AddOpenTelemetry() + .ConfigureResource(resource => + { + resource.AddService( + productInfo.Name, + serviceVersion: productInfo.Version, + serviceInstanceId: Program.InstanceId.ToString() + ); + }) + .WithTracing(tracing => + { + tracing.AddSource(productInfo.Name) + .AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation() + .AddHotChocolateInstrumentation() + .AddOtlpExporter(); + }) + .WithMetrics(metrics => + { + metrics.AddMeter(productInfo.Name) + .AddRuntimeInstrumentation() + .AddProcessInstrumentation() + .AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation() + .AddOtlpExporter(); + }); + + return services; + } } \ No newline at end of file diff --git a/backend/src/WebAPI/Options/ProductInfo.cs b/backend/src/WebAPI/Options/ProductInfo.cs new file mode 100644 index 0000000..dc20f5f --- /dev/null +++ b/backend/src/WebAPI/Options/ProductInfo.cs @@ -0,0 +1,12 @@ +using System.Reflection; + +namespace WebAPI.Options +{ + public class ProductInfo + { + public const string SectionName = "ProductInfo"; + + public string Name { get; set; } = Assembly.GetExecutingAssembly().GetName().Name!; + public string Version { get; set; } = Assembly.GetExecutingAssembly().GetName().Version?.ToString()!; + } +} \ No newline at end of file diff --git a/backend/src/WebAPI/Program.cs b/backend/src/WebAPI/Program.cs index 0ab4cf6..25e7996 100644 --- a/backend/src/WebAPI/Program.cs +++ b/backend/src/WebAPI/Program.cs @@ -11,12 +11,8 @@ { var builder = WebApplication.CreateBuilder(args); - builder.Host.UseSerilog((context, configuration) => - configuration.ReadFrom.Configuration(context.Configuration) - ); - - builder.Services.AddApplicationServices(builder.Configuration); builder.Services.AddWebApiServices(builder.Configuration); + builder.Services.AddApplicationServices(builder.Configuration); var app = builder.Build(); @@ -28,7 +24,9 @@ app.MapEndpoints(); await app.InitializeDatabase(); - + + Log.Information("Application initialized successfully"); + app.Run(); } catch (Exception e) @@ -38,4 +36,9 @@ finally { Log.CloseAndFlush(); +} + +public partial class Program +{ + public static readonly Guid InstanceId = Guid.NewGuid(); } \ No newline at end of file diff --git a/backend/src/WebAPI/Telemetry/Attributes.cs b/backend/src/WebAPI/Telemetry/Attributes.cs new file mode 100644 index 0000000..435b629 --- /dev/null +++ b/backend/src/WebAPI/Telemetry/Attributes.cs @@ -0,0 +1,9 @@ +namespace WebAPI.Telemetry +{ + public static class Attributes + { + public const string ServiceName = "service.name"; + public const string ServiceVersion = "service.version"; + public const string ServiceInstanceId = "service.instance.id"; + } +} \ No newline at end of file diff --git a/backend/src/WebAPI/WebAPI.csproj b/backend/src/WebAPI/WebAPI.csproj index a5142d7..2d4cafd 100644 --- a/backend/src/WebAPI/WebAPI.csproj +++ b/backend/src/WebAPI/WebAPI.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable Linux @@ -20,10 +20,16 @@ - - - - + + + + + + + + + + diff --git a/backend/src/WebAPI/appsettings.Development.json b/backend/src/WebAPI/appsettings.Development.json index e385d05..7bb01ba 100644 --- a/backend/src/WebAPI/appsettings.Development.json +++ b/backend/src/WebAPI/appsettings.Development.json @@ -18,7 +18,6 @@ "MinimumLevel": { "Default": "Information", "Override": { - "Microsoft.AspNetCore": "Warning", "MongoDB.Command": "Debug" } } diff --git a/backend/src/WebAPI/appsettings.json b/backend/src/WebAPI/appsettings.json index cb475ca..030e82e 100644 --- a/backend/src/WebAPI/appsettings.json +++ b/backend/src/WebAPI/appsettings.json @@ -1,5 +1,8 @@ { "AllowedHosts": "*", + "ProductInfo": { + "Name": "PTSDetect API" + }, "IdentityOptions": { "RequireUniqueEmail": true, "RequiredPasswordLength": 8 @@ -45,20 +48,10 @@ "MinimumLevel": { "Default": "Information", "Override": { - "Microsoft.AspNetCore": "Warning" + "Microsoft": "Warning", + "System": "Warning" } }, - "WriteTo": [ - { - "Name": "Console" - }, - { - "Name": "File", - "Args": { - "path": "logs/log.txt" - } - } - ], "Enrich": [ "FromLogContext" ] diff --git a/frontend/.dockerignore b/frontend/.dockerignore index b512c09..b9744a5 100644 --- a/frontend/.dockerignore +++ b/frontend/.dockerignore @@ -1 +1,6 @@ -node_modules \ No newline at end of file +node_modules +dist +.env +.env.example +.vscode +.git \ No newline at end of file diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 2324a78..2005fbf 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,16 +1,25 @@ +# Use a specific node version FROM node:18-alpine + +# Build arguments ARG VITE_GRAPHQL_URI +# Set working directory WORKDIR /app -COPY package.json ./ +# Copy package.json and lock files +COPY package.json pnpm-lock.yaml ./ -RUN npm install +# Install dependencies using pnpm (as indicated by pnpm-lock.yaml) +RUN npm install -g pnpm && pnpm install --frozen-lockfile +# Copy the rest of the application code COPY . . -RUN npm run build +# Build the application +RUN pnpm run build +# Expose the application port EXPOSE 5173 -CMD [ "npm", "run", "preview" ] \ No newline at end of file +CMD [ "pnpm", "preview" ] \ No newline at end of file