nopcommerce中文网

nopcommerce是国外asp.net领域一个高质量的b2c开源项目,基于EntityFramework和MVC开发,QQ群1:75272942(2000人超级群,已满) QQ群2:640322459

导航 - 搜索

asp.net mvc如何使用Elmah处理错误日志?(转)

常在服务器端处理用户请求时.特别是针对Web应用程序.当出现异常是可以根据日志操作记录还原异常出现时操作步骤.而记录异常堆栈信息判断问题出现问题位置. 为了跟踪和记录服务器行为.特别是针对出现异常时构建简单、统一的异常处理模式就显得尤为重要.

如果有一个基础的架构用来记录服务器端中日志和事件.那么对于调试和 在问题的解决就变得更加简单直接.针对日志记录.可能针对大部分开发人员.首先表现明显就是应用程序底层或是运行时中存在Bug或是特定情况下Crash 掉等. 比较明显的行为.这时日志记录目的是为了跟踪应用程序的底层行为.了解出现异常时应用程序内部所执行的过程. 能够帮助开发人员和软件测试找到应用程序崩溃的原因. 快速解决问题.

而还有一些情况.是很难再开发阶段把问题暴露出来.类似性能问题.而此时如果有了日志记录服务端行为.则可以通过提供的详细执行时间记录可以很方便的找出应用的性能瓶颈.定位这些比较”隐性“问题.

所以花了点时间研究日志记录组件.说说个人看法.

在开源日志管理上当然不得不提到是LogStash .

2013-01-22_162111

它是一个应用程序日志、事件的传输、处理、管理和搜索的平台.基于 HTML5、Jquery、Css3和SVG等技术.所以也是跨平台的、跨浏览器的.可应用任何的Asp.net开发.可以用它来统一对应用程序日志进行 收集管理.最难得可贵的提供Web接口用户查询和统计. 所以特点是跨平台同时也是足够开放的.[这就是开源社区的力量.]推荐.

另外一个就是从Java移植过来的.Net版本Log4Net

 

 

ls-logo

这个可能给位已经很熟悉了.Log4net是从java平台下非常优 秀的日志记录框架Log4J移植到.NEt下版本.它也是Apache基金资助的项目的一部分.Log4net可以帮助我们把日志信息输出到各种不同目标 (文本文件、数据库、控制台等)的.net类库,它可以容易的加载到开发项目中,实现程序调试和运行的时候的日志信息输出,提供了比.net自己提供的 debug类和trace类的功能更多,使用起来也是非常的简单.

在说道本篇即将提到的Elmah.

2013-01-22_163710

 

 

Elmah其实是[The Error Logging Modules and Handlers]缩写.它是专用于ASP.NET的完全可热插拔的 错误日志记录工具。其特点就是无需ASP.NET程序重新编译,即可通过配置web.config(或machine.config)来实现整个应用程序 甚至是IIS中所有ASP.NET应用程序的错误日志记录工作。它支持日志的多种存储方式(各种数据库、XML、内存存储),除了提供一个界面用于查询日 志详细信息外,还可以通过E-MAIL、RSS订阅或Twitter发布方式通知错误信息给相关人员.

分别试用一下.

LogStash最大的特点是除了跨平台本身之外.它最强大的地方是 其提供丰富的插件的.各种灵活自定义规则.输出各种各样的日志结果.可以在不同的服务器上对不同的数据来源做自定义的filter,然后输出到不同的目的 插件上去.这样对于分布式是采集日志提供很好解决方案.类似要监控A B服务器上日志.可以再C服务器上接受日志记录数据并分析让后分发给D服务器做报警和容错处理. 自由开放.可以任意端采集日志数据.

Log4Net包含了主要有四种重要的组件,分别是Logge, Repository, Appender以及 Layout.功能强大.可以自定义日志输出级别.但我认为对于规模偏小的应用程序.在配置方式和灵活度显得不够Clean.

本篇来尝试Elmah在Asp.net MVC 4使用.

首先Build 空的Asp.net MVC 4 Project:

2013-01-22_172012

添加Elmah引用:

2013-01-22_172204

如果采用VS2012则如上关于Elmah组建已经配置成功.其实这个过程做了两件事:

A:将Elmah.dll复制到程序的根��录的Bin文件夹下.并当前项目的引用.

