Just started using log4net and trying to get my head around the config and logger hierarchy. Is this hierarchy based on namespaces or class and method/function hierarchy?
Lets say I have the following class structure...
public class MyClass
{
private static readonly ILog log = LogManager.GetLogger(typeof(MyClass));
public void Method1()
{
log4net.info("message");
}
public void Method2()
{
log4net.info("message");
}
}
Is it possible to setup in the config for the log4net.info in method1 to use one appender and the log4net.info in method 2 to use another appender, even if they are off the same type e.g. SmtpAppender. If so how would the config look. here is my first attempt at it.
<appender name="SMTP1" type="log4net.Appender.SMTPAppender">
</appender>
<appender name="SMTP2" type="log4net.Appender.SMTPAppender">
</appender>
<logger name="MyClass.Method1">
<level value="INFO" />
<appender-ref ref="SMTP1" />
</logger>
<logger name="MyClass.Method2">
<level value="INFO" />
<appender-ref ref="SMTP2" />
</logger>
The hierarchy is based on "names". What does that mean?
Well, you can specify a namespace in your logger xml (eg. Foo.Bar
) and then fetch a logger for a class in that namespace using the GetLogger
method which takes a Type
. Any "sub" namespace under Foo.Bar
will inherit Foo.Bar
's logger config.
Alternatively, you can fetch a logger based on any old string using the GetLogger
method which takes a string
.
You can fetch loggers a couple of different ways. Most notably, by Type
or by string
.
Being able to fetch by string
, you really can name your loggers anything and fetch them using anything. What you currently have won't work because log4net
will fetch the logger based on the class... so you will be using the same logger for both methods.
For what you want to do you have to create two loggers:
public class MyClass
{
private static readonly ILog log = LogManager.GetLogger(typeof(MyClass).Name + "." + "Method1");
private static readonly ILog log2 = LogManager.GetLogger(typeof(MyClass).Name + "." + "Method2");
public void Method1()
{
log.info("message");
}
public void Method2()
{
log2.info("message");
}
}
Here is the same logger xml file:
<logger name="MyClass.Method1">
<level value="INFO" />
<appender-ref ref="SMTP1" />
</logger>
<logger name="MyClass.Method2">
<level value="INFO" />
<appender-ref ref="SMTP2" />
</logger>
I'm not too experienced with .Net, so maybe someone can find a better/more robust way to get the loggers for each method using some ninja Reflection, but that is the best I could do.
The same logger can't route to multiple appenders based on the current method, at least not directly. However, what you can do is use log4net's filters
to do what you want. The log4net framework populates each LoggingEvent with the location information you need (e.g., method name) to do the filtering you want. You'll probably need to write a custom IFilter
, though, to filter on that. IFilter
is a pretty trivial interface to implement: 1 method/1property. Your filter's Decide()
method makes 1 of 3 decisions on each logging event passed to it:
Then add your filter to the filter chain for each appender you want to have. That can be done on the fly, or it can be configure via your log4net.config.
You should be aware, though, that the quality of the location information you get is dependent on whether it's a Debug or Release build...and whether, I believe, it's got debugging symbols available.
You might also want to look at log4net's various contexts (and context stacks)
if you need to do add some contextual information on which to base your filtering.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With