统计WebService的调用者、调用函数、运行时间

系统WebServic分布太久了, 都不知道哪些系统在用? 调用的哪些函数?于是乎,写一个Soap Extension, 再加一个页面,来查询一下。

先看一下配制说明,和效果

web.config中

    <system.web>
        <compilation debug="true" targetFramework="4.0" />
      <!--<httpHandlers>
        <add path="dl" type="OA4.SOA.Impl.HttpHandler.DownloadAttach" verb="GET"/>
      </httpHandlers>-->
      <webServices>
        <soapExtensionTypes>
          <add type=" OA4.CommonLib.Soap.TimeWatchExtension,OACommonLib"
              priority="1"
              group="0" />
        </soapExtensionTypes>
      </webServices>

    </system.web>

  

然后访问查询页面:

 

当前运行:0

最后记录:20,	3.0 (Call/S), 27.8 (MS/Call)
Host:10.129.255.105,  UseTime:0, Time:2012-9-4 9:15:42, name:GetCanStarFlowList,Arg:AComp:=衡水分公司, ADept:=县公司, AUser:=杨立华
Host:10.129.255.105,  UseTime:15.6249, Time:2012-9-4 9:15:42, name:GetAgendumList,Arg:sUserName:=杨立华, sCompany:=衡水分公司, sDepartment:=县公司, sDuty:=经理, sRole:=, type:=all, dbfield:=ReceiveTime, order:=ASC, pageSize:=25, pageNumber:=1, pageCount:=0, recordCount:=0
Host:10.129.255.104,  UseTime:46.8747, Time:2012-9-4 9:15:43, name:GetBillData_done,Arg:ABillID:=54533f29-8979-4b1d-adf8-b8fbf2cf7678, year:=
Host:10.129.255.104,  UseTime:0, Time:2012-9-4 9:15:43, name:GetCurrentActivityName,Arg:flowInstanceId:=54533f29-8979-4b1d-adf8-b8fbf2cf7678
Host:10.129.255.218,  UseTime:15.6249, Time:2012-9-4 9:15:43, name:GetAgendumList,Arg:sUserName:=耿书芬, sCompany:=邯郸分公司, sDepartment:=广平分公司, sDuty:=, sRole:=, type:=all, dbfield:=ReceiveTime, order:=DESC, pageSize:=20, pageNumber:=1, pageCount:=0, recordCount:=0
Host:10.129.255.216,  UseTime:15.6249, Time:2012-9-4 9:15:45, name:GetAgendumList,Arg:sUserName:=魏广芹, sCompany:=张家口分公司, sDepartment:=渠道管理中心, sDuty:=, sRole:=, type:=all, dbfield:=ReceiveTime, order:=DESC, pageSize:=20, pageNumber:=1, pageCount:=0, recordCount:=0
Host:10.129.255.104,  UseTime:46.8747, Time:2012-9-4 9:15:46, name:GetUserInfo,Arg:userName:=caoruifen_sjz
Host:10.129.255.104,  UseTime:0, Time:2012-9-4 9:15:46, name:GetDoingFlowInfo,Arg:activeInstId:=c1e1d9ef-6a8f-46e8-98d1-dedac3c6137c
Host:10.129.255.104,  UseTime:0, Time:2012-9-4 9:15:46, name:GetActiveInstInfo,Arg:activeInstID:=c1e1d9ef-6a8f-46e8-98d1-dedac3c6137c, parentBillID:=47a88d95-05db-4c24-a18c-ff41620495a0
Host:10.129.255.104,  UseTime:62.4996, Time:2012-9-4 9:15:46, name:GetBillData_done,Arg:ABillID:=e14d1f34-53b5-4824-afd9-f8207dc4bab3, year:=
Host:10.129.255.104,  UseTime:15.6249, Time:2012-9-4 9:15:46, name:UpdateRead,Arg:ActivityInstanceID:=c1e1d9ef-6a8f-46e8-98d1-dedac3c6137c
Host:10.129.255.104,  UseTime:15.6249, Time:2012-9-4 9:15:46, name:FindNextRouteReturnConnects,Arg:sFlowID:=ae76d210-85f3-403f-ba4b-485c72cbb96e, sFlowInstanceID:=e14d1f34-53b5-4824-afd9-f8207dc4bab3, sActivityID:=c16d997c-f471-49f1-adef-e64cad616d79
Host:10.129.255.104,  UseTime:234.3735, Time:2012-9-4 9:15:47, name:GetBillData_done,Arg:ABillID:=da7276c9-80af-485a-975a-f881be30b0f2, year:=2008
Host:10.129.255.105,  UseTime:15.6249, Time:2012-9-4 9:15:47, name:GetActiveInstInfo,Arg:activeInstID:=4b19dfbc-51e7-4a0f-b3ce-08e17e49f64b, parentBillID:=266d7ab5-57fe-48fc-9118-27b43d1e5f10
Host:10.129.255.105,  UseTime:46.8747, Time:2012-9-4 9:15:47, name:GetBillData_done,Arg:ABillID:=32d11123-7ab0-4757-ba57-5d3e53b8eafe, year:=
Host:10.129.255.105,  UseTime:31.2498, Time:2012-9-4 9:15:47, name:UpdateRead,Arg:ActivityInstanceID:=4b19dfbc-51e7-4a0f-b3ce-08e17e49f64b
Host:10.129.255.105,  UseTime:0, Time:2012-9-4 9:15:47, name:FindNextRouteReturnConnects,Arg:sFlowID:=ae76d210-85f3-403f-ba4b-485c72cbb96e, sFlowInstanceID:=32d11123-7ab0-4757-ba57-5d3e53b8eafe, sActivityID:=12e9306a-5107-493f-8ac9-8966011bd0fc
Host:10.129.255.104,  UseTime:0, Time:2012-9-4 9:15:47, name:GetCurrentActivityName,Arg:flowInstanceId:=da7276c9-80af-485a-975a-f881be30b0f2
Host:10.129.255.104,  UseTime:0, Time:2012-9-4 9:15:47, name:GetWordField,Arg:flowInstID:=da7276c9-80af-485a-975a-f881be30b0f2
Host:10.129.255.104,  UseTime:0, Time:2012-9-4 9:15:47, name:SaveFavorite,Arg:userName:=张翔凯, flowInstID:=7d03a4a1-07ff-4bdc-b2a4-cb381fec357f

  

 