B:向项目根目录下Web.Config文件添加如下内容

在webConfig文件中添加如下内容:

 1:   <configSections>
 2:     <sectionGroup name="elmah">
 3:       <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
 4:       <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
 5:       <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
 6:       <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
 7:     </sectionGroup>
 8:   </configSections>
 9:  
 10:   <httpHandlers>
 11:       <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
 12:   </httpHandlers>
 13:    
 14:   <httpModules>
 15:       <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
 16:   </httpModules>
 

关于Elmah项目引用配置基本完成.如果你不习惯NuGEt也可以采用如上手工的方式添加项目引用.

此时在homeController中throw 一个nullException :

 1:   public class HomeController : Controller
 2:     {
 3:         public ActionResult Index()
 4:         {
 5:             //throw new null exception for test
 6:             throw new ArgumentNullException();
 7:             return View();
 8:         }
 9:     }

运行效果如下:

2013-01-22_173931

很明显.当我们throw一个异常后.,会出现报错的黄页.在来看看Elmah是否记录本次执行过程中出现ArgumentNullException.

2013-01-22_174214

可以看到Elmah已经如期的扑捉到当前应用程序的异常.ELMAH在后台记录了错误信息,并为我们提供了查询错误日志信息的界面,只需要简单的操作,就完成了基本的需求.

其实Elmah处理原理.当我们请求页面报错时.在返回黄页错误时首 先被httpModules中名为ErrorLog模块进行拦截. 该模块将本次请求出错的信息保存起来.-默认是放置在内存中.便于即时调试.但用户输入elmah.axd要查看日志信息时. 首先httpHandlers捕获到该请求.并交给专门处理elmah.axd的处理程序.该模块把错误日志View返回给用户.可见Elmah核心技术 还是基于HttpModules和HttpHandlers来实现的.

在添加完对Elmah引用可见在web.config同时添加Elmah节点 如下:

 1:  <elmah>
 2:     <!--
 3:  See http://code.google.com/p/elmah/wiki/SecuringErrorLogPages for 
 4:  more information on remote access and securing ELMAH.
 5:  -->
 6:     <security allowRemoteAccess="false" />
 7:   </elmah>

Elmah通过该节点对外公开功能配置项.该配置选项功能丰富.开篇提到Elmah对存储方式支持包含:

 

首先如果你只是引用Elmah而没有配置采用什么存储形式.Elmah默认设置为内存存储的方式.虽然这种方式便于开发调试.但在部署生产环境后还是推荐对数据要进行持久化存储. Xml文件或是采用支持的数据库.

改成文件存储方式只需要在配置项添加如下代码即可:

 1:   <elmah>
 2:     <!--
 3:         See http://code.google.com/p/elmah/wiki/SecuringErrorLogPages for 
 4:         more information on remote access and securing ELMAH.
 5:     -->
 6:     <security allowRemoteAccess="false" />
 7:     <errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="~/Static/Log/" />
 8:   </elmah>

该配置必需确认LogPath路径目录是完整存在的.测试会发现在本地文件中会出现一个XML文件:

2013-01-26_152341

这种方式虽然简单直观.但Elmah设计方式在每次运行如果应用程序出错一旦扑捉到.就独立生成一个独立的文件.这种方式会导致服务器端存在大量冗余文件.且对这些文件管理也是一个问题.

在数据可视化和管理上数据库依然是最理想的选择.这里采用SQlServer2008 版本测试.在构建Elmah支持SQLServer数据支持需要如下三个操作:

A: 需要告诉Elmah 需要连接什么类型的数据库

B: Elmah如何连接这些数据库.也就是连接字符串需要提供

C: 在指定数据库中已经存在对应存储Log日志表和视图存储过程.

实际操作首先需要Elmah节点添加如下内容:

 1:   <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="SQlServerConStr" />

在该数据执行如下SQL语句.请参考官方的连接.

Elmah SQL Server Script File:http://code.google.com/p/elmah/source/browse/src/Elmah/SQLServer.sql

执行sQL语句完成后会在当前数据库看到表:

2013-01-26_150301

当再次运行应用程序.在Throw ArgumentNullException时查询数据库:

2013-01-26_151242

可见简单实用.另外针对SQL语句执行全部以官方标准为主.不同数据库之间SQL Script脚本会存在一定的差异.

