Monday, May 21, 2012
 
The best way to analyze your logs! Minimize
 Log4Net Mail archive   

The Log4Net mailing list is a great source of information about using log4Net, in this forum we collect all the messages in the log4net user list and some selected threads from the developer list.

Subject: Remote Appender
Prev Next
You are not authorized to post a reply.

Author Messages
ppden

05/18/2009 11:13 PM  


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

Loren Keagle

05/19/2009 1:21 AM  

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

05/19/2009 1:59 AM  


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

05/19/2009 2:17 AM  

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

05/19/2009 2:57 AM  


Thanks again for your help. But now I am at a bit of a loss. If the sink
class on the server side or on the client? I assume it was on the client
side, but as per you code it appears to be on the server side.

Also, I notice that you are not using the same pattern I use to log events.
I just use the basic log.Info(...) and the reason I though it would be a
good idea to use the remote appender is because I don't have to change the
code (over 2 milion lines of code with lots of log.info) and handle
everything by adding the new appender to the configuration file. Am I
completely wrong?

Loren Keagle

05/19/2009 7:37 AM  

Sorry about the terminology confusion.  In client/server programming,
the convention is that the client is the object that initiates the
connection.  In .Net remoting, the conventional terminology is that you
have an object that 'sources' data, and an object that 'sinks' data.  In
this case, the source is considered a client, because it initiates the
connection to the sink, which is considered a server.

This has nothing to do with whether your application itself is a server
or a client or a word processor, etc.  From log4net's perspective, you
have a source (client) of logging events, and a sink (server) which is
receiving events.  In my particular use case, I used remoting because I
have several dozen embedded machines with no local resources, so they
all send their logging information to a remote logging server.  Some
people use the remote syslog appender for this, but I needed the
flexibility of handling the logging events myself, and setting log
levels for each remote client.

As far as the logging itself is concerned, the appender works exactly
the same as the console appender, in that if you set it to INFO, only
INFO level events and higher will be sent over the remoting pipe.  You
should not change any of your logging code just to add another
appender.  It's one of the benefits of the log4net architecture.  Now
what you do with the events on the sink is completely up to you.  My use
case was to build a remote logger because I couldn't log locally, so I
simply take the events and send them to, surprise, another log4net instance!

client --(log.Info)--> RemotingAppender ----|
client --(log.Info)--> RemotingAppender ----|
client --(log.Info)--> RemotingAppender ----|---> (Network) --> logging
server --(log.Info)--> FileAppender
client --(log.Info)--> RemotingAppender ----|
client --(log.Info)--> RemotingAppender ----|


~Loren

You are not authorized to post a reply.
Forums > Log4Net > Log4Net Mail archive > Remote Appender



ActiveForums 3.7

 

 

 

 

 

 

 

 

Log4Net Dashboard

Log analysis and monitoring made easy!

Log4Net Dashboard is a log viewer that can read log statements from a variety of logging output targets.

You can download a free developer version.

  

Check it out!

On the demonstration site you can try it  with live data.demo.l4ndash.com - Try Log4Net Dashboard with live data

The mail archive is a copy of all the mail sent to the mail address: log4net-user@logging.apache.org, organized as a forum.

If you would like to participate in the mail list, send a mail to log4net-user-subscribe@logging.apache.org.

More information about the mailing list is available on: http://logging.apache.org/log4net/support.html

 

A complete topic list is available and can be viewed here (warning, it takes some time to load)

 

Copyright 2005-2008 by FaktNet AS Terms Of Use Privacy Statement