-
Notifications
You must be signed in to change notification settings - Fork 7.6k
表达式支持使用qlexpress4.0 #2978
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
taokan
wants to merge
44
commits into
alibaba:master
Choose a base branch
from
taokan:qlexpress
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
表达式支持使用qlexpress4.0 #2978
Changes from all commits
Commits
Show all changes
44 commits
Select commit
Hold shift + click to select a range
b126872
[support qlexpress]
taokan 2b88739
Merge branch 'master' of https://github.com/taokan/arthas
taokan 30fe689
【支持qlexpress表达式】
taokan efebecd
【支持qlexpress表达式】
taokan b1a0379
【支持qlexpress表达式】
taokan a878dc6
【支持qlexpress表达式】
taokan c780218
【支持qlexpress表达式】
taokan a54ac65
【支持qlexpress表达式】
taokan cbdf590
【支持qlexpress表达式】
taokan ec0f951
【支持qlexpress表达式】
taokan 2dab795
【支持qlexpress表达式】
taokan 44fde5c
【支持qlexpress表达式】
taokan aebe302
【支持qlexpress表达式】
taokan 7d73a17
【支持qlexpress表达式】
taokan 49d9397
【支持qlexpress表达式】
taokan 87b71d0
【支持qlexpress表达式】
taokan 35899a8
【支持qlexpress表达式】
taokan 5a77e93
【支持qlexpress表达式】yarn revert
taokan adb0257
【支持qlexpress表达式】pom版本升级
taokan 4f3a518
【支持qlexpress表达式】冲突
taokan 564c11a
【支持qlexpress表达式】冲突
taokan 23c3df1
【支持qlexpress表达式】冲突
taokan 74a84f8
【支持qlexpress表达式】冲突
taokan 92cff37
【支持qlexpress表达式】冲突
taokan 63c648c
【支持qlexpress表达式】冲突
taokan dac03f5
【支持qlexpress表达式】冲突
taokan 99f4850
【支持qlexpress表达式】冲突
taokan 0de1a3f
Merge branch 'qlexpress' into qlexpress20240112
taokan ded1ca5
【支持qlexpress表达式】文档
taokan 6dfe5fa
【支持qlexpress表达式】文档
taokan 4bb7b1e
【支持qlexpress表达式】刪除未引用代码
taokan cd4ce45
【支持qlexpress表达式】刪除未引用代码
taokan df33bba
【支持qlexpress表达式】刪除未引用代码
taokan cf8a6ee
【增加gl命令】command命令
taokan 4bc09fb
【增加qlexpress命令】command命令
taokan 28d99d4
Merge branch 'master' of https://github.com/taokan/arthas
taokan 5a8a935
Merge branch 'master' into qlexpress
taokan b9f8f56
【qlexpress版本】4.0.0
taokan 8001cf1
【qlexpress版本】4.0.0
taokan 15e0ffd
【qlexpress版本】4.0.0
taokan 993e4e9
qlexpress version 4.0.3
DQinYuan 7c390e6
Update site/docs/doc/options.md
DQinYuan 17ceb67
【qlexpress版本】4.0.0
taokan e11628f
【qlexpress版本】4.0.0
taokan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
core/src/main/java/com/taobao/arthas/core/command/basic1000/QLExpressCommand.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package com.taobao.arthas.core.command.basic1000; | ||
|
||
import com.alibaba.arthas.deps.org.slf4j.Logger; | ||
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; | ||
import com.taobao.arthas.core.command.Constants; | ||
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.command.model.ClassLoaderVO; | ||
import com.taobao.arthas.core.command.model.ObjectVO; | ||
import com.taobao.arthas.core.command.model.QLExpressModel; | ||
import com.taobao.arthas.core.shell.command.AnnotatedCommand; | ||
import com.taobao.arthas.core.shell.command.CommandProcess; | ||
import com.taobao.arthas.core.util.ClassLoaderUtils; | ||
import com.taobao.arthas.core.util.ClassUtils; | ||
import com.taobao.middleware.cli.annotations.*; | ||
|
||
import java.lang.instrument.Instrumentation; | ||
import java.util.Collection; | ||
import java.util.List; | ||
|
||
/** | ||
* @Author TaoKan | ||
* @Date 2025/3/23 8:59 PM | ||
*/ | ||
@Name("qlexpress") | ||
@Summary("Execute qlexpress expression.") | ||
@Description(Constants.EXAMPLE | ||
+ " qlexpress 'java.lang.System.out.println(\"hello~\")' \n" | ||
+ " qlexpress -x 2 'java.lang.Math.abs(1)' \n" | ||
+ " qlexpress -c 5d113a51 'com.taobao.arthas.core.GlobalOptions.isDump' \n" | ||
+ Constants.WIKI + Constants.WIKI_HOME + "qlexpress\n" | ||
+ " https://github.com/alibaba/QLExpress/tree/v4.0.0-beta.1") | ||
public class QLExpressCommand extends AnnotatedCommand { | ||
private static final Logger logger = LoggerFactory.getLogger(QLExpressCommand.class); | ||
|
||
private String express; | ||
private String hashCode; | ||
private String classLoaderClass; | ||
private int expand = 1; | ||
|
||
@Argument(argName = "express", index = 0, required = true) | ||
@Description("The qlexpress expression.") | ||
public void setExpress(String express) { | ||
this.express = express; | ||
} | ||
|
||
@Option(shortName = "c", longName = "classLoader") | ||
@Description("The hash code of the special class's classLoader, default classLoader is SystemClassLoader.") | ||
public void setHashCode(String hashCode) { | ||
this.hashCode = hashCode; | ||
} | ||
|
||
|
||
@Option(longName = "classLoaderClass") | ||
@Description("The class name of the special class's classLoader.") | ||
public void setClassLoaderClass(String classLoaderClass) { | ||
this.classLoaderClass = classLoaderClass; | ||
} | ||
|
||
|
||
@Option(shortName = "x", longName = "expand") | ||
@Description("Expand level of object (1 by default).") | ||
public void setExpand(Integer expand) { | ||
this.expand = expand; | ||
} | ||
@Override | ||
public void process(CommandProcess process) { | ||
Instrumentation inst = process.session().getInstrumentation(); | ||
ClassLoader classLoader = null; | ||
if (hashCode != null) { | ||
classLoader = ClassLoaderUtils.getClassLoader(inst, hashCode); | ||
if (classLoader == null) { | ||
process.end(-1, "Can not find classloader with hashCode: " + hashCode + "."); | ||
return; | ||
} | ||
} else if (classLoaderClass != null) { | ||
List<ClassLoader> matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst, classLoaderClass); | ||
if (matchedClassLoaders.size() == 1) { | ||
classLoader = matchedClassLoaders.get(0); | ||
} else if (matchedClassLoaders.size() > 1) { | ||
Collection<ClassLoaderVO> classLoaderVOList = ClassUtils.createClassLoaderVOList(matchedClassLoaders); | ||
QLExpressModel qlModel = new QLExpressModel() | ||
.setClassLoaderClass(classLoaderClass) | ||
.setMatchedClassLoaders(classLoaderVOList); | ||
process.appendResult(qlModel); | ||
process.end(-1, "Found more than one classloader by class name, please specify classloader with '-c <classloader hash>'"); | ||
return; | ||
} else { | ||
process.end(-1, "Can not find classloader by class name: " + classLoaderClass + "."); | ||
return; | ||
} | ||
} else { | ||
classLoader = ClassLoader.getSystemClassLoader(); | ||
} | ||
|
||
Express unpooledExpress = ExpressFactory.unpooledExpressByQL(classLoader); | ||
try { | ||
Object value = unpooledExpress.bind(new Object()).get(express); | ||
QLExpressModel qlModel = new QLExpressModel() | ||
.setValue(new ObjectVO(value, expand)); | ||
process.appendResult(qlModel); | ||
process.end(); | ||
} catch (ExpressException e) { | ||
logger.warn("qlexpress: failed execute express: " + express, e); | ||
process.end(-1, "Failed to execute qlexpress, exception message: " + e.getMessage() | ||
+ ", please check $HOME/logs/arthas/arthas.log for more details. "); | ||
} | ||
} | ||
} |
33 changes: 27 additions & 6 deletions
33
core/src/main/java/com/taobao/arthas/core/command/express/ExpressFactory.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
78 changes: 78 additions & 0 deletions
78
core/src/main/java/com/taobao/arthas/core/command/express/QLExpress.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package com.taobao.arthas.core.command.express; | ||
|
||
import com.alibaba.arthas.deps.org.slf4j.Logger; | ||
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; | ||
import com.alibaba.qlexpress4.*; | ||
import com.alibaba.qlexpress4.security.QLSecurityStrategy; | ||
|
||
|
||
/** | ||
* @Author TaoKan | ||
* @Date 2024/9/17 6:01 PM | ||
*/ | ||
public class QLExpress implements Express { | ||
private static final Logger logger = LoggerFactory.getLogger(QLExpress.class); | ||
private Express4Runner expressRunner; | ||
private QLGlobalContext qlGlobalContext; | ||
|
||
private QLOptions qlOptions; | ||
|
||
private InitOptions initOptions; | ||
|
||
public QLExpress() { | ||
this(QLExpressCustomClassResolver.customClassResolver); | ||
} | ||
|
||
public QLExpress(ClassSupplier classResolver) { | ||
this.initOptions = initQLExpress(classResolver); | ||
this.expressRunner = QLExpressRunner.getInstance(initOptions); | ||
this.qlOptions = initConfig(); | ||
this.qlGlobalContext = new QLGlobalContext(expressRunner); | ||
} | ||
|
||
private QLOptions initConfig() { | ||
return QLOptions.DEFAULT_OPTIONS; | ||
} | ||
|
||
private InitOptions initQLExpress(ClassSupplier classResolver) { | ||
InitOptions.Builder initOptionsBuilder = InitOptions.builder(); | ||
initOptionsBuilder.securityStrategy(QLSecurityStrategy.open()); | ||
initOptionsBuilder.allowPrivateAccess(true); | ||
initOptionsBuilder.classSupplier(classResolver); | ||
return initOptionsBuilder.build(); | ||
} | ||
|
||
@Override | ||
public Object get(String express) throws ExpressException { | ||
try { | ||
return expressRunner.execute(express, qlGlobalContext, qlOptions).getResult(); | ||
} catch (Exception e) { | ||
logger.error("Error during evaluating the expression with QLExpress:", e); | ||
throw new ExpressException(express, e); | ||
} | ||
} | ||
|
||
@Override | ||
public boolean is(String express) throws ExpressException { | ||
final Object ret = get(express); | ||
return ret instanceof Boolean && (Boolean) ret; | ||
} | ||
|
||
@Override | ||
public Express bind(Object object) { | ||
qlGlobalContext.bindObj(object); | ||
return this; | ||
} | ||
|
||
@Override | ||
public Express bind(String name, Object value) { | ||
qlGlobalContext.put(name, value); | ||
return this; | ||
} | ||
|
||
@Override | ||
public Express reset() { | ||
qlGlobalContext.clear(); | ||
return this; | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
...c/main/java/com/taobao/arthas/core/command/express/QLExpressClassLoaderClassResolver.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package com.taobao.arthas.core.command.express; | ||
|
||
import com.alibaba.qlexpress4.ClassSupplier; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
|
||
/** | ||
* @Author TaoKan | ||
* @Date 2024/12/1 7:07 PM | ||
*/ | ||
public class QLExpressClassLoaderClassResolver implements ClassSupplier { | ||
|
||
private ClassLoader classLoader; | ||
|
||
private final Map<String, Optional<Class<?>>> cache = new ConcurrentHashMap<>(); | ||
|
||
public QLExpressClassLoaderClassResolver(ClassLoader classLoader) { | ||
this.classLoader = classLoader; | ||
} | ||
|
||
private Optional<Class<?>> loadClsInner(String clsQualifiedName) { | ||
try { | ||
Class<?> aClass = null; | ||
if (classLoader != null) { | ||
aClass = classLoader.loadClass(clsQualifiedName); | ||
}else { | ||
aClass = Class.forName(clsQualifiedName); | ||
} | ||
return Optional.of(aClass); | ||
} catch (ClassNotFoundException | NoClassDefFoundError e) { | ||
return Optional.empty(); | ||
} | ||
} | ||
@Override | ||
public Class<?> loadCls(String className) { | ||
Optional<Class<?>> clsOp = cache.computeIfAbsent(className, this::loadClsInner); | ||
return clsOp.orElse(null); | ||
} | ||
} |
44 changes: 44 additions & 0 deletions
44
core/src/main/java/com/taobao/arthas/core/command/express/QLExpressCustomClassResolver.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package com.taobao.arthas.core.command.express; | ||
|
||
import com.alibaba.arthas.deps.org.slf4j.Logger; | ||
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; | ||
import com.alibaba.qlexpress4.ClassSupplier; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
|
||
/** | ||
* @Author TaoKan | ||
* @Date 2024/12/1 7:06 PM | ||
*/ | ||
public class QLExpressCustomClassResolver implements ClassSupplier { | ||
|
||
public static final QLExpressCustomClassResolver customClassResolver = new QLExpressCustomClassResolver(); | ||
|
||
private final Map<String, Optional<Class<?>>> cache = new ConcurrentHashMap<>(); | ||
|
||
private QLExpressCustomClassResolver() { | ||
|
||
} | ||
|
||
private Optional<Class<?>> loadClsInner(String clsQualifiedName) { | ||
try { | ||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); | ||
Class<?> aClass = null; | ||
if (classLoader != null) { | ||
aClass = classLoader.loadClass(clsQualifiedName); | ||
} else { | ||
aClass = Class.forName(clsQualifiedName); | ||
} | ||
return Optional.of(aClass); | ||
} catch (ClassNotFoundException | NoClassDefFoundError e) { | ||
return Optional.empty(); | ||
} | ||
} | ||
@Override | ||
public Class<?> loadCls(String clsQualifiedName) { | ||
Optional<Class<?>> clsOp = cache.computeIfAbsent(clsQualifiedName, this::loadClsInner); | ||
return clsOp.orElse(null); | ||
} | ||
|
||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
个人觉得在 put 的时候加上 "#" 前缀,要比 get 的时候 replace 要好。这样 context 的逻辑更加简单纯粹。replace 可能会导致改变不该改变的字符。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok