log4j发送邮件乱码

时间:2023-03-09 15:43:25
log4j发送邮件乱码

Log4J发日志邮件给多个接收者及标题、正文乱码问题

以前开发的系统没有单独的日志管理,所有的日志统一输出到tomcat后台一个文件里,不几天就是好几G,现在要整体增加一个Log4J管理日志的功能,其实这方面的资料网上多的是。发邮件的配置说明也有,但是具体怎么发,乱码问题怎么解决那就比较少了。

利用javamail发送邮件,你需要导入包mail.jar和activation.jar这两个包 ,否则是没法发邮件的 ,下边配置文件里绿色行显示的就是发给两个接收者ac和ae。

这里会出现中文乱码问题,主要有两方面的乱码,一是标题乱码;二是正文乱码。下边具体说明这两种乱码的解决方案。 
一、 标题乱码 
Log4J日志邮件的标题在配置文件log4j.properties里设定,如下 
log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender 
log4j.appender.MAIL.Threshold=FATAL 
log4j.appender.MAIL.BufferSize=10 
log4j.appender.MAIL.From=ab@163.com
log4j.appender.MAIL.SMTPHost=smtp@163.com
log4j.appender.MAIL.Subject= Log4J提醒您:系统发生了严重错误 
log4j.appender.MAIL.To=ac @163.com,ae@163.com
log4j.appender.MAIL.layout=com.sun.DefineLayOut 
log4j.appender.MAIL.layout.LocationInfo=true

灰色的行就是标题,log4J配置文件默认的读取方式是ISO-88591,遇到中文会出现乱码,我们可以把这个配置文件log4j.properties用jdk的工具native2asii转换一下编码方式。 
命令:native2asii log4j.properties log4jxx.properties 
把这个log4jxx.properties改名为log4j.properties取代原来的log4j.properties就ok了。 
灰色行重新编码后是: 
log4j.appender.MAIL.Subject=Log4J/u63d0/u9192/u60a8/uff1a/u7cfb/u7edf/u53d1/u751f/u4e86/u4e25/u91cd/u9519/u8bef

二、 正文乱码 
        正文乱码,解决也比较简单。阅读Log4J的源码类SMTPAppender,我们可以发现sendBuffer()方法中有这样一句: 
part.setContent(sbuf.toString(), layout.getContentType()); 
我们继续追踪发现layout就是配置文件里的layout属性对应的布局模式。但是这些布局模式都是继承自Layout,而contentType是只 可通过getContentType方法取得,不能修改。所有的布局模式getContentType方法返回的都是”text/plain”; 
为处理中文乱码,我们可以写一个布局模式。如果你要使用HTMLLayout,我们就写一个HTMLLayout的子类,覆盖HTMLLayout的 getContentType方法即可。假如我要用org.apache.log4j.HTMLLayout。我们就可以写一个DefineLayOut 类,代码如下: 
package com.sun;

