I have made a DatagramSocketAppender, used DatagramSocket. In my project, I
have another TCP short-connection connector. When connect fail,
DatagramSocket will fail. I had replaced it with linux-socket, and it works
fine.

In attachments, dgramsocketappender_old.* are the implementation with
DatagramSocket, dgramsocketappender.* are the implementation with
linux-socket
/*
 * Copyright 2003,2004 The Apache Software Foundation.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
#include <dgramsocketappender.h>
#include <log4cxx/logstring.h>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/helpers/optionconverter.h>
#include <log4cxx/helpers/stringhelper.h>
#include <log4cxx/helpers/datagrampacket.h>
#include <log4cxx/helpers/socketimpl.h>
#include <log4cxx/helpers/bytebuffer.h>
#include <log4cxx/spi/loggingevent.h>
#include <arpa/inet.h>

using namespace log4cxx;
using namespace log4cxx::helpers;
using namespace log4cxx::net;

IMPLEMENT_LOG4CXX_OBJECT(DatagramSocketAppender)

class InvalidAddressException : public SocketException
{
};


DatagramSocketAppender::DatagramSocketAppender()
: sock(-1), port(0), locationInfo(false)
{
        memset(&address, 0, sizeof(address));
        address.sin_addr.s_addr = (in_addr_t)-1;
        //this->dgramSocket = new DatagramSocket;
}

DatagramSocketAppender::DatagramSocketAppender(const LogString& host, int port_)
: sock(-1), remoteHost(host), port(port_), locationInfo(false)
{
        memset(&address, 0, sizeof(address));
        address.sin_addr.s_addr = (in_addr_t)-1;
}

DatagramSocketAppender::~DatagramSocketAppender()
{
        finalize();
}

void DatagramSocketAppender::activateOptions()
{
        memset(&address, 0, sizeof(address));
        address.sin_family = AF_INET;
        address.sin_port = htons(port);

        address.sin_addr.s_addr = inet_addr(remoteHost.c_str());
        if(address.sin_addr.s_addr == (in_addr_t)-1)
        {
                throw InvalidAddressException();
        }

        if (sock != -1)
        {
                ::close(sock);
                sock = 1;
        }

        sock = socket(AF_INET, SOCK_DGRAM, 0);
        int i=1;
        setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&i, sizeof(int));

}

void DatagramSocketAppender::setOption(const LogString& option,
        const LogString& value)
{
        if (StringHelper::equalsIgnoreCase(option, "REMOTEHOST", "remotehost"))
        {
                setRemoteHost(value);
        }
        else if (StringHelper::equalsIgnoreCase(option, "PORT", "port"))
        {
                setPort(OptionConverter::toInt(value, 0));
        }
        else if (StringHelper::equalsIgnoreCase(option, "LOCATIONINFO", 
"locationinfo"))
        {
                setLocationInfo(OptionConverter::toBoolean(value, false));
        }
        else
        {
                AppenderSkeleton::setOption(name, value);
        }

        if (remoteHost != "" && port != 0 && sock == -1)
        {
                activateOptions();
        }
}

void DatagramSocketAppender::close()
{
        if(closed)
        {
                return;
        }

        closed = true;
        cleanUp();
}

void DatagramSocketAppender::cleanUp()
{
        /*if(dgramSocket != 0)
        {
                try
                {
                        dgramSocket->close();
                }
                catch(IOException& e)
                {
                        LogLog::error("Could not close socket :", e);
                }
                
                dgramSocket = 0;
        }*/
        ::close(sock);
        sock = -1;
}

