测试项目搭建

定义一个简单的Mvc项目,有如下文件:

(1)

public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Run(context =>
{
return Task.Run(
async () => {
await Task.Delay(600);
await context.Response.WriteAsync("Hello, world." + context.Request.Uri);
});
});
}
}

(2)

public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
DebugUtils.Log("Application_Start"); Task.Run(() => { DebugUtils.beginLog($"bugLog.txt"); }); for (long i = 0; i < 10000000000; i++) ; DebugUtils.Log("Application_Start finished");
} protected void Application_End(object sender, EventArgs e)
{
DebugUtils.Log("Application_End"); for (long i = 0; i < 10000000000; i++) ; DebugUtils.Log("Application_End finished");
}
}

(3)

public class DebugUtils
{ public static ConcurrentQueue<string> queue = new ConcurrentQueue<string>(); public static void beginLog(string fileName)
{
string dirPath = "G:\\c#\\www\\debugLog\\";
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath); using (FileStream fs = new FileStream(dirPath + "/" + fileName, FileMode.Append))
{
using (StreamWriter sw = new StreamWriter(fs))
{
string str;
while (true)
{
if (queue.TryDequeue(out str))
{
sw.WriteLine(str);
sw.Flush();
}
} }
}
} public static void Log(string str)
{
queue.Enqueue("[" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "]--[" + Thread.CurrentThread.ManagedThreadId + "]--" + str);
}
}

测试

常规操作

将站点部署到IIS上后,依次进行 修改config, bin文件夹,站点关闭、重启,回收线程池 操作,日志里都有Application_End的触发日志。随后访问页面又会有Application_Start的日志记录。

高并发

使用工具模拟请求高并发地访问这个站点

在此期间修改config, 日志文件中只有Application_End的记录,却没有Application_Start的记录。

再次修改config,这次只有Application_Start的记录,却又没有end的了。尝试多次,一直都这样轮替出现。



虽然上面日志中的记录看上去很平常,但是实际情况却不是这样。


于是做了如下修改(每次启动都使用新的日志文件)



同样进行了几次config文件的修改,新的日志记录如下

可以看到Application_Start事件并不会等待Application_End执行完毕才触发。

待解决的疑问:

  1. 上面测试中情况

    前面使用同一个日志文件时,日志只记录部分,甚至很规律地交替出现,是因为文件被占用吗?

在打开日志文件时刻意抛出异常,网站可以照常访问,但不再记录日志了,所以文件占用异常确实可以导致上述情况。

    public  void beginLog(string fileName)
{
string dirPath = "G:\\c#\\www\\debugLog\\";
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath); throw new Exception("test"); using (FileStream fs = new FileStream(dirPath + "/" + fileName, FileMode.Append))
{
using (StreamWriter sw = new StreamWriter(fs))
{
string str;
while (true)
{
if (queue.TryDequeue(out str))
{
sw.WriteLine(str);
sw.Flush();
}
} }
}
}

修改日志记录类为非静态类

(1)

public class DebugUtils
{
public static DebugUtils Instance = new DebugUtils(); public static ConcurrentQueue<string> queue = new ConcurrentQueue<string>(); public void beginLog(string fileName)
{
string dirPath = "G:\\c#\\www\\debugLog\\";
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath); using (FileStream fs = new FileStream(dirPath + "/" + fileName, FileMode.Append))
{
using (StreamWriter sw = new StreamWriter(fs))
{
string str;
while (true)
{
if (queue.TryDequeue(out str))
{
sw.WriteLine(str);
sw.Flush();
}
} }
}
} public void Log(string str, string date)
{
queue.Enqueue($"[{ date }]--[{Thread.CurrentThread.ManagedThreadId}]-[{ this.GetHashCode() }]-{str}");
}
}

(2)

