woozoo73/adonistrack
GitHub: woozoo73/adonistrack
一款轻量级的 Java 方法调用追踪与性能分析工具,无需编写代码即可记录调用栈的参数、返回值、异常和执行耗时。
Stars: 4 | Forks: 2
= AdonisTrack image:https://img.shields.io/badge/License-Apache%202.0-blue.svg["许可证", link="https://opensource.org/licenses/Apache-2.0"] image:https://img.shields.io/maven-central/v/com.woozooha/adonistrack.svg["Maven Central", link="https://central.sonatype.com/search?q=g:com.woozooha%20a:adonistrack"]
简单的 Java 性能分析工具。('hazin-tracer' 的轻量级版本)
* 可以立即跟踪调用栈。
* 无需编写代码即可跟踪方法调用。
* 提供方法调用信息(参数、返回值、错误和执行时间)。
* 兼容 Spring Framework。
* 并发调用时的信息不会相互混淆。
* 提供扩展点以供自定义。
* ...
== 用法
=== 1. 将此库添加到您的项目中
image:https://img.shields.io/maven-central/v/com.woozooha/adonistrack.svg["Maven Central", link="https://central.sonatype.com/search?q=g:com.woozooha%20a:adonistrack"]
=== 2. 将 AdonistrackFilter 添加到您的应用程序中
* 如果您的应用程序不是 Web 应用程序,请跳过此部分。
## .Application.java
[source,java,indent=0]
package com.woozooha.adonistrack.test.spring;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import com.woozooha.adonistrack.filter.AdonistrackFilter;
@SpringBootApplication
public class Application {
```
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public FilterRegistrationBean profileFilter() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new AdonistrackFilter());
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
```
## }
=== 3. 配置您的 aspect 进行分析
* 通过扩展 `ProfileAspect` 创建一个 aspect,例如 `AdonisTrackAspect.java`
* 使用 pointcut 表达式配置该 aspect 的 `profilePointcut` 和 `executionPointcut`。
* 您可以使用 pointcut 表达式设置分析目标。
如果您遇到问题,可能需要更改此 @Pointcut 表达式。
以下页面会对您有所帮助。
https://howtodoinjava.com/spring-aop/aspectj-pointcut-expressions/
## .AdonisTrackAspect.java
[source,java,indent=0]
package com.woozooha.adonistrack.test.spring;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import com.woozooha.adonistrack.aspect.ProfileAspect;
@Aspect
@Component
public class AdonisTrackAspect extends ProfileAspect {
```
/**
* Fix this @Pointcut expression according to your situation. For
* example, modify "com.woozooha.adonistrack.test.spring" to your application's
* top-level package name "com.yourcompany.killerapp".
*/
@Pointcut("execution(* *(..)) && (within(com.woozooha.adonistrack.test.spring..*) || within(com.woozooha.adonistrack.test.spring..*+))")
public void executionPointcut() {
}
```
## }
=== 4. 使用上述 aspect `AdonistrackFilter` 配置和 `AdonisTrackAspect.java` 运行您的应用程序
## .运行应用程序日志
[indent=0]
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.3.RELEASE)
## 2019-04-17 13:45:18.014 INFO 254732 --- [ main] com.woozooha.hello.Application : Starting Application ...
2019-04-17 13:45:33.663 INFO 254732 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 10 ms
=== 5. 调用您的应用程序并检查日志
当您的应用程序通过 `GET /greeting?name=hello HTTP/1.1` 被调用时
* 这是执行成功时的日志。
## .输出日志
[indent=0]
## ----> [REQUEST] GET http://localhost:8080/greeting/1 (230.83ms:100.00%)
----> com.woozooha.adonistrack.test.spring.GreetingController.greeting(1) (29.40ms:100.00%)
----> com.woozooha.adonistrack.test.spring.GreetingService.greeting(1) (25.33ms:100.00%)
----> com.sun.proxy.$Proxy87.findById(1) (19.92ms:100.00%)
<---- Optional[Greeting(id=1, content=Hello\nfoo)]
<---- Greeting(id=1, content=Hello\nfoo)
<---- Greeting(id=1, content=Hello\nfoo)
<---- [RESPONSE] 200
* 上面的日志表示如下的时序图。
image:diagram-happy.png["图表", link="https://github.com/francoislaberge/diagrams"]
* 这是执行失败时的日志。
## .输出日志
[indent=0]
## ----> [REQUEST] GET http://localhost:8080/greeting/2 (21.97ms:100.00%)
----> com.woozooha.adonistrack.test.spring.GreetingController.greeting(2) (5.60ms:100.00%)
----> com.woozooha.adonistrack.test.spring.GreetingService.greeting(2) (1.66ms:100.00%)
----> com.sun.proxy.$Proxy87.findById(2) (0.71ms:100.00%)
<---- Optional.empty
<<<<< java.util.NoSuchElementException: No value present
<<<<< java.util.NoSuchElementException: No value present
<---- [RESPONSE] 200
* 上面的日志表示如下的时序图。
image:diagram-unhappy.png["图表", link="https://github.com/francoislaberge/diagrams"]
=== 6. 更多选项
要将默认的 "ToStringFormat" 替换为自定义格式,您需要设置属性 "adonistrack.to-string.class"。
## .Application.java
[source,java,indent=0]
@SpringBootApplication
public class Application {
```
public static void main(String[] args) {
System.setProperty("adonistrack.to-string.class", YourCustomToStringFormat.class.getName());
SpringApplication.run(Application.class, args);
}
...
```
## }
Adonistrack 支持 load-time-weaving,以实现更强大的分析功能。
如果您想分析 JDBC 查询,请执行以下操作。
* 将 aop.xml 文件添加到您的应用程序项目中。
## ./META-INF/aop.xml
[source,xml,indent=0]
----
* 运行您的应用程序时添加 VM 参数。
## .VM 参数
## -javaagent:/{your-home-path}/.m2/repository/org/aspectj/aspectjweaver/1.9.2/aspectjweaver-1.9.2.jar
现在您可以看到 JDBC 查询已进行分析,如下所示。
## .输出日志
[indent=0]
## ----> [REQUEST] GET http://localhost:8080/greeting/1 (227.91ms:100.00%)
----> com.woozooha.adonistrack.test.spring.GreetingController.greeting(1) (36.04ms:100.00%)
----> com.woozooha.adonistrack.test.spring.GreetingService.greeting(1) (31.40ms:100.00%)
----> com.sun.proxy.$Proxy88.findById(1) (26.41ms:100.00%)
| [JDBC] [sql=select greeting0_.id as id1_0_0_, greeting0_.content as content2_0_0_ from greeting greeting0_ where greeting0_.id=?, parameterMap={1=1}]
<---- Optional[Greeting(id=1, content=Hello\nfoo)]
<---- Greeting(id=1, content=Hello\nfoo)
<---- Greeting(id=1, content=Hello\nfoo)
<---- [RESPONSE] 200
== 7. 已知问题
=== 1. 使用 `AdonisTrackFilter` 时可能会发生 HTTP 状态码不匹配的错误
* 要修复此错误:
* 1. 移除 `AdonisTrackFilter`。
## .Application.java
[source,java,indent=0]
package com.woozooha.adonistrack.test.spring;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import com.woozooha.adonistrack.filter.AdonistrackFilter;
@SpringBootApplication
public class Application {
```
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
```
## }
* 2. 根据具体情况,您可以通过创建如下的一点代码来纠正 HTTP 状态码。
## .AdonistrackInterceptor.java
[source,java,indent=0]
package com.woozooha.adonistrack.test.spring;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.woozooha.adonistrack.aspect.ProfileAspect;
import com.woozooha.adonistrack.domain.Event;
import com.woozooha.adonistrack.domain.Invocation;
import com.woozooha.adonistrack.domain.RequestInfo;
import com.woozooha.adonistrack.domain.RequestInfoEvent;
import com.woozooha.adonistrack.domain.ResponseInfo;
import com.woozooha.adonistrack.domain.ResponseInfoEvent;
public class AdonistrackInterceptor implements HandlerInterceptor {
```
private static ThreadLocal CONTEXT = new ThreadLocal();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (request.getRequestURI().startsWith("/adonistrack")) {
return true;
}
Invocation invocation = CONTEXT.get();
if (invocation == null) {
invocation = before(request);
CONTEXT.set(invocation);
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
if (request.getRequestURI().startsWith("/adonistrack")) {
return;
}
Invocation invocation = CONTEXT.get();
if (invocation != null) {
after(invocation, request, response);
CONTEXT.set(null);
}
}
private Invocation before(HttpServletRequest request) {
Event event = new RequestInfoEvent(new RequestInfo(request));
return ProfileAspect.before(event);
}
private void after(Invocation invocation, HttpServletRequest request, HttpServletResponse response) {
Event event = new ResponseInfoEvent(new ResponseInfo(response));
ProfileAspect.after(invocation, event);
}
```
## }
* 3. 添加您的 `AdonisTrackInterceptor`。
## .WebConfig.java
[source,java,indent=0]
package com.woozooha.adonistrack.test.spring;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
```
@Override
public void addInterceptors(InterceptorRegistry registry) {
AdonistrackInterceptor adonistrackInterceptor = new AdonistrackInterceptor();
registry.addInterceptor(adonistrackInterceptor).addPathPatterns("/**/*");
}
```
## }
* 4. 现在,RESPONSE 状态码变为了 `500`。
## .输出日志
[indent=0]
## ----> [REQUEST] GET http://localhost:8080/greeting/2 (134.97ms:100.00%)
----> com.woozooha.adonistrack.test.spring.GreetingController.greeting(2) (29.34ms:100.00%)
----> com.woozooha.adonistrack.test.spring.GreetingService.greeting(2) (9.78ms:100.00%)
----> com.sun.proxy.$Proxy96.findById(2) (6.15ms:100.00%)
| [JDBC] [sql=select greeting0_.id as id1_0_0_, greeting0_.content as content2_0_0_ from greeting greeting0_ where greeting0_.id=?, parameterMap={1=2}]
<---- Optional.empty
<<<<< java.util.NoSuchElementException: No value present
<<<<< java.util.NoSuchElementException: No value present
<---- [RESPONSE] 500
== 许可证
AdonisTrack 是开源软件,基于 Apache 2.0 许可证发布。
== 关于 AdonisTrack?
侧金盏花(Adonis)的花语在西方是“悲伤的回忆”,而在东方则是“永恒的幸福”。
image:adonis-flower-01.jpg["Adonis amurensis", link="https://en.wikipedia.org/wiki/Adonis_amurensis", width=42%]
image:adonis-flower-02.jpg["Adonis amurensis", link="https://en.wikipedia.org/wiki/Adonis_amurensis", width=42%]
image:adonis-flower-03.jpg["Adonis amurensis", link="https://en.wikipedia.org/wiki/Adonis_amurensis", width=42%]
image:adonis-flower-04.jpg["Adonis amurensis", link="https://en.wikipedia.org/wiki/Adonis_amurensis", width=42%]
标签:JS文件枚举, SOC Prime, Spring, 域名枚举, 开发工具, 性能分析, 方法跟踪