NLog对运行在Azure Web App上的任何自定义目标抛出``找不到目标''

时间:2019-06-21 15:23:10

标签: asp.net azure nlog

我已经在.NET Standard 2.0上创建了两个NLog自定义目标,并将它们导入到现有的ASP.NET 4.7.2网站中。

nlog.config看起来像这样:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true"
      internalLogLevel="Info"
      internalLogFile="${basedir}/internal-nlog.txt"
      throwExceptions="true"
      throwConfigExceptions="true">

    <extensions>
        <add assembly="MyAssembly"/>
    </extensions>

    <targets async="false">
        <target name="logconsole" xsi:type="Console" />
        <target xsi:type="AzureTableTarget"
                  name="azureTable"
                  // some configs
        />
        <target xsi:type="PostmarkLogTarget"
                  name="postmark"
                  // some configs
        />
    </targets>

    <rules>
        <logger name="*" minlevel="Warn" writeTo="postmark" />
        <logger name="*" minlevel="Info" writeTo="azureTable" />
        <logger name="*" minlevel="Debug" writeTo="logconsole" />
    </rules>
</nlog>

当应用在本地启动时,一切正常。当它在Azure App Service上启动时,我在nlog内部日志(以及一个大的错误页面)中得到了这个信息:

2019-06-21 15:08:53.5719 Info Message Template Auto Format enabled
2019-06-21 15:08:53.6015 Info Loading assembly: MyAssembly
2019-06-21 15:08:53.6926 Info Adding target ConsoleTarget(Name=logconsole)
2019-06-21 15:08:53.7595 Error Parsing configuration from D:\home\site\wwwroot\NLog.config failed. Exception: NLog.NLogConfigurationException: Exception when parsing D:\home\site\wwwroot\NLog.config.  ---> System.ArgumentException: Target cannot be found: 'AzureTableTarget'
   at NLog.Config.Factory`2.CreateInstance(String itemName)
   at NLog.Config.LoggingConfigurationParser.ParseTargetsElement(ILoggingConfigurationElement targetsElement)
   at NLog.Config.LoggingConfigurationParser.ParseNLogSection(ILoggingConfigurationElement configSection)
   at NLog.Config.XmlLoggingConfiguration.ParseNLogSection(ILoggingConfigurationElement configSection)
   at NLog.Config.LoggingConfigurationParser.LoadConfig(ILoggingConfigurationElement nlogConfig, String basePath)
   at NLog.Config.XmlLoggingConfiguration.ParseNLogElement(ILoggingConfigurationElement nlogElement, String filePath, Boolean autoReloadDefault)
   at NLog.Config.XmlLoggingConfiguration.ParseTopLevel(NLogXmlElement content, String filePath, Boolean autoReloadDefault)
   at NLog.Config.XmlLoggingConfiguration.Initialize(XmlReader reader, String fileName, Boolean ignoreErrors)
   --- End of inner exception stack trace ---
2019-06-21 15:08:53.8489 Error Failed loading from config file location: D:\home\site\wwwroot\NLog.config Exception: NLog.NLogConfigurationException: Exception when parsing D:\home\site\wwwroot\NLog.config.  ---> System.ArgumentException: Target cannot be found: 'AzureTableTarget'
   at NLog.Config.Factory`2.CreateInstance(String itemName)
   at NLog.Config.LoggingConfigurationParser.ParseTargetsElement(ILoggingConfigurationElement targetsElement)
   at NLog.Config.LoggingConfigurationParser.ParseNLogSection(ILoggingConfigurationElement configSection)
   at NLog.Config.XmlLoggingConfiguration.ParseNLogSection(ILoggingConfigurationElement configSection)
   at NLog.Config.LoggingConfigurationParser.LoadConfig(ILoggingConfigurationElement nlogConfig, String basePath)
   at NLog.Config.XmlLoggingConfiguration.ParseNLogElement(ILoggingConfigurationElement nlogElement, String filePath, Boolean autoReloadDefault)
   at NLog.Config.XmlLoggingConfiguration.ParseTopLevel(NLogXmlElement content, String filePath, Boolean autoReloadDefault)
   at NLog.Config.XmlLoggingConfiguration.Initialize(XmlReader reader, String fileName, Boolean ignoreErrors)
   --- End of inner exception stack trace ---
   at NLog.Config.XmlLoggingConfiguration.Initialize(XmlReader reader, String fileName, Boolean ignoreErrors)
   at NLog.Config.XmlLoggingConfiguration..ctor(XmlReader reader, String fileName, Boolean ignoreErrors, LogFactory logFactory)
   at NLog.Config.LoggingConfigurationFileLoader.LoadXmlLoggingConfiguration(XmlReader xmlReader, String configFile, LogFactory logFactory)
   at NLog.Config.LoggingConfigurationFileLoader.LoadXmlLoggingConfigurationFile(LogFactory logFactory, String configFile)
   at NLog.Config.LoggingConfigurationFileLoader.TryLoadLoggingConfiguration(LogFactory logFactory, String configFile, LoggingConfiguration& config)
