无侵入方面编程-用HttpModule+SoapExtension监视页面执行参数(一)
先简单介绍一下项目吧,我们这个项目是用VS2003开发的,老早一个项目。WEB前端机+业务处理(WebService层)+数据库分别布置在不同的计算机上。
现在老总有一个需求,要统计出每个页面的执行时间,以及每次调用过哪些WebService方法,调用的时间等参数。
可行的方案有好多,但我感觉使用HttpModule+SoapExtension,可以不在改变目标系统源码的基础上,完成这项工作。也许有一天,老总说,现在不需要再统计了,我就直接配置一下,不再统计就行了。
由于要调用WebService,我们采用编写一个SoapExtension,在它的ProcessMessage函数中,在message.Stage是 BeforeSerialize 时,记一个开始时间,并采集一些数据,在message.Stage==AfterDeserialize时,再采集一些时间等数据。最后通过HttpContext.Current.Items[WSInvokeMonitorKey]获取HttpModule的对象,把采集到的数据放在HttpModule里面。
在HttpModule层,我们可以context的BeginRequest、PreRequestHandlerExecute、PreSendRequestContent、EndRequest中采集数据,最后写入通过Log4net写入日志文件。
具体实现起来,应该很简单,高手可以略过了。
先看看如何使用吧,只需在Web.Config中加一条配置:
<configuration>
<system.web>
<httpModules>
<add name="WSInvokeMonitorHttpModule" type="Hebmc.WebTools.WSInvokeMonitor.WSInvokeMonitorHttpModule,WSInvokeMonitor"/>
</httpModules>
<webServices>
<soapExtensionTypes>
<add type="Hebmc.WebTools.WSInvokeMonitor.SimpleWSInvokeMonitorExtension,WSInvokeMonitor"
priority="1"
group="0" />
</soapExtensionTypes>
</webServices>
</system.web>
</configuration>
SoapExtension实现:
public class SimpleWSInvokeMonitorExtension : SoapExtension
{
private const string WSInvokeMonitorKey = "__WSInvokeMonitorKey__";
private WSInvokeInfo invokeInfo = new WSInvokeInfo();
public override System.IO.Stream ChainStream(System.IO.Stream stream)
{
return stream;
} public override object GetInitializer(Type serviceType)
{
return null;
} public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
{
return null;
} public override void Initialize(object initializer)
{ } public override void ProcessMessage(SoapMessage message)
{
if(message is SoapClientMessage)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeSerialize: //采集时间
this.invokeInfo.BeginInvokeTime = DateTime.Now;
//采集WebService方法名
this.invokeInfo.MethodName = message.MethodInfo.Name;
break; case SoapMessageStage.AfterSerialize:
break; case SoapMessageStage.BeforeDeserialize:
break; // About to call methods
case SoapMessageStage.AfterDeserialize: //采集时间
this.invokeInfo.EndInvokeTime = DateTime.Now; PageInfo pageInfo = (PageInfo)HttpContext.Current.Items[WSInvokeMonitorKey] ;
if(pageInfo != null)
{
//添加到Module记录
pageInfo.AppendInvokeInfo(this.invokeInfo);
} break; // After Method call default:
throw new Exception("No stage such as this");
} }
else if(message is SoapServerMessage)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeDeserialize:
break; case SoapMessageStage.AfterDeserialize:
break; case SoapMessageStage.BeforeSerialize:
break; case SoapMessageStage.AfterSerialize:
break; default:
throw new Exception("No stage such as this");
} }
} }
HttpModule实现:
public class WSInvokeMonitorHttpModule : IHttpModule
{
private static ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private const string WSInvokeMonitorKey = "__WSInvokeMonitorKey__";
HttpApplication httpApp = null; #region IHttpModule 成员 public void Init(HttpApplication webApp)
{
this.httpApp = webApp; //注册事件
this.httpApp.BeginRequest+=new EventHandler(context_BeginRequest);
this.httpApp.PreRequestHandlerExecute+=new EventHandler(httpApp_PreRequestHandlerExecute);
this.httpApp.PreSendRequestContent+=new EventHandler(context_PreSendRequestContent);
this.httpApp.EndRequest+=new EventHandler(context_EndRequest);
} public void Dispose()
{
this.httpApp.BeginRequest-=new EventHandler(context_BeginRequest);
this.httpApp.PreSendRequestContent-=new EventHandler(context_PreSendRequestContent);
this.httpApp.EndRequest-=new EventHandler(context_EndRequest);
} #endregion private void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication webApp = sender as HttpApplication;
if(webApp != null)
{
PageInfo pageInfo = null;
//开始时,设置数据对象,将来采集到的数据都放在这里
webApp.Context.Items[WSInvokeMonitorKey] = pageInfo = new PageInfo(); //采集路径
pageInfo.PageUri = webApp.Context.Request.Url.ToString();
}
} private void httpApp_PreRequestHandlerExecute(object sender, EventArgs e)
{
HttpApplication webApp = sender as HttpApplication;
if(webApp != null)
{
Page page = webApp.Context.Handler as Page;
if(page != null)
{
PageInfo pageInfo = (PageInfo)webApp.Context.Items[WSInvokeMonitorKey];
if(pageInfo != null)
{
//采集处理类名,及时间
pageInfo.TypeName = page.GetType().FullName;
pageInfo.PreRequestHandlerExecuteTime = DateTime.Now;
}
} }
} private void context_PreSendRequestContent(object sender, EventArgs e)
{
HttpApplication webApp = sender as HttpApplication;
if(webApp != null)
{
Page page = webApp.Context.Handler as Page;
if(page != null)
{
PageInfo pageInfo = (PageInfo)webApp.Context.Items[WSInvokeMonitorKey];
if(pageInfo != null)
{
try
{
//采集时间
pageInfo.PreSendRequestContentTime = DateTime.Now; if(log.IsInfoEnabled)
{
//记日志
string xmlData = string.Empty;
XmlSerializer xs = new XmlSerializer(typeof(PageInfo));
StringBuilder sb = new StringBuilder();
using(MemoryStream ms = new MemoryStream())
{
XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8);
xtw.Formatting = Formatting.None;
xs.Serialize(xtw, pageInfo);
ms.Position = 0; StreamReader sr = new StreamReader(ms, Encoding.UTF8);
xmlData = sr.ReadToEnd();
} TimeSpan tsExecute = pageInfo.EndRequestTime - pageInfo.BeginRequestTime;
log.InfoFormat("{0},{1},{2}MS,{3},{4},{5}",
pageInfo.BeginRequestTime,
pageInfo.TypeName,
tsExecute.TotalMilliseconds,
pageInfo.WSInvokeCount,
pageInfo.PageUri,
xmlData); }
}
catch (System.Exception ex)
{
log.Error(ex);
}
}
}
}
} private void context_EndRequest(object sender, EventArgs e)
{
HttpApplication webApp = sender as HttpApplication;
if(webApp != null)
{
Page page = webApp.Context.Handler as Page;
if(page != null)
{
PageInfo pageInfo = (PageInfo)webApp.Context.Items[WSInvokeMonitorKey];
if(pageInfo != null)
{
//采集时间
pageInfo.EndRequestTime = DateTime.Now;
} }
}
} }
用到的数据类:
namespace Hebmc.WebTools.WSInvokeMonitor.Data
{
[Serializable]
public class PageInfo
{
private string typeName;
private string pageUri;
private DateTime beginRequestTime = DateTime.Now;
private DateTime preRequestHandlerExecuteTime = DateTime.Now;
private DateTime endRequestTime = DateTime.Now;
private DateTime preSendRequestContentTime = DateTime.Now;
private ArrayList wsInvokeInfoList = new ArrayList(); /// <summary>
/// 类名
/// </summary>
public string TypeName
{
get { return typeName; }
set { typeName = value; }
} /// <summary>
/// 页面URI
/// </summary>
public string PageUri
{
get { return pageUri; }
set { pageUri = value; }
} /// <summary>
/// 开始时间
/// </summary>
public System.DateTime BeginRequestTime
{
get { return beginRequestTime; }
set { beginRequestTime = value; }
} /// <summary>
/// 开始处理时间
/// </summary>
public System.DateTime PreRequestHandlerExecuteTime
{
get { return preRequestHandlerExecuteTime; }
set { preRequestHandlerExecuteTime = value; }
} /// <summary>
/// 结束处理时间
/// </summary>
public System.DateTime EndRequestTime
{
get { return endRequestTime; }
set { endRequestTime = value; }
} /// <summary>
/// 向客户端发送数据开始时间
/// </summary>
public System.DateTime PreSendRequestContentTime
{
get { return preSendRequestContentTime; }
set { preSendRequestContentTime = value; }
} /// <summary>
/// 调用次数
/// </summary>
[XmlIgnore]
public int WSInvokeCount
{
get
{
return this.wsInvokeInfoList.Count;
}
} /// <summary>
/// 该页面调用的WebService信息
/// </summary>
public WSInvokeInfo[] WSInvokeInfos
{
get
{
return (WSInvokeInfo[])wsInvokeInfoList.ToArray(typeof(WSInvokeInfo));
}
set
{
wsInvokeInfoList.AddRange(value);
}
} /// <summary>
/// 添加一个调用WebService日志
/// </summary>
/// <param name="info"></param>
public void AppendInvokeInfo(WSInvokeInfo info)
{
wsInvokeInfoList.Add(info);
} /// <summary>
/// 序列化需要
/// </summary>
public PageInfo()
{}
} [Serializable]
public class WSInvokeInfo
{
private string methodName;
private DateTime beginInvokeTime = DateTime.Now;
private DateTime endInvokeTime = DateTime.Now; /// <summary>
/// 函数名
/// </summary>
public string MethodName
{
get { return methodName; }
set { methodName = value; }
} /// <summary>
/// 开始调用时间
/// </summary>
public System.DateTime BeginInvokeTime
{
get { return beginInvokeTime; }
set { beginInvokeTime = value; }
} /// <summary>
/// 结束调用时间
/// </summary>
public System.DateTime EndInvokeTime
{
get { return endInvokeTime; }
set { endInvokeTime = value; }
} }
}
OK了,这个方案还可以继续深入,可以使用SoapExtension把WebService层的采集到的数据,也拉到前端。这样便可以知道一个WebService方法执行几次数据库连接。嘿嘿。
http://www.cnblogs.com/evlon/archive/2009/05/22/1486866.html
无侵入方面编程-用HttpModule+SoapExtension监视页面执行参数(一)的更多相关文章
- 无侵入方面编程-用HttpModule+SoapExtension监视页面执行参数(二)
上一篇文章 "无侵入方面编程-用HttpModule+SoapExtension监视页面执行参数(一)"中,我们实现了监视每个页面的执行情况和调用WebService的简单信息. ...
- Android平台免Root无侵入AOP框架Dexposed使用详解
Dexposed是基于久负盛名的开源Xposed框架实现的一个Android平台上功能强大的无侵入式运行时AOP框架. Dexposed的AOP实现是完全非侵入式的,没有使用任何注解处理器,编织器或者 ...
- Android免Root无侵入AOP框架Dexposed
Dexposed框架是阿里巴巴无线事业部近期开源的一款在Android平台下的免Root无侵入运行期AOP框架,该框架基于AOP思想,支持经典的AOP使用场景,可应用于日志记录,性能统计,安全控制,事 ...
- Dexposed:android免Root无侵入Aop框架
在网上看到了阿里推出的一个android开源项目,名为Dexposed, 是一个Android平台下的无侵入运行期AOP框架.旨在解决像性能监控.在线热补丁等移动开发常见难题,典型使用场景为: AOP ...
- 无插件Vim编程技巧
无插件Vim编程技巧 http://bbs.byr.cn/#!article/buptAUTA/59钻风 2014-03-24 09:43:46 发表于:vim 相信大家看过<简明Vim教程& ...
- 单点登录CAS使用记(八):使用maven的overlay实现无侵入的改造CAS
前期在学习CAS部署的过程中,都是网上各种教程,各种方案不停的尝试. 期间各种侵入改源码,时间久了,改了哪个文件,改了哪段配置,增加了哪段代码,都有可能混淆不清了. 而且最大的问题是,万一换个人来维护 ...
- 发布时去掉 debug 和 提醒日志,简单无侵入
在 proguard 文件中加入下面代码,让发布时去掉 debug 和 提醒日志,简单无侵入! -assumenosideeffects class android.util.Log { public ...
- 无插件VIM编程技巧(网摘)
无插件VIM编程技巧 原文出处:[陈皓 coolshell] 相信大家看过<简明Vim教程>也玩了<Vim大冒险>的游戏了,相信大家对Vim都有一个好的入门了.我在这里把我日常 ...
- Hook 无侵入式埋点(页面统计)
一.技术原理 Method-Swizzling 黑魔法 方法交换(不懂的可以查) 二.页面统计 某盟页面统计SDK需要开发者在APP基类里实现ViewDidAppear和viewDidDisappea ...
随机推荐
- Mysql源码目录结构
Programs for handling SQL commands. The "core" of MySQL. These are the .c and .cc files in ...
- 使用git提交github代码
新的项目的提交 touch README.md git init git add README.md git commit -m "first commit" git remote ...
- sql server 创建文件组,文件
添加文件组: --ADD FILEGROUP 增加文件组 ALTER DATABASE TestHekaton ADD FILEGROUP [Report] ALTER DATABASE TestH ...
- java_list,set,map集合
一.集合定义 集合就是讲诺干用途相同.近似的“数据”结合成一个整体 集合从体系上分为三种 1.列表(List):List集合区分元素的顺序,允许包含相同的元素 2.集(set):Set集合不区分元素的 ...
- linux包之sysstat之sar命令
要启动SAR,必须通过cron工具以周期性的间隔启动.安装sysstat包后,默认创建一个/etc/cron.d/sysstat文件,其默认内容为:# run system activity acco ...
- web的各种前端打印方法之CSS控制网页打印样式
来源:http://www.jb51.net/web/70358.html CSS控制网页打印样式: 使用CSS控制打印样式,握刚刚使用时一塌糊涂,根本不知道CSS中的midia的作用是什么,问到别人 ...
- 内联样式自动出现,一般是js控制写入的
内联样式自动出现,一般是js控制写入的
- 通过Profiles查看create语句的执行时间消耗 (转)
一,查看profiles的状态值 1,查看profiles是否已经打开了,默认是不打开的. mysql> show profiles; Empty set (0.02 sec) my ...
- Message,MessageQueue,Looper,Handler详解+实例
Message,MessageQueue,Looper,Handler详解+实例 原文地址 Android的Handler使用(这篇简单介绍Handler的使用) 一.几个关键概念 1.Message ...
- .Net分布式缓存应用实例:Couchbase
转自:http://www.cnblogs.com/wu-jian Couchbase概述 Couchbase最早叫Membase,是由Memcached项目组的一些头目另立的山头. 2011年与Co ...