| /* |
| * 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. |
| */ |
| |
| #include "../appenderskeletontestcase.h" |
| #include <log4cxx/patternlayout.h> |
| #include <log4cxx/basicconfigurator.h> |
| #include <log4cxx/net/xmlsocketappender.h> |
| #include <log4cxx/helpers/serversocket.h> |
| #include <log4cxx/helpers/loglog.h> |
| #include <log4cxx/helpers/stringhelper.h> |
| #include <log4cxx/helpers/transcoder.h> |
| #include <log4cxx/private/aprsocket.h> |
| #include <apr_network_io.h> |
| |
| namespace LOG4CXX_NS { namespace net { |
| using SocketAppender = XMLSocketAppender; |
| } } |
| |
| using namespace LOG4CXX_NS; |
| |
| /** |
| Unit tests of log4cxx::SocketAppender |
| */ |
| class SocketAppenderTestCase : public AppenderSkeletonTestCase |
| { |
| LOGUNIT_TEST_SUITE(SocketAppenderTestCase); |
| // |
| // tests inherited from AppenderSkeletonTestCase |
| // |
| LOGUNIT_TEST(testDefaultThreshold); |
| LOGUNIT_TEST(testSetOptionThreshold); |
| LOGUNIT_TEST(testRetryConnect); |
| |
| LOGUNIT_TEST_SUITE_END(); |
| |
| #ifdef _DEBUG |
| struct Fixture |
| { |
| Fixture() { |
| helpers::LogLog::setInternalDebugging(true); |
| } |
| } suiteFixture; |
| #endif |
| |
| |
| public: |
| |
| AppenderSkeleton* createAppenderSkeleton() const |
| { |
| return new log4cxx::net::SocketAppender(); |
| } |
| |
| void testRetryConnect() |
| { |
| int tcpPort = 44445; |
| auto appender = std::make_shared<net::SocketAppender>(); |
| appender->setLayout(std::make_shared<log4cxx::PatternLayout>(LOG4CXX_STR("%d [%T] %m%n"))); |
| appender->setRemoteHost(LOG4CXX_STR("localhost")); |
| appender->setReconnectionDelay(50); // milliseconds |
| appender->setPort(tcpPort); |
| helpers::Pool pool; |
| appender->activateOptions(pool); |
| |
| BasicConfigurator::configure(appender); |
| |
| helpers::ServerSocketUniquePtr serverSocket; |
| try |
| { |
| serverSocket = helpers::ServerSocket::create(tcpPort, true, {}); |
| } |
| catch (std::exception& ex) |
| { |
| helpers::LogLog::error(LOG4CXX_STR("ServerSocket::create failed"), ex); |
| LOGUNIT_FAIL("ServerSocket::create"); |
| } |
| serverSocket->setSoTimeout(1000); // milliseconds |
| |
| auto logger = Logger::getLogger("test"); |
| int logEventCount = 3000; |
| auto doLogging = [logger, logEventCount]() |
| { |
| for( int x = 0; x < logEventCount; x++ ){ |
| LOG4CXX_INFO(logger, "Message " << x); |
| if (0 == x % 1000) |
| apr_sleep(50000); // 50 millisecond |
| } |
| }; |
| std::vector<std::thread> loggingThread; |
| for (auto i : {0, 1}) |
| loggingThread.emplace_back(doLogging); |
| |
| helpers::SocketPtr incomingSocket; |
| try |
| { |
| incomingSocket = serverSocket->accept(); |
| } |
| catch (std::exception& ex) |
| { |
| helpers::LogLog::error(LOG4CXX_STR("ServerSocket::accept failed"), ex); |
| for (auto& t : loggingThread) |
| t.join(); |
| serverSocket->close(); |
| LOGUNIT_FAIL("accept failed"); |
| } |
| auto aprSocket = std::dynamic_pointer_cast<helpers::APRSocket>(incomingSocket); |
| LOGUNIT_ASSERT(aprSocket); |
| auto pSocket = aprSocket->getSocketPtr(); |
| LOGUNIT_ASSERT(pSocket); |
| apr_socket_timeout_set(pSocket, 400000); // 400 millisecond |
| std::vector<int> messageCount; |
| char buffer[8*1024]; |
| apr_size_t len = sizeof(buffer); |
| apr_status_t status; |
| while (APR_SUCCESS == (status = apr_socket_recv(pSocket, buffer, &len))) |
| { |
| auto pStart = &buffer[0]; |
| auto pEnd = pStart + len; |
| for (auto pChar = pStart; pChar < pEnd; ++pChar) |
| { |
| if ('\n' == *pChar) |
| { |
| std::string line(pStart, pChar); |
| auto pos = line.rfind(' '); |
| if (line.npos != pos && pos + 1 < line.size()) |
| { |
| try |
| { |
| auto msgNumber = std::stoi(line.substr(pos)); |
| if (messageCount.size() <= msgNumber) |
| messageCount.resize(msgNumber + 1); |
| ++messageCount[msgNumber]; |
| } |
| catch (std::exception const& ex) |
| { |
| LogString msg; |
| helpers::Transcoder::decode(ex.what(), msg); |
| msg += LOG4CXX_STR(" processing\n"); |
| helpers::Transcoder::decode(line, msg); |
| helpers::LogLog::warn(msg); |
| } |
| } |
| pStart = pChar + 1; |
| } |
| } |
| len = sizeof(buffer); |
| } |
| if (helpers::LogLog::isDebugEnabled()) |
| { |
| helpers::LogLog::debug(helpers::Exception::makeMessage(LOG4CXX_STR("apr_socket_recv terminated"), status)); |
| } |
| incomingSocket->close(); |
| serverSocket->close(); |
| for (auto& t : loggingThread) |
| t.join(); |
| |
| if (helpers::LogLog::isDebugEnabled()) |
| { |
| helpers::Pool p; |
| LogString msg(LOG4CXX_STR("messageCount ")); |
| for (auto item : messageCount) |
| { |
| msg += logchar(' '); |
| helpers::StringHelper::toString(item, p, msg); |
| } |
| helpers::LogLog::debug(msg); |
| } |
| LOGUNIT_ASSERT_EQUAL(logEventCount, (int)messageCount.size()); |
| } |
| }; |
| |
| LOGUNIT_TEST_SUITE_REGISTRATION(SocketAppenderTestCase); |