123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
/*******************************************************************************

        copyright:      Copyright (c) 2004 Kris Bell. All rights reserved

        license:        BSD style: $(LICENSE)
      
        version:        Initial release: May 2004
        
        author:         Kris

*******************************************************************************/

module tango.util.log.AppendSocket;

private import  tango.util.log.Log;

private import  tango.io.Console;

private import  tango.io.stream.Buffered;
                
private import  tango.net.device.Socket,
                tango.net.InternetAddress;

/*******************************************************************************

        Appender for sending formatted output to a Socket.

*******************************************************************************/

public class AppendSocket : Appender
{
        private const(char)[] eol;
        private Mask            mask_;
        private Bout            buffer;
        private Socket          conduit;
        private InternetAddress address;
        private bool            connected;

        /***********************************************************************
                
                Create with the given Layout and address. Specify an end-
                of-line string if you want that appended to each message 

        ***********************************************************************/

        this (InternetAddress address, Appender.Layout how = null, const(char)[] eol=null)
        {
                layout (how);

                this.eol     = eol;
                this.address = address;
                this.conduit = new Socket;
                this.buffer  = new Bout (conduit);

                // Get a unique fingerprint for this class
                mask_ = register (address.toString());
        }

        /***********************************************************************
                
                Return the fingerprint for this class

        ***********************************************************************/

        @property override const Mask mask ()
        {
                return mask_;
        }

        /***********************************************************************
                
                Return the name of this class

        ***********************************************************************/

        @property override  const const(char)[] name ()
        {
                return this.classinfo.name;
        }
                
        /***********************************************************************
                
                Append an event to the output. If the operations fails
                we have to revert to an alternative logging strategy, 
                which will probably require a backup Appender specified
                during construction. For now we simply echo to Cerr if
                the socket has become unavailable.               
                 
        ***********************************************************************/

        override void append (LogEvent event)
        {
                auto layout = layout();

                if (buffer)
                   {
                   try {
                       if (! connected)
                          {
                          conduit.connect (address);
                          connected = true;
                          }

                       layout.format (event, &buffer.write);
                       if (eol.length)
                           buffer.write (eol);
                       buffer.flush();
                       return;
                       } catch (Exception e)
                               {
                               connected = false;
                               Cerr ("SocketAppender.append :: "~e.toString()).newline;
                               }
                   }

                Cerr (event.toString()).newline;
        }

        /***********************************************************************
            
                Close the socket associated with this Appender
                    
        ***********************************************************************/

        override void close ()
        {
                if (conduit)
                    conduit.detach();
                conduit = null;
        }
}