0

エンタープライズ ライブラリ 5 のログ ブロックからエラーを取得する方法を知っていますか?

私が知っているように、ロギングの哲学は中断しないことであるため、たとえば構成にエラーがある場合、エラーがスローされることはありません。

しかし、私たちのアプリケーションでは、ロギングが非常に重要であるため、ログなしで実行するよりも、アプリケーションを順不同にする必要があります。

そのため、そのように構成する必要があります。存在する場合はエラーがスローされます。

ここでイベントについて何かを見つけました: Enterprise Library Logging Application Block options

したがって、このイベントをリッスンして、少なくとも独自のエラーをスローできるはずですが、次のコードに GetInstrumentationEventProvider() メソッドが表示されないため、ロギング インストルメンテーションへの参照を取得できませんでした。

LoggingInstrumentationProvider instrumentation = Logger.Writer.GetInstrumentationEventProvider() as LoggingInstrumentationProvider;

instrumentation.failureLoggingError += (s, z) => { throw z.Exception; };

ご協力ありがとうございました。

4

1 に答える 1

2

LoggingInstrumentationProvider の定義がバージョン 4 と 5 の間で変更されてイベントが削除されたため、投稿されたアプローチは Enterprise Library 5 では機能しないと思います。

Enterprise Library が例外を飲み込まないように動作を変更するには、いくつかの方法があります。

  • Enterprise Library のソース コードを変更して、必要な動作を実装する
  • LogWriterImpl/LogSource コードを複製し、コンテナーに挿入します (このアプローチは、Enterprise Library Logging Extensions – Part 1で確認できます)
  • 現在の LoggingInstrumentationProvider 実装をスローするものに置き換えます

最後のアプローチを示します (これが最善だからではなく、最も興味深いからです)。LoggingInstrumentationProviderしたがって、このアプローチを機能させるには、TraceListenerこの新しいTraceListener.

基本的に、カスタムTraceListenerはエラーの特別なソースで使用され、エラーが発生して標準にログを記録しようとしたときに呼び出されますTraceListeners(またはその他のエラーですが、それは典型的なエラー シナリオです)。カスタムTraceListenerがスローされ、LoggingInstrumentationProvider.FireFailureLoggingErrorEvent メソッドが呼び出され、スローされて例外が発生します。(はい、先は長いです!)

最初にカスタムを作成しますLoggingInstrumentationProvider:

[HasInstallableResourcesAttribute]
[PerformanceCountersDefinition(counterCategoryName, "LoggingCountersHelpResource")]
[EventLogDefinition("Application", "Enterprise Library Logging")]
public class MyLoggingInstrumentationProvider : InstrumentationListener, ILoggingInstrumentationProvider
{
    static EnterpriseLibraryPerformanceCounterFactory factory = new EnterpriseLibraryPerformanceCounterFactory();
    private const string TotalLoggingEventsRaised = "Total Logging Events Raised";
    private const string TotalTraceListenerEntriesWritten = "Total Trace Listener Entries Written";

    [PerformanceCounter("Logging Events Raised/sec", "LoggingEventRaisedHelpResource", PerformanceCounterType.RateOfCountsPerSecond32)]
    private EnterpriseLibraryPerformanceCounter logEventRaised;

    [PerformanceCounter(TotalLoggingEventsRaised, "TotalLoggingEventsRaisedHelpResource", PerformanceCounterType.NumberOfItems32)]
    private EnterpriseLibraryPerformanceCounter totalLoggingEventsRaised;

    [PerformanceCounter("Trace Listener Entries Written/sec", "TraceListenerEntryWrittenHelpResource", PerformanceCounterType.RateOfCountsPerSecond32)]
    private EnterpriseLibraryPerformanceCounter traceListenerEntryWritten;

    [PerformanceCounter(TotalTraceListenerEntriesWritten, "TotalTraceListenerEntriesWrittenHelpResource", PerformanceCounterType.NumberOfItems32)]
    private EnterpriseLibraryPerformanceCounter totalTraceListenerEntriesWritten;

    private const string counterCategoryName = "Enterprise Library Logging Counters";
    private IEventLogEntryFormatter eventLogEntryFormatter;

