使用Spring跟踪应用异常(1)

标签: 基础技术 教程 Spring 异常处理 | 发表时间:2014-06-18 08:00 | 作者:dqiushuang
出处:http://www.importnew.com

几周以前,一个同事请我帮他一周的忙。他想要享受一个难得的假期,但是找不到其他人帮他。由于我刚完成一个特别复杂的编码工作,需要来点自我调节,所以就答应了他的请求。换换环境对我也是非常有益的。

那份工作的一部分是监控一些非常关键的后台运行进程,观察它们是否运行正常。

开发者花了很多时间和精力在应用中加入日志输出,以此表明应用正常运行。当异常发生时,可以知道究竟出现了什么错误。这些日志文件通常可以说明我们的应用每天运行究竟是正常的还是异常的。

在这里,我将忽略其它技术。比如为应用增加类似HTTP或JMX监视器。这些技术提供的是应用程序即时信息,而不是本文讨论的二级监视结果。

监控日志文件通常有三种方式:

  1. 从不检查;
  2. 被动检查;
  3. 主动检查。

从不检查意味着那些应用一直运行从不停止,而且也不需要检查。这一点我敢打赌。

被动检查是很常见的。举个例子,Smith太太打电话投诉当她想要买一双新鞋时,网站就瘫痪了。她已经支付了两次,但是从没收到过鞋子。在这个传统的公司中,开发者和运维工程师是被完全隔离的。必须从运维工程师获得该问题发生时的日志,开发者才能开始分析。但是从运维那里返回的往往是一些完全不相关的日志,接下来开发者不得不再次向他们索要日志,甚至如此反复多次。这个过程耗费了几周时间,Smith太太变得怒不可遏。最后,日志终于到了开发者手中,问题解决。

可能很多公司都像上面“被动检查”的场景中描述的那样,开发者不被信任或允许操作在线服务器。这种情况司空见惯,我们中的绝大部分人都遇到过这种情况。我们应当信任开发者去操作在线系统。然而,作为一个开发者,在操作在线系统之前,必须记住两条黄金定律:

  1. 不要停止任何东西;
  2. 如果停止某些东西,请确保有人会在身边提醒你。

“主动检查”意味着检查日志文件要成为一个定期任务:每天、每小时或其它间隔定期执行。即使你的应用包含了大量的JMX、http或其他监视器,也不能确保一定会能发现每个问题。监视器只能发现你设定问题,除此之外的其他任何问题都不会报告。

再回到要我帮忙的问题,可能是历史的或其他原因,通过手动检查日志文件来监控系统运行,通常要对一些文件进行剪切或粘贴操作。这些重复的剪切和粘贴操作,每周大概会占用一个人半天的工作时间。

我非常不喜欢这些工作。我不善于这些需要手动且易出错的重复无聊的工作。每周要消耗半天人力,所以将这项任务自动化显然更符合成本效益。只要时间不是花在追求完美的解决方案上。那么,有什么选择呢?

如果你看了日志的规模,你一定会喜欢上Splunk,它能够监控多个消息源(譬如系统的日志守护进程)的消息。

这就意味着向Splunk发送错误只是简单地建立一个Log4j的系统日志附加器,不过那不是这篇博文的范畴…

最后,你需要写一些shell脚本来完成一些类似于“grep”命令的功能,将结果写入文件,并将这些文件通过邮件发送给你。

开发一个基于Spring的app有多难?它需要包含一些尽可能通用的、可重用的类,能够定期检查错误日志文件并将结果通过邮件发送给你。当然,结果还是通过邮件发送比较好,因为你总是会习惯性地查看你的邮箱。

开始

在其他类似的工程当中,都面临着如何迈出第一步的问题。要想让这个工程发布,需要写哪些类。有很多方法来确定你需要写哪些类,譬如简单地凭直觉,或者利用类似UML的设计工具,或者用快速原型或 测试驱动开发。在每种情况下,你真正要做的就是让类名体现的功能满足一些要求。例如,在这里我需要:

  1. 搜索一个给定的路径和子路径,找出某种特定类型的文件。
  2. 检查找到文件的时间,判断是否有必要在这个文件中搜索错误。
  3. 时间满足要求,则在其中查找异常。
  4. 找到异常,则判断是否是我们关注的,还是需要忽略它。
  5. 如果异常是我们关注的,则将其加到报告中。
  6. 检查完所有文件后,形成待发布报告。
  7. 通过邮件或其他方式发布报告。
  8. 以上所有操作每天定时执行。

