我们怎么去做日志同步呢?
方案一:在Log4j的体系中有个东西叫做LoggerFilter,这个类的工具是用来做日志过滤,每次我们打印日志的时候都会经过这个filter,来决定是否打印日志。比如:
public int decide(LoggingEvent event) { if(this.levelMin != null) { if (event.getLevel().isGreaterOrEqual(levelMin) == false) { // level of event is less than minimum return Filter.DENY; } } if(this.levelMax != null) { if (event.getLevel().toInt() > levelMax.toInt()) { // level of event is greater than maximum // Alas, there is no Level.isGreater method. and using // a combo of isGreaterOrEqual && !Equal seems worse than // checking the int values of the level objects.. return Filter.DENY; } } if (acceptOnMatch) { // this filter set up to bypass later filters and always return // accept if level in range return Filter.ACCEPT; } else { // event is ok for this filter; allow later filters to have a look.. return Filter.NEUTRAL; } }
可以看到我们在配置文件里面配置的
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelMax" value="ERROR" />
<param name="LevelMin" value="info" />
</filter>
根据上面的原理,我们可以定义一个filter,然后每次打印日志的时候异步把日志发送出去。
/** * Alipay.com Inc. * Copyright (c) 2004-2016 All Rights Reserved. */ package com.zhangwei.learning.utils.log; import java.util.Date; import org.apache.log4j.spi.Filter; import org.apache.log4j.spi.LoggingEvent; import com.zhangwei.learning.model.Constants; import com.zhangwei.learning.model.LogResource; import com.zhangwei.learning.model.LogResourceDTO; /** * 日志filter * @author Administrator * @version $Id: LogFilter.java, v 0.1 2016年7月4日 下午9:41:26 Administrator Exp $ */ public class LogSendFilter extends Filter implements Constants { /** 暂存日志的DTO,当日志内容大小到达sendSize的时候,会把日志发送给服务器 */ private ThreadLocal<LogResourceDTO> dtoThreadLocal = new ThreadLocal<LogResourceDTO>() { protected LogResourceDTO initialValue() { LogResourceDTO logResourceDTO = new LogResourceDTO(); return logResourceDTO; }; }; /** 日志长度为多少字符的时候会触发发送日志事件 */ private int sendSize = 100; /** 系统名 */ private String systemName = null; /** 用于接收日志的服务器 */ private String logServerAddress = null; private LogSender logSender = new LogSender(); /** * @see org.apache.log4j.spi.Filter#decide(org.apache.log4j.spi.LoggingEvent) */ @Override public int decide(LoggingEvent event) { initOnEveryTime(); sendLogs(event); return Filter.ACCEPT; } /** * 每次调用Filter得时候都会初始化下 */ private void initOnEveryTime() { LogResourceDTO dto = dtoThreadLocal.get(); dto.setSystemName(systemName); } /** * 按照日志条数发送 * @param event * @return */ private void sendLogs(LoggingEvent event) { //先检查大小 String content = event.getMessage() + EMPTY_STRING; LogResourceDTO logResourceDTO = dtoThreadLocal.get(); logResourceDTO.addLogResource(new LogResource(new Date(), event.getLoggerName(), content)); //当数据没到sendSize那么保存日志 if (logResourceDTO.getLogs().size() < sendSize) { return; } //日志超sendSize了,那么发送日志,然后把新的日志保存 //TODO send data try { logSender.sendLog(logResourceDTO.reflectToString(), logServerAddress); logResourceDTO.clear(); } catch (Exception e) { e.printStackTrace(); } finally { } return; } /** * Setter method for property <tt>sendSize</tt>. * * @param sendSize value to be assigned to property sendSize */ public void setSendSize(int sendSize) { this.sendSize = sendSize; } /** * 设置系统名 * @param systemName */ public void setSystemName(String systemName) { this.systemName = systemName; } /** * Setter method for property <tt>logServerAddress</tt>. * * @param logServerAddress value to be assigned to property logServerAddress */ public void setLogServerAddress(String logServerAddress) { this.logServerAddress = logServerAddress; } }