    /// <summary>
    /// Initializes a new instance of the <see cref="LoggingInstrumentationProvider"/> class.
    /// </summary>
    /// <param name="performanceCountersEnabled"><code>true</code> if performance counters should be updated.</param>
    /// <param name="eventLoggingEnabled"><code>true</code> if event log entries should be written.</param>
    /// <param name="applicationInstanceName">The application instance name.</param>
    public MyLoggingInstrumentationProvider(bool performanceCountersEnabled,
                                          bool eventLoggingEnabled,
                                          string applicationInstanceName)
        : base(performanceCountersEnabled, eventLoggingEnabled, new AppDomainNameFormatter(applicationInstanceName))
    {
        this.eventLogEntryFormatter = new EventLogEntryFormatter("Enterprise Library Logging Application Block");//Resources.BlockName);
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="LoggingInstrumentationProvider"/> class.
    /// </summary>
    /// <param name="instanceName">The instance name.</param>
    /// <param name="performanceCountersEnabled"><code>true</code> if performance counters should be updated.</param>
    /// <param name="eventLoggingEnabled"><code>true</code> if event log entries should be written.</param>
    /// <param name="applicationInstanceName">The application instance name.</param>
    public MyLoggingInstrumentationProvider(string instanceName,
                                          bool performanceCountersEnabled,
                                          bool eventLoggingEnabled,
                                          string applicationInstanceName)
        : base(instanceName, performanceCountersEnabled, eventLoggingEnabled, new AppDomainNameFormatter(applicationInstanceName))
    {
        this.eventLogEntryFormatter = new EventLogEntryFormatter("Enterprise Library Logging Application Block");//Resources.BlockName);
    }

    /// <summary>
    /// Fires the <see cref="LoggingInstrumentationProvider.traceListenerEntryWritten"/> event.
    /// </summary>
    public void FireTraceListenerEntryWrittenEvent()
    {
        if (PerformanceCountersEnabled)
        {
            traceListenerEntryWritten.Increment();
            totalTraceListenerEntriesWritten.Increment();
        }
    }

    ///<summary>
    ///
    ///</summary>
    /// <param name="exception">The exception that describes the reconfiguration error.</param>
    public void FireReconfigurationErrorEvent(Exception exception)
    {
        if (exception == null) throw new ArgumentNullException("exception");
        if (EventLoggingEnabled)
        {
            string entryText = eventLogEntryFormatter.GetEntryText("An unknown error occurred reconfiguring the Logging Application Block. Reconfiguration will not take place."
            //Resources.ReconfigurationFailure
            , exception);
            EventLog.WriteEntry(GetEventSourceName(), entryText, EventLogEntryType.Error);
        }
    }

    /// <summary>
    /// </summary>
    /// <param name="message">A message describing the failure.</param>
    /// <param name="exception">The exception that caused the failure..</param>
    public void FireFailureLoggingErrorEvent(string message, Exception exception)
    {
        if (exception == null) throw new ArgumentNullException("exception");
        if (EventLoggingEnabled)
        {
            string entryText = eventLogEntryFormatter.GetEntryText(message, exception);

            EventLog.WriteEntry(GetEventSourceName(), entryText, EventLogEntryType.Error);
        }

        // New Code to throw an exception
        throw exception;
    }

    /// <summary>
    /// </summary>
    /// <param name="configurationException">The exception that describes the configuration error.</param>
    public void FireConfigurationFailureEvent(Exception configurationException)
    {
        if (configurationException == null) throw new ArgumentNullException("configurationException");
        if (EventLoggingEnabled)
        {
            string entryText = eventLogEntryFormatter.GetEntryText("The error occurred while refreshing the logging configuration. The configuration will not be updated."
            //Resources.ConfigurationFailureUpdating
            , configurationException);
            EventLog.WriteEntry(GetEventSourceName(), entryText, EventLogEntryType.Error);
        }
    }

    /// <summary>
    /// Fires the <see cref="LoggingInstrumentationProvider.logEventRaised"/> event.
    /// </summary>
    public void FireLogEventRaised()
    {
        if (PerformanceCountersEnabled)
        {
            logEventRaised.Increment();
            totalLoggingEventsRaised.Increment();
        }
    }

    /// <summary/>
    /// <param name="message"></param>
    public void FireLockAcquisitionError(string message)
    {
        if (EventLoggingEnabled)
        {
            string entryText = eventLogEntryFormatter.GetEntryText(message);
            EventLog.WriteEntry(GetEventSourceName(), entryText, EventLogEntryType.Error);
        }
    }

    /// <summary>
    /// Creates the performance counters to instrument the logging events to the instance names.
    /// </summary>
    /// <param name="instanceNames">The instance names for the performance counters.</param>
    protected override void CreatePerformanceCounters(string[] instanceNames)
    {
        logEventRaised = factory.CreateCounter(counterCategoryName, "Logging Events Raised/sec", instanceNames);
        traceListenerEntryWritten = factory.CreateCounter(counterCategoryName, "Trace Listener Entries Written/sec", instanceNames);
        totalLoggingEventsRaised = factory.CreateCounter(counterCategoryName, TotalLoggingEventsRaised, instanceNames);
        totalTraceListenerEntriesWritten = factory.CreateCounter(counterCategoryName, TotalTraceListenerEntriesWritten, instanceNames);
    }
}

Enterprise Library バージョンからの唯一の機能変更はthrow exceptionFireFailureLoggingErrorEventメソッドへの の追加です。

次にTraceListener、例外をスローする を作成する必要があります。

[ConfigurationElementType(typeof(CustomTraceListenerData))]
public class ExceptionThrowingTraceListener : CustomTraceListener
{
    private void Throw()
    {
        throw new Exception("An Error occurred logging.  Check error logs.");
    }

