Log日志
大约 3 分钟
Log日志
在完成日常任务时,有时候需要根据不同的目的,自己定制化完成log日志的输出,通过配置文件实现日志输出存在一定的局限性,可以通过代码来,定制化实现下面的目标
- 自定义日志文件输出目录
- 自定义日志文件名称格式
- 自定义日志文件输出间隔
- 自定义日志内容输出格式 ...
配置文件
package com.game.server.config;
import java.text.SimpleDateFormat;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.varia.LevelRangeFilter;
public class LoggerFactory {
// 防止频繁创建Logger对象
private static volatile Map<String, List<Object>> logMap = new ConcurrentHashMap<String, List<Object>>();
public static Logger getLogger(String baseDir, String appId, String type) {
SimpleDateFormat formatter = new SimpleDateFormat("'_'yyyyMMdd");
String date = formatter.format(new Date());
if (StringUtils.isEmpty(baseDir) || StringUtils.isEmpty(appId)) {
throw new IllegalArgumentException("cannot be empty");
}
// 防止map过大不按时间存储{ key: [date_A, logger_A] }
String key = baseDir + "/" + appId + "/gameserver_" + appId + "_" + type;
List<Object> list = logMap.get(key);
if (list == null) {
// 存储新数据
try {
Logger logger = createLogger(key, type, date);
return logger;
} catch (Exception e) {
e.printStackTrace();
}
}
// 比较时间
String saveDate = String.valueOf(list.get(0));
if (saveDate.equals(date)) {
Logger logger = (Logger) list.get(1);
return logger;
} else {
try {
// 更新数据
Logger logger = createLogger(key, type, date);
return logger;
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
/**
* 添加同步锁,并进行双端校验,防止重复创建
*
* @param key
* @param type
* @param date
* @return
*/
private synchronized static Logger createLogger(String key, String type, String date) {
// 双端检索,防止重复创建
List<Object> list = logMap.get(key);
if (list != null) {
String saveDate = String.valueOf(list.get(0));
if (saveDate.equals(date)) {
Logger logger = (Logger) list.get(1);
return logger;
}
}
String logFilePath = key + date;
// 添加Appender到日志记录器
Logger logger = Logger.getLogger("com.game.server.config.LoggerFactory." + type + date);
FileAppender appender = new FileAppender();
// 设置输出文件名
appender.setFile(logFilePath);
// 设置输出格式
appender.setLayout(new PatternLayout("%m%n"));
// 设置Appender的阈值级别
appender.setThreshold(Level.INFO);
appender.activateOptions();
LevelRangeFilter filterInfo = new LevelRangeFilter();
filterInfo.setLevelMin(Level.INFO);
filterInfo.setLevelMax(Level.ERROR);
appender.addFilter(filterInfo);
logger.addAppender(appender);
list = new ArrayList<>();
list.add(date);
list.add(logger);
logMap.put(key, list);
return logger;
}
}
配置介绍
本文采用log4j作为基础,使用时需要引入相关依赖
主要通过getLogger静态方法,获取日志Logger对象,入参是String baseDir, String appId, String type
- baseDir设置日志存放根目录
- appId区分不同日志目录
- type区分日志文件类型
本文中采用的是每天自动生成新的日志文件,为了防止运行时占用堆空间过大,不以时间直接存储到logMap,这样既可以减少资源的占用,又可以减少Logger对象的频繁创建
主要是对比时间以及文件类型来判断是否需要创建Logger对象
提示
// 双端检索,防止重复创建
List<Object> list = logMap.get(key);
if (list != null) {
String saveDate = String.valueOf(list.get(0));
if (saveDate.equals(date)) {
Logger logger = (Logger) list.get(1);
return logger;
}
}
这段代码比较重要,防止并发的时候重复创建日志记录器,
// 添加Appender到日志记录器 Logger logger = Logger.getLogger("com.game.server.config.LoggerFactory." + type + date);
日志使用
Logger logger = LoggerFactory.getLogger(cache.getBaseDir(), appid, CORE_LOG);
logger.info("[" + time + "][LogReg]," + JSON.toJSONString(params, SerializerFeature.WriteMapNullValue));