| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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. |
| */ |
| |
| #define __STDC_CONSTANT_MACROS |
| #include <log4cxx/net/socketappenderskeleton.h> |
| #include <log4cxx/helpers/loglog.h> |
| #include <log4cxx/helpers/optionconverter.h> |
| #include <log4cxx/helpers/stringhelper.h> |
| #include <log4cxx/spi/loggingevent.h> |
| #include <log4cxx/helpers/transcoder.h> |
| #include <log4cxx/helpers/bytearrayoutputstream.h> |
| #include <log4cxx/helpers/threadutility.h> |
| #include <log4cxx/private/appenderskeleton_priv.h> |
| #include <log4cxx/private/socketappenderskeleton_priv.h> |
| #include <functional> |
| #include <chrono> |
| |
| using namespace LOG4CXX_NS; |
| using namespace LOG4CXX_NS::helpers; |
| using namespace LOG4CXX_NS::net; |
| |
| #define _priv static_cast<SocketAppenderSkeletonPriv*>(m_priv.get()) |
| |
| SocketAppenderSkeleton::SocketAppenderSkeleton(int defaultPort, int reconnectionDelay) |
| : AppenderSkeleton(std::make_unique<SocketAppenderSkeletonPriv>(defaultPort, reconnectionDelay)) |
| { |
| } |
| |
| SocketAppenderSkeleton::SocketAppenderSkeleton(helpers::InetAddressPtr address, int port, int reconnectionDelay) |
| : AppenderSkeleton(std::make_unique<SocketAppenderSkeletonPriv>(address, port, reconnectionDelay)) |
| { |
| } |
| |
| SocketAppenderSkeleton::SocketAppenderSkeleton(const LogString& host, int port, int reconnectionDelay) |
| : AppenderSkeleton(std::make_unique<SocketAppenderSkeletonPriv>(host, port, reconnectionDelay)) |
| { |
| } |
| |
| SocketAppenderSkeleton::SocketAppenderSkeleton(std::unique_ptr<SocketAppenderSkeletonPriv> priv) |
| : AppenderSkeleton (std::move(priv)) |
| { |
| } |
| |
| SocketAppenderSkeleton::~SocketAppenderSkeleton() |
| { |
| finalize(); |
| } |
| |
| void SocketAppenderSkeleton::activateOptions(Pool& p) |
| { |
| AppenderSkeleton::activateOptions(p); |
| connect(p); |
| } |
| |
| void SocketAppenderSkeleton::close() |
| { |
| { |
| std::lock_guard<std::mutex> lock(_priv->interrupt_mutex); |
| |
| if (_priv->closed) |
| { |
| return; |
| } |
| |
| _priv->closed = true; |
| cleanUp(_priv->pool); |
| } |
| _priv->interrupt.notify_all(); |
| if ( _priv->thread.joinable() ) |
| { |
| _priv->thread.join(); |
| } |
| } |
| |
| void SocketAppenderSkeleton::connect(Pool& p) |
| { |
| if (_priv->address == 0) |
| { |
| LogLog::error(LogString(LOG4CXX_STR("No remote host is set for Appender named \"")) + |
| _priv->name + LOG4CXX_STR("\".")); |
| } |
| else |
| { |
| cleanUp(p); |
| |
| try |
| { |
| LogString msg(LOG4CXX_STR("Connecting to [") |
| + _priv->address->toString() + LOG4CXX_STR(":")); |
| StringHelper::toString(_priv->port, p, msg); |
| msg += LOG4CXX_STR("]."); |
| LogLog::debug(msg); |
| SocketPtr socket = Socket::create(_priv->address, _priv->port); |
| setSocket(socket, p); |
| } |
| catch (SocketException& e) |
| { |
| LogString msg = LOG4CXX_STR("Could not connect to [") |
| + _priv->address->toString() + LOG4CXX_STR(":"); |
| StringHelper::toString(_priv->port, p, msg); |
| msg += LOG4CXX_STR("]."); |
| |
| fireConnector(); // fire the connector thread |
| LogLog::error(msg, e); |
| } |
| } |
| } |
| |
| void SocketAppenderSkeleton::setOption(const LogString& option, const LogString& value) |
| { |
| if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("REMOTEHOST"), LOG4CXX_STR("remotehost"))) |
| { |
| setRemoteHost(value); |
| } |
| else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("PORT"), LOG4CXX_STR("port"))) |
| { |
| setPort(OptionConverter::toInt(value, getDefaultPort())); |
| } |
| else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("LOCATIONINFO"), LOG4CXX_STR("locationinfo"))) |
| { |
| setLocationInfo(OptionConverter::toBoolean(value, false)); |
| } |
| else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("RECONNECTIONDELAY"), LOG4CXX_STR("reconnectiondelay"))) |
| { |
| setReconnectionDelay(OptionConverter::toInt(value, getDefaultDelay())); |
| } |
| else |
| { |
| AppenderSkeleton::setOption(option, value); |
| } |
| } |
| |
| void SocketAppenderSkeleton::fireConnector() |
| { |
| std::lock_guard<std::recursive_mutex> lock(_priv->mutex); |
| |
| if ( !_priv->thread.joinable() ) |
| { |
| LogLog::debug(LOG4CXX_STR("Connector thread not alive: starting monitor.")); |
| |
| _priv->thread = ThreadUtility::instance()->createThread( LOG4CXX_STR("SocketAppend"), &SocketAppenderSkeleton::monitor, this ); |
| } |
| } |
| |
| void SocketAppenderSkeleton::monitor() |
| { |
| Pool p; |
| SocketPtr socket; |
| |
| while (!is_closed()) |
| { |
| try |
| { |
| LogString msg(LOG4CXX_STR("Attempting connection to [") |
| + _priv->address->toString() + LOG4CXX_STR(":")); |
| StringHelper::toString(_priv->port, p, msg); |
| msg += LOG4CXX_STR("]."); |
| LogLog::debug(msg); |
| socket = Socket::create(_priv->address, _priv->port); |
| setSocket(socket, p); |
| LogLog::debug(LOG4CXX_STR("Connection established. Exiting connector thread.")); |
| return; |
| } |
| catch (ConnectException& e) |
| { |
| LogLog::error(LOG4CXX_STR("Remote host ") |
| + _priv->address->toString() |
| + LOG4CXX_STR(" refused connection."), e); |
| } |
| catch (IOException& e) |
| { |
| LogString msg(LOG4CXX_STR("Could not connect to [") |
| + _priv->address->toString() + LOG4CXX_STR(":")); |
| StringHelper::toString(_priv->port, p, msg); |
| msg += LOG4CXX_STR("]."); |
| LogLog::error(msg, e); |
| } |
| |
| if (_priv->reconnectionDelay > 0) |
| { |
| LogString msg(LOG4CXX_STR("Waiting ")); |
| StringHelper::toString(_priv->reconnectionDelay, p, msg); |
| msg += LOG4CXX_STR(" ms before retrying [") |
| + _priv->address->toString() + LOG4CXX_STR(":"); |
| StringHelper::toString(_priv->port, p, msg); |
| msg += LOG4CXX_STR("]."); |
| LogLog::debug(msg); |
| |
| std::unique_lock<std::mutex> lock( _priv->interrupt_mutex ); |
| if (_priv->interrupt.wait_for( lock, std::chrono::milliseconds( _priv->reconnectionDelay ), |
| std::bind(&SocketAppenderSkeleton::is_closed, this) )) |
| break; |
| } |
| } |
| } |
| |
| bool SocketAppenderSkeleton::is_closed() |
| { |
| return _priv->closed; |
| } |
| |
| void SocketAppenderSkeleton::setRemoteHost(const LogString& host) |
| { |
| _priv->address = helpers::InetAddress::getByName(host); |
| _priv->remoteHost.assign(host); |
| } |
| |
| const LogString& SocketAppenderSkeleton::getRemoteHost() const |
| { |
| return _priv->remoteHost; |
| } |
| |
| void SocketAppenderSkeleton::setPort(int port1) |
| { |
| _priv->port = port1; |
| } |
| |
| int SocketAppenderSkeleton::getPort() const |
| { |
| return _priv->port; |
| } |
| |
| void SocketAppenderSkeleton::setLocationInfo(bool locationInfo1) |
| { |
| _priv->locationInfo = locationInfo1; |
| } |
| |
| bool SocketAppenderSkeleton::getLocationInfo() const |
| { |
| return _priv->locationInfo; |
| } |
| |
| void SocketAppenderSkeleton::setReconnectionDelay(int reconnectionDelay1) |
| { |
| _priv->reconnectionDelay = reconnectionDelay1; |
| } |
| |
| int SocketAppenderSkeleton::getReconnectionDelay() const |
| { |
| return _priv->reconnectionDelay; |
| } |