| /* |
| * 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 "logunit.h" |
| |
| #include <log4cxx/logger.h> |
| #include <log4cxx/logmanager.h> |
| #include <log4cxx/simplelayout.h> |
| #include "vectorappender.h" |
| #include <log4cxx/asyncappender.h> |
| #include "appenderskeletontestcase.h" |
| #include <log4cxx/helpers/pool.h> |
| #include <apr_strings.h> |
| #include "testchar.h" |
| #include <log4cxx/helpers/stringhelper.h> |
| #include <log4cxx/helpers/synchronized.h> |
| #include <log4cxx/spi/location/locationinfo.h> |
| #include <log4cxx/xml/domconfigurator.h> |
| #include <log4cxx/file.h> |
| |
| using namespace log4cxx; |
| using namespace log4cxx::helpers; |
| using namespace log4cxx::spi; |
| |
| class NullPointerAppender : public AppenderSkeleton |
| { |
| public: |
| NullPointerAppender() |
| { |
| } |
| |
| |
| /** |
| * @{inheritDoc} |
| */ |
| void append(const spi::LoggingEventPtr&, log4cxx::helpers::Pool&) |
| { |
| throw NullPointerException(LOG4CXX_STR("Intentional NullPointerException")); |
| } |
| |
| void close() |
| { |
| } |
| |
| bool requiresLayout() const |
| { |
| return false; |
| } |
| }; |
| |
| /** |
| * Vector appender that can be explicitly blocked. |
| */ |
| class BlockableVectorAppender : public VectorAppender |
| { |
| private: |
| Mutex blocker; |
| public: |
| /** |
| * Create new instance. |
| */ |
| BlockableVectorAppender() : blocker(pool) |
| { |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| void append(const spi::LoggingEventPtr& event, log4cxx::helpers::Pool& p) |
| { |
| synchronized sync(blocker); |
| VectorAppender::append(event, p); |
| |
| // |
| // if fatal, echo messages for testLoggingInDispatcher |
| // |
| if (event->getLevel() == Level::getInfo()) |
| { |
| LoggerPtr logger = Logger::getLoggerLS(event->getLoggerName()); |
| LOG4CXX_LOGLS(logger, Level::getError(), event->getMessage()); |
| LOG4CXX_LOGLS(logger, Level::getWarn(), event->getMessage()); |
| LOG4CXX_LOGLS(logger, Level::getInfo(), event->getMessage()); |
| LOG4CXX_LOGLS(logger, Level::getDebug(), event->getMessage()); |
| } |
| } |
| |
| Mutex& getBlocker() |
| { |
| return blocker; |
| } |
| |
| }; |
| |
| typedef helpers::ObjectPtrT<BlockableVectorAppender> BlockableVectorAppenderPtr; |
| |
| #if APR_HAS_THREADS |
| /** |
| * Tests of AsyncAppender. |
| */ |
| class AsyncAppenderTestCase : public AppenderSkeletonTestCase |
| { |
| LOGUNIT_TEST_SUITE(AsyncAppenderTestCase); |
| // |
| // tests inherited from AppenderSkeletonTestCase |
| // |
| LOGUNIT_TEST(testDefaultThreshold); |
| LOGUNIT_TEST(testSetOptionThreshold); |
| |
| LOGUNIT_TEST(closeTest); |
| LOGUNIT_TEST(test2); |
| LOGUNIT_TEST(test3); |
| // |
| // TODO: test fails on Linux. |
| //LOGUNIT_TEST(testBadAppender); |
| LOGUNIT_TEST(testLocationInfoTrue); |
| LOGUNIT_TEST(testConfiguration); |
| LOGUNIT_TEST_SUITE_END(); |
| |
| |
| public: |
| void setUp() |
| { |
| AppenderSkeletonTestCase::setUp(); |
| } |
| |
| void tearDown() |
| { |
| LogManager::shutdown(); |
| AppenderSkeletonTestCase::tearDown(); |
| } |
| |
| AppenderSkeleton* createAppenderSkeleton() const |
| { |
| return new AsyncAppender(); |
| } |
| |
| // this test checks whether it is possible to write to a closed AsyncAppender |
| void closeTest() |
| { |
| LoggerPtr root = Logger::getRootLogger(); |
| LayoutPtr layout = new SimpleLayout(); |
| VectorAppenderPtr vectorAppender = new VectorAppender(); |
| AsyncAppenderPtr asyncAppender = new AsyncAppender(); |
| asyncAppender->setName(LOG4CXX_STR("async-CloseTest")); |
| asyncAppender->addAppender(vectorAppender); |
| root->addAppender(asyncAppender); |
| |
| root->debug(LOG4CXX_TEST_STR("m1")); |
| asyncAppender->close(); |
| root->debug(LOG4CXX_TEST_STR("m2")); |
| |
| const std::vector<spi::LoggingEventPtr>& v = vectorAppender->getVector(); |
| LOGUNIT_ASSERT_EQUAL((size_t) 1, v.size()); |
| } |
| |
| // this test checks whether appenders embedded within an AsyncAppender are also |
| // closed |
| void test2() |
| { |
| LoggerPtr root = Logger::getRootLogger(); |
| LayoutPtr layout = new SimpleLayout(); |
| VectorAppenderPtr vectorAppender = new VectorAppender(); |
| AsyncAppenderPtr asyncAppender = new AsyncAppender(); |
| asyncAppender->setName(LOG4CXX_STR("async-test2")); |
| asyncAppender->addAppender(vectorAppender); |
| root->addAppender(asyncAppender); |
| |
| root->debug(LOG4CXX_TEST_STR("m1")); |
| asyncAppender->close(); |
| root->debug(LOG4CXX_TEST_STR("m2")); |
| |
| const std::vector<spi::LoggingEventPtr>& v = vectorAppender->getVector(); |
| LOGUNIT_ASSERT_EQUAL((size_t) 1, v.size()); |
| LOGUNIT_ASSERT(vectorAppender->isClosed()); |
| } |
| |
| // this test checks whether appenders embedded within an AsyncAppender are also |
| // closed |
| void test3() |
| { |
| size_t LEN = 200; |
| LoggerPtr root = Logger::getRootLogger(); |
| VectorAppenderPtr vectorAppender = new VectorAppender(); |
| AsyncAppenderPtr asyncAppender = new AsyncAppender(); |
| asyncAppender->setName(LOG4CXX_STR("async-test3")); |
| asyncAppender->addAppender(vectorAppender); |
| root->addAppender(asyncAppender); |
| |
| for (size_t i = 0; i < LEN; i++) |
| { |
| LOG4CXX_DEBUG(root, "message" << i); |
| } |
| |
| asyncAppender->close(); |
| root->debug(LOG4CXX_TEST_STR("m2")); |
| |
| const std::vector<spi::LoggingEventPtr>& v = vectorAppender->getVector(); |
| LOGUNIT_ASSERT_EQUAL(LEN, v.size()); |
| LOGUNIT_ASSERT_EQUAL(true, vectorAppender->isClosed()); |
| } |
| |
| /** |
| * Tests that a bad appender will switch async back to sync. |
| */ |
| void testBadAppender() |
| { |
| AppenderPtr nullPointerAppender = new NullPointerAppender(); |
| AsyncAppenderPtr asyncAppender = new AsyncAppender(); |
| asyncAppender->addAppender(nullPointerAppender); |
| asyncAppender->setBufferSize(5); |
| Pool p; |
| asyncAppender->activateOptions(p); |
| LoggerPtr root = Logger::getRootLogger(); |
| root->addAppender(asyncAppender); |
| LOG4CXX_INFO(root, "Message"); |
| Thread::sleep(10); |
| |
| try |
| { |
| LOG4CXX_INFO(root, "Message"); |
| LOGUNIT_FAIL("Should have thrown exception"); |
| } |
| catch (NullPointerException&) |
| { |
| } |
| } |
| |
| /** |
| * Tests non-blocking behavior. |
| */ |
| void testLocationInfoTrue() |
| { |
| BlockableVectorAppenderPtr blockableAppender = new BlockableVectorAppender(); |
| AsyncAppenderPtr async = new AsyncAppender(); |
| async->addAppender(blockableAppender); |
| async->setBufferSize(5); |
| async->setLocationInfo(true); |
| async->setBlocking(false); |
| Pool p; |
| async->activateOptions(p); |
| LoggerPtr rootLogger = Logger::getRootLogger(); |
| rootLogger->addAppender(async); |
| { |
| synchronized sync(blockableAppender->getBlocker()); |
| |
| for (int i = 0; i < 140; i++) |
| { |
| LOG4CXX_INFO(rootLogger, "Hello, World"); |
| Thread::sleep(1); |
| } |
| |
| LOG4CXX_ERROR(rootLogger, "That's all folks."); |
| } |
| async->close(); |
| const std::vector<spi::LoggingEventPtr>& events = blockableAppender->getVector(); |
| LOGUNIT_ASSERT(events.size() > 0); |
| LoggingEventPtr initialEvent = events[0]; |
| LoggingEventPtr discardEvent = events[events.size() - 1]; |
| LOGUNIT_ASSERT(initialEvent->getMessage() == LOG4CXX_STR("Hello, World")); |
| LOGUNIT_ASSERT(discardEvent->getMessage().substr(0, 10) == LOG4CXX_STR("Discarded ")); |
| LOGUNIT_ASSERT_EQUAL(log4cxx::spi::LocationInfo::getLocationUnavailable().getClassName(), |
| discardEvent->getLocationInformation().getClassName()); |
| } |
| |
| void testConfiguration() |
| { |
| log4cxx::xml::DOMConfigurator::configure("input/xml/asyncAppender1.xml"); |
| AsyncAppenderPtr asyncAppender(Logger::getRootLogger()->getAppender(LOG4CXX_STR("ASYNC"))); |
| LOGUNIT_ASSERT(!(asyncAppender == 0)); |
| LOGUNIT_ASSERT_EQUAL(100, asyncAppender->getBufferSize()); |
| LOGUNIT_ASSERT_EQUAL(false, asyncAppender->getBlocking()); |
| LOGUNIT_ASSERT_EQUAL(true, asyncAppender->getLocationInfo()); |
| AppenderList nestedAppenders(asyncAppender->getAllAppenders()); |
| // TODO: |
| // test seems to work okay, but have not found a working way to |
| // get a reference to the nested vector appender |
| // |
| // LOGUNIT_ASSERT_EQUAL((size_t) 1, nestedAppenders.size()); |
| // VectorAppenderPtr vectorAppender(nestedAppenders[0]); |
| // LOGUNIT_ASSERT(0 != vectorAppender); |
| LoggerPtr root(Logger::getRootLogger()); |
| |
| size_t LEN = 20; |
| |
| for (size_t i = 0; i < LEN; i++) |
| { |
| LOG4CXX_DEBUG(root, "message" << i); |
| } |
| |
| asyncAppender->close(); |
| // const std::vector<spi::LoggingEventPtr>& v = vectorAppender->getVector(); |
| // LOGUNIT_ASSERT_EQUAL(LEN, v.size()); |
| // LOGUNIT_ASSERT_EQUAL(true, vectorAppender->isClosed()); |
| } |
| |
| |
| }; |
| |
| LOGUNIT_TEST_SUITE_REGISTRATION(AsyncAppenderTestCase); |
| #endif |