首先介绍功能:
官方在线demo地址:http://demo.skywalking.apache.org
我们可以在这里体验skywalking的功能:服务-普通服务-点击服务[songs]进入钻取面板-点击Trace Profiling,查看链路分析. –点击”分析”按钮,采集当前的栈信息
当线上发生故障,或者观测在线运行状况时,可以在此面板新建一个Trace Profiling任务,来进行采样,分析
本文我们主要关注栈信息是怎么获取的.
在我们日常排查问题时,会使用jstack查看线程栈详情. 而skywalking是如何获取的呢? 其实skywalking获取线程栈信息的方式与jstack在本质上是一样的. 他们都是native方法 dumpThreads来获取当前栈信息的.
在ProfileThread类中,会轮询profiler任务.当执行profiling任务时,会生成TracingThreadSnapshot 线程快照.
追踪源码可以找到 ThreadProfiler.buildSnapshot()中,通过prifilingThread(一个后台线程)对堆栈信息进行采样
为了了解Thread.getStackTrace的效果,我们可以执行如下代码
public class MainClazz {
public static void main(String[] args) {
methodA();
}
private static void methodA(){
System.out.println("方法A执行");
int a = 0;
methodB();
}
private static void methodB(){
System.out.println("方法B执行");
int b = 1;
StackTraceElement[] stackTraceElement = Thread.currentThread().getStackTrace();
System.out.println(stackTraceElement.length);
}
}
通过断点,查看栈帧
让我们追进Thread.getStackTrace方法,我们能够看到当前线程内的调用链路.相关代码如下:
知道了获取stack的手段, 那么如何在触发指定业务逻辑的时候,打印/记录堆栈信息呢?
结合skywalking中的处理细节,可以在增强类里 织入针对异常/特定业务code(比如后端返回400)的处理. 当出现需要追踪的异常时,获取当前堆栈的快照.
public class MainClazz {
public static void main(String[] args) {
try {
methodA();
} catch (Exception ex){
System.out.println("业务异常");
ProfileUtil.printStack(ex.getStackTrace());
}
methodA();
}
private static void methodA(){
System.out.println("方法A执行");
int a = 0;
methodB();
}
private static void methodB(){
System.out.println("方法B执行");
int b = 1;
int c = b * 0;
int d = b/c;
}
}
import java.util.ArrayList;
import java.util.Arrays;
public class ProfileUtil {
public static void printStack(StackTraceElement[] stackTrace){
if(stackTrace == null) return;
//把JVM给的堆栈倒序打印
for (int i = stackTrace.length -1; i >= 0; i--) {
System.out.println(buildStackElementCodeSignature(stackTrace[i]));
}
}
private static String buildStackElementCodeSignature(StackTraceElement element) {
return element.getClassName() + "." + element.getMethodName() + ":" + element.getLineNumber();
}
}