groovy

Arthas 支持 groovy 脚本增强,允许像 BTrace 一样编写脚本来解决问题,可以在 groovy 脚本中进行if/for/switch/while 等控制语句,不受限制,但相比 BTrace 而言拥有更多的限制范围。

限制内容

  1. 禁止改变原有逻辑,与 watch 等命令一样,重点保证的是监听和观察。
  2. 只允许在方法的 before/success/exception/finish 四个环节进行监听。

参数说明

参数名称 参数说明
class-pattern 类名表达式匹配
method-pattern 方法名表达式匹配
script-filepath groovy 脚本的绝对路径
[S] 匹配所有的子类
[E] 开启正则表达式匹配,默认为通配符匹配

需要说明的是,第三个输入参数是脚本的绝对路径,比如 /tmp/test.groovy,不建议输入相对路径,比如 ./test.groovy

五个关键函数声明

  1. /**
  2. * 增强脚本监听器
  3. */
  4. interface ScriptListener {
  5. /**
  6. * 脚本创建
  7. *
  8. * @param output 输出器
  9. */
  10. void create(Output output);
  11. /**
  12. * 脚本销毁
  13. *
  14. * @param output 输出器
  15. */
  16. void destroy(Output output);
  17. /**
  18. * 方法执行前
  19. *
  20. * @param output 输出器
  21. * @param advice 通知点
  22. */
  23. void before(Output output, Advice advice);
  24. /**
  25. * 方法正常返回
  26. *
  27. * @param output 输出器
  28. * @param advice 通知点
  29. */
  30. void afterReturning(Output output, Advice advice);
  31. /**
  32. * 方法异常返回
  33. *
  34. * @param output 输出器
  35. * @param advice 通知点
  36. */
  37. void afterThrowing(Output output, Advice advice);
  38. }

参数 Advice 说明

Advice 参数最主要是封装了通知节点的所有信息。参考表达式核心变量中关于该节点的描述。

参数 Output 说明

Output 参数只拥有三个方法,主要的工作还是输出对应的文本信息

  1. /**
  2. * 输出器
  3. */
  4. interface Output {
  5. /**
  6. * 输出字符串(不换行)
  7. *
  8. * @param string 待输出字符串
  9. * @return this
  10. */
  11. Output print(String string);
  12. /**
  13. * 输出字符串(换行)
  14. *
  15. * @param string 待输出字符串
  16. * @return this
  17. */
  18. Output println(String string);
  19. /**
  20. * 结束当前脚本
  21. *
  22. * @return this
  23. */
  24. Output finish();
  25. }

一个输出日志的 groovy 脚本示例

  1. import com.taobao.arthas.core.command.ScriptSupportCommand
  2. import com.taobao.arthas.core.util.Advice
  3. import static java.lang.String.format
  4. /**
  5. * 输出方法日志
  6. */
  7. public class Logger implements ScriptSupportCommand.ScriptListener {
  8. @Override
  9. void create(ScriptSupportCommand.Output output) {
  10. output.println("script create.");
  11. }
  12. @Override
  13. void destroy(ScriptSupportCommand.Output output) {
  14. output.println("script destroy.");
  15. }
  16. @Override
  17. void before(ScriptSupportCommand.Output output, Advice advice) {
  18. output.println(format("before:class=%s;method=%s;paramslen=%d;%s;",
  19. advice.getClazz().getSimpleName(),
  20. advice.getMethod().getName(),
  21. advice.getParams().length, advice.getParams()))
  22. }
  23. @Override
  24. void afterReturning(ScriptSupportCommand.Output output, Advice advice) {
  25. output.println(format("returning:class=%s;method=%s;",
  26. advice.getClazz().getSimpleName(),
  27. advice.getMethod().getName()))
  28. }
  29. @Override
  30. void afterThrowing(ScriptSupportCommand.Output output, Advice advice) {
  31. output.println(format("throwing:class=%s;method=%s;",
  32. advice.getClazz().getSimpleName(),
  33. advice.getMethod().getName()))
  34. }
  35. }

使用示例:

  1. $ groovy com.alibaba.sample.petstore.dal.dao.ProductDao getProductById /Users/zhuyong/middleware/arthas/scripts/Logger.groovy -S
  2. script create.
  3. Press Ctrl+C to abort.
  4. Affect(class-cnt:1 , method-cnt:1) cost in 102 ms.
  5. before:class=IbatisProductDao;method=getProductById;paramslen=1;[Ljava.lang.Object;@45df64fc;
  6. returning:class=IbatisProductDao;method=getProductById;
  7. before:class=IbatisProductDao;method=getProductById;paramslen=1;[Ljava.lang.Object;@5b0e2d00;
  8. returning:class=IbatisProductDao;method=getProductById;