在上一个博客中 ,我开始谈论需要弄清楚您的应用程序在生产环境中是否行为异常。 我说过,监视应用程序的一种方法是检查其日志文件是否存在异常,如果发现异常,则采取适当的措施。 显然,日志文件会占用数百兆的磁盘空间,而手动监视它们是不切实际的,而且很无聊。

我还说过,有几种方法可以自动监视日志文件,并提出了一个基于Spring的实用程序,该实用程序每天都会梳理日志文件,并在发现任何异常时向您发送电子邮件。

我只介绍了第一类: FileLocator ,它将在目录及其子目录中搜索日志文件。 找到一个后,将其传递给FileValidator

FileValidator必须对文件执行多项检查。 首先,它必须确定文件是否足够年轻以检查异常。 想法是,由于应用程序定期运行,因此没有必要检查目录中找到的所有文件是否存在错误,我们只希望自应用程序上次运行以来已创建或更新的文件。

这种设计的思想是将同一接口的几种实现组合在一起,创建一个负责验证文件的聚合对象。 鹰眼的读者会注意到,这是Delegate Pattern的实现。

在上面的类图中,将RegexValidatorFileAgeValidator实例注入到FileValidator ,并将其验证任务委托给这些类。

依次进行这些操作,并首先处理Validator接口…

public interface Validator { /** The validation method */ public <T> boolean validate(T obj); }

上面的代码演示了Validator接口的简单性。 它具有单个方法validate(T obj) ,这是一个泛型方法调用,可以提高此接口的灵活性和可重用性。 当类实现此接口时,它们可以更改输入参数类型以适合自己的目的……如下面的第一个实现所示:

public class RegexValidator implements Validator { private static final Logger logger = LoggerFactory.getLogger(RegexValidator.class); private final Pattern pattern; public RegexValidator(String regex) { pattern = Pattern.compile(regex); logger.info("loaded regex: {}", regex); } @Override public <T> boolean validate(T string) { boolean retVal = false; Matcher matcher = pattern.matcher((String) string); retVal = matcher.matches(); if (retVal && logger.isDebugEnabled()) { logger.debug("Found error line: {}", string); } return retVal; }
}

RegexValidator类具有一个带正则表达式字符串的单个参数构造函数。 然后将其转换为Pattern实例变量,并由validate(T string)方法使用它来测试String输入参数是否与原始构造函数arg正则表达式匹配。 如果是这样,那么validate(T string)将返回true。

@Service
public class FileAgeValidator implements Validator { @Value("${max.days}") private int maxDays; /** * Validate the age of the file. * * @see com.captaindebug.errortrack.Validator#validate(java.lang.Object) */ @Override public <T> boolean validate(T obj) { File file = (File) obj; Calendar fileDate = getFileDate(file); Calendar ageLimit = getFileAgeLimit(); boolean retVal = false; if (fileDate.after(ageLimit)) { retVal = true; } return retVal; } private Calendar getFileAgeLimit() { Calendar cal = Calendar.getInstance(); cal.add(Calendar.DAY_OF_MONTH, -1 * maxDays); return cal; } private Calendar getFileDate(File file) { long fileDate = file.lastModified(); Calendar when = Calendar.getInstance(); when.setTimeInMillis(fileDate); return when; } }

第二个Validator(T obj)实现是FileAgeValidator显示的FileAgeValidator ,首先要注意的是,整个过程是由max.days属性驱动的。 这被注入到FileAgeValidator@Value注释的maxDays实例变量中。 此变量确定文件的最长使用期限(天)。 该文件早于该值,然后validate(T obj)将返回false。

在此实现中, validate(T obj) 'obj'参数被强制转换为File对象,然后将其用于将文件的日期转换为Calendar对象。 下一行代码将maxDays变量转换为第二个Calendar对象: ageLimit 。 然后将ageLimitfileDate对象进行比较。 如果fileDateageLimit之后,则validate(T obj)返回true。

validator程序包中的最后一个类是FileValidator ,如上所示,它将很多职责委托给其他三个聚合的验证程序:一个FileAgeValidator和两个RegexValidator

