Log4j 2 API
Marker
日志框架最主要的目的之一,就是仅在需要的时候生成调试和诊断信息,并且过滤这些信息以防淹没系统或需要使用它的个体。举个例子,程序渴望记录它的进入、退出和其他操作,要与SQL语句的执行分离开,并且希望可以将查询和更新分开记录。一种做法是像下面这样做:
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.MarkerManager;
import java.util.Map;
public class MyApp {
private Logger logger = LogManager.getLogger(MyApp.class.getName());
private static final Marker SQL_MARKER = MarkerManager.getMarker("SQL");
private static final Marker UPDATE_MARKER = MarkerManager.getMarker("SQL_UPDATE").setParents(SQL_MARKER);
private static final Marker QUERY_MARKER = MarkerManager.getMarker("SQL_QUERY").setParents(SQL_MARKER);
public String doQuery(String table) {
logger.entry(param);
logger.debug(QUERY_MARKER, "SELECT * FROM {}", table);
return logger.exit();
}
public String doUpdate(String table, Map<String, String> params) {
logger.entry(param);
if (logger.isDebugEnabled()) {
logger.debug(UPDATE_MARKER, "UPDATE {} SET {}", table, formatCols());
return logger.exit();
}
private String formatCols(Map<String, String> cols) {
StringBuilder sb = new StringBuilder();
boolean first = true;
for (Map.Entry<String, String> entry : cols.entrySet()) {
if (!first) {
sb.append(", ");
}
sb.append(entry.getKey()).append("=").append(entry.getValue());
first = false;
}
return sb.toString();
}
}
在上例中,现在可以通过添加MarkerFilter来在MyApp中做到:只允许SQL更新操作被记录、所有的SQL更新被记录或记录所有。
使用Marker时必须注意一些重要的规则:
- Marker必须是唯一的。它们将根据名称被永久地注册,应该注意确保应用程序使用的Marker和应用所依赖的那些是不同的,除非那是确实需要的。
- 父Marker可以被动态地添加或删除。然而,这代价非常高。相反,推荐像上面例子中那样在首次获取Marker时定位父Marker。特别注意,set方法会在一次添加或删除操作中一次性地替换掉所有的Marker。
- 评估一个拥有多个祖先的Marker比没有祖先的Marker成本要更高。例如,在一组测试中评估一个Marker是否匹配其祖父要比评估该Marker自身花费三倍更长的时间。尽管如此,与处理调用者类名和行号相比,Marker的成本还不是很高。