log4net log to database...open to sql injection - log4net

Is there an accepted way to both use the log4net ado provider and guard against SQL injection? I can do my own hand rolled scrubbing methods, but that strikes me as risky.
Is there some kind of "DontLetPeopleOwnMyDatabase" = true setting?
our current dangerous config:
<appender name="ADONetAppender" type="log4net.Appender.ADONetAppender">
<threshold value="ERROR"/>
<bufferSize value="1"/>
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<connectionString value="server=myDBServer; uid=myuserName; pwd=myPassword; database=myDatabase"/>
<commandText value="INSERT INTO errorlog([message], [ServerName], [ApplicationName]) VALUES(#message, 'myServer', 'myApp')" />
<parameter>
<parameterName value="#message"/>
<dbType value="String"/>
<size value="4000"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message"/>
</layout>
</parameter>
</appender>

Maybe I'm wrong, but you are already using parameters, so there is no risk of SQL injection. #message is passed as a separate SQL parameter by log4net, not through string concatenation.
But if you are that afraid about SQL injection, how about using a stored procedure...?
Edit Fear no more, dear OP. Here is the missing proof that the log4net logging mechanism is safe against SQL injection:
Records are written into the database either using a prepared statement or a stored procedure. The CommandType property is set to Text (System.Data.CommandType.Text) to specify a prepared statement or to StoredProcedure (System.Data.CommandType.StoredProcedure) to specify a stored procedure.
So, prepared -> pre-compiled -> safe parameter assignment.
If you need more info, you may find it here.

Related

Maintaining the last N log entries in the log file (circular logging)

