LoggingInstrumentationProvider の定義がバージョン 4 と 5 の間で変更されてイベントが削除されたため、投稿されたアプローチは Enterprise Library 5 では機能しないと思います。
Enterprise Library が例外を飲み込まないように動作を変更するには、いくつかの方法があります。
最後のアプローチを示します (これが最善だからではなく、最も興味深いからです)。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 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 & 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 のソース コードを直接変更する方がよい場合があります。