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 <[email protected]>
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);
+       }
+
 };
 
 //

Reply via email to