log4net 记录MVC监控日志

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

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

log4net 记录MVC监控日志

监控程序实现

  改监控程序主要继承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,具体配置如下。

log4net 记录MVC监控日志
<?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="log\\LogError\\"/>

      <appendToFile value="true"/>

      <rollingStyle value="Date"/>

      <datePattern value="yyyy\\yyyyMM\\yyyyMMdd'.txt'"/>

      <staticLogFileName value="false"/>

      <param name="MaxSizeRollBackups" value="100"/>

      <layout type="log4net.Layout.PatternLayout">

        <!--每条日志末尾的文字说明-->

        <!--输出格式-->

        <!--样例:2008-03-26 13:42:32,111 [10] INFO  Log4NetDemo.MainClass [(null)] - info-->

        <conversionPattern value="%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="Log\\LogInfo\\" />

      <param name="AppendToFile" value="true" />

      <param name="MaxFileSize" value="10240" />

      <param name="MaxSizeRollBackups" value="100" />

      <param name="StaticLogFileName" value="false" />

      <param name="DatePattern" value="yyyy\\yyyyMM\\yyyyMMdd'.txt'" />

      <param name="RollingStyle" value="Date" />

      <layout type="log4net.Layout.PatternLayout">

        <conversionPattern value="%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="Log\\LogMonitor\\" />

      <param name="AppendToFile" value="true" />

      <param name="MaxFileSize" value="10240" />

      <param name="MaxSizeRollBackups" value="100" />

      <param name="StaticLogFileName" value="false" />

      <param name="DatePattern" value="yyyy\\yyyyMM\\yyyyMMdd'.txt'" />

      <param name="RollingStyle" value="Date" />

      <layout type="log4net.Layout.PatternLayout">

        <conversionPattern value="%newline %n记录时间:%date %n线程ID:[%thread] %n日志级别:  %-5level %n跟踪描述:%message%newline %n"/>

      </layout>

    </appender>

    <!--Error日志-->

    <logger name="logerror">

      <level value="ERROR" />

      <appender-ref ref="RollingLogFileAppender" />

    </logger>

    <!--Info日志-->

    <logger name="loginfo">

      <level value="INFO" />

      <appender-ref ref="InfoAppender" />

    </logger>

    <!--监控日志-->

    <logger name="logmonitor">

      <level value="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日志生成的文件目录结构如下图

log4net 记录MVC监控日志

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

 源代码

你可能感兴趣的:(mvc)