C#组件系列——又一款日志组件:Elmah的学习和分享

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介:

 

正文

前言:好久没动笔了,都有点生疏,12月都要接近尾声,可是这月连一篇的产出都没有,不能坏了“规矩”,今天还是来写一篇。最近个把月确实很忙,不过每天早上还是会抽空来园子里逛逛。一如既往,园子里每年这个时候都有大把的年终总结、回忆过去展望未来之类的文章。博主是没时间写总结了,要学的东西太多。关于Vue的系列一定要抽时间补上。最近刚用了一个日志组件Elmah,比较适合开发阶段异常信息的快速定位与追溯,有兴趣的跟着博主一起来看看吧。

本文原创地址:http://www.cnblogs.com/landeanfen/p/6221403.html

 一、组件介绍

ELMAH的全称是The Error Logging Modules And Handlers,翻译过来是错误日志模块和处理。顾名思义,就是一个日志的拦截和处理组件,说到.net的日志组件,大家的第一反应该是Log4Net、NLog等这些东西,关于Log4Net和NLog,可以说是.net日志组件里面使用最为广泛的组件了,它们功能强大、使用方便。相比它们:

1、ELMAH的使用更加简单,它甚至不用写一句代码,只需要引入dll,然后在Web.config里面配置相应的节点即可;

2、按照网上的说法,ELMAH是一种“可拔插式”的组件,即在一个运行的项目里面我们可以随意轻松加入日志功能,或者移除日志功能;

3、ELMAH组件自带界面,不用写任何代码,即可查看异常日志的界面,轻松找到当前异常的详细信息;和web的结合更加紧密;

4、组件提供了一个用于集中记录和通知错误日志的机制,通过邮件的机制通知错误信息给相关人员。

二、组件安装使用

1、安装组件

 Elmah的安装使用同样也很简单,我们万能的Nuget帮我们一键搞定。

安装如上图的两个组件即可在MVC项目里面应用起来。注意这里有一个依赖关系Elmah.MVC依赖Elmah.corelibrary组件。

安装成功后,项目中会添加如下两个dll的引用。

2、配置组件

组件安装成功之后,会自动在我们MVC项目的Web.config里面添加如下节点:

复制代码
<sectionGroup name="elmah">
      <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
      <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
      <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
      <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
</sectionGroup>

......

<appSettings>
   <add key="elmah.mvc.disableHandler" value="false" />
   <add key="elmah.mvc.disableHandleErrorFilter" value="false" />      
   <add key="elmah.mvc.requiresAuthentication" value="false" />
   <add key="elmah.mvc.IgnoreDefaultRoute" value="false" />
   <add key="elmah.mvc.allowedRoles" value="*" />
   <add key="elmah.mvc.allowedUsers" value="*" />
   <add key="elmah.mvc.route" value="elmah" />
   <add key="elmah.mvc.UserAuthCaseSensitive" value="true" />
</
appSettings> ...... <httpModules> <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" /> <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" /> <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" /> </httpModules> ...... <system.webServer> <modules> <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" /> <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" /> <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" /> </modules> </system.webServer> ...... <elmah> </elmah>
复制代码

除此之外,还需要手动在Web.config里面加入如下配置节点:

复制代码
<elmah>
    <security allowRemoteAccess="false" />
    <!--三种存储方式:内存、xml、数据库。存储到xml里面格式如下行-->
    <!--<errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="~/Static/Log/" />-->
    <!--<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ElmahConn" />-->
</elmah>
  <location path="elmah.axd" inheritInChildApplications="false">
    <system.web>
      <httpHandlers>
        <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
      </httpHandlers>
    </system.web>
    <system.webServer>
      <handlers>
        <add name="ELMAH" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" preCondition="integratedMode" />
      </handlers>
    </system.webServer>
  </location>
复制代码

