Log4j-日志邮件异常栈显示原理

本文详细解析了Log4j如何将日志中的异常信息转化为邮件并发送的过程,从Error方法到forcedLog,再到LoggingEvent的创建,特别关注了异常信息的封装和在SMTPAppender及HTMLLayout中的处理,最终通过getThrowableStrRep()方法将异常栈信息转化为String数组,实现邮件中的详细显示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java代码

public class Log4jSendMail {
	public static void main(String args[]) throws InterruptedException {
		// 读取Log4j.properties配置文件
		PropertyConfigurator.configure(Log4jSendMail.class.getResource("/log4j.properties"));
		Logger logger = Logger.getLogger(Log4jSendMail.class);
		try {
			int a = 1 / 0;
		} catch (Exception e) {
			logger.error("error:", e);
		}
	}
}

邮件打印信息:


红色区域打印的就是异常栈信息。

Error方法

public
  void error(Object message, Throwable t) {
    if(repository.isDisabled(Level.ERROR_INT))
      return;
    if(Level.ERROR.isGreaterOrEqual(this.getEffectiveLevel()))
      forcedLog(FQCN, Level.ERROR, message, t);

}

继续向下跟踪,forcedLog方法

protected void forcedLog(String fqcn, Priority level, Object message, Throwable t) {
		callAppenders(new LoggingEvent(fqcn, this, level, message, t));
}

在创建LoggingEvent对象时,将异常信息封装,继续跟踪new LoggingEvent

public LoggingEvent(String fqnOfCategoryClass, Category logger,
		      Priority level, Object message, Throwable throwable){
    this.fqnOfCategoryClass = fqnOfCategoryClass;
    this.logger = logger;
    this.categoryName = logger.getName();
    this.level = level;
    this.message = message;
    if(throwable != null) {
      this.throwableInfo = new ThrowableInformation(throwable);
    }
    timeStamp = System.currentTimeMillis();
}

异常信息存入throwableInfo属性中。

发送邮件时,调用properties中配置的类

SMTPAppender:处理邮件发送,可以自定义。

HTMLLayout:处理邮件样式的,可以自定义。

SMTPAppender类中的sendBuffer方法

protected void sendBuffer() {

    // Note: this code already owns the monitor for this
    // appender. This frees us from needing to synchronize on 'cb'.
    try {
      MimeBodyPart part = new MimeBodyPart();

      StringBuffer sbuf = new StringBuffer();
      String t = layout.getHeader();
      if(t != null)
	sbuf.append(t);
      int len =  cb.length();
      for(int i = 0; i < len; i++) {
	//sbuf.append(MimeUtility.encodeText(layout.format(cb.get())));
	LoggingEvent event = cb.get();
	sbuf.append(layout.format(event));
	if(layout.ignoresThrowable()) {
	  String[] s = event.getThrowableStrRep();
	  if (s != null) {
	    for(int j = 0; j < s.length; j++) {
	      sbuf.append(s[j]);
	      sbuf.append(Layout.LINE_SEP);
	    }
	  }
	}
      }
      t = layout.getFooter();
      if(t != null)
	sbuf.append(t);
      part.setContent(sbuf.toString(), layout.getContentType());

      Multipart mp = new MimeMultipart();
      mp.addBodyPart(part);
      msg.setContent(mp);

      msg.setSentDate(new Date());
      Transport.send(msg);
    } catch(Exception e) {
      LogLog.error("Error occured while sending e-mail notification.", e);
    }
}

layout.format(event),调用HTMLLayout中的format方法,format方法中如下段落拼装异常信息内容。

String[] s = event.getThrowableStrRep();
    if(s != null) {
      sbuf.append("<tr><td bgcolor=\"#993300\" style=\"color:White; font-size : xx-small;\" colspan=\"6\">");
      appendThrowableAsHTML(s, sbuf);
      sbuf.append("</td></tr>" + Layout.LINE_SEP);
}

event.getThrowableStrRep()方法,获得上面封装的异常栈信息

public String[] getThrowableStrRep() {

    if(throwableInfo ==  null)
      return null;
    else
      return throwableInfo.getThrowableStrRep();
}

调用getThrowableStrRep()方法

public  String[] getThrowableStrRep() {
    if(rep != null) {
      return (String[]) rep.clone();
    } else {
      StringWriter sw = new StringWriter();
      PrintWriter pw = new PrintWriter(sw);
      throwable.printStackTrace(pw);
      pw.flush();
      LineNumberReader reader = new LineNumberReader(
              new StringReader(sw.toString()));
      ArrayList lines = new ArrayList();
      try {
        String line = reader.readLine();
        while(line != null) {
          lines.add(line);
          line = reader.readLine();
        }
      } catch(IOException ex) {
          lines.add(ex.toString());
      }
      rep = new String[lines.size()];
      lines.toArray(rep);
    }
    return rep;
}

OK,这个方法就是将throwableInfo属性封装的异常类的异常栈信息转换为Sting数组。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值