You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ts...@apache.org on 2020/06/06 12:43:56 UTC

[logging-log4cxx] 01/05: Implement mapfilter Build unit test for mapfilter

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

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

commit b9ea65496003b9cb8f29ddc76e0c8f21e18ae862
Author: Patrick Mills <pa...@cerberusftp.com>
AuthorDate: Tue Jun 2 19:29:37 2020 -0400

    Implement mapfilter
    Build unit test for mapfilter
---
 src/main/cpp/CMakeLists.txt                 |   1 +
 src/main/cpp/Makefile.am                    |   1 +
 src/main/cpp/mapfilter.cpp                  |  79 ++++++++++++++
 src/main/include/log4cxx/filter/mapfilter.h |  71 +++++++++++-
 src/test/cpp/Makefile.am                    |   1 +
 src/test/cpp/filter/CMakeLists.txt          |   1 +
 src/test/cpp/filter/mapfiltertest.cpp       | 163 ++++++++++++++++++++++++++++
 7 files changed, 312 insertions(+), 5 deletions(-)

diff --git a/src/main/cpp/CMakeLists.txt b/src/main/cpp/CMakeLists.txt
index 321edf0..8f7d609 100644
--- a/src/main/cpp/CMakeLists.txt
+++ b/src/main/cpp/CMakeLists.txt
@@ -87,6 +87,7 @@ target_sources(log4cxx
   logmanager.cpp
   logstream.cpp
   manualtriggeringpolicy.cpp
+  mapfilter.cpp
   mdc.cpp
   messagebuffer.cpp
   messagepatternconverter.cpp
diff --git a/src/main/cpp/Makefile.am b/src/main/cpp/Makefile.am
index 236a9a6..3643623 100644
--- a/src/main/cpp/Makefile.am
+++ b/src/main/cpp/Makefile.am
@@ -93,6 +93,7 @@ liblog4cxx_la_SOURCES = \
         logmanager.cpp \
         logstream.cpp \
         manualtriggeringpolicy.cpp \
+        mapfilter.cpp \
         messagebuffer.cpp \
         messagepatternconverter.cpp \
         methodlocationpatternconverter.cpp \
diff --git a/src/main/cpp/mapfilter.cpp b/src/main/cpp/mapfilter.cpp
new file mode 100644
index 0000000..da03464
--- /dev/null
+++ b/src/main/cpp/mapfilter.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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/logstring.h>
+#include <log4cxx/filter/mapfilter.h>
+#include <log4cxx/spi/loggingevent.h>
+#include <log4cxx/helpers/stringhelper.h>
+#include <log4cxx/helpers/optionconverter.h>
+
+using namespace log4cxx;
+using namespace log4cxx::filter;
+using namespace log4cxx::spi;
+using namespace log4cxx::helpers;
+
+IMPLEMENT_LOG4CXX_OBJECT(MapFilter)
+
+void MapFilter::setOption(const LogString& option,
+	const LogString& value)
+{
+
+	if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("ACCEPTONMATCH"), LOG4CXX_STR("acceptonmatch"))) {
+
+		acceptOnMatch = OptionConverter::toBoolean(value, acceptOnMatch);
+	}
+	else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("OPERATOR"), LOG4CXX_STR("operator"))) {
+
+		mustMatchAll = StringHelper::equalsIgnoreCase(value, LOG4CXX_STR("AND"), LOG4CXX_STR("and")) ? true : false;
+	}
+	else if (!option.empty() && !value.empty()) {
+
+		mapKeyValList.emplace(option, value);
+	}
+}
+
+Filter::FilterDecision MapFilter::decide(
+	const log4cxx::spi::LoggingEventPtr& event) const
+{
+	if (mapKeyValList.empty()) {
+		return Filter::NEUTRAL;
+	}
+
+	bool	matched = true;
+	for (auto it = mapKeyValList.cbegin(); it != mapKeyValList.cend(); ++it) {
+		LogString curval;
+		event->getMDC(it->first, curval);
+
+		if (curval.empty() || curval != it->second) {
+			matched = false;
+		}
+		else {
+			matched = true;
+		}
+			
+		if (mustMatchAll != matched) {
+			break;
+		}
+	}
+
+	if (acceptOnMatch)	{
+		return matched ? Filter::ACCEPT : Filter::DENY;
+	}
+	else {
+		return matched ? Filter::DENY : Filter::ACCEPT;
+	}
+}
diff --git a/src/main/include/log4cxx/filter/mapfilter.h b/src/main/include/log4cxx/filter/mapfilter.h
index d6db108..5bc37b9 100644
--- a/src/main/include/log4cxx/filter/mapfilter.h
+++ b/src/main/include/log4cxx/filter/mapfilter.h
@@ -19,26 +19,87 @@
 
 #include <log4cxx/spi/filter.h>
 
