ABP记录EF生成的数据库日志
1.首先我们建两个类来记录EFCore产生的脚本日志
using Microsoft.Extensions.Logging; using System; namespace STK.backendCode.EntityFrameworkCore.Logger { public class EFLogger : ILogger { public Castle.Core.Logging.ILogger Logger { get; set; } private readonly string _categoryName; public EFLogger(string categoryName, Castle.Core.Logging.ILogger logger) { this._categoryName = categoryName; this.Logger = logger; } public bool IsEnabled(LogLevel logLevel) => true; public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) { //ef core执行数据库查询时的categoryName为Microsoft.EntityFrameworkCore.Database.Command,日志级别为Information var logContent2 = formatter(state, exception); if (_categoryName == "Microsoft.EntityFrameworkCore.Database.Command" && logLevel == LogLevel.Information) { var logContent = formatter(state, exception); Logger.Warn(logContent); } } public IDisposable BeginScope<TState>(TState state) => null; } }
using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Text; namespace STK.backendCode.EntityFrameworkCore.Logger { public class EfLoggerProvider : ILoggerProvider { public Castle.Core.Logging.ILogger Logger; public EfLoggerProvider(Castle.Core.Logging.ILogger logger) { Logger = logger; } public ILogger CreateLogger(string categoryName) { return new EFLogger(categoryName, Logger); } public void Dispose() { } } }
2.修改AbpDemoDbContextConfigurer.cs
using System.Data.Common; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; namespace STK.backendCode.EntityFrameworkCore { public static class backendCodeDbContextConfigurer { public static void Configure(DbContextOptionsBuilder<backendCodeDbContext> builder, string connectionString, LoggerFactory loggerFactory) { //builder.UseSqlServer(connectionString); builder.UseLoggerFactory(loggerFactory).UseMySql(connectionString); builder.EnableSensitiveDataLogging(); //日志显示脚本参数 } public static void Configure(DbContextOptionsBuilder<backendCodeDbContext> builder, DbConnection connection, LoggerFactory loggerFactory) { //builder.UseSqlServer(connection); builder.UseLoggerFactory(loggerFactory).UseMySql(connection); builder.EnableSensitiveDataLogging(); //日志显示脚本参数 } } }
3, 修改AbpDemoEntityFrameworkModule.cs 构建EfLoggerProvider类并提供给配置类使用
using Abp.EntityFrameworkCore.Configuration; using Abp.Modules; using Abp.Reflection.Extensions; using Abp.Zero.EntityFrameworkCore; using STK.backendCode.EntityFrameworkCore.Logger; using STK.backendCode.EntityFrameworkCore.Seed; namespace STK.backendCode.EntityFrameworkCore { [DependsOn( typeof(backendCodeCoreModule), typeof(AbpZeroCoreEntityFrameworkCoreModule))] public class backendCodeEntityFrameworkModule : AbpModule { /* Used it tests to skip dbcontext registration, in order to use in-memory database of EF Core */ public bool SkipDbContextRegistration { get; set; } public bool SkipDbSeed { get; set; } public override void PreInitialize() { if (!SkipDbContextRegistration) { Configuration.Modules.AbpEfCore().AddDbContext<backendCodeDbContext>(options => { if (options.ExistingConnection != null) { backendCodeDbContextConfigurer.Configure(options.DbContextOptions, options.ExistingConnection, DbLoggerFactory); } else { backendCodeDbContextConfigurer.Configure(options.DbContextOptions, options.ConnectionString, DbLoggerFactory); } }); } } public override void Initialize() { IocManager.RegisterAssemblyByConvention(typeof(backendCodeEntityFrameworkModule).GetAssembly()); } public override void PostInitialize() { if (!SkipDbSeed) { SeedHelper.SeedHostDb(IocManager); } } private static Microsoft.Extensions.Logging.LoggerFactory _loggerFactory; private Microsoft.Extensions.Logging.LoggerFactory DbLoggerFactory { get { if (null == _loggerFactory) { _loggerFactory = new Microsoft.Extensions.Logging.LoggerFactory(); //_loggerFactory.AddProvider(new EfLoggerProvider(IocManager.Resolve<Castle.Core.Logging.ILogger>())); _loggerFactory.AddProvider(new EfLoggerProvider(Logger)); } return _loggerFactory; } } } }
4, 修复AbpDemoDbContextFactory.cs 的报错,传入空日志类就可以了
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using Microsoft.Extensions.Configuration; using STK.backendCode.Configuration; using STK.backendCode.Web; namespace STK.backendCode.EntityFrameworkCore { /* This class is needed to run "dotnet ef ..." commands from command line on development. Not used anywhere else */ public class backendCodeDbContextFactory : IDesignTimeDbContextFactory<backendCodeDbContext> { public backendCodeDbContext CreateDbContext(string[] args) { var builder = new DbContextOptionsBuilder<backendCodeDbContext>(); var configuration = AppConfigurations.Get(WebContentDirectoryFinder.CalculateContentRootFolder()); backendCodeDbContextConfigurer.Configure(builder, configuration.GetConnectionString(backendCodeConsts.ConnectionStringName), null); return new backendCodeDbContext(builder.Options); } } }
这样运行项目, 在Logs.txt中就会显示所有的数据库脚本了
我对日志进行了分类存放, 下面是参考的 log4net.config
<?xml version="1.0" encoding="utf-8" ?> <log4net> <!-- 全部的日志 DEBUG < INFO < WARN < ERROR < FATAL --> <appender name="Info" type="log4net.Appender.RollingFileAppender" > <file value="App_Data/Logs/Info" /> <appendToFile value="true" /> <rollingStyle value="Date" /> <datePattern value="yyyyMM\\'Info'yyyyMMdd'.txt'"/> <maxSizeRollBackups value="100" /> <maximumFileSize value="10000KB" /> <staticLogFileName value="false" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%newline%date [%thread] [%-5level] %logger %newline%message%newline"/> </layout> </appender> <!-- SQL --> <appender name="Warn" type="log4net.Appender.RollingFileAppender" > <file value="App_Data/Logs/Warn" /> <appendToFile value="true" /> <rollingStyle value="Date" /> <datePattern value="yyyyMM\\'Warn'yyyyMMdd'.txt'"/> <maxSizeRollBackups value="100" /> <maximumFileSize value="10000KB" /> <staticLogFileName value="false" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%newline%date [%thread] [%-5level] %logger %newline%message%newline"/> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <levelMin value="Warn" /> <levelMax value="Warn" /> </filter> </appender> <!-- Error --> <appender name="Error" type="log4net.Appender.RollingFileAppender" > <file value="App_Data/Logs/Error" /> <appendToFile value="true" /> <rollingStyle value="Date" /> <datePattern value="yyyyMM/'Error'yyyyMMdd'.txt'"/> <maxSizeRollBackups value="100" /> <maximumFileSize value="10000KB" /> <staticLogFileName value="false" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%newline%date [%thread] [%-5level] %logger property: [%property{NDC}] %newline%message%newline"/> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <levelMin value="Error" /> </filter> </appender> <!-- 只有Debug --> <appender name="Debug" type="log4net.Appender.RollingFileAppender" > <file value="App_Data/Logs/Debug.txt" /> <appendToFile value="true" /> <rollingStyle value="Size" /> <maxSizeRollBackups value="10" /> <maximumFileSize value="10000KB" /> <staticLogFileName value="true" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%newline%date [%thread] [%-5level] %logger %newline%message%newline"/> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <levelMin value="Debug" /> <levelMax value="Debug" /> </filter> </appender> <!--输出到控制台--> <appender name="Console" type="log4net.Appender.ManagedColoredConsoleAppender"> <mapping> <level value="ERROR"> <foreColor value="Yellow,HighIntensity" /> </level> </mapping> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%newline%date [%thread] [%-5level] %-40.40logger %newline%message%newline" /> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <levelMin value="Error" /> </filter> </appender> <root> <appender-ref ref="Warn" /> <appender-ref ref="Info" /> <appender-ref ref="Error" /> <appender-ref ref="Debug" /> <appender-ref ref="Console" /> <level value="DEBUG" /> </root> <logger name="NHibernate"> <level value="WARN" /> </logger> </log4net>