From 42f5e7e148cbab4fdcf42d185b59e567d894d96a Mon Sep 17 00:00:00 2001 From: James Gunn Date: Mon, 4 Dec 2023 19:57:27 +0000 Subject: [PATCH] Centralise logging config over all apps (#940) --- TeachingRecordSystem/Directory.Packages.props | 9 ++- TeachingRecordSystem/TeachingRecordSystem.sln | 17 +++++- .../src/TeachingRecordSystem.Api/Dockerfile | 2 +- ...gnoreSuppressedExceptionsLogEventFilter.cs | 17 ------ .../Infrastructure/Logging/LogSuppressions.cs | 43 -------------- .../WebApplicationBuilderExtensions.cs | 59 ++----------------- .../src/TeachingRecordSystem.Api/Program.cs | 3 +- .../TeachingRecordSystem.Api.csproj | 6 +- .../appsettings.Development.json | 1 - .../appsettings.Testing.json | 1 - .../TeachingRecordSystem.Core/SentryErrors.cs | 54 ----------------- .../HostApplicationBuilderExtensions.cs | 32 ++++++++++ .../TeachingRecordSystem.Hosting.csproj | 17 ++++++ .../TeachingRecordSystem.SupportUi/Dockerfile | 2 +- .../WebApplicationBuilderExtensions.cs | 24 ++++++++ .../TeachingRecordSystem.SupportUi/Program.cs | 3 + .../TeachingRecordSystem.SupportUi.csproj | 4 ++ .../appsettings.Development.json | 11 ++-- .../appsettings.Production.json | 10 ++++ .../appsettings.Testing.json | 8 +++ .../appsettings.json | 13 ++-- .../TeachingRecordSystem.Worker/Dockerfile | 2 +- .../HostApplicationBuilderExtensions.cs | 28 +++++++++ .../TeachingRecordSystem.Worker/Program.cs | 6 ++ .../Properties/launchSettings.json | 10 ++++ .../TeachingRecordSystem.Worker.csproj | 34 ++++++++++- .../appsettings.Development.json | 2 + .../appsettings.Production.json | 10 ++++ .../appsettings.json | 8 +++ terraform/aks/app.tf | 21 ++++--- 30 files changed, 256 insertions(+), 201 deletions(-) delete mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Logging/IgnoreSuppressedExceptionsLogEventFilter.cs delete mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Logging/LogSuppressions.cs delete mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Core/SentryErrors.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Hosting/HostApplicationBuilderExtensions.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Hosting/TeachingRecordSystem.Hosting.csproj create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Infrastructure/Logging/WebApplicationBuilderExtensions.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.Production.json create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Worker/Infrastructure/Logging/HostApplicationBuilderExtensions.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Worker/Properties/launchSettings.json create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Worker/appsettings.Development.json create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Worker/appsettings.Production.json create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Worker/appsettings.json diff --git a/TeachingRecordSystem/Directory.Packages.props b/TeachingRecordSystem/Directory.Packages.props index 599612d7b..ff9f0bbb5 100644 --- a/TeachingRecordSystem/Directory.Packages.props +++ b/TeachingRecordSystem/Directory.Packages.props @@ -29,6 +29,7 @@ + @@ -64,11 +65,15 @@ + + + - + + @@ -79,4 +84,4 @@ - + \ No newline at end of file diff --git a/TeachingRecordSystem/TeachingRecordSystem.sln b/TeachingRecordSystem/TeachingRecordSystem.sln index d395bfddf..77b8f5d1b 100644 --- a/TeachingRecordSystem/TeachingRecordSystem.sln +++ b/TeachingRecordSystem/TeachingRecordSystem.sln @@ -36,7 +36,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TeachingRecordSystem.Suppor EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FormFlow", "lib\formflow\src\FormFlow\FormFlow.csproj", "{DA3F55CA-6B95-4A85-A3D6-2997C3149A63}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeachingRecordSystem.Worker", "src\TeachingRecordSystem.Worker\TeachingRecordSystem.Worker.csproj", "{E7D4BCFD-E610-41E2-B209-0BE13799C7A8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TeachingRecordSystem.Worker", "src\TeachingRecordSystem.Worker\TeachingRecordSystem.Worker.csproj", "{E7D4BCFD-E610-41E2-B209-0BE13799C7A8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeachingRecordSystem.Hosting", "src\TeachingRecordSystem.Hosting\TeachingRecordSystem.Hosting.csproj", "{BD13EB34-437A-45FE-AE0C-7DAD1E9681C0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -192,6 +194,18 @@ Global {E7D4BCFD-E610-41E2-B209-0BE13799C7A8}.Release|x64.Build.0 = Release|Any CPU {E7D4BCFD-E610-41E2-B209-0BE13799C7A8}.Release|x86.ActiveCfg = Release|Any CPU {E7D4BCFD-E610-41E2-B209-0BE13799C7A8}.Release|x86.Build.0 = Release|Any CPU + {BD13EB34-437A-45FE-AE0C-7DAD1E9681C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BD13EB34-437A-45FE-AE0C-7DAD1E9681C0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BD13EB34-437A-45FE-AE0C-7DAD1E9681C0}.Debug|x64.ActiveCfg = Debug|Any CPU + {BD13EB34-437A-45FE-AE0C-7DAD1E9681C0}.Debug|x64.Build.0 = Debug|Any CPU + {BD13EB34-437A-45FE-AE0C-7DAD1E9681C0}.Debug|x86.ActiveCfg = Debug|Any CPU + {BD13EB34-437A-45FE-AE0C-7DAD1E9681C0}.Debug|x86.Build.0 = Debug|Any CPU + {BD13EB34-437A-45FE-AE0C-7DAD1E9681C0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BD13EB34-437A-45FE-AE0C-7DAD1E9681C0}.Release|Any CPU.Build.0 = Release|Any CPU + {BD13EB34-437A-45FE-AE0C-7DAD1E9681C0}.Release|x64.ActiveCfg = Release|Any CPU + {BD13EB34-437A-45FE-AE0C-7DAD1E9681C0}.Release|x64.Build.0 = Release|Any CPU + {BD13EB34-437A-45FE-AE0C-7DAD1E9681C0}.Release|x86.ActiveCfg = Release|Any CPU + {BD13EB34-437A-45FE-AE0C-7DAD1E9681C0}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -209,6 +223,7 @@ Global {407EB5A5-8B4F-4F7D-80BA-E39AB6AD013C} = {91DCFC76-6636-4AC1-B81C-7F8AE1F22116} {DA3F55CA-6B95-4A85-A3D6-2997C3149A63} = {837E2941-F1CC-41EF-A652-B605101B2E84} {E7D4BCFD-E610-41E2-B209-0BE13799C7A8} = {837E2941-F1CC-41EF-A652-B605101B2E84} + {BD13EB34-437A-45FE-AE0C-7DAD1E9681C0} = {837E2941-F1CC-41EF-A652-B605101B2E84} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {61D239F9-888B-4D01-84BC-9276C92383EA} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Dockerfile b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Dockerfile index d52534276..138eae791 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Dockerfile +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Dockerfile @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.18 ARG GIT_SHA -ENV GitSha ${GIT_SHA} +ENV SENTRY_RELEASE ${GIT_SHA} ENV ASPNETCORE_HTTP_PORTS 80 COPY src/TeachingRecordSystem.Api/bin/Release/net8.0/publish/ App/ COPY src/TeachingRecordSystem.Cli/bin/Release/net8.0/publish/ TrsCli/ diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Logging/IgnoreSuppressedExceptionsLogEventFilter.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Logging/IgnoreSuppressedExceptionsLogEventFilter.cs deleted file mode 100644 index 87c48e9c6..000000000 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Logging/IgnoreSuppressedExceptionsLogEventFilter.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Serilog.Core; -using Serilog.Events; - -namespace TeachingRecordSystem.Api.Infrastructure.Logging; - -public class IgnoreSuppressedExceptionsLogEventFilter : ILogEventFilter -{ - public bool IsEnabled(LogEvent logEvent) - { - if (logEvent.Exception is not null && LogSuppressions.ShouldIgnoreException(logEvent.Exception)) - { - return false; - } - - return true; - } -} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Logging/LogSuppressions.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Logging/LogSuppressions.cs deleted file mode 100644 index 741cd0ee8..000000000 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Logging/LogSuppressions.cs +++ /dev/null @@ -1,43 +0,0 @@ -namespace TeachingRecordSystem.Api.Infrastructure.Logging; - -public static class LogSuppressions -{ - private static readonly AsyncLocal>> _exceptionsToIgnore = new(); - - public static bool ShouldIgnoreException(Exception exception) => - _exceptionsToIgnore.Value is not null && _exceptionsToIgnore.Value.Any(f => f(exception)); - - public static IDisposable SuppressException() - where TException : Exception - { - return SuppressException(_ => true); - } - - public static IDisposable SuppressException(Func filter) - where TException : Exception - { - return SuppressException(ex => ex is TException typedException && filter(typedException)); - } - - public static IDisposable SuppressException(Predicate filter) - { - _exceptionsToIgnore.Value ??= new(); - _exceptionsToIgnore.Value.Add(filter); - return new SuppressExceptionScope(() => _exceptionsToIgnore.Value.Remove(filter)); - } - - private class SuppressExceptionScope : IDisposable - { - private readonly Action _onDispose; - - public SuppressExceptionScope(Action onDispose) - { - _onDispose = onDispose; - } - - public void Dispose() - { - _onDispose(); - } - } -} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Logging/WebApplicationBuilderExtensions.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Logging/WebApplicationBuilderExtensions.cs index 29904b236..635c52a1f 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Logging/WebApplicationBuilderExtensions.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Logging/WebApplicationBuilderExtensions.cs @@ -1,75 +1,28 @@ -using Microsoft.ApplicationInsights.Extensibility; -using Sentry.AspNetCore; using Sentry.Extensibility; using Serilog; -using Serilog.Formatting.Compact; using TeachingRecordSystem.Api.Infrastructure.ApplicationInsights; +using TeachingRecordSystem.Hosting; namespace TeachingRecordSystem.Api.Infrastructure.Logging; public static class WebApplicationBuilderExtensions { - public static WebApplicationBuilder ConfigureLogging(this WebApplicationBuilder builder, string? platformEnvironmentName) + public static WebApplicationBuilder ConfigureLogging(this WebApplicationBuilder builder) { if (builder.Environment.IsProduction()) { - builder.WebHost.UseSentry(options => - { - options.SetBeforeSend((Sentry.SentryEvent e) => - { - if (e.Exception is not null && !SentryErrors.ShouldReport(e.Exception)) - { - return null; - } - - return e; - }); - }); - - builder.Services.AddSingleton(); - - builder.Services.Configure(options => - { - if (!string.IsNullOrEmpty(platformEnvironmentName)) - { - options.Environment = platformEnvironmentName; - } - - var gitSha = builder.Configuration["GitSha"]; - if (!string.IsNullOrEmpty(gitSha)) - { - options.Release = gitSha; - } - }); + builder.WebHost.UseSentry(dsn: builder.Configuration.GetRequiredValue("Sentry:Dsn")); } + builder.Services.AddSingleton(); + builder.Services.AddApplicationInsightsTelemetry() .AddApplicationInsightsTelemetryProcessor(); // We want all logging to go through Serilog so that our filters are always applied builder.Logging.ClearProviders(); - builder.Host.UseSerilog((ctx, services, config) => - { - config - .ReadFrom.Configuration(ctx.Configuration) - .Filter.With(new IgnoreSuppressedExceptionsLogEventFilter()) - .WriteTo.ApplicationInsights(services.GetRequiredService(), TelemetryConverter.Traces) - .WriteTo.Sentry(o => - { - o.MinimumBreadcrumbLevel = Serilog.Events.LogEventLevel.Debug; - o.MinimumEventLevel = Serilog.Events.LogEventLevel.Error; - }); - - if (ctx.HostingEnvironment.IsProduction()) - { - config.WriteTo.Console(new CompactJsonFormatter()); - } - else - { - config.WriteTo.Console(); - } - }); + builder.Host.UseSerilog((ctx, services, config) => config.ConfigureSerilog(ctx.HostingEnvironment, ctx.Configuration, services)); return builder; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Program.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Program.cs index 4c0405494..e0ce04302 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Program.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Program.cs @@ -59,8 +59,7 @@ public static void Main(string[] args) builder.Configuration.AddJsonEnvironmentVariable("AppConfig"); } - var platformEnvironmentName = configuration["PlatformEnvironment"]; - builder.ConfigureLogging(platformEnvironmentName); + builder.ConfigureLogging(); string pgConnectionString = new NpgsqlConnectionStringBuilder(configuration.GetRequiredValue("ConnectionStrings:DefaultConnection")) { diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/TeachingRecordSystem.Api.csproj b/TeachingRecordSystem/src/TeachingRecordSystem.Api/TeachingRecordSystem.Api.csproj index e65485d14..484267469 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/TeachingRecordSystem.Api.csproj +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/TeachingRecordSystem.Api.csproj @@ -25,12 +25,7 @@ - - - - - @@ -50,6 +45,7 @@ + diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/appsettings.Development.json b/TeachingRecordSystem/src/TeachingRecordSystem.Api/appsettings.Development.json index 4cfae967d..37ba80495 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/appsettings.Development.json +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/appsettings.Development.json @@ -1,6 +1,5 @@ { "DetailedErrors": true, - "Platform": "Local", "Serilog": { "MinimumLevel": { "Default": "Information", diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/appsettings.Testing.json b/TeachingRecordSystem/src/TeachingRecordSystem.Api/appsettings.Testing.json index a32dd535b..2565e5456 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/appsettings.Testing.json +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/appsettings.Testing.json @@ -1,5 +1,4 @@ { - "Platform": "Local", "Serilog": { "MinimumLevel": { "Default": "Error", diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/SentryErrors.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/SentryErrors.cs deleted file mode 100644 index 98018c0fb..000000000 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Core/SentryErrors.cs +++ /dev/null @@ -1,54 +0,0 @@ -namespace TeachingRecordSystem.Core; - -public static class SentryErrors -{ - private static readonly AsyncLocal>> _exceptionsToSkip = new(); - - public static bool ShouldReport(Exception ex) => _exceptionsToSkip.Value is null || - !_exceptionsToSkip.Value.Any(f => f(ex)); - - public static ISuppressScope Suppress() - where TException : Exception - { - return Suppress(_ => true); - } - - public static ISuppressScope Suppress(Func filter) - where TException : Exception - { - return Suppress(ex => ex is TException typedException && filter(typedException)); - } - - public static ISuppressScope Suppress(Func filter) - { - _exceptionsToSkip.Value ??= new(); - _exceptionsToSkip.Value.Add(filter); - return new SuppressScope(filter, () => _exceptionsToSkip.Value.Remove(filter)); - } - - private class SuppressScope : ISuppressScope - { - private readonly Func _filter; - private readonly Action _onDispose; - - public SuppressScope(Func filter, Action onDispose) - { - _filter = filter; - _onDispose = onDispose; - } - - public Func ExceptionPredicate => _filter; - - public void Dispose() - { - _onDispose(); - } - - public bool IsExceptionSuppressed(Exception ex) => _filter(ex); - } - - public interface ISuppressScope : IDisposable - { - bool IsExceptionSuppressed(Exception ex); - } -} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Hosting/HostApplicationBuilderExtensions.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Hosting/HostApplicationBuilderExtensions.cs new file mode 100644 index 000000000..2eb175861 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Hosting/HostApplicationBuilderExtensions.cs @@ -0,0 +1,32 @@ +using Microsoft.ApplicationInsights.Extensibility; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Serilog; +using Serilog.Formatting.Compact; + +namespace TeachingRecordSystem.Hosting; + +public static class Extensions +{ + public static void ConfigureSerilog( + this LoggerConfiguration config, + IHostEnvironment environment, + IConfiguration configuration, + IServiceProvider services) + { + config + .ReadFrom.Configuration(configuration) + .WriteTo.ApplicationInsights(services.GetRequiredService(), TelemetryConverter.Traces) + .WriteTo.Sentry(o => o.InitializeSdk = false); + + if (environment.IsProduction()) + { + config.WriteTo.Console(new CompactJsonFormatter()); + } + else + { + config.WriteTo.Console(); + } + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Hosting/TeachingRecordSystem.Hosting.csproj b/TeachingRecordSystem/src/TeachingRecordSystem.Hosting/TeachingRecordSystem.Hosting.csproj new file mode 100644 index 000000000..56d3148a0 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Hosting/TeachingRecordSystem.Hosting.csproj @@ -0,0 +1,17 @@ + + + + net8.0 + + + + + + + + + + + + + diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Dockerfile b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Dockerfile index 221743d5b..333ca8682 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Dockerfile +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Dockerfile @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.18 ARG GIT_SHA -ENV GitSha ${GIT_SHA} +ENV SENTRY_RELEASE ${GIT_SHA} ENV ASPNETCORE_HTTP_PORTS 80 COPY src/TeachingRecordSystem.SupportUi/bin/Release/net8.0/publish/ App/ WORKDIR /App diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Infrastructure/Logging/WebApplicationBuilderExtensions.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Infrastructure/Logging/WebApplicationBuilderExtensions.cs new file mode 100644 index 000000000..779b97645 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Infrastructure/Logging/WebApplicationBuilderExtensions.cs @@ -0,0 +1,24 @@ +using Serilog; +using TeachingRecordSystem.Hosting; + +namespace TeachingRecordSystem.SupportUi.Infrastructure.Logging; + +public static class WebApplicationBuilderExtensions +{ + public static WebApplicationBuilder ConfigureLogging(this WebApplicationBuilder builder) + { + if (builder.Environment.IsProduction()) + { + builder.WebHost.UseSentry(dsn: builder.Configuration.GetRequiredValue("Sentry:Dsn")); + } + + builder.Services.AddApplicationInsightsTelemetry(); + + // We want all logging to go through Serilog so that our filters are always applied + builder.Logging.ClearProviders(); + + builder.Host.UseSerilog((ctx, services, config) => config.ConfigureSerilog(ctx.HostingEnvironment, ctx.Configuration, services)); + + return builder; + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Program.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Program.cs index a5454469b..2777546cb 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Program.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Program.cs @@ -20,6 +20,7 @@ using TeachingRecordSystem.SupportUi.Infrastructure.Conventions; using TeachingRecordSystem.SupportUi.Infrastructure.Filters; using TeachingRecordSystem.SupportUi.Infrastructure.FormFlow; +using TeachingRecordSystem.SupportUi.Infrastructure.Logging; using TeachingRecordSystem.SupportUi.Infrastructure.ModelBinding; using TeachingRecordSystem.SupportUi.Infrastructure.Redis; using TeachingRecordSystem.SupportUi.Infrastructure.Security; @@ -35,6 +36,8 @@ builder.Configuration.AddJsonEnvironmentVariable("AppConfig"); } +builder.ConfigureLogging(); + var pgConnectionString = builder.Configuration.GetRequiredValue("ConnectionStrings:DefaultConnection"); if (builder.Environment.IsProduction()) diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/TeachingRecordSystem.SupportUi.csproj b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/TeachingRecordSystem.SupportUi.csproj index e88bd56c3..9c77675cc 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/TeachingRecordSystem.SupportUi.csproj +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/TeachingRecordSystem.SupportUi.csproj @@ -15,16 +15,20 @@ + + + + diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.Development.json b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.Development.json index dec0a345d..58c8350fc 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.Development.json +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.Development.json @@ -1,10 +1,11 @@ { "DetailedErrors": true, - "Logging": { - "LogLevel": { + "Serilog": { + "MinimumLevel": { "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Override": { + "Microsoft.AspNetCore": "Warning" + } } - }, - "StorageConnectionString": "UseDevelopmentStorage=true" + } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.Production.json b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.Production.json new file mode 100644 index 000000000..641c71ae4 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.Production.json @@ -0,0 +1,10 @@ +{ + "Serilog": { + "MinimumLevel": { + "Default": "Error", + "Override": { + "TeachingRecordSystem.SupportUi": "Warning" + } + } + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.Testing.json b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.Testing.json index a533ade2f..2565e5456 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.Testing.json +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.Testing.json @@ -1,3 +1,11 @@ { + "Serilog": { + "MinimumLevel": { + "Default": "Error", + "Override": { + "Microsoft.AspNetCore": "Fatal" + } + } + }, "ConcurrentNameChangeWindowSeconds": 1 } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.json b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.json index fcc453b90..fc6d9069e 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.json +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.json @@ -1,9 +1,12 @@ { - "Logging": { - "LogLevel": { + "Serilog": { + "MinimumLevel": { "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } + "Override": { + "Microsoft.AspNetCore": "Warning" + } + }, + "Enrich": [ "FromLogContext" ] }, "AzureAd": { "Instance": "https://login.microsoftonline.com/", @@ -12,5 +15,5 @@ "SignedOutCallbackPath": "/signout-oidc" }, "AllowedHosts": "*", - "ConcurrentNameChangeWindowSeconds": 5 + "ConcurrentNameChangeWindowSeconds": 5 } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Worker/Dockerfile b/TeachingRecordSystem/src/TeachingRecordSystem.Worker/Dockerfile index ccd5f40ad..38873a380 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Worker/Dockerfile +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Worker/Dockerfile @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 FROM mcr.microsoft.com/dotnet/runtime:8.0-alpine3.18 ARG GIT_SHA -ENV GitSha ${GIT_SHA} +ENV SENTRY_RELEASE ${GIT_SHA} COPY src/TeachingRecordSystem.Worker/bin/Release/net8.0/publish/ App/ COPY src/TeachingRecordSystem.Cli/bin/Release/net8.0/publish/ TrsCli/ WORKDIR /App diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Worker/Infrastructure/Logging/HostApplicationBuilderExtensions.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Worker/Infrastructure/Logging/HostApplicationBuilderExtensions.cs new file mode 100644 index 000000000..7cf145a62 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Worker/Infrastructure/Logging/HostApplicationBuilderExtensions.cs @@ -0,0 +1,28 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Sentry; +using Serilog; +using TeachingRecordSystem.Hosting; + +namespace TeachingRecordSystem.Worker.Infrastructure.Logging; + +public static class HostApplicationBuilderExtensions +{ + public static HostApplicationBuilder ConfigureLogging(this HostApplicationBuilder builder) + { + if (builder.Environment.IsProduction()) + { + SentrySdk.Init(dsn: builder.Configuration.GetRequiredValue("Sentry:Dsn")); + } + + builder.Services.AddApplicationInsightsTelemetryWorkerService(); + + // We want all logging to go through Serilog so that our filters are always applied + builder.Logging.ClearProviders(); + + builder.Services.AddSerilog((services, config) => config.ConfigureSerilog(builder.Environment, builder.Configuration, services)); + + return builder; + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Worker/Program.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Worker/Program.cs index 3c60e9b70..480ddb0e9 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Worker/Program.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Worker/Program.cs @@ -1,6 +1,12 @@ +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using TeachingRecordSystem.Worker.Infrastructure.Logging; var builder = Host.CreateApplicationBuilder(args); +builder.ConfigureLogging(); + +builder.Services.Configure(o => o.BackgroundServiceExceptionBehavior = BackgroundServiceExceptionBehavior.Ignore); + var host = builder.Build(); await host.RunAsync(); diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Worker/Properties/launchSettings.json b/TeachingRecordSystem/src/TeachingRecordSystem.Worker/Properties/launchSettings.json new file mode 100644 index 000000000..0ef67d990 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Worker/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "profiles": { + "TeachingRecordSystem.Worker": { + "commandName": "Project", + "environmentVariables": { + "DOTNET_ENVIRONMENT": "Development" + } + } + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Worker/TeachingRecordSystem.Worker.csproj b/TeachingRecordSystem/src/TeachingRecordSystem.Worker/TeachingRecordSystem.Worker.csproj index eeffd0fb8..b1303e050 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Worker/TeachingRecordSystem.Worker.csproj +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Worker/TeachingRecordSystem.Worker.csproj @@ -7,7 +7,39 @@ - + + + + + + + + PreserveNewest + true + PreserveNewest + + + PreserveNewest + true + PreserveNewest + + + PreserveNewest + true + PreserveNewest + + + + + + + + + + + + + diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Worker/appsettings.Development.json b/TeachingRecordSystem/src/TeachingRecordSystem.Worker/appsettings.Development.json new file mode 100644 index 000000000..2c63c0851 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Worker/appsettings.Development.json @@ -0,0 +1,2 @@ +{ +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Worker/appsettings.Production.json b/TeachingRecordSystem/src/TeachingRecordSystem.Worker/appsettings.Production.json new file mode 100644 index 000000000..3f60b792a --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Worker/appsettings.Production.json @@ -0,0 +1,10 @@ +{ + "Serilog": { + "MinimumLevel": { + "Default": "Error", + "Override": { + "TeachingRecordSystem.Worker": "Warning" + } + } + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Worker/appsettings.json b/TeachingRecordSystem/src/TeachingRecordSystem.Worker/appsettings.json new file mode 100644 index 000000000..f3e7b3e32 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Worker/appsettings.json @@ -0,0 +1,8 @@ +{ + "Serilog": { + "MinimumLevel": { + "Default": "Information" + }, + "Enrich": [ "FromLogContext" ] + } +} diff --git a/terraform/aks/app.tf b/terraform/aks/app.tf index 4dafb46be..16bd227ee 100644 --- a/terraform/aks/app.tf +++ b/terraform/aks/app.tf @@ -54,7 +54,7 @@ module "api_application_configuration" { secret_key_vault_short = "api" config_variables = { - PlatformEnvironment = var.environment_name + SENTRY_ENVIRONMENT = var.environment_name DistributedLockContainerName = azurerm_storage_container.locks.name DqtReporting__RunService = var.run_dqt_reporting_service RecurringJobs__Enabled = var.run_recurring_jobs @@ -67,6 +67,7 @@ module "api_application_configuration" { ConnectionStrings__Redis = module.redis.connection_string StorageConnectionString = "DefaultEndpointsProtocol=https;AccountName=${azurerm_storage_account.app_storage.name};AccountKey=${azurerm_storage_account.app_storage.primary_access_key}" DqtReporting__ReportingDbConnectionString = local.reporting_db_connection_string + Sentry__Dsn = module.infrastructure_secrets.map.SENTRY-DSN } } @@ -104,14 +105,16 @@ module "ui_application_configuration" { secret_key_vault_short = "ui" config_variables = { - PlatformEnvironment = var.environment_name + SENTRY_ENVIRONMENT = var.environment_name DataProtectionKeysContainerName = azurerm_storage_container.keys.name } secret_variables = { - ConnectionStrings__DefaultConnection = module.postgres.dotnet_connection_string - ConnectionStrings__Redis = "${module.redis.connection_string},defaultDatabase=1" - StorageConnectionString = "DefaultEndpointsProtocol=https;AccountName=${azurerm_storage_account.app_storage.name};AccountKey=${azurerm_storage_account.app_storage.primary_access_key}" + ApplicationInsights__ConnectionString = azurerm_application_insights.app.connection_string + ConnectionStrings__DefaultConnection = module.postgres.dotnet_connection_string + ConnectionStrings__Redis = "${module.redis.connection_string},defaultDatabase=1" + StorageConnectionString = "DefaultEndpointsProtocol=https;AccountName=${azurerm_storage_account.app_storage.name};AccountKey=${azurerm_storage_account.app_storage.primary_access_key}" + Sentry__Dsn = module.infrastructure_secrets.map.SENTRY-DSN } } @@ -148,12 +151,14 @@ module "worker_application_configuration" { secret_key_vault_short = "worker" config_variables = { - PlatformEnvironment = var.environment_name + SENTRY_ENVIRONMENT = var.environment_name } secret_variables = { - ConnectionStrings__DefaultConnection = module.postgres.dotnet_connection_string - StorageConnectionString = "DefaultEndpointsProtocol=https;AccountName=${azurerm_storage_account.app_storage.name};AccountKey=${azurerm_storage_account.app_storage.primary_access_key}" + ApplicationInsights__ConnectionString = azurerm_application_insights.app.connection_string + ConnectionStrings__DefaultConnection = module.postgres.dotnet_connection_string + StorageConnectionString = "DefaultEndpointsProtocol=https;AccountName=${azurerm_storage_account.app_storage.name};AccountKey=${azurerm_storage_account.app_storage.primary_access_key}" + Sentry__Dsn = module.infrastructure_secrets.map.SENTRY-DSN } }