2022-07-15 22:37:32 +08:00
|
|
|
# groovy
|
2018-09-07 16:16:05 +08:00
|
|
|
|
2022-07-15 22:37:32 +08:00
|
|
|
::: tip
|
|
|
|
Arthas 支持 groovy 脚本增强,允许像 BTrace 一样编写脚本来解决问题,可以在 groovy 脚本中进行 if/for/switch/while 等控制语句,不受限制,但相比 BTrace 而言拥有更多的限制范围。
|
|
|
|
:::
|
2018-09-07 16:16:05 +08:00
|
|
|
|
|
|
|
### 限制内容
|
|
|
|
|
|
|
|
1. 禁止改变原有逻辑,与 watch 等命令一样,重点保证的是监听和观察。
|
|
|
|
1. 只允许在方法的 before/success/exception/finish 四个环节进行监听。
|
|
|
|
|
|
|
|
### 参数说明
|
|
|
|
|
2022-07-15 22:37:32 +08:00
|
|
|
| 参数名称 | 参数说明 |
|
|
|
|
| ----------------: | :----------------------------------- |
|
|
|
|
| _class-pattern_ | 类名表达式匹配 |
|
|
|
|
| _method-pattern_ | 方法名表达式匹配 |
|
|
|
|
| _script-filepath_ | groovy 脚本的绝对路径 |
|
|
|
|
| [S] | 匹配所有的子类 |
|
|
|
|
| [E] | 开启正则表达式匹配,默认为通配符匹配 |
|
2018-09-07 16:16:05 +08:00
|
|
|
|
2018-10-28 22:41:20 +08:00
|
|
|
需要说明的是,第三个输入参数是脚本的绝对路径,比如 `/tmp/test.groovy`,不建议输入相对路径,比如 `./test.groovy`
|
2022-07-15 22:37:32 +08:00
|
|
|
|
2018-09-07 16:16:05 +08:00
|
|
|
### 五个关键函数声明
|
|
|
|
|
|
|
|
```java
|
|
|
|
/**
|
|
|
|
* 增强脚本监听器
|
|
|
|
*/
|
|
|
|
interface ScriptListener {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 脚本创建
|
|
|
|
*
|
|
|
|
* @param output 输出器
|
|
|
|
*/
|
|
|
|
void create(Output output);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 脚本销毁
|
|
|
|
*
|
|
|
|
* @param output 输出器
|
|
|
|
*/
|
|
|
|
void destroy(Output output);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 方法执行前
|
|
|
|
*
|
|
|
|
* @param output 输出器
|
|
|
|
* @param advice 通知点
|
|
|
|
*/
|
|
|
|
void before(Output output, Advice advice);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 方法正常返回
|
|
|
|
*
|
|
|
|
* @param output 输出器
|
|
|
|
* @param advice 通知点
|
|
|
|
*/
|
|
|
|
void afterReturning(Output output, Advice advice);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 方法异常返回
|
|
|
|
*
|
|
|
|
* @param output 输出器
|
|
|
|
* @param advice 通知点
|
|
|
|
*/
|
|
|
|
void afterThrowing(Output output, Advice advice);
|
|
|
|
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### 参数 `Advice` 说明
|
|
|
|
|
2018-09-10 15:19:57 +08:00
|
|
|
`Advice` 参数最主要是封装了通知节点的所有信息。参考[表达式核心变量](advice-class.md)中关于该节点的描述。
|
2018-09-07 16:16:05 +08:00
|
|
|
|
|
|
|
### 参数 `Output` 说明
|
|
|
|
|
|
|
|
`Output` 参数只拥有三个方法,主要的工作还是输出对应的文本信息
|
|
|
|
|
|
|
|
```java
|
|
|
|
/**
|
|
|
|
* 输出器
|
|
|
|
*/
|
|
|
|
interface Output {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 输出字符串(不换行)
|
|
|
|
*
|
|
|
|
* @param string 待输出字符串
|
|
|
|
* @return this
|
|
|
|
*/
|
|
|
|
Output print(String string);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 输出字符串(换行)
|
|
|
|
*
|
|
|
|
* @param string 待输出字符串
|
|
|
|
* @return this
|
|
|
|
*/
|
|
|
|
Output println(String string);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 结束当前脚本
|
|
|
|
*
|
|
|
|
* @return this
|
|
|
|
*/
|
|
|
|
Output finish();
|
|
|
|
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### 一个输出日志的 groovy 脚本示例
|
|
|
|
|
|
|
|
```groovy
|
|
|
|
import com.taobao.arthas.core.command.ScriptSupportCommand
|
|
|
|
import com.taobao.arthas.core.util.Advice
|
|
|
|
|
|
|
|
import static java.lang.String.format
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 输出方法日志
|
|
|
|
*/
|
|
|
|
public class Logger implements ScriptSupportCommand.ScriptListener {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
void create(ScriptSupportCommand.Output output) {
|
|
|
|
output.println("script create.");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
void destroy(ScriptSupportCommand.Output output) {
|
|
|
|
output.println("script destroy.");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
void before(ScriptSupportCommand.Output output, Advice advice) {
|
|
|
|
output.println(format("before:class=%s;method=%s;paramslen=%d;%s;",
|
|
|
|
advice.getClazz().getSimpleName(),
|
|
|
|
advice.getMethod().getName(),
|
|
|
|
advice.getParams().length, advice.getParams()))
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
void afterReturning(ScriptSupportCommand.Output output, Advice advice) {
|
|
|
|
output.println(format("returning:class=%s;method=%s;",
|
|
|
|
advice.getClazz().getSimpleName(),
|
|
|
|
advice.getMethod().getName()))
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
void afterThrowing(ScriptSupportCommand.Output output, Advice advice) {
|
|
|
|
output.println(format("throwing:class=%s;method=%s;",
|
|
|
|
advice.getClazz().getSimpleName(),
|
|
|
|
advice.getMethod().getName()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
使用示例:
|
|
|
|
|
|
|
|
```
|
|
|
|
$ groovy com.alibaba.sample.petstore.dal.dao.ProductDao getProductById /Users/zhuyong/middleware/arthas/scripts/Logger.groovy -S
|
|
|
|
script create.
|
|
|
|
Press Ctrl+C to abort.
|
|
|
|
Affect(class-cnt:1 , method-cnt:1) cost in 102 ms.
|
|
|
|
before:class=IbatisProductDao;method=getProductById;paramslen=1;[Ljava.lang.Object;@45df64fc;
|
|
|
|
returning:class=IbatisProductDao;method=getProductById;
|
|
|
|
before:class=IbatisProductDao;method=getProductById;paramslen=1;[Ljava.lang.Object;@5b0e2d00;
|
|
|
|
returning:class=IbatisProductDao;method=getProductById;
|
2018-10-28 22:41:20 +08:00
|
|
|
```
|