diff --git a/docs/_coverpage.md b/docs/_coverpage.md index df61929..c182e8f 100644 --- a/docs/_coverpage.md +++ b/docs/_coverpage.md @@ -1,6 +1,6 @@ ![logo](v200/kotime.png) -v2.0.9@Huoyo +v2.2.0@Huoyo > koTime是一个springboot方法调用链路追踪和运行时长统计工具 @@ -9,4 +9,4 @@ [Gitee](https://gitee.com/huoyo/ko-time) -[文档教程](v204/introduce) +[文档教程](v220/introduce) diff --git a/docs/_navbar.md b/docs/_navbar.md index 16736e3..97e335e 100644 --- a/docs/_navbar.md +++ b/docs/_navbar.md @@ -1,5 +1,6 @@ * 其他版本教程 + * [V2.2.0+](v220/getstart) * [V2.0.4+](v204/getstart) * [V2.0.3](v203/getstart) * [V2.0.2](v202/getstart) diff --git a/docs/index.html b/docs/index.html index ec058ad..e922b24 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,7 +1,7 @@ - + diff --git a/docs/v220/_sidebar.md b/docs/v220/_sidebar.md new file mode 100644 index 0000000..5a8fed1 --- /dev/null +++ b/docs/v220/_sidebar.md @@ -0,0 +1,6 @@ +* [简介](v220/introduce) +* [快速上手](v220/getstart) +* [高级特性](v220/more) +* [UI页面说明](v220/uiguide) +* [API数据接口](v220/apiintro) +* [常见问题](v220/questions) \ No newline at end of file diff --git a/docs/v220/apiintro.md b/docs/v220/apiintro.md new file mode 100644 index 0000000..9e1bb41 --- /dev/null +++ b/docs/v220/apiintro.md @@ -0,0 +1,282 @@ + +## 获取接口方法列表 + +* 接口名 + +>`GET` /koTime/getApis + +* 返回示例 + +```json +[ + { + "id":"com.example.demo.controller.IndexController.test1", + "name":"IndexController.test1", + "className":"com.example.demo.controller.IndexController", + "methodName":"test1", + "value":2001.38, + "avgRunTime":2001.38, + "maxRunTime":2001.9, + "minRunTime":2001.19, + "methodType":"Controller", + "exceptionNum":0, + "children":[ + + ], + "exceptions":[ + + ] + }, + { + "id":"com.example.demo.controller.IndexController.test2", + "name":"IndexController.test1", + "className":"com.example.demo.controller.IndexController", + "methodName":"test1", + "value":2001.38, + "avgRunTime":2001.38, + "maxRunTime":2001.9, + "minRunTime":2001.19, + "methodType":"Controller", + "exceptionNum":0, + "children":[ + + ], + "exceptions":[ + + ] + } +] +``` + + +## 获取方法列表调用链路 + +* 接口名 + +>`GET` /koTime/getTree?methodName=每一个方法的id + +* 返回示例 +```json +{ + "id":"com.example.demo.controller.IndexController.test1", + "name":"IndexController.test1", + "className":"com.example.demo.controller.IndexController", + "methodName":"test1", + "value":2001.38, + "avgRunTime":2001.38, + "maxRunTime":2001.9, + "minRunTime":2001.19, + "methodType":"Controller", + "exceptionNum":0, + "children":[ + { + "id":"com.example.demo.service.impl.IndexServiceImpl.getParents", + "name":"IndexServiceImpl.getParents", + "className":"com.example.demo.service.impl.IndexServiceImpl", + "methodName":"getParents", + "value":0.47, + "avgRunTime":0.47, + "maxRunTime":0.59, + "minRunTime":0.43, + "methodType":"Service", + "exceptionNum":1, + "children":[ + { + "id":"com.example.demo.service.impl.IndexServiceImpl.index2", + "name":"IndexServiceImpl.index2", + "className":"com.example.demo.service.impl.IndexServiceImpl", + "methodName":"index2", + "value":0.35, + "avgRunTime":0.35, + "maxRunTime":0.4, + "minRunTime":0.32, + "methodType":"Service", + "exceptionNum":0, + "children":[ + + ], + "exceptions":[ + + ] + } + ], + "exceptions":[ + { + "id":"java.lang.RuntimeExceptionRuntimeException获取信息失败", + "name":"RuntimeException", + "className":"java.lang.RuntimeException", + "message":"获取信息失败", + "location":91, + "methodName":null, + "occurClassName":null + } + ] + }, + { + "id":"com.example.demo.service.impl.IndexServiceImpl.getUsers", + "name":"IndexServiceImpl.getUsers", + "className":"com.example.demo.service.impl.IndexServiceImpl", + "methodName":"getUsers", + "value":1000.91, + "avgRunTime":1000.91, + "maxRunTime":1006.25, + "minRunTime":1000.79, + "methodType":"Service", + "exceptionNum":1, + "children":[ + { + "id":"com.example.demo.service.impl.IndexServiceImpl.index1", + "name":"IndexServiceImpl.index1", + "className":"com.example.demo.service.impl.IndexServiceImpl", + "methodName":"index1", + "value":0.42, + "avgRunTime":0.42, + "maxRunTime":3.81, + "minRunTime":0.37, + "methodType":"Service", + "exceptionNum":0, + "children":[ + { + "id":"com.example.demo.service.impl.IndexServiceImpl.test2", + "name":"IndexServiceImpl.test2", + "className":"com.example.demo.service.impl.IndexServiceImpl", + "methodName":"test2", + "value":0.01, + "avgRunTime":0.01, + "maxRunTime":0.02, + "minRunTime":"0.0", + "methodType":"Service", + "exceptionNum":0, + "children":[ + + ], + "exceptions":[ + + ] + }, + { + "id":"com.example.demo.service.impl.IndexServiceImpl.test1", + "name":"IndexServiceImpl.test1", + "className":"com.example.demo.service.impl.IndexServiceImpl", + "methodName":"test1", + "value":0.04, + "avgRunTime":0.04, + "maxRunTime":0.08, + "minRunTime":0.03, + "methodType":"Service", + "exceptionNum":0, + "children":[ + + ], + "exceptions":[ + + ] + } + ], + "exceptions":[ + + ] + } + ], + "exceptions":[ + { + "id":"java.lang.RuntimeExceptionRuntimeException认证失败", + "name":"RuntimeException", + "className":"java.lang.RuntimeException", + "message":"认证失败", + "location":82, + "methodName":null, + "occurClassName":null + } + ] + } + ], + "exceptions":[ + + ] +} +``` + +## 获取异常列表 + +* 接口名 + +>`GET` /koTime/getExceptions + +* 返回示例 + +```json +[ + { + "id":"java.lang.RuntimeExceptionRuntimeException认证失败", + "name":"RuntimeException", + "className":"java.lang.RuntimeException", + "message":"认证失败", + "value":82 + }, + { + "id":"java.lang.RuntimeExceptionRuntimeException获取信息失败", + "name":"RuntimeException", + "className":"java.lang.RuntimeException", + "message":"获取信息失败", + "value":91 + } +] +``` + +## 获取异常详情 + +* 接口名 + +> `GET` /koTime/getMethodsByExceptionId?exceptionId=xx + +* 返回示例 +```json +[ + { + "id":"java.lang.RuntimeExceptionRuntimeException获取信息失败", + "name":"RuntimeException", + "className":"java.lang.RuntimeException", + "message":"获取信息失败", + "location":91, + "methodName":"getParents", + "occurClassName":"com.example.demo.service.impl.IndexServiceImpl" + } +] +``` + +## 获取当前配置信息 + +* 接口名 + +>`GET` /koTime/getConfig + +* 返回示例 + +```json +{ + "logLanguage":"chinese", + "enable":true, + "logEnable":false, + "threshold":"800.0", + "exceptionEnable":true, + "dataSaver":"memory" +} +``` + +## 更新当前配置信息 + +* 接口名 + +>`POST` /koTime/updateConfig + +* 参数示例 + +```json +{ + "enable":true, + "logEnable":false, + "threshold":"800.0", + "exceptionEnable":true +} +``` \ No newline at end of file diff --git a/docs/v220/apis.png b/docs/v220/apis.png new file mode 100644 index 0000000..e308d33 Binary files /dev/null and b/docs/v220/apis.png differ diff --git a/docs/v220/ff.png b/docs/v220/ff.png new file mode 100644 index 0000000..b8e105a Binary files /dev/null and b/docs/v220/ff.png differ diff --git a/docs/v220/ffss.png b/docs/v220/ffss.png new file mode 100644 index 0000000..f37c8d6 Binary files /dev/null and b/docs/v220/ffss.png differ diff --git a/docs/v220/getstart.md b/docs/v220/getstart.md new file mode 100644 index 0000000..4ea8436 --- /dev/null +++ b/docs/v220/getstart.md @@ -0,0 +1,71 @@ +## 引入依赖 + +在pom.xml文件中引入 + + +``` + + cn.langpy + ko-time + 2.2.0.BETA + +``` + +## 配置 + +在`application.properties`文件中进行配置 + +* 必填配置 + +> +> ko-time.pointcut=`execution(public * com.huoyo..*.*(..))` # 需要监测的切面范围,参考aop的@pointcut 或者左侧常见问题 +> + + +* 可选配置(以下配置一般不用设置) + +> +> ko-time.enable=true # 是否开启koTime,默认开启,当为false时,关闭koTime +> ko-time.log-enable=false # 是否开启控制输出,默认false +> ko-time.log-language=chinese # 控制台输出语言(english/chinese)默认chinese +> ko-time.threshold=800.0 # 时间阈值,用于前端展示,大于阈值显示红色,小于阈值显示绿色,默认800 +> ko-time.context-path=http://localhost:80 # 前端页面调用接口的上下文环境,无法自动获取时可手动配置,一般情况切记不要配置 v2.0.1开始支持 +> ko-time.exception-enable=true # 是否开启异常检测,默认为false,开启后会对方法内部抛出的异常进行统计 v2.0.0开始支持 +> ko-time.auth-enable=true # 是否开启认证,默认为false,开启后需要登录才能访问调用链路 v2.0.2开始支持 +> ko-time.user-name=xxxx # 登录用户 v2.0.2开始支持 +> ko-time.password=xxxx # 登录密码 v2.0.2开始支持 +> ko-time.param-analyse=true #是否开启入参组合分析 默认开启 v2.0.8开始支持 双击方法节点即可看到效果 +> ko-time.saver=memory #接口信息存储位置,可选{memory,database} 默认memory v2.2.0.BETA开始支持 +> ko-time.thread-num=5 #调用信息存储线程数(为了不影响项目本身的性能,链路存储异步进行),默认5 v2.2.0.BETA开始支持 + +## 访问 + +> 注意: +> 1.引入了上面的依赖和配置以后,确认项目中是否有aop相关的包,koTime使用了@Aspect注解,未引入的自行引入,如aspectj或者spring-boot-starter-aop +> 2.做完前面的步骤,koTime的集成已经完毕,无需进行其他配置 +> 3.如果后台有权限认证,需要放开`/koTime`和`/koTime/**` + + + +* 启动项目访问 `/koTime` 路径即可 + +* 如果仅仅只是想统计某个方法,在方法上加上`@ComputeTime`即可,控制台会输出耗时 + + +> 建议使用谷歌浏览器或者Edge浏览器,IE是不可能支持的 + +如果项目自定义的contextpath,访问如`http://localhost:8080/xxx服务/koTime` + +如:application.properties中定义了 `server.servlet.context-path=/myservice`,那么访问路径为`http://localhost:8080/myservice/koTime` + +如果页面能正常显示,但是无法获取方法链路,可配置`ko-time.context-path=http://localhost:8080/myservice` + + +--- + + +**为了让作者不要偷懒,督促他好好维护和开发,我准备用金钱对他进行鞭笞** + + + + diff --git a/docs/v220/introduce.md b/docs/v220/introduce.md new file mode 100644 index 0000000..63efeb6 --- /dev/null +++ b/docs/v220/introduce.md @@ -0,0 +1,60 @@ + +## 简介 +koTime是一个springboot项目性能分析工具,通过追踪方法调用链路以及对应的运行时长快速定位性能瓶颈 + +## 预览 + +http://huoyo.gitee.io/ko-time/example + + +## 优点 + +> * 实时监听方法,统计运行时长 +> * web展示方法调用链路,瓶颈可视化追踪 + + + + +## 重要版本说明 + +> V1.0:基本功能 + +> V1.1:接口统计 + +> V1.2:不可用,错误版本 + +> V1.3:添加日志、时间阈值可配置 + +> V1.4:添加koTime.pointcut配置 + +> V1.8:支持Mybatis的Mapper监测、新增最大/最小运行时间、修复小数位数过长页面边界溢出的bug + +> V2.0.0:添加异常监测,开放数据接口,修复与swagger冲突bug,添加配置动态更新功能以及重构数据存储机制 + +> V2.0.1:移除freemarker与thymeleaf; + 移除spring.profiles.active=koTime配置; + 优化方法链路获取机制(移除getAllStackTraces()); + 替换layui; + 优化配置方式; + 优化页面显示 + +> V2.0.2:新增登录认证; + 优化页面加载; + 修复方法循环调用栈溢出的bug + +> V2.0.7:Controller层显示路由 + +> V2.0.8:入参组合分析 + +> V2.2.0:添加数据库存储支持 + +## 作者 + +> Huoyo/Zhang Chang + +--- + +**为了让作者不要偷懒,督促他好好维护和开发,我准备用金钱对他进行鞭笞** + + + diff --git a/docs/v220/kotime.png b/docs/v220/kotime.png new file mode 100644 index 0000000..f939889 Binary files /dev/null and b/docs/v220/kotime.png differ diff --git a/docs/v220/more.md b/docs/v220/more.md new file mode 100644 index 0000000..f20d747 --- /dev/null +++ b/docs/v220/more.md @@ -0,0 +1,112 @@ +## 存储多样性 + +v2.2.0开始支持数据库存储接口信息功能,可在内存和数据库中进行切换 + +### 内存存储 + +更改配置: + +> ko-time.saver=memory #默认存储方式,无需此配置也行 + +### 数据库存储 + +1.更改配置: + +> ko-time.saver=database + +2.数据表创建 + +```sql +create table ko_method_node ( + id varchar(200) not null primary key comment '主键' , + name varchar(200) null comment '类名+方法名' , + class_name varchar(200) null comment '类名' , + method_name varchar(200) null comment '方法名' , + route_name varchar(200) null comment '路由,controller才有' , + method_type varchar(64) null comment '方法类型' +) comment '方法信息表'; + + +create table ko_method_relation ( + id varchar(200) not null primary key comment '' , + source_id varchar(200) null comment '调用方id' , + target_id varchar(200) null comment '被调用方id' , + avg_run_time numeric(10,2) null comment '平均耗时' , + max_run_time numeric(10,2) null comment '最大耗时' , + min_run_time numeric(10,2) null comment '最小耗时' +) comment '方法调用关系表'; + +; +create table ko_exception_node ( + id varchar(200) not null primary key comment '主键' , + name varchar(200) null comment '异常名' , + class_name varchar(200) null comment '类名' , + message varchar(200) null comment '异常消息' +) comment '异常表'; + + +create table ko_exception_relation ( + id varchar(200) not null primary key comment '' , + source_id varchar(200 null comment '调用方法id' , + target_id varchar(200) null comment '异常id' , + location int null comment '异常位置' +) comment '异常关系表'; + +create table ko_param_ana ( + source_id varchar(200) null comment '调用方法id' , + params varchar(200) null comment '参数组合,-分隔' , + avg_run_time numeric(10,2) null comment '平均耗时' , + max_run_time numeric(10,2) null comment '最大耗时' , + min_run_time numeric(10,2) null comment '最小耗时' +) comment '参数分析表'; +``` + + +## 方法调用信息扩展监听 + +如果需要做方法调用信息进行监听,然后做一些扩展的,可以使用此方法 + +1.新建监听类,实现InvokedHandler,并能加上注解@KoListener即可 + +```java + +@KoListener +public class TestInvoke implements InvokedHandler { + @Override + public void onInvoked(MethodNode current, MethodNode parent, Parameter[] names, Object[] values) { + System.out.println("调用的方法:"+current); + System.out.println("调用当前方法的上一级方法:"+parent); + System.out.println("调用的方法-参数名称:"+names); + System.out.println("调用的方法-具体参数:"+values); + } +} +``` + +2.如果需要监听异常情况 + +实现InvokedHandler的默认方法即可 + +```java + +@KoListener +public class TestInvoke implements InvokedHandler { + @Override + public void onInvoked(MethodNode current, MethodNode parent, Parameter[] names, Object[] values) { + + } + + @Override + public void onException(MethodNode current, MethodNode parent, ExceptionNode exception, Parameter[] names, Object[] values) { + System.out.println("异常:"+exception); + } +} +``` + +--- + + +**为了让作者不要偷懒,督促他好好维护和开发,我准备用金钱对他进行鞭笞** + + + + diff --git a/docs/v220/param.png b/docs/v220/param.png new file mode 100644 index 0000000..b0652b4 Binary files /dev/null and b/docs/v220/param.png differ diff --git a/docs/v220/param2.png b/docs/v220/param2.png new file mode 100644 index 0000000..2b23bfa Binary files /dev/null and b/docs/v220/param2.png differ diff --git a/docs/v220/pay.jpg b/docs/v220/pay.jpg new file mode 100644 index 0000000..a5fa50e Binary files /dev/null and b/docs/v220/pay.jpg differ diff --git a/docs/v220/pz.png b/docs/v220/pz.png new file mode 100644 index 0000000..993cc13 Binary files /dev/null and b/docs/v220/pz.png differ diff --git a/docs/v220/questions.md b/docs/v220/questions.md new file mode 100644 index 0000000..73bcfc3 --- /dev/null +++ b/docs/v220/questions.md @@ -0,0 +1,94 @@ +## 额外依赖引入 + +koTime使用了@Aspect注解,未引入 aop相关包的自行引入,如aspectj或者spring-boot-starter-aop + + +## pointcut写法参考 + +pointcut直接引用了aop中的写法,下面简要提供几个写法: + +假设项目的包路径为: + +``` +com.huoyo.demo + |-controller + |-service + |-mapper + |-others + |-other1 + |-other2 + |-Test.java + +``` + +想要切`cn.langpy.demo`下面的所有方法(包括子包中的),可以写: + +> `execution(public * com.huoyo.demo..*.*(..))` #切记,是两个点. + + +只想要切`cn.langpy.demo.controller`下面的类的所有方法(不包括子包的),可以写: + +> `execution(public * com.huoyo.demo.controller.*.*(..))` #切记,是一个点. + +只想要切`cn.langpy.demo.others`下面的类的所有方法(不包括other1和other2下面的),可以写: + +> `execution(public * com.huoyo.demo.others.*.*(..))` + +只想要切`cn.langpy.demo.others`下面的类的所有方法(包括other1和other2),可以写: + +> `execution(public * com.huoyo.demo.others..*.*(..))` + +更多写法请详细参考aop + +## 是否支持前后端分离项目 + +支持! + +## 如何与shiro集成 + +koTime没有做相关方面的限制,在shiro的配置中将相关路径放开即可,如: + +```Java +ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); +/*设置过滤*/ +Map filterChainDefinitionMap = new LinkedHashMap(); +/*authc:所有url都必须认证通过才可以访问;*/ +/*anon:所有url都都可以匿名访问*/ +filterChainDefinitionMap.put("/koTime", "anon"); +filterChainDefinitionMap.put("/koTime/**", "anon"); +shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); + +``` + +## 运行时间计算 + +运行时间分了三个指标:**平均运行时间、最大运行时间、最小运行时间** + +平均运行时间会将方法下每一次的运行时间与之前的求平均 + + +## 数据是否会保存 + +目前暂不支持数据的存储,也就是每一次项目重启之后,以往的统计数据都归0 + +## 集成是否需要复制资源文件 + +不需要复制 static和template 等资源文件,引入依赖时已自动集成 + +## 能正常启动但是页面样式不对 + +打开f12查看静态资源路径加载是否正确,如果不正确,手动配置属性`ko-time.context-path=http://ip:port/contextPath` + +## V2.0.1开始更改了配置,V2.0.0的配置方式是否可用 + +V2.0.1开始,两种配置均生效,建议使用新的配置方式 + +## 问题咨询 + +访问[koTime开源地址](https://gitee.com/huoyo/ko-time)进行咨询 + +--- + +**我觉得作者列的问题太少了,不能满足我,我准备用金钱对他进行鞭笞,并备注上本大爷的要求** + + diff --git a/docs/v220/test3.png b/docs/v220/test3.png new file mode 100644 index 0000000..456086b Binary files /dev/null and b/docs/v220/test3.png differ diff --git a/docs/v220/uiguide.md b/docs/v220/uiguide.md new file mode 100644 index 0000000..7bb7889 --- /dev/null +++ b/docs/v220/uiguide.md @@ -0,0 +1,57 @@ + + +## 首页面板 + +首页有六个统计指标,分别是 + +`总接口数`、`延迟响应接口数`、`正常响应接口数`、`平均响应`、`最大响应`、`最小响应` + + +接口是否延迟取决于`ko-time.threshold`的配置,大于该阈值即表示延迟,显示为红色,如下图 + +![](zl.png) + + +## 接口列表 + +该列表展示的是监测到被请求过的接口,按照其平均响应时间倒序排列,超过`ko-time.threshold`的接口显示红色,如下图: + +可根据类名或者方法名模糊搜索,回车即可 + +![](ffss.png) + + + + +点击每一个接口后会显示该接口的方法调用链路、各个方法的运行时间以及该方法是否发生了异常,方法节点可拖动 +![](ff.png) + + +双击节点,可以查看不同入参组合下的调用时间分析(再双击即可收起): + +![](param.png) + +**-** 表示无参数 + +![](param2.png) + +## 异常列表 + +异常列表以异常为切入点,并显示每个异常发生的位置 + +![](yc.png) + + +## 配置面板 + +配置面板有四项配置,可在不重启系统的情况下进行配置 + +`开启koTime监测` :该开关对应`ko-time.enable`,默认开启,当不需要koTime时可选择关闭 + +`开启异常监测` :该开关对应`ko-time.exception-enable`,默认关闭,当需要时可选择开启 + +`开启控制台日志` :该开关对应`ko-time.log-enable`,默认关闭,当需要时可选择开启,即可在控制台打印日志 + +`方法运行时间阈值` :该开关对应`ko-time.threshold`,默认800ms,可调整,调整后接口列表和方法节点的颜色将以新的阈值变化 + +![](pz.png) \ No newline at end of file diff --git a/docs/v220/yc.png b/docs/v220/yc.png new file mode 100644 index 0000000..5cb9007 Binary files /dev/null and b/docs/v220/yc.png differ diff --git a/docs/v220/zl.png b/docs/v220/zl.png new file mode 100644 index 0000000..6a980a3 Binary files /dev/null and b/docs/v220/zl.png differ