这些操作就形成了几个类名:FileLocator、FileValidator、RegexValidator、FileAgeValidator和Report。

上述几个类名中包含了多次的“Validator”,意味着我们可以用一个接口,叫做“Validator”。利用接口的几个实现来完成上面的验证工作。这些实现可以结合起来组成一个应用。

这只是一个初步的想法。如果你看了代码,会发现没有一个类名是Report,只有一个Results类和 重构的Formatter接口、TextFormatter和HtmlFormatter类、Publisher接口和EmailPublisher类。

为了让任务定期执行,有多种选择。首先,需要将java代码和调用它的脚本放在一起,然后放在Unix机器上执行。但是这就意味着该应用不能在Windows上运行,并且只能作为一个独立的应用。这是个大问题,所以我们可以利用Spring和Quartz调度,使得建立一个调度任务非常简单。

而且Spring提供了一个非常好的Java邮件类和Email模板,这对我们的报告邮件非常有用。

这些只是开始,关于类设计一些模糊的想法通过一种松耦合的方式连接在一起组成了我们的应用。如果在正式的工作中,你可能需要花时间把这些整理成文档,甚至需要画出类图,加在一个Doc文档中,然后多次复查直到都不在改变。但是,我不需要去管这些…

配置应用

和其他应用一样,我们需要指出系统建立必须的属性值以及它们是如何被使用的。这个应用由app.properties文件配置,路径为src/main/resources。

# The path to the log file directory to scan for errors 
scan.in=/Library/Tomcat/logs
# A regex defining what to look for - or what not to include
scan.for=^.*Exception.*
exclude=^.*IllegalStateException.*
# The number of following lines to add to the report
following.lines=10
# Where to email the report
[email protected]
# The max age of a file in days
max.days=1000

第一个我们感兴趣的属性是scan.in,它是Web服务器的日志路径,作为类FileLocator的输入参数。

搜索文件

在编写FileLocator类时,我在要求的范围之外做了一点提升。

提升真的不是一个好主意。你应该为了满足功能要求而编写代码,那是为了完成工作。

下面的代码不只是搜索指定路径下的log文件,还搜索所有的子目录。

@Service
public class FileLocator {

  private static final Logger logger = LoggerFactory.getLogger(FileLocator.class);

  @Value("${scan.in}")
  private String scanIn;

  @Autowired
  @Qualifier("fileValidator")
  private Validator validator;

  /** Search for the files requested */
  public void findFile() {

    logger.info("Searching in... {}", scanIn);
    File file = createFile(scanIn);
    search(file);
  }

  @VisibleForTesting
  File createFile(String name) {
    return new File(name);
  }

  private void search(File file) {

    if (file.isDirectory()) {
      logger.debug("Searching directory: {}", file.getName());
      File[] files = file.listFiles();
      searchFiles(files);
    } else {
      logger.debug("Validating file: {}", file.getName());
      validator.validate(file);
    }
  }

  private void searchFiles(File[] files) {
    for (File file : files) {
      search(file);
    }
  }
}

上面的代码用比较传统的递归方法来搜索日志文件,主要的入口函数是findFile()。它利用Spring标记@Value标记的scanIn实例变量创建一个File对象,并把其传给search()方法,由该方法检查这个File对象是不是一个目录。如果是目录,则对该目录下的每一个File对象循环调用search()。如果File对象是一个文件,则用文件验证类来处理。
到目前为止,利用应用的第一个类,我们能搜索一个指定的日志文件路径,找到该路径下的日志文件。如果你想知道搜索到文件后做了什么,就需要等待我的下一篇博文。

最后一个思考:是否需要关注系统中的每一个错误?有一个古老的哲学寓言:如果森林里的一棵树到了,但是没有其他任何一棵树听见,还能认为它发出了声音吗?同样道理,如果你的应用抛出了一个异常,但是用户没有受到影响,这还是一个错误吗?是否还需要花时间研究它?

以上代码请见Github: https://github.com/roghughe/captaindebug/tree/master/error-track

相关文章

相关 [spring 跟踪 应用] 推荐:

