You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rm...@apache.org on 2022/03/21 22:26:26 UTC

[logging-log4cxx] branch master updated: LOGCXX-550 The thread name should now be able to be logged (#108)

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

rmiddleton 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 f3e1499  LOGCXX-550 The thread name should now be able to be logged (#108)
f3e1499 is described below

commit f3e14997ff400fce5fe1822a7a69752fb861618c
Author: Robert Middleton <rm...@users.noreply.github.com>
AuthorDate: Mon Mar 21 18:26:22 2022 -0400

    LOGCXX-550 The thread name should now be able to be logged (#108)
    
    * LOGCXX-550 The thread name should now be able to be logged
---
 src/cmake/pthread/log4cxx-pthread.cmake            |  6 ++-
 src/cmake/pthread/test-pthread-getname.cpp         |  7 +++
 .../{test-pthread.cpp => test-pthread-setname.cpp} |  0
 src/main/cpp/CMakeLists.txt                        |  1 +
 src/main/cpp/loggingevent.cpp                      | 37 ++++++++++++++-
 src/main/cpp/patternlayout.cpp                     |  4 ++
 src/main/cpp/threadusernamepatternconverter.cpp    | 53 ++++++++++++++++++++++
 src/main/include/CMakeLists.txt                    |  6 ++-
 .../pattern/threadusernamepatternconverter.h       | 53 ++++++++++++++++++++++
 src/main/include/log4cxx/patternlayout.h           |  8 +++-
 .../include/log4cxx/private/log4cxx_private.h.in   |  2 +
 src/main/include/log4cxx/spi/loggingevent.h        | 16 +++++++
 src/test/cpp/pattern/patternparsertestcase.cpp     | 41 +++++++++++++++++
 13 files changed, 229 insertions(+), 5 deletions(-)

diff --git a/src/cmake/pthread/log4cxx-pthread.cmake b/src/cmake/pthread/log4cxx-pthread.cmake
index d4a5272..bd9e859 100644
--- a/src/cmake/pthread/log4cxx-pthread.cmake
+++ b/src/cmake/pthread/log4cxx-pthread.cmake
@@ -1,6 +1,10 @@
 include(FindThreads)
 
 try_compile(PTHREAD_SETNAME_NP_FOUND "${CMAKE_BINARY_DIR}/pthread-compile-tests"
-    "${CMAKE_CURRENT_LIST_DIR}/test-pthread.cpp"
+    "${CMAKE_CURRENT_LIST_DIR}/test-pthread-setname.cpp"
+    LINK_LIBRARIES Threads::Threads )
+
+try_compile(PTHREAD_GETNAME_NP_FOUND "${CMAKE_BINARY_DIR}/pthread-compile-tests"
+    "${CMAKE_CURRENT_LIST_DIR}/test-pthread-getname.cpp"
     LINK_LIBRARIES Threads::Threads )
 
diff --git a/src/cmake/pthread/test-pthread-getname.cpp b/src/cmake/pthread/test-pthread-getname.cpp
new file mode 100644
index 0000000..4e149ed
--- /dev/null
+++ b/src/cmake/pthread/test-pthread-getname.cpp
@@ -0,0 +1,7 @@
+#include <pthread.h>
+
+int main(){
+	pthread_t tid;
+	char buffer[16];
+	pthread_getname_np(tid, buffer, sizeof(buffer));
+}
diff --git a/src/cmake/pthread/test-pthread.cpp b/src/cmake/pthread/test-pthread-setname.cpp
similarity index 100%
rename from src/cmake/pthread/test-pthread.cpp
rename to src/cmake/pthread/test-pthread-setname.cpp
diff --git a/src/main/cpp/CMakeLists.txt b/src/main/cpp/CMakeLists.txt
index 419503b..bb1445a 100644
--- a/src/main/cpp/CMakeLists.txt
+++ b/src/main/cpp/CMakeLists.txt
@@ -165,6 +165,7 @@ target_sources(log4cxx
   telnetappender.cpp
   threadlocal.cpp
   threadpatternconverter.cpp
+  threadusernamepatternconverter.cpp
   threadspecificdata.cpp
   threadutility.cpp
   throwableinformationpatternconverter.cpp
diff --git a/src/main/cpp/loggingevent.cpp b/src/main/cpp/loggingevent.cpp
index 98056d5..eb59e2f 100644
--- a/src/main/cpp/loggingevent.cpp
+++ b/src/main/cpp/loggingevent.cpp
@@ -77,7 +77,8 @@ LoggingEvent::LoggingEvent(
 	message(message1),
 	timeStamp(apr_time_now()),
 	locationInfo(locationInfo1),
-	threadName(getCurrentThreadName())
+	threadName(getCurrentThreadName()),
+	threadUserName(getCurrentThreadUserName())
 {
 }
 
@@ -88,6 +89,10 @@ LoggingEvent::~LoggingEvent()
 	delete properties;
 }
 
+const LogString& LoggingEvent::getThreadUserName() const{
+	return threadUserName;
+}
+
 bool LoggingEvent::getNDC(LogString& dest) const
 {
 	if (ndcLookupRequired)
@@ -247,6 +252,36 @@ const LogString LoggingEvent::getCurrentThreadName()
 #endif /* APR_HAS_THREADS */
 }
 
+const LogString LoggingEvent::getCurrentThreadUserName()
+{
+	LOG4CXX_THREAD_LOCAL LogString thread_name;
+	if( thread_name.size() ){
+		return thread_name;
+	}
+
+#if LOG4CXX_HAS_PTHREAD_GETNAME
+	char result[16];
+	pthread_t current_thread = pthread_self();
+	if( pthread_getname_np( current_thread, result, sizeof(result) ) < 0 ){
+		thread_name = LOG4CXX_STR("(noname)");
+	}
+
+	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);
+	}else{
+		thread_name = LOG4CXX_STR("(noname)");
+	}
+#else
+	thread_name = LOG4CXX_STR("(noname)");
+#endif
+	return thread_name;
+}
 
 void LoggingEvent::setProperty(const LogString& key, const LogString& value)
 {
diff --git a/src/main/cpp/patternlayout.cpp b/src/main/cpp/patternlayout.cpp
index 3070085..4b610db 100644
--- a/src/main/cpp/patternlayout.cpp
+++ b/src/main/cpp/patternlayout.cpp
@@ -49,6 +49,7 @@
 #include <log4cxx/pattern/ndcpatternconverter.h>
 #include <log4cxx/pattern/propertiespatternconverter.h>
 #include <log4cxx/pattern/throwableinformationpatternconverter.h>
+#include <log4cxx/pattern/threadusernamepatternconverter.h>
 
 
 using namespace log4cxx;
@@ -190,6 +191,9 @@ log4cxx::pattern::PatternMap PatternLayout::getFormatSpecifiers()
 	RULES_PUT("t", ThreadPatternConverter);
 	RULES_PUT("thread", ThreadPatternConverter);
 
+	RULES_PUT("T", ThreadUsernamePatternConverter);
+	RULES_PUT("threadname", ThreadUsernamePatternConverter);
+
 	RULES_PUT("x", NDCPatternConverter);
 	RULES_PUT("ndc", NDCPatternConverter);
 
diff --git a/src/main/cpp/threadusernamepatternconverter.cpp b/src/main/cpp/threadusernamepatternconverter.cpp
new file mode 100644
index 0000000..81e042a
--- /dev/null
+++ b/src/main/cpp/threadusernamepatternconverter.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+#if defined(_MSC_VER)
+	#pragma warning ( disable: 4231 4251 4275 4786 )
+#endif
+
+#include <log4cxx/logstring.h>
+#include <log4cxx/pattern/threadusernamepatternconverter.h>
+#include <log4cxx/spi/loggingevent.h>
+#include <log4cxx/spi/location/locationinfo.h>
+
+using namespace log4cxx;
+using namespace log4cxx::pattern;
+using namespace log4cxx::spi;
+using namespace log4cxx::helpers;
+
+IMPLEMENT_LOG4CXX_OBJECT(ThreadUsernamePatternConverter)
+
+ThreadUsernamePatternConverter::ThreadUsernamePatternConverter() :
+	LoggingEventPatternConverter(LOG4CXX_STR("Thread Name"),
+		LOG4CXX_STR("Thread Name"))
+{
+}
+
+PatternConverterPtr ThreadUsernamePatternConverter::newInstance(
+	const std::vector<LogString>& /* options */)
+{
+	static PatternConverterPtr def(new ThreadUsernamePatternConverter());
+	return def;
+}
+
+void ThreadUsernamePatternConverter::format(
+	const LoggingEventPtr& event,
+	LogString& toAppendTo,
+	Pool& /* p */) const
+{
+	toAppendTo.append(event->getThreadUserName());
+}
+
diff --git a/src/main/include/CMakeLists.txt b/src/main/include/CMakeLists.txt
index 667d78a..625c8b2 100644
--- a/src/main/include/CMakeLists.txt
+++ b/src/main/include/CMakeLists.txt
@@ -115,13 +115,17 @@ if(UNIX)
     if(${PTHREAD_SETNAME_NP_FOUND})
 	set(HAS_PTHREAD_SETNAME 1)
     endif()
+    if(${PTHREAD_GETNAME_NP_FOUND})
+	set(HAS_PTHREAD_GETNAME 1)
+    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_STD_LOCALE  HAS_ODBC  HAS_MBSRTOWCS  HAS_WCSTOMBS  HAS_FWIDE  HAS_LIBESMTP  HAS_SYSLOG HAS_PTHREAD_SIGMASK HAS_PTHREAD_SETNAME HAS_SETTHREADDESCRIPTION)
+foreach(varName HAS_STD_LOCALE  HAS_ODBC  HAS_MBSRTOWCS  HAS_WCSTOMBS  HAS_FWIDE  HAS_LIBESMTP  HAS_SYSLOG HAS_PTHREAD_SIGMASK HAS_PTHREAD_SETNAME HAS_PTHREAD_GETNAME HAS_SETTHREADDESCRIPTION HAS_GETTHREADDESCRIPTION)
   if(${varName} EQUAL 0)
     continue()
   elseif(${varName} EQUAL 1)
diff --git a/src/main/include/log4cxx/pattern/threadusernamepatternconverter.h b/src/main/include/log4cxx/pattern/threadusernamepatternconverter.h
new file mode 100644
index 0000000..60bb9ca
--- /dev/null
+++ b/src/main/include/log4cxx/pattern/threadusernamepatternconverter.h
@@ -0,0 +1,53 @@
+/*
+ * 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_THREAD_USERNAME_PATTERN_CONVERTER_H
+#define LOG4CXX_THREAD_USERNAME_PATTERN_CONVERTER_H
+
+#include <log4cxx/pattern/loggingeventpatternconverter.h>
+#include <log4cxx/spi/loggingevent.h>
+
+namespace log4cxx
+{
+
+namespace pattern
+{
+
+class LOG4CXX_EXPORT ThreadUsernamePatternConverter : public LoggingEventPatternConverter
+{
+        ThreadUsernamePatternConverter();
+
+    public:
+	    DECLARE_LOG4CXX_PATTERN(ThreadUsernamePatternConverter)
+	    BEGIN_LOG4CXX_CAST_MAP()
+	    LOG4CXX_CAST_ENTRY(ThreadUsernamePatternConverter)
+	    LOG4CXX_CAST_ENTRY_CHAIN(LoggingEventPatternConverter)
+	    END_LOG4CXX_CAST_MAP()
+
+	    static PatternConverterPtr newInstance(
+	            const std::vector<LogString>& options);
+
+	    void format(const log4cxx::spi::LoggingEventPtr& event,
+	            LogString& toAppendTo,
+	            log4cxx::helpers::Pool& p) const;
+};
+
+}
+}
+
+#endif
+
diff --git a/src/main/include/log4cxx/patternlayout.h b/src/main/include/log4cxx/patternlayout.h
index 7b695d7..aa59b3b 100644
--- a/src/main/include/log4cxx/patternlayout.h
+++ b/src/main/include/log4cxx/patternlayout.h
@@ -206,8 +206,12 @@ LOG4CXX_LIST_DEF(FormattingInfoList, log4cxx::pattern::FormattingInfoPtr);
  *      </td>
  *  </tr>
  *  <tr>
- *      <td align="center"><strong>t</strong></td>
- *      <td>Used to output the name of the thread that generated the logging event.</td>
+ *      <td align="center"><strong>t</strong><p><strong>thread</strong></p></td>
+ *      <td>Used to output the ID of the thread that generated the logging event.</td>
+ *  </tr>
+ *  <tr>
+ *      <td align="center"><strong>T</strong><p><strong>threadname</strong></p></td>
+ *      <td>Used to output the name of the thread that generated the logging event.  May not be available on all platforms.</td>
  *  </tr>
  *  <tr>
  *      <td align="center"><strong>x</strong></td>
diff --git a/src/main/include/log4cxx/private/log4cxx_private.h.in b/src/main/include/log4cxx/private/log4cxx_private.h.in
index bf965c9..26281e0 100644
--- a/src/main/include/log4cxx/private/log4cxx_private.h.in
+++ b/src/main/include/log4cxx/private/log4cxx_private.h.in
@@ -55,7 +55,9 @@
 
 #define LOG4CXX_HAS_PTHREAD_SIGMASK @HAS_PTHREAD_SIGMASK@
 #define LOG4CXX_HAS_PTHREAD_SETNAME @HAS_PTHREAD_SETNAME@
+#define LOG4CXX_HAS_PTHREAD_GETNAME @HAS_PTHREAD_GETNAME@
 #define LOG4CXX_HAS_SETTHREADDESCRIPTION @HAS_SETTHREADDESCRIPTION@
+#define LOG4CXX_HAS_GETTHREADDESCRIPTION @HAS_GETTHREADDESCRIPTION@
 
 #ifdef __BORLANDC__
 /*
diff --git a/src/main/include/log4cxx/spi/loggingevent.h b/src/main/include/log4cxx/spi/loggingevent.h
index 6e40103..ffea0d4 100644
--- a/src/main/include/log4cxx/spi/loggingevent.h
+++ b/src/main/include/log4cxx/spi/loggingevent.h
@@ -117,6 +117,12 @@ class LOG4CXX_EXPORT LoggingEvent :
 			return threadName;
 		}
 
+		/**
+		 * Get the user name of the thread.  The default name is (noname) if
+		 * Log4cxx is unable to retrieve the name using a platform-specific call.
+		 */
+		const LogString& getThreadUserName() const;
+
 		/** The number of microseconds elapsed from 01.01.1970 until logging event
 		 was created. */
 		inline log4cxx_time_t getTimeStamp() const
@@ -248,15 +254,25 @@ class LOG4CXX_EXPORT LoggingEvent :
 
 		/** The identifier of thread in which this logging event
 		was generated.
+		Note: This is the thread ID in hex.
+		See also LoggingEvent::threadUserName
 		*/
 		const LogString threadName;
 
+		/**
+		 * The user-specified name of the thread(on a per-platform basis).
+		 * This is set using a method such as pthread_setname_np on POSIX
+		 * systems or SetThreadDescription on Windows.
+		 */
+		const LogString threadUserName;
+
 		//
 		//   prevent copy and assignment
 		//
 		LoggingEvent(const LoggingEvent&);
 		LoggingEvent& operator=(const LoggingEvent&);
 		static const LogString getCurrentThreadName();
+		static const LogString getCurrentThreadUserName();
 
 		static void writeProlog(log4cxx::helpers::ObjectOutputStream& os, log4cxx::helpers::Pool& p);
 
diff --git a/src/test/cpp/pattern/patternparsertestcase.cpp b/src/test/cpp/pattern/patternparsertestcase.cpp
index 01a7a42..93221b0 100644
--- a/src/test/cpp/pattern/patternparsertestcase.cpp
+++ b/src/test/cpp/pattern/patternparsertestcase.cpp
@@ -50,6 +50,11 @@
 #include <log4cxx/pattern/ndcpatternconverter.h>
 #include <log4cxx/pattern/propertiespatternconverter.h>
 #include <log4cxx/pattern/throwableinformationpatternconverter.h>
+#include <log4cxx/pattern/threadusernamepatternconverter.h>
+
+#define LOG4CXX_TEST 1
+#include <log4cxx/private/log4cxx_private.h>
+#include <thread>
 
 
 using namespace log4cxx;
@@ -71,6 +76,7 @@ LOGUNIT_CLASS(PatternParserTestCase)
 	LOGUNIT_TEST(testBasic1);
 	LOGUNIT_TEST(testBasic2);
 	LOGUNIT_TEST(testMultiOption);
+	LOGUNIT_TEST(testThreadUsername);
 	LOGUNIT_TEST_SUITE_END();
 
 	LoggingEventPtr event;
@@ -78,6 +84,21 @@ LOGUNIT_CLASS(PatternParserTestCase)
 public:
 	void setUp()
 	{
+		LogString threadName = LOG4CXX_STR("log4cxx-thr");
+
+#if LOG4CXX_HAS_PTHREAD_SETNAME
+	if( pthread_setname_np( pthread_self(), threadName.c_str() ) < 0 ){
+		LOGLOG_ERROR( LOG4CXX_STR("unable to set thread name") );
+	}
+#elif LOG4CXX_HAS_SETTHREADDESCRIPTION
+	HRESULT hr = SetThreadDescription(GetCurrentThread(), threadName.c_str());
+	if(FAILED(hr)){
+		LOGLOG_ERROR( LOG4CXX_STR("unable to set thread name") );
+	}
+#else
+		threadName = LOG4CXX_STR("(noname)");
+#endif
+
 		event = LoggingEventPtr(new LoggingEvent(
 					LOG4CXX_STR("org.foobar"), Level::getInfo(), LOG4CXX_STR("msg 1"), LOG4CXX_LOCATION));
 	}
@@ -124,6 +145,9 @@ public:
 		RULES_PUT("t", ThreadPatternConverter);
 		RULES_PUT("thread", ThreadPatternConverter);
 
+		RULES_PUT("T", ThreadUsernamePatternConverter);
+		RULES_PUT("threadname", ThreadUsernamePatternConverter);
+
 		RULES_PUT("x", NDCPatternConverter);
 		RULES_PUT("ndc", NDCPatternConverter);
 
@@ -243,6 +267,23 @@ public:
 			expected);
 	}
 
+	void testThreadUsername()
+	{
+		Pool pool;
+		RelativeTimeDateFormat relativeFormat;
+		LogString expected;
+		relativeFormat.format(expected, event->getTimeStamp(), pool);
+
+		expected.append(LOG4CXX_STR(" INFO  ["));
+		expected.append(event->getThreadUserName());
+		expected.append(LOG4CXX_STR("] org.foobar - msg 1"));
+		expected.append(LOG4CXX_EOL);
+
+		assertFormattedEquals(LOG4CXX_STR("%relative %-5level [%threadname] %logger - %m%n"),
+			getFormatSpecifiers(),
+			expected);
+	}
+
 };
 
 //