爱上MVC3系列~监视Action的运行时间,并提供超时记录机制

回到目录

文章出现的原因

很久没写关于MVC的文章了,原因是将关注点移向了MVVM和DDD这边,而这篇文章完全是因为公司项目的需要,因为公司网站总是不定时的502,而这由可能是程序超时所引起的,为了分析出现问题的点,所以,对action进行了监控,这个监控功能我选择了在global里注入全局的filter来实现这个功能,为了避免并发,所选择了将记录存储到cache的队列里,再通过quartZ的任务调度功能,来实现数据的IO写入或者数据库与入.

系统流程图

用代码说话

1 建立一个Filter

   /// <summary>

    /// Action渲染页面所需要的时间

    /// </summary>

    public class ActionRenderTimeAttribute : System.Web.Mvc.ActionFilterAttribute

    {

      



        /// <summary>

        /// 锁对象

        /// </summary>

        static object lockObj = new object();

        /// <summary>

        /// 记录进行Action的时间

        /// </summary>

        DateTime joinTime;

        /// <summary>

        /// 进行action之前

        /// </summary>

        /// <param name="filterContext"></param>

        public override void OnActionExecuting(System.Web.Mvc.ActionExecutingContext filterContext)

        {

            joinTime = DateTime.Now;

            base.OnActionExecuting(filterContext);

        }

        /// <summary>

        /// 渲染页面HTML之后

        /// </summary>

        /// <param name="filterContext"></param>

        public override void OnResultExecuted(System.Web.Mvc.ResultExecutedContext filterContext)

        {

            int outSeconds;//! 超时的秒数,默认为60S

            int.TryParse((System.Configuration.ConfigurationManager.AppSettings["ActionRenderTime"] ?? "60").ToString(), out outSeconds);

            var timeSpan = (DateTime.Now - joinTime).Seconds;

            if (timeSpan > outSeconds)

            {

                lock (lockObj)

                {

                    var temp = (System.Web.HttpRuntime.Cache["RunTime"] as Queue<Tuple<int, string>>) ?? new Queue<Tuple<int, string>>();

                    temp.Enqueue(new Tuple<int, string>(timeSpan, filterContext.RequestContext.HttpContext.Request.Url.AbsoluteUri));

                    System.Web.HttpRuntime.Cache.Insert("RunTime", temp);

                }

            }



            base.OnResultExecuted(filterContext);

        }





    }

2 为filter加全局注入点

 public class FilterConfig

    {

        public static void RegisterGlobalFilters(GlobalFilterCollection filters)

        {

            filters.Add(new HandleErrorAttribute());

            filters.Add(new MVVM.ActionRenderTimeAttribute());

        }

    }

3 建立一个QuartZ的任务

   /// <summary>

    /// 工作任务基类

    /// </summary>

    public abstract class JobBase

    {

        /// <summary>

        /// log4日志对象

        /// </summary>

        protected log4net.ILog Logger

        {

            get

            {

                return log4net.LogManager.GetLogger(this.GetType());//得到当前类类型(当前实实例化的类为具体子类)

            }

        }

    }
    public class ActionTimeJob : JobBase, IJob

    {



        #region Fields & Properties

        /// <summary>

        /// 锁对象

        /// </summary>

        private static object lockObj = new object();

        #endregion



        #region IJob 成员



        public void Execute(IJobExecutionContext context)

        {

            lock (lockObj)

            {

                try

                {

                    if ((System.Web.HttpRuntime.Cache["RunTime"] as Queue<Tuple<int, string>>) != null

                        && (System.Web.HttpRuntime.Cache["RunTime"] as Queue<Tuple<int, string>>).Count > 0)

                    {

                        var temp = (System.Web.HttpRuntime.Cache["RunTime"] as Queue<Tuple<int, string>>).Dequeue();

                        if (temp != null)

                        {

                            //! 超时,开始记录日志

                            global::Logger.Core.LoggerFactory.Instance.Logger_Info(

                                        string.Format("出现异常的页面:{0},页面加载需要的时间:{1}秒,异常发生时间:{2}"

                                        , temp.Item2, temp.Item1, DateTime.Now),"actionTime.log");

                        }

                    }

                }

                catch (Exception ex )

                {



                    throw ex;

                }

            }

        }



        #endregion

    }

4 在global里配置QuartZ注入点

#region quartZ调度中心

            const string DEFAULTINTERVAL = "300";//默认为5分钟

            string user_Classroom_RJobInterval = ConfigurationManager.AppSettings["ActionRunTimeJob"]

          ?? DEFAULTINTERVAL;



            ISchedulerFactory sf = new Quartz.Impl.StdSchedulerFactory();

            IScheduler sched = sf.GetScheduler();

            //一个工作可以由多个组组成,而每个组又可以由多个trigger组成

            IDictionary<IJobDetail, IList<ITrigger>> scheduleJobs = new Dictionary<IJobDetail, IList<ITrigger>>();



            #region ActionRunTimeJob

            scheduleJobs.Add(JobBuilder.Create<ActionTimeJob>()

               .WithIdentity("job1", "group1")

               .Build(),

               new List<ITrigger> 

                    { 

                     (ICronTrigger)TriggerBuilder.Create()

                                                 .WithIdentity("trigger", "group1")

                                                 .WithCronSchedule(user_Classroom_RJobInterval)

                                                 .Build() 

                    });



            sched.ScheduleJobs(scheduleJobs, true);

            sched.Start();

            #endregion

            #endregion

5 在config里配置相关调度和性能监控的信息

    <!-- 每次得到的数据行数,以便减少内存的占用-->

    <add key="DataRow" value="1"/>

    <!-- 每3秒执行一次-->

    <add key="ActionRunTimeJob" value="0/3 * * * * ?"/>

    <!-- 每页面渲染时间超时为1秒-->

    <add key="ActionRenderTime" value="1"/>

    <!-- 是否开启action性能监控-->

    <add key="isActionRender" value="1"/>

6 程序效果截图

回到目录

你可能感兴趣的:(action)