实现代码:Soap

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Services.Protocols;
using System.Web;
using System.Collections.Specialized;
using System.Collections.Concurrent;
using System.Collections;
using log4net;
using System.Threading;

namespace OA4.CommonLib.Soap
{
    public class TimeWatchExtension : SoapExtension
    {
        protected static ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        private static ConcurrentDictionary<Guid, WSInvokeInfo> running = new System.Collections.Concurrent.ConcurrentDictionary<Guid, WSInvokeInfo>();

        private static ConcurrentQueue<WSInvokeInfo> last = new ConcurrentQueue<WSInvokeInfo>();

        private static ConcurrentDictionary<string, ConcurrentQueue<WSInvokeInfo>> remoteUserHost = new ConcurrentDictionary<string, ConcurrentQueue<WSInvokeInfo>>();


        public static ConcurrentDictionary<Guid, WSInvokeInfo> Running { get { return running; } }

        public static ConcurrentQueue<WSInvokeInfo> LastInvoke { get { return last; } }

        public static RemoteHostInfo[] RemoteUserHost { get { return remoteUserHost.ToList().ConvertAll(d=>new RemoteHostInfo(){ Host = d.Key, LastInvoke = d.Value.ToArray()}).ToArray(); } }

        public static int MaxRunningMilliseconds = int.Parse(System.Configuration.ConfigurationManager.AppSettings["TimeWatchExtension.MaxRunningMilliseconds"] ?? "800");

