由于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 = ,
View =
}
/// <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 == )
{
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(, Parameters.Length - );
}
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="log\\LogError\\"/>
<appendToFile value="true"/>
<rollingStyle value="Date"/>
<datePattern value="yyyy\\yyyyMM\\yyyyMMdd'.txt'"/>
<staticLogFileName value="false"/>
<param name="MaxSizeRollBackups" value=""/>
<layout type="log4net.Layout.PatternLayout">
<!--每条日志末尾的文字说明-->
<!--输出格式-->
<!--样例:-- ::, [] 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="" />
<param name="MaxSizeRollBackups" value="" />
<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="" />
<param name="MaxSizeRollBackups" value="" />
<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日志生成的文件目录结构如下图

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

源代码

log4net 记录MVC监控日志的更多相关文章

  1. 学习总结 之 WebApi服务监控 log4net记录监控日志

    在请求WebApi 的时候,我们更想知道在请求数据的时候,调用了哪个接口传了什么参数过来,调用这个Action花了多少时间,有没有人恶意请求.我们可以通过记录日志,对Action进行优化,可以通过日志 ...

  2. 如何使用Apache log4net库与ASP.NET MVC 5日志记录

    在运行软件程序的时候,跟踪和监控日志是一种记录过程的好方法. 简介: 在运行软件程序的时候,跟踪和监控日志是一种记录过程的好方法.尤其在应用程序出错的时候,日志是我们最需要的文件.不管是在web,wi ...

  3. 在ASP.NET MVC中使用Log4Net记录异常日志,出错时导向到静态页

    本篇体验在ASP.NET MVC 4中使用Log4Net记录日志. 通过NuGet安装Log4Net. 需求是:当出错时导向到Error.html静态页面,Log4Net记录错误信息. 大致的思路是: ...

  4. ASP.NET MVC中Log4Net记录错误日志的使用

    第一.在管理NuGet程序包 =>下载 Log4Net 第二.在web.config配置Log4Net 1:在<configuration>节点下 <configSection ...

  5. Log4Net在MVC下的配置以及运用线程队列记录异常信息

    Log4Net是用来记录日志的,可以将程序运行过程中的信息输出到一些地方(文件.数据库.EventLog等),日志就是程序的黑匣子,可以通过日志查看系统的运行过程,从而发现系统的问题.日志的作用:将运 ...

  6. log4net记录系统错误日志到文本文件用法详解(最新)

    此配置文件可以直接拿来用,配置文件上面有详细用法说明,里面也有详细注释说明.此配置文件涵盖按照日期记录和按照文件大小(建议)的实例. 又包括:按照Fatal.Info.Error.Debug.Warn ...

  7. C# 使用Log4Net记录程序日志

    在之前的博客中,写过使用系统内置的Trace类记录程序日志,具体请参考:C# 使用Trace记录程序日志.这篇博客将介绍如何使用Log4Net记录程序日志. 首先需要引用Log4Net.dll,我们可 ...

  8. C#中四步轻松使用log4net记录本地日志

    在这里,记录我在项目中使用log4net记录本地日志的步骤.在不会之前感觉很难,很神秘,一旦会了之后其实没那么难.其实所有的事情都是一样的,下面我就分享一下我使用log4Net的经验. 第一步:首先从 ...

  9. WebForm应用log4net记录错误日志——使用线程列队写入

    我的项目结构如下图: 日志帮助类库需要log4net包:工具—NuGet包管理器—管理解决方案NuGet程序包 线程日志帮助类 FlashLogger.cs 代码 using System; usin ...

随机推荐

  1. [IOS]Swift 遍历预制的本地资源文件

    我事先放了一堆svg文件,但是我是批量使用的,想要直接遍历他们加入到一个list中来,那我直接就遍历他们的名称,把他们的名字组成一个array. var ss:NSString = NSBundle. ...

  2. Xamarin的不归路-生成安卓错误2

    错误提示: 解决方案:升级Andr​​oid sdk到Andr​​oid6.0即API23重新编译即可. Andr​​oid版本较低的手机如何使用? 你只需要编译和目标设定为6.0,根据需要设置最低A ...

  3. 跨域无法获取自定义header的问题

    同域的时候,header里面的参数可以随便自己定义.服务端都是可以获取的. 但是跨域的时候,除了设置 <add name="Access-Control-Allow-Origin&qu ...

  4. Java虚拟机

    虚拟机每次方法的调用和返回都伴随着栈帧的入栈和出栈,而每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用(表明该栈帧执行的是哪个方法),持有这个引用是为了支持方法调用中的动态连接.这些符号引用中 ...

  5. C/C++编译和链接过程详解 (重定向表,导出符号表,未解决符号表)

    详解link  有 些人写C/C++(以下假定为C++)程序,对unresolved external link或者duplicated external simbol的错误信息不知所措(因为这样的错 ...

  6. RazorEngine 3.3 在Mono 3.2上正常运行

    RazorEngine 是一个简化的模板引擎基于微软新的Razor 解析引擎, Razor是在 ASP.NET MVC3 和 Web Pages中引入的.RazorEngine 提供了一个外包装和额外 ...

  7. NodeJS入门(四)—— path对象

    很快Node就会迎来4.0的时代,届时将并入现有的iojs,所以先前写过的iojs入门系列直接更名为NodeJS入门. 本篇开始将逐个介绍Node的各主要模块,依循API文档走一遍,但会给出比API文 ...

  8. Lesson 9 A cold welcome

    Text On Wednesday evening, we went to the Town Hall. It was the last day of the year and a large cro ...

  9. Mysql 主从延时监控

    200 ? "200px" : this.width)!important;} --> 介绍 主从延时在主从环境中是一个非常值得关注的问题,有时候我们可以通过show sla ...

  10. Javascript闭包和C#匿名函数对比分析

    C#中引入匿名函数,多少都是受到Javascript的闭包语法和面向函数编程语言的影响.人们发现,在表达式中直接编写函数代码是一种普遍存在的需求,这种语法将比那种必须在某个特定地方定义函数的方式灵活和 ...