首页 > 代码库 > log4net 记录MVC监控日志

log4net 记录MVC监控日志

  由于MVC自身的特点,可以让我们记录每一个Controller下Action的执行时间以及View视图渲染完成的时间,本文采用log4net记录MVC每个Action的执行时间和View视图渲染完成时间,以及请求Action时post或get的数据。这样通过日志记录的时间方便我们定位哪一个Action和View执行的时间过长,进而采取优化的手段。

监控日志监控的指标如下图

技术分享

监控程序实现

  改监控程序主要继承ActionFilterAttribute类,并重写其中的OnActionExecuted、OnActionExecuting、OnResultExecuted、OnResultExecuting几个方法实现。

1、监控日志对象
/// <summary>    /// 监控日志对象    /// </summary>    public class MonitorLog    {        public string ControllerName        {            get;            set;        }        public string ActionName        {            get;            set;        }        public DateTime ExecuteStartTime        {            get;            set;        }        public DateTime ExecuteEndTime        {            get;            set;        }        /// <summary>        /// Form 表单数据        /// </summary>        public NameValueCollection FormCollections        {            get;            set;        }        /// <summary>        /// URL 参数        /// </summary>        public NameValueCollection QueryCollections        {            get;            set;        }        /// <summary>        /// 监控类型        /// </summary>        public enum MonitorType        {            Action = 1,            View = 2        }        /// <summary>        /// 获取监控指标日志        /// </summary>        /// <param name="mtype"></param>        /// <returns></returns>        public string GetLoginfo(MonitorType mtype = MonitorType.Action)        {            string ActionView = "Action执行时间监控:";            string Name = "Action";            if (mtype == MonitorType.View)            {                ActionView = "View视图生成时间监控:";                Name = "View";            }            string Msg = @"            {0}            ControllerName:{1}Controller            {8}Name:{2}            开始时间:{3}            结束时间:{4}            总 时 间:{5}秒            Form表单数据:{6}            URL参数:{7}                    ";            return string.Format(Msg,                ActionView,                ControllerName,                 ActionName,                ExecuteStartTime,                ExecuteEndTime,                 (ExecuteEndTime - ExecuteStartTime).TotalSeconds,                GetCollections(FormCollections),                GetCollections(QueryCollections),                Name);        }        /// <summary>        /// 获取Post 或Get 参数        /// </summary>        /// <param name="Collections"></param>        /// <returns></returns>        public string GetCollections(NameValueCollection Collections)        {            string Parameters = string.Empty;            if (Collections == null || Collections.Count == 0)            {                return Parameters;            }            foreach (string key in Collections.Keys)            {                Parameters += string.Format("{0}={1}&", key, Collections[key]);            }            if (!string.IsNullOrWhiteSpace(Parameters) && Parameters.EndsWith("&"))            {                Parameters = Parameters.Substring(0, Parameters.Length - 1);            }            return Parameters;        }    }