import org.apache.log4j.HTMLLayout; 
public class DefineLayOut extends HTMLLayout{ 
public String getContentType() { 
return "text/html;charset=GBK"; 


对应的配置文件设置如黄色行所示。

Commons-logging + Log4j 使用指南(转)

log4j 发邮件(解决中文乱码)

Log4j的html输出格式:HTMLLayout 类重写,根据自身需要输出不同列

附自定义html输出格式代码

FormatHTMLLayout类
package com.spike.test;

import java.text.SimpleDateFormat;

import org.apache.log4j.HTMLLayout;
import org.apache.log4j.Layout;
import org.apache.log4j.Level;
import org.apache.log4j.helpers.Transform;
import org.apache.log4j.spi.LocationInfo;
import org.apache.log4j.spi.LoggingEvent; public class FormatHTMLLayout extends HTMLLayout {
public FormatHTMLLayout() {
} public String getContentType() {
return "text/html;charset=GBK";
} protected final int BUF_SIZE = 256; protected final int MAX_CAPACITY = 1024; static String TRACE_PREFIX = "<br>    "; private StringBuffer sbuf = new StringBuffer(BUF_SIZE); String title="AAA"; /**
* A string constant used in naming the option for setting the the HTML
* document title. Current value of this string constant is <b>Title</b>.
*/
public static final String TITLE_OPTION = "Title"; // Print no location info by default
boolean locationInfo = true; public String format(LoggingEvent event) {
if (sbuf.capacity() > MAX_CAPACITY) {
sbuf = new StringBuffer(BUF_SIZE);
} else {
sbuf.setLength(0);
}
sbuf.append(Layout.LINE_SEP + "<tr>" + Layout.LINE_SEP); sbuf.append("<td>");
sbuf.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new java.util.Date()));
sbuf.append("</td>" + Layout.LINE_SEP); sbuf.append("<td title=\"BBB\">");
if (event.getLevel().equals(Level.FATAL)) {
sbuf.append("<font color=\"#339933\">");
sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
sbuf.append("</font>");
} else if (event.getLevel().isGreaterOrEqual(Level.WARN)) {
sbuf.append("<font color=\"#993300\"><strong>");
sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
sbuf.append("</strong></font>");
} else {
sbuf.append("<font color=\"green\">");
sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
sbuf.append("</font>");
}
sbuf.append("</td>" + Layout.LINE_SEP); if (locationInfo) {
LocationInfo locInfo = event.getLocationInformation();
sbuf.append("<td title=\"CCC\">");
sbuf.append(locInfo.getClassName());
sbuf.append('.');
sbuf.append(locInfo.getMethodName());
sbuf.append('(');
sbuf.append(Transform.escapeTags(locInfo.getFileName()));
sbuf.append(':');
sbuf.append(locInfo.getLineNumber());
sbuf.append(')');
sbuf.append("</td>" + Layout.LINE_SEP);
} sbuf.append("<td title=\"DDD\">");
sbuf.append(Transform.escapeTags(event.getRenderedMessage()));
sbuf.append("</td>" + Layout.LINE_SEP);
sbuf.append("</tr>" + Layout.LINE_SEP); if (event.getNDC() != null) {
sbuf.append("<tr><td bgcolor=\"#EEEEEE\" style=\"font-size : xx-small;\" colspan=\"6\" title=\"Nested Diagnostic Context\">");
sbuf.append("NDC: " + Transform.escapeTags(event.getNDC()));
sbuf.append("</td></tr>" + Layout.LINE_SEP);
} String[] s = event.getThrowableStrRep();
if (s != null) {
sbuf.append("<tr><td bgcolor=\"#993300\" style=\"color:White; font-size : xx-small;\" colspan=\"4\">");
appendThrowableAsHTML(s, sbuf);
sbuf.append("</td></tr>" + Layout.LINE_SEP);
}
return sbuf.toString();
} private void appendThrowableAsHTML(String[] s, StringBuffer sbuf) {
if (s != null) {
int len = s.length;
if (len == 0)
return;
sbuf.append(Transform.escapeTags(s[0]));
sbuf.append(Layout.LINE_SEP);
for (int i = 1; i < len; i++) {
sbuf.append(TRACE_PREFIX);
sbuf.append(Transform.escapeTags(s[i]));
sbuf.append(Layout.LINE_SEP);
}
}
} /**
* Returns appropriate HTML headers.
*/
public String getHeader() {
StringBuffer sbuf = new StringBuffer();
sbuf.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">" + Layout.LINE_SEP);
sbuf.append("<html>" + Layout.LINE_SEP);
sbuf.append("<head>" + Layout.LINE_SEP); sbuf.append("<title>" + title + "</title>" + Layout.LINE_SEP);
sbuf.append("<style type=\"text/css\">" + Layout.LINE_SEP);
sbuf.append("<!--" + Layout.LINE_SEP);
sbuf.append("body, table {font-family: '',arial,sans-serif; font-size: 12px;}" + Layout.LINE_SEP);
sbuf.append("th {background: #336699; color: #FFFFFF; text-align: left;}" + Layout.LINE_SEP);
sbuf.append("-->" + Layout.LINE_SEP);
sbuf.append("</style>" + Layout.LINE_SEP);
sbuf.append("</head>" + Layout.LINE_SEP);
sbuf.append("<body bgcolor=\"#FFFFFF\" topmargin=\"6\" leftmargin=\"6\">" + Layout.LINE_SEP); sbuf.append("<table cellspacing=\"0\" cellpadding=\"4\" border=\"1\" bordercolor=\"#224466\" width=\"100%\">" + Layout.LINE_SEP);
sbuf.append("<tr>" + Layout.LINE_SEP); sbuf.append("<th>执行时间</th>" + Layout.LINE_SEP);
sbuf.append("<th>级别</th>" + Layout.LINE_SEP); if (locationInfo) {
sbuf.append("<th>所在行</th>" + Layout.LINE_SEP);
} sbuf.append("<th>消息</th>" + Layout.LINE_SEP);
sbuf.append("</tr>" + Layout.LINE_SEP);
sbuf.append("<br></br>" + Layout.LINE_SEP);
return sbuf.toString();
}
}
MailEvaluator类:
package com.spike.test;

