WAS hosted WCF service and log4net - wcf

I'm facing a problem when trying to log my application using log4net.
My application consists of a WCF service, and clients connecting to it.
Logging at client-side is not a problem, everything works perfectly.
Here is how my server-side is made:
A WCF dll, which contains my service's contract and base implementation (including error handling). Actual operations are made in a separate business layer, which throws the needed exceptions which are caught by the implementation (and sent back using FaultContracts).
A data layer (not a problem here).
A "Utils" library, which contains my wrapper log methods.
My log4net.config file is the following:
<?xml version="1.0" encoding="utf-8" ?>
<log4net debug="false">
<appender name="TechnicalFileAppender" type="log4net.Appender.RollingFileAppender,log4net">
<param name="File" value="c:\\log\\technical.log"/>
<param name="AppendToFile" value="true"/>
<param name="RollingStyle" value="Date"/>
<param name="DatePattern" value="'_'yyyyMMdd-HH"/>
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%d [%-5t] %-5p - %m%n"/>
</layout>
</appender>
<root>
<level value="ALL"/>
</root>
<logger name="TechnicalLog">
<level value="ALL"/>
<appender-ref ref="TechnicalFileAppender"/>
</logger>
</log4net>
So when an error occurs in the business layer, it is captured, logged and transformed into a FaultException. There is the problem. No log file is created.
I googled and found some clues (access rights generally, but I used ProcMon and found no call to the desired file or directory).
I'm a bit lost now, I don't know what to try.
I publish my service using the "publish" command in visual studio, so on the server I have my application directory, inside there is a svc file, a web.config file, and then a bin directory with all my dll's including the log4net.dll, and log4net.config.
I tried to copy that config file in the root of my application without success.
I also tried to place the
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
statement in my WCF's AssemblyInfo.cs (it was originally in the Utils's AssemblyInfo.cs), but without any success.
Thanks for you help, any idea is welcome !

I am pretty sure that log4net does not find the configuration file.
I had the same issue and I think I solved it by having an application setting in the web.config file that contains the full path to the log4net config file. In my wrapper I made sure that log4net is configured by calling the ConfigureAndWatch method if log4net is not configured yet.
Alternatively you could simply copy the log4net configuration to the web.config file (but I would not do that because you loose the ability to change the log settings for the running system). In that case you need to add this to you AssemblyInfo.cs (or some other file if you prefer):
[assembly: log4net.Config.XmlConfigurator()]
If that still does not help then I recommend to turn on internal debugging.

Related

Log4Net setting contexts for multiple requests with multiple file logging?

We're trying to use log4net log processes requested to a WCF service. For that, our goal was to log in different files depending of some arguments of the request. For that, we have used Context properties of log4net, setting the context of it in every call to the service, but, because of possible concurrency issues, we can't use "GlobalContext".
Thinking(it seems that thinking wrong) that wcf uses one thread per call, we set ThreadContext properties when the request was received, such as this:
GlobalContext.Properties("fulldate") = Now.ToString("yyyyMMdd")
GlobalContext.Properties("date") = Now.ToString("yyyyMM")
ThreadContext.Properties("center") = center //it comes with the request header
XmlConfigurator.Configure()
And the appender is defined in the config file like this:
<appender name="IntAppender" type="log4net.Appender.FileAppender">
<file type="log4net.Util.PatternString" value="c:\\Logs\\%property{center}\\%property{date}\\%property{fulldate}\\theLog.log" />
<datePattern value=".yyyyMMdd.'log'" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level - [%ndc] %message%newline" />
</layout>
But sometimes, logs that should be in one center's log is in an another center's log, and it seems that the problem is how WCF manages threads. I don't want to set the service to be instanced per request. Can you point me a link or doc of how WCF manages threads? I haven't been able to find one. And is it possible to accomplish what I'm trying to do? That is, to log all request of one center in that center's log file.
Thanks.
That won't work, and it's nothing to do with WCF's thread model.
Log4net shares your single defined appender between loggers, and thus between threads. When one thread changes the file value on the file appender, this applies to all threads so it's a race condition to see what log the error actually ends up in!
To accomplish this you need to have one file appender per log file, per "center". If the centers are known beforehand you could set them up in config, or otherwise it's easy enough to set them up programatically

NHibernate messages going to the console no matter what

I have a console app using Fluent NHibernate. I have configured it to log to various places using log4net. And it works great. I can see the SQL that I want to see and can sent log output to various appenders. The problem is that I cannot suppress the log4net sql output going to the console.
The extra console output is not being controlled by my log4net config settings. It always appears, no matter if I turn off all appenders.
Any suggestions?
Do you have this property set to true in your nhibernate section in your app.config?
<property name="show_sql">true</property>
If so set it to false.
Edit
Here is a sample piece of code from the nhibernate source:
log.Debug(logMessage);
if (LogToStdout)
{
Console.Out.WriteLine("NHibernate: " + statement);
}
In the above code LogToStdout is directly linked to the show_sql configuration property. If you have this set to true nothing will stop it from writing to the console. In regards to your comment you cannot control this via log4net. You can only control what you are doing with the log.Debug(logMessage) via log4net.
To disable any logs put the following code:
< add key="nhibernate-logger" value="" />
into your appSettings section.
The NHibernate logs don't help me much, I'll turn them on when I need them... I add these settings to the log4net section of my app.config:
<logger name="NHibernate">
<level value="OFF" />
</logger>
<logger name="NHibernate.SQL">
<level value="OFF" />
</logger>

