feat(core): add optional SQL query logging
This commit is contained in:
		
							parent
							
								
									b95fb76cd4
								
							
						
					
					
						commit
						6aed05af06
					
				
					 8 changed files with 56 additions and 31 deletions
				
			
		|  | @ -1,6 +1,7 @@ | |||
| using Foxchat.Chat.Database.Models; | ||||
| using Foxchat.Core; | ||||
| using Foxchat.Core.Database; | ||||
| using Foxchat.Core.Extensions; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using Microsoft.EntityFrameworkCore.Design; | ||||
| using Npgsql; | ||||
|  | @ -10,6 +11,7 @@ namespace Foxchat.Chat.Database; | |||
| public class ChatContext : IDatabaseContext | ||||
| { | ||||
|     private readonly NpgsqlDataSource _dataSource; | ||||
|     private readonly ILoggerFactory? _loggerFactory; | ||||
| 
 | ||||
|     public override DbSet<Instance> Instance { get; set; } | ||||
|     public DbSet<IdentityInstance> IdentityInstances { get; set; } | ||||
|  | @ -18,7 +20,7 @@ public class ChatContext : IDatabaseContext | |||
|     public DbSet<Channel> Channels { get; set; } | ||||
|     public DbSet<Message> Messages { get; set; } | ||||
| 
 | ||||
|     public ChatContext(InstanceConfig config) | ||||
|     public ChatContext(InstanceConfig config, ILoggerFactory? loggerFactory) | ||||
|     { | ||||
|         var connString = new NpgsqlConnectionStringBuilder(config.Database.Url) | ||||
|         { | ||||
|  | @ -29,12 +31,14 @@ public class ChatContext : IDatabaseContext | |||
|         var dataSourceBuilder = new NpgsqlDataSourceBuilder(connString); | ||||
|         dataSourceBuilder.UseNodaTime(); | ||||
|         _dataSource = dataSourceBuilder.Build(); | ||||
|         _loggerFactory = loggerFactory; | ||||
|     } | ||||
| 
 | ||||
|     protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) | ||||
|         => optionsBuilder | ||||
|             .UseNpgsql(_dataSource, o => o.UseNodaTime()) | ||||
|             .UseSnakeCaseNamingConvention(); | ||||
|             .UseSnakeCaseNamingConvention() | ||||
|             .UseLoggerFactory(_loggerFactory); | ||||
| 
 | ||||
|     protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) | ||||
|     { | ||||
|  | @ -73,6 +77,6 @@ public class DesignTimeIdentityContextFactory : IDesignTimeDbContextFactory<Chat | |||
|             // Get the configuration as our config class | ||||
|             .Get<InstanceConfig>() ?? new(); | ||||
| 
 | ||||
|         return new ChatContext(config); | ||||
|         return new ChatContext(config, null); | ||||
|     } | ||||
| } | ||||
|  | @ -4,13 +4,14 @@ using Foxchat.Core; | |||
| using Foxchat.Chat; | ||||
| using Foxchat.Chat.Database; | ||||
| using Foxchat.Chat.Extensions; | ||||
| using Foxchat.Core.Extensions; | ||||
| using Newtonsoft.Json; | ||||
| 
 | ||||
| var builder = WebApplication.CreateBuilder(args); | ||||
| 
 | ||||
| var config = builder.AddConfiguration<InstanceConfig>("chat.ini"); | ||||
| 
 | ||||
| builder.AddSerilog(config.LogEventLevel); | ||||
| builder.AddSerilog(); | ||||
| 
 | ||||
| await BuildInfo.ReadBuildInfo(); | ||||
| Log.Information("Starting Foxchat.Chat {Version} ({Hash})", BuildInfo.Version, BuildInfo.Hash); | ||||
|  |  | |||
|  | @ -2,9 +2,6 @@ Host = localhost | |||
| Port = 7610 | ||||
| Domain = chat.fox.localhost | ||||
| 
 | ||||
| ; The level to log things at. Valid settings: Verbose, Debug, Information, Warning, Error, Fatal | ||||
| LogEventLevel = Debug | ||||
| 
 | ||||
| [Database] | ||||
| ; The database URL in ADO.NET format. | ||||
| Url = "Host=localhost;Database=foxchat_cs_chat;Username=foxchat;Password=password" | ||||
|  | @ -13,3 +10,11 @@ Url = "Host=localhost;Database=foxchat_cs_chat;Username=foxchat;Password=passwor | |||
| Timeout = 5 | ||||
| ; The maximum number of open connections. Defaults to 50. | ||||
| MaxPoolSize = 500 | ||||
| 
 | ||||
