This is an automated email from the ASF dual-hosted git repository. swebb2066 pushed a commit to branch make_default_configuration_useful in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git
commit b0bc0617d948acbde06c7c704c2eb3b094c3e7c1 Author: Stephen Webb <[email protected]> AuthorDate: Fri Aug 15 14:21:04 2025 +1000 Add support for programmatically providing runtime values for configuration option values --- src/examples/cpp/CMakeLists.txt | 2 +- src/examples/cpp/com/foo/config4.cpp | 62 ++++++++++++++++++++ .../cpp/com/foo/product_version.h} | 20 ++----- src/main/cpp/configurator.cpp | 29 ++++++++++ src/main/cpp/defaultconfigurator.cpp | 67 +++++++++++----------- src/main/cpp/domconfigurator.cpp | 2 +- src/main/cpp/optionconverter.cpp | 2 +- src/main/cpp/properties.cpp | 16 ++++++ src/main/cpp/propertyconfigurator.cpp | 2 +- src/main/cpp/system.cpp | 60 +++++++++++++++++++ src/main/include/log4cxx/defaultconfigurator.h | 26 +++++++-- .../log4cxx/helpers/filesystempath.h} | 28 ++++----- src/main/include/log4cxx/helpers/properties.h | 14 ++++- src/main/include/log4cxx/helpers/system.h | 23 ++++++-- src/main/include/log4cxx/spi/configurator.h | 19 ++++++ src/site/markdown/example-programs.md | 5 +- 16 files changed, 298 insertions(+), 79 deletions(-) diff --git a/src/examples/cpp/CMakeLists.txt b/src/examples/cpp/CMakeLists.txt index e2487c25..983bb748 100644 --- a/src/examples/cpp/CMakeLists.txt +++ b/src/examples/cpp/CMakeLists.txt @@ -46,7 +46,7 @@ foreach(exampleName IN LISTS ALL_LOG4CXX_EXAMPLES) target_link_libraries(${PROGRAM_NAME} PRIVATE log4cxx-qt) endif() if(${exampleName} STREQUAL auto-configured) - target_sources(${PROGRAM_NAME} PRIVATE com/foo/config3.cpp ) + target_sources(${PROGRAM_NAME} PRIVATE com/foo/config4.cpp ) endif() target_compile_definitions(${PROGRAM_NAME} PRIVATE ${EXAMPLE_COMPILE_DEFINITIONS} ${LOG4CXX_COMPILE_DEFINITIONS} ${APR_COMPILE_DEFINITIONS} ${APR_UTIL_COMPILE_DEFINITIONS} ) target_include_directories(${PROGRAM_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR} $<TARGET_PROPERTY:log4cxx,INCLUDE_DIRECTORIES>) diff --git a/src/examples/cpp/com/foo/config4.cpp b/src/examples/cpp/com/foo/config4.cpp new file mode 100644 index 00000000..26f79aef --- /dev/null +++ b/src/examples/cpp/com/foo/config4.cpp @@ -0,0 +1,62 @@ +/* + * 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 "config.h" +#include "product_version.h" +#include <log4cxx/logmanager.h> +#include <log4cxx/defaultconfigurator.h> +#include <log4cxx/basicconfigurator.h> +#include <log4cxx/helpers/transcoder.h> + +namespace com { namespace foo { + +// Retrieve the \c name logger pointer. +// Configure Log4cxx on the first call. +auto getLogger(const std::string& name) -> LoggerPtr { + using namespace log4cxx; + static struct log4cxx_initializer { + log4cxx_initializer() { + auto vendorFolder = getVendorFolder(); + auto productFolder = getProductFolder(); + LOG4CXX_DECODE_CHAR(lsVendorFolder, vendorFolder); + LOG4CXX_DECODE_CHAR(lsProductFolder, productFolder); + + // Allow expansion of ${CURRENT_VENDOR_FOLDER} and ${CURRENT_PRODUCT_FOLDER} + // when loading a configuration from a file + auto& props = spi::Configurator::configurationProperties(); + props.setProperty(LOG4CXX_STR("CURRENT_VENDOR_FOLDER"), lsVendorFolder); + props.setProperty(LOG4CXX_STR("CURRENT_PRODUCT_FOLDER"), lsProductFolder); + + // Use a configuration file in the current working directory + DefaultConfigurator::setConfigurationFileName(LOG4CXX_STR("${PROGRAM_FILE_PATH.STEM}.xml")); + if (DefaultConfigurator::tryConfigure() == spi::ConfigurationStatus::NotConfigured) + { + // Use a configuration file in the same directory as the program + DefaultConfigurator::setConfigurationFileName(LOG4CXX_STR("${PROGRAM_FILE_PATH.PARENT_PATH}/${PROGRAM_FILE_PATH.STEM}.xml")); + if (DefaultConfigurator::tryConfigure() == spi::ConfigurationStatus::NotConfigured) + BasicConfigurator::configure(); // Send events to the console + } + } + ~log4cxx_initializer() { + LogManager::shutdown(); + } + } initialiser; + return name.empty() + ? LogManager::getRootLogger() + : LogManager::getLogger(name); +} + +} } // namespace com::foo diff --git a/src/main/cpp/configurator.cpp b/src/examples/cpp/com/foo/product_version.h similarity index 76% copy from src/main/cpp/configurator.cpp copy to src/examples/cpp/com/foo/product_version.h index 26fa1461..56c51221 100644 --- a/src/main/cpp/configurator.cpp +++ b/src/examples/cpp/com/foo/product_version.h @@ -15,19 +15,11 @@ * limitations under the License. */ -#include <log4cxx/logstring.h> -#include <log4cxx/spi/configurator.h> -#include <assert.h> -#include <log4cxx/logger.h> - -using namespace LOG4CXX_NS; -using namespace LOG4CXX_NS::spi; - -IMPLEMENT_LOG4CXX_OBJECT(Configurator) - - - - -Configurator::Configurator() +std::string getVendorFolder() +{ + return "ApacheSoftwareFoundation"; +} +std::string getProductFolder() { + return "Logging"; } diff --git a/src/main/cpp/configurator.cpp b/src/main/cpp/configurator.cpp index 26fa1461..c1603ecd 100644 --- a/src/main/cpp/configurator.cpp +++ b/src/main/cpp/configurator.cpp @@ -19,6 +19,13 @@ #include <log4cxx/spi/configurator.h> #include <assert.h> #include <log4cxx/logger.h> +#include <log4cxx/helpers/singletonholder.h> +#include <log4cxx/helpers/system.h> + +#if !defined(LOG4CXX) + #define LOG4CXX 1 +#endif +#include <log4cxx/helpers/aprinitializer.h> using namespace LOG4CXX_NS; using namespace LOG4CXX_NS::spi; @@ -26,8 +33,30 @@ using namespace LOG4CXX_NS::spi; IMPLEMENT_LOG4CXX_OBJECT(Configurator) +namespace +{ + struct ConfiguratorTag {}; + using ConfiguratorProperties = std::pair<ConfiguratorTag, helpers::Properties>; + ConfiguratorProperties& getInstance() + { + using ConfiguratorObject = helpers::SingletonHolder<ConfiguratorProperties>; + auto result = helpers::APRInitializer::getOrAddUnique<ConfiguratorObject> + ( []() -> helpers::ObjectPtr + { return std::make_shared<ConfiguratorObject>(); } + ); + return result->value(); + } +} Configurator::Configurator() { } + +helpers::Properties& Configurator::configurationProperties() +{ + auto& result = getInstance().second; + if (result.isEmpty()) + helpers::System::addProgramFilePathComponents(result); + return result; +} diff --git a/src/main/cpp/defaultconfigurator.cpp b/src/main/cpp/defaultconfigurator.cpp index 646d50e3..8daac617 100644 --- a/src/main/cpp/defaultconfigurator.cpp +++ b/src/main/cpp/defaultconfigurator.cpp @@ -16,46 +16,53 @@ */ #include <log4cxx/logstring.h> #include <log4cxx/defaultconfigurator.h> +#include <log4cxx/logmanager.h> #include <log4cxx/helpers/pool.h> #include <log4cxx/spi/loggerrepository.h> #include <log4cxx/file.h> #include <log4cxx/helpers/loglog.h> #include <log4cxx/helpers/optionconverter.h> #include <log4cxx/helpers/stringhelper.h> +#include <log4cxx/helpers/system.h> #include <log4cxx/xml/domconfigurator.h> #include <log4cxx/propertyconfigurator.h> + using namespace LOG4CXX_NS; using namespace LOG4CXX_NS::spi; using namespace LOG4CXX_NS::helpers; namespace { - LogString DefaultConfiguratorPath; - int DefaultConfiguratorWatchSeconds = 0; + const LogString CONFIGURATION_FILE_KEY{ LOG4CXX_STR("LOG4CXX_CONFIGURATION") }; + const LogString WATCH_SECONDS_KEY{ LOG4CXX_STR("LOG4CXX_CONFIGURATION_WATCH_SECONDS") }; + const LogString CONFIGURATOR_CLASS_KEY{ LOG4CXX_STR("LOG4CXX_CONFIGURATOR_CLASS") }; } void DefaultConfigurator::setConfigurationFileName(const LogString& path) { - DefaultConfiguratorPath = path; + Configurator::configurationProperties().setProperty(CONFIGURATION_FILE_KEY, path); } - void DefaultConfigurator::setConfigurationWatchSeconds(int seconds) { - DefaultConfiguratorWatchSeconds = seconds; + Pool p; + LogString strSeconds; + StringHelper::toString(seconds, p, strSeconds); + Configurator::configurationProperties().setProperty(WATCH_SECONDS_KEY, strSeconds); } -static const int MillisecondsPerSecond = 1000; +spi::ConfigurationStatus DefaultConfigurator::tryConfigure() +{ + auto r = LogManager::getLoggerRepository(); + configure(r); + return r->isConfigured() ? spi::ConfigurationStatus::Configured : spi::ConfigurationStatus::NotConfigured; +} void DefaultConfigurator::configure(LoggerRepositoryPtr repository) { - repository->setConfigured(true); - const LogString configuratorClassName(getConfiguratorClass()); - LogString configurationFileName = DefaultConfiguratorPath; - if (configurationFileName.empty()) - configurationFileName = getConfigurationFileName(); + LogString configurationFileName = getConfigurationFileName(); Pool pool; File configuration; @@ -92,6 +99,7 @@ void DefaultConfigurator::configure(LoggerRepositoryPtr repository) if (configuration.exists(pool)) { + repository->setConfigured(true); if (LogLog::isDebugEnabled()) { LogString msg(LOG4CXX_STR("Using configuration file [")); @@ -103,12 +111,11 @@ void DefaultConfigurator::configure(LoggerRepositoryPtr repository) LoggerRepositoryPtr repo(repository); OptionConverter::selectAndConfigure( configuration, - configuratorClassName, + getConfiguratorClass(), repo, - 0 < DefaultConfiguratorWatchSeconds - ? DefaultConfiguratorWatchSeconds * MillisecondsPerSecond - : getConfigurationWatchDelay() + getConfigurationWatchDelay() ); + // TBD: Report a failure } else if (LogLog::isDebugEnabled()) { @@ -129,37 +136,31 @@ void DefaultConfigurator::configure(LoggerRepositoryPtr repository) const LogString DefaultConfigurator::getConfiguratorClass() { - - // Use automatic configration to configure the default hierarchy - const LogString log4jConfiguratorClassName( - OptionConverter::getSystemProperty(LOG4CXX_STR("log4j.configuratorClass"), LOG4CXX_STR(""))); - const LogString configuratorClassName( - OptionConverter::getSystemProperty(LOG4CXX_STR("LOG4CXX_CONFIGURATOR_CLASS"), - log4jConfiguratorClassName)); - return configuratorClassName; + return System::getProperty(CONFIGURATOR_CLASS_KEY); } const LogString DefaultConfigurator::getConfigurationFileName() { - static const WideLife<LogString> LOG4CXX_DEFAULT_CONFIGURATION_KEY(LOG4CXX_STR("LOG4CXX_CONFIGURATION")); - static const WideLife<LogString> LOG4J_DEFAULT_CONFIGURATION_KEY(LOG4CXX_STR("log4j.configuration")); - const LogString log4jConfigurationFileName( - OptionConverter::getSystemProperty(LOG4J_DEFAULT_CONFIGURATION_KEY, LOG4CXX_STR(""))); - const LogString configurationFileName( - OptionConverter::getSystemProperty(LOG4CXX_DEFAULT_CONFIGURATION_KEY, - log4jConfigurationFileName)); - return configurationFileName; + auto& props = Configurator::configurationProperties(); + LogString configurationFileName = props.getProperty(CONFIGURATION_FILE_KEY); + if (configurationFileName.empty()) + configurationFileName = System::getProperty(CONFIGURATION_FILE_KEY); + return OptionConverter::substVars(configurationFileName, props); } int DefaultConfigurator::getConfigurationWatchDelay() { - static const WideLife<LogString> LOG4CXX_DEFAULT_CONFIGURATION_WATCH_KEY(LOG4CXX_STR("LOG4CXX_CONFIGURATION_WATCH_SECONDS")); - LogString optionStr = OptionConverter::getSystemProperty(LOG4CXX_DEFAULT_CONFIGURATION_WATCH_KEY, LogString()); + LogString optionStr = Configurator::configurationProperties().getProperty(WATCH_SECONDS_KEY); + if (optionStr.empty()) + optionStr = System::getProperty(WATCH_SECONDS_KEY); int milliseconds = 0; if (!optionStr.empty()) + { + static const int MillisecondsPerSecond = 1000; milliseconds = StringHelper::toInt(optionStr) * MillisecondsPerSecond; + } return milliseconds; } diff --git a/src/main/cpp/domconfigurator.cpp b/src/main/cpp/domconfigurator.cpp index ac448574..6cf90f4a 100644 --- a/src/main/cpp/domconfigurator.cpp +++ b/src/main/cpp/domconfigurator.cpp @@ -65,7 +65,7 @@ using namespace LOG4CXX_NS::rolling; struct DOMConfigurator::DOMConfiguratorPrivate { - helpers::Properties props; + helpers::Properties props = Configurator::configurationProperties(); spi::LoggerRepositoryPtr repository; spi::LoggerFactoryPtr loggerFactory; }; diff --git a/src/main/cpp/optionconverter.cpp b/src/main/cpp/optionconverter.cpp index f70baef3..178e2437 100644 --- a/src/main/cpp/optionconverter.cpp +++ b/src/main/cpp/optionconverter.cpp @@ -228,7 +228,7 @@ LogString OptionConverter::findAndSubst(const LogString& key, Properties& props) LogString OptionConverter::substVars(const LogString& val, Properties& props) { LogString sbuf; - const logchar delimStartArray[] = { 0x24, 0x7B, 0 }; + const logchar delimStartArray[] = { 0x24, 0x7B, 0 }; // '$', '{' const LogString delimStart(delimStartArray); const logchar delimStop = 0x7D; // '}'; const size_t DELIM_START_LEN = 2; diff --git a/src/main/cpp/properties.cpp b/src/main/cpp/properties.cpp index 2c06b0ff..dfa72f83 100644 --- a/src/main/cpp/properties.cpp +++ b/src/main/cpp/properties.cpp @@ -399,6 +399,18 @@ Properties::Properties() : properties(new PropertyMap()) { } +Properties::Properties(const Properties& other) + : properties(new PropertyMap(*other.properties)) +{ +} + +Properties& Properties::operator=(const Properties& other) +{ + delete this->properties; + this->properties = new PropertyMap(*other.properties); + return *this; +} + Properties::~Properties() { delete properties; @@ -451,3 +463,7 @@ std::vector<LogString> Properties::propertyNames() const return names; } +bool Properties::isEmpty() const +{ + return properties->empty(); +} \ No newline at end of file diff --git a/src/main/cpp/propertyconfigurator.cpp b/src/main/cpp/propertyconfigurator.cpp index 9586a13b..2b56686b 100644 --- a/src/main/cpp/propertyconfigurator.cpp +++ b/src/main/cpp/propertyconfigurator.cpp @@ -113,7 +113,7 @@ spi::ConfigurationStatus PropertyConfigurator::doConfigure auto hierarchy = repository ? repository : LogManager::getLoggerRepository(); hierarchy->setConfigured(true); - Properties props; + Properties props = Configurator::configurationProperties(); try { diff --git a/src/main/cpp/system.cpp b/src/main/cpp/system.cpp index ad4a75f6..ad0ecfc9 100644 --- a/src/main/cpp/system.cpp +++ b/src/main/cpp/system.cpp @@ -17,13 +17,24 @@ #include <log4cxx/logstring.h> #include <log4cxx/helpers/system.h> +#include <log4cxx/helpers/filesystempath.h> #include <log4cxx/helpers/transcoder.h> #include <log4cxx/helpers/pool.h> +#include <log4cxx/helpers/properties.h> +#include <log4cxx/helpers/loglog.h> #include <apr_file_io.h> #include <apr_user.h> #include <apr_env.h> +#ifdef _WIN32 +#include <windows.h> +#elif __APPLE__ +#include <mach-o/dyld.h> +#elif (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 500) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) +#include <unistd.h> // getpid +#endif +#include <sstream> using namespace LOG4CXX_NS; using namespace LOG4CXX_NS::helpers; @@ -120,3 +131,52 @@ LogString System::getProperty(const LogString& lkey) return rv; } +void System::addProgramFilePathComponents(Properties& props) +{ + // 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); +#elif (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 500) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) + std::ostringstream exeLink; + exeLink << "/proc/" << getpid() << "/exe"; + bufCount = readlink(exeLink.str().c_str(), buf, bufSize); + if (0 < bufCount) + buf[bufCount] = 0; +#else + return; +#endif + + // Add the path to the properties + std::string programFileName(buf); + LOG4CXX_DECODE_CHAR(lsProgramFileName, programFileName); + LogString prefix{ LOG4CXX_STR("PROGRAM_FILE_PATH") }; + props.setProperty(prefix, lsProgramFileName); + +#if LOG4CXX_HAS_FILESYSTEM_PATH + // Add the path components to the properties + prefix += '.'; + Path programPath(programFileName); + LOG4CXX_DECODE_CHAR(root_name, programPath.root_name().string()); + props.setProperty(prefix + LOG4CXX_STR("ROOT_NAME"), root_name); + LOG4CXX_DECODE_CHAR(root_directory, programPath.root_directory().string()); + props.setProperty(LOG4CXX_STR("ROOT_DIRECTORY"),root_directory); + LOG4CXX_DECODE_CHAR(root_path, programPath.root_path().string()); + props.setProperty(prefix + LOG4CXX_STR("ROOT_PATH"), root_path); + LOG4CXX_DECODE_CHAR(relative_path, programPath.relative_path().string()); + props.setProperty(prefix + LOG4CXX_STR("RELATIVE_PATH"), relative_path); + LOG4CXX_DECODE_CHAR(parent_path, programPath.parent_path().string()); + props.setProperty(prefix + LOG4CXX_STR("PARENT_PATH"), parent_path); + LOG4CXX_DECODE_CHAR(filename, programPath.filename().string()); + props.setProperty(prefix + LOG4CXX_STR("FILENAME"), filename); + LOG4CXX_DECODE_CHAR(stem, programPath.stem().string()); + props.setProperty(prefix + LOG4CXX_STR("STEM"), stem); + LOG4CXX_DECODE_CHAR(extension, programPath.extension().string()); + props.setProperty(prefix + LOG4CXX_STR("EXTENSION"), extension); +#endif +} diff --git a/src/main/include/log4cxx/defaultconfigurator.h b/src/main/include/log4cxx/defaultconfigurator.h index dabe9b1a..f6ff2393 100644 --- a/src/main/include/log4cxx/defaultconfigurator.h +++ b/src/main/include/log4cxx/defaultconfigurator.h @@ -36,12 +36,15 @@ class LOG4CXX_EXPORT DefaultConfigurator public: /** - Configure \c repository. + Configure the default 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 variable "LOG4CXX_CONFIGURATION" value is used, + with ${varname} instances expanded using the helpers::Properties object + provided by DefaultConfigurator::configurationProperties(). + Unless a custom configurator is specified using the - "LOG4CXX_CONFIGURATOR_CLASS" or "log4j.configuratorClass" + "LOG4CXX_CONFIGURATOR_CLASS" 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 @@ -58,10 +61,19 @@ class LOG4CXX_EXPORT DefaultConfigurator a background thread is started that will periodically check for a change to the configuration file and apply any configuration changes found. */ + static spi::ConfigurationStatus tryConfigure(); + + /** + Configure \c repository. + */ static void configure(spi::LoggerRepositoryPtr repository); /** Make \c path the configuration file used by configure(). + + Any ${varname} instances in the \c path value are expanded + using either a system environment variable value (if found) + otherwise using the map provided by Configurator::configurationProperties. */ static void setConfigurationFileName(const LogString& path); @@ -96,14 +108,16 @@ class LOG4CXX_EXPORT DefaultConfigurator * @param filenames The names of the files to look for * @return The status of the configuration, and the filename loaded(if a file was found). */ - static std::tuple<LOG4CXX_NS::spi::ConfigurationStatus,LogString> configureFromFile(const std::vector<LogString>& directories, - const std::vector<LogString>& filenames); + static std::tuple<spi::ConfigurationStatus,LogString> configureFromFile + ( const std::vector<LogString>& directories + , const std::vector<LogString>& filenames + ); private: static const LogString getConfigurationFileName(); static const LogString getConfiguratorClass(); static int getConfigurationWatchDelay(); - static LOG4CXX_NS::spi::ConfigurationStatus tryLoadFile(const LogString& filename); + static spi::ConfigurationStatus tryLoadFile(const LogString& filename); }; // class DefaultConfigurator } // namespace log4cxx diff --git a/src/main/cpp/configurator.cpp b/src/main/include/log4cxx/helpers/filesystempath.h similarity index 56% copy from src/main/cpp/configurator.cpp copy to src/main/include/log4cxx/helpers/filesystempath.h index 26fa1461..b09eaa88 100644 --- a/src/main/cpp/configurator.cpp +++ b/src/main/include/log4cxx/helpers/filesystempath.h @@ -15,19 +15,19 @@ * limitations under the License. */ -#include <log4cxx/logstring.h> -#include <log4cxx/spi/configurator.h> -#include <assert.h> -#include <log4cxx/logger.h> +#ifndef LOG4CXX_FILE_SYSTEM_PATH_HDR_ +#define LOG4CXX_FILE_SYSTEM_PATH_HDR_ -using namespace LOG4CXX_NS; -using namespace LOG4CXX_NS::spi; +#ifdef __has_include // Check if __has_include is present +# if __has_include(<filesystem>) // Check for a standard version +# include <filesystem> +# if defined(__cpp_lib_filesystem) // C++ >= 17 +namespace LOG4CXX_NS { using Path = std::filesystem::path; } +#define LOG4CXX_HAS_FILESYSTEM_PATH 1 +# endif +# else // Not found at all +#define LOG4CXX_HAS_FILESYSTEM_PATH 0 +# endif +#endif // __has_include -IMPLEMENT_LOG4CXX_OBJECT(Configurator) - - - - -Configurator::Configurator() -{ -} +#endif /* LOG4CXX_FILE_SYSTEM_PATH_HDR_ */ diff --git a/src/main/include/log4cxx/helpers/properties.h b/src/main/include/log4cxx/helpers/properties.h index 7992e841..1481d2cc 100644 --- a/src/main/include/log4cxx/helpers/properties.h +++ b/src/main/include/log4cxx/helpers/properties.h @@ -34,18 +34,26 @@ class LOG4CXX_EXPORT Properties private: typedef std::map<LogString, LogString> PropertyMap; PropertyMap* properties; - Properties(const Properties&); - Properties& operator=(const Properties&); - public: + public: // ...structors /** * Create new instance. */ Properties(); + Properties(const Properties&); + Properties(const Properties&&) = delete; + Properties& operator=(const Properties&); + Properties& operator=(const Properties&&) = delete; /** * Destructor. */ ~Properties(); + + public: // Methods + /** Does this contain any key-value pairs? + */ + bool isEmpty() const; + /** Reads a property list (key and element pairs) from the input stream. The stream is assumed to be using the ISO 8859-1 character encoding. diff --git a/src/main/include/log4cxx/helpers/system.h b/src/main/include/log4cxx/helpers/system.h index 37381b7b..5c0ba3c9 100644 --- a/src/main/include/log4cxx/helpers/system.h +++ b/src/main/include/log4cxx/helpers/system.h @@ -34,18 +34,33 @@ class LOG4CXX_EXPORT System { public: + /** - Gets the system property indicated by the specified key. + Add to \c props the currently executing program file path + and the [std::filesystem::path](https://en.cppreference.com/w/cpp/filesystem/path.html) + decomposition of the currently executing program file path, using the variable names: + - PROGRAM_FILE_PATH + - PROGRAM_FILE_PATH.ROOT_NAME + - PROGRAM_FILE_PATH.ROOT_DIRECTORY + - PROGRAM_FILE_PATH.ROOT_PATH + - PROGRAM_FILE_PATH.RELATIVE_PATH + - PROGRAM_FILE_PATH.PARENT_PATH + - PROGRAM_FILE_PATH.FILENAME + - PROGRAM_FILE_PATH.STEM + - PROGRAM_FILE_PATH.EXTENSION + */ + static void addProgramFilePathComponents(Properties& props); + + /** + The value of the system property associated with \c key. @param key the name of the system property. - @return the string value of the system property, or the default value if - there is no property with that key. + @return the string value of the system property. @throws IllegalArgumentException if key is empty. */ static LogString getProperty(const LogString& key); - }; } // namespace helpers } // namespace log4cxx diff --git a/src/main/include/log4cxx/spi/configurator.h b/src/main/include/log4cxx/spi/configurator.h index d4dae180..a0199eb4 100644 --- a/src/main/include/log4cxx/spi/configurator.h +++ b/src/main/include/log4cxx/spi/configurator.h @@ -19,6 +19,7 @@ #define _LOG4CXX_SPI_CONFIGURATOR_H #include <log4cxx/spi/loggerrepository.h> +#include <log4cxx/helpers/properties.h> namespace LOG4CXX_NS { @@ -63,6 +64,24 @@ class LOG4CXX_EXPORT Configurator : virtual public helpers::Object #endif ) = 0; + /** + The key value pairs used when expanding ${varname} instances in a configuration file. + + By default, the map holds the currently executing program file path + and the [std::filesystem::path](https://en.cppreference.com/w/cpp/filesystem/path.html) + decomposition of the currently executing program file path, using the variable names: + - ${PROGRAM_FILE_PATH} + - ${PROGRAM_FILE_PATH.ROOT_NAME} + - ${PROGRAM_FILE_PATH.ROOT_DIRECTORY} + - ${PROGRAM_FILE_PATH.ROOT_PATH} + - ${PROGRAM_FILE_PATH.RELATIVE_PATH} + - ${PROGRAM_FILE_PATH.PARENT_PATH} + - ${PROGRAM_FILE_PATH.FILENAME} + - ${PROGRAM_FILE_PATH.STEM} + - ${PROGRAM_FILE_PATH.EXTENSION} + */ + static helpers::Properties& configurationProperties(); + protected: Configurator(); diff --git a/src/site/markdown/example-programs.md b/src/site/markdown/example-programs.md index 72992d80..5ad3d527 100644 --- a/src/site/markdown/example-programs.md +++ b/src/site/markdown/example-programs.md @@ -115,7 +115,7 @@ This version of *config.cpp* instructs [PropertyConfigurator](@ref log4cxx.Prope to use the *MyApp.properties* file to configure Log4cxx. A more realistic approach would (for example) use the current module name to select the configuration file -(see the \ref com/foo/config3.cpp file for how to do this). +(see the \ref com/foo/config4.cpp file for how to do this). Here is a sample *MyApp.properties* configuration file that results in exactly same output as the previous [BasicConfigurator::configure](@ref log4cxx.BasicConfigurator.configure) based example. @@ -196,3 +196,6 @@ This file is a simplified example of encapsulated Log4cxx configuration. \example com/foo/config3.cpp This file is an example of how to use the current module name to select the Log4cxx configuration file. + +\example com/foo/config4.cpp +This file is a simpler example of how to use the current module name to select the Log4cxx configuration file. \ No newline at end of file