在使用Elmah过程发一下一些特点.这里需要说明一下.

Elmah是通过Http Modules 和Http Handler来记录和展示程序捕获的异常. 但是如果你在应用程序中添加异常处理模块.Try-Catch Elmah是无法记录到的.或是在Catch后在Throw出来. 在整个应用程序异常链上. 只有最终的异常抛给了Asp.net运行时Elmah组件才能捕获到并记录.

有很多人认为加入Elmah组件后能够处理应用异常.其实本质上Elmah本质上是一个日志记录工具.并没有处理异常的能力.所以如果异常发生.不会改变原来应用程序给用户体验.依然还会出现黄色页面.

在官方Note明确提到一个例外.:

ELMAH捕获异常是基于HttpApplication对象的Error事件。

如果软件项目中的一些处理导致了HttpApplication事件无法被触发(比如在发生异常后,还没来得及执行Application_Error,就执行了Server.ClearError()方法,

会阻止Error事件的触发,再比如,如果一个异常被try-catch捕获到,并且没有再次throw,那么异常也是不会最终触发Error事件)

日志记录工具还是不少的,比如著名的Log4net以及Enterprise Library中的Logging Application Block。 可以说,这些工具相对ELMAH来说,太重量级了,他们可以记录各种日志信息,比如监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分 析工作;跟踪代码运行时轨迹,作为日后审计的依据;担当集成开发环境中的调试器的作用,向文件或控制台打印代码的调试信息。因此,如果仅仅是记录 ASP.NET的错误日志.而Elmah开源且足够Clean.首选.

blog comments powered by Disqus
nopcommerce中文网 | GitHub 上一份很受欢迎的前端代码优化指南-强烈推荐收藏

nopcommerce中文网

nopcommerce是国外asp.net领域一个高质量的b2c开源项目,基于EntityFramework和MVC开发,QQ群1:75272942(2000人超级群,已满) QQ群2:640322459

导航 - 搜索

GitHub 上一份很受欢迎的前端代码优化指南-强烈推荐收藏

看到一份很受欢迎的前端代码指南,根据自己的理解进行了翻译,但能力有限,对一些JS代码理解不了,如有错误,望斧正。

HTML

语义化标签

HTML5 提供了很多语义化元素,更好地帮助描述内容。希望你能从这些丰富的标签库中受益。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- bad -->
<div id="main">
  <div class="article">
    <div class="header">
      <h1>Blog post</h1>
      <p>Published: <span>21st Feb, 2015</span></p>
    </div>
    <p>…</p>
  </div>
</div>
 
<!-- good -->
<main>
  <article>
    <header>
      <h1>Blog post</h1>
      <p>Published: <time datetime="2015-02-21">21st Feb, 2015</time></p>
    </header>
    <p>…</p>
  </article>
</main>

请确保正确使用语义化的标签,错误的用法甚至不如保守的用法。

1
2
3
4
5
6
7
8
9
10
11
<!-- bad -->
<h1>
  <figure>
    <img alt=Company src=logo.png>
  </figure>
</h1>
 
<!-- good -->
<h1>
  <img alt=Company src=logo.png>
</h1>

简洁

确保代码简洁性,不要再采用XHTML的旧做法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!-- bad -->
<!doctype html>
<html lang=en>
  <head>
    <meta http-equiv=Content-Type content="text/html; charset=utf-8" />
    <title>Contact</title>
    <link rel=stylesheet href=style.css type=text/css />
  </head>
  <body>
    <h1>Contact me</h1>
    <label>
      Email address:
      <input type=email placeholder=you@email.com required=required />
    </label>
    <script src=main.js type=text/javascript></script>
  </body>
</html>
 
<!-- good -->
<!doctype html>
<html lang=en>
  <meta charset=utf-8>
  <title>Contact</title>
  <link rel=stylesheet href=style.css>
 
  <h1>Contact me</h1>
  <label>
    Email address:
    <input type=email placeholder=you@email.com required>
  </label>
  <script src=main.js></script>
</html>

可用性

可用性不应该是事后才考虑的事情。你不必成为WCAG专家来改进网站,你可以通过简单的修改做出不错的效果,例如;

  • 正确使用alt属性
  • 确保链接和按钮正确使用(不要用<div class="button">这种粗暴的做法)
  • 不依赖于颜色来传达信息
  • 给表单做好lable标记
