using System.Data; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Serilog; using Serilog.Enrichers.Span; using Serilog.Events; using Serilog.Exceptions; using Serilog.Formatting.Json; using Serilog.Sinks.MSSqlServer; namespace Baya.Infrastructure.CrossCutting.Logging; public static class LoggingConfiguration { public static Action ConfigureLogger => (context, configuration) => { #region Level & enrichment var env = context.HostingEnvironment; // refinement-phase-9 §9.3: deployed environments log Information+ (previously Warning+, which silently // dropped every Information-level audit trail — logins, money-operation context). Framework categories // are held at Warning so raising the floor doesn't flood the sink with ASP.NET/EF request noise. // No PII/secrets are ever logged: the mock SMS sender no longer logs the OTP code, and clinical text / // IBANs / phone numbers are encrypted or masked before they reach any handler that logs. configuration .MinimumLevel.Information() .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) .MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning) .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning) .MinimumLevel.Override("System", LogEventLevel.Warning) .Enrich.FromLogContext() .Enrich.WithProperty("ApplicationName", env.ApplicationName) .Enrich.WithProperty("Environment", env.EnvironmentName) .Enrich.WithSpan() .Enrich.WithExceptionDetails(); #endregion var columnOpts = new ColumnOptions(); columnOpts.Store.Remove(StandardColumn.Properties); columnOpts.Store.Add(StandardColumn.LogEvent); columnOpts.LogEvent.DataLength = 4096; columnOpts.PrimaryKey = columnOpts.Id; columnOpts.Id.DataType = SqlDbType.Int; // Development and Testing (WebApplicationFactory) log locally; the SQL sink is for deployed envs. if (!context.HostingEnvironment.IsDevelopment() && !context.HostingEnvironment.IsEnvironment("Testing")) { // Retention for the `log.LogEvents` table is an ops/DBA responsibility (a scheduled purge or a // partitioned/rolling table on Baya_Logs) — distinct from application data. Set an OpenTelemetry:Otlp // collector (see OpenTelemetryConfigurations) if you prefer to ship logs off-box instead of the SQL sink. configuration.WriteTo .MSSqlServer( connectionString: context.Configuration.GetConnectionString("logDb"), sinkOptions: new MSSqlServerSinkOptions { TableName = "LogEvents", AutoCreateSqlTable = true, SchemaName = "log", AutoCreateSqlDatabase = true }, columnOptions: columnOpts); } else { configuration.WriteTo.Console(); configuration.WriteTo.File(new JsonFormatter(), "logs/log.json"); } }; }