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/19 16:32:53 UTC
[logging-log4cxx] 01/01: LOGCXX-550 The thread name should now be able to be logged
This is an automated email from the ASF dual-hosted git repository.
rmiddleton pushed a commit to branch LOGCXX-550
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git
commit 7b693b91d5876704132a76ce52b84d7a2d6003e7
Author: Robert Middleton <ro...@rm5248.com>
AuthorDate: Sat Mar 19 12:32:33 2022 -0400
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..5fcba0e 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
+ char* result;
+ DWORD threadId = GetCurrentThreadId();
+ 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..e7dddd0 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_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..a8ea26c 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-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);
+ }
+
};
//