一步步开发自己的博客 番外篇(7、异步记录日志 和 文章阅读量统
<h1 id="autoid-0-0">前言?
其他的就不多说了,进入今天的主题,异步记录日志和文章阅读量统计。 异步记录日志我们常用日志记录,无非就是,数据库记录和文本日志记录。而今天我要说的是,文本日志记录。 最简单的文本记录:??使用静态类File的WriteAllText 如果文件存在则覆盖,传入文件路径和消息内容。ok,完事。 当然,我们不能每次都覆盖上一次的记录。??那么我们可是在原有内容追加。这里,我们不用关系文件流是否关闭,使用静态类File的这两个方法都会自动帮我们关闭。 如果,我们是使用的winfrom单线程。那么,基本的日志记录就这个两个方法 完全可以搞定。 但是,如果是web程序就不一样了,天生的多线程。多个线程同时访问一个文件,肯定是会报错的。不信你试试。 那我们怎么解决这个问题?有人会说,加锁呗。锁肯定是要加,不过要看怎么加了。如果加到写文件内容的时候肯定是不合适的。因为写文件要打开文件流,比较耗时。我们可以先把要写的日志,统一存内存,然后单线程从内存取数据,写到文本。当然,写内存也可能会多线程并发,这个时候,我们就可以把锁加到写内存的地方。这里大家就不用担心了,写内存的速度是非常快的,和直接写文件那差的可不是一两个档次的问题了。 我们刚才说存内存,怎么存?当然是存集合了。有个数据类型??为什么要用它。因为它是队列,有个特点:先进先出。我们取数据的时候就是去的最早存进去的数据了。 使用:存数据? Queue(); myQ.Enqueue();? ?取数据? t = myQ.Dequeue();?直接在取值的时候就把值在队列中移除了。这样正好免了我手动移除。 那么,很简单。我们记日志的时候就先把日志往??里存,然后单独开个进程取值存值写文件里。ok,完事。 刚才说了,我们要加锁。是的,要加锁。因为??并不是线程安全数据。我们在写数据和读数据的时候都要加锁。 myLock=
m = logQueue.Dequeue();
我之前在网上查资料说不能多线程同时写入队列,经测试其实是不能同时读和写队列。所以在Dequeue取的时候也要锁定同一个对象 思路大体就是这样了。当然,我们还可以扩展很多的东西。如:定时删除指定过期日志、分文件大小存储日志、自动增加的日志文件命名...等等。
没错,我确实是在造轮子。我不想解释太多了。累... ? 大神请略过.... 下面给出,我的具体实现代码。分为四个文件??包含文件名、日志内容??存队列、写文件??读取相关配置??外部直接调用 <span style="color: #0000ff;">namespace<span style="color: #000000;"> CommonLib.HiLog
{ <span style="color: #808080;">/// <span style="color: #808080;"> <span style="color: #808080;">///<span style="color: #008000;"> 日志模型 <span style="color: #808080;">/// <span style="color: #808080;"> <span style="color: #0000ff;">internal <span style="color: #0000ff;">class<span style="color: #000000;"> LogModel { <span style="color: #0000ff;">#region logFileName <span style="color: #0000ff;">private <span style="color: #0000ff;">string<span style="color: #000000;"> _logFileName;
} <span style="color: #0000ff;">namespace<span style="color: #000000;"> CommonLib.HiLog
{ <span style="color: #808080;">/// <span style="color: #808080;"> <span style="color: #808080;">///<span style="color: #008000;"> 日志操作辅助类 <span style="color: #808080;">///<span style="color: #008000;"> zhaopeiym@163.com <span style="color: #808080;">///<span style="color: #008000;"> 创建20150104 修改20151003 <span style="color: #808080;">/// <span style="color: #808080;"> <span style="color: #0000ff;">internal <span style="color: #0000ff;">class<span style="color: #000000;"> LogHelper { <span style="color: #808080;">/// <span style="color: #808080;"> <span style="color: #808080;">///<span style="color: #008000;"> 消息队列 <span style="color: #808080;">/// <span style="color: #808080;"> <span style="color: #0000ff;">private <span style="color: #0000ff;">static Queue <span style="color: #808080;">/// <span style="color: #808080;"> <span style="color: #808080;">///<span style="color: #008000;"> 消息队列 对外只读 <span style="color: #808080;">/// <span style="color: #808080;"> <span style="color: #0000ff;">public <span style="color: #0000ff;">static Queue { <span style="color: #0000ff;">get { <span style="color: #0000ff;">return<span style="color: #000000;"> LogHelper.logQueue; } }
<span style="color: #000000;"> {
<span style="color: #000000;"> }
<span style="color: #000000;"> File.AppendAllText(LogfileFullNqme,encoding);
<span style="color: #000000;"> }
<span style="color: #000000;"> {
<span style="color: #000000;"> }
} <span style="color: #0000ff;">namespace<span style="color: #000000;"> CommonLib.HiLog
{ <span style="color: #808080;">/// <span style="color: #808080;"> <span style="color: #808080;">///<span style="color: #008000;"> 日志相关配置 <span style="color: #808080;">/// <span style="color: #808080;"> <span style="color: #0000ff;">public <span style="color: #0000ff;">static <span style="color: #0000ff;">class<span style="color: #000000;"> LogConfig { <span style="color: #0000ff;">#region 辅助方法 <span style="color: #808080;">/// <span style="color: #808080;"> <span style="color: #808080;">///<span style="color: #008000;"> GetAppSettings <span style="color: #808080;">/// <span style="color: #808080;"> <span style="color: #808080;">/// <span style="color: #808080;"><param name="key"> <span style="color: #808080;">/// <span style="color: #808080;"> <span style="color: #0000ff;">public <span style="color: #0000ff;">static <span style="color: #0000ff;">string GetAppSettings(<span style="color: #0000ff;">string<span style="color: #000000;"> key) { <span style="color: #0000ff;">if<span style="color: #000000;"> (ConfigurationManager.AppSettings.AllKeys.Contains(key)) <span style="color: #0000ff;">return<span style="color: #000000;"> ConfigurationManager.AppSettings[key].ToString(); <span style="color: #0000ff;">return <span style="color: #0000ff;">string<span style="color: #000000;">.Empty; }
} <span style="color: #0000ff;">namespace<span style="color: #000000;"> CommonLib.HiLog
{ <span style="color: #808080;">/// <span style="color: #808080;"> <span style="color: #808080;">///<span style="color: #008000;"> 异步单线程 <span style="color: #808080;">/// <span style="color: #808080;"> <span style="color: #0000ff;">public <span style="color: #0000ff;">class<span style="color: #000000;"> LogSave { <span style="color: #808080;">/// <span style="color: #808080;"> <span style="color: #808080;">///<span style="color: #008000;"> 获得Exception 的详细信息 <span style="color: #808080;">/// <span style="color: #808080;"> <span style="color: #808080;">/// <span style="color: #808080;"><param name="ex"> <span style="color: #808080;">/// <span style="color: #808080;"> <span style="color: #0000ff;">public <span style="color: #0000ff;">static <span style="color: #0000ff;">string<span style="color: #000000;"> GetExceptionInfo(Exception ex) { StringBuilder str = <span style="color: #0000ff;">new<span style="color: #000000;"> StringBuilder(); str.Append(<span style="color: #800000;">"<span style="color: #800000;">错误信息:<span style="color: #800000;">" +<span style="color: #000000;"> ex.Message); str.Append(<span style="color: #800000;">"<span style="color: #800000;">rn错误源:<span style="color: #800000;">" +<span style="color: #000000;"> ex.Source); str.Append(<span style="color: #800000;">"<span style="color: #800000;">rn异常方法:<span style="color: #800000;">" +<span style="color: #000000;"> ex.TargetSite); str.Append(<span style="color: #800000;">"<span style="color: #800000;">rn堆栈信息:<span style="color: #800000;">" +<span style="color: #000000;"> ex.StackTrace); <span style="color: #0000ff;">return<span style="color: #000000;"> str.ToString(); }
} 写好之后,下次我在别的项目里面就直接引用。 如果你使用的是EF,那么我再告诉你一个小秘密。??中的??可以直接记录所有EF执行的sql语句和参数。 使用如:?? 而LogSave.TrackLogSave我们在上面已经封装过。 ??? 文章阅读量统计我在一开始就琢磨着怎么统计阅读量。之前也在的最后提出了这个疑问。 遗憾的是,并没有谁告诉我更好的解决方案。 好吧,靠人不如靠己。还是自己瞎折腾吧。 但是,实现方式还是使用的我自己的提出的“” 1、我们在每次浏览器访问的时候都种下cookie,并设置过期时间为24小时。下次,浏览器访问的时候。我们检测如果存在我们种下的cookie。则直接忽略。 2、如果没有带上我们的cookie。我们就先组合“联合主键”。然后检测24小时内的记录有没有这个“联合主键”。如果有,则忽略,否则在原有阅读量的基础上加一,然后存入“联合主键”。 这里的"联合主键"有个小技巧。大家肯定都发现了,这个主键有点长。存数据库有点浪费空间(),然后查询检索应该也会慢些吧()。我们想想,其实我们要的不是这么长一串东东。其实,我们只要得到这串东西代表的唯一性就可以了。那么我们可以用到md5,咱不管你是1G、2G还是高清或是无码。统统给你返回一定长度字符串()。 随着数据的增加,这个统计阅读量的表数据,肯定是所有表中最大的。然而,我们统计阅读量是在,点击访问文章的时候,然后在统计阅读量这个环节卡太久,给人的感觉就是这个页面访问太慢,体验不好。 然而,我们每次统计都需要检测数据库里面是否存在,且数据量还不小。那我们只有再开个进程来做统计。 具体实现代码: 判断是否阅读过 如果没有 这在BlogReadInfo 插入一条标识信息
IsRead(Blogs.ModelDB.Blogs blogobj, (blogobj.BlogReadInfo.Where(t => t.MD5 == md5 && t.LastTime.AddHours() > DateTime.Now).Count() >
blogobj.BlogReadInfo.Add(== ====
统计阅读量 异步调用方法
SaveReadDelegate(ModelDB.Blogs blogobj, SaveReadNum(ModelDB.Blogs blogobj,), isup = = blogtemp = blogbll.GetList(t => t.Id == blogobj.Id,isAsNoTracking: (blogtemp.BlogReadNum == = (!++=
获取客户端标识(伪)
GetUserDistinguish(HttpRequestBase requestt, IsMD5 =
StringBuilder str = ip = (requestt.ServerVariables.AllKeys.Contains() && requestt.ServerVariables.Get() != = requestt.ServerVariables.Get(= requestt.ServerVariables.Get( + + + + +
str.Append( + + + +浏览器的分辨率(像素):" + Request["width"].ToString() + "*" + Request["height"].ToString());
str.Append( + +
然后我们通过委托从线程池抓去线程异步调用
SaveReadDelegate(SaveReadNum).BeginInvoke(blogobj,GetUserDistinguish(Request),,);
ok,统计完事。?
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- [和管子对话] 1 2007-4-5/对面向对象的你言我语
- asp.net-mvc-3 – 如何使用Console.WriteLine在ASP.Net MVC
- asp.net – tag-helpers无法正确生成我的网址
- asp.net-mvc-3 – ASP.NET MVC注入Http / Request / Contro
- asp.net – 过程或函数’xyz’指定了太多参数
- asp.net-mvc – 为什么Razor会添加另一个值属性以及如何删除
- asp.net – 有没有办法在Web Api控制器中处理表单发布数据?
- asp.net-core – Visual Studio 2015中的ASP.NET核心支持?
- asp.net-mvc-3 – EF 4.1 – 模型关系
- asp.net – asmx到WCF或Web API
- 为什么从ASP.NET页面下载时,.docx文件被损坏?
- asp.net-mvc-2 – 如何在asp.net mvc2中的控制器
- asp.net-mvc-4 – 如何在asp.net MVC4查看页面中
- asp.net – 如何从SQL Server 2008本身获取客户端
- asp.net-mvc – 如何在ASP.NET MVC的同一页面中使
- asp.net – 如何将模型从一个局部视图传递到另一
- asp.net – InvalidOperationException:没有数据
- ASP.NET MVC 3可以在ASP.NET 3.5网站中运行吗?
- VS2005(c#)项目调试问题解决方案集锦 转
- ASP.NET MVC或ASP.NET MVC2 RC2 – > RTM