故障排除编辑

使用本节中的信息对常见问题进行故障排除,并找到常见问题的答案。第一步,请确保您的堆栈与代理的支持的技术兼容。

如果您无法确定问题所在,请不要担心;我们随时为您提供帮助。如果您是拥有支持合同的现有 Elastic 客户,请在Elastic 支持门户中创建故障单。如果不是,请在APM 讨论论坛中发帖。

请附上您的调试日志,以便我们分析问题。将完整日志上传到https://gist.github.com等服务。日志应包含从应用程序启动到第一个请求执行的所有内容。

没有数据发送到 APM 服务器编辑

如果既没有错误也没有性能指标发送到 APM 服务器,最好先检查您的日志并查找应用程序启动时的输出。

如果您在代理日志中没有看到任何可疑内容(没有警告或错误),建议将日志级别设置为Trace 以进行进一步调查。

收集代理日志编辑

收集日志的方式取决于应用程序的设置。

ASP.NET Core编辑

如果您按照ASP.NET Core文档使用UseAllElasticApmUseElasticApm 方法将代理添加到应用程序中,它将与ASP.NET Core 日志记录基础结构集成。这意味着代理将获取配置的日志记录提供程序,并像任何其他组件日志一样记录。

在这种情况下,LogLevel APM 代理配置(例如,设置ELASTIC_APM_LOG_LEVEL 环境变量)不会控制代理日志的详细程度。代理日志由IConfiguration 中的 ASP.NET Core 日志记录配置控制,通常通过appsettings.json 配置。

例如,appsettings.json 中的以下配置将 APM 代理日志限制为日志级别为Warning 或更高级别的日志

"Logging": {
  "LogLevel": {
    "Default": "Information",
    "Elastic.Apm": "Warning" 
  }
},

通过设置Elastic.Apm 类别的日志级别来控制代理日志的详细程度

ASP.NET Classic编辑

ASP.NET(经典)没有预定义的日志记录系统。默认情况下,代理配置为使用源名称"Elastic.Apm" 将日志消息发送到System.Diagnostics.TraceSource。TraceSource 遵循 APM 代理配置中定义的日志级别。通常,您将使用web.config 中的应用程序设置来配置首选日志级别。

System.Diagnostics.TraceSource 要求指定TRACE 编译器指令,默认情况下,调试和发布构建配置都指定了该指令。

可以使用<system.diagnostics> 部分的 web.config 配置TraceListeners 来监视跟踪源的日志消息。例如,以下 web.config 部分将 Elastic.Apm 日志消息写入名为 my_log_file.log 的文件

<configuration>
  <!-- other sections .... -->
  <system.diagnostics>
  <sources>
    <source name="Elastic.Apm"> 
      <listeners>
        <add name="file"
          type="System.Diagnostics.TextWriterTraceListener"
          initializeData="my_log_file.log" />
      </listeners>
    </source>
  </sources>
</system.diagnostics>
</configuration>

在名为"Elastic.Apm" 的源下定义侦听器以捕获代理日志

其他日志记录系统编辑

如果您有现有的日志记录系统,例如NLogSerilog 或类似系统,则可以通过在代理的内部记录器和日志记录系统之间创建适配器,将代理日志定向到您的日志记录系统。

首先实现Elastic.Apm.Logging 命名空间中的IApmLogger 接口

internal class ApmLoggerAdapter : IApmLogger
{
	private readonly Lazy<Logger> _logger;
	public bool IsEnabled(ApmLogLevel level)
	{
		// Check for log level here.
		// Typically you just compare the configured log level of your logger
		// to the input parameter of this method and return if it's the same/higher or not
	}

	public void Log<TState>(ApmLogLevel apmLogLevel, TState state, Exception e, Func<TState, Exception, string> formatter)
	{
		// You can log the given log into your logging system here.
	}
}

您可以在我们的 GitHub 存储库中看到 NLog 的示例实现。

然后告诉代理使用ApmLoggerAdapter。对于 ASP.NET(经典),请将以下代码放入应用程序的HttpApplication 实现中的Application_Start 方法中,该方法通常位于Global.asax.cs 文件中

using Elastic.Apm.AspNetFullFramework;

namespace MyApp
{
	public class MyApplication : HttpApplication
	{
		protected void Application_Start()
		{
			AgentDependencies.Logger = new ApmLoggerAdapter();

			// other application setup...
		}
	}
}

在初始化期间,代理会检查是否配置了其他记录器——代理只执行一次此操作,因此在进程中尽早设置它非常重要,通常在Application_Start 方法中。

通用 .NET 应用程序编辑

如果上述情况均不适用于您的应用程序,您仍然可以使用记录器适配器并将代理日志重定向到 .NET 日志记录系统,例如 NLog、Serilog 或类似系统。

为此,您需要一个IApmLogger 实现(见上文),您需要在代理设置期间将其传递给Setup 方法

Agent.Setup(new AgentComponents(logger: new ApmLoggerAdapter()));

日志中出现以下错误:单例 APM 代理已被实例化,无法再进行配置。编辑

请参阅“抛出InstanceAlreadyCreatedException 异常”。

抛出InstanceAlreadyCreatedException 异常编辑