需要说明的是在elmah节点里面可以配置组件支持的三种日志存储方式:

  • 如果elmah节点不配置任何任何东西,表示默认组件是将日志信息保存到内存中,这种方式的弊端在于一旦系统重启,所有的异常信息都会丢失;
  •  <errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="~/Static/Log/" /> 表示日志保存到xml文件里面,第二个属性配置保存xml的路径;
  •  <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ElmahConn" /> 表示日志保存到数据库里面,第二个参数对应数据库的链接字符串的name,也就是说如果配置保存到数据库,则必须要在web.config里面配置连接字符串,这里的connectionStringName就对应我们配置的连接字符串的name,并且这个时候还需要使用脚本在数据库里面新建需要的表和存储过程,这个放在后面说。

3、测试效果

通过以上安装和配置,我们即可记录异常。首先我们采用内存的方式来记录异常,先来看看效果:

复制代码
public class HomeController : Controller
{
        public ActionResult Index()
        {
            return View();
        }
        
        //测试异常
        public JsonResult Get()
        {
            var a = 0;
            var b = 5;
            var c = b / a;
            return Json(a, JsonRequestBehavior.AllowGet);
        }
}
复制代码

然后我们前端ajax来调用

复制代码
<html>
<head>
    <title>Index</title>
    <script src="~/Scripts/jquery-1.9.1.min.js"></script>
    <script type="text/javascript">
        $(function () {
            $("#btn").click(function () {
                $.ajax({
                    type: 'get',
                    url: '/Home/Get',
                    data: {},
                });
            });
        });
    </script>
</head>
<body>
    <h1>首页</h1>
    <div> 
        <button type="button" id="btn">测试异常</button>
    </div>
</body>
</html>
复制代码

点击按钮出现异常,然后我们通过地址http://localhost:51230/elmah.axd来查看异常信息。

点击展开详细信息如下

 到这一步,我们的组件就可以生效了。但是看到这个elmah.axd这个路径太恶心了,我们想要改一下,用我们自己的路径,呵呵,这个确实是可以配置的。我们再来看看web.config里面的location节点,在location节点里面其实就配置一个东西——HttpHandler,虽然有 system.web 和 system.webServer 两个节点,如果你仔细观察,其实它们是一个东西,只不过是为了兼容不同的IIS版本而写了两个配置,这一点和我们HttpHandler的配置是相同的,对于这个配置不熟悉的,可以看看博主之前的文章http://www.cnblogs.com/landeanfen/p/6000978.html。我们将location的节点改成这样:

复制代码
  <location path="log.axd" inheritInChildApplications="false">
    <!--<system.web>
      <httpHandlers>
        <add verb="POST,GET,HEAD" path="log.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
      </httpHandlers>
    </system.web>-->
    <system.webServer>
      <handlers>
        <add name="ELMAH" verb="POST,GET,HEAD" path="log.axd" type="Elmah.ErrorLogPageFactory, Elmah" preCondition="integratedMode" />
      </handlers>
    </system.webServer>
  </location>
复制代码

然后我们通过http://localhost:51230/log.axd这个地址来访问,能达到同样的效果。博主本地使用的是IIS经典模式,所以使用的是system.webServer里面的配置,注释掉或者删掉system.web节点都不会有任何问题。

三、功能介绍

1、将日志信息保存到数据库

上述使用在内存中保存日志信息的方式,在实际项目中基本上很少会用到。除此之外,还有保存到xml和数据库两种方式。保存到xml文件这个没什么好说的,就是配置一下保存路径即可。下面就以保存到数据库的方式来看看想想介绍下。

首先我们在web.config里面加入连接字符串节点。

复制代码
  <connectionStrings>
    <add name="ElmahConn" connectionString="Data source=127.0.0.1;Initial Catalog=PowerMangent;Persist Security Info=True;User ID=sa;Password=123456" providerName="System.Data.EntityClient" />
    <add name="ElmahContainer" connectionString="metadata=res://*/Elmah.csdl|res://*/Elmah.ssdl|res://*/Elmah.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=127.0.0.1;initial catalog=PowerMangent;user id=sa;password=123456;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>
复制代码

然后配置elmah节点

  <elmah>
    <security allowRemoteAccess="false" />
    <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ElmahConn" />
  </elmah>

最后就是在数据库创建需要的表和存储过程,官方提供了脚本,这个不用我们担心,脚本如下

  CreateElmah.sql

 做了以上三步之后,程序里面的异常就能记录到数据库里面,程序再次启动的时候会自动从数据库里面去取对应的信息。

