log4net. Where to put BasicConfigurator.Configure() when your codespans multiple projects

M

Mr Flibble

Hi all,

I've decided to use log4net for my logging/tracing.

In the example on the site it shows using main() to setup the root
logger and then using the LogManager within your classes to create more
loggers (subloggers). This is nice since I can use just one
configuration file to control the behaviour of all the loggers within my
app. This is great if I'm using a project that contains all my classes
but what happens if my class is in another namespace in another project?
My namespaces span multiple projects...

Do I have to initialise a root logger within each project?

What do people do in this situation?
 
L

Lalit Bhatia

You have to call XmlConfigurator.Configure(...) to initialise only once in
the first project where you have your main() method.
 
M

Mr Flibble

* Lalit Bhatia said:
You have to call XmlConfigurator.Configure(...) to initialise only once in
the first project where you have your main() method.

My problem is that I dont have a main() so I cant get my head around
where is the best place to place the configurator.

I have a website that creates an object x. x just returns some data
that the website presents. this object x uses objects y and z to get the
data. I want tracing in x , y , and z.. and of course the website
itself. and preferably just a single XML configuaration file.

Where do I configure log4net? Within the website itself?, individually
in the constructors of all of x, y & z? If I call
XmlConfigurator.Configure() from the website can I magically use
LogManger.GetLogger from the components even though they are in seperate
bin files (physically rather than logically, they're all related by
their parent namespace).

I'm confused can some kind soul shed some light?
 
D

Dinsdale

I tend to put mine in my most upper level class before the UI or the
EnterpriseService wrapper, then each class has a static reference to
the logger. I do this so that the logging is tied to my Object model
rather than my UI or wrapper and if the functional spec changes, the
logging still works. I had one project that had a UI but was then
integrated into another app just using the class library I had built. I
had another one turn into a service over night (last minute customer
request). Since the Logging was initialized in my libraries, the
switch over was flawless. The only problem is if the UI has an
exception before you initialize your object model, or during the
initialization process, you won't get that logged so you need to be
careful where you do things (don't do anything until your logger is
initialized).

Initialization:

public SystemModelController(string strApplicationPath)
{

log4net.Config.XmlConfigurator.Configure();

_strApplicationPath = strApplicationPath;


MyObj.ConfigFilePath = _strApplicationPath + "\\" +
System.Configuration.
ConfigurationSettings.AppSettings["system_config_name"];

MyObj.Initialize();

}

Then in all my classes:

private static ILog _l4nSystemLogger =
LogManager.GetLogger(System.Reflection.MethodBase.
GetCurrentMethod().DeclaringType);

I usually have 3 or 4 projects per solution and they all use the that
single init call in the main class.

Here is a config file section that creates a rolling file appender
based on date:

<configSections>
<section name="log4net"
type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>

<log4net debug="false">
<appender name="SystemLog" type="log4net.Appender.RollingFileAppender">
<param name="File" value=".\\SYSTEM\\" />
<param name="Threshold" value="ALL" />
<param name="AppendToFile" value="true" />
<param name="RollingStyle" value="Date" />
<param name="MaxSizeRollBackups" value="10" />
<param name="DatePattern"
value="yyyy\\MMMMMMMMM\\yyyyMMdd.\M\Y\F\I\L\E"/>
<param name="StaticLogFileName" value="False" />
<layout type="log4net.Layout.PatternLayout">
<header value="[BEGIN LOGGING AT %date ]%newline"
type="log4net.Util.PatternString" />
<footer value="[END LOGGING]%newline"
type="log4net.Util.PatternString" />
<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n"
/>
</layout>
</appender>

<root>
<appender-ref ref="SystemLog" />
</root>
</log4net>

(Courtesy of Nicko at Log4Net - Thanks again dude!)

Cheers
Russ
 
M

Mr Flibble

* Dinsdale said:
I tend to put mine in my most upper level class before the UI or the
EnterpriseService wrapper,