        public static Timer timerSnap = null;
        static TimeWatchExtension()
        {
            timerSnap = new Timer(new TimerCallback(e => {

                if (Running.Count > 0)
                {
                    var running = Running.ToList();

                    running.ForEach(d => {
                        if (d.Value.UseTime.TotalMilliseconds > MaxRunningMilliseconds)
                        {
                            log.Warn(d.Value.ToString());
                        }
                    });
                }
            
            }));

            timerSnap.Change(1000, 1000);
        }



        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:

                        break;


                    case SoapMessageStage.AfterSerialize:
                        break;


                    case SoapMessageStage.BeforeDeserialize:
                        break;

                    // About to call methods
                    case SoapMessageStage.AfterDeserialize:
                        break;

                    // After Method call
                    default:
                        throw new Exception("No stage such as this");
                }

            }
            else if (message is SoapServerMessage)
            {
                SoapServerMessage msg = (SoapServerMessage)message;
                switch (message.Stage)
                {
                    case SoapMessageStage.BeforeDeserialize:
                        break;

                    case SoapMessageStage.AfterDeserialize:
                        {
                            //采集时间
                            this.invokeInfo.BeginInvokeTime = DateTime.Now;
                            //采集WebService方法名
                            this.invokeInfo.MethodName = message.MethodInfo.Name;

                            this.invokeInfo.UserHostAddress = System.Web.HttpContext.Current.Request.UserHostAddress;


                            this.invokeInfo.Args = new Dictionary<string, object>();

                            message.MethodInfo.InParameters.ToList().ForEach(d =>
                                {
                                    this.invokeInfo.Args.Add(d.Name, message.GetInParameterValue(d.Position));
                                });

                            running.TryAdd(this.invokeInfo.Id, this.invokeInfo);

                            {
                                last.Enqueue(invokeInfo);

                                if (last.Count > 20)
                                {
                                    WSInvokeInfo removed;
                                    last.TryDequeue(out removed);
                                }
                            }
                            {
                                var queue = remoteUserHost.GetOrAdd(invokeInfo.UserHostAddress, uha => new ConcurrentQueue<WSInvokeInfo>());
                                queue.Enqueue(invokeInfo);
                                if (queue.Count > 5)
                                {
                                    WSInvokeInfo removed;
                                    queue.TryDequeue(out removed);
                                }
                            }
                        }
                        break;

                    case SoapMessageStage.BeforeSerialize:
                        {
                            //采集时间
                            this.invokeInfo.EndInvokeTime = DateTime.Now;
                            WSInvokeInfo removed;
                            running.TryRemove(this.invokeInfo.Id, out removed);

                            if (log.IsDebugEnabled)
                            {
                                if (this.invokeInfo.UseTime.TotalMilliseconds > MaxRunningMilliseconds)
                                    log.Debug(this.invokeInfo.ToString());
                            }
                        }
                        break;

                    case SoapMessageStage.AfterSerialize:
                        break;

                    default:
                        throw new Exception("No stage such as this");
                }

            }
        }


    }

    public class WSInvokeInfo
    {
        public WSInvokeInfo()
        {
            Id = Guid.NewGuid();
        }
        public Guid Id { get; private set; }
        public DateTime BeginInvokeTime { get; set; }

        public string MethodName { get; set; }

        public string UserHostAddress { get; set; }


        public DateTime? EndInvokeTime { get; set; }

        public Dictionary<string,object> Args { get; set; }

        public TimeSpan UseTime { get { return (EndInvokeTime.HasValue ? EndInvokeTime.Value : DateTime.Now) - BeginInvokeTime; } }

        public static string GetString(ICollection val)
        {
            var ret = new List<string>();
            var iter = val.GetEnumerator();
            while (iter.MoveNext())
            {
                if (iter.Current is ICollection)
                    ret.Add(GetString((ICollection)iter.Current));
                else
                    ret.Add(iter.Current.ToString());
            }

            return string.Concat("[", string.Join(", ", ret.ToArray()), "]");
        }


        public override string ToString()
        {
            return string.Format("Host:{0},  UseTime:{1}, Time:{2}, name:{3},Arg:{4}",
                this.UserHostAddress ?? "none",
                this.UseTime.TotalMilliseconds,
                this.BeginInvokeTime,
                this.MethodName ?? "unkown",
                string.Join(", ", this.Args.ToList().ConvertAll(d => string.Format("{0}:={1}", d.Key, d.Value == null ? "null" : (d.Value is ICollection ? GetString((ICollection)d.Value) : d.Value.ToString()))).ToArray()));
        }

    }

    public class RemoteHostInfo
    {
        public string Host { get; set; }

        public WSInvokeInfo[] LastInvoke { get; set; }
    }

}

  

