Log4j 2 API

标记

日志框架的主要目的之一是提供一种方法,仅在需要时生成调试和诊断信息,并允许过滤这些信息,以防止其淹没系统或需要使用这些信息的人员。例如,应用程序希望分别记录其入口、退出和其他操作,与正在执行的 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.traceEntry();

        logger.debug(QUERY_MARKER, "SELECT * FROM {}", table);

        String result = ...

        return logger.traceExit(result);
    }

    public String doUpdate(String table, Map<String, String> params) {
        logger.traceEntry();

        if (logger.isDebugEnabled()) {
            logger.debug(UPDATE_MARKER, "UPDATE {} SET {}", table, formatCols());
        }

        String result = ...

        return logger.traceExit(result);
    }

    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();
    }
}

在上面的示例中,现在可以添加 MarkerFilters,仅允许记录 SQL 更新操作,记录所有 SQL 更新操作,或记录 MyApp 中的所有内容。

在使用标记时,必须考虑一些关于标记的重要规则。

  1. 标记必须是唯一的。它们是按名称永久注册的,因此应注意确保应用程序中使用的标记与应用程序依赖项中的标记不同,除非这是预期的行为。
  2. 可以动态添加或删除父标记。但是,这样做相当昂贵。相反,建议在第一次获取标记时识别父标记,如上面的示例所示。具体来说,set 方法在单个操作中替换所有标记,而 add 和 remove 方法一次只对单个标记进行操作。
  3. 评估具有多个祖先的标记比评估没有父标记的标记要昂贵得多。例如,在一组测试中,评估标记是否与其祖父母匹配所花费的时间是评估标记本身的三倍。即使如此,评估标记的成本仍然比解析调用者的类名或行号要低。