使用Spring跟踪应用程序异常

几周前,一位同事要求我花一个星期的时间做后援,因为他需要一个掩护,而他度过了一个赚钱的假期,而他找不到其他人。 当我刚完成一个特别复杂的编码项目并感到有些疲倦时,我说“是”。 毕竟,改变对我有好处。

工作的一部分包括监视一组相当关键的支持流程,以查看它们的执行情况以及它们是否出错。

我们的开发人员花费大量时间和精力在我们的应用程序中添加日志记录,以证明它可以正常工作并找出发生异常时出了什么问题。 这些日志文件通常用于告诉我们我们的应用程序每天的运行状况有多好。

我忽略了其他技术,例如通过选择的任何方法(例如HTTP或JMX)向应用程序添加探针。 这些提供有关您的应用程序的即时信息,而不是此处讨论的第二级监视。

至少有三种监视日志文件的方式:

  • 决不
  • 积极地
  • 主动地

“从不”表示它的意思。 我敢打赌,有些应用程序会上线,似乎永远不会失败,也不会被检查。

“反应式”策略非常普遍; Doncaster的Smith夫人打电话给她,抱怨说她试图买一双新鞋时网站崩溃了。 她被起诉了两次,从未收到任何鞋子。 在这个传统的公司中,DEV和OPS的角色完全分开,研究问题的开发人员要求OPS记录事件发生的时间和日期。 当然,开发人员会获取日志中完全不相关的部分,并且不得不重新请求正确的部分-几次。 到那时,已经过去了几个星期,史密斯太太很生气。 日志最终到达,问题得以解决。

在这种“反应性”场景中,我假设当开发人员在没有信任或允许接触实时服务器的情况下,这就是那些公司之一。 这太普遍了,我们大多数人都会去过那里。 开发人员应该可以使用实时系统。 但是,作为开发人员,您应该记住在处理实时系统时有两个黄金法则:

  1. 不要破坏任何东西。
  2. 如果您确实弄坏了东西,请确保您还有其他责任。

“主动”是指定期检查日志文件:每天,每小时或任何时间。 即使您的应用程序包含大量的JMX,http或其他探针,也无法保证它们会发现问题。 探测只能探测您告诉他们要探测的内容,其他任何问题都无法解决。

回到我的支持上来……是出于某种(可能是历史原因)的原因,此监视的大部分内容包括使用一组记录的“ grep”命令通过一些剪切和粘贴手动检查日志文件中的错误。 如果您将花费的时间加在重复的剪切和粘贴工作上,那么我可以确认,它每周大约消耗½人日。

这让我开始思考……我真的不喜欢做这种任务。 我不太擅长,它是手动的,容易出错,重复并且很无聊。 每周要花费½个工作日来完成这项任务,显然会节省成本,只要不花时间在使他的解决方案完美无缺上。 那么,有哪些选择呢?

如果您从专业的角度来看,那么Splunk就是可以监视来自多种来源(例如syslog守护程序)的消息的工具。

这意味着向Splunk发送错误的一种简单方法是简单地设置Log4j syslog附加程序,但这超出了本博客的范围……

在快速而肮脏的范围内,您可以非常Swift地编写一个shell脚本来执行一些“ grep”命令,将结果写入文件并将其邮寄到您的Unix邮箱。

然后我想到了中间立场。 编写一个包含尽可能多的通用可重用类的Spring应用程序有多困难,它会定期运行以检查大量错误日志并通过电子邮件将结果发送给您。 对于这种事情,电子邮件是件好事,因为您通常出于习惯阅读它们。

入门

在任何这样的项目中,都有一些无形的第一步可以推动整个过程。 它们构成了对您需要编写哪些类才能发布此“东西”的问题的答案? 有很多方法可以确定需要编写哪些类,例如,使用UML,快速原型设计或测试驱动设计之类的正式设计技术,凭空挑选它们(胆怯)。 在每种情况下,您真正​​要做的就是提出一些要求,从中弹出某些类的名称。 例如,在这种情况下,我需要:

  1. 搜索给定目录及其子目录(可能)以查找特定类型的文件。
  2. 如果找到文件,请检查其日期:是否需要搜索文件以查找错误?
  3. 如果文件足够年轻以至于无法检查,则对其进行验证,以查找异常。
  4. 如果它包含例外,是我们正在寻找的例外还是被排除在外?
  5. 如果它包含我们所需要的例外类型,则将详细信息添加到报告中。
  6. 检查完所有文件后,格式化报告以准备发布。
  7. 使用电子邮件或其他技术发布报告。
  8. 整个过程每天都会在给定的时间运行

这抛出了几个类的名称。 我需要一个FileLocatorFileValidatorRegexValidatorFileAgeValidator和一个Report

鉴于以上列表中多次出现“ Validator”一词,这表明我可以使用一个接口(大概称为Validator并创建多个实现来执行上述验证任务。 然后可以将这些实现组合在一起以创建一个一致的应用程序。

请注意,这只是想法的初步列表。 如果看一下代码,将找不到名为Report的类,将其重命名为Results并进行重构以创建Formatter接口, TextFormatterHtmlFormatter类以及Publisher接口和EmailPublisher类。

就定期运行此功能而言,有两种选择。 首先,您可以将Java代码与一个简单的脚本一起编写以调用它,并将其提供给Unix机器crontab。 没关系,但这意味着该应用程序无法在Windows上运行,并且只能作为独立应用程序运行。 这可能是一件大事,所以可以选择使用Spring和Quartz时间表。 使制定Cron时间表相当简单。

至于报告的电子邮件发送; 再次,Spring提供了一个非常好的电子邮件模板,可以简化Java电子邮件类的使用。

好的,这就是起点:一组模糊的类想法可以以某种松散耦合的方式链接在一起以创建我们的应用程序。 如果您走了一条正式路线,那么您可能想花时间记录所有这些内容,甚至可能制作一个类图,然后将其添加到Word文档中,并进行多次审查,直到一切都定下来。 但是,我不必为此烦恼……

配置应用程序

与任何应用程序一样,需要弄清楚我们将如何设置通常是整个属性值的数组以及应用程序如何使用它们。 该应用程序通常由src/main/resources目录中的app.properties文件驱动。

# 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.to=info@captaindebug.com
# The max age of a file in days
max.days=1000

我们感兴趣的第一个属性是scan.in属性。 这是我们Web服务器日志目录的位置,用作下一节概述的FileLocator类的起点。

搜索文件

在编写FileLocator我超出了要求,并有意进行了一些“镀金” 。

镀金确实是个坏主意。 您应该只编写足以满足功能要求的代码,即可以完成工作。 在这种情况下,作为一个博客……我的博客,我可以说它符合记录我以前使用过多次的技术的非功能性要求,以此来证明它是合理的。

以下代码不仅在指定的日志文件目录中搜索日志文件,还搜索所有/任何子目录。

@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对象的search() 。 如果目录检查显示File对象是文件,则调用文件验证。

到目前为止,到目前为止,使用应用程序的第一类,我们现在可以搜索日志文件目录; 但是,如果您想知道找到文件后会发生什么,则必须等到下一个博客发布为止。

最后一个想法:您是否需要调查系统中的每个错误? 有一句古老的哲学名言:如果一棵树在森林中倒下而没有人听到,它还能发出声音吗? 同样,如果您的应用程序引发异常并且用户不受影响,那么它仍然是错误吗? 您需要花费时间进行调查吗? 让我知道你的想法?

  • 该博客的代码可在Github上找到: https : //github.com/roghughe/captaindebug/tree/master/error-track 。

参考: Captain Debug的Blog博客上的JCG合作伙伴 Roger Hughes 使用Spring跟踪了应用程序异常 。

翻译自: https://www.javacodegeeks.com/2014/03/tracking-application-exceptions-with-spring.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/364677.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php redis.dll php5.6,在Windows 64位下为PHP5.6.14安装redis扩展

一.php安装redis扩展1.使用phpinfo()查看当前版本的信息2.根据PHP版本号,编译器版本号和CPU架构选择php_redis-2.2.5-5.6-nts-vc11-x64.zip和php_igbinary-1.2.1-5.5-nts-vc11-x64.zip下载地址:http://windows.php.net/downloads/pecl/snaps/redis/2.2.5…

js sort方法根据数组中对象的某一个属性值进行排序(实用方法)

js sort方法根据数组中对象的某一个属性值进行排序 sort方法接收一个函数作为参数,这里嵌套一层函数用来接收对象属性名,其他部分代码与正常使用sort方法相同. var arr [{name:zopp,age:0},{name:gpp,age:18},{name:yjj,age:8} ];function compare(pr…

洛谷 P1018乘积最大

题目描述 今年是国际数学联盟确定的“20002000――世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰9090周年。在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友XZXZ也有幸得以参加。活动中,主…

matrix derivatives

来源:cs229 stanford Machine Learning Notes转载于:https://www.cnblogs.com/pertinencec/p/10082965.html

Project Student:维护Webapp(只读)

这是Project Student的一部分。 其他职位包括带有Jersey的 Web服务 客户端,带有Jersey的 Web服务服务器 , 业务层 , 具有Spring数据的持久性 ,分片集成测试数据 , Webservice集成和JPA标准查询 。 当我开始这个项目时…

基于vue的无缝滚动组件

vue-seamless-scroll A simple, Seamless scrolling for Vue.js 在awesome上一直没有发现vue的无缝滚动组件,在工作之余写了个组件,分享出来希望大家一起学习进步。Demo https://github.com/chenxuan0000/vue-seamless-scroll/index.html Installatio…

教务管理及教材订购系统设计文档

教务管理及教材订购系统设计文档目录 一、概述 1.1 开发背景 1.2 使用技术 1.3运行环境 1.4 设计目标 1.4.1权限管理 1.4.2信息管理 1.4.3选课管理 1.4.4 成绩管理 1.4.5教材订购 二、功能分析划分 2.1信息管理 2.1.1班级信息管理 2.1.2专业信息管理 2.1.3课程信息管理 2.1.4学…

关于构造器中的super()

1、为什么在子类的constructor里面要加一句super()? 答:如果子类用了extends的关键字继承的父类,那么子类在使用构造器的时候就要加super()语句,这是语法规范,就是这么定…

php 复制行,phpstorm怎么快速复制当前行?

qq_花开花谢_0PhpStorm 默认快捷键ctrlj 插入活动代码提示ctrlaltt 当前位置插入环绕代码altinsert 生成代码菜单Shift Enter 新一行ctrlq 查看代码注释ctrld 复制当前行ctrly 删除当前行ctrlalty 刷新项目缓…

Project Student:维护Webapp(可编辑)

这是Project Student的一部分。 其他帖子包括带有Jersey的 Web服务 客户端,带有Jersey的 Web服务服务器 , 业务层 , 具有Spring数据的持久性 ,分片集成测试数据 , Webservice集成 , JPA标准查询和维护Webap…

express接受get数据

server.use(/,function(req,res){res.writeHead(200, { content-type:text/html;charsetutf-8});var namereq.query[name]; //直接req.query[参数名称];var pwdreq.query[pwd];if(!users[name]){res.write("不存在该用户");}else if(users[name]!pwd){re…

php curl 采集文件,curl获取远程文件内容

/**获取远程文件内容param $url 文件http地址*/function fopen_url($url){if (function_exists(file_get_contents)) {$file_content file_get_contents($url);} elseif (ini_get(allow_url_fopen) && ($file fopen($url, rb))){$i 0;while (!feof($file) &&…

SAP work process Memory allocate

SAP work process Memory allocate Memory allocation sequence to dialog work processes in SAP What is the memory allocation sequence to dialog work processes in SAP?When does a work process go to PRIV mode?How to avoid or minimize work process going to PRI…

基于 Vue.js 的移动端组件库mint-ui实现无限滚动加载更多

通过多次爬坑,发现了这些监听滚动来加载更多的组件的共同点, 因为这些加载更多的方法是绑定在需要加载更多的内容的元素上的, 所以是进入页面则直接触发一次,当监听到滚动事件之后,继续加载更多, 所以对…

创建Maven源代码和Javadoc工件

许多人都知道Maven源代码和Javadoc工件,但是不知道为什么要创建它们。 我肯定在这个阵营中–我可以理解为什么人们想要此信息,但是由于要手动导航Maven存储库,因此获取信息似乎相对效率较低。 然后我被线索棒击中。 这些工件由IDE而非人员使…

JS内置方法(object)

属性 constructorprototype 实例方法 1、toString()返回当前对象的字符串形式,返回值为String类型。 2、toLocaleString()返回当前对象的"本地化"字符串形式,以便于当前环境的用户辨识和使用,返回值为String类型。 3、valueOf()返回…

金蝶云php webapi,K/3 Cloud Web API销售出库单PHP完整示例【分享】

按照惯例,先上图【销售出库单】保存,如图:已经打印出 登陆请求及登陆成功,保存请求及保存成功的返回信息。如下代码,是完全可以直接进行运行的代码,具体详见代码中注释。[code]//K/3 Cloud 业务站点地址$cl…

JavaFX自定义控件– Nest Thermostat第2部分

自从我开始创建Nest恒温器FX自定义控件以来,已经有一段时间了! 因此,上次,如Gerrit Grunwald所建议,我花了一些时间用inkscape复制Nest恒温器设计,这是构建JavaFX版本的第一步。 今天,我想与大…

函数和模块的使用

函数: 函数作用: 减少代码重复 增加程序可扩展性 使程序易于维护 函数定义: 关键字:def 名称:与变量名命名规则相同 参数: def fun() #无参数 def fun(x) #普通参数 def fun(name, age22, happyalex) #默…

关于 Error: No PostCSS Config found in 的错误

问题描述: 项目在本地运行不报错,上传到 GitHub 之后,再 clone 到本地, npm install安装完成之后再执行 npm run dev这时报错 Error: No PostCSS Config found in... 本以为是 GitHub 上传的问题,后开又试了两回&am…