This is an automated email from the ASF dual-hosted git repository.

swebb2066 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git


The following commit(s) were added to refs/heads/master by this push:
     new b3238278 Provide temporary logging level change support using RAII 
(#301)
b3238278 is described below

commit b323827889181d77df0f1dd43121b9346b7c76dc
Author: Stephen Webb <[email protected]>
AuthorDate: Thu Nov 30 11:58:47 2023 +1100

    Provide temporary logging level change support using RAII (#301)
    
    .
---
 src/main/include/log4cxx/levelchange.h |  84 ++++++++++++++++++++
 src/test/cpp/CMakeLists.txt            |   1 +
 src/test/cpp/levelchangetestcase.cpp   | 140 +++++++++++++++++++++++++++++++++
 3 files changed, 225 insertions(+)

diff --git a/src/main/include/log4cxx/levelchange.h 
b/src/main/include/log4cxx/levelchange.h
new file mode 100644
index 00000000..df2f6f96
--- /dev/null
+++ b/src/main/include/log4cxx/levelchange.h
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#ifndef LOG4CXX_LEVEL_CHANGE_HDR_
+#define LOG4CXX_LEVEL_CHANGE_HDR_
+
+#include <log4cxx/logmanager.h>
+#include <log4cxx/logger.h>
+
+namespace LOG4CXX_NS
+{
+
+/**
+ * Changes a verbosity level for the instance variable's lifetime.
+
+ * Create a LevelChange variable on the stack
+ * to temporarily (e.g. for a single method)
+ * increase the quantity of information logged.
+
+ * Typically used to propagate the locally used logger's level (e.g. DEBUG or 
TRACE)
+ * to another named (e.g. the name of the class of the method invoked next) 
logger.
+
+ * The LevelChange variable does not need to be removed from the code (e.g. 
for a release build)
+ * as it has no impact when the local and other logger point to the same level
+ * (e.g. null_ptr, implying their level is inherited).
+ */
+ class LevelChange
+{
+       LoggerPtr m_otherCategory;
+       LevelPtr m_savedLevel;
+public: // ...structors
+       /// Set \c otherCategory to \c level
+       LevelChange(const LoggerPtr& otherCategory, const LevelPtr& level)
+               : m_otherCategory(otherCategory)
+               , m_savedLevel(otherCategory->getLevel())
+       {
+               m_otherCategory->setLevel(level);
+       }
+       /// Set \c otherCategory to the level of \c thisCategory
+       LevelChange(const LoggerPtr& otherCategory, const LoggerPtr& 
thisCategory)
+               : LevelChange(otherCategory, m_otherCategory->getLevel())
+       {
+       }
+       /// Set the logger named \c otherCategory to \c level
+       template <class StringType>
+       LevelChange(const StringType& otherCategory, const LevelPtr& level)
+               : LevelChange(LogManager::getLogger(otherCategory), level)
+       {
+       }
+       /// Set the logger named \c otherCategory to the level of \c 
thisCategory
+       template <class StringType>
+       LevelChange(const StringType& otherCategory, const LoggerPtr& 
thisCategory)
+               : LevelChange(LogManager::getLogger(otherCategory), 
thisCategory->getLevel())
+       {
+       }
+       /// Restore the verbosity level of the other logger
+       ~LevelChange()
+       {
+               m_otherCategory->setLevel(m_savedLevel);
+       }
+private: // Prevent copies and assignment 
+       LevelChange(const LevelChange&) = delete;
+       LevelChange(LevelChange&&) = delete;
+       LevelChange& operator=(const LevelChange&) = delete;
+       LevelChange& operator=(LevelChange&&) = delete;
+};
+
+} // namespace LOG4CXX_NS
+
+#endif // LOG4CXX_LEVEL_CHANGE_HDR_
diff --git a/src/test/cpp/CMakeLists.txt b/src/test/cpp/CMakeLists.txt
index 049aad7e..f015e416 100644
--- a/src/test/cpp/CMakeLists.txt
+++ b/src/test/cpp/CMakeLists.txt
@@ -50,6 +50,7 @@ set(ALL_LOG4CXX_TESTS
     jsonlayouttest
     l7dtestcase
     leveltestcase
+    levelchangetestcase
     loggertestcase
     mdctestcase
     minimumtestcase
diff --git a/src/test/cpp/levelchangetestcase.cpp 
b/src/test/cpp/levelchangetestcase.cpp
new file mode 100644
index 00000000..85ea1eb2
--- /dev/null
+++ b/src/test/cpp/levelchangetestcase.cpp
@@ -0,0 +1,140 @@
+
+/*
+ * 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 <log4cxx/levelchange.h>
+#include <log4cxx/appenderskeleton.h>
+#include <log4cxx/helpers/loglog.h>
+#include "logunit.h"
+
+using namespace log4cxx;
+
+namespace
+{
+
+class CountingAppender : public AppenderSkeleton
+{
+       public:
+               int count;
+
+               CountingAppender() : count(0)
+               {}
+
+               void close() override
+               {}
+
+               void append(const spi::LoggingEventPtr& /*event*/, 
helpers::Pool& /*p*/) override
+               {
+                       count++;
+               }
+
+               bool requiresLayout() const override
+               {
+                       return true;
+               }
+
+               LogString getName() const override
+               {
+                       return LOG4CXX_STR("counter");
+               }
+};
+
+LoggerPtr getLogger(const LogString& name = LogString())
+{
+       auto r = LogManager::getLoggerRepository();
+       r->ensureIsConfigured([r]()
+               {
+                       
r->getRootLogger()->addAppender(std::make_shared<CountingAppender>());
+               });
+       return name.empty() ? r->getRootLogger() : r->getLogger(name);
+}
+
+} // anonymous namespace
+
+// A mocked worker
+class ComplexProcessing
+{
+public:
+       LoggerPtr logger = getLogger(LOG4CXX_STR("ComplexProcessing"));
+       void DoStep1()
+       {
+               LOG4CXX_DEBUG(logger, "Step 1 message");
+       }
+       void DoStep2()
+       {
+               LOG4CXX_DEBUG(logger, "Step 2 message");
+       }
+       void DoStep3()
+       {
+               LOG4CXX_DEBUG(logger, "Step 3 message");
+       }
+};
+static ComplexProcessing processor;
+
+LOGUNIT_CLASS(LevelChangeTestCase)
+{
+       LOGUNIT_TEST_SUITE(LevelChangeTestCase);
+       LOGUNIT_TEST(testLevelChange);
+       LOGUNIT_TEST_SUITE_END();
+
+#ifdef _DEBUG
+       struct Fixture
+       {
+               Fixture() {
+                       helpers::LogLog::setInternalDebugging(true);
+               }
+       } suiteFixture;
+#endif
+
+public:
+       void setUp()
+       {
+               // Disable DEBUG output from ComplexProcessing
+               processor.logger->setLevel(Level::getInfo());
+       }
+
+       void testLevelChange()
+       {
+               auto appender = 
dynamic_cast<CountingAppender*>(getLogger()->getAppender(LOG4CXX_STR("counter")).get());
+               LOGUNIT_ASSERT(appender);
+
+               auto myLogger = getLogger(LOG4CXX_STR("Controller"));
+               myLogger->setLevel(Level::getDebug());
+
+               // Check this debug request is sent to the appender
+               LOG4CXX_DEBUG(myLogger, "Start test");
+               auto initialCount = appender->count;
+               LOGUNIT_ASSERT_EQUAL(initialCount, 1);
+
+               // Check the ComplexProcessing debug request is not sent to the 
appender
+               processor.DoStep1();
+               LOGUNIT_ASSERT_EQUAL(appender->count, initialCount);
+               {
+                       LevelChange x(LOG4CXX_STR("ComplexProcessing"), 
myLogger);
+                       processor.DoStep2();
+                       // Check the ComplexProcessing debug request was sent 
to the appender
+                       LOGUNIT_ASSERT_EQUAL(appender->count, initialCount + 1);
+               }
+
+               // Check the ComplexProcessing debug request is no longer sent 
to the appender
+               auto finalCount = appender->count;
+               processor.DoStep3();
+               LOGUNIT_ASSERT_EQUAL(appender->count, finalCount);
+       }
+};
+
+LOGUNIT_TEST_SUITE_REGISTRATION(LevelChangeTestCase);

Reply via email to