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

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


The following commit(s) were added to refs/heads/next_stable by this push:
     new 2ac4b90e Add example of logging in a static initializer (#141)
2ac4b90e is described below

commit 2ac4b90e8b9fc311d9cba1dbbdae5e151469c843
Author: Stephen Webb <[email protected]>
AuthorDate: Sun Oct 9 15:28:10 2022 +1100

    Add example of logging in a static initializer (#141)
    
    * Replace the description default configuration behaviour in the usage page 
with a link to the DefaultConfigurator documentation
    
    * Improve automatic configuration explainations
    
    * Add an 'auto-configured' example showing logging during static 
initialization
    
    * Link to the auto-confiure example from the usage page. Update the logging 
performance section.
    
    * Enable Log::Log debug messages in a Debug build of the 'auto-configured' 
example
    
    Co-authored-by: Stephen Webb <[email protected]>
---
 src/cmake/win32_target_environment_path.cmake  |  27 ++++
 src/examples/cpp/CMakeLists.txt                |  29 +++-
 src/examples/cpp/UserLib/logmanager.cpp        | 175 +++++++++++++++++++++++++
 src/examples/cpp/UserLib/logmanager.h          |   8 ++
 src/examples/cpp/auto-configured.cpp           |  37 ++++++
 src/examples/cpp/auto-configured.xml           |  15 +++
 src/main/cpp/defaultconfigurator.cpp           |   4 +-
 src/main/include/log4cxx/defaultconfigurator.h |  18 ++-
 src/main/include/log4cxx/hierarchy.h           |  14 +-
 src/main/include/log4cxx/logmanager.h          | 133 +++++++++++--------
 src/site/markdown/usage.md                     |  83 ++++++------
 src/test/cpp/CMakeLists.txt                    |  24 +---
 src/test/cpp/autoconfiguretestcase.cpp         |   6 +-
 13 files changed, 430 insertions(+), 143 deletions(-)

diff --git a/src/cmake/win32_target_environment_path.cmake 
b/src/cmake/win32_target_environment_path.cmake
new file mode 100644
index 00000000..ea122c89
--- /dev/null
+++ b/src/cmake/win32_target_environment_path.cmake
@@ -0,0 +1,27 @@
+# Put the list of runtime path directories into varName.
+function(get_target_environment_path varName)
+  get_filename_component(APR_DLL_DIR "${APR_DLL}" DIRECTORY)
+  get_filename_component(APR_UTIL_DLL_DIR "${APR_UTIL_DLL}" DIRECTORY)
+  get_filename_component(EXPAT_LIB_DIR "${EXPAT_LIBRARY}" DIRECTORY)
+
+
+  set(EXPAT_DLL_DIR "${EXPAT_LIB_DIR}/../bin")
+  set(LOG4CXX_DLL_DIR "$<SHELL_PATH:$<TARGET_FILE_DIR:log4cxx>>;")
+  set(PATH_FOR_TESTS 
${CMAKE_PROGRAM_PATH};${APR_DLL_DIR};${APR_UTIL_DLL_DIR};${LOG4CXX_DLL_DIR};${EXPAT_DLL_DIR}\;)
+  list(REMOVE_DUPLICATES PATH_FOR_TESTS)
+
+  # Note: we need to include the APR DLLs on our path so that the tests will 
run.
+  # The way that CMake sets the environment is that it actually generates a 
secondary file,
+  # CTestTestfile.cmake, which sets the final properties of the test.
+  # However, this results in a secondary quirk to the running of the tests: 
CMake uses
+  # a semicolon to deliminate entries in a list!  Since the Windows PATH is 
semicolon-delimited
+  # as well, CMake uses only the first entry in the list when setting the path.
+  # So, we need to do a triple escape on the PATH that we want to set in order 
for CMake to
+  # properly interpret the PATH
+  set(NORMAL_PATH $ENV{PATH})
+  set(ESCAPED_PATH "")
+  foreach( ENTRY ${PATH_FOR_TESTS}${NORMAL_PATH} )
+         set(ESCAPED_PATH "${ESCAPED_PATH}${ENTRY}\\\;")
+  endforeach()
+  set(${varName} ${ESCAPED_PATH} PARENT_SCOPE)
+endfunction()
diff --git a/src/examples/cpp/CMakeLists.txt b/src/examples/cpp/CMakeLists.txt
index cfb2fe7a..0d36048f 100644
--- a/src/examples/cpp/CMakeLists.txt
+++ b/src/examples/cpp/CMakeLists.txt
@@ -15,13 +15,33 @@
 # limitations under the License.
 #
 
-set(ALL_LOG4CXX_EXAMPLES console delayedloop stream trivial custom-appender)
+set(ALL_LOG4CXX_EXAMPLES auto-configured console delayedloop stream trivial 
custom-appender)
+if( WIN32 )
+    include(win32_target_environment_path)
+    get_target_environment_path(ESCAPED_PATH)
+elseif(CMAKE_BUILD_TYPE)
+  string(TOUPPER ${CMAKE_BUILD_TYPE} UPPER_BUILD_TYPE)
+  if (UPPER_BUILD_TYPE STREQUAL "DEBUG")
+    set(EXAMPLE_COMPILE_DEFINITIONS _DEBUG)
+  endif()
+else()
+  set(EXAMPLE_COMPILE_DEFINITIONS _DEBUG)
+endif()
 
 foreach(exampleName IN LISTS ALL_LOG4CXX_EXAMPLES)
     add_executable(${exampleName} ${exampleName}.cpp)
-    target_compile_definitions(${exampleName} PRIVATE 
${LOG4CXX_COMPILE_DEFINITIONS} ${APR_COMPILE_DEFINITIONS} 
${APR_UTIL_COMPILE_DEFINITIONS} )
+    if(${exampleName} STREQUAL auto-configured)
+        target_sources(${exampleName} PRIVATE UserLib/logmanager.cpp)
+    endif()
+    target_compile_definitions(${exampleName} PRIVATE 
${EXAMPLE_COMPILE_DEFINITIONS} ${LOG4CXX_COMPILE_DEFINITIONS} 
${APR_COMPILE_DEFINITIONS} ${APR_UTIL_COMPILE_DEFINITIONS} )
     target_include_directories(${exampleName} PRIVATE 
${CMAKE_CURRENT_LIST_DIR} $<TARGET_PROPERTY:log4cxx,INCLUDE_DIRECTORIES>)
     target_link_libraries(${exampleName} PRIVATE log4cxx ${APR_UTIL_LIBRARIES} 
${EXPAT_LIBRARIES} ${APR_LIBRARIES} ${APR_SYSTEM_LIBS})
+    if( WIN32 )
+        set_target_properties(${exampleName} PROPERTIES
+          VS_DEBUGGER_ENVIRONMENT "PATH=${ESCAPED_PATH}"
+          VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
+        )
+    endif()
 endforeach()
 
 configure_file( custom-appender.xml
@@ -35,4 +55,9 @@ if(${fmt_FOUND})
     target_compile_definitions(format-string PRIVATE 
${LOG4CXX_COMPILE_DEFINITIONS} ${APR_COMPILE_DEFINITIONS} 
${APR_UTIL_COMPILE_DEFINITIONS} )
     target_include_directories(format-string PRIVATE ${CMAKE_CURRENT_LIST_DIR} 
$<TARGET_PROPERTY:log4cxx,INCLUDE_DIRECTORIES>)
     target_link_libraries(format-string PRIVATE log4cxx ${APR_UTIL_LIBRARIES} 
${EXPAT_LIBRARIES} ${APR_LIBRARIES} ${APR_SYSTEM_LIBS} fmt::fmt)
+    if( WIN32 )
+        set_target_properties( format-string PROPERTIES
+          VS_DEBUGGER_ENVIRONMENT "PATH=${ESCAPED_PATH}"
+        )
+    endif()
 endif(${fmt_FOUND})
diff --git a/src/examples/cpp/UserLib/logmanager.cpp 
b/src/examples/cpp/UserLib/logmanager.cpp
new file mode 100644
index 00000000..9c39ffb9
--- /dev/null
+++ b/src/examples/cpp/UserLib/logmanager.cpp
@@ -0,0 +1,175 @@
+/*
+ * 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 <UserLib/logmanager.h>
+#include <log4cxx/logmanager.h>
+#include <log4cxx/logstring.h>
+#include <log4cxx/defaultconfigurator.h>
+#include <log4cxx/helpers/pool.h>
+#include <log4cxx/spi/loggerrepository.h>
+#include <log4cxx/file.h>
+#include <log4cxx/helpers/loglog.h>
+#include <log4cxx/helpers/transcoder.h>
+
+#ifdef WIN32
+#include <Windows.h>
+#elif __APPLE__
+#include <mach-o/dyld.h>
+#else
+#include <unistd.h>     /* getpid */
+#endif
+
+namespace
+{
+
+using namespace log4cxx;
+
+// Get a list of file base names that may contain configuration data
+// and put an alternate path into \c altPrefix
+       std::vector<std::string>
+DefaultConfigurationFileNames(std::string& altPrefix)
+{
+       std::vector<std::string> result;
+
+       // Find the executable file name
+       static const int bufSize = 4096;
+       char buf[bufSize+1] = {0}, pathSepar = '/';
+       uint32_t bufCount = 0;
+#if defined(WIN32)
+       GetModuleFileName(NULL, buf, bufSize);
+       pathSepar = '\\';
+#elif defined(__APPLE__)
+       _NSGetExecutablePath(buf, &bufCount);
+#else
+       std::ostringstream exeLink;
+       exeLink << "/proc/" << getpid() << "/exe";
+       bufCount = readlink(exeLink.str().c_str(), buf, bufSize);
+       if (0 < bufCount)
+               buf[bufCount] = 0;
+#endif
+       std::string programFileName(buf);
+       auto slashIndex = programFileName.rfind(pathSepar);
+       if (std::string::npos != slashIndex)
+       {
+               // Extract the path
+               altPrefix = programFileName.substr(0, slashIndex + 1);
+#if defined(_DEBUG)
+               LogString msg1 = LOG4CXX_STR("Alternate prefix [");
+               helpers::Transcoder::decode(altPrefix, msg1);
+               msg1 += LOG4CXX_STR("]");
+               helpers::LogLog::debug(msg1);
+#endif
+               // Add a local directory relative name
+               result.push_back(programFileName.substr(slashIndex + 1));
+#if defined(_DEBUG)
+               LogString msg2(LOG4CXX_STR("Alternate configuration file name 
["));
+               helpers::Transcoder::decode(result.back(), msg2);
+               msg2 += LOG4CXX_STR("]");
+               helpers::LogLog::debug(msg2);
+#endif
+               // Add a local directory relative name without any extension
+               auto dotIndex = result.back().rfind('.');
+               if (std::string::npos != dotIndex)
+               {
+                       result.push_back(result.back());
+                       result.back().erase(dotIndex);
+#if defined(_DEBUG)
+                       LogString msg3(LOG4CXX_STR("Alternate configuration 
file name ["));
+                       helpers::Transcoder::decode(result.back(), msg3);
+                       msg3 += LOG4CXX_STR("]");
+                       helpers::LogLog::debug(msg3);
+#endif
+               }
+       }
+       else if (!programFileName.empty())
+       {
+               auto dotIndex = result.back().rfind('.');
+               if (std::string::npos != dotIndex)
+               {
+                       programFileName.erase(dotIndex);
+                       result.push_back(programFileName);
+#if defined(_DEBUG)
+                       LogString msg(LOG4CXX_STR("Alternate configuration file 
name ["));
+                       helpers::Transcoder::decode(result.back(), msg);
+                       msg += LOG4CXX_STR("]");
+                       helpers::LogLog::debug(msg);
+#endif
+               }
+       }
+       result.push_back("log4cxx");
+       result.push_back("log4j");
+       return result;
+}
+
+struct log4cxx_initializer
+{
+       log4cxx_initializer()
+       {
+#if defined(_DEBUG)
+               helpers::LogLog::setInternalDebugging(true);
+#endif
+               const char* extension[] = { ".xml", ".properties", 0 };
+               std::string altPrefix;
+               log4cxx::helpers::Pool pool;
+
+               for (auto baseName : DefaultConfigurationFileNames(altPrefix))
+               {
+                       int i = 0;
+                       for (; extension[i]; ++i)
+                       {
+                               log4cxx::File 
current_working_dir_candidate(baseName + extension[i]);
+                               if (current_working_dir_candidate.exists(pool))
+                               {
+                                       
log4cxx::DefaultConfigurator::setConfigurationFileName(current_working_dir_candidate.getPath());
+                                       
log4cxx::DefaultConfigurator::setConfigurationWatchSeconds(5);
+                                       break;
+                               }
+                               if (!altPrefix.empty())
+                               {
+                                       log4cxx::File 
alt_dir_candidate(altPrefix + baseName + extension[i]);
+                                       if (alt_dir_candidate.exists(pool))
+                                       {
+                                               
log4cxx::DefaultConfigurator::setConfigurationFileName(alt_dir_candidate.getPath());
+                                               
log4cxx::DefaultConfigurator::setConfigurationWatchSeconds(5);
+                                               break;
+                                       }
+                               }
+                       }
+                       if (extension[i]) // Found a configuration file?
+                               break;
+               }
+       }
+       ~log4cxx_initializer()
+       {
+               log4cxx::LogManager::shutdown();
+       }
+};
+
+} // namespace
+
+namespace UserLib
+{
+
+       log4cxx::LoggerPtr
+getLogger(const std::string& name)
+{
+       static log4cxx_initializer initAndShutdown;
+       return name.empty()
+               ? log4cxx::LogManager::getRootLogger()
+               : log4cxx::LogManager::getLogger(name);
+}
+
+} // namespace UserLib
diff --git a/src/examples/cpp/UserLib/logmanager.h 
b/src/examples/cpp/UserLib/logmanager.h
new file mode 100644
index 00000000..a23d7adc
--- /dev/null
+++ b/src/examples/cpp/UserLib/logmanager.h
@@ -0,0 +1,8 @@
+#include <log4cxx/logger.h>
+
+namespace UserLib
+{
+
+extern log4cxx::LoggerPtr getLogger(const std::string& name = std::string());
+
+} // namespace UserLib
diff --git a/src/examples/cpp/auto-configured.cpp 
b/src/examples/cpp/auto-configured.cpp
new file mode 100644
index 00000000..93333209
--- /dev/null
+++ b/src/examples/cpp/auto-configured.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 <UserLib/logmanager.h>
+
+       log4cxx::LoggerPtr
+rootLogger(UserLib::getLogger());
+
+struct ExampleStaticData
+{
+       ExampleStaticData()
+       {
+               LOG4CXX_DEBUG(rootLogger, "static initiallizer message");
+       }
+};
+
+static ExampleStaticData data;
+
+int main()
+{
+       int result = EXIT_SUCCESS;
+       LOG4CXX_INFO(rootLogger, "main function message");
+       return EXIT_SUCCESS;
+}
diff --git a/src/examples/cpp/auto-configured.xml 
b/src/examples/cpp/auto-configured.xml
new file mode 100644
index 00000000..77666bbc
--- /dev/null
+++ b/src/examples/cpp/auto-configured.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/";>
+  <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">
+    <param name="Target" value="System.out"/>
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss}] %c %-5p 
- %m%n"/>
+    </layout>
+  </appender>
+
+  <root>
+     <priority value="debug" />
+     <appender-ref ref="ConsoleAppender"/>
+  </root>
+
+</log4j:configuration>
diff --git a/src/main/cpp/defaultconfigurator.cpp 
b/src/main/cpp/defaultconfigurator.cpp
index db01845d..b7df7239 100644
--- a/src/main/cpp/defaultconfigurator.cpp
+++ b/src/main/cpp/defaultconfigurator.cpp
@@ -23,12 +23,11 @@
 #include <log4cxx/helpers/optionconverter.h>
 #include <log4cxx/helpers/stringhelper.h>
 
-
 using namespace log4cxx;
 using namespace log4cxx::spi;
 using namespace log4cxx::helpers;
 
-namespace 
+namespace
 {
        LogString DefaultConfiguratorPath;
        int DefaultConfiguratorWatchSeconds = 0;
@@ -112,7 +111,6 @@ void DefaultConfigurator::configure(LoggerRepositoryPtr 
repository)
 
 }
 
-
 const LogString DefaultConfigurator::getConfiguratorClass()
 {
 
diff --git a/src/main/include/log4cxx/defaultconfigurator.h 
b/src/main/include/log4cxx/defaultconfigurator.h
index 9c296b62..0825f2d7 100644
--- a/src/main/include/log4cxx/defaultconfigurator.h
+++ b/src/main/include/log4cxx/defaultconfigurator.h
@@ -38,14 +38,22 @@ class LOG4CXX_EXPORT DefaultConfigurator
                Configure \c repository.
 
                If the configuration file name has not been provided by a call 
to setConfigurationFileName(),
-               the environment variables 'LOG4CXX_CONFIGURATION' and 
'log4j.configuration' are examined.
+               the environment variables "LOG4CXX_CONFIGURATION" and 
"log4j.configuration" are examined.
+               Unless a custom configurator is specified using the
+               "LOG4CXX_CONFIGURATOR_CLASS" or "log4j.configuratorClass"
+               environment variable, the PropertyConfigurator will be used to
+               configure log4cxx unless the file name ends with the ".xml"
+               extension, in which case the DOMConfigurator will be used. If a
+               custom configurator is specified, the environment variable 
should
+               contain a fully qualified class name of a class that implements 
the
+               Configurator interface.
 
-               If the configuration file name has not been provided by any of 
the previous approaches
-               the current directory is examined for a file named either
-               "log4cxx.xml", "log4cxx.properties", "log4j.xml" or 
"log4j.properties".
+               If the configuration file name is not found using any of the 
previous approaches,
+               the current directory is examined for a file with extension 
".xml" or ".properties"
+               with a base name "log4cxx" or "log4j".
 
                If a positive number has been provided by a call to 
setConfigurationWatchSeconds()
-               or the environment variables 
'LOG4CXX_CONFIGURATION_WATCH_SECONDS' contains a positive number
+               or the environment variables 
"LOG4CXX_CONFIGURATION_WATCH_SECONDS" contains a positive number
                a background thread is started that will periodically check for 
a change to the configuration file
                and apply any configuration changes found.
                .*/
diff --git a/src/main/include/log4cxx/hierarchy.h 
b/src/main/include/log4cxx/hierarchy.h
index 1f3c55a4..058dfdfe 100644
--- a/src/main/include/log4cxx/hierarchy.h
+++ b/src/main/include/log4cxx/hierarchy.h
@@ -79,7 +79,7 @@ class LOG4CXX_EXPORT Hierarchy :
                void addHierarchyEventListener(const 
spi::HierarchyEventListenerPtr& listener) override;
 
                /**
-                * Load the configuration if not yet configured.
+                * Call DefaultConfigurator::configure if not yet configured.
                 */
                void autoConfigure() override;
 
@@ -128,10 +128,10 @@ class LOG4CXX_EXPORT Hierarchy :
                LevelPtr getThreshold() const override;
 
                /**
-               Return a new logger instance named as the first parameter using
-               the default factory.
+               Retrieve the \c name Logger instance using
+               the default factory to create it if required.
 
-               <p>If a logger of that name already exists, then it will be
+               If a logger of that name already exists, then it will be
                returned.  Otherwise, a new logger will be instantiated and
                then linked with its existing ancestors as well as children.
 
@@ -141,10 +141,10 @@ class LOG4CXX_EXPORT Hierarchy :
                LoggerPtr getLogger(const LogString& name) override;
 
                /**
-               Return a new logger instance named as the first parameter using
-               <code>factory</code>.
+               Retrieve the \c name Logger instance using
+               <code>factory</code> to create it if required.
 
-               <p>If a logger of that name already exists, then it will be
+               If a logger of that name already exists, then it will be
                returned.  Otherwise, a new logger will be instantiated by the
                <code>factory</code> parameter and linked with its existing
                ancestors as well as children.
diff --git a/src/main/include/log4cxx/logmanager.h 
b/src/main/include/log4cxx/logmanager.h
index d347f9aa..109ff98c 100644
--- a/src/main/include/log4cxx/logmanager.h
+++ b/src/main/include/log4cxx/logmanager.h
@@ -54,20 +54,20 @@ class LOG4CXX_EXPORT LogManager
 
        public:
                /**
-               Sets <code>LoggerFactory</code> but only if the correct
-               <em>guard</em> is passed as parameter.
+               Use \c selector to source the {@link spi::LoggerRepository 
LoggerRepository}, but only if the correct
+               \c guard is passed as parameter.
 
                <p>Initally the guard is null.  If the guard is
                <code>null</code>, then invoking this method sets the logger
                factory and the guard. Following invocations will throw a {@link
                helpers::IllegalArgumentException IllegalArgumentException},
-                       unless the previously set <code>guard</code> is passed 
as the second
-                       parameter.
+               unless the previously set \c guard is passed as the second
+               parameter.
 
                <p>This allows a high-level component to set the {@link
                spi::RepositorySelector RepositorySelector} used by the
-                       <code>LogManager</code>.
-                       */
+               LogManager.
+               */
 
                static void setRepositorySelector(spi::RepositorySelectorPtr 
selector,
                        void* guard);
@@ -75,117 +75,136 @@ class LOG4CXX_EXPORT LogManager
                static spi::LoggerRepositoryPtr getLoggerRepository();
 
                /**
-               Retrieve the appropriate root logger.
+               Retrieve the root logger from the {@link spi::LoggerRepository 
LoggerRepository}.
+
+               Call {@link spi::LoggerRepository::autoConfigure autoConfigure}
+               if the repository is not yet configured.
                */
                static LoggerPtr getRootLogger();
 
                /**
-               Retrieve the appropriate Logger instance.
-               * @param name logger name in current encoding.
-               * @return logger.
+               Retrieve the \c name Logger instance from the
+               {@link spi::LoggerRepository LoggerRepository}
+               using DefaultLoggerFactory to create it if required.
+
+               Call {@link spi::LoggerRepository::autoConfigure autoConfigure}
+               if the repository is not yet configured.
                */
                static LoggerPtr getLogger(const std::string& name);
+
                /**
-               Retrieve the appropriate Logger instance.
-               * @param name logger name in current encoding.
-               * @param factory logger factory.
-               * @return logger.
+               Retrieve the \c name Logger instance from the
+               {@link spi::LoggerRepository LoggerRepository}
+               using \c factory to create it if required.
+
+               Call {@link spi::LoggerRepository::autoConfigure autoConfigure}
+               if the repository is not yet configured.
                */
                static LoggerPtr getLogger(const std::string& name,
                        const spi::LoggerFactoryPtr& factory);
                /**
-                * Determines if logger name exists in the hierarchy.
-                * @param name logger name.
-                * @return true if logger exists.
+                Does the logger \c name exist in the hierarchy?
                 */
                static LoggerPtr exists(const std::string& name);
 #if LOG4CXX_WCHAR_T_API
                /**
-               Retrieve the appropriate Logger instance.
-               * @param name logger name.
-               * @return logger.
+               Retrieve the \c name Logger instance from the
+               {@link spi::LoggerRepository LoggerRepository}
+               using DefaultLoggerFactory to create it if required.
+
+               Call {@link spi::LoggerRepository::autoConfigure autoConfigure}
+               if the repository is not yet configured.
                */
                static LoggerPtr getLogger(const std::wstring& name);
                /**
-               Retrieve the appropriate Logger instance.
-               * @param name logger name.
-               * @param factory logger factory.
-               * @return logger.
+               Retrieve the \c name Logger instance from the
+               {@link spi::LoggerRepository LoggerRepository}
+               using \c factory to create it if required.
+
+               Call {@link spi::LoggerRepository::autoConfigure autoConfigure}
+               if the repository is not yet configured.
                */
                static LoggerPtr getLogger(const std::wstring& name,
                        const spi::LoggerFactoryPtr& factory);
                /**
-                * Determines if logger name exists in the hierarchy.
-                * @param name logger name.
-                * @return true if logger exists.
+                Does the logger \c name exist in the hierarchy?
                 */
                static LoggerPtr exists(const std::wstring& name);
 #endif
 #if LOG4CXX_UNICHAR_API
                /**
-               Retrieve the appropriate Logger instance.
-               * @param name logger name.
-               * @return logger.
+               Retrieve the \c name Logger instance from the
+               {@link spi::LoggerRepository LoggerRepository}
+               using DefaultLoggerFactory to create it if required.
+
+               Call {@link spi::LoggerRepository::autoConfigure autoConfigure}
+               if the repository is not yet configured.
                */
                static LoggerPtr getLogger(const std::basic_string<UniChar>& 
name);
                /**
-               Retrieve the appropriate Logger instance.
-               * @param name logger name.
-               * @param factory logger factory.
-               * @return logger.
+               Retrieve the \c name Logger instance from the
+               {@link spi::LoggerRepository LoggerRepository}
+               using \c factory to create it if required.
+
+               Call {@link spi::LoggerRepository::autoConfigure autoConfigure}
+               if the repository is not yet configured.
                */
                static LoggerPtr getLogger(const std::basic_string<UniChar>& 
name,
                        const spi::LoggerFactoryPtr& factory);
                /**
-                * Determines if logger name exists in the hierarchy.
-                * @param name logger name.
-                * @return true if logger exists.
+                Does the logger \c name exist in the hierarchy?
                 */
                static LoggerPtr exists(const std::basic_string<UniChar>& name);
 #endif
 #if LOG4CXX_CFSTRING_API
                /**
-               Retrieve the appropriate Logger instance.
-               * @param name logger name.
-               * @return logger.
+               Retrieve the \c name Logger instance from the
+               {@link spi::LoggerRepository LoggerRepository}
+               using DefaultLoggerFactory to create it if required.
+
+               Call {@link spi::LoggerRepository::autoConfigure autoConfigure}
+               if the repository is not yet configured.
                */
                static LoggerPtr getLogger(const CFStringRef& name);
                /**
-               Retrieve the appropriate Logger instance.
-               * @param name logger name.
-               * @param factory logger factory.
-               * @return logger.
+               Retrieve the \c name Logger instance from the
+               {@link spi::LoggerRepository LoggerRepository}
+               using \c factory to create it if required.
+
+               Call {@link spi::LoggerRepository::autoConfigure autoConfigure}
+               if the repository is not yet configured.
                */
                static LoggerPtr getLogger(const CFStringRef& name,
                        const spi::LoggerFactoryPtr& factory);
                /**
-                * Determines if logger name exists in the hierarchy.
-                * @param name logger name.
-                * @return true if logger exists.
+                Does the logger \c name exist in the hierarchy?
                 */
                static LoggerPtr exists(const CFStringRef& name);
 #endif
 
 
                /**
-               Retrieve the appropriate Logger instance.
-               * @param name logger name.
-               * @return logger.
+               Retrieve the \c name Logger instance from the
+               {@link spi::LoggerRepository LoggerRepository}
+               using DefaultLoggerFactory to create it if required.
+
+               Call {@link spi::LoggerRepository::autoConfigure autoConfigure}
+               if the repository is not yet configured.
                */
                static LoggerPtr getLoggerLS(const LogString& name);
                /**
-               Retrieve the appropriate Logger instance.
-               * @param name logger name.
-               * @param factory logger factory.
-               * @return logger.
+               Retrieve the \c name Logger instance from the
+               {@link spi::LoggerRepository LoggerRepository}
+               using \c factory to create it if required.
+
+               Call {@link spi::LoggerRepository::autoConfigure autoConfigure}
+               if the repository is not yet configured.
                */
                static LoggerPtr getLoggerLS(const LogString& name,
                        const spi::LoggerFactoryPtr& factory);
 
                /**
-                * Determines if logger name exists in the hierarchy.
-                * @param name logger name.
-                * @return true if logger exists.
+                Does the logger \c name exist in the hierarchy?
                 */
                static LoggerPtr existsLS(const LogString& name);
 
diff --git a/src/site/markdown/usage.md b/src/site/markdown/usage.md
index 232aa7c9..aefa0df1 100644
--- a/src/site/markdown/usage.md
+++ b/src/site/markdown/usage.md
@@ -301,7 +301,11 @@ additivity flag set to *false*, then *C*'s output will be 
directed to
 all the appenders in *C* and it's ancestors up to and including *P* but,
 not the appenders in any of the ancestors of *P*.  
   
-Loggers have their additivity flag set to *true* by default. 
+Loggers have their additivity flag set to *true* by default, 
+meaning output goes to the appender attached to a
+parent [Logger](@ref log4cxx.Logger).
+It is therefore often sufficient to configure or attach an appender
+only to the root logger in the [Hierarchy](@ref log4cxx.Hierarchy).
 
 The table below shows an
 example:
@@ -595,27 +599,21 @@ event to a second log4cxx server.
 # Default Initialization Procedure {#default-initialization-procedure}
 
 The log4cxx library does not make any assumptions about its environment.
-In particular, there are no default log4cxx appenders. Under certain
-well-defined circumstances however, the static inializer of the *Logger*
-class will attempt to automatically configure log4cxx. 
-
-The exact default initialization algorithm is defined as follows: 
-
-1.  Set the configurationOptionStr string variable to the value of the
-    **LOG4CXX\_CONFIGURATION** environment variable if set, otherwise
-    the value of the **log4j.configuration** environment variable if
-    set, otherwise the first of the following file names which exist in
-    the current working directory, "log4cxx.xml", "log4cxx.properties",
-    "log4j.xml" and "log4j.properties". If configurationOptionStr has
-    not been set, then disable logging. 
-2.  Unless a custom configurator is specified using the
-    **LOG4CXX\_CONFIGURATOR\_CLASS** or **log4j.configuratorClass**
-    environment variable, the PropertyConfigurator will be used to
-    configure log4cxx unless the file name ends with the ".xml"
-    extension, in which case the DOMConfigurator will be used. If a
-    custom configurator is specified, the environment variable should
-    contain a fully qualified class name of a class that implements the
-    Configurator interface. 
+In particular, when initially created the root [Logger](@ref log4cxx.Logger) 
has no appender.
+However the library will attempt automatic configuration.
+
+If the LoggerRepositoy is not yet configured on the first call to
+[getLogger](@ref log4cxx.LogManager.getLogger) of [LogManager](@ref 
log4cxx.LogManager),
+the [autoConfigure](@ref log4cxx.spi.LoggerRepository.autoConfigure) virtual 
method
+of [LoggerRepository](@ref log4cxx.spi.LoggerRepository) is called.
+
+The [default autoConfigure](@ref log4cxx.Hierarchy.autoConfigure) 
implementation
+calls the [configure](@ref log4cxx.DefaultConfigurator.configure) method
+of the [DefaultConfigurator](@ref log4cxx.DefaultConfigurator) class.
+
+To use automatic configuration with a non-standard file name
+create and use your own wrapper for [getLogger](@ref 
log4cxx.LogManager.getLogger).
+A full example can be seen in the src/examples/cpp/UserLib/logmanager.cpp file.
 
 # Nested Diagnostic Contexts {#nested-diagnostic-contexts}
 
@@ -697,20 +695,27 @@ The user should be aware of the following performance 
issues.
 
 1.  **Logging performance when logging is turned off.** 
     
-    When logging is turned off entirely or just for a set of levels, the
-    cost of a log request consists of a method invocation plus an
-    integer comparison. The LOG4CXX\_DEBUG and similar macros suppress
-    unnecessary expression evaluation if the request is not enabled. 
+    The LOG4CXX\_DEBUG and similar macros have a
+    cost of an in-lined null pointer check plus an integer comparison
+    when the logger not currently enabled for that level.
+    The other terms inside the macro are not evaluated.
+
+    When the level is enabled for a logger but the logging hierarchy is turned 
off
+    entirely or just for a set of levels, the cost of a log request consists
+    of a method invocation plus an integer comparison.
 
-2.  **The performance of deciding whether to log or not to log when
-    logging is turned on.** 
+2.  **Actually outputting log messages**
+
+    This is the cost of formatting the log output and sending it to its
+    target destination. Here again, a serious effort was made to make
+    layouts (formatters) perform as quickly as possible. The same is
+    true for appenders.
+
+3.  **The cost of changing a logger's level.**
     
-    This is essentially the performance of walking the logger hierarchy.
-    When logging is turned on, log4cxx still needs to compare the level
-    of the log request with the level of the request logger. However,
-    loggers may not have an assigned level; they can inherit them from
-    the logger hierarchy. Thus, before inheriting a level, the logger
-    may need to search its ancestors. 
+    The threshold value stored in any child logger is updated.
+    This is done iterating over the map of all known logger objects
+    and walking the hierarchy of each.
     
     There has been a serious effort to make this hierarchy walk to be as
     fast as possible. For example, child loggers link only to their
@@ -719,16 +724,6 @@ The user should be aware of the following performance 
issues.
     root logger, thereby circumventing the nonexistent *com* or
     *com.foo* loggers. This significantly improves the speed of the
     walk, especially in "sparse" hierarchies. 
-    
-    The cost of walking the hierarchy is typically 3 times slower than
-    when logging is turned off entirely. 
-
-3.  **Actually outputting log messages** 
-    
-    This is the cost of formatting the log output and sending it to its
-    target destination. Here again, a serious effort was made to make
-    layouts (formatters) perform as quickly as possible. The same is
-    true for appenders. 
 
 # Removing log statements {#removing-log-statements}
 
diff --git a/src/test/cpp/CMakeLists.txt b/src/test/cpp/CMakeLists.txt
index 0189b583..0e9cad93 100644
--- a/src/test/cpp/CMakeLists.txt
+++ b/src/test/cpp/CMakeLists.txt
@@ -82,29 +82,9 @@ add_subdirectory(xml)
 add_subdirectory(throughput)
 add_subdirectory(benchmark)
 
-# Note: we need to include the APR DLLs on our path so that the tests will run.
-# The way that CMake sets the environment is that it actually generates a 
secondary file,
-# CTestTestfile.cmake, which sets the final properties of the test.
-# However, this results in a secondary quirk to the running of the tests: 
CMake uses
-# a semicolon to deliminate entries in a list!  Since the Windows PATH is 
semicolon-delimited
-# as well, CMake uses only the first entry in the list when setting the path.
-# So, we need to do a triple escape on the PATH that we want to set in order 
for CMake to
-# properly interpret the PATH
 if( WIN32 )
-  get_filename_component(APR_DLL_DIR "${APR_DLL}" DIRECTORY)
-  get_filename_component(APR_UTIL_DLL_DIR "${APR_UTIL_DLL}" DIRECTORY)
-  get_filename_component(EXPAT_LIB_DIR "${EXPAT_LIBRARY}" DIRECTORY)
-
-
-  set(EXPAT_DLL_DIR "${EXPAT_LIB_DIR}/../bin")
-  set(LOG4CXX_DLL_DIR "$<SHELL_PATH:$<TARGET_FILE_DIR:log4cxx>>;")
-  set(PATH_FOR_TESTS 
${CMAKE_PROGRAM_PATH};${APR_DLL_DIR};${APR_UTIL_DLL_DIR};${LOG4CXX_DLL_DIR};${EXPAT_DLL_DIR}\;)
-  list(REMOVE_DUPLICATES PATH_FOR_TESTS)
-  set(NORMAL_PATH $ENV{PATH})
-  set(ESCAPED_PATH "")
-  foreach( ENTRY ${PATH_FOR_TESTS}${NORMAL_PATH} )
-         set(ESCAPED_PATH "${ESCAPED_PATH}${ENTRY}\\\;")
-  endforeach()
+  include(win32_target_environment_path)
+  get_target_environment_path(ESCAPED_PATH)
 elseif(CMAKE_BUILD_TYPE)
   string(TOUPPER ${CMAKE_BUILD_TYPE} UPPER_BUILD_TYPE)
   if (UPPER_BUILD_TYPE STREQUAL "DEBUG")
diff --git a/src/test/cpp/autoconfiguretestcase.cpp 
b/src/test/cpp/autoconfiguretestcase.cpp
index 629ef630..e486727e 100644
--- a/src/test/cpp/autoconfiguretestcase.cpp
+++ b/src/test/cpp/autoconfiguretestcase.cpp
@@ -70,7 +70,7 @@ LOGUNIT_CLASS(AutoConfigureTestCase)
 #endif
        helpers::Pool m_pool;
        char m_buf[2048];
-       LogString m_configFile = LOG4CXX_STR("autoConfigureTest.properties");
+       LogString m_configFile = 
LOG4CXX_STR("autoconfiguretestcase.properties");
 public:
 
        void copyPropertyFile()
@@ -78,7 +78,7 @@ public:
                
LOGUNIT_ASSERT(File(LOG4CXX_STR("input/autoConfigureTest.properties")).exists(m_pool));
                LOGUNIT_ASSERT(apr_file_copy
                        ( "input/autoConfigureTest.properties"
-                       , "autoConfigureTest.properties"
+                       , "autoconfiguretestcase.properties"
                        , APR_FPROT_UREAD | APR_FPROT_UWRITE
                        , m_pool.getAPRPool()
                        ) == APR_SUCCESS);
@@ -91,7 +91,7 @@ public:
        void shutdown()
        {
                LogManager::shutdown();
-               LOGUNIT_ASSERT(apr_file_remove("autoConfigureTest.properties", 
m_pool.getAPRPool()) == APR_SUCCESS);
+               
LOGUNIT_ASSERT(apr_file_remove("autoconfiguretestcase.properties", 
m_pool.getAPRPool()) == APR_SUCCESS);
        }
 
        void test1()    


Reply via email to