Reputation: 1167
When configuring NServiceBus in my application, I am setting up Log4Net to use a RollingFileAppender
:
.Log4Net<RollingFileAppender>(x=>
{
x.AppendToFile = true;
x.Threshold = Level.Debug;
x.MaxSizeRollBackups = 10;
x.RollingStyle = RollingFileAppender.RollingMode.Size;
x.File = "c:\\Logs\\log.txt";
})
I would like to remove buffering for testing (by setting the BufferSize = 1
)
Is this possible when using the .Log4Net()
extension?
Upvotes: 3
Views: 795
Reputation: 1167
In the end, buffering was not the issue and the solution was quite simple. It looks like the RollingFileAppender uses an exclusive lock by default so the log file was locked while the application was running.
The fix in this instance was to set: LockingModel = new FileAppender.MinimalLock();
The updated init looks like this:
.Log4Net<RollingFileAppender>(x=>
{
x.LockingModel = new FileAppender.MinimalLock();
x.Threshold = Level.Debug;
x.MaxSizeRollBackups = 10;
x.RollingStyle = RollingFileAppender.RollingMode.Size;
x.File = "c:\\Logs\\log.txt";
})
While I was searching the Log4Net docs for a buffering solution, I stumbled upon the BufferingForwardingAppender. This appender wraps non-buffering appenders providing a buffering service.
Here is what the config would look like if I wanted to add buffering to the RollingFileAppender:
.Log4Net<BufferingForwardingAppender>
(x =>
{
x.BufferSize = 50; // number of events to buffer
x.AddAppender(new RollingFileAppender()
{
LockingModel = new FileAppender.MinimalLock(),
Layout = new SimpleLayout(),
Threshold = Level.Debug,
MaxSizeRollBackups = 10,
RollingStyle = RollingFileAppender.RollingMode.Size,
File = "c:\\Logs\\log.txt",
SecurityContext = NullSecurityContext.Instance
});
})
Patrick.
Upvotes: 1
Reputation: 49250
The log4net FileAppender
classes don't provide a BufferSize
property, so you cannot set it - directly, in configuration or using that extension method. (This property is only exposed by the BufferingAppenderSkeleton
base class, which is however not a base class for the FileAppender
classes).
Actually, spelunking in the log4net code base, it looks as if that the only way you could control the buffer size used by a FileAppender
, is to write your own implementation of a LockingModelBase
. Those implementations that come with log4net, i.e. ExclusiveLock
or MinimalLock
, internally use a FileStream
constructor, that uses the default buffer size of 0x1000, i.e. 4096.
Having that said, you might be able to do something like this:
.Log4Net<RollingFileAppender>(x=>
{
x.AppendToFile = true;
x.Threshold = Level.Debug;
x.MaxSizeRollBackups = 10;
x.RollingStyle = RollingFileAppender.RollingMode.Size;
x.File = "c:\\Logs\\log.txt";
x.LockingModel = new MyUnbufferedLockingModel();
})
With MyUnbufferedLockingModel
something like this:
public class MyUnbufferedLockingModel : log4net.FileAppender.LockingModelBase
{
// This is essentially a rip-off of the default 'ExclusiveLock' class,
// but when creating the "m_stream", using an explicit buffer size of 1.
// Depending on your needs you may want to use the 'MinimalLock' class
// instead.
private Stream m_stream = null;
public override Stream AcquireLock()
{
return m_stream;
}
public override void CloseFile()
{
using (CurrentAppender.SecurityContext.Impersonate(this))
{
m_stream.Close();
}
}
public override void OpenFile(string filename, bool append, Encoding encoding)
{
try
{
using (CurrentAppender.SecurityContext.Impersonate(this))
{
string directoryName = Path.GetDirectoryName(filename);
if (!Directory.Exists(directoryName))
{
Directory.CreateDirectory(directoryName);
}
FileMode mode = append ? FileMode.Append : FileMode.Create;
m_stream = new FileStream(filename, mode, FileAccess.Write,
FileShare.Read,
1 /*BufferSize*/);
}
}
catch (Exception exception)
{
CurrentAppender.ErrorHandler.Error("Unable to acquire lock on file " + filename + ". " + exception.Message);
}
}
public override void ReleaseLock()
{
}
}
Upvotes: 2