[backend/configuration] Allow configuring of parameter logging for database exceptions

This commit is contained in:
Laura Hausmann 2024-06-21 16:24:03 +02:00
parent f2e4d11ce4
commit 3e0a5b5759
No known key found for this signature in database
GPG key ID: D044E84C5BE01605
4 changed files with 47 additions and 27 deletions

View file

@ -95,6 +95,7 @@ public sealed class Config
public string? Password { get; init; } public string? Password { get; init; }
[Range(1, 1000)] public int MaxConnections { get; init; } = 100; [Range(1, 1000)] public int MaxConnections { get; init; } = 100;
public bool Multiplexing { get; init; } = false; public bool Multiplexing { get; init; } = false;
public bool ParameterLogging { get; init; } = false;
} }
public sealed class StorageSection public sealed class StorageSection

View file

@ -91,25 +91,28 @@ public class DatabaseContext(DbContextOptions<DatabaseContext> options)
public virtual DbSet<Filter> Filters { get; init; } = null!; public virtual DbSet<Filter> Filters { get; init; } = null!;
public virtual DbSet<DataProtectionKey> DataProtectionKeys { get; init; } = null!; public virtual DbSet<DataProtectionKey> DataProtectionKeys { get; init; } = null!;
public static NpgsqlDataSource GetDataSource(Config.DatabaseSection? config) public static NpgsqlDataSource GetDataSource(Config.DatabaseSection config)
{ {
var dataSourceBuilder = new NpgsqlDataSourceBuilder(); var dataSourceBuilder = new NpgsqlDataSourceBuilder
{
ConnectionStringBuilder =
{
Host = config.Host,
Port = config.Port,
Username = config.Username,
Password = config.Password,
Database = config.Database,
MaxPoolSize = config.MaxConnections,
Multiplexing = config.Multiplexing
}
};
if (config == null) return ConfigureDataSource(dataSourceBuilder, config);
throw new Exception("Failed to initialize database: Failed to load configuration");
dataSourceBuilder.ConnectionStringBuilder.Host = config.Host;
dataSourceBuilder.ConnectionStringBuilder.Port = config.Port;
dataSourceBuilder.ConnectionStringBuilder.Username = config.Username;
dataSourceBuilder.ConnectionStringBuilder.Password = config.Password;
dataSourceBuilder.ConnectionStringBuilder.Database = config.Database;
dataSourceBuilder.ConnectionStringBuilder.MaxPoolSize = config.MaxConnections;
dataSourceBuilder.ConnectionStringBuilder.Multiplexing = config.Multiplexing;
return ConfigureDataSource(dataSourceBuilder);
} }
public static NpgsqlDataSource ConfigureDataSource(NpgsqlDataSourceBuilder dataSourceBuilder) private static NpgsqlDataSource ConfigureDataSource(
NpgsqlDataSourceBuilder dataSourceBuilder, Config.DatabaseSection config
)
{ {
dataSourceBuilder.MapEnum<Antenna.AntennaSource>(); dataSourceBuilder.MapEnum<Antenna.AntennaSource>();
dataSourceBuilder.MapEnum<Note.NoteVisibility>(); dataSourceBuilder.MapEnum<Note.NoteVisibility>();
@ -125,14 +128,22 @@ public class DatabaseContext(DbContextOptions<DatabaseContext> options)
dataSourceBuilder.EnableDynamicJson(); dataSourceBuilder.EnableDynamicJson();
if (config.ParameterLogging)
dataSourceBuilder.EnableParameterLogging();
return dataSourceBuilder.Build(); return dataSourceBuilder.Build();
} }
public static void Configure(DbContextOptionsBuilder optionsBuilder, NpgsqlDataSource dataSource) public static void Configure(
DbContextOptionsBuilder optionsBuilder, NpgsqlDataSource dataSource, Config.DatabaseSection config
)
{ {
optionsBuilder.UseNpgsql(dataSource); optionsBuilder.UseNpgsql(dataSource);
optionsBuilder.UseProjectables(options => { options.CompatibilityMode(CompatibilityMode.Full); }); optionsBuilder.UseProjectables(options => { options.CompatibilityMode(CompatibilityMode.Full); });
optionsBuilder.UseExceptionProcessor(); optionsBuilder.UseExceptionProcessor();
if (config.ParameterLogging)
optionsBuilder.EnableSensitiveDataLogging();
} }
protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnModelCreating(ModelBuilder modelBuilder)
@ -1292,10 +1303,12 @@ public class DesignTimeDatabaseContextFactory : IDesignTimeDbContextFactory<Data
.AddCustomConfiguration() .AddCustomConfiguration()
.Build(); .Build();
var config = configuration.GetSection("Database").Get<Config.DatabaseSection>(); var config = configuration.GetSection("Database").Get<Config.DatabaseSection>() ??
throw new Exception("Failed to initialize database: Failed to load configuration");
var dataSource = DatabaseContext.GetDataSource(config); var dataSource = DatabaseContext.GetDataSource(config);
var builder = new DbContextOptionsBuilder<DatabaseContext>(); var builder = new DbContextOptionsBuilder<DatabaseContext>();
DatabaseContext.Configure(builder, dataSource); DatabaseContext.Configure(builder, dataSource, config);
return new DatabaseContext(builder.Options); return new DatabaseContext(builder.Options);
} }
} }

View file

@ -159,9 +159,11 @@ public static class ServiceExtensions
public static void AddDatabaseContext(this IServiceCollection services, IConfiguration configuration) public static void AddDatabaseContext(this IServiceCollection services, IConfiguration configuration)
{ {
var config = configuration.GetSection("Database").Get<Config.DatabaseSection>(); var config = configuration.GetSection("Database").Get<Config.DatabaseSection>() ??
throw new Exception("Failed to initialize database: Failed to load configuration");
var dataSource = DatabaseContext.GetDataSource(config); var dataSource = DatabaseContext.GetDataSource(config);
services.AddDbContext<DatabaseContext>(options => { DatabaseContext.Configure(options, dataSource); }); services.AddDbContext<DatabaseContext>(options => { DatabaseContext.Configure(options, dataSource, config); });
services.AddKeyedDatabaseContext<DatabaseContext>("cache"); services.AddKeyedDatabaseContext<DatabaseContext>("cache");
services.AddDataProtection() services.AddDataProtection()
.PersistKeysToDbContextAsync<DatabaseContext>() .PersistKeysToDbContextAsync<DatabaseContext>()

View file

@ -102,6 +102,10 @@ MaxConnections = 100
;; Whether to enable connection multiplexing, which allows for more efficient use of the connection pool. ;; Whether to enable connection multiplexing, which allows for more efficient use of the connection pool.
Multiplexing = false Multiplexing = false
;; Whether to log parameter information on errors.
;; Caution: this may contain sensitive information, it's recommended to keep this disabled except for debugging purposes
ParameterLogging = false
[Storage] [Storage]
;; Where to store media attachments ;; Where to store media attachments
;; Options: [Local, ObjectStorage] ;; Options: [Local, ObjectStorage]