| /* |
| * 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. |
| */ |
| #if defined(_MSC_VER) |
| #pragma warning ( disable: 4231 4251 4275 4786 ) |
| #endif |
| |
| #include <log4cxx/net/sockethubappender.h> |
| |
| #include <log4cxx/helpers/loglog.h> |
| #include <log4cxx/helpers/optionconverter.h> |
| #include <log4cxx/helpers/stringhelper.h> |
| #include <log4cxx/helpers/serversocket.h> |
| #include <log4cxx/spi/loggingevent.h> |
| #include <log4cxx/helpers/synchronized.h> |
| #include <apr_atomic.h> |
| #include <apr_thread_proc.h> |
| #include <log4cxx/helpers/objectoutputstream.h> |
| #include <log4cxx/helpers/socketoutputstream.h> |
| #include <log4cxx/helpers/exception.h> |
| |
| using namespace log4cxx; |
| using namespace log4cxx::helpers; |
| using namespace log4cxx::net; |
| using namespace log4cxx::spi; |
| |
| #if APR_HAS_THREADS |
| |
| IMPLEMENT_LOG4CXX_OBJECT(SocketHubAppender) |
| |
| int SocketHubAppender::DEFAULT_PORT = 4560; |
| |
| SocketHubAppender::~SocketHubAppender() |
| { |
| finalize(); |
| } |
| |
| SocketHubAppender::SocketHubAppender() |
| : port(DEFAULT_PORT), streams(), locationInfo(false), thread() |
| { |
| } |
| |
| SocketHubAppender::SocketHubAppender(int port1) |
| : port(port1), streams(), locationInfo(false), thread() |
| { |
| startServer(); |
| } |
| |
| void SocketHubAppender::activateOptions(Pool& /* p */ ) |
| { |
| startServer(); |
| } |
| |
| void SocketHubAppender::setOption(const LogString& option, |
| const LogString& value) |
| { |
| if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("PORT"), LOG4CXX_STR("port"))) |
| { |
| setPort(OptionConverter::toInt(value, DEFAULT_PORT)); |
| } |
| else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("LOCATIONINFO"), LOG4CXX_STR("locationinfo"))) |
| { |
| setLocationInfo(OptionConverter::toBoolean(value, true)); |
| } |
| else |
| { |
| AppenderSkeleton::setOption(option, value); |
| } |
| } |
| |
| |
| void SocketHubAppender::close() |
| { |
| { |
| LOCK_W sync(mutex); |
| |
| if (closed) |
| { |
| return; |
| } |
| |
| closed = true; |
| } |
| |
| LogLog::debug(LOG4CXX_STR("closing SocketHubAppender ") + getName()); |
| // |
| // wait until the server thread completes |
| // |
| thread.join(); |
| |
| LOCK_W sync(mutex); |
| // close all of the connections |
| LogLog::debug(LOG4CXX_STR("closing client connections")); |
| |
| for (std::vector<helpers::ObjectOutputStreamPtr>::iterator iter = streams.begin(); |
| iter != streams.end(); |
| iter++) |
| { |
| if ( (*iter) != NULL) |
| { |
| try |
| { |
| (*iter)->close(pool); |
| } |
| catch (SocketException& e) |
| { |
| LogLog::error(LOG4CXX_STR("could not close socket: "), e); |
| } |
| } |
| } |
| |
| streams.erase(streams.begin(), streams.end()); |
| |
| |
| LogLog::debug(LOG4CXX_STR("SocketHubAppender ") |
| + getName() + LOG4CXX_STR(" closed")); |
| } |
| |
| void SocketHubAppender::append(const spi::LoggingEventPtr& event, Pool& p) |
| { |
| |
| // if no open connections, exit now |
| if (streams.empty()) |
| { |
| return; |
| } |
| |
| LogString ndcVal; |
| event->getNDC(ndcVal); |
| event->getThreadName(); |
| // Get a copy of this thread's MDC. |
| event->getMDCCopy(); |
| |
| |
| // loop through the current set of open connections, appending the event to each |
| std::vector<ObjectOutputStreamPtr>::iterator it = streams.begin(); |
| std::vector<ObjectOutputStreamPtr>::iterator itEnd = streams.end(); |
| |
| while (it != itEnd) |
| { |
| // list size changed unexpectedly? Just exit the append. |
| if (*it == 0) |
| { |
| break; |
| } |
| |
| try |
| { |
| event->write(**it, p); |
| (*it)->flush(p); |
| it++; |
| } |
| catch (std::exception& e) |
| { |
| // there was an io exception so just drop the connection |
| it = streams.erase(it); |
| itEnd = streams.end(); |
| LogLog::debug(LOG4CXX_STR("dropped connection"), e); |
| } |
| } |
| } |
| |
| void SocketHubAppender::startServer() |
| { |
| thread.run(monitor, this); |
| } |
| |
| void* APR_THREAD_FUNC SocketHubAppender::monitor(apr_thread_t* /* thread */, void* data) |
| { |
| SocketHubAppender* pThis = (SocketHubAppender*) data; |
| |
| ServerSocket* serverSocket = 0; |
| |
| try |
| { |
| serverSocket = new ServerSocket(pThis->port); |
| serverSocket->setSoTimeout(1000); |
| } |
| catch (SocketException& e) |
| { |
| LogLog::error(LOG4CXX_STR("exception setting timeout, shutting down server socket."), e); |
| delete serverSocket; |
| return NULL; |
| } |
| |
| bool stopRunning = pThis->closed; |
| |
| while (!stopRunning) |
| { |
| SocketPtr socket; |
| |
| try |
| { |
| socket = serverSocket->accept(); |
| } |
| catch (InterruptedIOException&) |
| { |
| // timeout occurred, so just loop |
| } |
| catch (SocketException& e) |
| { |
| LogLog::error(LOG4CXX_STR("exception accepting socket, shutting down server socket."), e); |
| stopRunning = true; |
| } |
| catch (IOException& e) |
| { |
| LogLog::error(LOG4CXX_STR("exception accepting socket."), e); |
| } |
| |
| // if there was a socket accepted |
| if (socket != 0) |
| { |
| try |
| { |
| InetAddressPtr remoteAddress = socket->getInetAddress(); |
| LogLog::debug(LOG4CXX_STR("accepting connection from ") |
| + remoteAddress->getHostName() |
| + LOG4CXX_STR(" (") |
| + remoteAddress->getHostAddress() |
| + LOG4CXX_STR(")")); |
| |
| // add it to the oosList. |
| LOCK_W sync(pThis->mutex); |
| OutputStreamPtr os(new SocketOutputStream(socket)); |
| Pool p; |
| ObjectOutputStreamPtr oos(new ObjectOutputStream(os, p)); |
| pThis->streams.push_back(oos); |
| } |
| catch (IOException& e) |
| { |
| LogLog::error(LOG4CXX_STR("exception creating output stream on socket."), e); |
| } |
| } |
| |
| stopRunning = (stopRunning || pThis->closed); |
| } |
| |
| delete serverSocket; |
| return NULL; |
| } |
| |
| #endif |