log4.net does not write until Windows Service Stops - c#

I am using log4.net in my Windows Service for logging.
Here is my config;
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<file value="MyApp.log" />
<appendToFile value="true" />
<bufferSize value="1" />
<maximumFileSize value="100000KB" />
<maxSizeRollBackups value="5" />
<rollingStyle value="Size" />
<immediateFlush value="true" />
</appender>
for some reason it does not write into file until I stop the service. Is there a sort of buffering is happening? Once I stop the service all pending logs are getting written.
What would be the issue?

Strange, are you sure it actually works at all?
My version of log4net (version 1.2.11) requires a Layout (otherwise nothing gets logged) and does not have a BufferSize property (but that doesn't stop it working)
Also, immediateFlush should default to true, so isn't needed.
The following works for me.
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<file value="MyApp.log" />
<appendToFile value="true" />
<maximumFileSize value="100000KB" />
<maxSizeRollBackups value="5" />
<rollingStyle value="Size" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %level %logger - %message%newline" />
</layout>
</appender>

I had a similar problem with my windows service, which only wrote to the log when the Service was stopped.
My initial thought was this feels like some sort of locking issue, either in the .Net code or on the file itself and by stopping the windows service, it removes the lock and allows the write to complete.
Having said that, I noticed that changing the User Account under which the Windows Service ran, to one with higher privileges, made it update immediately, rather than only on Service Stop.
I changed it from Local System to Administrator and it fixed the problems. Of course, running as Administrator isn't recommended, but it may at least help you to diagnosis if the problem is related to Profile/Permissions.
I still haven't figured out the root cause of this yet...

Related

Log4Net RollingFileAppender losing messages

I am using log4net to log to files and for some reason, some log messages are lost, and always in the same spot. First my configuration:
<log4net>
<root>
<level value="ALL" />
<appender-ref ref="RollingFileAppender" />
</root>
<appender name="aiAppender" type="Microsoft.ApplicationInsights.Log4NetAppender.ApplicationInsightsAppender, Microsoft.ApplicationInsights.Log4NetAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message%newline" />
</layout>
</appender>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="logs\import.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
</log4net>
The aiAppender, while defined, is not used.
The log pattern is that I initially burst log about 88 lines of which all are there. Then the missing log period starts and lasts approx 6 seconds. Then the logging continues and everything is logged from that point onward.
If I remove the burst logging and replace it with only a few log entries, nothing is lost.
Apparently RollingFileAppender can lose messages. I wasn't aware of that.
I am certain this is an issue with log4net, as I have a log-wrapper where I split my log messages to both log4net and to application insights (the aiAppender didn't do a good enough job for us) and application insights does receive the messages that log4net doesn't log.
Can I configure the RollingFileAppender to avoid losing messages?
Edit: The log wrapper logs first to log4net and then to application insights so it is not a question about the application insights logging that prevents log4net logging.
You can only debug this when you activate internal debugging. Active the debugger and see if for example log4net is reconfigured at some point.

Log4net outputting random method names after applciation is obfuscated via .net -reactor

I have obfuscated my application using .net reactor. Application is working fine other then on some places method names in log file created through log4net is coming as random string.
Strange thing is within same method different logs are coming with different behavior. Some coming with actual method name while other with random method name.
e.g,
My log4net appender is
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender" >
<file value="..\\Logs\\MyApp_N1" />
<encoding value="utf-8" />
<appendToFile value="true" />
<datePattern value="_yyyyMMdd'.log'" />
<staticLogFileName value="false" />
<rollingStyle value="Composite"/>
<maxSizeRollBackups value="-1"/>
<maximumFileSize value="10MB"/>
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<filter type="log4net.Filter.LevelRangeFilter">
<acceptOnMatch value="true" />
<levelMin value="DEBUG" />
<levelMax value="FATAL" />
</filter>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d{yyyy-MM-dd HH:mm:ss.fff} %p MyApp N1 %t %c{1}.%M %property{SessionId} %m%n" />
</layout>
</appender>
log4net version 2.0.8
.net reactor version 5.0
Sample Log Messages are
2017-12-08 15:17:33.722 DEBUG TWS N1 13 MyclassName.SendMessage My method start
2017-12-08 15:17:33.840 DEBUG TWS N1 13 MyclassName.urT1VHsGarQ1gTcc8O Message request add in db id =166364
2017-12-08 15:17:33.852 DEBUG TWS N1 13 MyclassName.SendMessage Message Services - Send End
If the method 'urT1VHsGarQ1gTcc8O' is not a public one then this is the expected output.
To obfuscate all public classes and methods as well you need to set "2. Protection Settings"->"Obfuscation"->"Obfuscate Public Types" to "True".

Problematic N-Tier logging with log4net

I am currently developing series of web services in WCF using .NET 4.5. For my logging I have chosen log4net framework but I found that its a big problem to use it in my project design.
I have everything separated into projects like this :
DataAccess
Common
etc. etc.
ExternalServicesContracts
ExternalServices
ExternalServicesProxies
InternalService
All of the services projects contains more services.
Situation
I need my log files to look like this ServiceName_YYYY_DDMM.log.
So in the log4net config file i need to use different loggers per namespace of the web service. I can achieve it by using loggers like this :
For the first service :
private static readonly ILog Log = LogManager.GetLogger(typeof(MyFirstService));
And the same for the second service :
private static readonly ILog Log = LogManager.GetLogger(typeof(MySecondService));
and then in config file I just point to them by loggers
<logger name="ExternalServices.MyFirstService">
<appender-ref ref="FirstServiceAppender"/>
</logger>
<logger name="ExternalServices.MySecondService">
<appender-ref ref="SecondServiceAppender"/>
</logger>
And in appenders
<appender type="log4net.Appender.RollingFileAppender" name="FirstServiceAppender">
<file value="c:\temp\FirstService"/>
<rollingStyle value="Composite" />
<datePattern value="_yyyy_MM_dd.lo\g"/>
<maxSizeRollBackups value="-1"/>
<maximumFileSize value="100MB"/>
....
</appender>
<appender type="log4net.Appender.RollingFileAppender" name="SecondServiceAppender">
<file value="c:\temp\SecondService"/>
<rollingStyle value="Composite" />
<datePattern value="_yyyy_MM_dd.lo\g"/>
<maxSizeRollBackups value="-1"/>
<maximumFileSize value="100MB"/>
....
</appender>
Problem
After this change, I can`t see anything from my DataAccess and Common because I had to do the same strategy with classes inside the layer.
So the logger will be loaded the same way like this:
private static readonly ILog Log = LogManager.GetLogger(typeof(UsersProvider));
I could add another logger for both projects but I need the logs from it to be written inside the same file (the log file used by the caller).
Question
I really cant separate the services into more projects because of the client.
Is there a way to use the same logger inside a library as the caller is using ? (So the DataAccess and Common writes logs into FirstServiceAppender when the service is using it.)
Or is there any pattern that would get me out of this situation ?
I don't have time to try this out right now, but this should be easier that you think it is. You can try configuring log4net to have a dynamic file name based on a GlobalContext.Properties value. In each service, put a value GlobalContext.Properties that "names" the service. This should be ok as each service is essentially a separate process, so using the GlobalContext should not result in any conflicts. This way you will need only one file target and your loggers can be configured very simply (just send the output to the one file target).
Configuration should be something like this:
<appender type="log4net.Appender.RollingFileAppender" name="RollingFileAppender">
<file type="log4net.Util.PatternString" value="C:\temp\%property{Service}"/>
<rollingStyle value="Composite" />
<datePattern value="_yyyy_MM_dd.log"/>
<maxSizeRollBackups value="-1"/>
<maximumFileSize value="100MB"/>
....
</appender>
<root>
<appender-ref ref="RollingFileAppender" />
</root>
In your code, when each service is initialized, put something like this:
GlobalContext.Properties["Service"] = "FirstService"; // for FirstService
GlobalContext.Properties["Service"] = "SecondService"; // for SecondService
Note that you must set the value into GlobalContext.Properties BEFORE anything else is done with log4net. The best place would be in the static constructor of your application/service.
This configuration should all logs generated in "FirstService" to be written to the FirstService log file and all logs generated in "SecondService" to be written to the SecondService log.
Update:
<appender name="DynamicRollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="c:\temp\%property{Service}" />
<datePattern value="_yyyy_MM_dd.lo\g" />
<appendToFile value="true" />
<maxSizeRollBackups value="-1" />
<maximumFileSize value="5000KB" />
<preserveLogFileNameExtension value="true"/>
<staticLogFileName value="false" />
<countDirection value="1"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%method] - %message%newline" />
</layout>
</appender>
You can pass logger as a parameter for classes. So maybe your DataAccess classes should take a logger as a constructor parameter and use it for loggin. Then you could give a desired logger from outside.

Creating new Log file everyday and deleting previous log files

I have one windows service. For Logging purpose in that service I am using Log4Net.dll. Now my requirement is that I want to create a new log file everyday and it should keep the log of only previous 7 days. Means on 8th day, it should delete first day file and use new file. I am using appender as:
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="D:\Log\%property{LogName}" />
<AppendToFile value="true" />
<rollingStyle value="Date" />
<maxSizeRollBackups value="100" />
<staticLogFileName value="false" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%newline %date %-5level %C.%M() - %message" />
</layout>
</appender>
And at service startup I am configuring logger as:
log4net.GlobalContext.Properties["LogName"] = "App_" + DateTime.Now.ToString("MMddyyyy") + ".log";
log4net.Config.XmlConfigurator.Configure();
So is there any functionality of Log4Net that will achieve above functionality? Or is there any other way to do it? Any type of help will be appreciated.
I'm afraid you can't: RollingFileAppender Class
A maximum number of backup files when rolling on date/time boundaries
is not supported
Have a look at this thread for other suggestions: Log4Net: set Max backup files on RollingFileAppender with rolling Date
To implement log file everyday you would use:
<rollingStyle value="Date" />
<datePattern value="yyyyMMdd" />

log4net EventLog custom logname created, but not used

In a project, i'm using log4net to write down in the event log. I need to create a custom log so all will go there. I have tried to add the event to different logs, and it worked, but for some reasons, now it is impossible to change the logname from the config file. Even if I change it, it will keep the previous one and log into it. Here is a sample of my app.config:
<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date{yyyy-MMMM-dd HH:mm:ss, fff} [%thread] %level %message %exception%newline"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="DEBUG" />
<levelMax value="FATAL" />
</filter>
<ApplicationName>TestLoggerFichierConfig</ApplicationName>
<LogName>AgentLogger</LogName>
</appender>
I read that the event log must be restarted when adding a new log so the recent events will be displayed in it. I did this, and it allowed me to see the new log that has been created, but nothing will go there. Is it possible to force Log4Net to stop using the previous log to rather use the one I defined in the app.config?
Thanks for the help.
Update:
It seems that le EventLogs recognizes the source application and decide in wich log to put the new events since he remembers where it previously went. When I first set the logName, it works fine. If I stop the app, change the logname and restart it, the event will still go to the previous log. If the logName does not exists in the event log, it will be created, but not used! There might be something to do, but it is not in the side of log4net, and it may be dangerous to change the windows settings at this level. I created two eventLogAppender on the same app.config file, both pointing at different logs. the events got to the same log though. It is being obvious that the problem doesn't come from log4net, and the solution to my problem will not be solved by code. Thanks for the great advices though.
Something is probably wrong with your configuration and it is simply not telling you about it because log4net itself is designed to never, ever throw errors.
You can turn on internal debugging for log4net, but don't deploy to production with log4net debugging turned on. Weirdness will eventually happen if deploy your product with the log4net debugging switch on.
http://haacked.com/archive/2006/09/27/Log4Net_Troubleshooting.aspx
http://logging.apache.org/log4net/release/faq.html (see the troubleshooting section)
I ran into this and it wasn't down to log4net but the re-mapping of the source to a new custom log. I took log4net out of the equation and finding that the problem occurred usint the EventLog class directly, I eventually found EventLog.CreateEventSource is not creating a custom log
I think it's also the reason behind this Windows service always writes to custom log and application log
First and foremost, I'd encourage you to turn on internal debugging, as found in the link ntcolonel posted. Add this to your config file:
<add key="log4net.Internal.Debug" value="true"/>
Perhaps I am not understanding your question entirely, but I'd like to ensure you have both created the appender and properly tell log4net that you want to actually use that appender:
<log4net debug="true">
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="Logs\SomeApplication.xml"/>
<appendToFile value="true"/>
<rollingStyle value="Size"/>
<countDirection value="1"/>
<maxSizeRollBackups value="30"/>
<maximumFileSize value="10MB"/>
<staticLogFileName value="true"/>
<lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
<layout type="log4net.Layout.XmlLayoutSchemaLog4j">
<locationInfo value="true"/>
</layout>
</appender>
<appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">
<to value="SomeDistributionList#somehost.com"/>
<from value="SomeApplication#somehost.com"/>
<subject type="log4net.Util.PatternString" value="Some Application Error - %property{log4net:HostName}"/>
<smtpHost value="smtp.somehost.com"/>
<bufferSize value="1"/>
<threshold value="ERROR"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %property{log4net:HostName} %logger %level %newline%newline%property{ExceptionThrottleInformation}%newline%newline%message%newline"/>
</layout>
<filter type="SomeNamespace.SomeSubNamespace.Log4Net.ExceptionThrottleFilter, SomeSubNamespace">
<threshold value="10"/>
<thresholdTimeoutSeconds value="60"/>
<timeoutSecondsBetweenMessages value="600000"/>
<exceptionText value="Timeout expired"/>
</filter>
</appender>
<appender name="DatabaseAppender" type="SomeNamespace.SomeSubNamespace.DatabaseTraceAppender, SomeSubNamespace">
<hoursToKeepInformationalTraces value="48"/>
<hoursToKeepErrorTraces value="96"/>
<threshold value="INFO"/>
</appender>
<root>
<level value="INFO"/>
<appender-ref ref="RollingFileAppender"/>
<appender-ref ref="SmtpAppender"/>
<appender-ref ref="DatabaseAppender"/>
</root>
Note that while I have multiple appenders, I reference which to call within the root tag. Since you didn't post your whole config file, it's tough to tell if everything is matching as it should.

Categories