refinement phase 9
This commit is contained in:
+1
-1
@@ -7,10 +7,10 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" />
|
||||
<PackageReference Include="Serilog.Sinks.File" />
|
||||
<PackageReference Include="Serilog.Sinks.MSSqlServer" />
|
||||
<PackageReference Include="Serilog.Sinks.PeriodicBatching" />
|
||||
<PackageReference Include="Serilog.Exceptions" />
|
||||
<PackageReference Include="Serilog.Sinks.Elasticsearch" />
|
||||
<PackageReference Include="Serilog.Enrichers.Span" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
+25
-34
@@ -1,8 +1,9 @@
|
||||
using System.Data;
|
||||
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;
|
||||
@@ -13,22 +14,29 @@ public static class LoggingConfiguration
|
||||
{
|
||||
public static Action<HostBuilderContext, LoggerConfiguration> ConfigureLogger => (context, configuration) =>
|
||||
{
|
||||
#region Enriching Logger Context
|
||||
#region Level & enrichment
|
||||
|
||||
var env = context.HostingEnvironment;
|
||||
|
||||
|
||||
configuration.Enrich.FromLogContext()
|
||||
// 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);
|
||||
@@ -39,36 +47,19 @@ public static class LoggingConfiguration
|
||||
// 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})
|
||||
.MinimumLevel.Warning();
|
||||
|
||||
sinkOptions: new MSSqlServerSinkOptions { TableName = "LogEvents", AutoCreateSqlTable = true, SchemaName = "log", AutoCreateSqlDatabase = true },
|
||||
columnOptions: columnOpts);
|
||||
}
|
||||
|
||||
else{
|
||||
configuration.WriteTo.Console().MinimumLevel.Information();
|
||||
configuration.WriteTo.File(new JsonFormatter(), "logs/log.json").MinimumLevel.Information();
|
||||
else
|
||||
{
|
||||
configuration.WriteTo.Console();
|
||||
configuration.WriteTo.File(new JsonFormatter(), "logs/log.json");
|
||||
}
|
||||
|
||||
#region ElasticSearch Configuration. UnComment if Needed
|
||||
|
||||
|
||||
//var elasticUrl = context.Configuration.GetValue<string>("Logging:ElasticUrl");
|
||||
|
||||
//if (!string.IsNullOrEmpty(elasticUrl))
|
||||
//{
|
||||
// configuration.WriteTo.Elasticsearch(
|
||||
// new ElasticsearchSinkOptions(new Uri(elasticUrl))
|
||||
// {
|
||||
// AutoRegisterTemplate = true,
|
||||
// AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv7,
|
||||
// IndexFormat = "web-logs-{0:yyyy.MM.dd}",
|
||||
// MinimumLogEventLevel = LogEventLevel.Debug
|
||||
// });
|
||||
//}
|
||||
|
||||
#endregion
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+8
-6
@@ -4,22 +4,24 @@ using Microsoft.Extensions.Logging;
|
||||
namespace Baya.Infrastructure.CrossCutting.Seams;
|
||||
|
||||
/// <summary>
|
||||
/// Mock <see cref="ISmsSender"/>: "delivers" by logging. The OTP code is written to the log so a
|
||||
/// developer can complete the login flow; the phone number is never logged in full (PII policy) —
|
||||
/// only its last four digits. The real implementation swaps to an Iranian SMS gateway
|
||||
/// (Kavenegar/Ghasedak/SMS.ir) behind the same interface via a registration change.
|
||||
/// Mock <see cref="ISmsSender"/>: "delivers" by logging. The OTP <b>code is never logged</b> (refinement-phase-9
|
||||
/// §9.3 — no secrets/PII in logs, in any environment): a developer retrieves it from the Development-only
|
||||
/// <c>GET /api/v1/dev/last_otp/{phone}</c> helper (the <c>DevCapturingSmsSender</c> decorator), never the log.
|
||||
/// The phone number is logged only as its last four digits. The real implementation swaps to an Iranian SMS
|
||||
/// gateway (Kavenegar/Ghasedak/SMS.ir) behind the same interface via a registration change.
|
||||
/// </summary>
|
||||
public sealed class LoggingSmsSender(ILogger<LoggingSmsSender> logger) : ISmsSender
|
||||
{
|
||||
public Task SendOtpAsync(string phone, string code, CancellationToken cancellationToken = default)
|
||||
{
|
||||
logger.LogWarning("MOCK SMS — OTP code {OtpCode} for phone ending in {PhoneTail}", code, Tail(phone));
|
||||
// Deliberately does NOT log the OTP code — it is a login secret. Retrieve it via /dev/last_otp in Development.
|
||||
logger.LogInformation("MOCK SMS — OTP issued to phone ending in {PhoneTail}", Tail(phone));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task SendAsync(string phone, string message, CancellationToken cancellationToken = default)
|
||||
{
|
||||
logger.LogWarning("MOCK SMS — message to phone ending in {PhoneTail}: {Message}", Tail(phone), message);
|
||||
logger.LogInformation("MOCK SMS — message to phone ending in {PhoneTail}: {Message}", Tail(phone), message);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user