系统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; } } } }