    public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data)
    {
        Throw();
    }

    public override void Write(string message)
    {
        Throw();
    }

    public override void WriteLine(string message)
    {
        Throw();
    }
}

次に、起動時にエンタープライズ ライブラリを構成して、新しいものを使用する必要がありますLoggingInstrumentationProvider(基になる UnityContainer に直接アクセスしています)。

IUnityContainer container = new UnityContainer();

container.AddNewExtension<EnterpriseLibraryCoreExtension>();

var instrumentationSection =
    ConfigurationManager.GetSection(InstrumentationConfigurationSection.SectionName)
    as InstrumentationConfigurationSection;

ILoggingInstrumentationProvider provider = null;

if (instrumentationSection != null)
{
    provider = new MyLoggingInstrumentationProvider(
        instrumentationSection.PerformanceCountersEnabled,
        instrumentationSection.EventLoggingEnabled,
        instrumentationSection.ApplicationInstanceName);
}
else
{
    provider = new MyLoggingInstrumentationProvider(false, false, "DefaultApplication");
}

container.RegisterInstance<ILoggingInstrumentationProvider>(provider);

EnterpriseLibraryContainer.Current = new UnityServiceLocator(container);

次に、エラーの特別なソースを構成して、失敗をログに記録し、例外をスローします。

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="instrumentationConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Common.Instrumentation.Configuration.InstrumentationConfigurationSection, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
    <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
  </configSections>
  <instrumentationConfiguration performanceCountersEnabled="false"
      eventLoggingEnabled="false" applicationInstanceName="TestApp" />
  <loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">
    <listeners>
      <!-- Using DB Trace Listener because it's easy to make it fail -->
      <add name="Database Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.Database.FormattedDatabaseTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging.Database, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
          listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Database.Configuration.FormattedDatabaseTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging.Database, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
          databaseInstanceName="Database Connection String" writeLogStoredProcName="WriteLog"
          addCategoryStoredProcName="AddCategory" />
      <add name="Flat File Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
          listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
          fileName="error.log" />
      <add listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.CustomTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
          type="ConsoleApplication28.ExceptionThrowingTraceListener, ConsoleApplication28, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
          name="ExceptionThrowingTraceListener" />
    </listeners>
    <formatters />
    <categorySources>
      <add switchValue="All" name="General">
        <listeners>
          <add name="Database Trace Listener" />
        </listeners>
      </add>
    </categorySources>
    <specialSources>
      <allEvents switchValue="All" name="All Events" />
      <notProcessed switchValue="All" name="Unprocessed Category" />
      <errors switchValue="All" name="Logging Errors &amp; Warnings">
        <listeners>
          <add name="Flat File Trace Listener" />
          <add name="ExceptionThrowingTraceListener" />
        </listeners>
      </errors>
    </specialSources>
  </loggingConfiguration>
  <connectionStrings>
    <add name="Database Connection String" connectionString="database=mydb"
        providerName="System.Data.SqlClient" />
  </connectionStrings>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
</configuration>

ここでテスト コードを実行すると、例外が発生します (構成内のデータベース トレース リスナーが失敗すると仮定します)。

LogWriter logWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();

try
{
    logWriter.Write("Test", "General");
}
catch (Exception e)
{
    Console.WriteLine("LogWriter.Write() threw an exception: " + e);
}

さて、例外がスローされるまでには長い道のりがあります。弾丸をかじって、throw ステートメントを追加して Enterprise Library のソース コードを直接変更する方がよい場合があります。

于 2013-09-04T14:34:08.200 に答える