I did not alter the connection functionality at all. I simply added a
timer: to the log4net 1.2.10 RemotingAppender as follows:
public class TimedRemotingAppender : RemotingAppender
{
public TimedRemotingAppender()
{
FlushPeriod = 10; // seconds
timer = new Timer(FlushBuffer);
}
/// <summary>
/// The period, in seconds, at which the buffer is sent
regardless of being full
/// </summary>
public int FlushPeriod { get; set; }
private readonly Timer timer;
private void FlushBuffer(object state) { Flush(); }
protected override void Append(LoggingEvent loggingEvent)
{
base.Append(loggingEvent);
timer.Change(FlushPeriod * 1000, Timeout.Infinite);
}
}
Which is configured the same as the RemotingAppender:
<appender name="RemotingAppender"
type="APS.Gate.TimedRemotingAppender" >
<sink value="tcp://localhost:9250/LoggingSink" />
<bufferSize value="100" />
<flushPeriod>20</flushPeriod>
</appender>
My server implementation is also trivially simple:
public class RemotingLogger : MarshalByRefObject,
RemotingAppender.IRemoteLoggingSink
{
private static readonly ILog logger =
LogManager.GetLogger(typeof(RemotingLogger));
public void LogEvents(LoggingEvent[] events)
{
if (events == null) return;
lock (this)
{
foreach (LoggingEvent le in events)
{
logger.Logger.Log(le);
}
}
}
}
All that is required for me is to add the following code to your remote
event sink:
TcpServerChannel channel = new
TcpServerChannel(Settings.Default.RemotingPort);
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemotingLogger),
"LoggingSink", WellKnownObjectMode.Singleton);
This works fine for me. Perhaps you have a firewall issue? My example
is for source and sink on the same machine. If the sink is on a
different machine, you'll need to open up your firewall for the port you
decide to use.
~Loren
ppden wrote:
Thanks Loren. However, it still doesn't work. I looked into the source for
the remote appender and at no point I see the channel registration. What is
version of log4net ar you using? When you sub-classes the appender, did you
handle the .net remoting connection (channel services and remoting
configuration) yourself?
Loren Keagle wrote:
With a buffer of 95, you won't see anything on the remote appender until
95 log events have been queued. I ended up subclassing the appender to
add a timer to flush automatically every N seconds. Try setting the
buffer length down to 1 or disable it entirely.
~Loren
ppden wrote:
Greetings,
I have been using log4net for a while and I think it rocks! It has
allowed
me to focus on the business functionality and have provided a very
reliable
and elegant platform for logging. So thanks to the people who maintain
it.
I have been trying all day to get the remote appender to work. I have
looked
for examples but didn't find anything other than going into the source
code
and checking out the unit tests.
Here is my client class:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using log4net.Core;
using IRemoteLoggingSink =
log4net.Appender.RemotingAppender.IRemoteLoggingSink;
namespace Miner.Responder.MultiSpeakInterfaces.Common
{
public class RemoteLoggingSinkImpl : MarshalByRefObject,
IRemoteLoggingSink
{
public static readonly RemoteLoggingSinkImpl Instance =
new
RemoteLoggingSinkImpl();
public LoggingEvent[] Events = null;
private TcpChannel m_remotingChannel;
#region Public Instance Constructors
private RemoteLoggingSinkImpl()
{
}
#endregion Public Instance Constructors
public void RegisterRemotingServerChannel()
{
if (m_remotingChannel == null)
{
m_remotingChannel = new TcpChannel(8085);
// Setup remoting server
try
{
ChannelServices.RegisterChannel(m_remotingChannel);
}
catch(Exception)
{
}
// Marshal the sink object
RemotingServices.Marshal(RemoteLoggingSinkImpl.Instance,
"LoggingSink", typeof(IRemoteLoggingSink));
}
}
#region Implementation of IRemoteLoggingSink
/// <summary>
/// Logs the events to the repository.
/// </summary>
/// The events to log.
/// <remarks>
/// The events passed are logged to the <see
cref="LoggerRepository"/>
/// </remarks>
public void LogEvents(LoggingEvent[] events)
{
Events = events;
}
#endregion Implementation of IRemoteLoggingSink
#region Override implementation of MarshalByRefObject
/// <summary>
/// Obtains a lifetime service object to control the lifetime
/// policy for this instance.
/// </summary>
/// <returns>
/// <c>null</c> to indicate that this instance should
live
/// forever.
/// </returns>
public override object InitializeLifetimeService()
{
return null;
}
#endregion Override implementation of MarshalByRefObject
}
}
Pretty simple, correct?
My server is also very simple. Here is the configuration:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net"
type="System.Configuration.IgnoreSectionHandler"
/>
</configSections>
<log4net>
<root>
<level value="ERROR" />
<appender-ref ref="EventLogAppender" />
<appender-ref ref="FileAppender" />
<appender-ref ref="RemotingAppender"/>
<level value="INFO"/>
<appender-ref ref="FileAppender" />
<appender-ref ref="RemotingAppender"/>
</root>
<appender name="TraceAppender" type="log4net.Appender.TraceAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern
value="%date [%thread] %-5level %logger [%property{NDC}] -
%message%newline" />
</layout>
</appender>
<appender name="ConsoleAppender"
type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern
value="%date [%thread] %-5level %logger [%property{NDC}] -
%message%newline" />
</layout>
</appender>
<appender name="FileAppender" type="log4net.Appender.FileAppender">
<file value="c:\\Log\\log-file.txt" />
<appendToFile value="true" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern
value="%date [%thread] %-5level %logger [%property{NDC}] -
%message%newline" />
</layout>
</appender>
<appender name="EventLogAppender"
type="log4net.Appender.EventLogAppender" >
<applicationName value="Test Service" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger
[%property{NDC}] - %message%newline" />
</layout>
</appender>
<appender name="RemotingAppender"
type="log4net.Appender.RemotingAppender" >
<sink value="tcp://localhost:8085/LoggingSink" />
<lossy value="false" />
<bufferSize value="95" />
<onlyFixPartialEventData value="true" />
</appender>
</log4net>
</configuration>
and my server code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private static readonly log4net.ILog _log =
log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
while (true)
{
_log.Info(DateTime.Now.ToLongTimeString());
Thread.Sleep(1000 * 10);
}
}
}
}
I can see the remoting listener start but a connection is never made. The
server is generating the messages, I can see then on the event log. Any
ideas?
Cheers,
PP
------------------------------------------------------------------------
No virus found in this incoming message.
Checked by AVG - www.avg.com
Version: 8.5.339 / Virus Database: 270.12.33/2120 - Release Date:
05/18/09 06:28:00
------------------------------------------------------------------------
No virus found in this incoming message.
Checked by AVG - www.avg.com
Version: 8.5.339 / Virus Database: 270.12.33/2120 - Release Date: 05/18/09 06:28:00