com.taobao.arthas.grpcweb.grpc.service.ObjectService Maven / Gradle / Ivy
package com.taobao.arthas.grpcweb.grpc.service;
import java.lang.instrument.Instrumentation;
import java.lang.invoke.MethodHandles;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import com.taobao.arthas.core.command.express.Express;
import com.taobao.arthas.core.command.express.ExpressException;
import com.taobao.arthas.core.command.express.ExpressFactory;
import com.taobao.arthas.core.util.Constants;
import com.taobao.arthas.grpcweb.grpc.objectUtils.JavaObjectConverter;
import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.taobao.arthas.common.VmToolUtils;
import arthas.VmTool;
import com.taobao.arthas.grpcweb.grpc.observer.ArthasStreamObserver;
import com.taobao.arthas.grpcweb.grpc.observer.impl.ArthasStreamObserverImpl;
import io.grpc.Status;
import io.grpc.stub.StreamObserver;
import io.arthas.api.ObjectServiceGrpc.ObjectServiceImplBase;
import io.arthas.api.ArthasServices.JavaObject;
import io.arthas.api.ArthasServices.ObjectQuery;
import io.arthas.api.ArthasServices.ObjectQueryResult;
import io.arthas.api.ArthasServices.ObjectQueryResult.Builder;
public class ObjectService extends ObjectServiceImplBase {
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass().getName());
private VmTool vmTool;
private Instrumentation inst;
private GrpcJobController grpcJobController;
public ObjectService(GrpcJobController grpcJobController, String libDir) {
this.inst = grpcJobController.getInstrumentation();
this.grpcJobController = grpcJobController;
try {
String detectLibName = VmToolUtils.detectLibName();
String vmToolLibPath = Paths.get(libDir, detectLibName).toString();
vmTool = VmTool.getInstance(vmToolLibPath);
} catch (Throwable e) {
logger.error("init vmtool error", e);
}
}
@Override
public void query(ObjectQuery query, StreamObserver responseObserver) {
if (vmTool == null) {
throw Status.UNAVAILABLE.withDescription("vmtool can not work").asRuntimeException();
}
ArthasStreamObserver arthasStreamObserver = new ArthasStreamObserverImpl<>(responseObserver, null,grpcJobController);
String className = query.getClassName();
String classLoaderHash = query.getClassLoaderHash();
String classLoaderClass = query.getClassLoaderClass();
int limit = query.getLimit();
int depth = query.getDepth();
String express = query.getExpress();
String resultExpress = query.getResultExpress();
// 如果只传递了 class name 参数,则jvm 里可能有多个同名的 class,需要全部查找
if (isEmpty(classLoaderHash) && isEmpty(classLoaderClass)) {
List> foundClassList = new ArrayList<>();
for (Class> clazz : inst.getAllLoadedClasses()) {
if (clazz.getName().equals(className)) {
foundClassList.add(clazz);
}
}
// 没找到
if (foundClassList.size() == 0) {
arthasStreamObserver.onNext(ObjectQueryResult.newBuilder().setSuccess(false)
.setMessage("can not find class: " + className).build());
arthasStreamObserver.onCompleted();
return;
} else if (foundClassList.size() > 1) {
String message = "found more than one class: " + className;
arthasStreamObserver.onNext(ObjectQueryResult.newBuilder().setSuccess(false).setMessage(message).build());
arthasStreamObserver.onCompleted();
return;
} else { // 找到了指定的 类
Object[] instances = vmTool.getInstances(foundClassList.get(0), limit);
Builder builder = ObjectQueryResult.newBuilder().setSuccess(true);
/**
* 这里尝试使用express
*/
Object value = null;
if (!isEmpty(express)) {
Express unpooledExpress = ExpressFactory.unpooledExpress(foundClassList.get(0).getClassLoader());
try {
value = unpooledExpress.bind(new InstancesWrapper(instances)).get(express);
} catch (ExpressException e) {
logger.warn("ognl: failed execute express: " + express, e);
}
}
if(value != null && !isEmpty(resultExpress)){
try {
value = ExpressFactory.threadLocalExpress(value).bind(Constants.COST_VARIABLE, 0.0).get(resultExpress);
} catch (ExpressException e) {
logger.warn("ognl: failed execute result express: " + express, e);
}
}
JavaObject javaObject = JavaObjectConverter.toJavaObjectWithExpand(value, depth);
builder.addObjects(javaObject);
arthasStreamObserver.onNext(builder.build());
arthasStreamObserver.onCompleted();
return;
}
}
// 有指定 classloader hash 或者 classloader className
Class> foundClass = null;
for (Class> clazz : inst.getAllLoadedClasses()) {
if (!clazz.getName().equals(className)) {
continue;
}
ClassLoader classLoader = clazz.getClassLoader();
if (classLoader == null) {
continue;
}
if (!isEmpty(classLoaderHash)) {
String hex = Integer.toHexString(classLoader.hashCode());
if (classLoaderHash.equals(hex)) {
foundClass = clazz;
break;
}
}
if (!isEmpty(classLoaderClass) && classLoaderClass.equals(classLoader.getClass().getName())) {
foundClass = clazz;
break;
}
}
// 没找到类
if (foundClass == null) {
arthasStreamObserver.onNext(ObjectQueryResult.newBuilder().setSuccess(false)
.setMessage("can not find class: " + className).build());
arthasStreamObserver.onCompleted();
return;
}
Object[] instances = vmTool.getInstances(foundClass, limit);
Builder builder = ObjectQueryResult.newBuilder().setSuccess(true);
// for (Object obj : instances) {
// JavaObject javaObject = JavaObjectConverter.toJavaObjectWithExpand(obj, depth);
// builder.addObjects(javaObject);
// }
Object value = null;
if (!isEmpty(express)) {
Express unpooledExpress = ExpressFactory.unpooledExpress(foundClass.getClassLoader());
try {
value = unpooledExpress.bind(new InstancesWrapper(instances)).get(express);
} catch (ExpressException e) {
logger.warn("ognl: failed execute express: " + express, e);
}
}
if(value != null && !isEmpty(resultExpress)){
try {
value = ExpressFactory.threadLocalExpress(value).bind(Constants.COST_VARIABLE, 0.0).get(resultExpress);
} catch (ExpressException e) {
logger.warn("ognl: failed execute result express: " + express, e);
}
}
JavaObject javaObject = JavaObjectConverter.toJavaObjectWithExpand(value, depth);
builder.addObjects(javaObject);
arthasStreamObserver.onNext(builder.build());
arthasStreamObserver.onCompleted();
}
public static boolean isEmpty(Object str) {
return str == null || "".equals(str);
}
static class InstancesWrapper {
Object instances;
public InstancesWrapper(Object instances) {
this.instances = instances;
}
public Object getInstances() {
return instances;
}
public void setInstances(Object instances) {
this.instances = instances;
}
}
}