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

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

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

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

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

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

屏幕+拍摄+ 2014-03-08 + at + 16.59.55

在上面的类图中,将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对象如何工作? 我没有提到它,输出是如何产生的? 下次再说。


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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值