void DatagramSocketAppender::append(const spi::LoggingEventPtr& event, 
log4cxx::helpers::Pool& pool)
{
        if(sock == -1)
        {
                errorHandler->error(
                                "Invalid remote address is set for 
DatagramSocketAppender.");
                return;
        }

        LogString message;
        this->layout->format(message, event, pool);
        sendto(sock, message.c_str(), message.size(), 0, reinterpret_cast<const 
sockaddr*>(&address), sizeof(address));

        /*if(dgramSocket != NULL) try
        {
                DatagramPacketPtr packet = new 
DatagramPacket((void*)message.c_str(), message.size(), this->address, 
this->port);
                dgramSocket->send(packet);
        }
        catch(SocketException& e)
        {
                LogLog::warn("Detected problem with connection: ", e);
        }*/
}


/*
 * Copyright 2003,2004 The Apache Software Foundation.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
#ifndef _LOG4CXX_NET_DGRAM_SOCKET_APPENDER_H
#define _LOG4CXX_NET_DGRAM_SOCKET_APPENDER_H
 
#include <log4cxx/appenderskeleton.h>
#include <log4cxx/helpers/datagramsocket.h>
#include <log4cxx/helpers/thread.h>
#include <netinet/in.h>

namespace log4cxx
{
	namespace net
	{
		class LOG4CXX_EXPORT DatagramSocketAppender;
		typedef helpers::ObjectPtrT<DatagramSocketAppender> DatagramSocketAppenderPtr;
       
      	class LOG4CXX_EXPORT DatagramSocketAppender : public AppenderSkeleton
    	{
    	protected:
			int sock;

    		/**
    		IP address
    		*/
			sockaddr_in address;
    		//helpers::InetAddressPtr address;


    		/**
    		host name
    		*/
    		LogString remoteHost;

    		int port;
    		bool locationInfo;

    	public:
			DECLARE_LOG4CXX_OBJECT(DatagramSocketAppender)
			BEGIN_LOG4CXX_CAST_MAP()
				LOG4CXX_CAST_ENTRY(DatagramSocketAppender)
				LOG4CXX_CAST_ENTRY_CHAIN(AppenderSkeleton)
			END_LOG4CXX_CAST_MAP()

    		DatagramSocketAppender();
			~DatagramSocketAppender();

    		/**
    		Connects to remote server at <code>host</code> and <code>port</code>.
    		*/
    		DatagramSocketAppender(const LogString& host, int port);

    		/**
    		Connect to the specified <b>RemoteHost</b> and <b>Port</b>.
    		*/
    		void activateOptions();

		    /**
		    Set options
		    */
			virtual void setOption(const LogString& option, const LogString& value);
			
    		/**
    		* Close this appender.
    		*
    		* <p>This will mark the appender as closed and call then 
    		* #cleanUp method.
    		* */
    		void close();

    		/**
    		* Drop the connection to the remote host and release the underlying
    		* connector thread if it has been created
    		* */
    		void cleanUp();

    		void connect();


    		virtual void append(const spi::LoggingEventPtr& event, log4cxx::helpers::Pool&);

    		/**
    		* The SocketAppender does not use a layout. Hence, this method
    		* returns <code>false</code>.
    		* */
    		bool requiresLayout() const
    			{ return true; }

    		/**
    		* The <b>RemoteHost</b> option takes a string value which should be
    		* the host name of the server where a 
			* [EMAIL PROTECTED] net::SocketNode SocketNode} is running.
    		* */
    		inline void setRemoteHost(const LogString& host)
    			{ 
				//address = new helpers::InetAddress(host, host);
    			remoteHost = host; }

    		/**
    		Returns value of the <b>RemoteHost</b> option.
    		*/
    		inline const LogString& getRemoteHost() const
    			{ return remoteHost; }

    		/**
    		The <b>Port</b> option takes a positive integer representing
    		the port where the server is waiting for connections.
    		*/
    		void setPort(int port)
    			{ this->port = port; }

    		/**
    		Returns value of the <b>Port</b> option.
    		*/
    		int getPort() const
    			{ return port; }

    		/**
    		The <b>LocationInfo</b> option takes a boolean value. If true,
    		the information sent to the remote host will include location
    		information. By default no location information is sent to the server.
    		*/
    		void setLocationInfo(bool locationInfo)
    			{ this->locationInfo = locationInfo; }

    		/**
    		Returns value of the <b>LocationInfo</b> option.
    		*/
    		bool getLocationInfo() const
    			{ return locationInfo; }
   
       private:
			//log4cxx::helpers::DatagramSocketPtr dgramSocket;
        }; // class DatagramSocketAppender
    } // namespace net
}; // namespace log4cxx