2、程序“吃掉”异常

如果你反编译elmah组件,你会它的原理其实就是通过配置的方式通过HttpModule注册应用程序的Error事件,然后统一处理记录。既然是注册的Application_Error事件,那么肯定就存在某些情况会吃掉异常。

(1)在程序里面try...catch...

这种情况很好理解,如果你再代码里面显示的声明了try...catch那么异常肯定不会进到Application_Error事件里面去,组件也不会记录异常。

(2)在异常捕获器里面处理了异常

除了使用try吃掉异常之外,很多系统里面都会使用异常捕获器去统一捕获异常,如果再异常捕获器里面设置过异常已经处理,组件也不会记录异常。比如:

复制代码
    protected override void OnException(ExceptionContext filterContext)
        {
            //如果加了这一句,表示异常已经处理,不会尽到应用程序的Error事件里面去
            filterContext.ExceptionHandled = true;
 
           //........

            base.OnException(filterContext);
        }
复制代码

这就是异常捕获器统一处理异常,既然这里标识了异常已经处理过,那么组件肯定不会再次处理。可是有些情况下,我们需要处理某些自定义异常,而对于系统异常我们还是希望组件能够记录,这种情况下怎么办呢?其实很简单,这里只需要判断一下,如果是自定义异常信息,这里就加上 filterContext.ExceptionHandled = true; 这一句,而对于其他系统异常,则统一加上这一句即可。这里还是做一个简单的演示供需要的园友参考。

    public class MyException : Exception
    {
        public MyException(string message) : base(message)
        { }
    }

满足一定条件则抛出自定义异常

复制代码
        public JsonResult Get()
        {
            if (DateTime.Now > Convert.ToDateTime("2016-12-15 10:00:00"))
            {
                //如果满足某些条件则抛出异常
                throw new MyException("当前时间已过期");
            }

            return Json("OK", JsonRequestBehavior.AllowGet);
        }
复制代码

然后再全局异常处理里面

复制代码
        protected override void OnException(ExceptionContext filterContext)
        {
            if (filterContext.Exception is MyException)
            {
                //如果加了这一句,表示异常已经处理,不会进到应用程序的Error事件里面去
                filterContext.ExceptionHandled = true;
            }

            base.OnException(filterContext);
        }
复制代码

这样就能达到我们系统异常记录,自定义异常不记录的目的了。

3、组件权限问题

 关于elmah组件,被人诟病的一个重要原因就是其安全问题,如果控制不好很容易招到他人入侵。大神汤姆大叔有篇文章记录这个,有兴趣可以看看。关于我们/elmah.axd路径,我们肯定是需要做一些限制,不能允许每个人都去查看,下面从以下几个方面来完善。

(1)拒绝远程访问

在web.config里面有一个节点配置不允许远程访问。

  <elmah>
    <security allowRemoteAccess="false" />
  </elmah>

(2)拒绝匿名用户访问

对于没有登录到系统的用户,拒绝访问。这个可以在IIS上面配置,当然,我们在web.config里面也要做相应的配置

复制代码
<location path="log.axd" inheritInChildApplications="false">
    <system.web>
      <authorization>
           <deny users="?"/>
        </authorization>
    </system.web>
  </location>
复制代码

(3)指定角色或用户访问

 可以在应用程序全局配置文件Global.asax里面的认证事件里面去做判断。

复制代码
protected void Application_AuthenticateRequest(object sender, EventArgs e)
        {
            HttpApplication app = (HttpApplication)sender;
            // 处理日志权限问题
            if (Request.Url.ToString().Contains("elmah.axd"))
            {
                var user = app.Context.User;
                if (user == null)
                {
                    Response.Write("无权限访问");
                    Response.End();
                }
                var userData = (UserInfo)user;
                //管理员角色才能查看
                if (!userData.UserData.IsAdmin)
                {
                    Response.Write("无权限访问");
                    Response.End();
                }
  
                //或者指定用户才能访问
               //if (userData.UserData.UserName!="administrator")
                //{
                   // Response.Write("无权限访问");
                   //Response.End();
                //}
            }
        }
