zoukankan      html  css  js  c++  java
  • 无侵入方面编程-用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

  • 相关阅读:
    lmdb简介——结合MVCC的B+树嵌入式数据库
    influxdb和boltDB简介——MVCC+B+树,Go写成,Bolt类似于LMDB,这个被认为是在现代kye/value存储中最好的,influxdb后端存储有LevelDB换成了BoltDB
    时序列数据库选型
    VoltDB介绍——本质:数据保存在内存,充分利用CPU,单线程去锁,底层数据结构未知
    关于时间序列数据库的思考——(1)运用hash文件(例如:RRD,Whisper) (2)运用LSM树来备份(例如:LevelDB,RocksDB,Cassandra) (3)运用B-树排序和k/v存储(例如:BoltDB,LMDB)
    241. Different Ways to Add Parentheses——本质:DFS
    麦克风阵列技术入门(3)
    [LeetCode]Palindrome Partitioning 找出所有可能的组合回文
    Linux在简短而经常使用的命令
    数据结构c字符串操作语言版本
  • 原文地址:https://www.cnblogs.com/chen110xi/p/5715542.html
Copyright © 2011-2022 走看看