| /* | |
| * 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/logmanager.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> | |
| #include <thread> | |
| 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(testRetryConnectDefault); | |
| LOGUNIT_TEST(testRetryConnectBSD); | |
| LOGUNIT_TEST_SUITE_END(); | |
| #ifdef _DEBUG | |
| struct Fixture | |
| { | |
| Fixture() { | |
| helpers::LogLog::setInternalDebugging(true); | |
| } | |
| } suiteFixture; | |
| #endif | |
| public: | |
| void tearDown() override | |
| { | |
| LogManager::shutdown(); | |
| } | |
| AppenderSkeleton* createAppenderSkeleton() const override | |
| { | |
| return new log4cxx::net::SocketAppender(); | |
| } | |
| void testRetryConnect(const LogString& socketImpl = {}) | |
| { | |
| int tcpPort = 44445; | |
| int millisecondDelay = 50; | |
| 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(millisecondDelay); | |
| appender->setPort(tcpPort); | |
| if (!socketImpl.empty()) | |
| appender->setSocketSubclass(socketImpl); | |
| appender->activateOptions(); | |
| 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()) | |
| { | |
| LogString msg(LOG4CXX_STR("messageCount ")); | |
| for (auto item : messageCount) | |
| { | |
| msg += logchar(' '); | |
| helpers::StringHelper::toString(item, msg); | |
| } | |
| helpers::LogLog::debug(msg); | |
| } | |
| LOGUNIT_ASSERT_EQUAL(logEventCount, (int)messageCount.size()); | |
| } | |
| void testRetryConnectDefault() | |
| { | |
| testRetryConnect(); | |
| } | |
| void testRetryConnectBSD() | |
| { | |
| testRetryConnect(LOG4CXX_STR("BSDSocket")); | |
| } | |
| }; | |
| LOGUNIT_TEST_SUITE_REGISTRATION(SocketAppenderTestCase); |