查看页面:

<%@ WebHandler Language="C#" Class="SoapUtil.ServerStat" %>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using OA4.CommonLib.Soap;

namespace SoapUtil
{
    /// <summary>
    /// Alive 的摘要说明
    /// </summary>
    public class ServerStat : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
            var resp = context.Response;
            try
            {
                var running = TimeWatchExtension.Running.ToList();

                resp.Write(string.Format("当前运行:{0}\n{1}",
                                        running.Count,
                                        string.Join("\n", running.ConvertAll(d =>
                                        {
                                            var ret = "exception";

                                            try { ret = d.Value.ToString(); }
                                            catch (Exception ex)
                                            {
                                                ret = string.Concat(ret, ",", d.Value.MethodName, ",", d.Value.UserHostAddress, ",", d.Value.BeginInvokeTime.ToString());
                                            }
                                            return ret;
                                        }).ToArray())
                                        )
                           );

                var last = TimeWatchExtension.LastInvoke.ToList();
                {
                    var strInfo = "";
                    if (last.Count > 1)
                    {
                        var f = last.First();
                        TimeSpan ts = DateTime.Now - f.BeginInvokeTime;
                        var speed = last.Count / ts.TotalSeconds;
                        var avgUseTime = last.Average(d => d.UseTime.Milliseconds);


                        strInfo = string.Format("{0:0.0} (Call/S), {1:0.0} (MS/Call)", speed, avgUseTime);
                    }
                    else
                    {

                    }
                    resp.Write(string.Format("\n最后记录:{0},\t{1}\n{2}",
                                           last.Count,
                                           strInfo,
                                           string.Join("\n", last.ConvertAll(d =>
                                           {
                                               var ret = "exception";

                                               try { ret = d.ToString(); }
                                               catch (Exception ex)
                                               {
                                                   ret = string.Concat(ret, ",", d.MethodName, ",", d.UserHostAddress, ",", d.BeginInvokeTime.ToString());
                                               }
                                               return ret;
                                           }).ToArray())
                                           )
                              );
                }

                resp.Write("\n");
                var userHost = TimeWatchExtension.RemoteUserHost;
                Array.ForEach(userHost, info =>
                    {
                        var invoke = info.LastInvoke.ToList();
                        if (invoke.Count > 1)
                        {
                            var f = invoke.First();

                            TimeSpan ts = DateTime.Now - f.BeginInvokeTime;
                            var speed = invoke.Count / ts.TotalSeconds;
                            var avgUseTime = invoke.Average(d => d.UseTime.Milliseconds);


                            var strInfo = string.Format("{0:0.0} (Call/S), {1:0.0} (MS/Call)", speed, avgUseTime);
                            resp.Write("\n\n" + info.Host + "[" + strInfo + "]:");
                        }
                        else
                        {
                            resp.Write("\n\n" + info.Host + ":");
                        }
                        resp.Write(string.Format("\n最后记录:{0}\n{1}",
                                      invoke.Count,
                                      string.Join("\n", invoke.ConvertAll(d =>
                                      {
                                          var ret = "exception";

                                          try { ret = d.ToString(); }
                                          catch (Exception ex)
                                          {
                                              ret = string.Concat(ret, ",", d.MethodName, ",", d.UserHostAddress, ",", d.BeginInvokeTime.ToString());
                                          }
                                          return ret;
                                      }).ToArray())
                                      )
                         );
                    });

            }
            catch (Exception ex)
            {
                context.Response.Write(string.Format("ERROR:{0}",ex.Message));
            }
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

  

posted @ 2012-09-04 09:23  阿牛  阅读(2199)  评论(0编辑  收藏  举报