EF6学习笔记二十一:格式化日志输出

要专业系统地学习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);
        }
    }
View Code

 在EF中注册配置

public class DBContextConfiguration:DbConfiguration
    {
        public DBContextConfiguration()
        {
            SetDatabaseLogFormatter((context,action) => new DBlogFormatter(context,action));
        }
    }
View Code

最后看看,在我们自定义之前和之后打印的比较

 

差不多就是这样了,行吧,我其实觉得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配置文件中添加配置

那么最后结果就是在bin\Debug目录下创建一个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);
            }
        }
    }
View Code
public class DBContextConfiguration:DbConfiguration
    {
        public DBContextConfiguration()
        {
            //  添加拦截器
            DbInterception.Add(new NLogCommandInterceptor());
        }
    }
View Code

 targets变迁 filename属性指的是将日志写到哪里去,我这里写的“${basedir}\Logs\log.txt”指的就是写到bin\Debug里面去

rules标签的name属性指的是logger对象所在的地方

<targets>
    <target name="logfile" xsi:type="File" fileName="${basedir}\Logs\log.txt"/>
  </targets>
  <rules>
    <logger name="_201901212.NLog.NLogCommandInterceptor" writeTo="logfile"/>
  </rules>
View Code

 

 

现在起码能够运行,NLog也起作用了,但是很定会有很多问题等着去解决

后面就具体弄一弄这个NLog,以及和EF搭配实现可用的日志管理功能。

 

posted @ 2019-01-25 13:17  张四海  阅读(400)  评论(0编辑  收藏  举报