复制代码

四、总结

以上总结了组件Elmah组件的使用和一些常见问题的处理。有兴趣的可以看看。欢迎推荐





本文转自懒得安分博客园博客,原文链接:http://www.cnblogs.com/landeanfen/p/6221403.html,如需转载请自行联系原作者

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
26天前
|
Arthas 监控 Java
JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)、Arthas
这篇文章全面介绍了JVM的命令行参数、GC日志分析以及性能调优的各个方面,包括监控工具使用和实际案例分析。
39 3
|
1月前
|
存储 Prometheus NoSQL
大数据-44 Redis 慢查询日志 监视器 慢查询测试学习
大数据-44 Redis 慢查询日志 监视器 慢查询测试学习
22 3
|
1月前
|
数据采集 监控 Java
SpringBoot日志全方位超详细手把手教程,零基础可学习 日志如何配置及SLF4J的使用......
本文是关于SpringBoot日志的详细教程,涵盖日志的定义、用途、SLF4J框架的使用、日志级别、持久化、文件分割及格式配置等内容。
96 0
SpringBoot日志全方位超详细手把手教程,零基础可学习 日志如何配置及SLF4J的使用......
|
2月前
|
Kubernetes API Docker
跟着iLogtail学习容器运行时与K8s下日志采集方案
iLogtail 作为开源可观测数据采集器,对 Kubernetes 环境下日志采集有着非常好的支持,本文跟随 iLogtail 的脚步,了解容器运行时与 K8s 下日志数据采集原理。
|
26天前
|
Python
log日志学习
【10月更文挑战第9天】 python处理log打印模块log的使用和介绍
25 0
|
26天前
|
开发框架 缓存 算法
开源且实用的C#/.NET编程技巧练习宝库(学习,工作,实践干货)
开源且实用的C#/.NET编程技巧练习宝库(学习,工作,实践干货)
|
1月前
|
缓存 Linux 编译器
【C++】CentOS环境搭建-安装log4cplus日志组件包及报错解决方案
通过上述步骤,您应该能够在CentOS环境中成功安装并使用log4cplus日志组件。面对任何安装或使用过程中出现的问题,仔细检查错误信息,对照提供的解决方案进行调整,通常都能找到合适的解决之道。log4cplus的强大功能将为您的项目提供灵活、高效的日志管理方案,助力软件开发与维护。
49 0
|
2月前
|
Linux C# 开发者
Uno Platform 驱动的跨平台应用开发:从零开始的全方位资源指南与定制化学习路径规划,助您轻松上手并精通 C# 与 XAML 编程技巧,打造高效多端一致用户体验的移动与桌面应用程序
【9月更文挑战第8天】Uno Platform 的社区资源与学习路径推荐旨在为初学者和开发者提供全面指南,涵盖官方文档、GitHub 仓库及社区支持,助您掌握使用 C# 和 XAML 创建跨平台原生 UI 的技能。从官网入门教程到进阶技巧,再到活跃社区如 Discord,本指南带领您逐步深入了解 Uno Platform,并提供实用示例代码,帮助您在 Windows、iOS、Android、macOS、Linux 和 WebAssembly 等平台上高效开发。建议先熟悉 C# 和 XAML 基础,然后实践官方教程,研究 GitHub 示例项目,并积极参与社区讨论,不断提升技能。
78 2
|
3月前
|
JSON 中间件 Go
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
本文详细介绍了如何在Go项目中集成并配置Zap日志库。首先通过`go get -u go.uber.org/zap`命令安装Zap,接着展示了`Logger`与`Sugared Logger`两种日志记录器的基本用法。随后深入探讨了Zap的高级配置,包括如何将日志输出至文件、调整时间格式、记录调用者信息以及日志分割等。最后,文章演示了如何在gin框架中集成Zap,通过自定义中间件实现了日志记录和异常恢复功能。通过这些步骤,读者可以掌握Zap在实际项目中的应用与定制方法
125 1
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
|
3月前
|
消息中间件 监控 搜索推荐
OpenFeign日志组件Logger原理与应用
该文章详细解释了如何在OpenFeign中配置并使用请求和响应的GZIP压缩功能。