Logging Configuration Issue?

Topics: Logging Application Block
Oct 10, 2012 at 4:04 PM

Trying to get a simple test working with the Logging Application Block.  I have installed Ent Lib 5.0, copied the DLLS to the BIN folder, added my references, etc...

 Microsoft.Practices.EnterpriseLibrary.Common
 Microsoft.Practices.EnterpriseLibrary.Data
 Microsoft.Practices.EnterpriseLibrary.Logging
 Microsoft.Practices.EnterpriseLibrary.Logging.Database
 Microsoft.Practices.ServiceLocation
 Microsoft.Practices.Unity
 Microsoft.Practices.Unity.Interception

Right-Click on app.config to Edit the Ent Lib Config and add default Logging Settings.

However, can't get by this first line:

 

LogWriter defaultWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();

Error:

Activation error occured while trying to get instance of type LogWriter

I've Google and searched this forum, but none of the suggestions help (don't use GAC, include ALL the references, invalid log name, etc....).  Seems like this "should just work".

Thanks!

 

Oct 10, 2012 at 4:31 PM

Finally found something that might be my issue:

http://entlib.codeplex.com/discussions/231439

I am trying to add the Ent Lib logging functionality to the custom class library (VS2010 project) that currently handles writing to the error log via EventLog.WriteEntry() -- the intent is to utlitmately move the log to SQL.

The existing App.Config is part of this project and contains configuration for other classes.  

I have a separate test project -- a simple console app that references the class library and calls the WriteEventTest() method.  If I edit this App.Config, then it all works fine... but this won't work with other apps that use the class library!

Using the static Logger class (i.e. Logger.Write) does not work either.

I can't imagine this situation is unique, but I'm not seeing what I need to...

 

Oct 10, 2012 at 5:34 PM

Enterprise Library relies extensively on configuration (which can also be programmatic).  By default, .NET configuration uses app.config (of the application) or web.config (of the web application) to load configuration information.

If you want to be totally isolated from the default configuration you can load your own configuration file.  You can add a configuration file (e.g. MyLogger.config) to the class library project and set the Copy to Output Directory to "Copy if newer" or "Copy Always".  Now that configuration file should be copied to the output folder of the console application.

The next step is to load this configuration in the class library.  You can do this using some code like the following:

public class MyLogger
{
    private static IServiceLocator container;

    static MyLogger()
    {
        try
        {
            FileConfigurationSource fcs = new FileConfigurationSource("MyLogger.config");
            container = EnterpriseLibraryContainer.CreateDefaultContainer(fcs);
            // Can also use the following but that will overwrite the current Enterprise Library Container
            // which could be bad if others are also using Enterprise Library
            //EnterpriseLibraryContainer.Current = EnterpriseLibraryContainer.CreateDefaultContainer(fcs);
        }
        catch (Exception)
        {
            // do something
        }
    }

    public static void Write(string msg, string category)
    {
        var logWriter = container.GetInstance<LogWriter>();
        logWriter.Write(msg, category);
    }
}

I've used a static constructor to simplify the example but you can use a proper singleton with lazy loading or other techniques to only load the configuration information once.  The FileConfigurationSource reads in the class library's configuration and then creates a container with the appropriate objects.  (You could also resolve (GetInstance) the LogWriter and keep a reference to that so that the Write method doesn't have to retrieve the instance every time.) Now the class library is not dependent on the app.config being set up.  

In the past, I've also put in checks to see if the expected configuration file exists and is valid (configuration succeeds) .  If loading the configuration fails then I would fall back to some sensible configuration using the Fluent Configuration API.

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Oct 10, 2012 at 8:22 PM

Thanks, Randy!

I was actuallly heading down that same path, but was having trouble getting past the absolute path for the config file -- the "Copy to Output Directory" (and possibly an upgrade to Optional Update 1) resolved that issue.

You also anticipated my questions regarding loading the configuration every time... I've implemented a singleton with a static constuctor that instansiates the LogWriter once.

Before I make the leap to logging to a database, I am trying to map the existing entries to the new LogWriter.Write() method.  Currently the 'Source' is passed on the EventLog.WriteEntry(), and that contained the calling application or web service.  However, it appears that Source is now obtained from the source paremeter of the listener in the configuration.

Do I need to have a separate listener to change the Source for each app that consumes this helper class?  I am still looking at other mapping options, but want to avoid touching any of the calling apps.

Again, much appreciated.

Jerry

Oct 10, 2012 at 9:18 PM

Yes, EventLog source property is obtained from FormattedEventLogTraceListener configuration.  If you want to have dynamic sources (for multiple arbitrary applications) then you need to configure them in advance.  Or you could add the source to your interface and write some custom code to parse the configuration extract the event log trace listener information and add a new trace listener with the new source.  Or you could use the Fluent API which would make it quite a bit easier.  

Note that if the end state is to use the FormattedDatabaseTraceListener that it does not have a source property.  Probably the Title would be set to the application/service name.

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Oct 10, 2012 at 10:47 PM

As my 2 threads are converging, I will post a single reply here (they seemed to be separate issues, but are now very much related).

Re: Source -- Yes,  I see that "Source" isn't even in the database table.

Moving my test scenario out of the console app shifted the issues...

Now I have a web service that references the MyUtils class libarary and invokes the static WriteLogEntry() method -- exactly how this needs to work.   Unfortunately, I am again failing on the EntLib.config because it is expected to be in the BIN folder of the web service!  What confuses me is that the other configuration settings (in the original App.config) are available without any special processing. 

So, will the Fluent API allow me to programatically set the configuration without the need for EntLib.config?  I would still have to address the DLL issue, but putting the necessary Microsoft.Practices.EnterpriseLibrary DLLs in the GAC may be the answer there.

An alternative would be to simply use EntityFramework to log to a custom SQL database -- similar to the Logging DB with the advantage of easily adding any custom fields.  I can see the value of the Enterprise Library, but is it just not a good fit for what I want to do?  Any downsides in terms of performace or other issues?

Thanks again,

Jerry