public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
DebugUtils.Instance.Log("Application_Start", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")); Task.Run(() => { DebugUtils.Instance.beginLog($"bugLog{DateTime.Now.ToString("yyyyMMdd-HHmmssfff")}.txt"); }); for (long i = 0; i < 10000000000; i++) ; DebugUtils.Instance.Log("Application_Start finished", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"));
} protected void Application_End(object sender, EventArgs e)
{
DebugUtils.Instance.Log("Application_End", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")); for (long i = 0; i < 10000000000; i++) ; DebugUtils.Instance.Log("Application_End finished", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"));
}
}

快速地修改了3次config(空格,保存,空格,保存,空格,保存), 发现日志文件的创建要滞后许多。

重试了一遍,这次也是3次修改,只触发了两次Application_End





在连续修改config的情况下,start事件几乎是立即就触发了,但end事件如果尚有前一个end事件未执行完成,新的end事件会延后触发。

在end事件中增加代码记录end的触发原因

        try
{
HttpRuntime runtime = (HttpRuntime)typeof(HttpRuntime).InvokeMember("_theRuntime",
BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField, null, null, null);
if (runtime == null)
return;
string shutDownMessage = (string)runtime.GetType().InvokeMember("_shutDownMessage",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField, null, runtime, null);
string shutDownStack = (string)runtime.GetType().InvokeMember("_shutDownStack",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField, null, runtime, null); DebugUtils.Instance.Log("MvcApplicationEnd事件触发:" + shutDownMessage + shutDownStack, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"));
}
catch (Exception ex)
{
DebugUtils.Instance.Log("MvcApplicationEnd事件触发异常:" + ex.Message, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"));
}





此时的网站日志文件中:

两个明显的请求处理停顿,刚好分别对应了上面的两次start事件

项目中遇到的问题

项目中使用log4net记录日志 ,配置文件如下:

<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender" >
<file value="App_Data/Logs/Logs.txt" />
<encoding value="utf-8" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10000KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level %date [%-5.5thread] %-40.40logger - %message%newline" />
</layout>
</appender>
<root>
<appender-ref ref="RollingFileAppender" />
<level value="DEBUG" />
</root>
</log4net>

Application_Start:

    protected override void Application_Start(object sender, EventArgs e)
{
Clock.Provider = ClockProviders.Utc; //Log4Net configuration
AbpBootstrapper.IocManager.IocContainer
.AddFacility<LoggingFacility>(f => f.UseAbpLog4Net()
.WithConfig(Server.MapPath("log4net.config"))
); base.Application_Start(sender, e); SingletonDependency<IOnlineUserManager>.Instance.ReloadWhenApplicationStart();
}

在站点发布后,常常会在某次Application_End事件触发后,日志不再记录,而等过段时间后又会有新的日志出现(Application_Start的日志为起始)。

确实也是因为文件被占用。

解决log4net独占日志文件的问题以及 log4net的各种输出配置

http://logging.apache.org/log4net/release/config-examples.html

log4net系列(三)--详解RollingFileAppender

log4net的配置详解

Application_Start 中的 SingletonDependency<IOnlineUserManager>.Instance.ReloadWhenApplicationStart();这行代码为什么经常不生效。

因为有socket连接及轮询请求的存在,常常是start事件在end之前被触发,所以在end事件触发时保存用户session数据就不合适了,因为保存与读取 的执行顺序无法保障。

关于Application_End 与 Application_Start事件触发情况的测试(待续)的更多相关文章

  1. 【深入浅出Linux网络编程】 “基础 -- 事件触发机制”

    回顾一下“"开篇 -- 知其然,知其所以然"”中的两段代码,第一段虽然只使用1个线程但却也只能处理一个socket,第二段虽然能处理成百上千个socket但却需要创建同等数量的线程 ...

  2. [转载] 理解 epoll 的事件触发机制

    原文: http://weibo.com/p/1001603862394207076573?sudaref=weibo.com epoll的I/O事件触发方式有两种模式:ET(Edge Trigger ...

  3. Zendframework 模块加载事件触发顺序。

    模块加载时事件触发的时间顺序: 0.loadModules(ModuleEvent::EVENT_LOAD_MODULES) 1.  loadModule.resolve(ModuleEvent::E ...

  4. Android中Touch事件分析--解决HorizontalScrollView滑动和按钮事件触发问题

    之前写过关于HorizontalScrollView滑动和按钮事件触发问题,但是不能所有的情况,最近几天一直在想这个问题,今天有一个比较好的解决思路,最终应用在项目里面效果也很好,首先说明一下功能: ...

  5. 基于raw os 的事件触发系统

    Raw os的事件触发系统有以下特点: 1 基于UML的状态机理念设计,实现了有限状态机(fsm)以及层次状态机(HSM). 2 实现了活动对象(ACTIVE OBJECT)的特性,一个活动对象包含了 ...

  6. jQuery事件触发和参数传递

    jQuery事件触发和参数传递: 参考:http://www.jb51.net/article/36249.htm <%@ page language="java" impo ...

  7. Javascript事件触发顺序

    html标签是有子和父的,这个时候就出现了事件触发顺序的问题,比如: <!DOCTYPE html> <html> <head> <style> .fi ...

  8. 【阿里云IoT+YF3300】4.Alink物模型之事件触发

    名词解释:设备的功能模型之一,设备运行时的事件,事件一般包含需要被外部感知和处理的通知信息,可包含多个输出参数.如,某项任务完成的信息,或者设备发生故障或告警时的温度等,事件可以被订阅和推送. 在工控 ...

  9. epoll水平/边缘触发模式下阻塞/非阻塞EPOLLOUT事件触发条件及次数

    在IO多路复用技术中,epoll默认的事件触发模式为Level_triggered(水平触发)模式,即当被监控的文件描述符上有可读/写事件发生时,epoll_wait()会通知处理程序去读写.如果这次 ...

随机推荐

  1. mysql 查询select语句汇总

    数据准备: 创建表: create table students( id int unsigned primary key auto_increment not null, name varchar( ...

  2. ZooKeeper:win7上安装单机及伪分布式安装

    zookeeper是一个为分布式应用所设计的分布式的.开源的调度服务,它主要用来解决分布式应用中经常遇到的一些数据管理问题,简化分布式应用,协调及其管理的难度,提高性能的分布式服务. 本章的目的:如何 ...

  3. POJ1017 Packets---贪心

    题目链接: https://vjudge.net/problem/POJ-1017 题目大意: 公司共有底面面积为1*1.2*2.3*3.4*4.5*5.6*6,高度同为H的六种产品,现在需要用最少的 ...

  4. scrollTop doesn't scroll on Chrome 61

    在chrome61 不支持滚动 解决方案: Use document.scrollingElement if supported, and fall back to the current code. ...

  5. echarts.js--前端可视化数据图形

    ECharts,一个使用 JavaScript 实现的开源可视化库,可以流畅的运行在 PC 和移动设备上, 兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等 ...

  6. burp的dns记录功能

    写个备忘. 先点copy复制url,然后生成的url就能用了. 一关就没了,比较鸡肋些,不适合持久的,适合马上就能见效果的那种.

  7. codefroces 911G Mass Change Queries

    题意翻译 给出一个数列,有q个操作,每种操作是把区间[l,r]中等于x的数改成y.输出q步操作完的数列. 输入输出格式 输入格式: The first line contains one intege ...

  8. [HAOI2016]找相同字符

    题目描述 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两个子串中有一个位置不同. 输入输出格式 输入格式: 两行,两个字符串s1,s2,长度分别为 ...

  9. C++traits——STL源码剖析

    有时候我们希望知道迭代器所指的元素类型. 以迭代器所指声明对象: template<typename Iterator, typename T> void func_impl(Iterat ...

  10. 【网络流】【BZOJ1001】狼抓兔子

    继续网络流的学习.... 题意简析:就是给你张图,叫你求最小割. 解题思路:最小割=最大流,按题意见图跑一次就好了. 附代码: #include<cstdio> #include<i ...