c# - 我们需要企业库日志来抛出错误

标签 c# logging error-handling enterprise-library

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

据我所知,日志记录的理念是不中断,所以如果配置中出现错误,我们不会抛出错误。

但是在我们的应用程序中,日志记录是如此重要,以至于我们需要让应用程序乱序运行,而不是在没有日志的情况下运行。

所以我们需要这样配置它,如果有的话它会抛出一个错误。

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

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

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

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

感谢您的帮助。

最佳答案

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

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

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

    我将演示最后一种方法(不是因为它是最好的,而是因为它是最有趣的)。因此,要使这种方法起作用,我们需要创建一个自定义 LoggingInstrumentationProvider定制TraceListener抛出并配置记录应用程序 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 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 语句。

    关于c# - 我们需要企业库日志来抛出错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18606946/

    相关文章:

    c# - 有没有办法将这种字符串转换为日期?

    C# 从一个配置文件中获取一个字符串以供多个项目使用

    logging - 当某些后台进程仍在运行时,命令 'exit' 不起作用

    php - 如何使SoapClient更正常地失败?

    php - PHP错误报告-无法匹配本地和Web服务器设置

    c# - 编译器在引用程序集时遇到麻烦

    c# - 如何在身份库的 asp.net core 中配置电子邮件发送?

    C++ 记录器性能和可移植性

    logging - 记录 Laravel 中的操作和执行时间

    php - 我如何查看多个文件上传PHP中数组是否为空