您现在的位置是:网站首页 > 代码编程 > JAVA开发JAVA开发

【原】log4j使用之SMTPAppender教程

不忘初心 不忘初心 2019-05-15 围观() 评论() 点赞() JAVA开发

简介:在一些场景中,对于error的感知需要非常快,需要第一时间通知到负责人,此时就需要SMTPAppender来救场了,它可以直接将日志内容当做邮件发出来,这样就算是责任人没在电脑旁边儿,也可以稍微从日志中找一下问题的原因。

在一些场景中,对于error的感知需要非常快,需要第一时间通知到负责人,此时就需要SMTPAppender来救场了,它可以直接将日志内容当做邮件发出来,这样就算是责任人没在电脑旁边儿,也可以稍微从日志中找一下问题的原因。

直接来看配置文件:log4j.properties

# 配置根logger,如果下面没有自定义logger,那么项目中的日志就都是debug级别,输出到console
log4j.rootLogger=DEBUG,console,mail

# 屏蔽框架日志,只有报错的时候才放出来,优先级高于rootLogger
log4j.logger.org.springframework=ERROR
log4j.logger.org.apache.ibatis=ERROR
log4j.logger.org.mybatis.spring=ERROR
log4j.logger.com.mchange=ERROR

# 自定义包路径中的日志等级,直接写一个level即可,appender可选择,如果没写就默认使用rootLogger中配置的console
log4j.logger.com.ssm=DEBUG

# 打印出jdbc的日志
log4j.appender.java.sql.ResultSet=DEBUG
log4j.appender.java.sql.Connection=DEBUG
log4j.appender.java.sql.Statement=DEBUG
log4j.appender.java.sql.PreparedStatement=DEBUG

# 控制台(console)
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.ImmediateFlush=true
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%5p] - %c - %m%n

# 发送日志到指定邮件
log4j.appender.mail=org.apache.log4j.net.SMTPAppender
#这里就需要注意了,强制只有error的才会发送邮件,所以指定了也没啥鸟用
log4j.appender.mail.Threshold=DEBUG
#缓冲区大小,默认512,单位:kb,每次发送邮件时会从缓冲区读日志
log4j.appender.mail.BufferSize=2
#开启debug模式,可以看到很多有用的信息,出错了容易查找
log4j.appender.mail.SMTPDebug=true
#配置邮件服务
log4j.appender.mail.SMTPHost=smtp.sina.com
#邮箱账号
log4j.appender.mail.SMTPUsername=xxx@sina.com
#邮箱密码
log4j.appender.mail.SMTPPassword=xxx
#发送者邮箱
log4j.appender.mail.From=xxx@sina.com
#接收者邮箱
log4j.appender.mail.To=xxx@sina.com
#邮件标题
log4j.appender.mail.Subject=Log4J Message
#选择输出方式
log4j.appender.mail.layout=org.apache.log4j.PatternLayout
#配置日志输出格式
log4j.appender.mail.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%5p] - %c - %m%n

我这里以新浪邮箱来做演示,与邮件发送相关的参数,大家请移步:Java发送新浪邮件图文教程

需要注意的有两点:

1、Threshold参数的配置,这里就很秀了,可能是防止日志级别配置有误,从而导致垃圾邮件干扰,所以log4j默认就只发送error级别及以上的日志邮件,就像我上面配置了debug,其实是没啥鸟用的;

2、BufferSize参数的配置,用来控制缓冲区大小;

3、新浪邮箱直接使用账号密码,其他的邮箱就需要使用SMTP授权字符;

挑重要的地方给大家看一下SMTPAppender的源码:

SMTPAppender的构造方法:

/**
   The default constructor will instantiate the appender with a
   {@link TriggeringEventEvaluator} that will trigger on events with
   level ERROR or higher.*/
public
SMTPAppender() {
  this(new DefaultEvaluator());
}

默认传入了一个DefaultEvaluator,这个是它的内部类:

class DefaultEvaluator implements TriggeringEventEvaluator {
  /**
     Is this <code>event</code> the e-mail triggering event?

     <p>This method returns <code>true</code>, if the event level
     has ERROR level or higher. Otherwise it returns
     <code>false</code>. */
  public
  boolean isTriggeringEvent(LoggingEvent event) {
    return event.getLevel().isGreaterOrEqual(Level.ERROR);
  }
}

实现了TriggeringEventEvaluator,重写了isGreaterOrEqual方法,跟error级别做了一个比对:

/**
   Returns <code>true</code> if this level has a higher or equal
   level than the level passed as argument, <code>false</code>
   otherwise.  
   
   <p>You should think twice before overriding the default
   implementation of <code>isGreaterOrEqual</code> method.
*/
public
boolean isGreaterOrEqual(Priority r) {
  return level >= r.level;
}