@Service
public class FileValidator implements Validator { private static final Logger logger = LoggerFactory.getLogger(FileValidator.class); @Value("${following.lines}") private Integer extraLineCount; @Autowired @Qualifier("scan-for") private RegexValidator scanForValidator; @Autowired(required = false) @Qualifier("exclude") private RegexValidator excludeValidator; @Autowired private FileAgeValidator fileAgeValidator; @Autowired private Results results; @Override public <T> boolean validate(T obj) { boolean retVal = false; File file = (File) obj; if (fileAgeValidator.validate(file)) { results.addFile(file.getPath()); checkFile(file); retVal = true; } return retVal; } private void checkFile(File file) { try { BufferedReader in = createBufferedReader(file); readLines(in, file); in.close(); } catch (Exception e) { logger.error("Error whilst processing file: " + file.getPath() + " Message: " + e.getMessage(), e); } } @VisibleForTesting BufferedReader createBufferedReader(File file) throws FileNotFoundException { BufferedReader in = new BufferedReader(new FileReader(file)); return in; } private void readLines(BufferedReader in, File file) throws IOException { int lineNumber = 0; String line; do { line = in.readLine(); if (isNotNull(line)) { processLine(line, file.getPath(), ++lineNumber, in); } } while (isNotNull(line)); } private boolean isNotNull(Object obj) { return obj != null; } private int processLine(String line, String filePath, int lineNumber, BufferedReader in) throws IOException { if (canValidateLine(line) && scanForValidator.validate(line)) { List<String> lines = new ArrayList<String>(); lines.add(line); addExtraDetailLines(in, lines); results.addResult(filePath, lineNumber, lines); lineNumber += extraLineCount; } return lineNumber; } private boolean canValidateLine(String line) { boolean retVal = true; if (isNotNull(excludeValidator)) { retVal = !excludeValidator.validate(line); } return retVal; } private void addExtraDetailLines(BufferedReader in, List<String> lines) throws IOException { for (int i = 0; i < extraLineCount; i++) { String line = in.readLine(); if (isNotNull(line)) { lines.add(line); } else { break; } } } }

FileValidatorvalidate(T obj)File作为参数。 它的首要职责是验证文件的年龄。 如果该验证器返回true,则它将通知Report类它已找到一个新的有效文件。 然后,它检查文件中是否有错误,并将找到的任何内容添加到Report实例。 它通过使用BufferedReader依次检查文件的每一行来做到这一点。 在检查某行是否包含错误之前,它会检查该行是否未从检查中排除-即,它与排除的异常或我们不感兴趣的异常不匹配。如果该行与排除的异常不匹配异常,然后使用RegexValidator的第二个实例检查是否需要查找异常。 如果该行确实包含错误,则会将其添加到List<String>对象。 然后从添加到列表的文件中读取以下几行,以使报告更具可读性。

因此,文件解析将继续,一次检查每一行以查找错误并建立报告,以便以后处理。

该封面的验证文件使用委托模式添加了发现到Report任何异常,但是此Report对象如何工作? 我没有提到它,输出是如何产生的? 下次再说。

  • 该博客的代码可在Github上找到: https : //github.com/roghughe/captaindebug/tree/master/error-track 。
参考: 使用Spring跟踪异常–第2部分–在Captain Debug的Blog博客上,由我们的JCG合作伙伴 Roger Hughes 委托模式 。

翻译自: https://www.javacodegeeks.com/2014/03/tracking-exceptions-with-spring-part-2-delegate-pattern.html

