`
mengqingyu
  • 浏览: 328279 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

AOP+LOG4J日志框架(自定义注解)

阅读更多
工作中用到日志功能,参考网上一些资料,写了个比较通用的日志框架,现在拿出来分享,内容没有做太多解释,如有不清楚的地方可以给我留言或是通过网上查资料来解决。
设计思路:通过AOP进入方法之前拦截做行为日志记录,方法抛异常拦截做错误日志记录。实现自定义注解,可以存入行为中文注释,也可以配置成完全根据注解来决定是否记录日志的策略,支持控制台、文件、数据库、邮件和异步处理等功能以及针对数据库可以添加行为统计、异常统计和钻取明细等等。
web.xml文件配置如下:
<!-- 日志 -->
<context-param>
	<param-name>log4jConfigLocation</param-name>
	<param-value>classpath:log4j.xml</param-value>
</context-param>
<!-- 监听器 放在spring监听器之前-->
<listener>
	<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>


spring配置文件如下:
<!-- 日志  AOP-->	
<bean id="logBeforeAdvice" class="com.berheley.bi.system.log.logManage.LogBeforeAdvice">
	<property name="annotation" value="true"/>
</bean>
<bean id="logThrowingAdvice" class="com.berheley.bi.system.log.logManage.LogThrowingAdvice">
	<property name="annotation" value="true"/>
</bean>
<!-- 日志  begin-->
<aop:config> 
	<aop:advisor pointcut="execution(* com.berheley.bi.meta..*.*(..))"   advice-ref="logBeforeAdvice"/>  
</aop:config>
<!-- 日志 end -->

import java.lang.reflect.Method;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.MethodBeforeAdvice;

/**
 * 
 * 类功能描述:日志框架
 *
 * @author <a href="mailto:qingyu.meng21@gmail.com">mengqingyu </a>
 * @version $Id: codetemplates.xml,v 1.1 2009/03/06 01:13:01 mengqingyu Exp  $
 * Create:  2013-4-9 下午05:23:41
 */
public class LogBeforeAdvice implements MethodBeforeAdvice {
	
	protected Log log = LogFactory.getLog(this.getClass());
	
	private boolean annotation = true;
	
	public void setAnnotation(boolean annotation) {
		this.annotation = annotation;
	}

	/**
	 * service方法前调用,记录行为或调试
	 */
	public void before(Method method, Object[] args, Object target) throws Throwable {
        LogUtils.beforeLog(target.getClass(), method, args, log, annotation);
	}
}


import java.lang.reflect.Method;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.ThrowsAdvice;

import com.berheley.bi.basic.exp.BusinessException;

/**
 * 
 * 类功能描述:日志框架
 *
 * @author <a href="mailto:qingyu.meng21@gmail.com">mengqingyu </a>
 * @version $Id: codetemplates.xml,v 1.1 2009/03/06 01:13:01 mengqingyu Exp  $
 * Create:  2013-4-9 下午05:23:41
 */
public class LogThrowingAdvice implements ThrowsAdvice {
	
	protected Log log = LogFactory.getLog(this.getClass());
	
	private boolean annotation = true;
	
	public void setAnnotation(boolean annotation) {
		this.annotation = annotation;
	}
	
	/**
	 * 
	 * @function:抛出异常时调用,记录错误内容
	 * @param method
	 * @param args
	 * @param target
	 * @param ex
	 * @throws BusinessException
	 * @author: mengqingyu    2013-4-9 下午05:24:20
	 */
	public void afterThrowing(Method method, Object[] args, Object target,  
			Exception ex) throws BusinessException {
//		DOMConfigurator.configure(LogThrowingAdvice.class.getResource("/log4j.xml"));//临时测试用
		LogUtils.throwingLog(target.getClass(), method, args, ex, log, annotation);
    }
}

log4j配置文件如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> 
<!-- log4j xml配置 控制台、文件、数据库和邮件 支持异步  mengqingyu -->
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
	<!-- 控制台 -->
	<appender name="console" class="org.apache.log4j.ConsoleAppender">
		<param name="target" value="System.out"/>
		<layout class="org.apache.log4j.PatternLayout">
			<param name="conversionPattern" value="[%-5p] %d{yyyy-MM-dd HH:mm:ss} %m %n"/>
		</layout>
	</appender>
	
	<!-- 文件 -->
	<appender name="webframe" class="org.apache.log4j.DailyRollingFileAppender">
		<param name="file" value="${webframe.root}/WEB-INF/logs/webframe.log"/>
		<!-- 8K为一个写单元
		<param name="BufferedIO" value="true" />
        <param name="BufferSize" value="8192" />
         -->
		<param name="append" value="true"/>
		<param name="datePattern" value="'.'yyyy-MM-dd"/>
		<layout class="org.apache.log4j.PatternLayout">
			<param name="conversionPattern" value="[%-5p] %d{yyyy-MM-dd HH:mm:ss} %m %n"/>
		</layout>
	</appender>	
	
	<!-- 数据库 -->
	<appender name="db" class="com.berheley.bi.system.log.log4j.JDBCCustomAppender">
		<param name="bufferSize" value="1" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="conversionPattern"
				value="insert into t_log (LOG_NAME_,USER_NAME_,CLASS_,METHOD_NAME_,CREATE_TIME_,LOG_LEVEL_,METHOD_PARAM_,MSG_BRIEF_,MSG_DETAIL_,CLASS_DISCRIPTION_,METHOD_DISCRIPTION_) values ('%X{LOG_NAME_}','%X{USER_NAME_}','%X{CLASS_}','%X{METHOD_NAME_}','%d{yyyy-MM-dd HH:mm:ss}','%p','%X{METHOD_PARAM_}','%m','%X{MSG_DETAIL_}','%X{CLASS_DISCRIPTION_}','%X{METHOD_DISCRIPTION_}')" />
		</layout>
		<!-- 级别过滤
		<filter class="org.apache.log4j.varia.LevelRangeFilter"> 
			<param name="LevelMax" value="error" /> 
			<param name="LevelMin" value="error" /> 
		</filter> 
		-->
	</appender>
	
	<!-- 邮件 可配置多个appender模块划分-->
	<appender name="mail" class="com.berheley.bi.system.log.log4j.SMTPCustomAppender">
		<param name="threshold" value="fatal"/>
		<param name="bufferSize" value="1"/>
		<param name="from" value="1@gmail.com"/>
		<param name="smtpHost" value="smtp.gmail.com"/>
		<param name="smtpAuth" value="true"/>
		<param name="smtpUsername" value="1@gmail.com"/>
		<param name="smtpPassword" value="1"/>
		<param name="subject" value=" Log4J Message"/>
		<param name="packages" value="com.berheley.bi.fillform,com.berheley.bi.system"/>  <!-- 可以配置多个以,号间隔 -->		
		<param name="to" value="1@gmail.com"/> <!-- 可以配置多个以,号间隔 -->		
		<layout class="com.berheley.bi.system.log.log4j.HTMLCustomLayout"/>
	</appender>	
	
	<!-- 多线程 -->		
	<appender name="async" class="org.apache.log4j.AsyncAppender">
		<param name="bufferSize" value="100" />
		<appender-ref ref="db" />
		<appender-ref ref="mail" />
	</appender>
	
	<!-- 继承root log4j包下运行异步线程日志 -->
	<logger name="com.berheley.bi.system.log"> 
		<level value="info"/>
		<appender-ref ref="async"/> 
	</logger>
	
	<!-- 输出级别 -->	
	<root>
		<priority value="error" />
		<appender-ref ref="console" />
		<appender-ref ref="webframe" />
	</root>
	
	<!-- 单个日志级别控制
	<category name="monitorLogger" additivity="false">
        <priority value="info" />
        <appender-ref ref="console"/>
    </category >
    -->
</log4j:configuration>


import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;

import org.apache.commons.logging.Log;
import org.apache.log4j.MDC;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.webframe.web.springmvc.exp.AjaxException;

import com.berheley.bi.basic.exp.BusinessException;
import com.berheley.bi.system.login.LoginUser;

/**
 * 
 * 类功能描述: 日志工具类,设置属性
 *
 * @author <a href="mailto:qingyu.meng21@gmail.com">mengqingyu </a>
 * @version $Id: codetemplates.xml,v 1.1 2009/03/06 01:13:01 mengqingyu Exp  $
 * Create:  2013-4-12 下午04:55:44
 */
public abstract class LogUtils {
	
	public static final String WEB_CONTEXT_ 			= 		"WEB_CONTEXT_";
	
	public static final String LOG_NAME_ 				= 		"LOG_NAME_";
	
	public static final String USER_NAME_ 				= 		"USER_NAME_";
	
	public static final String CLASS_ 					= 		"CLASS_";
	
	public static final String PACKAGES_ 				= 		"PACKAGES_";
	
	public static final String METHOD_NAME_ 			= 		"METHOD_NAME_";
	
	public static final String METHOD_PARAM_ 			= 		"METHOD_PARAM_";
	
	public static final String CLASS_DISCRIPTION_ 		= 		"CLASS_DISCRIPTION_";
	
	public static final String METHOD_DISCRIPTION_ 		= 		"METHOD_DISCRIPTION_";
	
	public static final String MSG_DETAIL_ 				= 		"MSG_DETAIL_";
	
	/**
	 * 
	 * @function:操作行为记录
	 * @param clazz 类对象
	 * @param method 方法对象
	 * @param args 方法参数
	 * @param log 日志对象
	 * @throws BusinessException
	 * @author: mengqingyu    2013-5-30 下午05:29:57
	 */
	public static void beforeLog(Class<?> clazz, Method method, Object[] args, Log log, boolean annotation) throws BusinessException{
		LogDiscription methodDiscription =  method.getAnnotation(LogDiscription.class);
		if(annotation==false||methodDiscription!=null){
			initLog(clazz, method, args, null, methodDiscription);
			log.info(new StringBuilder("info:").append(LogUtils.getClassName()).append("->").append(LogUtils.getMethodName()));
		}
	}
	
	/**
	 * 
	 * @function:异常记录
	 * @param clazz 类对象
	 * @param method 方法对象
	 * @param args 方法参数
	 * @param ex 异常对象
	 * @param log 日志对象
	 * @throws BusinessException
	 * @author: mengqingyu    2013-5-30 下午05:30:00
	 */
	public static void throwingLog(Class<?> clazz, Method method, Object[] args, Exception ex, Log log, boolean annotation) throws BusinessException{
		LogDiscription methodDiscription =  method.getAnnotation(LogDiscription.class);
		if(annotation==false||methodDiscription!=null){
			initLog(clazz, method, args, ex, methodDiscription);
			if(ex instanceof BusinessException || ex instanceof AjaxException){
				log.error(ex.getMessage(),ex);
			}
			else{
				log.fatal(ex.getMessage(),ex);
			}
		}
	}
	
	/**
	 * 
	 * @function:初始化参数
	 * @param clazz 类对象
	 * @param method 方法对象
	 * @param args 方法参数
	 * @param ex 异常对象
	 * @throws BusinessException
	 * @author: mengqingyu    2013-4-12 下午04:56:09
	 */
	protected static void initLog(Class<?> clazz, Method method, Object[] args, Exception ex, LogDiscription methodDiscription) throws BusinessException{
		if(clazz==null||method==null)
			throw new BusinessException("日志初始化参数clazz或method为空");
		
		setLogName();
		setClass(clazz);
		setMethodName(method);
		setMethodParam(args,methodDiscription);
		setClassDiscription(clazz.getAnnotation(LogDiscription.class));
		setMethodDiscription(methodDiscription);
		setMsgDetail(ex);
	}
	
	/**
	 * 
	 * @function:初始化参数
	 * @param clazz 类对象
	 * @param method 方法名称
	 * @param classTypes 方法参数类型
	 * @param args 方法参数
	 * @param ex 异常对象
	 * @throws BusinessException
	 * @author: mengqingyu    2013-4-12 下午04:56:09
	 */
	@SuppressWarnings("rawtypes")
	public static Method initLog(Class<?> clazz, String methodName, Class[] classTypes) throws BusinessException{
		if(clazz==null||methodName==null)
			throw new BusinessException("日志初始化参数:clazz或method为空");
		
		Method method;
		try {
			method = clazz.getMethod(methodName, classTypes);
		} catch (SecurityException e) {
			throw new BusinessException("方法权限错误"+methodName,e);
		} catch (NoSuchMethodException e) {
			throw new BusinessException("方法名或参数类型错误:"+methodName,e);
		}
		return method;
	}
	
	private static void setLogName(){
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
		String Username;
		String RealName;
		if(auth!=null){
			LoginUser loginUser = (LoginUser)auth.getPrincipal();
			Username = loginUser.getUsername();
			RealName = loginUser.getRealName();
		}
		else{
			Username = Thread.currentThread().getName();
			RealName = "无";
		}
		MDC.put(LogUtils.LOG_NAME_, Username);
		MDC.put(LogUtils.USER_NAME_, RealName);
	}
	
	private static void setClass(Class<?> clazz){
		MDC.put(LogUtils.CLASS_, clazz.getName().substring(clazz.getName().lastIndexOf(".")+1));
		MDC.put(LogUtils.PACKAGES_, clazz.getName());
	}
	
	private static void setMethodName(Method method){
		MDC.put(LogUtils.METHOD_NAME_, method.getName());
	}
	
	private static void setMethodParam(Object[] args, LogDiscription logDiscription){
		if(args!=null){
			StringBuilder methodParam = new StringBuilder();
			String param = logDiscription==null?"":logDiscription.param();
			if("".equals(param)){
		        for(Object o:args){  
		        	methodParam.append(o).append("<br/>");
		        }  
			}
			else{
				String[] paramArray = param.split(",");
				int paramLength = paramArray.length;
				if(paramLength != args.length){
					methodParam.append("参数注释错误");
				}
				else{
					for(int i=0;i<args.length;i++){
						methodParam.append(paramArray[i]).append(":").append(args[i]).append("<br/>");
					}
				}
			}
			MDC.put(LogUtils.METHOD_PARAM_, replaceParam(methodParam.toString()));
		}
	}
	
	private static void setClassDiscription(LogDiscription logDiscription){
		MDC.put(LogUtils.CLASS_DISCRIPTION_, replaceParam(logDiscription==null?"":logDiscription.clazz()));
	}
	
	private static void setMethodDiscription(LogDiscription logDiscription){
		MDC.put(LogUtils.METHOD_DISCRIPTION_, replaceParam(logDiscription==null?"":logDiscription.method()));
	}
	
	/**
	 * 
	 * @function:设置异常信息
	 * @param ex 异常对象
	 * @author: mengqingyu    2013-4-12 下午04:56:53
	 */
	public static void setMsgDetail(Exception ex){
		if(ex!=null){
			StringWriter sw = new StringWriter();
			PrintWriter pw = new PrintWriter(sw);
			ex.printStackTrace(pw);
			MDC.put(LogUtils.MSG_DETAIL_, sw);
		}
	}
	
	/**
	 * 
	 * @function:获取类名称
	 * @return
	 * @author: mengqingyu    2013-4-12 下午04:57:13
	 */
	public static String getClassName(){
		return MDC.get(LogUtils.CLASS_)==null?"null":MDC.get(LogUtils.CLASS_).toString();
	}
	
	/**
	 * 
	 * @function:获取方法名称
	 * @return
	 * @author: mengqingyu    2013-4-12 下午04:57:30
	 */
	public static String getMethodName(){
		return MDC.get(LogUtils.METHOD_NAME_)==null?"null":MDC.get(LogUtils.METHOD_NAME_).toString();
	}
	
	private static String replaceParam(String value){
		return value.replace(",", "\\,").replace("'", "\\'");
	}
}

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * 
 * 类功能描述:自定义日志注解
 *
 * @author <a href="mailto:qingyu.meng21@gmail.com">mengqingyu </a>
 * @version $Id: codetemplates.xml,v 1.1 2009/03/06 01:13:01 mengqingyu Exp  $
 * Create:  2013-4-12 下午01:57:44
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface LogDiscription {
	/**
	 * 用法:在类名上方加入注解代码 @LogDiscription(clazz="表单分配")
	 * @function:类注释
	 * @return
	 * @author: mengqingyu    2013-4-12 下午01:57:10
	 */
	String clazz() default "";
	
	/**
	 * 用法:在方法名上方加入注解代码 @LogDiscription(method = "立即发布",param = "任务ID:{0} 主键:{1} 创建时间:{2}")
	 * @function:方法注释
	 * @return
	 * @author: mengqingyu    2013-4-12 下午01:57:22
	 */
	String method() default "";
	
	/**
	 * 
	 * @function:方法参数注释
	 * @return
	 * @author: mengqingyu    2013-4-12 下午01:57:30
	 */
	String param() default "";
}

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Iterator;

import javax.sql.DataSource;

import org.apache.log4j.jdbc.JDBCAppender;
import org.apache.log4j.spi.ErrorCode;
import org.apache.log4j.spi.LoggingEvent;
import org.webframe.web.util.WebFrameUtils;

/**
 * 
 * 类功能描述:log4j 入库日志管理,重写此类解决数据源、批量插入和日志过滤等问题
 *
 * @author <a href="mailto:qingyu.meng21@gmail.com">mengqingyu </a>
 * @version $Id: codetemplates.xml,v 1.1 2009/03/06 01:13:01 mengqingyu Exp  $
 * Create:  2013-4-9 下午02:20:08
 */
public class JDBCCustomAppender extends JDBCAppender {

	/**
	 * 类功能描述:数据库连接池,单例,延迟实例化
	 */
	private static class DataSourceHolder {
		private static final DataSource dataSource = (DataSource) WebFrameUtils.getApplicationContext().getBean("dataSource");
	}
	
	/**
	 * 在日志加入集合过程中进行处理
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void append(LoggingEvent event) {
		buffer.add(event);
		if (buffer.size() >= bufferSize)
			flushBuffer();
	}

	/**
	 * 从连接池中获取连接
	 */
	@Override
	protected Connection getConnection() throws SQLException {
		return DataSourceHolder.dataSource.getConnection();
	}

	/**
	 * 删去了源方法中的一些操作
	 */
	@Override
	public void close() {
		this.closed = true;
	}

	/**
	 * 释放连接
	 */
	@Override
	protected void closeConnection(Connection con) {
		try {
			con.close();
		} catch (SQLException e) {
			errorHandler.error("Error closing connection", e, ErrorCode.GENERIC_FAILURE);
		}
	}

	/**
	 * 重写批量插入操作
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void flushBuffer() {
		Connection con = null;
		Statement stmt = null;
		try {
			con = getConnection();
			stmt = con.createStatement();
			removes.ensureCapacity(buffer.size());
			for (Iterator<LoggingEvent> i = buffer.iterator(); i.hasNext();) {
				LoggingEvent logEvent = i.next();
				stmt.addBatch(getLogStatement(logEvent));
				removes.add(logEvent);
			}
		 	stmt.executeBatch();
		} catch (SQLException e) {
		    errorHandler.error("Failed to excute sql", e,ErrorCode.FLUSH_FAILURE);
		} finally {
			try {
				stmt.close();
			} catch (SQLException e) {
				errorHandler.error("Failed to excute sql", e,ErrorCode.FLUSH_FAILURE);
			} finally {
				closeConnection(con);
			}
		}
		buffer.removeAll(removes);
		removes.clear();
	}
}

import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.net.SMTPAppender;
import org.apache.log4j.spi.ErrorCode;
import org.apache.log4j.spi.LoggingEvent;

/**
 * 
 * 类功能描述:log4j 邮件日志管理,重写此类解决不支持权限认证、缓存问题和gmail端口号问题,注:新版本log4j已经支持认证
 *
 * @author <a href="mailto:qingyu.meng21@gmail.com">mengqingyu </a>
 * @version $Id: codetemplates.xml,v 1.1 2009/03/06 01:13:01 mengqingyu Exp  $
 * Create:  2013-4-11 下午01:44:19
 */
public class SMTPCustomAppender extends SMTPAppender {

	protected String smtpUsername;

	protected String smtpPassword;

	protected String smtpAuth;

	protected String[] packages;
	
	protected String to;

	protected String from;

	protected String subject;

	protected String smtpHost;

	protected int bufferSize = 512;

	protected boolean locationInfo = false;

	public void setSmtpUsername(String smtpUsername) {
		this.smtpUsername = smtpUsername;
	}

	public void setSmtpPassword(String smtpPassword) {
		this.smtpPassword = smtpPassword;
	}

	public void setSmtpAuth(String smtpAuth) {
		this.smtpAuth = smtpAuth;
	}

	public void setTo(String to) {
		this.to = to;
	}

	public void setPackages(String packages) {
		this.packages = packages.split(",");
	}

	public void setFrom(String from) {
		this.from = from;
	}

	public void setSubject(String subject) {
		this.subject = subject;
	}

	public void setSmtpHost(String smtpHost) {
		this.smtpHost = smtpHost;
	}

	public void setBufferSize(int bufferSize) {
		this.bufferSize = bufferSize;
	}

	public void setLocationInfo(boolean locationInfo) {
		this.locationInfo = locationInfo;
	}

	/**
	 * 在日志加入集合过程中进行处理
	 */
	public void append(LoggingEvent event) {
		if (!checkEntryConditions()) {
			return;
		}

		event.getThreadName();
		event.getNDC();
		if (locationInfo) {
			event.getLocationInformation();
		}
		//包过滤
		if(packages!=null&&packages.length>0){
			String clazz = event.getMDC(LogUtils.PACKAGES_).toString();
			for(int i=0;i<packages.length;i++){
				if(clazz.startsWith(packages[i])){
					cb.add(event);
					break;
				}
			}
		}
		else{
			cb.add(event);
		}
		if (evaluator.isTriggeringEvent(event)) {
            if (cb.length() >= bufferSize) { //添加缓存判断 
                sendBuffer();  
            }  
		}
	}

	/**
	 * 初始化邮件对象并进行权限认证
	 */
	public void activateOptions() {
		Properties props = new Properties(System.getProperties());
		if (smtpHost != null) {
			props.put("mail.smtp.host", smtpHost);
			// 邮件默认端口号是25,gmail邮件服务商用是465端口,需要手动处理
			if (smtpHost.indexOf("smtp.gmail.com") >= 0) {
				props.setProperty("mail.smtp.socketFactory.class",
						"javax.net.ssl.SSLSocketFactory");
				props.setProperty("mail.smtp.socketFactory.fallback", "false");
				props.setProperty("mail.smtp.port", "465");
				props.setProperty("mail.smtp.socketFactory.port", "465");
			}
		}

		Authenticator authenticator = null;

		if (smtpAuth != null && smtpAuth.trim().equals("true")) {
			props.put("mail.smtp.auth", "true");
			authenticator = new Authenticator() {
				protected PasswordAuthentication getPasswordAuthentication() {
					return new PasswordAuthentication(smtpUsername,
							smtpPassword);
				}
			};
		}

		Session session = Session.getInstance(props, authenticator);
		msg = new MimeMessage(session);

		try {
			if (from != null)
				msg.setFrom(getAddress(from));// 设置发件人
			else
				msg.setFrom();
			msg.setRecipients(Message.RecipientType.TO, parseAddress(to));// 设置收件人
			if (subject != null){
				String context = WebFrameUtils.getWebContextPath();
				context = StringUtils.isBlank(context)?subject:context.replace("/", "")+" "+subject;
				msg.setSubject(context);
			}
				
		} catch (MessagingException e) {
			LogLog.error("Could not activate SMTPAppender options.", e);
		}
	}

	/**
	 * 
	 * @function:获得地址
	 * @param addressStr
	 * @return
	 * @author: mengqingyu 2013-4-10 下午02:38:30
	 */
	protected InternetAddress getAddress(String addressStr) {
		try {
			return new InternetAddress(addressStr);
		} catch (AddressException e) {
			errorHandler.error("Could not parse address [" + addressStr + "].",
					e, ErrorCode.ADDRESS_PARSE_FAILURE);
			return null;
		}
	}

	/**
	 * 
	 * @function:转换地址
	 * @param addressStr
	 * @return
	 * @author: mengqingyu 2013-4-10 下午02:38:52
	 */
	protected InternetAddress[] parseAddress(String addressStr) {
		try {
			return InternetAddress.parse(addressStr, true);
		} catch (AddressException e) {
			errorHandler.error("Could not parse address [" + addressStr + "].",
					e, ErrorCode.ADDRESS_PARSE_FAILURE);
			return null;
		}
	}
}

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;

/**
 * 
 * 类功能描述:log4j 日志模板,重写此类解决中文乱码和自定义模板问题
 *
 * @author <a href="mailto:qingyu.meng21@gmail.com">mengqingyu </a>
 * @version $Id: codetemplates.xml,v 1.1 2009/03/06 01:13:01 mengqingyu Exp  $
 * Create:  2013-4-11 下午01:46:43
 */
public class HTMLCustomLayout extends HTMLLayout {

	protected StringBuffer sbuf = new StringBuffer(BUF_SIZE);

	protected static String TRACE_PREFIX = "<br>&nbsp;&nbsp;&nbsp;&nbsp;";

	protected boolean locationInfo = false;

	protected String title = "Log4J Log Messages";

	public void setLocationInfo(boolean flag) {
		locationInfo = flag;
	}

	public boolean getLocationInfo() {
		return locationInfo;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getTitle() {
		return title;
	}

	/**
	 * 格式化HTML头部模板
	 */
	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: x-small;}"
				+ 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("<hr size=\"1\" noshade>" + Layout.LINE_SEP);
		sbuf.append("Log session start time " + new java.util.Date() + "<br>"
				+ Layout.LINE_SEP);
		sbuf.append("<br>" + 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);
		sbuf.append("<th>级别</th>" + Layout.LINE_SEP);
		sbuf.append("<th>类名称</th>" + Layout.LINE_SEP);
		if (locationInfo) {
			sbuf.append("<th>File:Line</th>" + Layout.LINE_SEP);
		}
		sbuf.append("<th>方法名称</th>" + Layout.LINE_SEP);
		sbuf.append("</tr>" + Layout.LINE_SEP);
		return sbuf.toString();
	}

	/**
	 * 格式化HTML模板
	 */
	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(event.getMDC("LOG_NAME_"));
		sbuf.append("</td>" + Layout.LINE_SEP);

		sbuf.append("<td>");
		sbuf.append(event.getMDC("USER_NAME_"));
		sbuf.append("</td>" + Layout.LINE_SEP);

		sbuf.append("<td title=\"Level\">");
		if (event.getLevel().equals(Level.DEBUG)) {
			sbuf.append("<font color=\"#339933\">");
			sbuf.append(event.getLevel());
			sbuf.append("</font>");
		} else if (event.getLevel().isGreaterOrEqual(Level.WARN)) {
			sbuf.append("<font color=\"#993300\"><strong>");
			sbuf.append(event.getLevel());
			sbuf.append("</strong></font>");
		} else {
			sbuf.append(event.getLevel());
		}
		sbuf.append("</td>" + Layout.LINE_SEP);

		sbuf.append("<td>");
		sbuf.append(event.getMDC("CLASS_"));
		sbuf.append("</td>" + Layout.LINE_SEP);

		if (locationInfo) {
			LocationInfo locInfo = event.getLocationInformation();
			sbuf.append("<td>");
			sbuf.append(Transform.escapeTags(locInfo.getFileName()));
			sbuf.append(':');
			sbuf.append(locInfo.getLineNumber());
			sbuf.append("</td>" + Layout.LINE_SEP);
		}

		sbuf.append("<td>");
		sbuf.append(event.getMDC("METHOD_NAME_"));
		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);
		}

		Object methodParam = event.getMDC("METHOD_PARAM_");
		if(methodParam!=null){
			sbuf.append("<tr><td style=\"font-size : xx-small;\" colspan=\"6\">");
			sbuf.append("方法参数:"+methodParam.toString().replace("\\r\\n", "&nbsp;&nbsp;"));
			sbuf.append("</td></tr>" + Layout.LINE_SEP);
		}
		
		sbuf.append("<tr><td style=\"font-size : xx-small;\" colspan=\"6\">");
		sbuf.append("异常摘要:"+event.getMessage());
		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=\"6\">");
			appendThrowableAsHTML(s, sbuf);
			sbuf.append("</td></tr>" + Layout.LINE_SEP);
		}

		return sbuf.toString();
	}

	/**
	 * 
	 * @function:拼装异常内容
	 * @param s
	 * @param sbuf
	 * @author: mengqingyu    2013-4-11 下午01:49:29
	 */
	protected 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);
			}
		}
	}

	/**
	 * 中文编码
	 */
	public String getContentType() {
		return "text/html;charset=GBK";
	}
}

注:在类或方法上通过注解的方式来进行描述
@LogDiscription(method = "立即发布",param = "任务ID, 主键, 创建时间")
	@Override
	public void insertOrUpdateMysqlDatas(JSONArray datas, String tableName, String pkName){}
分享到:
评论
2 楼 mengqingyu 2013-05-06  
肯定是线程安全的
w2220533 写道
我想问一个问题.
这个记录日志的框架是否是线程安全的.
如果是多个线程的调用.是不是日志输出就不太理想了.
不太懂.请多指教

异步输出,底层用的vector,线程安全的,多线程下会将所有要输出的日志对象都放到单独的一个线程中去同步处理vector中的日志,而不影响主线程返回结果,采用的是生产者消费者并发模式。
1 楼 w2220533 2013-05-03  
我想问一个问题.
这个记录日志的框架是否是线程安全的.
如果是多个线程的调用.是不是日志输出就不太理想了.
不太懂.请多指教

相关推荐

Global site tag (gtag.js) - Google Analytics