Flatfile logging a WPF app

Topics: Logging Application Block
Nov 30, 2010 at 7:31 PM

Hello. I have a WPF app that I need to log events to a flat file. I took a look at the LoggingQuickStart sample project, and tried to do the same in my app, but I can't get the configuration right. When I appended the logging sections from LoggingQuickStart to my app's App.config, my app wouldn't start.

As soon as it did start (making changes to the config entries), I keep getting the "The configuration section for Logging cannot be found in the configuration source." exception.

I came across a blog post that said:

this exception is usually caused by the Logger façade, which forcibly initializes using the application default .NET configuration file and not the one specified in the IConfigurationSource. In this scenario, avoid using the Logger class and use the LogWriter created from the Iconfiguration source.

and suggested:

// Reads a Logging Application Block configuration from an external configuration file
var fcs = new FileConfigurationSource(@"C:\TEMP\MyLoggingConfiguration.config");
var logWriter = new LogWriterFactory(fcs).Create();
var logEntry = new LogEntry() { Message = "Hello logging!" };
 
// You can use the logWriter directly
logWriter.Write(logEntry);
 
// Throws a ConfigurationErrorsException "The configuration section for Logging cannot be found in the configuration source."
// Because the Logger facade forcibly initializs using the application�s default .NET configuration file and not the one
// we specified manually (EntLib 4.1)
Logger.Write(logEntry);

Although this sidetracks the configuration exception, it doesn't log anything to the file mentioned in the config file.

Any ideas how to make this work?

Dec 1, 2010 at 12:41 AM

Are you sure your configuration file is named "App.config"?  Because I noticed by default, when you add a configuration in a WPF application, it names the configuration file as App1.config.

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Dec 1, 2010 at 1:33 AM

Nope, its app.config - but I wasn't able to add the logging sections to it w/out it crashing on me. Need some help with this.

Dec 1, 2010 at 1:36 AM

Could you describe your scenario in more details?  Did you check if there were any error written in the event log?

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Dec 1, 2010 at 8:32 PM

Hi Sarah - thanks for looking into this.

So first off, you're right - WPF does name its config file App1.config - I just changed it a long time ago and forgot about that.

So instead of going right into my huge app and try get logging working, i made a brand new simple WPF app to make things easier. So I have the config file as:

<configuration>
  <configSections>
    <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging" />
  </configSections>

  <loggingConfiguration tracingEnabled="true" defaultCategory="General">
    <logFilters>
      <add
		name="Category"
		type="Microsoft.Practices.EnterpriseLibrary.Logging.Filters.CategoryFilter, Microsoft.Practices.EnterpriseLibrary.Logging"
		categoryFilterMode="AllowAllExceptDenied">
        <categoryFilters>
          <add name="UI Events" />
        </categoryFilters>
      </add>
      <add
		name="Priority"
		type="Microsoft.Practices.EnterpriseLibrary.Logging.Filters.PriorityFilter, Microsoft.Practices.EnterpriseLibrary.Logging"
		minimumPriority="2"/>
      <add name="LogEnabled Filter"
        type="Microsoft.Practices.EnterpriseLibrary.Logging.Filters.LogEnabledFilter, Microsoft.Practices.EnterpriseLibrary.Logging"
        enabled="true"
           />
    </logFilters>

    <categorySources>
      <add
		name="Data Access Events"
		switchValue="All">
        <listeners>
          <add name="Flat File Destination" />
        </listeners>
      </add>
      <add
		name="General"
		switchValue="All">
        <listeners>
          <add name="Event Log Destination" />
        </listeners>
      </add>
      <add
		name="Troubleshooting"
		switchValue="All">
        <listeners>
          <add name="Event Log Destination" />
        </listeners>
      </add>
      <add
		name="UI Events"
		switchValue="All">
        <listeners>
          <add name="Flat File Destination" />
        </listeners>
      </add>
      <add
		name="Trace"
		switchValue="All">
        <listeners>
          <add name="Flat File Destination" />
        </listeners>
      </add>
    </categorySources>

    <specialSources>
      <errors name="errors" switchValue="All">
        <listeners>
          <add name="Event Log Destination" />
        </listeners>
      </errors>
    </specialSources>

    <listeners>
      <add name="Event Log Destination"
				type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging"
				listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging"
				source ="Logging Quick Start"
				formatter="Text Formatter"
        machineName="."
				/>
      <add name="Flat File Destination"
				type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging"
				listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging"
				fileName ="trace.log"
				header="----------------header------------------------"
				footer="----------------footer------------------------"
				formatter="Text Formatter"
				/>
    </listeners>
    <formatters>
      <add
				name="Text Formatter"
				type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging"
				template="Timestamp: {timestamp}
