log4j MDC NDC详解
NDC ( Nested Diagnostic Context )和 MDC ( Mapped Diagnostic Context )是 log4j 种非常有用的两个类,它们用于存储应用程序的上下文信息( context infomation ),从而便于在 log 中使用这些上下文信息。
NDC的实现是用hashtable来存储每个线程的stack信息,这个stack是每个线程可以设置当前线程的request的相关信息,然后当前线 程在处理过程中只要在log4j配置打印出%x的信息,那么当前线程的整个stack信息就会在log4j打印日志的时候也会都打印出来,这样可以很好的 跟踪当前request的用户行为功能。
MDC的实现是使用threadlocal来保存每个线程的Hashtable的类似map的信息,其他功能类似。
性能
在记录一些日志信息时,会一定程度地影响系统的运行效率,这时日志工具是否高效就是一个关键。Log4J的首要设计目标就是高效,一些关键组件都重写过很多次以不断提高性能。根据Log4J项目小组的报告,在AMD Duron 800MHz + JDK1.3.1的环境下,Log4J判断一条日志语句是否需要输出仅需要5纳秒。实际的日志语句执行的也非常快速,从使用SimpleLayout的21微秒(几乎与System.out.println一样快),到使用TTCCLayout的37微秒不等。
NDC的实现代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
public class NDC {
static Hashtable ht = new Hashtable();
private static Stack getCurrentStack() {
if (ht != null ) {
return (Stack) ht.get(Thread.currentThread());
}
return null ;
}
public static String pop() {
Stack stack = getCurrentStack();
if (stack != null && !stack.isEmpty())
return ((DiagnosticContext) stack.pop()).message;
else return "" ;
}
public static String peek() {
Stack stack = getCurrentStack();
if (stack != null && !stack.isEmpty())
return ((DiagnosticContext) stack.peek()).message;
else return "" ;
}
public static void push(String message) {
Stack stack = getCurrentStack();
if (stack == null ) {
DiagnosticContext dc = new DiagnosticContext(message, null );
stack = new Stack();
Thread key = Thread.currentThread();
ht.put(key, stack);
stack.push(dc);
} else if (stack.isEmpty()) {
DiagnosticContext dc = new DiagnosticContext(message, null );
stack.push(dc);
} else {
DiagnosticContext parent = (DiagnosticContext) stack.peek();
stack.push( new DiagnosticContext(message, parent));
}
}
|
MDC的实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
public class MDC {
final static MDC mdc = new MDC();
static final int HT_SIZE = 7 ;
boolean java1;
Object tlm;
private Method removeMethod;
private MDC() {
java1 = Loader.isJava1();
if (!java1) {
tlm = new ThreadLocalMap();
}
try {
removeMethod = ThreadLocal. class .getMethod( "remove" , null );
} catch (NoSuchMethodException e) {
// don't do anything - java prior 1.5
}
}
*/
static public void put(String key, Object o) {
if (mdc != null ) {
mdc.put0(key, o);
}
}
static public Object get(String key) {
if (mdc != null ) {
return mdc.get0(key);
}
return null ;
}
static public void remove(String key) {
if (mdc != null ) {
mdc.remove0(key);
}
}
public static Hashtable getContext() {
if (mdc != null ) {
return mdc.getContext0();
} else {
return null ;
}
}
public static void clear() {
if (mdc != null ) {
mdc.clear0();
}
}
private void put0(String key, Object o) {
if (java1 || tlm == null ) {
return ;
} else {
Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
if (ht == null ) {
ht = new Hashtable(HT_SIZE);
((ThreadLocalMap)tlm).set(ht);
}
ht.put(key, o);
}
}
private Object get0(String key) {
if (java1 || tlm == null ) {
return null ;
} else {
Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
if (ht != null && key != null ) {
return ht.get(key);
} else {
return null ;
}
}
}
private void remove0(String key) {
if (!java1 && tlm != null ) {
Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
if (ht != null ) {
ht.remove(key);
// clean up if this was the last key
if (ht.isEmpty()) {
clear0();
}
}
}
}
private Hashtable getContext0() {
if (java1 || tlm == null ) {
return null ;
} else {
return (Hashtable) ((ThreadLocalMap)tlm).get();
}
}
private void clear0() {
if (!java1 && tlm != null ) {
Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
if (ht != null ) {
ht.clear();
}
if (removeMethod != null ) {
// java 1.3/1.4 does not have remove - will suffer from a memory leak
try {
removeMethod.invoke(tlm, null );
} catch (IllegalAccessException e) {
// should not happen
} catch (InvocationTargetException e) {
// should not happen
}
}
}
}
} |
日志信息代表的含义:
1
2
3
4
5
6
7
8
9
10
11
12
|
%p: 输出日志信息优先级,即DEBUG,INFO,WARN,ERROR,FATAL, %d: 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921 %r: 输出自应用启动到输出该log信息耗费的毫秒数 %c: 输出日志信息所属的类目,通常就是所在类的全名 %t: 输出产生该日志事件的线程名 %l: 输出日志事件的发生位置,相当于%C.%M(%F:%L)的组合,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main (TestLog4.java:10) %x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像Java servlets这样的多客户多线程的应用中。 %%: 输出一个”%”字符 %F: 输出日志消息产生时所在的文件名称 %L: 输出代码中的行号 %m: 输出代码中指定的消息,产生的日志具体信息 %n: 输出一个回车换行符,Windows平台为”\r\n”,Unix平台为”\n”输出日志信息换行 |
log4j MDC NDC详解的更多相关文章
- commons-logging和Log4j 日志管理/log4j.properties配置详解
commons-logging和Log4j 日志管理 (zz) 什么要用日志(Log)? 这个……就不必说了吧. 为什么不用System.out.println()? 功能太弱:不易于控制.如果暂时不 ...
- Hibernate4搭建Log4J日志管理(附Log4j.properties配置详解)
1.首先加入slf4j的jar包,即slf4j-api-1.6.1.jar 在hibernate官网下载hibernate-release-4.2.2.Final.zip并解压,在hibernate- ...
- Spark log4j日志配置详解(转载)
一.spark job日志介绍 spark中提供了log4j的方式记录日志.可以在$SPARK_HOME/conf/下,将 log4j.properties.template 文件copy为 l ...
- log4j.properties配置详解与实例
log4j.properties配置详解与实例 第一步:加入log4j-1.x.x.jar到lib下. 第二步:在工程的src下下建立log4j.properties.内容如下: #OFF,syste ...
- Log4j介绍,log4j.properties配置详解
http://www.cnblogs.com/simle/archive/2011/09/29/2195341.html本文主要解释log4j的配置文件各个配置项的含义,内容是从网上转载的 1.Log ...
- slf4j log4j logback关系详解和相关用法
slf4j log4j logback关系详解和相关用法 写java也有一段时间了,一直都有用slf4j log4j输出日志的习惯.但是始终都是抱着"拿来主义"的态度,复制粘贴下配 ...
- 项目log4j日志管理详解
项目log4j日志管理详解 log4j日志系统在项目中重要性在这里就不再累述,我们在平时使用时如果没有特定要求,只需在log4j.properties文件中顶入输出级别就行了.如果要自定义输出文件,对 ...
- log4j.properties配置详解
1.Loggers Loggers组件在此系统中被分为五个级别:DEBUG.INFO.WARN.ERROR和FATAL.这五个级别是有顺序的,DEBUG < INFO < WARN < ...
- Log4J日志配置详解
一.Log4j简介 Log4j有三个主要的组件:Loggers(记录器),Appenders (输出源)和Layouts(布局).这里可简单理解为日志类别,日志要输出的地方和日志以何种形式输出.综合使 ...
随机推荐
- selenium.webdriver元素定位失败
错误提示: Traceback (most recent call last): File "E:/PythonData/Login/venv/logIn.py", line 18 ...
- 怎样用scratch2.0谱写音乐
打开scratch2.0将语言切换为简体中文: 如果需要播放特殊的声音,可以用播放声音,找到一些特有的音乐,或者通过录制,将自己的配音或者唱歌录制下来: 可以用弹奏鼓声命令弹奏各种击鼓音乐: 通过控制 ...
- Windows 手动安装 Apache24 web服务器
文章更新于:2020-02-18 按照惯例,需要的文件附上链接放在文首 文件名:httpd-2.4.41-o111c-x64-vc15-r2.7z 文件大小:6.1MB 下载链接:https://ww ...
- 09-soap接口类型进行测试webservice协议
webxml.com.cn/zh_cn/weather_icon.aspx webxml.com.cn/webservices/weatherWS.asmx? 以上2个url可用来免费使用(经典场景) ...
- vueThink框架搭建与填坑(new)
自己跟着官网搭建vueThink框架,发现github上文档有很多坑.所以总结一下(仅针对WIN端下载使用) 1.安装node.js 前端部分是基于node.js上运行的,所以必须先安装node.js ...
- 数组的连接和截取(contact和slice和splice)
<script> var arr1 = ["a","b","c"]; var arr2 = [1,2,3]; //concat把 ...
- while和do-while
1. While(条件表达式){ 只要条件表达式结果为true,循环一直执行,当条件表达式结果为false的时候,循环终止 } 2. Do{ 循环体代码:首先执行该循环体代码一次.如果while后边的 ...
- 如何练习python?有这五个游戏,实操经验就已经够了
现在学习python的人越来越多了,但仅仅只是学习理论怎么够呢,如何练习python?已经是python初学者比较要学会的技巧了! 其实,最好的实操练习,就是玩游戏. 也许你不会信,但这五个小游戏足够 ...
- numpy basic sheatsheet
NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库.NumPy 通常与 SciPy(Scien ...
- django 分页器 Paginator 基础操作
基于下面这个分页器,说明常用的属性 from django.core.paginator import Paginator #导入Paginator类 from sign.models import ...