的计数器来获得一些概要的数据。但是如果我们需要获取一些系统的详细状态甚至是需要根据需要进行动态改变的自定义需求则势必要深入到系统内部进行数据采集。因此我们可能需要让代码执行“一段时间”并将直接结果进行汇总输出。让代码执行一段时间不难简单地使用Thread.Sleep便可也不会造成什么性能或吞吐量上的损失。关键就在于在代码停留的这“一段时间”内我们使用什么样的做法来采集数据。这时候老赵脑海中立即浮现出的便是HttpModule般监听请求管道Pipeline中的各式事件。于是立马写出以下的代码在前文的示例基础上进行修改protected void btnExecute_Click(object sender, EventArgs e) { ScriptEngine engine Python.CreateEngine(); var scope engine.CreateScope(); var script engine.CreateScriptSourceFromString( this.txtCode.Text, SourceCodeKind.Statements); script.Execute(scope); TextWriter writer new StringWriter(); scope.SetVariable(logger, writer); ActionHttpContext traceRequest; if (scope.TryGetVariableActionHttpContext(traceRequest, out traceRequest)) { Action endTraceRequests; scope.TryGetVariableAction(endTraceRequests, out endTraceRequests); int waitTime; if (!scope.TryGetVariableint(waitTime, out waitTime)) { waitTime 10000; } this.TraceRequests(traceRequest, waitTime, endTraceRequests); } this.txtOutput.Text writer.ToString(); } private void TraceRequests(ActionHttpContext traceRequest, int waitTime, Action endTraceRequests) { EventHandler handler (sender, e) { try { traceRequest((sender as HttpApplication).Context); } catch { } }; this.Context.ApplicationInstance.BeginRequest handler; Thread.Sleep(waitTime); this.Context.ApplicationInstance.BeginRequest - handler; if (endTraceRequests ! null) endTraceRequests(); }再编译了IronPython代码之后我们会设法获取其中的traceRequest和endTraceRequests函数前者用于“记录每个请求”而后者用于采样最后的“聚合”。此外还会设法从代码中获取等待时间waitTime。然后使用TraceRequest方法开始对当前请求进行采样。具体做法为监听当前Application的BeginRequest事件并在每次获得请求时调用traceRequest委托进行“记录”。在等待时间过后自然将委托从BeginRequest事件中剥离。最后再通过endTraceRequests函数进行聚合输出。代码逻辑很清晰但可惜的是上面这段代码不能生效。具体原因不明可能是ASP.NET对这方面进行了限制使得我们无法在HttpModule之外为请求管道动态添加事件处理函数存疑求证。对此我们只能进行让步。不过既然ASP.NET允许HttpModule监听管道事件那么我们不如事先准备一个HttpModule监听各种事件并且在合适的时候把这一事件转发给IronPython函数。我们这里还是以BeginRequest事件为例public class IronPythonTraceModule : IHttpModule { private class TraceRequestEventArgs : EventArgs { public TraceRequestEventArgs(HttpContext context) { this.HttpContext context; } public HttpContext HttpContext { get; private set; } } public void Dispose() { } public void Init(HttpApplication context) { context.BeginRequest new EventHandler(OnBeginRequest); } static void OnBeginRequest(object sender, EventArgs e) { var traceRequest IronPythonTraceModule.TraceRequest; if (traceRequest ! null) { var context (sender as HttpApplication).Context; traceRequest(null, new TraceRequestEventArgs(context)); } } private static event EventHandlerTraceRequestEventArgs TraceRequest; public static void TraceRequests( ActionHttpContext traceRequest, Action endTraceRequests, int milliseconds) { EventHandlerTraceRequestEventArgs handler (sender, e) { try { traceRequest(e.HttpContext); } catch { } }; IronPythonTraceModule.TraceRequest handler; Thread.Sleep(milliseconds); IronPythonTraceModule.TraceRequest - handler; if (endTraceRequests ! null) endTraceRequests(); } }IronPythonTraceModule需要放入应用程序中它时刻对请求管道的BeginRequest进行监听只是在合适的时候才会发起TraceRequest静态事件显然这并不会对系统性能造成什么影响。Module包函一个静态的TraceRequests方法这便是给外部调用的接口。可以发现这段代码和之前的TraceRequests方法非常接近唯一不同的只是动态添加/删除处理函数的事件是IronPythonTraceModule.TraceRequest而不是HttpApplication.BeginRequest。于是原来的代码也需要做一定修改protected void btnExecute_Click(object sender, EventArgs e) { ... ActionHttpContext traceRequest; if (scope.TryGetVariableActionHttpContext(traceRequest, out traceRequest)) { Action endTraceRequests; scope.TryGetVariableAction(endTraceRequests, out endTraceRequests); int waitTime; if (!scope.TryGetVariableint(waitTime, out waitTime)) { waitTime 10000; } // 以下代码有所修改 IronPythonTraceModule.TraceRequests(traceRequest, endTraceRequests, waitTime); } this.txtOutput.Text writer.ToString(); }现在我们进行一番测试简单地检测一下5秒钟内收到 了多少请求使用自己的Module进行处理还有其他一些好处比如可以提供更好的控制。事实上目前文章里的解决方案有一些缺陷并且肯定无法完全满足真实需求。不过我们完全可以对目前的做法进行改进例如保证代码执行的线程安全包括事件添加时和traceRequest函数执行时。提供“采样特性”而不是对每个请求都使用traceRequest函数进行处理。将Logger放入公用的空间并在程序代码中植入检查功能这样便可以得知当前系统中每个功能的执行时间这就是Profiler的功能不是吗。不过除了应对前一篇文章中所提到的负载均衡环境下的问题之外这个解决方案还有另一个较为重要的情况需要特殊对待。如果使用目前的做法每次采样都是通过一个请求进行的所以它并不会在在请求队列阻塞时立即执行但是采样的常见场景便是在队列阻塞时间检查状况这显然形成了一个矛盾。不过要解决这个问题并非难事只要采样不要通过IIS即可。例如您使用普通Socket或“偷偷懒”使用WCF的TcpBinding进行采样便可——只要和被检查的应用程序在同一进程即w3wp.exe还有人用IIS5 吗中便可以使用任何方式进行通信。
使用IronPython检测ASP.NET程序状况(下)
发布时间:2026/5/29 1:06:47
的计数器来获得一些概要的数据。但是如果我们需要获取一些系统的详细状态甚至是需要根据需要进行动态改变的自定义需求则势必要深入到系统内部进行数据采集。因此我们可能需要让代码执行“一段时间”并将直接结果进行汇总输出。让代码执行一段时间不难简单地使用Thread.Sleep便可也不会造成什么性能或吞吐量上的损失。关键就在于在代码停留的这“一段时间”内我们使用什么样的做法来采集数据。这时候老赵脑海中立即浮现出的便是HttpModule般监听请求管道Pipeline中的各式事件。于是立马写出以下的代码在前文的示例基础上进行修改protected void btnExecute_Click(object sender, EventArgs e) { ScriptEngine engine Python.CreateEngine(); var scope engine.CreateScope(); var script engine.CreateScriptSourceFromString( this.txtCode.Text, SourceCodeKind.Statements); script.Execute(scope); TextWriter writer new StringWriter(); scope.SetVariable(logger, writer); ActionHttpContext traceRequest; if (scope.TryGetVariableActionHttpContext(traceRequest, out traceRequest)) { Action endTraceRequests; scope.TryGetVariableAction(endTraceRequests, out endTraceRequests); int waitTime; if (!scope.TryGetVariableint(waitTime, out waitTime)) { waitTime 10000; } this.TraceRequests(traceRequest, waitTime, endTraceRequests); } this.txtOutput.Text writer.ToString(); } private void TraceRequests(ActionHttpContext traceRequest, int waitTime, Action endTraceRequests) { EventHandler handler (sender, e) { try { traceRequest((sender as HttpApplication).Context); } catch { } }; this.Context.ApplicationInstance.BeginRequest handler; Thread.Sleep(waitTime); this.Context.ApplicationInstance.BeginRequest - handler; if (endTraceRequests ! null) endTraceRequests(); }再编译了IronPython代码之后我们会设法获取其中的traceRequest和endTraceRequests函数前者用于“记录每个请求”而后者用于采样最后的“聚合”。此外还会设法从代码中获取等待时间waitTime。然后使用TraceRequest方法开始对当前请求进行采样。具体做法为监听当前Application的BeginRequest事件并在每次获得请求时调用traceRequest委托进行“记录”。在等待时间过后自然将委托从BeginRequest事件中剥离。最后再通过endTraceRequests函数进行聚合输出。代码逻辑很清晰但可惜的是上面这段代码不能生效。具体原因不明可能是ASP.NET对这方面进行了限制使得我们无法在HttpModule之外为请求管道动态添加事件处理函数存疑求证。对此我们只能进行让步。不过既然ASP.NET允许HttpModule监听管道事件那么我们不如事先准备一个HttpModule监听各种事件并且在合适的时候把这一事件转发给IronPython函数。我们这里还是以BeginRequest事件为例public class IronPythonTraceModule : IHttpModule { private class TraceRequestEventArgs : EventArgs { public TraceRequestEventArgs(HttpContext context) { this.HttpContext context; } public HttpContext HttpContext { get; private set; } } public void Dispose() { } public void Init(HttpApplication context) { context.BeginRequest new EventHandler(OnBeginRequest); } static void OnBeginRequest(object sender, EventArgs e) { var traceRequest IronPythonTraceModule.TraceRequest; if (traceRequest ! null) { var context (sender as HttpApplication).Context; traceRequest(null, new TraceRequestEventArgs(context)); } } private static event EventHandlerTraceRequestEventArgs TraceRequest; public static void TraceRequests( ActionHttpContext traceRequest, Action endTraceRequests, int milliseconds) { EventHandlerTraceRequestEventArgs handler (sender, e) { try { traceRequest(e.HttpContext); } catch { } }; IronPythonTraceModule.TraceRequest handler; Thread.Sleep(milliseconds); IronPythonTraceModule.TraceRequest - handler; if (endTraceRequests ! null) endTraceRequests(); } }IronPythonTraceModule需要放入应用程序中它时刻对请求管道的BeginRequest进行监听只是在合适的时候才会发起TraceRequest静态事件显然这并不会对系统性能造成什么影响。Module包函一个静态的TraceRequests方法这便是给外部调用的接口。可以发现这段代码和之前的TraceRequests方法非常接近唯一不同的只是动态添加/删除处理函数的事件是IronPythonTraceModule.TraceRequest而不是HttpApplication.BeginRequest。于是原来的代码也需要做一定修改protected void btnExecute_Click(object sender, EventArgs e) { ... ActionHttpContext traceRequest; if (scope.TryGetVariableActionHttpContext(traceRequest, out traceRequest)) { Action endTraceRequests; scope.TryGetVariableAction(endTraceRequests, out endTraceRequests); int waitTime; if (!scope.TryGetVariableint(waitTime, out waitTime)) { waitTime 10000; } // 以下代码有所修改 IronPythonTraceModule.TraceRequests(traceRequest, endTraceRequests, waitTime); } this.txtOutput.Text writer.ToString(); }现在我们进行一番测试简单地检测一下5秒钟内收到 了多少请求使用自己的Module进行处理还有其他一些好处比如可以提供更好的控制。事实上目前文章里的解决方案有一些缺陷并且肯定无法完全满足真实需求。不过我们完全可以对目前的做法进行改进例如保证代码执行的线程安全包括事件添加时和traceRequest函数执行时。提供“采样特性”而不是对每个请求都使用traceRequest函数进行处理。将Logger放入公用的空间并在程序代码中植入检查功能这样便可以得知当前系统中每个功能的执行时间这就是Profiler的功能不是吗。不过除了应对前一篇文章中所提到的负载均衡环境下的问题之外这个解决方案还有另一个较为重要的情况需要特殊对待。如果使用目前的做法每次采样都是通过一个请求进行的所以它并不会在在请求队列阻塞时立即执行但是采样的常见场景便是在队列阻塞时间检查状况这显然形成了一个矛盾。不过要解决这个问题并非难事只要采样不要通过IIS即可。例如您使用普通Socket或“偷偷懒”使用WCF的TcpBinding进行采样便可——只要和被检查的应用程序在同一进程即w3wp.exe还有人用IIS5 吗中便可以使用任何方式进行通信。