2019-06-21 15:08:54.1153 Info Configuring from an XML element in D:\home\site\wwwroot\NLog.config...
2019-06-21 15:08:54.1457 Info Message Template Auto Format enabled
2019-06-21 15:08:54.1457 Info Loading assembly: MyAssembly
2019-06-21 15:08:54.1457 Info Adding target ConsoleTarget(Name=logconsole)
2019-06-21 15:08:54.3332 Info Adding target AzureTableTarget(Name=azureTable)
2019-06-21 15:08:54.3525 Info Adding target PostmarkLogTarget(Name=postmark)
2019-06-21 15:08:54.4120 Info Found 38 configuration items
2019-06-21 15:08:54.4738 Info Configuration initialized.

第二次加载是因为我在global.asax.cs中有代码可以专门注册和配置目标。设置AutoFac之后,任何尝试登录到任何地方之前,此代码都会立即触发。

在本地运行,即使在发布模式下,代码也按顺序执行这些步骤。在Azure上运行时,它似乎尝试在配置完成之前记录一条消息。

即使是这种情况,两个自定义目标都有默认的公共构造函数,因此NLog应该能够自动实例化它们。 (这就是为什么我在设置目标后重新加载配置的原因。)

两个问题:

  1. Azure App Service导致(或允许)NLog这样跳动的是什么?

  2. 删除nlog.config并设置登录代码的时间短,如何防止这种行为发生?

2 个答案:

答案 0 :(得分:1)

找到了。哇!

我将此代码挂在.cs文件中:

public static readonly Logger Logger = LogManager.GetCurrentClassLogger();

在App Service部署中,包含该行的类的静态构造函数在App_Start完成之前运行。在我的本地盒子上没有。

所以我将其更改为:

public static Logger Logger => _logger ?? (_logger = LogManager.GetCurrentClassLogger());
private static Logger _logger;

...现在一切正常。记录器仅在使用时创建,而不仅仅是因为ASP.NET希望提前实例化静态类。

答案 1 :(得分:0)

  

找不到目标:“ AzureTableTarget”

这意味着无法在其中一个程序集中找到目标类'AzureTableTarget',因此无法创建实例。

您需要告诉NLog在哪个程序集中可以找到AzureTableTarget类型。

类似这样的东西:

<extensions>
    <add assembly="AssemblyNameWhereAzureTableTargetIsDefined"/>
</extensions>
  

Azure App Service导致(或允许)NLog这样跳动的是什么?

是否有相同的程序集?那么发布带有AzureTableTarget的程序集了吗?

  

删除nlog.config并设置代码登录的简短过程

在这种情况下,从文件还是从代码配置NLog都没关系。

  

如何防止这种行为发生?

始终将所有外部NLog扩展名添加到<extensions>

最后但并非最不重要的是,不建议将throwExceptions="true"用于生产! (如果您的日志记录中断了,您是否真的喜欢您的应用程序中断?)