1
2
3
4
5
<!-- bad -->
 <h1><img alt="Logo" src="logo.png"></h1>
 
 <!-- good -->
 <h1><img alt="My Company, Inc." src="logo.png"></h1>

语言

定义语言和字符编码是可选项,建议在文档级别处定义。使用UTF-8编码。

1
2
3
4
5
6
7
8
9
10
<!-- bad -->
<!doctype html>
<title>Hello, world.</title>
 
<!-- good -->
<!doctype html>
<html lang=en>
  <meta charset=utf-8>
  <title>Hello, world.</title>
</html>

性能

除非有非要在加载内容前加载脚本的必要性由,不然别这样做,这样会阻碍网页渲染。如果你的样式表很大,必须独立放到一个文件里。两次HTTP 请求不会显著降低性能。

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- bad -->
<!doctype html>
<meta charset=utf-8>
<script src=analytics.js></script>
<title>Hello, world.</title>
<p>...</p>
 
<!-- good -->
<!doctype html>
<meta charset=utf-8>
<title>Hello, world.</title>
<p>...</p>
<script src=analytics.js></script>

CSS

分号

不能漏写分号

1
2
3
4
5
6
7
8
9
/* bad */
div {
  color: red
}
 
/* good */
div {
  color: red;
}

盒模型

整个文档的盒模型应该要相同,最好使用global * { box-sizing: border-box; }定义。不要修改某个元素的盒模型。

1
2
3
4
5
6
7
8
9
10
11
/* bad */
div {
  width: 100%;
  padding: 10px;
  box-sizing: border-box;
}
 
/* good */
div {
  padding: 10px;
}

尽量不要改变元素默认行为。保持默认的文本流。比如,移出一个图片下面的一个白块,不影响原本的显示:

1
2
3
4
5
6
7
8
9
/* bad */
img {
  display: block;
}
 
/* good */
img {
  vertical-align: middle;
}

类似的,尽量不要改变浮动方式。

1
2
3
4
5
6
7
8
9
10
11
12
/* bad */
div {
  width: 100px;
  position: absolute;
  right: 0;
}
 
/* good */
div {
  width: 100px;
  margin-left: auto;
}

定位

有很多CSS定位方法,尽量避免使用以下方法,根据性能排序:

1
2
3
4
5
6
display: block;
display: flex;
position: relative;
position: sticky;
position: absolute;
position: fixed;

选择器

紧密耦合DOM选择器,三个层级以上建议加class:

1
2
3
4
5
/* bad */
div:first-of-type :last-child > p ~ *
 
/* good */
div:first-of-type .info

避免不必要的写法:

1
2
3
4
5
6
7
8
9
/* bad */
img[src$=svg], ul > li:first-child {
  opacity: 0;
}
 
/* good */
[src$=svg], ul > :first-child {
  opacity: 0;
}

指明

不要让代码难于重写,让选择器更精确,减少ID、避免使用!important

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* bad */
.bar {
  color: green !important;
}
.foo {
  color: red;
}
 
/* good */
.foo.bar {
  color: green;
}
.foo {
  color: red;
}

覆盖

覆盖样式会使维护和调试更困难,所以要尽量避免。

1
2
3
4
5
6
7
8
9
10
11
12
/* bad */
li {
  visibility: hidden;
}
li:first-child {
  visibility: visible;
}
 
/* good */
li + li {
  visibility: hidden;
}

继承

不要把可继承的样式重复声明:

1
2
3
4
5
6
7
8
9
/* bad */
div h1, div p {
  text-shadow: 0 1px 0 #fff;
}
 
/* good */
div {
  text-shadow: 0 1px 0 #fff;
}

简洁

保持代码的简洁。使用属性缩写。不必要的值不用写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* bad */
div {
  transition: all 1s;
  top: 50%;
  margin-top: -10px;
  padding-top: 5px;
  padding-right: 10px;
  padding-bottom: 20px;
  padding-left: 10px;
}
 
/* good */
div {
  transition: 1s;
  top: calc(50% - 10px);
  padding: 5px 10px 20px;
}

语言

能用英文的时候不用数字。

1
2
3
4
5