Friday, April 17, 2009

Logging in Spring.NET with log4net, initialization

It didn't take long to run into a snag.

The docs I've found so far say to get your log thusly:
ILog log = LogManager.GetLogger( "Outermost" );

Being the lazy bastard that I am, I started copying that into various constructors. The thought occurred to me that I should be able to put all of this into the spring config, but then there's that whole "being the lazy bastard that I am".

It didn't take long to run into an unhelpful exception:
Cannot instantiate Type [FileCrawler.FileCrawlerEngine] using ctor [Void .ctor(System.String)] : 'Index (zero based) must be greater than or equal to zero and less than the size of the argument list.'

What had I changed? I hadn't been as aggressive committing as I should've been, so there were a lot of little changes to poke through.

In the constructor of FileCrawlerEngine, I used the log that I had just created:
log = LogManager.GetLogger( "FileCrawler" );
log.Trace( String.Format( "Initializing FileCrawler for basepath {0}" ) );

Removing the Trace from the constructor resolved it.

Hrm.

I switched everything over to use log4net, directly, and it all worked okay. Even with a few threads thrown in. It takes even less upfront work. Create the log4net section, and follow the log4net docs. Just make sure that somewhere in your initialization, you call the following:
log4net.Config.XmlConfigurator.Configure();

Then, use it in your code, thusly:
log = log4net.LogManager.GetLogger( "NdxDocument" );
log.Info( "Informative" );

Using it directly exposes a better API, and it works as expected. I haven't gotten any errors, but I'll bet they are clearer than the one thrown by Spring.NET. It seems like Common.Logging requires more work for less results - I think I'll be sticking with the direct use of log4net, now.

It should be possible to springify the log initialization. That'll have to be a digression for later - I still have a lot of logging retro-fitting to do.

UPDATE: I took one look at adding logging to the SolrSharp library, and decided that now was as good a time as any to add the logging config to spring. I ran into a similar problem - logging in the constructor failed. It had a better error message, though:
"Error creating object with name 'Document' defined in 'config [C:\\Users\\michael.THREETREES\\Documents\\Visual Studio 2008\\Projects\\Crawler\\FileCrawler\\bin\\Debug\\FileCrawler.vshost.exe.Config#spring/objects] line 1' : Initialization of object failed : Cannot instantiate Type [NdxCore.NdxDocument] using ctor [Void .ctor()] : 'Object reference not set to an instance of an object.'"

Okay, so the property doesn't get set until after construction. That makes sense, at least for my problem. Too bad the Spring.NET guys didn't find a way around this for Common.Logging (and that I'm too dumb to figure it out myself).

UPDATE 2: Spring.net will call a specified initialization method, so that you can use the objects which are initialized by the container.

Reading the manual is for the weak. So, I'm weak.

No comments:

Post a Comment