Spring 启动 Webflux + Elastic APM 监控
Spring Boot Webflux + Elastic APM Monitoring
我目前是 Elastic APM 的新手。
我目前正在使用 spring-webflux 开发应用程序,并想使用 Elastic APM 监控我的应用程序,但不幸的是,它对我不起作用。
依赖项
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
APM Java 代理版本 - 1.8.0
弹性搜索 - 7.2.0
APM 服务器 - 7.2.0
观察到异常 -
2020-05-07 00:03:31.529 [main] INFO co.elastic.apm.agent.bci.bytebuddy.ErrorLoggingListener - org.springframework.web.context.support.GenericWebApplicationContext refers to a missing class
java.lang.IllegalStateException: Cannot resolve type description for javax.servlet.ServletContext
at co.elastic.apm.agent.shaded.bytebuddy.pool.TypePool$Resolution$Illegal.resolve(TypePool.java:159)
at co.elastic.apm.agent.shaded.bytebuddy.pool.TypePool$Default$LazyTypeDescription$TokenizedGenericType.toErasure(TypePool.java:6241)
at co.elastic.apm.agent.shaded.bytebuddy.pool.TypePool$Default$LazyTypeDescription$GenericTypeToken$Resolution$Raw$RawAnnotatedType.of(TypePool.java:3412)
at co.elastic.apm.agent.shaded.bytebuddy.pool.TypePool$Default$LazyTypeDescription$GenericTypeToken$Resolution$Raw.resolveReturnType(TypePool.java:3302)
at co.elastic.apm.agent.shaded.bytebuddy.pool.TypePool$Default$LazyTypeDescription$LazyMethodDescription.getReturnType(TypePool.java:6796)
at co.elastic.apm.agent.shaded.bytebuddy.description.method.MethodDescription$AbstractBase.asSignatureToken(MethodDescription.java:838)
at co.elastic.apm.agent.bci.bytebuddy.FailSafeDeclaredMethodsCompiler.compile(FailSafeDeclaredMethodsCompiler.java:85)
at co.elastic.apm.agent.bci.bytebuddy.FailSafeDeclaredMethodsCompiler.compile(FailSafeDeclaredMethodsCompiler.java:66)
at co.elastic.apm.agent.shaded.bytebuddy.dynamic.scaffold.MethodRegistry$Default.prepare(MethodRegistry.java:471)
at co.elastic.apm.agent.shaded.bytebuddy.dynamic.scaffold.inline.RedefinitionDynamicTypeBuilder.make(RedefinitionDynamicTypeBuilder.java:198)
at co.elastic.apm.agent.shaded.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doTransform(AgentBuilder.java:10327)
at co.elastic.apm.agent.shaded.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10263)
at co.elastic.apm.agent.shaded.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.access00(AgentBuilder.java:10029)
at co.elastic.apm.agent.shaded.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:10648)
at co.elastic.apm.agent.shaded.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:10595)
at java.security.AccessController.doPrivileged(Native Method)
at co.elastic.apm.agent.shaded.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10186)
at sun.instrument.TransformerManager.transform(Unknown Source)
at sun.instrument.InstrumentationImpl.transform(Unknown Source)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access0(Unknown Source)
at java.net.URLClassLoader.run(Unknown Source)
at java.net.URLClassLoader.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition.resolve(FilteringSpringBootCondition.java:108)
at org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition$ClassNameFilter.isPresent(FilteringSpringBootCondition.java:140)
at org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition.getOutcome(OnWebApplicationCondition.java:71)
at org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition.getOutcomes(OnWebApplicationCondition.java:58)
at org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition.match(FilteringSpringBootCondition.java:49)
at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.filter(AutoConfigurationImportSelector.java:246)
at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.getAutoConfigurationEntry(AutoConfigurationImportSelector.java:121)
at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector$AutoConfigurationGroup.process(AutoConfigurationImportSelector.java:396)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGrouping.getImports(ConfigurationClassParser.java:882)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.processGroupImports(ConfigurationClassParser.java:808)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorHandler.process(ConfigurationClassParser.java:779)
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:192)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:319)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:236)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:275)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:95)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:706)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532)
at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
at com.dhisco.hotel.search.HotelSearchApp.main(HotelSearchApp.java:14)
有人可以建议我缺少什么吗?
WebFlux 可以 运行 在 Servlet 容器上支持 Servlet 3.1 非阻塞 IO API 以及其他异步 运行times 例如 Netty 和 Undertow。
每个 Spring 引导 Web 应用程序都包含一个嵌入式 Web 服务器。
对于反应式堆栈应用程序,我猜 spring-boot-starter-webflux
默认包含 Reactor Netty。而且它不包括 Servlet API
(Netty 是非 Servlet 运行 时间),但看起来你的 Elastic APM
期望这个 API 存在。
尝试使用 spring-boot-starter-tomcat
而不是 Netty。当 switching to a different HTTP server 时,除了包含您需要的依赖项之外,您还需要排除默认依赖项。
这是一个例子:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<exclusions>
<!-- Exclude the Netty dependency -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-reactor-netty</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use Tomcat instead -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
Tomcat依赖带来ServletAPI。也许它会解决您的问题。
看来 elastic 还没有对 WebFlux 的支持
点这里https://github.com/elastic/apm-agent-java/issues/60
他们目前正在努力,但还没有准备好日期
Elastic APM 现在支持 Webflux(Tomcat 或 Netty):
https://github.com/elastic/apm-agent-java/pull/1305
从 Elastic APM 1.25.0 开始,通过在 elasticapm.properties
中或作为 JVM 参数将 enable_experimental_instrumentations
设置为 true
来启用此功能:
enable_experimental_instrumentations=true
在此之前,它是通过将 disable_instrumentations
设置为空字符串来启用的:
disable_instrumentations=
https://github.com/elastic/apm-agent-java/issues/60#issuecomment-822419013
Features
Test application:
available as an executable jar and also used for unit-testing instrumentation
provides both functional and annotated controllers endpoints
executable with netty or tomcat as server, which allows to cover Webflux with or without Servlets
provides a client to call itself (based on Webflux client), thus using any third-party HTTP client is not necessary
Instrumentation:
Webflux server: covers both functional and annotated endpoints variants
Webflux client: not covered yet, see add support for Webflux client instrumentation #1306
using new plugin API and indy dispatcher.
adds reactor instrumentation for context-propagation
我目前是 Elastic APM 的新手。 我目前正在使用 spring-webflux 开发应用程序,并想使用 Elastic APM 监控我的应用程序,但不幸的是,它对我不起作用。
依赖项
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
APM Java 代理版本 - 1.8.0 弹性搜索 - 7.2.0 APM 服务器 - 7.2.0
观察到异常 -
2020-05-07 00:03:31.529 [main] INFO co.elastic.apm.agent.bci.bytebuddy.ErrorLoggingListener - org.springframework.web.context.support.GenericWebApplicationContext refers to a missing class
java.lang.IllegalStateException: Cannot resolve type description for javax.servlet.ServletContext
at co.elastic.apm.agent.shaded.bytebuddy.pool.TypePool$Resolution$Illegal.resolve(TypePool.java:159)
at co.elastic.apm.agent.shaded.bytebuddy.pool.TypePool$Default$LazyTypeDescription$TokenizedGenericType.toErasure(TypePool.java:6241)
at co.elastic.apm.agent.shaded.bytebuddy.pool.TypePool$Default$LazyTypeDescription$GenericTypeToken$Resolution$Raw$RawAnnotatedType.of(TypePool.java:3412)
at co.elastic.apm.agent.shaded.bytebuddy.pool.TypePool$Default$LazyTypeDescription$GenericTypeToken$Resolution$Raw.resolveReturnType(TypePool.java:3302)
at co.elastic.apm.agent.shaded.bytebuddy.pool.TypePool$Default$LazyTypeDescription$LazyMethodDescription.getReturnType(TypePool.java:6796)
at co.elastic.apm.agent.shaded.bytebuddy.description.method.MethodDescription$AbstractBase.asSignatureToken(MethodDescription.java:838)
at co.elastic.apm.agent.bci.bytebuddy.FailSafeDeclaredMethodsCompiler.compile(FailSafeDeclaredMethodsCompiler.java:85)
at co.elastic.apm.agent.bci.bytebuddy.FailSafeDeclaredMethodsCompiler.compile(FailSafeDeclaredMethodsCompiler.java:66)
at co.elastic.apm.agent.shaded.bytebuddy.dynamic.scaffold.MethodRegistry$Default.prepare(MethodRegistry.java:471)
at co.elastic.apm.agent.shaded.bytebuddy.dynamic.scaffold.inline.RedefinitionDynamicTypeBuilder.make(RedefinitionDynamicTypeBuilder.java:198)
at co.elastic.apm.agent.shaded.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doTransform(AgentBuilder.java:10327)
at co.elastic.apm.agent.shaded.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10263)
at co.elastic.apm.agent.shaded.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.access00(AgentBuilder.java:10029)
at co.elastic.apm.agent.shaded.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:10648)
at co.elastic.apm.agent.shaded.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:10595)
at java.security.AccessController.doPrivileged(Native Method)
at co.elastic.apm.agent.shaded.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10186)
at sun.instrument.TransformerManager.transform(Unknown Source)
at sun.instrument.InstrumentationImpl.transform(Unknown Source)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access0(Unknown Source)
at java.net.URLClassLoader.run(Unknown Source)
at java.net.URLClassLoader.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition.resolve(FilteringSpringBootCondition.java:108)
at org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition$ClassNameFilter.isPresent(FilteringSpringBootCondition.java:140)
at org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition.getOutcome(OnWebApplicationCondition.java:71)
at org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition.getOutcomes(OnWebApplicationCondition.java:58)
at org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition.match(FilteringSpringBootCondition.java:49)
at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.filter(AutoConfigurationImportSelector.java:246)
at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.getAutoConfigurationEntry(AutoConfigurationImportSelector.java:121)
at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector$AutoConfigurationGroup.process(AutoConfigurationImportSelector.java:396)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGrouping.getImports(ConfigurationClassParser.java:882)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.processGroupImports(ConfigurationClassParser.java:808)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorHandler.process(ConfigurationClassParser.java:779)
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:192)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:319)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:236)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:275)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:95)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:706)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532)
at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
at com.dhisco.hotel.search.HotelSearchApp.main(HotelSearchApp.java:14)
有人可以建议我缺少什么吗?
WebFlux 可以 运行 在 Servlet 容器上支持 Servlet 3.1 非阻塞 IO API 以及其他异步 运行times 例如 Netty 和 Undertow。
每个 Spring 引导 Web 应用程序都包含一个嵌入式 Web 服务器。
对于反应式堆栈应用程序,我猜 spring-boot-starter-webflux
默认包含 Reactor Netty。而且它不包括 Servlet API
(Netty 是非 Servlet 运行 时间),但看起来你的 Elastic APM
期望这个 API 存在。
尝试使用 spring-boot-starter-tomcat
而不是 Netty。当 switching to a different HTTP server 时,除了包含您需要的依赖项之外,您还需要排除默认依赖项。
这是一个例子:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<exclusions>
<!-- Exclude the Netty dependency -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-reactor-netty</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use Tomcat instead -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
Tomcat依赖带来ServletAPI。也许它会解决您的问题。
看来 elastic 还没有对 WebFlux 的支持
点这里https://github.com/elastic/apm-agent-java/issues/60
他们目前正在努力,但还没有准备好日期
Elastic APM 现在支持 Webflux(Tomcat 或 Netty): https://github.com/elastic/apm-agent-java/pull/1305
从 Elastic APM 1.25.0 开始,通过在 elasticapm.properties
中或作为 JVM 参数将 enable_experimental_instrumentations
设置为 true
来启用此功能:
enable_experimental_instrumentations=true
在此之前,它是通过将 disable_instrumentations
设置为空字符串来启用的:
disable_instrumentations=
https://github.com/elastic/apm-agent-java/issues/60#issuecomment-822419013
Features
Test application:
available as an executable jar and also used for unit-testing instrumentation
provides both functional and annotated controllers endpoints
executable with netty or tomcat as server, which allows to cover Webflux with or without Servlets
provides a client to call itself (based on Webflux client), thus using any third-party HTTP client is not necessary
Instrumentation:
Webflux server: covers both functional and annotated endpoints variants
Webflux client: not covered yet, see add support for Webflux client instrumentation #1306
using new plugin API and indy dispatcher.
adds reactor instrumentation for context-propagation