你也可以通过FasterXML Wiki找到更多关于Jackson的深度介绍。
  了解更多JSON相关信息
  你可以通过JSON主页学习更多JSON相关信息,或者通过CodeAcademy来通过学习一个交互式的快速上手教程(请注意这个课程是基于JavaScript的,而不是Java)。有一些在线工具例如JSONLint和JSON在线编辑器可以帮助你解析、验证以及格式化JSON代码。
  NDC、MDC以及ThreadContext
  当处理多线程应用程序,特别是web服务时,跟踪事件可能会变得困难。当针对多个同时存在的多个用户生成日志记录时,你如何区分哪个行为和哪个日志事件有关呢?如何两个用户没有成功打开一个相同的文件,或者在同一时间没有成功登陆,那么怎么处理日志记录?你可能需要一种方式来将日志记录和程序中的标示符关联起来,这些标识符可能是用户ID,会话ID或者设备ID。而这是NDC、MDC以及ThreadContext的用武之地。
  NDC、MDC和ThreadContext通过向单独的日志记录中添加的数据戳,来创建日志足迹(log trails)。这些数据戳也被称为鱼标记(fish tagging),我们可以通过一个或者多个的值来区分日志。这些数据戳在每个线程级别上进行管理,并且一直持续到线程结束,或者直到数据戳被删掉。例如,如果你的Web应用程序为每个用户生成一个新的线程,那么你可以使用这个用户的ID来标记日志记录。当你想在一个复杂的系统中跟踪特定的请求、事务或者用户,这是一种非常有用的方法。
  嵌套诊断上下文(NDC)
  NDC或者嵌套诊断上下文(Nested Diagnostic Context)是基于栈的思想,信息可以被放到栈上或者从栈中移除。而栈中的值可以被Logger访问,并且Logger无需显示想日志方法中传入任何值。
  下面的代码示例使用NDC和Log4j来将用户姓名和一条日志记录关联起来。NDC是一个静态类,因此我们可以直接访问它的方法,而无需实例化一个NDC对象。在这个示例中, NDC.oush(username) 和 NDC.push(sessionID) 方法在栈中存储了当前的用户名(admin)和会话ID(1234),而NDC.pop()方法将一些项从栈中移除,NDC.remove()方法让Java回收内存,以免造成内存溢出。

  import java.io.FileReader;
  import org.apache.Log4j.Logger;
  import org.apache.Log4j.NDC;
  ...
  String username = "admin";
  String sessionID = "1234";
  NDC.push(username);
  NDC.push(sessionID);
  try {
  // tmpFile doesn't exist, causing an exception.
  FileReader fr = new FileReader("tmpFile");
  }
  catch (Exception ex) {
  logger.error("Unable to open file.");
  }
  finally {
  NDC.pop();
  NDC.pop();
  NDC.remove();
  }
  Log4j的PatternLayout类通过%x转换字符从NDC中提取值。如果一个日志事件被触发,那么完整的NDC栈被传到Log4j:
  <PatternLayout pattern="%x %-5p - %m%n" />
  运行程序后,我们可以得出下面的输出:
  "admin 1234 ERROR – Unable to open file."
  映射诊断上下文(MDC)
  MDC或者映射诊断上下文和NDC很相似,不同之处在于MDC将值存储在键值对中,而不是栈中。这样你可以很容易的在Layout中引用一个单独的键。MDC.put(key,value) 方法将一个新的键值对添加到上下文中,而 MDC.remove(key) 方法会移除指定的键值对。
  如果想在日志中同样显示用户名和会话ID,我们需要使用 MDC.put() 方法将这两个变量存储成键值对:
  import java.io.FileReader;
  import org.apache.Log4j.Logger;
  import org.apache.Log4j.MDC;
  ...
  MDC.put("username", "admin");
  MDC.put("sessionID", "1234");
  try {
  // tmpFile doesn't exist, causing an exception.
  FileReader fr = new FileReader("tmpFile");
  }
  catch (Exception ex) {
  logger.error("Unable to open file!");
  }
  finally {
  MDC.clear();
  }
  这里再一次强调,在不需要使用Context后,我们需要使用 MDC.clear() 方法将所有的键值对从MDC中移除,这样会降低内存的使用量,并阻止MDC在后面试图调用那些已经过期的数据。
  在日志框架中访问MDC的值时,也稍微有些区别。对于存储在上下文中的任何键,我们可以使用%X(键)的方式来访问对应的值。这样,我们可以使用 %X(username) 和 %X(sessionID) 来获取对应的用户名和会话ID:
  <PatternLayout pattern="%X{username} %X{sessionID} %-5p - %m%n" />
  "admin 1234 ERROR – Unable to open file!"
  如果我们没有指定任何键,那么MDC上下文会被以 {(key, value),(key, value)} 的方式传递给Appender。
  Logback中的NDC和MDC
  和Log4j不同,Logback内置没有实现NDC。但是slf4j-ext包提供了一个NDC实现,它使用MDC作为基础。在Logback内部,你可以使用 MDC.put()、MDC.remove() 和 MDC.clear() 方法来访问和管理MDC:
  import org.slf4j.MDC;
  ...
  Logger logger = LoggerFactory.getLogger(MDCLogback.class);
  ...
  MDC.put("username", "admin");
  MDC.put("sessionID", "1234");
  try {
  FileReader fr = new FileReader("tmpFile");
  }
  catch (Exception ex) {
  logger.error("Unable to open file.");
  }
  finally {
  MDC.clear();
  }
  在Logback中,你可以在Logback.xml中将如下模式应用到Appender上,它可以输出和上面Log4j相同的结果:
  <Pattern>[%X{username}] %X{sessionID} %-5p - %m%n</Pattern>
  "[admin] 1234 ERROR - Unable to open file."
  针对MDC的访问并不仅制在PatternLayout上,例如,当使用JSONFormatter时,MDC中的所有值都会被导出:
  {
  "timestamp":"1431970324945",
  "level":"ERROR",
  "thread":"main",
  "mdc":{
  "username":"admin",
  "sessionID":"1234"
  },
  "logger":"MyClass",
  "message":"Unable to open file.",
  "context":"default"
  }
  ThreadContext
  Version 2 of Log4j merged MDC and NDC into a single concept known as the Thread Context. The Thread Context is an evolution of MDC and NDC, presenting them respectively as the Thread Context Map and Thread Context Stack. The Thread Context is managed through the static ThreadContext class, which is implemented similar to Log4j 1’s MDC and NDC classes.