您知道我们如何从企业库5日志记录块中获取错误吗?

据我所知,日志记录的理念是不间断,因此,例如,如果配置中存在错误,我们将不会抛出该错误。

但是在我们的应用程序中,日志记录至关重要,以至于我们需要使应用程序困惑,而不是不运行日志。

因此,我们需要对其进行配置,如果有的话,它将引发错误。

我在这里找到了一些有关事件的信息:Enterprise Library Logging Application Block options

因此,我们应该能够侦听此事件,并至少引发我们自己的错误,但是我无法获得对日志记录工具的引用,因为在以下代码中看不到GetInstrumentationEventProvider()方法。

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

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

感谢您的帮助。

最佳答案

我认为LoggingInstrumentationProvider定义在版本4和版本5之间进行了更改,以删除事件,因此发布的方法不适用于企业库5。

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

  • 修改企业库源代码以实现所需的行为
  • 复制LogWriterImpl/LogSource代码并注入(inject)到容器中(此方法可以在Enterprise Library Logging Extensions – Part 1
  • 中看到
  • 用抛出
  • 的实现替换当前的LoggingInstrumentationProvider实现

    我将演示最后一种方法(不是因为它是最好的方法,而是因为它是最有趣的方法)。因此,为了使这种方法起作用,我们将需要创建一个自定义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);
        }
    }
    

    与企业库版本相比,唯一的功能更改是在throw exception方法中添加了FireFailureLoggingErrorEvent

    接下来,我们需要创建一个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语句,直接修改企业库的源代码。

    10-07 19:30
    查看更多