2、监控类

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]    public class StatisticsTrackerAttribute : ActionFilterAttribute,IExceptionFilter    {        private readonly string Key = "_thisOnActionMonitorLog_";        #region Action时间监控        public override void OnActionExecuting(ActionExecutingContext filterContext)        {            MonitorLog MonLog = new MonitorLog();            MonLog.ExecuteStartTime = Convert.ToDateTime(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.ffff", DateTimeFormatInfo.InvariantInfo));            MonLog.ControllerName = filterContext.RouteData.Values["controller"] as string;            MonLog.ActionName = filterContext.RouteData.Values["action"] as string;            filterContext.Controller.ViewData[Key] = MonLog;        }        public override void OnActionExecuted(ActionExecutedContext filterContext)        {            MonitorLog MonLog = filterContext.Controller.ViewData[Key] as MonitorLog;            MonLog.ExecuteEndTime = DateTime.Now;            MonLog.FormCollections = filterContext.HttpContext.Request.Form;//form表单提交的数据            MonLog.QueryCollections = filterContext.HttpContext.Request.QueryString;//Url 参数            LoggerHelper.Monitor(MonLog.GetLoginfo());        }        #endregion        #region View 视图生成时间监控        public override void OnResultExecuting(ResultExecutingContext filterContext)        {            MonitorLog MonLog = filterContext.Controller.ViewData[Key] as MonitorLog;            MonLog.ExecuteStartTime = DateTime.Now;                   }        public override void OnResultExecuted(ResultExecutedContext filterContext)        {            MonitorLog MonLog = filterContext.Controller.ViewData[Key] as MonitorLog;            MonLog.ExecuteEndTime = DateTime.Now;            LoggerHelper.Monitor(MonLog.GetLoginfo(MonitorLog.MonitorType.View));            filterContext.Controller.ViewData.Remove(Key);        }              #endregion        #region 错误日志        public void OnException(ExceptionContext filterContext)        {            if (!filterContext.ExceptionHandled)            {                string ControllerName =string.Format("{0}Controller",filterContext.RouteData.Values["controller"] as string);                string ActionName = filterContext.RouteData.Values["action"] as string;                string ErrorMsg = string.Format("在执行 controller[{0}] 的 action[{1}] 时产生异常", ControllerName, ActionName);                LoggerHelper.Error(ErrorMsg, filterContext.Exception);            }        }        #endregion    }

3、引用监控

我们可以在每个Controller类上或Action上直接引用 [StatisticsTracker]即可完成对该Controller或Action的监控。

我们也可以在FilterConfig.cs中注册全局监控,这样我们就可以监控每一个Controller中的Action,代码如下:

public class FilterConfig    {        public static void RegisterGlobalFilters(GlobalFilterCollection filters)        {            filters.Add(new HandleErrorAttribute());            //监控引用            filters.Add(new StatisticsTrackerAttribute());        }    }

LoggerHelper

  log文件的记录采用log4net,log4net是.Net下一个非常优秀的开源日志记录组件。log4net记录日志的功能非常强大。具体配置如下。

1、log4net配置文件

  log4Net的配置文件名称为log4net.config,具体配置如下。

技术分享
<?xml version="1.0"?><configuration>  <configSections>    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>  </configSections>  <log4net>    <!--错误日志-->    <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">      <file value=http://www.mamicode.com/"log\\LogError\\"/>      <appendToFile value=http://www.mamicode.com/"true"/>      <rollingStyle value=http://www.mamicode.com/"Date"/>      <datePattern value=http://www.mamicode.com/"yyyy\\yyyyMM\\yyyyMMdd‘.txt‘"/>      <staticLogFileName value=http://www.mamicode.com/"false"/>      <param name="MaxSizeRollBackups" value=http://www.mamicode.com/"100"/>      <layout type="log4net.Layout.PatternLayout">        <!--每条日志末尾的文字说明-->        <!--输出格式-->        <!--样例:2008-03-26 13:42:32,111 [10] INFO  Log4NetDemo.MainClass [(null)] - info-->        <conversionPattern value=http://www.mamicode.com/"%newline %n记录时间:%date %n线程ID:[%thread] %n日志级别:  %-5level %n错误描述:%message%newline %n"/>      </layout>    </appender>    <!--Info日志-->    <appender name="InfoAppender" type="log4net.Appender.RollingFileAppender">      <param name="File" value=http://www.mamicode.com/"Log\\LogInfo\\" />      <param name="AppendToFile" value=http://www.mamicode.com/"true" />      <param name="MaxFileSize" value=http://www.mamicode.com/"10240" />      <param name="MaxSizeRollBackups" value=http://www.mamicode.com/"100" />      <param name="StaticLogFileName" value=http://www.mamicode.com/"false" />      <param name="DatePattern" value=http://www.mamicode.com/"yyyy\\yyyyMM\\yyyyMMdd‘.txt‘" />      <param name="RollingStyle" value=http://www.mamicode.com/"Date" />      <layout type="log4net.Layout.PatternLayout">        <conversionPattern value=http://www.mamicode.com/"%newline %n记录时间:%date %n线程ID:[%thread] %n日志级别:  %-5level %n日志描述:%message%newline %n"/>      </layout>    </appender>    <!--监控日志-->    <appender name="MonitorAppender" type="log4net.Appender.RollingFileAppender">      <param name="File" value=http://www.mamicode.com/"Log\\LogMonitor\\" />      <param name="AppendToFile" value=http://www.mamicode.com/"true" />      <param name="MaxFileSize" value=http://www.mamicode.com/"10240" />      <param name="MaxSizeRollBackups" value=http://www.mamicode.com/"100" />      <param name="StaticLogFileName" value=http://www.mamicode.com/"false" />      <param name="DatePattern" value=http://www.mamicode.com/"yyyy\\yyyyMM\\yyyyMMdd‘.txt‘" />      <param name="RollingStyle" value=http://www.mamicode.com/"Date" />      <layout type="log4net.Layout.PatternLayout">        <conversionPattern value=http://www.mamicode.com/"%newline %n记录时间:%date %n线程ID:[%thread] %n日志级别:  %-5level %n跟踪描述:%message%newline %n"/>      </layout>    </appender>    <!--Error日志-->    <logger name="logerror">      <level value=http://www.mamicode.com/"ERROR" />      <appender-ref ref="RollingLogFileAppender" />    </logger>    <!--Info日志-->    <logger name="loginfo">      <level value=http://www.mamicode.com/"INFO" />      <appender-ref ref="InfoAppender" />    </logger>    <!--监控日志-->    <logger name="logmonitor">      <level value=http://www.mamicode.com/"Monitor" />      <appender-ref ref="MonitorAppender" />    </logger>  </log4net></configuration>
log4net.config

2、注册log4net配置文件

  在Global.asax中注册log4net配置文件,代码如下

protected void Application_Start()        {            //注册 log4net            log4net.Config.XmlConfigurator.Configure(               new System.IO.FileInfo(AppDomain.CurrentDomain.BaseDirectory + "\\Config\\log4net.config")           );            AreaRegistration.RegisterAllAreas();            WebApiConfig.Register(GlobalConfiguration.Configuration);            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);            RouteConfig.RegisterRoutes(RouteTable.Routes);            BundleConfig.RegisterBundles(BundleTable.Bundles);        }

3、LoggerHelper.cs

using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace Monitor.Models.ActionFilters{    public class LoggerHelper    {        static readonly log4net.ILog loginfo = log4net.LogManager.GetLogger("loginfo");        static readonly log4net.ILog logerror = log4net.LogManager.GetLogger("logerror");        static readonly log4net.ILog logmonitor = log4net.LogManager.GetLogger("logmonitor");        public static void Error(string ErrorMsg, Exception ex = null)        {            if (ex != null)            {                logerror.Error(ErrorMsg, ex);            }            else            {                logerror.Error(ErrorMsg);            }        }        public static void Info(string Msg)        {            loginfo.Info(Msg);        }        public static void Monitor(string Msg)        {            logmonitor.Info(Msg);        }    }}

4.log4net日志生成的文件目录结构如下图

技术分享

目录结构我们区分开了错误日志、Info日志、监控日志,并且会按照日期生成日志,方便我们查看。

 源代码

log4net 记录MVC监控日志