import org.apache.log4j.Layout;
import org.apache.log4j.spi.LoggingEvent; public class MailEvaluator extends Layout {
StringBuffer sbuf;
@Override
public String getContentType()
{
return "text/html;charset=GBK";
}
public MailEvaluator() {
sbuf = new StringBuffer(128);
} @Override
public void activateOptions() {
// TODO Auto-generated method stub } @Override
public String format(LoggingEvent event) {
// TODO Auto-generated method stub
sbuf.setLength(0);
sbuf.append("错误等级:"+event.getLevel().toString()+"===");
sbuf.append("错误原因:"+event.getMessage().toString()+"===");
sbuf.append("错误所在类"+event.getLocationInformation().getClassName()+"===");
sbuf.append("错误方法所在:"+event.getLocationInformation().getMethodName()+"===");
sbuf.append("错误行:"+event.getLocationInformation().getLineNumber());
return sbuf.toString();
} @Override
public boolean ignoresThrowable() {
// TODO Auto-generated method stub
return false;
} }

DefineLayOut类

package com.spike.test;

import org.apache.log4j.HTMLLayout;

public class DefineLayOut extends HTMLLayout {
public String getContentType() {
return "text/html;charset=GBK";
}
}

配置文件:log4j.properties
log4j.rootLogger=DEBUG,MAIL,A1
log4j.addivity.org.apache=true # 每天新建日志 #(警告的意思是DailyRollingFileAppender这个类不带属性maxBackupIndex,maxFileSize的,它是#按日期来保存日志的,所以不需要设置该2个属性,如果想要设置日志文件的大小,可以使用#RollingFileAppender这个类,平时开发中日志配置文件中需要注意设置。)
log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A1.File=./logs/cebLog.txt
log4j.appender.A1.Encoding=GBK
log4j.appender.A1.Threshold=DEBUG
log4j.appender.A1.DatePattern='.'yyyy-MM-dd
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
#log4j.appender.A1.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{}:%L : %m%n
#log4j.appender.A1.layout.ConversionPattern=/n/n[%-5p] %d{yyyy-MM-dd HH\:mm\:ss,SSS} method\:%l%n%m%n
log4j.appender.A1.layout.ConversionPattern=%d %-5p %c.%M:%L - %m%n # 发送日志给邮件
log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender
log4j.appender.MAIL.Threshold=ERROR
log4j.appender.MAIL.BufferSize=
# 发件人地址
log4j.appender.MAIL.From=xxxx@.com
# 发送邮件的服务器
log4j.appender.MAIL.SMTPHost=smtp..com
# 邮件的标题
#log4j.appender.MAIL.Subject=Log4J ErrorMessage
#log4j.appender.MAIL.Subject= Log4J提醒您:系统发生了严重错误
log4j.appender.MAIL.Subject=Log4J error
# 用户名
log4j.appender.MAIL.SMTPUsername=xxxx
# 密码
log4j.appender.MAIL.SMTPPassword=xxxx
# 日志邮件的接收者
##发送到什么邮箱,如果要发送给多个邮箱,则用逗号分隔;
log4j.appender.MAIL.To=xxxx@qq.com
##如果需要抄送Cc给某人,则加入下列行:
#log4j.appender.MAIL.Cc=xxxx@qq.com
#是否打印调试信息,如果选true,则会输出和SMTP之间的握手等详细信息
log4j.appender.MAIL.SMTPDebug=true
#log4j.appender.MAIL.SMTPDebug=false #log4j.appender.MAIL.layout=org.apache.log4j.HTMLLayout #log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout
#log4j.appender.MAIL.layout.ConversionPattern=%d %-5p [%c] %m%n #日志显示格式
#log4j.appender.MAIL.layout=com.spike.test.MailEvaluator
#log4j.appender.MAIL.layout.ConversionPattern==%d{yyyy-MM-dd HH:mm:ss} - %c -%-4r [%t] %-5p %c %x - %m %l%n #log4j.appender.MAIL.layout=com.spike.test.DefineLayOut #HTMLLayout 类重写,根据自身需要输出不同列
#参考http://blog.****.net/drift_away/article/details/7410038,不过此文有问题
log4j.appender.MAIL.layout=com.spike.test.FormatHTMLLayout
#log4j.appender.MAIL.layout=org.apache.log4j.HTMLLayout
#log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout
#log4j.appender.MAIL.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c] [%p] - %m%n

配置文件:log4j.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'> <appender name="myConsole" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[%d{dd HH:mm:ss,SSS\} %-5p] [%t] %c{2\} - %m%n" />
</layout>
<!--过滤器设置输出的级别 -->
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="levelMin" value="debug" />
<param name="levelMax" value="error" />
<param name="AcceptOnMatch" value="true" />
</filter>
</appender> <appender name="myFile" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="./logs/cebLog.txt" /><!-- 设置日志输出文件名 -->
<!-- 设置是否在重新启动服务时,在原有日志的基础添加新日志 -->
<param name="Append" value="true" />
<param name="Encoding" value="GBK" />
<param name="DatePattern" value="'.'yyyy-MM-dd'.txt'" />
<!-- <param name="MaxBackupIndex" value="10" /> -->
<layout class="org.apache.log4j.PatternLayout">
<!-- <param name="ConversionPattern" value="%p (%c:%L)- %m%n" /> -->
<param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss SSS\} %-5p] [%t] %c{3\} - %m%n" />
</layout>
</appender> <appender name="activexAppender" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="D:/Logs/Logger.log" />
<param name="DatePattern" value="'.'yyyy-MM-dd'.log'" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[%d{MMdd HH:mm:ss SSS\} %-5p] [%t] %c{3\} - %m%n" />
</layout>
</appender> <appender name="DATABASE" class="org.apache.log4j.jdbc.JDBCAppender">
<param name="URL" value="jdbc:oracle:thin:@host:port:sid" />
<param name="driver" value="oracle.jdbc.driver.OracleDriver" />
<param name="user" value="username" />
<param name="password" value="password" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="INSERT INTO LOG4J_TEST(stamp,thread,infolevel,class,messages) VALUES ('%d{yyyy-MM-dd HH:mm:ss}', '%t', '%p', '%l', '%m')" />
</layout>
</appender> <!-- 发邮件(只有ERROR时才会发送!) -->
<appender name="MAIL" class="org.apache.log4j.net.SMTPAppender">
<param name="threshold" value="error" />
<!-- 日志的错误级别 <param name="threshold" value="fatal"/> -->
<!-- 缓存文件大小,日志达到512K时发送Email -->
<param name="BufferSize" value="512" /><!-- 单位K -->
<param name="From" value="****@126.com" />
<param name="SMTPHost" value="smtp.126.com" />
<param name="Subject" value="Log4J Error 错误" />
<!-- 多个收件人用逗号,隔开 -->
<!-- <param name="To" value="******@qq.com,******@qq.com" /> -->
<param name="To" value="*****@qq.com" />
<!-- 抄送收件人用Cc -->
<param name="Cc" value="****@qq.com" />
<param name="SMTPUsername" value="*****" />
<param name="SMTPPassword" value="****" />
<!-- 是否打印SMTP日志记录 -->
<param name="SMTPDebug" value="true" />
<!-- <layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-d{yyyy-MM-dd HH:mm:ss.SSS} [%p]-[%c] %m%n" />
</layout> -->
<!--解决中文乱码问题-->
<layout class="com.spike.test.FormatHTMLLayout">
</layout>
<!-- <layout class="org.apache.log4j.HTMLLayout">
</layout> -->
</appender> <!-- <appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
<param name="BufferSize" value="256" />
<appender-ref ref="DATABASE" />
</appender> 通过<logger></logger>的定义可以将各个包中的类日志输出到不同的日志文件中
<logger name="com.litt2.log4j" additivity="false">
<level value="WARN" />
<appender-ref ref="CONSOLE" />
</logger> 通过<category></category>的定义可以将各个包中的类日志输出到不同的日志文件中
<category name="com.litt3">
<level value="DEBUG" />
<appender-ref ref="CONSOLE" />
<appender-ref ref="MAIL" />
</category> --> <!-- 指定logger的设置,additivity指示是否遵循缺省的继承机制 -->
<!-- <logger name="com.runway.bssp.activeXdemo" additivity="false"> <priority
value ="info"/> <appender-ref ref="activexAppender" /> </logger> --> <!-- 根logger的设置 -->
<root>
<priority value="debug" />
<appender-ref ref="myConsole" />
<appender-ref ref="myFile" />
<appender-ref ref="activexAppender" />
<appender-ref ref="DATABASE" />
<appender-ref ref="MAIL" />
</root>
</log4j:configuration>

log4j.properties和log4j.xml都存在会优先读取log4j.xml。