Does log4net support circular logging? (I think that's the right term.)
I want to maintain the last N entries in a log file. Say N=100. If I have 100 entries and then add a 101st, the desired behavior would be to delete the 1st entry from the top of the file and add the new log entry at the bottom, so that there is always 100 (or fewer) entries, with the oldest entry at the top and the newest at the bottom.
Basically, I want to record a couple of pieces of information to a file every minute. I only am interesting in seeing/keeping the last 100 entries. I could roll my own solution, but I'm already using log4net for logging other issues and was hoping I could use it for this purpose, as well.
Thanks
Out of the box solution would be RollingFileAppender with Size limit. You cannot specify how many entries you want to keep in the file, but if you play with the size (lets say 100KB), you can get what you want.
Here is an example:
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="log.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="0" />
<maximumFileSize value="100KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
And some documentation about why setting maxSizeRollBackups is important in this case:
If set to zero, then there will be no backup files and the log file
will be truncated when it reaches MaxFileSize.
MaxSizeRollBackups RollingMode

Log4Net Writing to different files

I'm making a vehicle tracking application(ASP.NET MVC C#). I have windows service that takes data sent by GPS device. In the service I have written the code to Log the data.
Now consider a normal logging scenario in which i have only one GPS device.
08:00:24 Inside OnDataAvailable Method
08:00:25 Data Received - Device Id: 2 Data: abcdefghijkl
08:00:25 Leaving OnDataAvailable
and few more statements. and then it repeats
Now when I have more than one GPS device sending data, the log gets mixed. That is I have following kind of log:
08:00:23 Inside OnDataAvailable Method 08:00:24 Inside OnDataAvailable
Method
08:00:25 Data Received - Device Id: 2 Data: abcdefghijkl
08:00:25 Leaving OnDataAvailable
08:00:26 Data Received - Device Id: 1 Data: abcdefghijkl
08:00:26 Leaving OnDataAvailable
Now what I want to achieve is that, I should have different log files for different devices. So for device with Id 1 I have Log_D1.txt, For Device Id 2, Log_D2.txt.
Would appreciate if someone can point me in the right direction.
You should be able to use one of the context objects (like ThreadContext.Properties) to build the filename. You can configure the log file name to use properties to build up the name. So, in your case, you might store the device id in the context (are your requests being handled in separate threads?).
This article has a good explanation of how this works:
http://geekswithblogs.net/rgupta/archive/2009/03/03/dynamic-log-filenames-with-log4net.aspx
To summarize, you can configure your appender something like this:
<appender name="RollingFileAppenderV1" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="F:\HornetFeed\Log_%property{DeviceID}" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="-1" />
<maximumFileSize value="5000KB" />
<staticLogFileName value="true" />
<countDirection value="1"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%m%n" />
</layout>
<filter type="log4net.Filter.PropertyFilter">
<Key value="Version" />
<StringToMatch value="1" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
</appender>
Note the use of %property in the filename specification.
Then, in your code, you might do something like this:
private void OnDataAvailable(string id, int data)
{
ThreadContext.Properties["DeviceID"] = id;
logger.Info("Inside OnDataAvailable");
logger.Info("Leaving OnDataAvailable");
}
All log messages, at least in cases where the DeviceID property has been set, should be segregated into separated files, named, in part, by the DeviceID.

log4net creates 2 log files instead of expected one, when log4net is configure both in mine and 3rd party dll

I have 2 projects in my solution, both of class library type.
Actions: Project which contains actions, written using White (UI automation framework over MS UI Automation)
Tests: Project with test fixtures and test methods, using MbUnit
I decided to add logging using log4net for both projects. The log4net configuration I'm using is below:
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString"
value="c:/AutomationLog/Automation_%date{dd.MM.yy_HH.mm.ss}.log" />
<appendToFile value="false" />
<rollingStyle value="Once" />
<maxSizeRollBackups value="-1" />
<maximumFileSize value="10MB" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level %date{HH:mm:ss,fff} %logger - %message%newline" />
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="RollingLogFileAppender" />
</root>
<logger name="root">
<level value="OFF" />
</logger>
</log4net>
I would like that one file is created each run (one per fixture suite run). But two files are created:
Automation_27.01.13_07.33.53.log
Automation_27.01.13_07.33.53.log.1
After investigation I found that log is spitted into 2nd file each time in the same place -- when actions contain types from White is called. Looks like it happens due to White also uses log4net internally.
So, I guess, situation is like this:
I have a class which initializes log4net
I start the fixtures suite
In the tests project there is a class which runs 1st, which contains Log.Info("...")
log file is created
text is appended until..
1st action which references White's types is run from tests project
At this stage a new file is created
I guess it happens because of inside White Dlls there is another call to initialize log4net, it is hard coded inside
Any idea how to prevent log splitting without modifying the code of White (3rd party dlls)?
I have solved the problem by just renaming the config file, white looks for log4net.config name. But I still haven't got the answer - is it possible how to force log4net to be initialized just once, and skip future attempts.

log4net + multiple threads + rolling file appender

I've got this settings for log4net in the log4net.config to allow multiple threads to write to the same file:
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
<!-- Minimal locking to allow multiple threads to write to the same file -->
<lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
<file value="log\UI.log"/>
<appendToFile value="true"/>
<rollingStyle value="Date"/>
<maxSizeRollBackups value="30"/>
<datePattern value="-yyyyMMdd"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%newline%date [%thread] %-5level [%property{identity}] %logger{3} - %message%newline"/>
</layout>
</appender>
But after midnight the new created log file is being overwritten all the time and thus there is only the last one event in the file. After server restart it all goes right again till the next midnight.
So can anyone say whether this is a config issue or this is just a log4net issue?
The problem was solved by removing the locking model key since I have only one process (IIS, w3wp.exe) which uses the same logger.
<lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
Since it was said here:
If you use RollingFileAppender things become even worse as several process may try to start rolling the log file concurrently. RollingFileAppender completely ignores the locking model when rolling files, rolling files is simply not compatible with this scenario.
I think you will get unpredictable results.
My guess is that your use of a - sign on the datePattern is confusing the framework so that after the first roll any log triggers a roll event.
What happens when you try this with
<datePattern value="yyyyMMdd" />
per the example here.
To change the rolling period adjust the DatePattern value. For
example, a date pattern of "yyyyMMdd" will roll every day. See
System.Globalization.DateTimeFormatInfo for a list of available
patterns.

Log4Net + Send Email when done?

I have just started playing around with Log4Net... I now want to send an email with the full log either attached or directly in the mail. The problem with using SmtpAppender is that it requires a bufferSize which will be unknown because it should send the mail whether it's full of errors or just info.
Update: My config file
<appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">
<to value="ebb#mail.com" />
<from value="ebb#mail.com" />
<subject value="Backup Application - Log" />
<smtpHost value="mailserver" />
<authentication value="1" />
<username value="userName" />
<password value="mypw" />
<port value ="25"/>
<lossy value="true" />
<bufferSize value="500" />
<evaluator type="log4net.Core.LevelEvaluator">
<threshold value="ALL"/>
</evaluator>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%timestamp [%thread] %-5level %logger – %message%newline" />
</layout>
</appender>
BufferSize equals to the number of log messages that have to be buffered (ie if you set to 512 the mail will be sent once 512 messages have been collected).
I believe that setting it to int.MaxValue (which is 2.147.483.647) is a reasonable choice. 2 billions of messages are too much for a system, even long-running.
If you give me 10 minutes I'll confirm you (from source code) that if you clean stop your application, all logs collected so far will be sent
[Update]: confirmed!! Destructor flushes the queue as expected
[Add] I would remove both lossy and evaluator. Your problem is clear: Evaluator has precedence over buffer :) :)
The evaluator is used to flush the queue when a certain condition is met. Your condition equals to true. When this condition is triggered, the email is sent, so this is why the mail is sent at every single log call.
This is slightly different from sending ONLY info and error messages, which is achieved by log filtering.
Remove the two attributes and your code will work. Setting int.MaxValue will allow you to store the maximum possible number of messages. It's unlikely (you'd better win the Superenalotto's 178mln€ jackpot like some guys did tonight, or being hit by a comet in your head) that an application collects more than 2 billion errors/info in a run.

Resources