Message: {message}
Category: {category}
Priority: {priority}
EventId: {eventid}
Severity: {severity}
Title:{title}
Machine: {machine}
Application Domain: {appDomain}
Process Id: {processId}
Process Name: {processName}
Win32 Thread Id: {win32ThreadId}
Thread Name: {threadName}
Extended Properties: {dictionary({key} - {value}
)}"
				/>
    </formatters>
  </loggingConfiguration>
</configuration>

Just took it from the LoggingQuickStart project and took the DebugTraceListener out.

In code, I have this simple call:

            string logMessage = "Test Logging";

            LogEntry logEntry = new LogEntry();

            logEntry.Categories.Clear();
            logEntry.Categories.Add("Troubleshooting");
            logEntry.Priority = 5;
            logEntry.Message = logMessage;

            Logger.Write(logEntry);

When the Write method is called, I get the infamous "The configuration section for Logging cannot be found in the configuration source." exception.

To your question, I don't see anything in the event log.

I appreciate any tip on troubleshooting this.

Dec 2, 2010 at 12:06 AM

Could you send that simple WPF app you just created?  I don't see any reason for the error if you have the name of the configuration right.

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Dec 3, 2010 at 12:31 AM

I got the repro project.   The configuration file in that project is named "App1.config" which causes the error.  Rename it to App.config.

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Dec 6, 2010 at 4:15 PM
Edited Dec 6, 2010 at 10:51 PM

Hi - Thanks again for helping.

Ok - no exception thrown. But where is the Trace.log file? Where is it writing to? I tried changing:

 


      <add name="Flat File Destination"
 type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging"
 listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging"
fileName ="C:\trace.log"
header="----------------header------------------------"
footer="----------------footer------------------------"
formatter="Text Formatter"
/>

But that doesn't work either.
Dec 6, 2010 at 10:51 PM

Based on the sample code you sent to me, you are logging using the "Troubleshooting" category and this category references a Formatted Event Log Trace Listener which logs to the event log.  So if you want to log  to the trace.log file, you should use any of the following categories: Data Access Events, Trace, or UI Events.  Sample code below:

logEntry.Categories.Add("Data Access Events");

By the way, if you specified only trace.log in the fileName, meaning without specifying an absolute path, then the file goes to the project's output folder which is in the bin\debug folder (for Debug mode).

If you're sure you're logging using the correct category but still unable to see the log file, check the event log for any error log indicating why logging to file failed. 

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Dec 6, 2010 at 10:55 PM

Sarah, your help is very much appreciated.

Cheers.

Dec 6, 2010 at 11:56 PM

You're welcome.  Have you got it to work yet?

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Dec 7, 2010 at 3:48 PM

Yes, in my sample app I did, so no reason to expect complications with my real app.

Again, thanks, you were very helpful.

Dec 28, 2010 at 5:13 PM

Hi again - Is there a way to set the "Flat File Destination" dynamically in code? I want to be able to write something like:

            LogEntry logEntry = new LogEntry();

            logEntry.Categories.Clear();
            logEntry.Categories.Add("Trace");
            logEntry.Severity = eventType;
            logEntry.Message = logMessage;
            
            string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
            logEntry.fileName = appDataPath + "/log.dat";

            Logger.Write(logEntry);     

 

Thanks.

 


Dec 29, 2010 at 12:00 AM

If you're using EntLib 5.0, you can leverage the Fluent Configuration API

If you're using a lower version, you can make use of the sample code posted here.

By the way, please create a new thread for a different topic.

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com