邮件报警的简单实现

其实,log4j就可以实现邮件报警功能,只需要简单的配置即可。其实,不光可以发邮件,还可以通过sockets将日志文件发送到网络中的指定地址。具体查看log4j的各个appender就好啦。error级别的日志发送邮件配置👇

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Error级别的日志发送邮件
log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender
log4j.appender.MAIL.Threshold=ERROR
log4j.appender.MAIL.BufferSize=10
log4j.appender.MAIL.From=189********@163.com
log4j.appender.MAIL.SMTPHost=smtp.163.com
log4j.appender.MAIL.Subject=Error Message from *** Project
# 可以发送多个用户中间用,去分隔
log4j.appender.MAIL.To=destination0@qq.com,destination1@qq.com
# 邮箱帐号
log4j.appender.MAIL.SMTPUsername=189********@163.com
# 邮箱密码
log4j.appender.MAIL.SMTPPassword=authcode
log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout
log4j.appender.MAIL.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss} [%c]-[%p] [%t] (%F\:%L) %X{merchant_id} ->%m %n

(PS:本篇内容无具体实现,只有实现思路)

(PPS: PS 是 postscript 的缩写,笑哭)

Context

我司主力项目托管在阿里云服务器,有些业务需要调用客户服务器的一些接口(以HTTP请求的方式,,理论上效率并不是非常好,传说使用netty会好一些,挖坑待实现)。主力项目主要做统筹工作,类似微信开放平台中的第三方平台,然后客户授权相关权限给我司,然后我司代实现其业务逻辑,,但商品数据存放在用户服务器的数据库中,倘若将所有用户的商品数据同步到阿里云线上,一则是没必要,二则所有客户的商品数据也是不小的体量,三则也可能会有客户不希望将自己的数据代托管,,种种。所以采用的这种方式。

于是,需求出现了,,为了保证阿里云服务器中的项目与客户服务器通讯的可靠性,需保证调用出现异常时,开发人员及时知晓并fix bug。所以异常报警势在必行。

有点意思,,让我来~

开头难

于是,开始网上了解相关解决方案,,得到的大部分都服务器状态监测相关,比如zabbixnagios(虽然不知道这俩货具体是啥。。待我用自己的服务器练练手先)。看上去比较『重』,,因为我目前只需要邮件报警的功能,,主要是我司服务器是 Windows 的。。

好吧,这条路暂时走不通了。

想想其他办法

异常报警,,那肯定是捕捉到异常之后的处理,所以应该在 catch 块儿中实现相关报警代码就行。按照java 使用JavaMail 做异常邮件报警 ,支持163邮箱、outlook邮箱中代码实现即可。后来发现项目框架中有相关的 MailUtil 工具类,倒是省事儿。虽然上面博客中的代码并未复用,但至少让我看到了成功的希望。然而,,实现RuntimeException,然后捕捉到异常后抛出新实现的异常类,,真的有必要么??我在捕捉到异常之后,为什么不直接发送邮件,反而继续向上层抛异常?上层还有未捕获异常的处理??至少我的项目中没有;另外,,如果在每个方法中去try{}catch(e){},需要改动每个相关接口代码,太不优雅了。。

有没有一种一劳永逸的方法,,一处设置,处处生效??我首先想到的是过滤器,,

1
2
3
4
5
6
7
8
try{
doFilter();
}catch(Exception e){
e.printStackTrace();
// 邮件报警
// 短信报警
// bulabula
}

但实现之后,发现异常并没有被抛出到过滤器中,,直接被其他逻辑catch捕捉处理了,,额。那就在 Route(或Controller) 级别的拦截器中处理,,

1
2
3
4
5
try{
invocation.invoke();
}catch(Exception e){
// 报警bulabula
}

完美!!然鹅,,业务中调用客户服务器中的接口需返回值,丫的!!
 
另外,所有与客户服务器交互的方法全被写在了 API.java 中,,其他业务中直接静态调用相应的方法即可。所以,用 Controller 级别的拦截器还不行。。

权衡之下,最终以 action 为单位,自定义 catch 逻辑,返回相应的错误代码调用封装好的发送报警邮件的方法。同理,短信报警及其他报警形式。具体实现其实没什么难的,这里梳理下思路。


参考链接:java 使用JavaMail 做异常邮件报警 ,支持163邮箱、outlook邮箱