slf4j 的MDC (附带主动获取方法堆栈)

[b]1. 主动获取方法调用链[/b]
本来是想能在打印日志时获取关键方法的调用链,比如Dao层是关键点,那能获取这个方法是被哪个Service调用,这个Service又是被哪个Controller调用,并且这些调用传递的参数分别是什么,这样对定位问题就很方便了。
初步设想是通过主动获取调用堆栈:
public static void test()
{
// 这个ex定义在哪里,打印出来的就是哪个方法被调用的堆栈
Throwable ex = new Throwable();

StackTraceElement[] stackElements = ex.getStackTrace();

if(stackElements != null)
{
System.out.println(stackElements.length);
for(int i = 0; i < stackElements.length; i++)
{
System.out.println(stackElements[i].getClassName());
System.out.println(stackElements[i].getFileName());
System.out.println(stackElements[i].getLineNumber());
System.out.println(stackElements[i].getMethodName());
}
}
}


在idea里直接run main,打印:

7
com.dd.domain.template.Template
Template.java
194
test
-----------------------------------
com.dd.domain.template.Template
Template.java
165
main
-----------------------------------
sun.reflect.NativeMethodAccessorImpl
NativeMethodAccessorImpl.java
-2
invoke0
-----------------------------------
sun.reflect.NativeMethodAccessorImpl
NativeMethodAccessorImpl.java
39
invoke
-----------------------------------
sun.reflect.DelegatingMethodAccessorImpl
DelegatingMethodAccessorImpl.java
25
invoke
-----------------------------------
java.lang.reflect.Method
Method.java
597
invoke
-----------------------------------
com.intellij.rt.execution.application.AppMain
AppMain.java
134
main
-----------------------------------


如果只是debug main, 则打印:
2
com.dd.domain.template.Template
Template.java
194
test
-----------------------------------
com.dd.domain.template.Template
Template.java
165
main
-----------------------------------

这也说明idea里debug和run时的启动类不一样。
[color=red]这种方式有两个问题:
1)能获取到这个堆栈,但不能获取到调用参数,
2)另外这个ex必须定义在“关键方法”里才能获取到方法调用链[/color]

[b]2. 使用slf4j的MDC为一个调用链设置唯一标识UUID[/b]
后来确定通过MDC来为一个调用流程设置一个唯一UUID,出现问题时返回这个UUID,搜索日志UUID,则可以获取一个业务调用流程所有的日志信息。

[b][color=red]但是要注意:[/color][/b]
1)这只能保证一个线程内的调用是同一个UUID,如果主线程里又启动了其他子线程,则子线程不会被跟踪。
2)MDC是通过web.xml的Filter来实现过滤页面请求,但这种也会拦截到对静态资源的请求,比如js,css等,根据需要做单独过滤,比如:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
// 排除.js,.css,.png等资源文件进入Filter。只拦截Controller请求,Controller请求url不带"."
if (((HttpServletRequest) request).getRequestURI().contains(".") || ROOT_URL.equals(((HttpServletRequest) request).getRequestURI()))
{
chain.doFilter(request, response);
return;
}

try
{
/*
* This code puts the value "UUID" to the Mapped Diagnostic context.
* Since MDc is a static class, we can directly access it without creating a new object from it.
* Here, instead of hard coding the user name, the value can be retrieved from a HTTP Request object.
*/
String uuid = UUID.randomUUID().toString();
MDC.put("requestUUID", uuid.replaceAll("-", "").toUpperCase());
chain.doFilter(request, response);
}
finally
{
MDC.remove("requestUUID");
}
}

具体操作详情可以参考:
[url]http://veerasundar.com/blog/2009/11/log4j-mdc-mapped-diagnostic-context-example-code/[/url]
[url]http://logback.qos.ch/manual/mdc.html[/url]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值