以前开发的系统没有单独的日志管理,所有的日志统一输出到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的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{1}:%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=10 # 发件人地址 log4j.appender.MAIL.From=xxxx@126.com # 发送邮件的服务器 log4j.appender.MAIL.SMTPHost=smtp.126.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.csdn.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。