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


Reply via email to