| [Logging] | ||||
| ; The level to log things at. Valid settings: Verbose, Debug, Information, Warning, Error, Fatal | ||||
| LogEventLevel = Debug | ||||
| ; Whether to log SQL queries. | ||||
| LogQueries = true | ||||
| ; Optional logging to Seq | ||||
| SeqLogUrl = http://localhost:5341 | ||||
|  | @ -11,9 +11,7 @@ public class CoreConfig | |||
| 
 | ||||
|     public string Address => $"{(Secure ? "https" : "http")}://{Host}:{Port}"; | ||||
| 
 | ||||
|     public LogEventLevel LogEventLevel { get; set; } = LogEventLevel.Debug; | ||||
|     public string? SeqLogUrl { get; set; } | ||||
| 
 | ||||
|     public LoggingConfig Logging { get; set; } = new(); | ||||
|     public DatabaseConfig Database { get; set; } = new(); | ||||
| 
 | ||||
|     public class DatabaseConfig | ||||
|  | @ -22,4 +20,11 @@ public class CoreConfig | |||
|         public int? Timeout { get; set; } | ||||
|         public int? MaxPoolSize { get; set; } | ||||
|     } | ||||
| 
 | ||||
|     public class LoggingConfig | ||||
|     { | ||||
|         public LogEventLevel LogEventLevel { get; set; } = LogEventLevel.Debug; | ||||
|         public string? SeqLogUrl { get; set; } | ||||
|         public bool LogQueries { get; set; } = false; | ||||
|     } | ||||
| } | ||||
|  | @ -7,30 +7,32 @@ using NodaTime; | |||
| using Serilog; | ||||
| using Serilog.Events; | ||||
| 
 | ||||
| namespace Foxchat.Core; | ||||
| namespace Foxchat.Core.Extensions; | ||||
| 
 | ||||
| public static class ServiceCollectionExtensions | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Adds Serilog to this service collection. This method also initializes Serilog so it should be called as early as possible, before any log calls. | ||||
|     /// </summary> | ||||
|     public static void AddSerilog(this WebApplicationBuilder builder, LogEventLevel level) | ||||
|     public static void AddSerilog(this WebApplicationBuilder builder) | ||||
|     { | ||||
|         var config = builder.Configuration.Get<CoreConfig>() ?? new(); | ||||
| 
 | ||||
|         var logCfg = new LoggerConfiguration() | ||||
|             .Enrich.FromLogContext() | ||||
|             .MinimumLevel.Is(level) | ||||
|             .MinimumLevel.Is(config.Logging.LogEventLevel) | ||||
|             // ASP.NET's built in request logs are extremely verbose, so we use Serilog's instead. | ||||
|             // Serilog doesn't disable the built in logs so we do it here. | ||||
|             // Serilog doesn't disable the built-in logs, so we do it here. | ||||
|             .MinimumLevel.Override("Microsoft", LogEventLevel.Information) | ||||
|             .MinimumLevel.Override("Microsoft.EntityFrameworkCore.Database.Command", | ||||
|                 config.Logging.LogQueries ? LogEventLevel.Information : LogEventLevel.Warning) | ||||
|             .MinimumLevel.Override("Microsoft.AspNetCore.Hosting", LogEventLevel.Warning) | ||||
|             .MinimumLevel.Override("Microsoft.AspNetCore.Mvc", LogEventLevel.Warning) | ||||
|             .MinimumLevel.Override("Microsoft.AspNetCore.Routing", LogEventLevel.Warning) | ||||
|             .WriteTo.Console(); | ||||
| 
 | ||||
|         if (config.SeqLogUrl != null) | ||||
|             logCfg.WriteTo.Seq(config.SeqLogUrl, restrictedToMinimumLevel: LogEventLevel.Verbose); | ||||
|         if (config.Logging.SeqLogUrl != null) | ||||
|             logCfg.WriteTo.Seq(config.Logging.SeqLogUrl, restrictedToMinimumLevel: LogEventLevel.Verbose); | ||||
| 
 | ||||
|         Log.Logger = logCfg.CreateLogger(); | ||||
| 
 | ||||
|  | @ -54,9 +56,9 @@ public static class ServiceCollectionExtensions | |||
|         return services; | ||||
|     } | ||||
| 
 | ||||
