You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by sw...@apache.org on 2023/01/19 06:36:25 UTC

[logging-log4cxx] 01/01: Allow use on Window Server 2016 (issue #180). Put more than the first character of thread name into the event log on Windows.

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

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

commit b47bec5ac05b60af5042a20edee0a85c16875aef
Author: Stephen Webb <st...@sabreautonomous.com.au>
AuthorDate: Thu Jan 19 17:35:37 2023 +1100

    Allow use on Window Server 2016 (issue #180).
    Put more than the first character of thread name into the event log on
    Windows.
---
 src/main/cpp/loggingevent.cpp                      | 32 +++++++++++++++++-----
 src/main/cpp/threadutility.cpp                     | 25 +++++++++++++----
 src/main/include/CMakeLists.txt                    |  7 -----
 src/test/cpp/autoconfiguretestcase.cpp             | 27 ++++++++++++++++++
 .../resources/input/autoConfigureTest.properties   |  3 +-
 5 files changed, 73 insertions(+), 21 deletions(-)

diff --git a/src/main/cpp/loggingevent.cpp b/src/main/cpp/loggingevent.cpp
index daf89500..cc7f7479 100644
--- a/src/main/cpp/loggingevent.cpp
+++ b/src/main/cpp/loggingevent.cpp
@@ -374,13 +374,31 @@ const LogString& LoggingEvent::getCurrentThreadUserName()
 	}
 
 	log4cxx::helpers::Transcoder::decode(reinterpret_cast<const char*>(result), thread_name);
-#elif LOG4CXX_HAS_GETTHREADDESCRIPTION
-	PWSTR result;
-	HANDLE threadId = GetCurrentThread();
-	if( GetThreadDescription( threadId, &result ) == 0 ){
-		// Success
-		log4cxx::helpers::Transcoder::decode(reinterpret_cast<const char*>(result), thread_name);
-		LocalFree(result);
+#elif WIN32
+	typedef HRESULT (WINAPI *TGetThreadDescription)(HANDLE, PWSTR*);
+	static struct initialiser
+	{
+		HMODULE hKernelBase;
+		TGetThreadDescription GetThreadDescription;
+		initialiser()
+			: hKernelBase(GetModuleHandleA("KernelBase.dll"))
+			, GetThreadDescription(nullptr)
+		{
+			if (hKernelBase)
+				GetThreadDescription = reinterpret_cast<TGetThreadDescription>(GetProcAddress(hKernelBase, "GetThreadDescription"));
+		}
+	} win32func;
+	if (win32func.GetThreadDescription)
+	{
+		PWSTR result = 0;
+		HRESULT hr = win32func.GetThreadDescription(GetCurrentThread(), &result);
+		if (SUCCEEDED(hr))
+		{
+			std::wstring wresult = result;
+			LOG4CXX_DECODE_UNICHAR(decoded, wresult);
+			LocalFree(result);
+			thread_name = decoded;
+		}
 	}else{
 		thread_name = LOG4CXX_STR("(noname)");
 	}
diff --git a/src/main/cpp/threadutility.cpp b/src/main/cpp/threadutility.cpp
index 877b06ea..b579965e 100644
--- a/src/main/cpp/threadutility.cpp
+++ b/src/main/cpp/threadutility.cpp
@@ -139,13 +139,26 @@ void ThreadUtility::threadStartedNameThread(LogString threadName,
 	if (pthread_setname_np(static_cast<pthread_t>(nativeHandle), sthreadName.c_str()) < 0) {
 		LOGLOG_ERROR(LOG4CXX_STR("unable to set thread name"));
 	}
-#elif LOG4CXX_HAS_SETTHREADDESCRIPTION
-	LOG4CXX_ENCODE_WCHAR(wthreadName, threadName);
-	HRESULT hr = SetThreadDescription(static_cast<HANDLE>(nativeHandle), wthreadName.c_str());
-	if(FAILED(hr)){
-		LOGLOG_ERROR( LOG4CXX_STR("unable to set thread name") );
+#elif WIN32
+	typedef HRESULT (WINAPI *TSetThreadDescription)(HANDLE, PCWSTR);
+	static struct initialiser
+	{
+		HMODULE hKernelBase;
+		TSetThreadDescription SetThreadDescription;
+		initialiser()
+			: hKernelBase(GetModuleHandleA("KernelBase.dll"))
+			, SetThreadDescription(nullptr)
+		{
+			if (hKernelBase)
+				SetThreadDescription = reinterpret_cast<TSetThreadDescription>(GetProcAddress(hKernelBase, "SetThreadDescription"));
+		}
+	} win32Func;
+	if (win32Func.SetThreadDescription)
+	{
+		LOG4CXX_ENCODE_WCHAR(wthreadName, threadName);
+		if(FAILED(win32Func.SetThreadDescription(static_cast<HANDLE>(nativeHandle), wthreadName.c_str())))
+			LOGLOG_ERROR( LOG4CXX_STR("unable to set thread name") );
 	}
-
 #endif
 }
 
diff --git a/src/main/include/CMakeLists.txt b/src/main/include/CMakeLists.txt
index 59982cf3..62f61bd4 100644
--- a/src/main/include/CMakeLists.txt
+++ b/src/main/include/CMakeLists.txt
@@ -146,11 +146,6 @@ if(UNIX)
     endif()
 endif(UNIX)
 
-if(WIN32)
-    CHECK_SYMBOL_EXISTS(SetThreadDescription "windows.h;processthreadsapi.h" HAS_SETTHREADDESCRIPTION)
-    CHECK_SYMBOL_EXISTS(GetThreadDescription "windows.h;processthreadsapi.h" HAS_GETTHREADDESCRIPTION)
-endif(WIN32)
-
 foreach(varName
   HAS_THREAD_LOCAL
   HAS_STD_LOCALE
@@ -163,8 +158,6 @@ foreach(varName
   HAS_PTHREAD_SIGMASK
   HAS_PTHREAD_SETNAME
   HAS_PTHREAD_GETNAME
-  HAS_SETTHREADDESCRIPTION
-  HAS_GETTHREADDESCRIPTION
   )
   if(${varName} EQUAL 0)
     continue()
diff --git a/src/test/cpp/autoconfiguretestcase.cpp b/src/test/cpp/autoconfiguretestcase.cpp
index e486727e..73527e73 100644
--- a/src/test/cpp/autoconfiguretestcase.cpp
+++ b/src/test/cpp/autoconfiguretestcase.cpp
@@ -24,6 +24,7 @@
 #include <log4cxx/helpers/loglog.h>
 #include <log4cxx/helpers/pool.h>
 #include <log4cxx/helpers/stringhelper.h>
+#include <log4cxx/helpers/threadutility.h>
 #include <thread>
 #include <apr_file_io.h>
 #include <apr_file_info.h>
@@ -104,11 +105,37 @@ public:
 		LOGUNIT_ASSERT(rep->isConfigured());
 	}
 
+	// Base for a template that identifies whather std::thread::id has a native_handle member
+	template< class, class = void >
+	struct has_native_handle_member : std::false_type { };
+
+	template< class T >
+	struct has_native_handle_member<T,
+		std::void_t<decltype(std::declval<T&>().native_handle)>
+	> : std::true_type { };
+
+	template <typename V>
+	void setThreadName(const V& n, const LogString& name,
+		typename std::enable_if<!has_native_handle_member<V>::value, bool>::type* tag = 0)
+	{
+#ifdef WIN32
+		log4cxx::helpers::ThreadUtility::instance()->threadStartedNameThread(name, n, ::GetCurrentThread());
+#endif
+	}
+	template <typename V>
+	void setThreadName(const V& n, const LogString& name,
+		typename std::enable_if<has_native_handle_member<V>::value, bool>::type* tag = 0)
+	{
+		log4cxx::helpers::ThreadUtility::instance()->threadStartedNameThread(name, n, n.native_handle())
+	}
+
 	void test2()
 	{
+		setThreadName(std::this_thread::get_id(), LOG4CXX_STR("main"));
 		auto debugLogger = LogManager::getLogger(LOG4CXX_STR("AutoConfig.test2"));
 		LOGUNIT_ASSERT(debugLogger);
 		LOGUNIT_ASSERT(debugLogger->isDebugEnabled());
+		LOG4CXX_DEBUG(debugLogger, "Test message");
 	}
 
 	void test3()
diff --git a/src/test/resources/input/autoConfigureTest.properties b/src/test/resources/input/autoConfigureTest.properties
index 1187d130..604f878f 100644
--- a/src/test/resources/input/autoConfigureTest.properties
+++ b/src/test/resources/input/autoConfigureTest.properties
@@ -14,12 +14,13 @@
 # limitations under the License.
 #
 log4j.rootCategory=INFO, A1
+log4j.threadConfiguration=NameThreadOnly
 
 log4j.appender.A1=org.apache.log4j.FileAppender
 log4j.appender.A1.File=output/autoConfigureTest.log
 log4j.appender.A1.Append=false
 log4j.appender.A1.layout=org.apache.log4j.PatternLayout
-log4j.appender.A1.layout.ConversionPattern=%m%n
+log4j.appender.A1.layout.ConversionPattern=%T %m%n
 
 #log4j.logger.AutoConfig.test1=DEBUG
 log4j.logger.AutoConfig.test2=DEBUG