log4net ADO.NET Appender работает в Dev Fabric, но тихо завершает работу в Azure

Я использую приложение ADO.NET для приложения log4net для записи сообщений рабочей роли Azure в экземпляр SQL Azure (диагностика по умолчанию просто не подходит). По какой-то причине, когда рабочий работает в среде разработки, ведение журнала работает. Тем не менее, когда экземпляр развертывается в облаке (с точно такой же конфигурацией), ошибки не регистрируются.

Конфигурация происходит в коде с использованием этого файла:

<?xml version="1.0" encoding="utf-8" ?>
<log4net>
  <renderer renderingClass="{ExceptionRenderer}" renderedClass="System.Exception" />
  <appender name="TraceAppender" type="log4net.Appender.TraceAppender">
    <layout type="log4net.Layout.PatternLayout">
      <!--<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />-->
      <conversionPattern value="%message%newline" />
    </layout>
  </appender>
  <appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
    <bufferSize value="3" />
    <connectionType value="{ConnectionType}" />
    <connectionString value="{ConnectionString}" />
    <commandText value="INSERT INTO Salescast_Log ([Date],[Thread],[Version],[Level],[Logger],[Message],[Exception]) VALUES (@log_date, @thread, '{Version}',@log_level, @logger, @message, @exception)" />
    <parameter>
      <parameterName value="@log_date" />
      <dbType value="DateTime" />
      <layout type="log4net.Layout.RawTimeStampLayout" />
    </parameter>
    <parameter>
      <parameterName value="@thread" />
      <dbType value="String" />
      <size value="255" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%thread" />
      </layout>
    </parameter>
    <parameter>
      <parameterName value="@log_level" />
      <dbType value="String" />
      <size value="50" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%level" />
      </layout>
    </parameter>
    <parameter>
      <parameterName value="@logger" />
      <dbType value="String" />
      <size value="255" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%logger" />
      </layout>
    </parameter>
    <parameter>
      <parameterName value="@message" />
      <dbType value="String" />
      <size value="4000" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%message" />
      </layout>
    </parameter>
    <parameter>
      <parameterName value="@exception" />
      <dbType value="String" />
      <size value="4000" />
      <layout type="{ExceptionLayoutType}" />
    </parameter>
    <filter type="log4net.Filter.LevelRangeFilter">
      <levelMin value="ERROR" />
      <levelMax value="FATAL" />
    </filter>
  </appender>
  <root>
    <level value="DEBUG" />
    <appender-ref ref="TraceAppender" />
    <appender-ref ref="AdoNetAppender" />
  </root>
</log4net>

log4net инициализируется с правильными значениями, когда среда Autofac IoC инициализируется (при запуске каждой роли). Код выглядит так:

static ILogProvider BuildProvider(IComponentContext context)
{
  var connection = context
    .Resolve<IProvideBusSettings>()
    .GetString("SqlConnection")
    .ExposeException("Failed to get SQL string for logging");

  var xml = Properties.Resources.Logging
    .Replace("{ConnectionType}", typeof(SqlConnection).AssemblyQualifiedName)
    .Replace("{ConnectionString}", connection)
    .Replace("{ExceptionLayoutType}", typeof(LoggingTrimmedExceptionLayout).AssemblyQualifiedName)
    .Replace("{ExceptionRenderer}", typeof(LoggingExceptionRenderer).AssemblyQualifiedName)
    .Replace("{Version}", SystemDescriptor.Default.Version.ToString());

  var doc = new XmlDocument();
  doc.LoadXml(xml);
  XmlConfigurator.Configure(doc.DocumentElement);
  return new LoggingProvider();
}

Используется ОС Azure по умолчанию. SQL-соединения, очевидно, действительны.

Может ли кто-нибудь придумать причину, по которой log4net регистрирует ошибки из фабрики разработчиков, но не делает этого из лазурной ОС, используя точно такие же файлы конфигурации службы?

3 ответа

Я просто столкнулся с этим и провел большую часть дня, пытаясь понять это. Все сводилось к тому, что SQL Azure требует кластеризованных индексов в ваших таблицах. Пример кода SQL, предоставленного log4net для создания таблицы журнала, не имеет кластеризованного индекса, что является обязательным требованием для SQL Azure. Добавление каких-либо данных в таблицу не удастся, если только у нее нет кластерного индекса (на момент написания этой записи).

Попробуйте выполнить оператор вставки вручную, используя SQL Server Management Studio при подключении к SQL Azure, и он сразу скажет вам, если это проблема. Если это так, запустите следующий SQL, чтобы добавить кластеризованный индекс в таблицу (при условии, что вы использовали SQL напрямую из log4net), а затем повторите попытку.

CREATE UNIQUE CLUSTERED INDEX PK_Log ON [Log]
  ([Id])
GO

Я могу иметь лидерство в этом вопросе. Я включил внутреннюю регистрацию для log4net, как описано здесь. Регистрация будет работать некоторое время, а затем остановится. Ошибка в журнале log4net:

log4net: ОШИБКА [log4netDbAppender] Сбой в DoAppend System.Data.SqlClient.SqlException (0x80131904): при отправке запроса на сервер произошла ошибка транспортного уровня. (поставщик: поставщик TCP, ошибка: 0 - установленное соединение было прервано программным обеспечением на вашем хост-компьютере.) в System.Data.SqlClient.SqlConnection.OnError(исключение SqlException, Boolean breakConnection) в System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() в System.Data.SqlClient.TdsParserStateObject.WriteSni() в System.Data.SqlClient.TdsParserStateObject.ExecuteFlush() в System.Data.SqlClient.TdsParser.TdsExquiSqSlayEp notificationRequest, TdsParserStateObject stateObj, булева isCommandProc) при System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean, Boolean returnStream асинхронном) в System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, булевой returnStream, Метод String, результат DbAsyncResult) в System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(результат DbAsyncResult, String methodName, логическое sendToPipe) в System.Data.SqlClient.SqlCommand.ExecuteNonQuery() в log4net.Appender.AdoNetAppender.SendBuffer(события IDbTransaction dbTran, LoggingEvent[]) в событиях log4net.Appender.AendEpp
в log4net.Appender.BufferingAppenderSkeleton.Append(LoggingEvent loggingEvent) в log4net.Appender.AppenderSkeleton.DoAppend(LoggingEvent loggingEvent)

Кажется, что log4net перестает пытаться после возникновения этой ошибки. В этой статье описан способ борьбы с этим типом исключений в целом, и его можно использовать для расширения AdoNetAppender.

РЕДАКТИРОВАТЬ Что может помочь, это установка AdoNetAppender.ReconnectOnError = true, по умолчанию это false.

Может ли это быть проблемой с вашими правилами брандмауэра SQL Azure?

Другие вопросы по тегам