Ok, for me I dont have any top level class so the only place I could
conievabely configure the root logger is in the UI (which I dont want to
do in case different UI's are used, or the UI is infact removed
completely). Does it make sense for each class to initialise it's own
root logger or should there be just one BasicConfigurator.Configure()
(or similar initiatlisation statement) within a solution? i.e. does
this hierarchial logging only work if Configure() is used in one place
only? Also what about calling GetLogger() within a class in a seperate
project, how does it get connected to the root logger in the calling
app/site/client if that is itself in a different project?

Sorry if my questions are confusing , it's because I myself am confused :)
 
D

Dinsdale

As I understand it, the logger is a static object. Once the Configure()
function is called, all you have to do is get the reference to the
logger. Therefore, so long as your objects are running in the same
AppDomain, the config is still valid. It doesn't matter about the
design time structure. If l4n is configured, any class that calls the
GetLogger() function gets the instance for the whole app (that is,
depending on how you set L4N up. You can create different loggers and
then get the reference to that specific logger as well). If it's not
configured, it doesn't seem to do anything (again, so far as I can
tell). I forgot to configure an app once and I didn't realize what was
wrong until much later because there was no exception. :)

Remember, each asp.net "site" runs as an application and all the pages
use the same AppDomain. It doesn't matter about the class structure
when the app is running - It seems to me you are confusing the idea of
referencing classes in a project with what is going on here. The static
instance of the Logger is shared across the entire application
regardless of the "physical" structure of the classes. If you configure
the L4N in your globals.asax page, then all pages called after that can
use the same instance because the GetLogger call I posted previously
simply says: "Get me the Logger that is being used by this class".
Since I don't have any class specific logger, it gets the one that is
specific to the application.

APPLICATION
- L4N Logger Instance 1

- Page1 instance 1 -> Uses l4n1
- Page1 instance 2 -> Still using l4n1
- page2 instance 1 -> you got it, l4n1


Two side notes that are entirely my opinion:

1) It sounds to me like this is the perfect opportunity for you to
design a hierachy and a class that takes care of configuration (which
is what I do in my top level class). How bout a static class that has
one function called Begin() that calls all config stuff?

2) I would recommend signing up to the Log4Net mailing list. Those guys
are totally brilliant and are usually very quick at getting answers
back. The only time I ever had to wait, one of the guys was away or
something and he answered my 3 week old message anyways!

Cheers
Russ
 
M

Mr Flibble

* Dinsdale said:
As I understand it, the logger is a static object. Once the Configure()
function is called, all you have to do is get the reference to the
logger. Therefore, so long as your objects are running in the same
AppDomain, the config is still valid.

Firstly thanks for your very imformative reply. Hopefully it will also
help other people who stumble upon it via google groups et al.

Now to some more questions I have :) You're right I was wondering how
to get a reference back to the original instantiation of the previously
configured Logger object. Seems that you're saying that so long as they
are within the same AppDomain I dont need to care, where or how (or even
who by) it was configured. OK this is great, but sadly I can't see of a
good place to put the configuration..

I have a site Default.aspx that in it's Default.aspx.cs calls a method
on an instance a of data retrieval class. I also have a service that
that runs independantly to the website that is basically a data
gatherer. This data retriever just serves the data gathered by this.
Are these considered different AppDomains?

Assuming they are, or can be made to be, I guess the place that makes
the most sense for the configuration of l4net would be in the webpage
(globals.aspx), since as you can see I really dont have any top-level
object since I have webpage that creates an object and a service that
creates an object. No real class hierarchy or relation to one another.

This worries me since I dont want the UI to be webpage bound.
Two side notes that are entirely my opinion:

1) It sounds to me like this is the perfect opportunity for you to
design a hierachy and a class that takes care of configuration (which
is what I do in my top level class). How bout a static class that has
one function called Begin() that calls all config stuff?

I could create a utility function "ConfigureLogging" and make sure the
UI calls it. This would make it UI independant but would mean that the
UI "would need to know" that it must do this. I was hoping of hiding
this from the UI.
2) I would recommend signing up to the Log4Net mailing list.

I shall. :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top