要专业系统地学习EF推荐《你必须掌握的Entity Framework 6.x与Core 2.0》。这本书作者(汪鹏,Jeffcky)的博客:https://www.cnblogs.com/CreateMyself/
格式化日志输出
上次我们知道了利用ctx.Database.Log来进行简单的日志打印,还是很有帮助的。
那么它其实是继承自DatabaseLogFormatter,那么我们可以写一个派生自DatabaseLogFormatter这个类,来实现更多的自定义操作
实现步骤
1 写一个派生自DatabaseLogFormatter的类
2.在EF中进行注册
又到了学英语的时候,看一下DatabaseLogFormatter
我来重写LogCommad 和Closing方法,因为对里面的东西都不熟,所以我都打印看一下
public class DBlogFormatter : DatabaseLogFormatter { public DBlogFormatter(DbContext context, Action<string> writeAction) : base(context, writeAction) { } public override void LogCommand<TResult>(DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext) { Write($"重写LogCommand:记录将要执行的命令:command.CommandText:{command.CommandText}{Environment.NewLine}" + $"command.CommandTimeout:{command.CommandTimeout}{Environment.NewLine}" + $"command.CommandType:{command.CommandType}{Environment.NewLine}" + $"command.Connection:{command.Connection}{Environment.NewLine}" + $"command.Container:{command.Container}{Environment.NewLine}" + $"command.Parameters:{command.Parameters}{Environment.NewLine}" + $"command.Site:{command.Site}{Environment.NewLine}" + $"command.ToString():{command.ToString()}{Environment.NewLine}" + $"command.Transaction:{command.Transaction}{Environment.NewLine}" + $"command.UpdateRowSource:{command.UpdatedRowSource}{Environment.NewLine}"); } public override void Closing(DbConnection connection, DbConnectionInterceptionContext interceptionContext) { Write($"重写Closing:{Environment.NewLine}" + $"connection.ConnectinoString:{connection.ConnectionString}{Environment.NewLine}" + $"connection.ConnectionTimeout:{connection.ConnectionTimeout}{Environment.NewLine}" + $"connection.Container:{connection.Container}{Environment.NewLine}" + $"connection.Database:{connection.Database}{Environment.NewLine}" + $"connection.DataSource:{connection.DataSource}{Environment.NewLine}" + $"connection.ServerVersion:{connection.ServerVersion}{Environment.NewLine}" + $"connection.Site:{connection.Site}{Environment.NewLine}"); base.Closing(connection, interceptionContext); } }
在EF中注册配置
public class DBContextConfiguration:DbConfiguration { public DBContextConfiguration() { SetDatabaseLogFormatter((context,action) => new DBlogFormatter(context,action)); } }
最后看看,在我们自定义之前和之后打印的比较
差不多就是这样了,行吧,我其实觉得ctx.Database.Log对我来说已经够用了。那么作者又说到了拦截和日志框架的使用
拦截+NLog日志框架
要实现拦截就要继承IDbInterceptor,当EF调用ExceuteNonQuery、ExecuteScalar、ExecuteReader(CURD)等相关方法时,在IDbInterceptor上定义的方法都会被调用。
该接口存在的最终意义是为了追踪SQL和格式化输出SQL
我们上面弄得那个DatabaseLogFormatter,它就继承了IDbInterceptor
弄起来很简单,和上面差不多,只不过我们现在加上一个NLog日志框架来配合使用
步骤,1.下载Nlog、NLog.config
2.写一个派生自IDbinterceptor的类,将拦截信息使用NLog写入
3.在EF中注册配置
4、NLog配置文件中添加配置
那么最后结果就是在binDebug目录下创建一个Logs文件夹,里面有记录的日志
namespace _201901212.NLog { public class NLogCommandInterceptor : IDbCommandInterceptor { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) { LogIfError(command,interceptionContext); } public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) { LogIfNonAsync(command,interceptionContext); } public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { LogIfError(command,interceptionContext); } public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { LogIfNonAsync(command, interceptionContext); } public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) { LogIfError(command, interceptionContext); } public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) { LogIfNonAsync(command,interceptionContext); } private void LogIfNonAsync<TResult>(DbCommand command,DbCommandInterceptionContext<TResult> interceptionContext) { if (!interceptionContext.IsAsync) { Console.WriteLine(Logger.Name); Console.WriteLine($"张四海{Logger}"); Logger.Warn("Non-async command used:{0}",command.CommandText); } } private void LogIfError<TResult>(DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext) { if (interceptionContext.Exception != null) { Logger.Error("Command {0} failed with exception {1}",command.CommandText,interceptionContext.Exception); } } }
public class DBContextConfiguration:DbConfiguration { public DBContextConfiguration() { // 添加拦截器 DbInterception.Add(new NLogCommandInterceptor()); } }
targets变迁 filename属性指的是将日志写到哪里去,我这里写的“${basedir}Logslog.txt”指的就是写到binDebug里面去
rules标签的name属性指的是logger对象所在的地方
<targets> <target name="logfile" xsi:type="File" fileName="${basedir}Logslog.txt"/> </targets> <rules> <logger name="_201901212.NLog.NLogCommandInterceptor" writeTo="logfile"/> </rules>
现在起码能够运行,NLog也起作用了,但是很定会有很多问题等着去解决
后面就具体弄一弄这个NLog,以及和EF搭配实现可用的日志管理功能。