views:

124

answers:

3

I was profiling our ASP .NET application to try and reduce the CPU usage and fond some strange behaviour regarding NHibernate and log4net.

Over 50% of the time on our app is spent in the log4net GetLogger and CreateRepository methods, which are called from ExecuteReader in NHibernate. The screenshot below is a jetBrains dottrace hotspot analysis where the arrows point from a calling method to the called method.

alt text

The below screenshot is just a straight up list of slowest functions.As you can see the NHybridDataReader constructor calls GetLogger and it takes ages.

alt text

Clearly something fishy is going on, and I want to disable log4net completely in NHibernate as we use other logging functionality.

Our web.config has no entries in it regarding log4net, so how do I disable it? There are no log files being produced, and from the look of the method names, it hasn't actually got round to logging anything, but is merely trying to find the logger it should write stuff to.

Most confusing, can anyone help?

+5  A: 

As I see it, the screenshot you posted says that the time is actually spent on NHibernate running some query. log4net has nothing to do here. The real problem is that you seem to be executing some query 3529 times.

Mauricio Scheffer
Sorry, I think the screenshot was misleading, will post another jetBrains view type to make it more clear. The time is definetly being spent in log4net.
Robin Weston
@Robin: you should sort by the "own time" column, not the other time column.
Mauricio Scheffer
@Mauricio: While it's true that "time" includes time spent in both the method as well as method invocations, the fact is that NHybridDataReader's constructor is very minimal if you look at the code. The initializer gets the logger and a variable is assigned.
Rich
@Robin: If what you're saying is true, then there should be a ton of time taken by the static method LoggerProvider.LoggerFor method. Show a screeen shot of that method across all calls.
Rich
+1  A: 

For an answer to your specific question (turning off use of log4net by NHibernate), look into the code the Logging.cs file for NHibernate. When I looked at it (granted, I looked at 3.0 alpha code, but I doubt it's much different than 2.x), in the static LoggerProvider constructor, it delegates to GetNHibernateLoggerClass to determine the class to utilize. If it doesn't get one, it uses a no-op based class. So if you look in the GetNHibernateLoggerClass method, you see that it first looks for an appsettings key called "nhibernate-logger", which you should be able to set to "NHibernate.NoLoggingLoggerFactory, NHibernate". You may also notice that lacking a defined key, it will automatically use log4net if it finds the log4net DLL in the search path (likely just the directory containing NHibernate DLL. So you may also want to try removing the log4net DLL itself and see what happens. Though the first solution is more explicit and the second more is more inferred, so I would use the first.

As a side note, this is a great example of why open source works so well. Being able to just look thru the source code to answer a question like this. In closed source, you'd either have to cheat and .NET reflector the code (which could be obfuscated), or pray that the owners heavily documented obscure points like this one.

BTW, this same source code file provides what would need if you want to take NHibernate's log messages and redirect them to your own logging solution, as you mentioned you had (implement the ILogger and ILoggerFactory interfaces and use the config setting).

Rich
A: 

Set the logging level approproately for the NHibernate logger in your config file:

<logger name="NHibernate">
  <level value="ERROR" />
</logger>

I believe it defaults to DEBUG and it does a lot of logging. I would not disable it entirely since you want to be informed of ERROR or FATAL events.

Jamie Ide
If you don't have a logger ouput specified (as we do) will this make any difference?
Robin Weston
I think it will but I don't know for certain.
Jamie Ide