比对的值是一个Level对象:

/**
   Defines the minimum set of levels recognized by the system, that is
   <code>OFF</code>, <code>FATAL</code>, <code>ERROR</code>,
   <code>WARN</code>, <code>INFO</code, <code>DEBUG</code> and
   <code>ALL</code>.

   <p>The <code>Level</code> class may be subclassed to define a larger
   level set.

   @author Ceki G&uuml;lc&uuml;

 */
public class Level extends Priority implements Serializable {

   /**
    * TRACE level integer value.
    * @since 1.2.12
    */
  public static final int TRACE_INT = 5000;

  /**
     The <code>OFF</code> has the highest possible rank and is
     intended to turn off logging.  */
  final static public Level OFF = new Level(OFF_INT, "OFF", 0);

  /**
     The <code>FATAL</code> level designates very severe error
     events that will presumably lead the application to abort.
   */
  final static public Level FATAL = new Level(FATAL_INT, "FATAL", 0);

  /**
     The <code>ERROR</code> level designates error events that
     might still allow the application to continue running.  */
  final static public Level ERROR = new Level(ERROR_INT, "ERROR", 3);

  /**
     The <code>WARN</code> level designates potentially harmful situations.
  */
  final static public Level WARN  = new Level(WARN_INT, "WARN",  4);

  /**
     The <code>INFO</code> level designates informational messages
     that highlight the progress of the application at coarse-grained
     level.  */
  final static public Level INFO  = new Level(INFO_INT, "INFO",  6);

  /**
     The <code>DEBUG</code> Level designates fine-grained
     informational events that are most useful to debug an
     application.  */
  final static public Level DEBUG = new Level(DEBUG_INT, "DEBUG", 7);

  /**
    * The <code>TRACE</code> Level designates finer-grained
    * informational events than the <code>DEBUG</code level.
   *  @since 1.2.12
    */
  public static final Level TRACE = new Level(TRACE_INT, "TRACE", 7);


  /**
     The <code>ALL</code> has the lowest possible rank and is intended to
     turn on all logging.  */
  final static public Level ALL = new Level(ALL_INT, "ALL", 7);

}

Level继承了Priority:

/**
   <font color="#AA4444">Refrain from using this class directly, use
   the {@link Level} class instead</font>.

   @author Ceki G&uuml;lc&uuml; */
public class Priority {

  transient int level;
  transient String levelStr;
  transient int syslogEquivalent;

  public final static int OFF_INT = Integer.MAX_VALUE;
  public final static int FATAL_INT = 50000;
  public final static int ERROR_INT = 40000;
  public final static int WARN_INT  = 30000;
  public final static int INFO_INT  = 20000;
  public final static int DEBUG_INT = 10000;
    //public final static int FINE_INT = DEBUG_INT;
  public final static int ALL_INT = Integer.MIN_VALUE;

}

可以看到Priority中定义的这些常量,正好是Level构造方法中传入的参数。

代码看到这里,基本上已经可以明白log4j是怎么实现这个控制的,上面的代码跳来跳去,不过最终比对的值就是Priority的level字段,而level字段在初始化Level对象的时候会被赋值成Priority中的常量,那么将isGreaterOrEqual方法中算式取出来就是:>=40000,而符合这个条件的,只有ERROR和FATAL级别。

好了,来给大家看下效果:

log4j使用之SMTPAppender教程

效果有了,不过大家注意看上图,最下面几封邮件内容中竟然还是有debug级别的日志,莫非是我噼里啪啦讲了这么多废话?

不是的,大家不要惊慌,在上面提到了BufferSize参数,这里就是因为它导致的,我配置的是2kb,所以总共会有2kb的数据在缓冲区中,从最后一个字节往回算,总共2kb大小的日志。

来张图给大家看一下:

log4j使用之SMTPAppender教程

只缓冲了错误日志上面那一行的信息,而这个参数默认是512,那如果使用默认的值,error之前的日志信息将会更多,如下图:

log4j使用之SMTPAppender教程

但是作为报错的场景来说,其实是需要更多日志的,我觉着512反而还不够,所以大家在使用的时候酌情考量!

log4j日志框架

看完文章,有任何疑问,请加入群聊一起交流!!!

很赞哦! ()

文章评论

  • 请先说点什么
    人参与,条评论

请使用电脑浏览器访问本页面,使用手机浏览器访问本页面会导致下载文件异常!!!

雨落无影

关注上方公众号,回复关键字【下载】获取下载码

用完即删,每次下载需重新获取下载码

若出现下载不了的情况,请及时联系站长进行解决

站点信息

  • 网站程序:spring + freemarker
  • 主题模板:《今夕何夕》
  • 文章统计:篇文章
  • 标签管理标签云
  • 微信公众号:扫描二维码,关注我们