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。

有几种方法可以更改行为,以便企业库不会吞下异常:

我将演示最后一种方法(不是因为它是最好的,而是因为它是最有趣的)。因此,要使这种方法起作用,我们将需要创建一个自定义LoggingInstrumentationProvider的自定义TraceListener,它会抛出并配置 Logging Application Block 错误特殊源以使用这个新的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();
    }
}

接下来我们需要在启动时配置 Enterprise Library 以使用我们新的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 语句。

于 2013-09-04T14:34:08.200 回答