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