使用Spring跟踪应用异常(1)

- - ImportNew
几周以前,一个同事请我帮他一周的忙. 他想要享受一个难得的假期,但是找不到其他人帮他. 由于我刚完成一个特别复杂的编码工作,需要来点自我调节,所以就答应了他的请求. 那份工作的一部分是监控一些非常关键的后台运行进程,观察它们是否运行正常. 开发者花了很多时间和精力在应用中加入日志输出,以此表明应用正常运行.

使用spring-boot快速开发spring应用

- - 企业架构 - ITeye博客
spring多年以来一直都是java平台开发web应用的主流技术,在标准的J2EE架构之外提供了一个轻量级的解决方案. 虽然spring提供了很多功能,简化了java平台的企业应用开发,降低了开发工作量,但相比较其它语言的一些框架(例如ruby on rails,python Django)来说,基于spring 的开发仍然比较复杂,尤其是新建一个项目时,需要进行各种配置,重复的工作量较大.

Spring AOP 实现原理与 CGLIB 应用

- - 博客 - 伯乐在线
来源: IBM Developerworks. 简介: AOP(Aspect Orient Programming),也就是面向方面编程,作为面向对象编程的一种补充,专门用于处理系统中分布于各个模块(不同方法)中的交叉关注点的问题,在 Java EE 应用中,常常通过 AOP 来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等.

spring+hibernate多数据源的应用

- - CSDN博客推荐文章
我有两个数据库test,和test1,两个库里都有一张表TEST_ONE. applicationContext.xml的配置如下. //数据库test1配置.   //整合两个数据源,指定数据源管理类.    //数据库test.    //数据库test1. //这个类是用来管理数据源的,配置文件中.

Spring/Hibernate应用性能调优

- - ImportNew
对于大多数典型的Spring/Hibernate 企业应用来说,应用程序的性能几乎完全取决于它的持久层的性能. 这篇文章将会对如何确认在“数据库约束”的应用前,使用7种“快速见效”的技巧来帮助我们提升应用性能. 如何确认一个应用受到“数据库约束”. 为了验证一个应用程序是否受到“数据库约束”,首先在一些开发环境中做一些普遍的行为,即使用 VisualVM来监控.

Spring / Hibernate应用性能调优

- - ImportNew
对大部分典型的Spring/Hibernate企业应用来说,应用的性能大部分由持久层的性能决定. 这篇文章会重温一下怎么去确认我们的应用是否是”数据库依赖(data-bound)”( 译者注:即非常依赖数据库,大量时间花在数据库操作上),然后会大概过一下7个常用的提升应用性能的速效方案. 怎么确定应用是否是“数据库依赖”.

spring boot应用启动原理分析

- - ImportNew
在spring boot里,很吸引人的一个特性是可以直接把应用打包成为一个jar/war,然后这个jar/war是可以直接启动的,不需要另外配置一个Web Server. 如果之前没有使用过spring boot可以通过下面的demo来感受下. 下面以这个工程为例,演示如何启动Spring boot项目:.

Spring MVC+JQuery+Google Map打造IP位置查找应用(1)

- - 企业架构 - ITeye博客
All examples are simple, easy to read, and full source code available, and of course well tested in our development environment.. 在本文中,读者将学习到如何使用Spring MVC框架和jQuery及Google Map,制作一个简单的根据IP位置查找应用.

在应用层通过spring解决数据库读写分离

- - CSDN博客推荐文章
如何配置mysql数据库的主从. 单机配置mysql主从: http://my.oschina.net/god/blog/496. 常见的解决数据库读写分离有两种方案. http://neoremind.net/2011/06/spring实现数据库读写分离. 目前的一些解决方案需要在程序中手动指定数据源,比较麻烦,后边我会通过AOP思想来解决这个问题.

Spring/Hibernate_应用性能优化的7种方法

- - 企业架构 - ITeye博客
对于大多数典型的 Spring/Hibernate 企业应用而言,其性能表现几乎完全依赖于持久层的性能. 此篇文章中将介绍如何确认应用是否受数据库约束,同时介绍七种常用的提高应用性能的速成法. 如何确认应用是否受限于数据库. 确认应用是否受限于数据库的第一步,是在开发环境中进行测试,并使用 VisualVM 进行监控.