在受监控进程的早期阶段,代理可能会抛出InstanceAlreadyCreatedException 异常,并显示以下消息:“单例 APM 代理已被实例化,无法再进行配置。”,或者出现包含相同消息的错误日志。当您尝试多次初始化代理时会发生这种情况,这是不允许的。允许多个代理实例每个进程都会导致问题,例如多次捕获每个实例的事件和指标,或者为事件序列化和传输到 APM 服务器使用多个后台线程。

有关代理初始化工作原理的更多信息,请查看公共代理 API的初始化部分。

例如,如果您多次调用Elastic.Apm.Agent.Setup 方法,或者如果您在Elastic.Apm.Agent 上调用了另一个隐式初始化代理的方法,然后在已初始化的代理上调用Elastic.Apm.Agent.Setup 方法,则可能会发生此问题。

另一个例子是,当您将公共代理 API 与 IIS 模块或 ASP.NET Core NuGet 包结合使用时,您使用UseElasticApmUseAllElasticApm 方法启用代理。对 IIS 模块的第一次调用和UseElasticApm/UseAllElasticApm 方法都会在内部调用Elastic.Apm.Agent.Setup 方法来初始化代理。

您可以在代码中使用公共代理 API 和Elastic.Apm.Agent 类,这些代码可能会在 IIS 模块初始化或UseElasticApm/UseAllElasticApm 调用执行之前执行。如果发生这种情况,这些操作将失败,因为代理已被隐式初始化。

为了防止在这些情况下出现InstanceAlreadyCreatedException,首先使用Elastic.Apm.Agent.IsConfigured 方法检查代理是否已初始化。检查后,您可以安全地使用公共代理 API 中的其他方法。这将防止意外的隐式代理初始化。

ASP.NET 正在使用 LegacyAspNetSynchronizationContext,并且可能无法很好地处理异步代码编辑

如果您看到记录了此警告,则表示您的经典 ASP.NET 应用程序正在 quirks 模式下运行,并且正在使用已弃用但向后兼容的异步上下文。当异步代码引入线程切换时,这可能会阻止我们的代理正常工作,因为此上下文无法可靠地还原HttpContext.Items

要退出 quirks 模式,必须在 web.config 中显式指定运行时

<httpRuntime targetFramework="4.5" />

在此处详细了解 ASP.NET quirks 模式:https://devblogs.microsoft.com/dotnet/all-about-httpruntime-targetframework

SqlEventListener 无法捕获 sql 语句(无法从 ProcessingSpans 中删除)。编辑

当我们的 SQL 事件侦听器无法找到活动事务时,我们会记录此警告。仅在应用程序在 quirks 模式下运行时,才会在 IIS 下观察到这种情况。有关更多背景信息和可能的修复方法,请参阅“ASP.NET 正在使用 LegacyAspNetSynchronizationContext,并且可能无法很好地处理异步代码”部分。

HttpDiagnosticListenerFullFrameworkImpl 没有当前事务,跳过为传出的 HTTP 请求创建 span编辑

当我们的传出 HTTP 侦听器无法获取当前事务时,我们会记录此跟踪警告。这仅在 IIS 下以 quirks 模式运行应用程序时才会观察到。有关更多背景信息和可能的修复方法,请参阅“ASP.NET 正在使用 LegacyAspNetSynchronizationContext,并且可能无法很好地处理异步代码”部分。

异常:System.PlatformNotSupportedException:此操作需要 IIS 集成管道模式编辑

如果在强制使用经典管道模式的应用程序池下运行经典 ASP.NET 应用程序,则会发生此异常。这会阻止我们的代理修改标头,从而破坏分布式跟踪。

该代理仅在 IIS7 及更高版本(其中 集成管道模式 为默认模式)上受支持。

启动钩子失败编辑

如果 启动钩子 集成引发异常,则可以通过在启动应用程序之前设置 ELASTIC_APM_STARTUP_HOOKS_LOGGING 环境变量来获取更多详细信息

set ELASTIC_APM_STARTUP_HOOKS_LOGGING=1

然后在环境变量可见的上下文中运行应用程序。设置此值后,除了写入标准输出外,还会将 ElasticApmAgentStartupHook.log 文件写入包含启动钩子程序集的目录。

代理导致开销过大编辑

一个好的起点是 所有选项摘要。有多个设置带有 性能 关键字,可以帮助您根据需要调整代理。

代理中最昂贵的操作通常是堆栈跟踪捕获。默认情况下,代理仅捕获持续时间为 5 毫秒或更长的 span 的堆栈跟踪,并且限制为 50 个堆栈帧。如果在您的环境中这太多了,请考虑部分或完全禁用堆栈跟踪捕获

ElasticApmModule 不加载或捕获事务,并且在 IISExpress 上没有生成代理日志编辑

使用 Visual Studio 和 IISExpress 调试应用程序时,也需要使用 集成 托管管道模式。在解决方案资源管理器中选择您的 Web 应用程序项目,然后按 F4 加载属性窗口。如果托管管道模式设置为经典,则 ElasticApmModule 将不会加载。

例如

Classic Managed Pipeline Mode in Properties

应该改为

Integrated Managed Pipeline Mode in Properties

您可能需要重新启动 Visual Studio 才能使这些更改完全生效。