log4net: deny other components except than a specific one from logging

Assume you are using some libraries like NHibernate or Castle ActiveRecord that use log4net internally. Your application uses log4net too. It's possible to configure all applications to save logs into file or any other output. But the problem is by enabling log4net for my own application, other programs save their log into the log file and causes it grow very fast with information that I don't need at the moment.
How can I route logs of each application to different outputs or at least how can I deny other applications from logging?
NHibernate/Castle Active Record generate lot of log information but that is all DEBUG level logging. So you can turn down your log level from "ALL" to "INFO" or "ERROR" in config file and you should be OK.
log4Net also support named logger and logger hierarchy. I am sure both NHibernate/Castle would be using named logger. So you can choose to ignore that particular named logger using configuration. See log4Net help where they have used have different logging level for Com.Foo library.
Using named logger is a typical way of separating log traces from different components/modules/libraries etc. Each application (as in different process) would have different configuration file and you can always have different log files to separate the log traces.
Just direct different loggers to different appenders.
Pseudo example:
<log4net>
<appender name="MyAppender" type="log4net.Appender.FileAppender">
<!--appender properties (file name, layout, etc)-->
</appender>
<appender name="NHAppender" type="log4net.Appender.FileAppender">
<!--ditto-->
</appender>
<logger name="MyAppMainNamespace">
<level value="INFO"/>
<appender-ref ref="MyAppender" />
</logger>
<logger name="NHibernate">
<level value="ERROR"/>
<appender-ref ref="NHAppender" />
</logger>
</log4net>

WCF logging not working, trying to get ANY information on why services don't work

I have deployed a few WCF services to a server via a web setup project
they are being hosted in an IIS Application, which appears to be running fine.
However when i try to navigate to the wsdl, nothing is found.
I am trying to set up diagnostics logging, to get some information.
I have followed the advice from here: wcf trying to set up tracing to debug, not writing to log file
Also, I have tried what is in the referenced MSDN documentation: under "Recommended Settings for Deployment or Debugging" .. my web.config has that identical configuration. But no log file is being created.
Nothing useful in the event viewer.
Any ideas?
Could be a permissions issue; IIRC those don't always turn up in the event log. Ensure the user IIS runs under has write permissions to the log file path.
This is typically the diagnostic config I use. Seems to work for me.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
...
<system.diagnostics>
<trace autoflush="true" />
<sources>
<source name="System.ServiceModel"
switchValue="Verbose">
<listeners>
<add name="sdt"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="D:\wcfLog.svcLog" />
</listeners>
</source>
</sources>
</system.diagnostics>
</configuration>
If you are not getting any output it may be because your service is not starting correctly. The ServiceHost must be up for diagnostics to output anything. With IIS even though your site is running it does not mean that the ServiceHost started correctly. It's usually a config issue. I'm not a web guy but doesn't IIS write to EventViewer if there is an unhandled exception in the website?
Also, you could try creating a custom ServiceHostFactory. That way your code controls the ServiceHost creation and you can trap any exceptions and log them on your own.
Creating a custom ServiceHost in IIS -> LINK
This is an old question but for the benefit of anyone who might stumble upon the issue:
Make sure you have configured both the system.diagnostics and the System.serviceModel/diagnostics sections configured.
Make sure you have them configured in the correct App.config/Web.config file. The thing to note is that multiple config files may exist in a project, and the one used depends on the Build Configuration.
Personally I had the very same symptom until I noticed that I put the sections
under app.config (in my case, client side tracing), instead of
app.DebugLocal.config. The later was used as my build configuration was set to DebugLocal.

How can I access app.config on the BeforeBuild event from a custom MSBuild task?

I've written a custom MSBuild task to generate model code from MSSQL stored procedures. I want to use the same configuration for my task to connect to the database as the application does. I've created a config section that looks like this
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="CoreDataConnections" type="CoreData.ConfigHandler, CoreData"></section>
</configSections>
<CoreDataConnections>
<Connection Name="BillingDB" ConnectionString="Data Source=SERVER0;Initial Catalog=DB0;persist security info=False;user id=user;password=password;packet size=4096"/>
<Connection Name="ValidationDB" ConnectionString="data source=SERVER1;initial catalog=DB1;persist security info=False;user id=user;password=password;packet size=4096"/>
</CoreDataConnections>
</configuration>
and access it all day from my app like so:
Dictionary<string,string> Connections = (Dictionary<string,string>)ConfigurationSettings.GetConfig("CoreDataConnections");
My custom task can't see it, though, and GetConfig returns null.
What should I do here? I'd prefer not to have to rewrite my custom config section handler, and am more interested in, say, specifying the app.config file in an MSBuild property, but I'll do what it takes.
more interested in, say, specifying the app.config file in an MSBuild property
That's what I did. Worked fine.
Have you tried the ConfigurationManager.OpenExeConfiguration method? You should probably have that path passed into your task from the MSBuild script calling it.
Since the application that is running at the time is msbuild.exe the configuration that was loaded was msbuild.exe.config when you try to access config elements as you normally do in your app you will not get the values in your app.config file.