在debug hadoop的问题的时候,经常需要临时打开hadoop的debug日志,可以通过更改环境变量:
1
|
export
HADOOP_ROOT_LOGGER=DEBUG,console
|
来开启debug log,这几天在看hadoop shell的时候发现有daemonlog这个参数,可以临时获取或更改当前日志基本,是通过org.apache.hadoop.log.LogLevel的main方法来实现的,比如操作datanode的日志级别:
1
2
|
hadoop daemonlog -getlevel 127.0.0.1:50070 datanode
hadoop daemonlog -setlevel 127.0.0.1:50070 datanode DEBUG
//level
的设置必须是大写的
|
来看下org.apache.hadoop.log.LogLevel的具体实现:
main方法在开始会解析输入的参数,并生成一个url,调用process方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public static void main(String[] args) {
if
(args. length == 3 &&
"-getlevel"
.equals(args[0])) {
process(
"http://"
+ args[1] +
"/logLevel?log="
+ args[2]);
return
;
}
else
if
(args.length == 4 &&
"-setlevel"
.equals(args[0])) {
process(
"http://"
+ args[1] +
"/logLevel?log="
+ args[2]
+
"&level="
+ args[3]);
//
由process实现
return
;
}
System.err.println( USAGES);
System.
exit
(-1);
}
|
调用process方法,建立到url的连接,并获取读取数据:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
private static void process(String urlstring) {
try {
URL url = new URL(urlstring);
System.out.println(
"Connecting to "
+ url);
URLConnection connection = url.openConnection();
connection.connect();
BufferedReader
in
= new BufferedReader(new InputStreamReader(
connection.getInputStream()));
for
(String line; (line =
in
.readLine()) != null; )
if
(line.startsWith(MARKER)) {
System.out.println(TAG.matcher(line).replaceAll(
""
));
}
in
.close();
} catch (IOException ioe) {
System.err.println(
""
+ ioe);
}
}
|
LogLevel其内部实现了一个扩展了HttpServlet 的Servlet,并重写了一个doGet方法来处理GET请求,如果是/logLevel?log=xxxx的url是获取日志级别,/logLevel?log=xxx&level=xxxx是设置日志级别:
Servlet类:
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
|
public
static
class
Servlet
extends
HttpServlet {
private
static
final
long
serialVersionUID = 1L;
public
void
doGet(HttpServletRequest request, HttpServletResponse response
)
throws
ServletException, IOException {
//doGet方法用来处理请求
// Do the authorization
if
(!HttpServer.hasAdministratorAccess(getServletContext (), request,
response)) {
return
;
}
PrintWriter out = ServletUtil.initHTML(response,
"Log Level"
);
//初始化响应的html头内容
String logName = ServletUtil.getParameter(request,
"log"
);
//从请求中获取log的设置
String level = ServletUtil.getParameter(request,
"level"
);
//从请求中获取level的设置
if
(logName !=
null
) {
out.println(
"<br /><hr /><h3>Results</h3>"
);
out.println( MARKER
+
"Submitted Log Name: <b>"
+ logName +
"</b><br />"
);
Log log = LogFactory.getLog(logName);
//根据日志名获取Log对象 org.apache.commons.logging.LogFactory org.apache.commons.logging.Log(Log是一个接口)
out.println( MARKER
+
"Log Class: <b>"
+ log.getClass().getName() +
"</b><br />"
);
if
(level !=
null
) {
out.println( MARKER +
"Submitted Level: <b>"
+ level +
"</b><br />"
);
}
if
(log
instanceof
Log4JLogger) {
//对不同的log类调用对用的process方法
process(((Log4JLogger)log).getLogger(), level, out);
}
else
if
(log
instanceof
Jdk14Logger ) {
process(((Jdk14Logger)log).getLogger(), level, out);
}
else
{
out.println(
"Sorry, "
+ log.getClass() +
" not supported.<br />"
);
}
}
out.println( FORMS);
out.println(ServletUtil.HTML_TAIL);
}
|
再来看对应的process方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
private
static
void
process(org.apache.log4j.Logger log, String level,
PrintWriter out)
throws
IOException {
//以常用的log4j为例
if
(level !=
null
) {
//如果请求中含有level=xxx
if
(!level.equals(org.apache.log4j.Level.toLevel(level).toString())) {
out.println( MARKER +
"Bad level : <b>"
+ level +
"</b><br />"
);
}
else
{
log.setLevel( org.apache.log4j.Level.toLevel(level));
//并且level为正确的值的话,直接调用对应Log实现类的setlevel设置log的级别
out.println( MARKER +
"Setting Level to "
+ level +
" ...<br />"
);
}
}
out.println( MARKER
+
"Effective level: <b>"
+ log.getEffectiveLevel() +
"</b><br />"
);
}
|
本文转自菜菜光 51CTO博客,原文链接:http://blog.51cto.com/caiguangguang/1592794,如需转载请自行联系原作者