log4j发送邮件乱码

时间:2022-03-24 21:47:53

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{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。