+#if defined(_MSC_VER)
+	#pragma warning ( push )
+	#pragma warning ( disable: 4251 )
+#endif
+
 namespace log4cxx
 {
 namespace filter
 {
+/**
+ * A Filter that operates on a Map.
+ */
 
+ using keyvallist = std::map<LogString, LogString>;
 
 class LOG4CXX_EXPORT MapFilter: public log4cxx::spi::Filter
 {
+	private:
+		bool acceptOnMatch{true};
+		bool mustMatchAll{false};	// true = AND; false = OR
+		keyvallist mapKeyValList;
+
 	public:
 		DECLARE_LOG4CXX_OBJECT(MapFilter)
 		BEGIN_LOG4CXX_CAST_MAP()
-		LOG4CXX_CAST_ENTRY(log4cxx::spi::Filter)
+		LOG4CXX_CAST_ENTRY(MapFilter)
+		LOG4CXX_CAST_ENTRY_CHAIN(log4cxx::spi::Filter)
 		END_LOG4CXX_CAST_MAP()
 
-		MapFilter();
+		MapFilter(){}
+
+		/**
+		Set options
+		*/
+		virtual void setOption(const LogString& option,
+			const LogString& value);
+
+		inline void setKeyValue(const LogString& strKey, const LogString& strValue)
+		{
+			this->mapKeyValList[strKey] = strValue;
+		}
 
+		inline const LogString& getValue(const LogString& strKey) const
+		{
+			static const LogString empty{};
+			auto it = mapKeyValList.find(strKey);
+			return (it != mapKeyValList.end() ? it->second : empty);
+		}
 
+		inline void setAcceptOnMatch(bool acceptOnMatch1)
+		{
+			this->acceptOnMatch = acceptOnMatch1;
+		}
+
+		inline bool getAcceptOnMatch() const
+		{
+			return acceptOnMatch;
+		}
+
+		inline bool getMustMatchAll() const
+		{
+			return mustMatchAll;
+		}
+
+		inline void setMustMatchAll(bool mustMatchAll1)
+		{
+			this->mustMatchAll = mustMatchAll1;
+		}
+
+		/**
+		Returns {@link log4cxx::spi::Filter#NEUTRAL NEUTRAL}
+		is there is no string match.
+		*/
 		FilterDecision decide(const spi::LoggingEventPtr& event) const;
+}; // class MapFilter
+LOG4CXX_PTR_DEF(MapFilter);
+}  // namespace filter
+} // namespace log4cxx
 
-};
-}
-}
+#if defined(_MSC_VER)
+	#pragma warning (pop)
 #endif
+
+#endif // _LOG4CXX_FILTER_MAPFILTER_H
diff --git a/src/test/cpp/Makefile.am b/src/test/cpp/Makefile.am
index 8b6c95d..1f42361 100644
--- a/src/test/cpp/Makefile.am
+++ b/src/test/cpp/Makefile.am
@@ -67,6 +67,7 @@ filter_tests = \
     filter/levelmatchfiltertest.cpp \
     filter/levelrangefiltertest.cpp \
     filter/loggermatchfiltertest.cpp \