|     public static T AddConfiguration<T>(this WebApplicationBuilder builder, string? configFile = null) where T : class, new() | ||||
|     public static T AddConfiguration<T>(this WebApplicationBuilder builder, string? configFile = null) | ||||
|         where T : class, new() | ||||
|     { | ||||
| 
 | ||||
|         builder.Configuration.Sources.Clear(); | ||||
|         builder.Configuration.AddConfiguration(configFile); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| using Foxchat.Core; | ||||
| using Foxchat.Core.Database; | ||||
| using Foxchat.Core.Extensions; | ||||
| using Foxchat.Identity.Database.Models; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using Microsoft.EntityFrameworkCore.Design; | ||||
|  | @ -10,6 +11,7 @@ namespace Foxchat.Identity.Database; | |||
| public class IdentityContext : IDatabaseContext | ||||
| { | ||||
|     private readonly NpgsqlDataSource _dataSource; | ||||
|     private readonly ILoggerFactory? _loggerFactory; | ||||
| 
 | ||||
|     public override DbSet<Instance> Instance { get; set; } | ||||
|     public DbSet<Account> Accounts { get; set; } | ||||
|  | @ -18,7 +20,7 @@ public class IdentityContext : IDatabaseContext | |||
|     public DbSet<Token> Tokens { get; set; } | ||||
|     public DbSet<GuildAccount> GuildAccounts { get; set; } | ||||
| 
 | ||||
|     public IdentityContext(InstanceConfig config) | ||||
|     public IdentityContext(InstanceConfig config, ILoggerFactory? loggerFactory) | ||||
|     { | ||||
|         var connString = new NpgsqlConnectionStringBuilder(config.Database.Url) | ||||
|         { | ||||
|  | @ -29,12 +31,14 @@ public class IdentityContext : IDatabaseContext | |||
|         var dataSourceBuilder = new NpgsqlDataSourceBuilder(connString); | ||||
|         dataSourceBuilder.UseNodaTime(); | ||||
|         _dataSource = dataSourceBuilder.Build(); | ||||
|         _loggerFactory = loggerFactory; | ||||
|     } | ||||
| 
 | ||||
|     protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) | ||||
|         => optionsBuilder | ||||
|             .UseNpgsql(_dataSource, o => o.UseNodaTime()) | ||||
|                 .UseSnakeCaseNamingConvention(); | ||||
|             .UseSnakeCaseNamingConvention() | ||||
|             .UseLoggerFactory(_loggerFactory); | ||||
| 
 | ||||
|     protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) | ||||
|     { | ||||
|  | @ -67,6 +71,6 @@ public class DesignTimeIdentityContextFactory : IDesignTimeDbContextFactory<Iden | |||
|             // Get the configuration as our config class | ||||
|             .Get<InstanceConfig>() ?? new(); | ||||
| 
 | ||||
|         return new IdentityContext(config); | ||||
|         return new IdentityContext(config, null); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| using Newtonsoft.Json.Serialization; | ||||
| using Serilog; | ||||
| using Foxchat.Core; | ||||
| using Foxchat.Core.Extensions; | ||||
| using Foxchat.Identity; | ||||
| using Foxchat.Identity.Database; | ||||
| using Foxchat.Identity.Services; | ||||
|  | @ -11,7 +12,7 @@ var builder = WebApplication.CreateBuilder(args); | |||
| 
 | ||||
| var config = builder.AddConfiguration<InstanceConfig>("identity.ini"); | ||||
| 
 | ||||
| builder.AddSerilog(config.LogEventLevel); | ||||
| builder.AddSerilog(); | ||||
| 
 | ||||
| await BuildInfo.ReadBuildInfo(); | ||||
| Log.Information("Starting Foxchat.Identity {Version} ({Hash})", BuildInfo.Version, BuildInfo.Hash); | ||||
|  |  | |||
|  | @ -2,11 +2,6 @@ Host = localhost | |||
| Port = 7611 | ||||
| Domain = id.fox.localhost | ||||
| 
 | ||||
| ; The level to log things at. Valid settings: Verbose, Debug, Information, Warning, Error, Fatal | ||||
| LogEventLevel = Debug | ||||
| ; Optional logging to Seq | ||||
| SeqLogUrl = http://localhost:5341 | ||||
| 
 | ||||
| [Database] | ||||
| ; The database URL in ADO.NET format. | ||||
| Url = "Host=localhost;Database=foxchat_cs_ident;Username=foxchat;Password=password" | ||||
|  | @ -15,3 +10,11 @@ Url = "Host=localhost;Database=foxchat_cs_ident;Username=foxchat;Password=passwo | |||
| Timeout = 5 | ||||
| ; The maximum number of open connections. Defaults to 50. | ||||
| MaxPoolSize = 500 | ||||
| 
 | ||||
| [Logging] | ||||
| ; The level to log things at. Valid settings: Verbose, Debug, Information, Warning, Error, Fatal | ||||
| LogEventLevel = Debug | ||||
| ; Whether to log SQL queries. | ||||
| LogQueries = true | ||||
| ; Optional logging to Seq | ||||
| SeqLogUrl = http://localhost:5341 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue