几周前,一位同事要求我花一个星期的时间做后援,因为他需要一个掩护,而他度过了一个赚钱的假期,而他找不到其他人。 当我刚完成一个特别复杂的编码项目并感到有些疲倦时,我说“是”。 毕竟,改变对我有好处。
工作的一部分包括监视一组相当关键的支持流程,以查看它们的执行情况以及它们是否出错。
我们的开发人员花费大量时间和精力在我们的应用程序中添加日志记录,以证明它可以正常工作并找出发生异常时出了什么问题。 这些日志文件通常用于告诉我们我们的应用程序每天的运行状况有多好。
我忽略了其他技术,例如通过选择的任何方法(例如HTTP或JMX)向应用程序添加探针。 这些提供有关您的应用程序的即时信息,而不是此处讨论的第二级监视。
至少有三种监视日志文件的方式:
- 决不
- 积极地
- 主动地
“从不”表示它的意思。 我敢打赌,有些应用程序会上线,似乎永远不会失败,也不会被检查。
“反应式”策略非常普遍; Doncaster的Smith夫人打电话给她,抱怨说她试图买一双新鞋时网站崩溃了。 她被起诉了两次,从未收到任何鞋子。 在这个传统的公司中,DEV和OPS的角色完全分开,研究问题的开发人员要求OPS记录事件发生的时间和日期。 当然,开发人员会获取日志中完全不相关的部分,并且不得不重新请求正确的部分-几次。 到那时,已经过去了几个星期,史密斯太太很生气。 日志最终到达,问题得以解决。
在这种“反应性”场景中,我假设当开发人员在没有信任或允许接触实时服务器的情况下,这就是那些公司之一。 这太普遍了,我们大多数人都会去过那里。 开发人员应该可以使用实时系统。 但是,作为开发人员,您应该记住在处理实时系统时有两个黄金法则:
- 不要破坏任何东西。
- 如果您确实弄坏了东西,请确保您还有其他责任。
“主动”是指定期检查日志文件:每天,每小时或任何时间。 即使您的应用程序包含大量的JMX,http或其他探针,也无法保证它们会发现问题。 探测只能探测您告诉他们要探测的内容,其他任何问题都无法解决。
回到我的支持上来……是出于某种(可能是历史原因)的原因,此监视的大部分内容包括使用一组记录的“ grep”命令通过一些剪切和粘贴手动检查日志文件中的错误。 如果您将花费的时间加在重复的剪切和粘贴工作上,那么我可以确认,它每周大约消耗½人日。
这让我开始思考……我真的不喜欢做这种任务。 我不太擅长,它是手动的,容易出错,重复并且很无聊。 每周要花费½个工作日来完成这项任务,显然会节省成本,只要不花时间在使他的解决方案完美无缺上。 那么,有哪些选择呢?
如果您从专业的角度来看,那么Splunk就是可以监视来自多种来源(例如syslog守护程序)的消息的工具。
这意味着向Splunk发送错误的一种简单方法是简单地设置Log4j syslog附加程序,但这超出了本博客的范围……
在快速而肮脏的范围内,您可以非常Swift地编写一个shell脚本来执行一些“ grep”命令,将结果写入文件并将其邮寄到您的Unix邮箱。
然后我想到了中间立场。 编写一个包含尽可能多的通用可重用类的Spring应用程序有多困难,它会定期运行以检查大量错误日志并通过电子邮件将结果发送给您。 对于这种事情,电子邮件是件好事,因为您通常出于习惯阅读它们。
入门
在任何这样的项目中,都有一些无形的第一步可以推动整个过程。 它们构成了对您需要编写哪些类才能发布此“东西”的问题的答案? 有很多方法可以确定需要编写哪些类,例如,使用UML,快速原型设计或测试驱动设计之类的正式设计技术,凭空挑选它们(胆怯)。 在每种情况下,您真正要做的就是提出一些要求,从中弹出某些类的名称。 例如,在这种情况下,我需要:
- 搜索给定目录及其子目录(可能)以查找特定类型的文件。
- 如果找到文件,请检查其日期:是否需要搜索文件以查找错误?
- 如果文件足够年轻以至于无法检查,则对其进行验证,以查找异常。
- 如果它包含例外,是我们正在寻找的例外还是被排除在外?
- 如果它包含我们所需要的例外类型,则将详细信息添加到报告中。
- 检查完所有文件后,格式化报告以准备发布。
- 使用电子邮件或其他技术发布报告。
- 整个过程每天都会在给定的时间运行
这抛出了几个类的名称。 我需要一个FileLocator
, FileValidator
, RegexValidator
, FileAgeValidator
和一个Report
。
鉴于以上列表中多次出现“ Validator”一词,这表明我可以使用一个接口(大概称为Validator
并创建多个实现来执行上述验证任务。 然后可以将这些实现组合在一起以创建一个一致的应用程序。
请注意,这只是想法的初步列表。 如果看一下代码,将找不到名为Report
的类,将其重命名为Results
并进行重构以创建Formatter
接口, TextFormatter
和HtmlFormatter
类以及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 。
翻译自: https://www.javacodegeeks.com/2014/03/tracking-application-exceptions-with-spring.html