+    filter/mapfiltertest.cpp \
     filter/stringmatchfiltertest.cpp
 
 helpers = \
diff --git a/src/test/cpp/filter/CMakeLists.txt b/src/test/cpp/filter/CMakeLists.txt
index 83dc498..3b4bcb0 100644
--- a/src/test/cpp/filter/CMakeLists.txt
+++ b/src/test/cpp/filter/CMakeLists.txt
@@ -4,6 +4,7 @@ add_executable(filtertests
     levelmatchfiltertest.cpp
     levelrangefiltertest.cpp
     loggermatchfiltertest.cpp
+    mapfiltertest.cpp
     stringmatchfiltertest.cpp
 )
 set(ALL_LOG4CXX_TESTS ${ALL_LOG4CXX_TESTS} filtertests PARENT_SCOPE)
diff --git a/src/test/cpp/filter/mapfiltertest.cpp b/src/test/cpp/filter/mapfiltertest.cpp
new file mode 100644
index 0000000..b34f57c
--- /dev/null
+++ b/src/test/cpp/filter/mapfiltertest.cpp
@@ -0,0 +1,163 @@
+/*
+ * 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/filter/mapfilter.h>
+#include <log4cxx/logger.h>
+#include <log4cxx/spi/filter.h>
+#include <log4cxx/spi/loggingevent.h>
+#include "../logunit.h"
+
+using namespace log4cxx;
+using namespace log4cxx::filter;
+using namespace log4cxx::spi;
+using namespace log4cxx::helpers;
+
+/**
+ * Unit tests for MapFilter.
+ */
+LOGUNIT_CLASS(MapFilterTest)
+{
+	LOGUNIT_TEST_SUITE(MapFilterTest);
+	LOGUNIT_TEST(test1);
+	LOGUNIT_TEST(test2);
+	LOGUNIT_TEST(test3);
+	LOGUNIT_TEST(test4);
+	LOGUNIT_TEST_SUITE_END();
+
+public:
+
+	/**
+	 * Check that MapFilter.decide() returns Filter.NEUTRAL
+	 *   when there are no map entries specified.
+	 */
+	void test1()
+	{
+		LoggingEventPtr event(new LoggingEvent(
+				LOG4CXX_STR("MapFilterTest"),
+				Level::getInfo(),
+				LOG4CXX_STR("Hello, World"),
+				LOG4CXX_LOCATION));
+		FilterPtr filter(new MapFilter());
+		Pool p;
+		filter->activateOptions(p);
+		LOGUNIT_ASSERT_EQUAL(Filter::NEUTRAL, filter->decide(event));
+	}
+
+	/**
+	 * Check that MapFilter.decide() returns Filter.ACCEPT or Filter.DENY
+	 *   based on Accept on Match setting when key/value does not match
+	 */
+	void test2()
+	{
+		LoggingEventPtr event(new LoggingEvent(
+				LOG4CXX_STR("MapFilterTest"),
+				Level::getInfo(),
+				LOG4CXX_STR("Hello, World"),
+				LOG4CXX_LOCATION));
+		MDC::put(LOG4CXX_STR("my.ip"), LOG4CXX_STR("localhost"));
+		MapFilterPtr filter(new MapFilter());
+		filter->setKeyValue(LOG4CXX_STR("my.ip"), LOG4CXX_STR("127.0.0.1"));
+		Pool p;
+		filter->activateOptions(p);
+
+		filter->setAcceptOnMatch(true);
+		LOGUNIT_ASSERT_EQUAL(Filter::DENY, filter->decide(event));
+
+		filter->setAcceptOnMatch(false);
+		LOGUNIT_ASSERT_EQUAL(Filter::ACCEPT, filter->decide(event));
+	}
+
+	/**
+	 * Check that MapFilter.decide() returns Filter.ACCEPT or Filter.DENY
+	 *   based on Accept on Match setting when key/value matches
+	 */
+	void test3()
+	{
+		LoggingEventPtr event(new LoggingEvent(
+				LOG4CXX_STR("MapFilterTest"),
+				Level::getInfo(),
+				LOG4CXX_STR("Hello, World"),
+				LOG4CXX_LOCATION));
+		MDC::put(LOG4CXX_STR("my.ip"), LOG4CXX_STR("127.0.0.1"));
+		MapFilterPtr filter(new MapFilter());
+		filter->setKeyValue(LOG4CXX_STR("my.ip"), LOG4CXX_STR("127.0.0.1"));
+		Pool p;
+		filter->activateOptions(p);
+
+		filter->setAcceptOnMatch(true);
+		LOGUNIT_ASSERT_EQUAL(Filter::ACCEPT, filter->decide(event));
+
+		filter->setAcceptOnMatch(false);
+		LOGUNIT_ASSERT_EQUAL(Filter::DENY, filter->decide(event));
+	}
+
+	/**
+	 * Check that MapFilter.decide() ANDs or ORs multiple key/values
+	 *   based on operator setting
+	 */
+	void test4()
+	{
+		LoggingEventPtr event(new LoggingEvent(
+				LOG4CXX_STR("MapFilterTest"),
+				Level::getInfo(),
+				LOG4CXX_STR("Hello, World"),
+				LOG4CXX_LOCATION));
+		MDC::put(LOG4CXX_STR("my.ip"), LOG4CXX_STR("127.0.0.1"));
+		MDC::put(LOG4CXX_STR("my.name"), LOG4CXX_STR("Test"));
+		MapFilterPtr filter(new MapFilter());
+		filter->setKeyValue(LOG4CXX_STR("my.ip"), LOG4CXX_STR("127.0.0.1"));
+		filter->setKeyValue(LOG4CXX_STR("my.name"), LOG4CXX_STR("Unknown"));
+		filter->setAcceptOnMatch(true);
+		Pool p;
+		filter->activateOptions(p);
+
+		filter->setMustMatchAll(true);		// AND T/F
+		LOGUNIT_ASSERT_EQUAL(Filter::DENY, filter->decide(event));		// does not match second
+
+		filter->setMustMatchAll(false);	// OR T/F
+		LOGUNIT_ASSERT_EQUAL(Filter::ACCEPT, filter->decide(event));	// matches first
+
+		filter->setKeyValue(LOG4CXX_STR("my.name"), LOG4CXX_STR("Test"));	
+
+		filter->setMustMatchAll(true);		// AND T/T
+		LOGUNIT_ASSERT_EQUAL(Filter::ACCEPT, filter->decide(event));	// matches all
+
+		filter->setMustMatchAll(false);	// OR T/T
+		LOGUNIT_ASSERT_EQUAL(Filter::ACCEPT, filter->decide(event));	// matches first
+
+		filter->setKeyValue(LOG4CXX_STR("my.ip"), LOG4CXX_STR("localhost"));	
+
+		filter->setMustMatchAll(true);		// AND F/T
+		LOGUNIT_ASSERT_EQUAL(Filter::DENY, filter->decide(event));		// does not match first
+
+		filter->setMustMatchAll(false);	// OR F/T
+		LOGUNIT_ASSERT_EQUAL(Filter::ACCEPT, filter->decide(event));	// matches second
+
+		filter->setKeyValue(LOG4CXX_STR("my.name"), LOG4CXX_STR("Unkonwn"));	
+
+		filter->setMustMatchAll(true);		// AND F/F
+		LOGUNIT_ASSERT_EQUAL(Filter::DENY, filter->decide(event));		// does not match first
+
+		filter->setMustMatchAll(false);	// OR F/F
+		LOGUNIT_ASSERT_EQUAL(Filter::DENY, filter->decide(event));		// matches none
+	}
+
+};
+
+
+LOGUNIT_TEST_SUITE_REGISTRATION(MapFilterTest);
+
+