#endif // _LOG4CXX_NET_DGRAM_SOCKET_APPENDER_H

/*
 * Copyright 2003,2004 The Apache Software Foundation.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
#include <dgramsocketappender.h>
#include <log4cxx/logstring.h>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/helpers/optionconverter.h>
#include <log4cxx/helpers/stringhelper.h>
#include <log4cxx/helpers/datagrampacket.h>
#include <log4cxx/helpers/socketimpl.h>
#include <log4cxx/helpers/bytebuffer.h>
#include <log4cxx/spi/loggingevent.h>

using namespace log4cxx;
using namespace log4cxx::helpers;
using namespace log4cxx::net;

IMPLEMENT_LOG4CXX_OBJECT(DatagramSocketAppender)

// The default port number of remote logging server (4560)
int DatagramSocketAppender::DEFAULT_PORT                 = 4561;


DatagramSocketAppender::DatagramSocketAppender()
: port(DEFAULT_PORT), locationInfo(false)
{
        this->dgramSocket = new DatagramSocket;
}

DatagramSocketAppender::DatagramSocketAppender(const LogString& host, int port_)
: address(InetAddress::getByName(host)),
  remoteHost(host), port(port_), locationInfo(false)
{
}

DatagramSocketAppender::~DatagramSocketAppender()
{
        finalize();
}

void DatagramSocketAppender::activateOptions()
{
}

void DatagramSocketAppender::setOption(const LogString& option,
        const LogString& value)
{
        if (StringHelper::equalsIgnoreCase(option, "REMOTEHOST", "remotehost"))
        {
                setRemoteHost(value);
        }
        else if (StringHelper::equalsIgnoreCase(option, "PORT", "port"))
        {
                setPort(OptionConverter::toInt(value, DEFAULT_PORT));
        }
        else if (StringHelper::equalsIgnoreCase(option, "LOCATIONINFO", 
"locationinfo"))
        {
                setLocationInfo(OptionConverter::toBoolean(value, false));
        }
        else
        {
                AppenderSkeleton::setOption(name, value);
        }
}

void DatagramSocketAppender::close()
{
        if(closed)
        {
                return;
        }

        closed = true;
        cleanUp();
}

void DatagramSocketAppender::cleanUp()
{
        if(dgramSocket != 0)
        {
                try
                {
                        dgramSocket->close();
                }
                catch(IOException& e)
                {
                        LogLog::error("Could not close socket :", e);
                }
                
                dgramSocket = 0;
        }
}

void DatagramSocketAppender::append(const spi::LoggingEventPtr& event, 
log4cxx::helpers::Pool& pool)
{
        if(address == NULL)
        {
                errorHandler->error(
                        "No remote host is set for DatagramSocketAppender named 
\"" +
                        name+"\".");
                return;
        }

        if(dgramSocket != NULL) try
        {
/*      
                if(locationInfo)
                {
                        event.getLocationInformation();
                }
*/
                LogString message;
                this->layout->format(message, event, pool);
                DatagramPacketPtr packet = new 
DatagramPacket((void*)message.c_str(), message.size(), this->address, 
this->port);
                dgramSocket->send(packet);
        }
        catch(SocketException& e)
        {
                LogLog::warn("Detected problem with connection: ", e);
        }
}