使用Spring跟踪异常–第2部分–委托模式相关推荐

  1. spring 异常捕获异常_使用Spring跟踪异常–第2部分–委托模式

    spring 异常捕获异常 在上一个博客中 ,我开始谈论需要弄清您的应用程序在生产环境中是否行为异常. 我说过,监视应用程序的一种方法是检查其日志文件是否存在异常,如果发现异常,则采取适当的措施. 显 ...

  2. spring发邮件_跟踪异常–第4部分– Spring的邮件发件人

    spring发邮件 如果您阅读过本系列以前的任何博客,您可能会记得我正在开发一个小型但几乎具有工业实力的应用程序,该应用程序在日志文件中搜索异常. 您可能还记得,我现在有一个可以包含大量结果的类,这些 ...

  3. spring 异常捕获异常_跟踪异常–第5部分–使用Spring进行计划

    spring 异常捕获异常 看来我终于快要结束本系列有关使用Spring进行错误跟踪的博客了,对于那些还没有阅读该系列博客的人,我正在编写一个简单但几乎具有工业实力的Spring应用程序,扫描日志文件 ...

  4. 跟踪异常–第4部分– Spring的邮件发件人

    如果您阅读过本系列以前的任何博客,您可能会记得我正在开发一个小型但几乎具有工业实力的应用程序,该应用程序在日志文件中搜索异常. 您可能还记得,我现在有一个可以包含一堆结果的类,需要将其发送给感兴趣的任 ...

  5. 跟踪异常–第5部分–使用Spring进行计划

    看来我终于快要结束本系列有关使用Spring进行错误跟踪的博客了,对于那些还没有阅读该系列博客的人,我正在编写一个简单但几乎具有工业实力的Spring应用程序,扫描日志文件中的异常,然后生成报告. 在 ...

  6. 使用Spring跟踪应用程序异常

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

  7. spring 4 异常HttpMediaTypeNotAcceptableException解决方案

    异常问题 jsp页面ajax请求错误:406Not Acceptable 后台代码: [2017:05:1709:51:22]:Resolving exception from handler [pu ...

  8. spring全局异常抓取validation校验信息

    spring全局异常抓取validation校验信息 参考文章: (1)spring全局异常抓取validation校验信息 (2)https://www.cnblogs.com/jianxiaopo ...

  9. spring mvc异常统一处理(ControllerAdvice注解)

    spring mvc异常统一处理(ControllerAdvice注解) 参考文章: (1)spring mvc异常统一处理(ControllerAdvice注解) (2)https://www.cn ...

最新文章

  1. R语言dplyr包mutate_all函数一次性处理所有的数据列的内容(使用统一的函数)实战
  2. ArrayList、LinkedList和Vector
  3. size()函数的使用
  4. 外设驱动库开发笔记36:NTC负温度系数热电阻测温驱动
  5. 服务器主板稳定,服务器主板
  6. mysqldump原理及实验
  7. AndroidM 内核空间到用户空间接口类型
  8. 资金流学习 - 选股逻辑
  9. python面向对象三大特性_Python面向对象之多态原理与用法案例分析
  10. 计算机验收标准和验收方法,【超详细】综合布线系统验收标准及内容
  11. 模仿笔迹最好的软件_模仿签名代写签字行业进入战国时代,乱战模式开启!
  12. type python django models_django新版本(2.x)踩坑记录
  13. cmos和ttl_TTL与CMOS详细介绍
  14. 基于jqUI的日期选择(‘yy-mm-dd’)
  15. python 广告联盟_利用京东联盟API获取自定义推广链接
  16. 知识图谱学习笔记(三)——知识表示方法
  17. python读取excel一行一行的读取_python读取excel数据
  18. css3的@media
  19. zbb20170630 web项目发布至tomcat的ROOT下方法(开发环境和部署环境)
  20. C++习题--求余数

热门文章

  1. android studio 配置国内镜像
  2. java填充线缺口,在geom_freqpoly线下填充区域的最简单方法是什么?
  3. taro 缺点_Taro小程序富文本解析4种方法
  4. 实现了某一个接口的匿名类的例子_java中的内部类内部接口详解,一文搞定
  5. session实现购物车
  6. 转:线性代数知识汇总
  7. 通过smack client + openfire server 实现 peer to peer communication
  8. 夜神模拟器模拟安卓测试_使用模拟进行测试
  9. apache derby_Apache Derby数据库JVM安全策略
  10. spring boot简介_Spring Boot简介