故障排除编辑

某些东西没有按预期工作?以下是一些找出问题所在的方法。

第一步,请检查您的堆栈是否与当前支持的技术兼容。

如果您无法找出问题所在,请在APM 讨论论坛中创建一个主题,我们会帮助您解决问题。

如果您这样做,请附上您的调试日志,以便我们分析问题。将完整日志上传到像https://gist.github.com这样的服务。日志应包括从应用程序启动到第一个请求执行的所有内容。除了代理和应用程序日志外,请在所有服务的标准输出和标准错误日志中查找[elastic-apm-agent]条目,我们有时会在日志不可用时打印有用的信息。

更新到最新代理版本编辑

代理会经常更新,并且版本发布与堆栈中的其他组件没有强绑定关系。

因此,尝试更新到最新发布的代理版本通常是推荐的第一步故障排除步骤。如果可能,尝试使用最新快照甚至更好,因为它将包含尚未发布的修复程序。

有关更多详细信息,请参阅升级文档

与其他代理一起运行编辑

与许多其他 Java 代理一样,我们的代理通过在运行时将字节码注入类来对类进行检测。我们的字节码检测保证只生成有效的字节码,并且永远不会更改类的“模式”。如果您除了我们之外还使用其他具有相同保证的 Java 代理,它们不应该相互干扰。但是,一些 Java 代理不符合这些保证,在这种情况下,可能存在与我们并行使用它们的问题。如果您遇到错误,首先要做的事情之一是删除任何其他代理,以检查这是否确实是代理不匹配的情况。我们仍然可以找到一种方法让它们一起工作,但此信息对于我们提供帮助至关重要,因此请确保在报告此类问题时包含它。

日志记录编辑

有几个与日志记录相关的配置选项。其中最重要的一个是log_level

将日志级别设置为DEBUG甚至TRACE以获取有关代理行为的更多信息。

  • DEBUG显示

    • 代理读取的代理配置
    • 事务和跨度创建、激活和停用事件
  • TRACEDEBUG更详细

    • 每次事务或跨度激活或停用时都会打印一个堆栈跟踪
    • 发送到 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.Span - 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.Span - 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.Span - 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.Span - 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日志级别,因此请使用DEBUG,除非要求使用TRACE

在这里,我们将代理日志文件称为/tmp/agent.log,但可以使用任何其他位置。

  1. 使用log_level=debuglog_level=trace文档)和log_file=/tmp/agent.log文档)配置代理
  2. 截断/tmp/agent.log文件并重新启动应用程序
  3. 执行一些代理无法正确捕获的事务
  4. 复制/tmp/agent.log文件并将其发送回去以供调查

代理匹配启发式方法编辑

代理依赖于启发式方法来有效地定义哪些类需要进行检测或不进行检测,以防止检测开销。

这些启发式方法基于包和类名,并受application_packagesjms_listener_packages配置的影响。但是,如果检测没有按预期应用,或者您想在没有正确了解应用程序内部结构的情况下调查创建配置,那么禁用这些启发式方法以进行调查可能相关

  1. 通过设置enable_type_matching_name_pre_filtering=false禁用名称启发式方法并启用代理日志
  2. 重新启动应用程序,由于额外的开销,应用程序将比平时慢
  3. 通过过滤包含Method match字符串的行来分析代理日志,以识别哪些类/方法被检测到。
  4. 使用适用的值正确配置application_packagesjms_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 availableElastic 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,代理将默认将事务命名为“未知路由”。

这可能发生的原因有两个:

  1. 请求到达 Servlet,但代理无法正确检测到它们。
  2. 请求未到达 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 手动设置事务名称。

针对旧版 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 仍然发生崩溃,请尝试以下操作之一

    1. -XX:CompileCommand=exclude,java.lang.invoke.LambdaForm*::*添加到命令行以避免有问题的 JIT 编译
    2. 通过设置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 - myfaces 一些 2.2.x 版本在 JDK 15 上不受支持 - 请参阅相关错误