日志设计文档
日志使我们系统中必不可少的元素,他的特点是比较多。为了不让日志影响我们的正常的业务响应速度,采用了如下设计。
1 采用日志池概念,当业务系统产生一条日志时候,我们直接丢在日志池里面,单独开一个线程把日志池中缓存的日志写入数据库。
2 业务系统解耦,一般的操作我们都想记录用户的ip所以我们可以新建拦截器,当用户请求过来时候可以缓存一个log对象记录请求的ip和用户名,当请求结束时候,清空缓存。业务系统丢日志进来后,先根据线程id查询当前线程中缓存的log。取其中的用户ip和名字
核心代码
a 拦截器实现
public class DefaultExceptionInterceptor implements Interceptor {
public void intercept(Invocation ai) {
try{
Controller controller = ai.getController();
Log log = new Log();
log.set("user_ip", ActionFunc.getIp(controller.getRequest()));
LogFactory.getLogManager().putCache(log);
ai.invoke();
}
catch(Exception e) {
String erroCcode = ResultCode.ERROR.getCode();
String errorMsg = ResultCode.ERROR.getMsg();
Controller controller = ai.getController();
if(e instanceof DmsException) {
erroCcode = ((DmsException) e).getCode();
errorMsg = e.getMessage();
}
else {
e.printStackTrace();
}
//如果是ajax请求
if("XMLHttpRequest".equals(controller.getRequest().getHeader("X-Requested-With"))){
controller.renderJson(ResultJson.getError(erroCcode,errorMsg));
}
else {
controller.setAttr("errorMsg", errorMsg);
controller.render("/WEB-INF/frame/error.html");
}
}
finally {
LogFactory.getLogManager().removeCache();
}
}
}
b 日志池
public class LogManagerImpl implements LogManager {
protected final static Logger logger = LoggerFactory.getLogger(LogManagerImpl.class);
private List<Log> loglist1 = new ArrayList<Log>();
private List<Log> loglist2 = new ArrayList<Log>();
private boolean useList1 = true;
private static Hashtable<Long, Log> logs = new Hashtable<Long, Log>();
private final String sql = "insert into sys_log (partner_id,user_id,user_name,user_ip,detail,log_type,create_time) values(?,?,?,?,?,?,?)";
@Override
public void run() {
while(true) {
try {
Thread.sleep(5000l);
List<Log> freeList = null;
if(useList1) {
freeList = loglist2;
}
else {
freeList = loglist1;
}
int size = freeList.size();
if(size != 0) {
Object[][] paramValue=new Object[size][7];
for(int i=0;i<size;i++) {
Log temp = freeList.get(i);
paramValue[i] = new Object[]{temp.get("partner_id"),temp.get("user_id"),temp.get("user_name"),temp.get("user_ip"),temp.get("detail"),temp.get("log_type"),temp.get("create_time")};
}
Db.batch(sql, paramValue, 500);
}
freeList.clear();
useList1 = !useList1;
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void addLog(int level, String detail) {
long threadId = Thread.currentThread().getId();
Log log = logs.get(threadId);
if(log == null) {
log = new Log();
}
Log saveLog = new Log();
saveLog.put("partner_id", log.get("partner_id"));
saveLog.put("user_id", log.get("user_id"));
saveLog.put("user_name", log.get("user_name"));
saveLog.put("user_ip", log.get("user_ip"));
saveLog.put("log_type", level);
saveLog.put("detail", detail);
saveLog.put("create_time", new Date());
if(useList1) {
loglist1.add(saveLog);
}
else {
loglist2.add(saveLog);
}
}
@Override
public void putCache(Log log) {
long threadId = Thread.currentThread().getId();
logs.put(threadId, log);
}
@Override
public Log getCacheLog() {
long threadId = Thread.currentThread().getId();
return logs.get(threadId);
}
@Override
public void removeCache() {
long threadId = Thread.currentThread().getId();
logs.remove(threadId);
}
}
c 日志记录器
public class LoggerImpl implements Logger {
private LogManager manager = null;
public LoggerImpl(LogManager manager) {
this.manager = manager;
}
@Override
public void debug(String detail) {
manager.addLog(LogConst.LEVEL_DEBUG, detail);
}
@Override
public void info(String detail) {
manager.addLog(LogConst.LEVEL_INFO, detail);
}
@Override
public void warn(String detail) {
manager.addLog(LogConst.LEVEL_WARN, detail);
}
@Override
public void error(String detail) {
manager.addLog(LogConst.LEVEL_ERROR, detail);
}
@Override
public void fatal(String detail) {
manager.addLog(LogConst.LEVEL_FATAL, detail);
}
}
d 日志调用
private static Logger logger = LogFactory.getLogger();
/**
* 用户登录
* @param userId
* @param password
* @return
*/
public static Map<String,Object> doLogin(String partnerId,String userId,String password) {
Map<String,Object> user = null;
//如果是超级管理员
if(StrFunc.compareStr(RestaurantConfig.globalConf.getProperty("adminName"), userId)) {
user = adminLogin(partnerId, userId, password);
}
//普通用户登录
else {
user = userLogin(partnerId,userId,password);
}
logger.info("登录系统");
return user;
}