Log4j版本2中将MDC和NDC合并到一个单独的组件中,这个组件被称为线程上下文。线程上下文是针对MDC和NDC的进化,它分别用线程上下文Map映射线程上下文栈来表示MDC和NDC。我们可以通过ThreadContext静态类来管理线程上下文,这个类在实现上类似于Log4j版本1中的MDC和NDC。
  When using the Thread Context Stack, data is pushed to and popped from a stack just like with NDC:
  当使用线程上下文栈时,我们可以向NDC那样向栈中添加或者删除数据:
  import org.apache.logging.Log4j.ThreadContext;
  ...
  ThreadContext.push(username);
  ThreadContext.push(sessionID);
  // Logging methods go here
  ThreadContext.pop();
  ...
  当使用线程上下文映射时,我们可以像MDC那样将值和键结合在一起:
  import org.apache.logging.Log4j.ThreadContext;
  ...
  ThreadContext.put(“username”,"admin");
  ThreadContext.put("sessionID", "1234");
  // Logging methods go here
  ThreadContext.clearMap();
  ...
  ThreadContext类提供了一些方法,用于清除栈、清除MDC、清除存储在上下文中的所有值,对应的方法是ThreadContext.clearAll()、ThreadContext.clearMap()和ThreadContext.clearStack()。
  和在MDC以及NDC中一样,我们可以使用Layouts在线程上下文中访问这些值。使用PatternLayout时,%x转换模式会从栈中获取值,%X和%X(键)会从图中获取值。
  ThreadContext过滤
  一些框架允许你基于某些属性对日志进行过滤。例如,Log4j的DynamicThresholdFilter 会在键满足特定条件的情况下,自动调整日志级别。再比如,如果我们想要触发TRACE级别的日志消息,我们可以创建一个名为trace-logging-enabled的键,并向log4j配置文件中添加一个过滤器:
  <Configuration name="MyApp">
  <DynamicThresholdFilter key="trace-logging-enabled" onMatch="ACCEPT" onMismatch="NEUTRAL">
  <KeyValuePair key="true" value="TRACE" />
  </DynamicThresholdFilter>
  ...
  如果ThreadContext包含一个名为trace-logging-enabled的键,onMatch 和 onMismatch 会决定如何处理它。关于 onMatch 和 onMismatch,我们有三个可选项:ACCEPT,它会处理过滤器的规则;DENY,它会忽略过滤器的规则;NEUTRAL,它会推迟到下一个过滤器。除了这些,我们还定义一个键值对,当值为true时,我们启用TRACE级别的日志。
  现在,当trace-logging-enabled被设置成true时,即使根Logger设置的日志级别高于TRACE,Appender也会记录TRACE级别的消息。
  你可能还想过滤一些特定的日志到特定的Appender中,Log4j中提供了ThreadContextMapFilter来实现这一点。如果我们想要限制某个特定的Appender,只记录针对某个用户的TRACE级别的消息,我们可以基于username键添加一个ThreadContextMapFilter:
  <Console name="ConsoleAppender" target="SYSTEM_OUT">
  <ThreadContextMapFilter onMatch="ACCEPT" onMismatch="DENY">
  <KeyValuePair key="username" value="admin" />
  </ThreadContextMapFilter>
  ...
  如果想了解更多信息,你可以查看Log4j和Logback文档中关于DynamicThresholdFilter部分。
  Markers
  Markers允许你对单独的日志记录添加一些的数据。它可以用来对日志记录进行分组,触发一些行为,或者对日志记录进行过滤,并将过滤结果输出到指定的Appender中。你甚至可以将Markers和ThreadContext结合在一起使用,以提高搜索和过滤日志数据的能力。
  例如,假设我们有一个可以连接到数据库的类,如果在打开数据库的时候发生了异常,我们需要把异常记录成fatal错误。我们可以创建一个名为DB_ERROR的Marker,然后将其应用到日志事件中:
  import org.apache.logging.Log4j.Marker;
  import org.apache.logging.Log4j.MarkerManager;
  ...
  final static Marker DB_ERROR = MarkerManager.getMarker("DATABASE_ERROR");
  ...
  logger.fatal(DB_ERROR, "An exception occurred.");
  为了在日志输出中显示Marker信息,我们需要在PatternLayout中添加%marker转换模式:
  <PatternLayout pattern="%p %marker: %m%n" />
  [FATAL] DATABASE_ERROR: An exception occurred.
  或者对于JSON和XML格式的Layouts,会自动在输出中包含Marker信息:
  ...
  "thread" : "main",
  "level" : "FATAL",
  "loggerName" : "DBClass",
  "marker" : {
  "name" : "DATABASE_ERROR"
  },
  "message" : "An exception occurred.",
  ...
  通过对Marker数据进行自动解析和排序,集中式的日志服务可以很容易对日志进行搜索处理。
  Markers过滤
  Marker过滤器可以让你决定哪些Marker由哪些Logger来处理。marker字段会比较在日志事件里面的Marker名字,如果名字匹配,那么Logger会执行后续的行为。例如,在Log4j中,我们可以配置一个Appender来只显示哪些使用了DB_ERROR Marker的消息,这可以通过log4j2.xml中的Appender添加如下信息来实现:
  <MarkerFilter marker="DATABASE_ERROR" onMatch="ACCEPT" onMismatch="DENY" />
  如果日志记录中某一条的Marker可以匹配这里的marker字段,那么onMatch会决定如何处理这条记录。如果不能够匹配,或者日志记录中没有Marker信息,那么onMismatch会决定如何处理这条记录。对于onMatch和onMismatch来说,有3个可选项:ACCEPT,它允许记录事件;DENY,它会阻塞事件;NEUTRAL,它不会对事件进行任何处理。
  在Logback中,我们需要更多一些设置。首先,想Appender中添加一个新的EvaluatorFilter,并如上所述指定onMatch和onMismatch行为。然后,添加一个OnMarkerEvaluator并将Marker的名字传递给它:
  <filter class="ch.qos.Logback.core.filter.EvaluatorFilter">
  <evaluator class="ch.qos.Logback.classic.boolex.OnMarkerEvaluator">
  <marker>DATABASE_ERROR</marker>
  </evaluator>
  <onMatch>ACCEPT</onMatch>
  <onMismatch>DENY</onMismatch>
  </filter>
  将Markers和NDC、MDC以及ThreadContext结合使用
  Marker的功能和ThreadContext类似,它们都是向日志记录中添加的数据,这些数据可以被Appender访问。如果把这两者结合使用,可以让你更容易的对日志数据进行索引和搜索。如果能够知道何时使用哪一种技术,会对我们有所帮助。
  NDC、MDC和ThreadContext被用于将相关日志记录结合在一起。如果你的应用程序会处理多个同时存在的用户,ThreadContext可以让你将针对某个特定用户的一组日志记录组合在一起。因为ThreadContext针对每个线程都是不一样的,所以你可以使用同样的方法来对相关的日志记录进行自动分组。
  另一方面,Marker通常用于标记或者高亮显示某些特殊事件。在上述示例中,我们使用DB_ERROR Marker来标明在方法中发生的SQL相关异常。我们可以使用DB_ERROR Marker来将这些事件的处理过程和其他事件区分开来,例如我们可以使用SMTP Appender来将这些事件通过邮件发送给数据库管理员。
  额外资源
  指南和教程
  Java Logging(Jakob Jenkov)——使用Java Logging API进行日志开发教程
  Java Logging Overview(Oracle)—— Oracle提供的在Java中进行日志开发的指南
  Log4J Tutorial(Tutorials Point)——使用log4j 版本1进行日志开发的指南
  日志抽象层
  Apache Commons Logging(Apache)——针对Log4j、Avalon LogKit和java.util.logging的抽象层
  SLF4J(QOS.ch)——一个流程的抽象层,应用在多个日志框架上,包括Log4j、Logback以及java.util.logging
  日志框架
  Java Logging API(Oracle)—— Java默认的日志框架
  Log4j(Apache)——开源日志框架
  Logback(Logback Project)——开源项目,被设计成Log4j版本1的后续版本
  tinylog(tinylog)——轻量级开源logger