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);