故障排除
编辑故障排除
编辑某些功能无法按预期工作?以下是一些找出问题所在的方法。
第一步,请检查您的堆栈是否与当前支持的技术兼容。
如果您无法找出问题所在,请不要担心。在APM 讨论论坛中创建一个主题,我们将帮助您。
如果您这样做,请附加您的调试日志,以便我们分析问题。将完整日志上传到类似https://gist.github.com的服务。日志应包含从应用程序启动到执行第一个请求的所有内容。除了代理和应用程序日志外,请查找所有服务标准输出和标准错误日志中的[elastic-apm-agent]
条目,当日志记录不可用时,我们有时会在其中打印有用的信息。
更新到最新代理版本
编辑代理会频繁更新,并且版本发布与堆栈中的其他组件没有紧密关联。
因此,尝试更新到最新发布的代理版本通常是推荐的第一步故障排除步骤。如果可能,尝试使用最新快照甚至更好,因为它包含尚未发布的修复程序。
有关更多详细信息,请参阅升级文档。
与其他代理一起运行
编辑与许多其他 Java 代理一样,我们的代理通过在运行时将字节码注入到类中来检测类。我们的字节码检测保证只产生有效的字节码,并且永远不会更改类的“模式”。如果您除了我们提供的还使用其他具有相同保证的 Java 代理,则它们不应该相互干扰。但是,某些 Java 代理不符合这些保证,在这种情况下,可能无法与我们的代理并行使用。如果您遇到错误,首先要做的事情之一就是删除任何其他代理,以检查这是否确实是代理不匹配的情况。我们仍然可以找到一种方法使它们一起工作,但是此信息对于我们提供帮助的能力至关重要,因此请确保在报告此类问题时包含它。
日志记录
编辑有几个与日志记录相关的配置选项。其中最重要的是log_level
。
将日志级别设置为DEBUG
甚至TRACE
以获取有关代理行为的更多信息。
-
DEBUG
显示- 代理读取的代理配置
- 事务和跨度创建、激活和停用事件
-
TRACE
比DEBUG
更详细- 每次激活或停用事务或跨度时都会打印堆栈跟踪
- 发送到 apm-server 的所有数据都包含在 JSON 格式中
寻求帮助时,请始终发布日志文件的全部内容。使用此过程确保在报告潜在问题时获得一致的日志。
代理启动时,您应该看到类似以下的日志
[main] INFO co.elastic.apm.agent.configuration.StartupInfo - Starting Elastic APM (unknown version) on Java 10 (Oracle Corporation) Mac OS X 10.13.6 [apm-server-healthcheck] INFO co.elastic.apm.agent.report.ApmServerHealthChecker - Elastic APM server is available: {"build_date":"2018-11-05T07:58:08Z","build_sha":"dffb98a72a262ca22adad0152f0245ea743ea904","version":"7.0.0-alpha1"} [main] DEBUG co.elastic.apm.agent.configuration.StartupInfo - service_name: 'elastic-apm-test' (source: Java System Properties) [main] DEBUG co.elastic.apm.agent.configuration.StartupInfo - log_level: 'DEBUG' (source: Java System Properties)
在发布日志文件之前,请确保对您的应用程序执行一些请求。每个请求至少应在日志中添加一些类似以下的行
[http-nio-8080-exec-10] DEBUG co.elastic.apm.agent.impl.ElasticApmTracer - startTransaction '' 00-2a82cbe3df7a0208f7be6da65be260d1-05e72d045206587a-01 { [http-nio-8080-exec-10] DEBUG co.elastic.apm.agent.impl.ElasticApmTracer - Activating '' 00-2a82cbe3df7a0208f7be6da65be260d1-05e72d045206587a-01 on thread 66 [http-nio-8080-exec-10] DEBUG co.elastic.apm.agent.impl.transaction.SpanImpl - startSpan '' 00-2a82cbe3df7a0208f7be6da65be260d1-b2ffa0401105e3d8-01 { [http-nio-8080-exec-10] DEBUG co.elastic.apm.agent.impl.ElasticApmTracer - Activating 'APIRestController#products' 00-2a82cbe3df7a0208f7be6da65be260d1-b2ffa0401105e3d8-01 on thread 66 [http-nio-8080-exec-10] DEBUG co.elastic.apm.agent.impl.transaction.SpanImpl - startSpan '' 00-2a82cbe3df7a0208f7be6da65be260d1-49b9d805eca42ec6-01 { [http-nio-8080-exec-10] DEBUG co.elastic.apm.agent.impl.ElasticApmTracer - Activating '' 00-2a82cbe3df7a0208f7be6da65be260d1-49b9d805eca42ec6-01 on thread 66 [http-nio-8080-exec-10] DEBUG co.elastic.apm.agent.impl.ElasticApmTracer - Deactivating 'SELECT' 00-2a82cbe3df7a0208f7be6da65be260d1-49b9d805eca42ec6-01 on thread 66 [http-nio-8080-exec-10] DEBUG co.elastic.apm.agent.impl.transaction.SpanImpl - endSpan 'SELECT' 00-2a82cbe3df7a0208f7be6da65be260d1-49b9d805eca42ec6-01 [apm-reporter] DEBUG co.elastic.apm.agent.report.IntakeV2ReportingEventHandler - Receiving SPAN event (sequence 23) [apm-reporter] DEBUG co.elastic.apm.agent.report.IntakeV2ReportingEventHandler - Starting new request to http://127.0.0.1:8200/intake/v2/events [http-nio-8080-exec-10] DEBUG co.elastic.apm.agent.impl.ElasticApmTracer - Deactivating 'APIRestController#products' 00-2a82cbe3df7a0208f7be6da65be260d1-b2ffa0401105e3d8-01 on thread 66 [http-nio-8080-exec-10] DEBUG co.elastic.apm.agent.impl.transaction.SpanImpl - endSpan 'APIRestController#products' 00-2a82cbe3df7a0208f7be6da65be260d1-b2ffa0401105e3d8-01 [apm-reporter] DEBUG co.elastic.apm.agent.report.IntakeV2ReportingEventHandler - Scheduling request timeout in 10s [apm-reporter] DEBUG co.elastic.apm.agent.report.IntakeV2ReportingEventHandler - Receiving SPAN event (sequence 24) [http-nio-8080-exec-10] DEBUG co.elastic.apm.agent.impl.ElasticApmTracer - Deactivating 'APIRestController#products' 00-2a82cbe3df7a0208f7be6da65be260d1-05e72d045206587a-01 on thread 66 [http-nio-8080-exec-10] DEBUG co.elastic.apm.agent.impl.ElasticApmTracer - endTransaction 'APIRestController#products' 00-2a82cbe3df7a0208f7be6da65be260d1-05e72d045206587a-01 [apm-reporter] DEBUG co.elastic.apm.agent.report.IntakeV2ReportingEventHandler - Receiving TRANSACTION event (sequence 25)
如果在日志中没有看到任何内容,则您使用的技术堆栈可能不受支持。
之后,您应该看到指示代理已成功将数据发送到 APM 服务器的日志
[apm-request-timeout-timer] DEBUG co.elastic.apm.agent.report.IntakeV2ReportingEventHandler - Request flush because the request timeout occurred [apm-reporter] DEBUG co.elastic.apm.agent.report.IntakeV2ReportingEventHandler - Receiving FLUSH event (sequence 26) [apm-reporter] DEBUG co.elastic.apm.agent.report.IntakeV2ReportingEventHandler - Flushing 10912 uncompressed 2667 compressed bytes
如果 APM 服务器响应 400,则可能表示 JSON 验证错误。日志将包含无法验证的实际文档
[apm-reporter] INFO co.elastic.apm.agent.report.IntakeV2ReportingEventHandler - Backing off for 0 seconds (±10%) [apm-reporter] WARN co.elastic.apm.agent.report.IntakeV2ReportingEventHandler - Server returned HTTP response code: 400 for URL: http://127.0.0.1:8200/intake/v2/events [apm-reporter] WARN co.elastic.apm.agent.report.IntakeV2ReportingEventHandler - {"accepted":13,"errors":[{"message":"Problem validating JSON document against schema: I[#] S[#] doesn't validate with \"span#\"\n I[#] S[#/allOf/2] allOf failed\n I[#] S[#/allOf/2/required] missing properties: \"transaction_id\"","document":"{\"span\":{\"name\":\"OpenTracing product span\",\"timestamp\":29352159207,\"id\":\"aeaa7e0ac95acad6\",\"trace_id\":\"d88b5cbfc4536f9a700cd114a53bfeae\",\"parent_id\":\"082fd71ce7e4089a\",\"duration\":17.992,\"context\":{\"tags\":{\"productId\":\"1\"}},\"type\":\"unknown\"}}"}]}
捕获日志过程
编辑理想情况下,这应该在生产环境之外进行。
- 它需要重新启动应用程序
- 使用
DEBUG
日志级别时,日志可能非常冗长,使用TRACE
日志级别时,日志将更加冗长。 - 日志中只有少量事务可以使调查更容易,生产流量会产生噪声。
- 如果不可能,我们仍然可以在生产环境中使用它几分钟,当使用外部配置文件(文档)时,
log_level
可以在运行时更改。
大多数调查都需要使用DEBUG
日志级别,因此除非要求使用TRACE
,否则请使用DEBUG
。
在这里,我们将代理日志文件称为/tmp/agent.log
,但可以使用任何其他位置。
代理匹配启发式方法
编辑代理依靠启发式方法来有效地定义哪些类需要检测或不需要检测,以防止检测开销。
这些启发式方法基于包和类名称,并受application_packages
和jms_listener_packages
配置的影响。但是,如果检测未按预期应用,或者如果您想在不了解应用程序内部结构的情况下调查创建配置,则禁用这些启发式方法进行调查可能相关
- 通过设置
enable_type_matching_name_pre_filtering=false
禁用名称启发式方法并启用代理日志。 - 重新启动应用程序,由于额外的开销,它将比平时慢
- 通过过滤包含
Method match
字符串的行来分析代理日志,以识别哪些类/方法已被检测。 - 使用适用的值正确配置
application_packages
或jms_listener_packages
调试
编辑有时仅仅阅读日志不足以调试问题。由于代理是开源的并在 Maven Central 上发布,因此调试代理代码非常容易。
为了让您的 IDE 下载源代码,首先声明对代理的依赖项。
代理是通过-javaagent
标志添加的。因此,您必须确保以不会两次将代理添加到类路径的方式声明依赖项。例如,当您正在开发 Web 应用程序时,请确保代理未打包在您的 war 文件的WEB-INF/lib
中。在 IDE 的调试窗口中,请确保apm-agent
未出现在-classpath
中。
pom.xml。
<dependency> <groupId>co.elastic.apm</groupId> <artifactId>apm-agent</artifactId> <version>${elastic-apm.version}</version> <scope>provided</scope> </dependency>
即使将scope
设置为provided
,IntelliJ 有时也会将代理添加到类路径。一种解决方法是将scope
设置为test
。
build.gradle。
compileOnly "co.elastic.apm:apm-agent:$elasticApmVersion"
在 1.26.0 之前的版本中,您需要声明对elastic-apm-agent
模块的依赖项,而不是apm-agent
常见问题
编辑Kibana APM 应用程序中没有数据
编辑此问题的最常见原因是代理和 APM 服务器之间的连接问题。
如果 APM 服务器未收到来自代理的数据,请检查代理是否能够建立与服务器的连接。在代理日志中,查找包含Elastic APM server is available
和Elastic APM server is not available
的日志。
如果您看到消息Elastic APM server is not available
,则表示代理在连接到 APM 服务器时遇到问题。检查server_url
的设置,并确保代理能够连接到服务器。尝试从代理运行的机器上执行curl -v <apm-server-url>
。服务器应以 200 状态代码响应。
如果 APM 服务器未成功响应,请查看 APM 服务器日志以验证服务器是否正在运行。还要确保配置防火墙,以便代理运行的主机可以打开到 APM 服务器的 HTTP 连接。
Kibana APM 应用程序显示“未知路由”
编辑默认情况下,事务使用处理请求的 Servlet 名称命名。因此,如果请求未到达 Servlet,代理将默认将事务命名为“未知路由”
这可能发生的原因有两个
- 请求到达 Servlet,但代理无法正确检测到它们。
-
请求未到达 Servlet。它可能是由过滤器、静态资源等处理的。
- 请求到达 Servlet
-
代理具有一个预过滤器启发式方法,只考虑名称以Servlet结尾的类。可以通过设置内部配置
enable_type_matching_name_pre_filtering=false
来禁用此启发式方法。请注意,这会影响所有插件。预计应用程序启动时间会有少量开销增加。
- 请求未到达 Servlet
-
可以更改默认事务命名以使用 URL 路径。有关更多信息,请参阅
use_path_as_transaction_name
( [1.0.0] 在 1.0.0 中添加。自 1.22.0 版本起,可以在运行时更改此值 )。不幸的是,如果事务路径相似,这可能会创建大量重复的事务。例如,在
/usr/{id}
中,其中{id}
是用户 ID,最终事务数量可能与用户数量一样多。您可以使用url_groups
(已弃用)来减轻这个问题,它允许在事务 URL 中使用通配符。
如果建议的修复方案无法解决问题,或者需要自定义名称,则可以使用我们的 API 在整个请求处理流程中手动设置事务名称。
-
Transaction currentTransaction()
获取当前事务。 -
Transaction setName(String name)
设置事务名称。
针对旧版 Java 版本编译的库
编辑如果您的应用程序中出现类似这样的警告,则表示您正在使用针对非常旧的 Java 版本编译的库。
org.apache.commons.dbcp.DelegatingStatement uses an unsupported class file version (pre Java 5) and can't be instrumented. Consider updating to a newer version of that library.
这主要涉及 JDBC 驱动程序。将它们更新到较新的版本应该可以解决问题。
找不到 Premain-Class 清单属性
编辑如果您使用的是带有-javaagent
标志针对应用程序服务器的手动设置,并且看到Failed to find Premain-Class manifest attribute
错误以及启动失败,则您可能指向了错误的 jar 文件。
指向的正确 jar 文件应为elastic-apm-agent-<version>.jar
形式,有关如何下载此文件的更多信息,请参阅手动设置说明。
与 APM 服务器的通信
编辑unable to find valid certification path to requested target
- 服务器身份验证失败。请查看APM 服务器证书身份验证。
java.net.SocketException: Broken pipe
- 一个可能的原因是客户端身份验证失败。请查看代理证书身份验证。
对于其他与 SSL/TLS 相关的問題,请查看JSSE 故障排除部分。您可以将-Djavax.net.debug=all
添加到 JVM 命令行以获取有关问题的更多详细信息。
不常见的问题
编辑JVM 崩溃
编辑通常情况下,JVM 崩溃表明 JVM 中的错误是由在被跟踪应用程序及其依赖项的特定配置中安装 Java 代理而导致的。因此,首先尝试将 JVM 升级到最新的次要版本。
已知问题
- 更新 40 之前的早期 Java 8 版本不受支持,因为它们存在一些错误,这些错误可能会在 Java 代理处于活动状态时导致 JVM 崩溃,因此代理在这些版本上将无法启动。
- 类似地,更新 60 之前的 Java 7 版本不受支持,因为它们在
invokedynamic
方面存在错误。 -
已知更新 60 后的 Java 7 版本和更新 40 之前的早期 Java 8 版本会在启动后(有时很久之后)的某个随机点与代理版本 1.18.0-1.20.0 崩溃,这是由于一个错误导致 C2 编译器创建错误的本机代码。此类崩溃的症状是不确定的。为了防止此类崩溃,我们在代理版本 1.21.0 中添加了内置的延迟以进行代理初始化,这将自动应用于这些 Java 版本。如果代理版本 > 1.20.0 仍然发生崩溃,请尝试以下方法之一
- 将
-XX:CompileCommand=exclude,java.lang.invoke.LambdaForm*::*
添加到命令行以避免有问题的 JIT 编译。 - 通过设置
elastic.apm.delay_agent_premain_ms
系统属性来增加默认值(3000 毫秒)的延迟,以指示要延迟的毫秒数,例如通过命令行:-Delastic.apm.delay_agent_premain_ms=10000
。
- 将
- 当
profiling_inferred_spans_enabled
( [1.15.0] 在 1.15.0 中添加。 实验性)设置为true
时,它使用一个本机库从 JVM 收集低级信息。到目前为止,所有已知问题都已修复。如果您认为崩溃可能与此相关,请尝试禁用它。我们持续升级到最新的异步分析器版本,因此将您的代理升级到最新版本可能已经包含修复程序。
每当遇到 JVM 崩溃时,请通过我们的论坛或通过在我们的GitHub 存储库上创建一个问题来报告。查找崩溃日志(例如hs_err_pid<PID>.log
)并在报告时提供它,以及描述您的设置和场景的所有因素。
JVM 挂起
编辑如果您的 JVM 在附加 Java 代理时挂起,请创建一个线程转储(例如,通过jstack
),并通过我们的论坛或通过在我们的GitHub 存储库上创建一个问题来报告。
使用jlink
的自定义 Java 运行时
编辑如果您使用jlink
创建自定义运行时,请确保添加以下模块:--add-modules java.base,java.logging,java,jdk.zipfs,java.management,jdk.management
禁用代理
编辑如果代理意外导致生产应用程序中断,您可以在进行故障排除时禁用代理。
使用动态配置,您可以通过将recording
设置为false
来禁用事件的记录。
如果这不起作用,您可以通过将enabled
设置为false
来完全禁用代理。您需要重新启动应用程序才能使此更改生效。
不受支持的框架版本
编辑- JSF - 一些 2.2.x 版本的 myfaces 在 JDK 15 上不受支持 - 请参阅相关错误。