/*
 * Copyright 2003,2004 The Apache Software Foundation.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
#ifndef _LOG4CXX_NET_DGRAM_SOCKET_APPENDER_H
#define _LOG4CXX_NET_DGRAM_SOCKET_APPENDER_H
 
#include <log4cxx/appenderskeleton.h>
#include <log4cxx/helpers/datagramsocket.h>
#include <log4cxx/helpers/thread.h>

namespace log4cxx
{
	namespace net
	{
		class LOG4CXX_EXPORT DatagramSocketAppender;
		typedef helpers::ObjectPtrT<DatagramSocketAppender> DatagramSocketAppenderPtr;
       
      	class LOG4CXX_EXPORT DatagramSocketAppender : public AppenderSkeleton
    	{
    	public:
    		/**
    		The default port number of remote logging server (4560).
    		*/
    		static int DEFAULT_PORT;
    	protected:

    		/**
    		IP address
    		*/
    		helpers::InetAddressPtr address;


    		/**
    		host name
    		*/
    		LogString remoteHost;

    		int port;
    		bool locationInfo;

    	public:
			DECLARE_LOG4CXX_OBJECT(DatagramSocketAppender)
			BEGIN_LOG4CXX_CAST_MAP()
				LOG4CXX_CAST_ENTRY(DatagramSocketAppender)
				LOG4CXX_CAST_ENTRY_CHAIN(AppenderSkeleton)
			END_LOG4CXX_CAST_MAP()

    		DatagramSocketAppender();
			~DatagramSocketAppender();

    		/**
    		Connects to remote server at <code>host</code> and <code>port</code>.
    		*/
    		DatagramSocketAppender(const LogString& host, int port);

    		/**
    		Connect to the specified <b>RemoteHost</b> and <b>Port</b>.
    		*/
    		void activateOptions();

		    /**
		    Set options
		    */
			virtual void setOption(const LogString& option, const LogString& value);
			
    		/**
    		* Close this appender.
    		*
    		* <p>This will mark the appender as closed and call then 
    		* #cleanUp method.
    		* */
    		void close();

    		/**
    		* Drop the connection to the remote host and release the underlying
    		* connector thread if it has been created
    		* */
    		void cleanUp();

    		void connect();


    		virtual void append(const spi::LoggingEventPtr& event, log4cxx::helpers::Pool&);

    		/**
    		* The SocketAppender does not use a layout. Hence, this method
    		* returns <code>false</code>.
    		* */
    		bool requiresLayout() const
    			{ return true; }

    		/**
    		* The <b>RemoteHost</b> option takes a string value which should be
    		* the host name of the server where a 
			* [EMAIL PROTECTED] net::SocketNode SocketNode} is running.
    		* */
    		inline void setRemoteHost(const LogString& host)
    			{ address = helpers::InetAddress::getByName(host);
    			remoteHost = host; }

    		/**
    		Returns value of the <b>RemoteHost</b> option.
    		*/
    		inline const LogString& getRemoteHost() const
    			{ return remoteHost; }

    		/**
    		The <b>Port</b> option takes a positive integer representing
    		the port where the server is waiting for connections.
    		*/
    		void setPort(int port)
    			{ this->port = port; }

    		/**
    		Returns value of the <b>Port</b> option.
    		*/
    		int getPort() const
    			{ return port; }

    		/**
    		The <b>LocationInfo</b> option takes a boolean value. If true,
    		the information sent to the remote host will include location
    		information. By default no location information is sent to the server.
    		*/
    		void setLocationInfo(bool locationInfo)
    			{ this->locationInfo = locationInfo; }

    		/**
    		Returns value of the <b>LocationInfo</b> option.
    		*/
    		bool getLocationInfo() const
    			{ return locationInfo; }
   
       private:
			log4cxx::helpers::DatagramSocketPtr dgramSocket;
        }; // class DatagramSocketAppender
    } // namespace net
}; // namespace log4cxx

#endif // _LOG4CXX_NET_DGRAM_SOCKET_APPENDER_H

Reply via email to