From 52342533333e7a92656c3116ec70721a8e236c15 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Tue, 29 Dec 2015 11:07:41 -0800 Subject: [PATCH 1/4] Added max_files option to text_file_backend's file_collector As requested here: https://svn.boost.org/trac/boost/ticket/8746 this commit introduces the boost::log::keywords::max_files keyword and implements this functionality in the file collector. Additionally, the non-keyword make_collector call has max_files added as a uintmax_t parameter, which has a default value as to not break existing code. The purpose of this is to limit the total number of files in the collected logs. If not specified, the limit will be std::numeric_limits::max(), which is likely greater than the capacity of the filesystem. --- include/boost/log/keywords/max_files.hpp | 40 +++++++++++++++++++ include/boost/log/sinks/text_file_backend.hpp | 10 ++++- src/text_file_backend.cpp | 30 +++++++++----- 3 files changed, 67 insertions(+), 13 deletions(-) create mode 100644 include/boost/log/keywords/max_files.hpp diff --git a/include/boost/log/keywords/max_files.hpp b/include/boost/log/keywords/max_files.hpp new file mode 100644 index 0000000000..5d898e31e8 --- /dev/null +++ b/include/boost/log/keywords/max_files.hpp @@ -0,0 +1,40 @@ +/* + * Copyright Andrey Semashev 2007 - 2015. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file keywords/max_files.hpp + * \author Erich Keane + * \date 29.12.2015 + * + * The header contains the \c max_files keyword declaration. + */ + +#ifndef BOOST_LOG_KEYWORDS_MAX_FILES_HPP_INCLUDED_ +#define BOOST_LOG_KEYWORDS_MAX_FILES_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace keywords { + +//! The keyword allows to specify maximum total number of log files +BOOST_PARAMETER_KEYWORD(tag, max_files) + +} // namespace keywords + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#endif // BOOST_LOG_KEYWORDS_MAX_FILES_HPP_INCLUDED_ diff --git a/include/boost/log/sinks/text_file_backend.hpp b/include/boost/log/sinks/text_file_backend.hpp index 7fe6df80ad..143ef1f217 100644 --- a/include/boost/log/sinks/text_file_backend.hpp +++ b/include/boost/log/sinks/text_file_backend.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -129,7 +130,8 @@ namespace aux { BOOST_LOG_API shared_ptr< collector > make_collector( filesystem::path const& target_dir, uintmax_t max_size, - uintmax_t min_free_space + uintmax_t min_free_space, + uintmax_t max_files = (std::numeric_limits< uintmax_t >::max)() ); template< typename ArgsT > inline shared_ptr< collector > make_collector(ArgsT const& args) @@ -137,7 +139,8 @@ namespace aux { return aux::make_collector( filesystem::path(args[keywords::target]), args[keywords::max_size | (std::numeric_limits< uintmax_t >::max)()], - args[keywords::min_free_space | static_cast< uintmax_t >(0)]); + args[keywords::min_free_space | static_cast< uintmax_t >(0)], + args[keywords::max_files | (std::numeric_limits< uintmax_t >::max)()]); } } // namespace aux @@ -190,6 +193,9 @@ inline shared_ptr< collector > make_collector(T1 const& a1, T2 const& a2, T3 con * the collector tries to maintain. If the threshold is exceeded, the oldest * file(s) is deleted to free space. The threshold is not maintained, if not * specified. + * \li \c max_files - Specifies the maximum number of log files stored. If the number of files exceeds + * this threshold, the oldest file(s) is deleted to free space. The threshhold is + * not maintained if not specified. * * \return The file collector. */ diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index c4c4d4708e..fae0e4cf6c 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -545,6 +545,9 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { uintmax_t m_MaxSize; //! Free space lower limit uintmax_t m_MinFreeSpace; + //! File count upper limit + uintmax_t m_MaxFiles; + //! The current path at the point when the collector is created /* * The special member is required to calculate absolute paths with no @@ -565,7 +568,8 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { shared_ptr< file_collector_repository > const& repo, filesystem::path const& target_dir, uintmax_t max_size, - uintmax_t min_free_space); + uintmax_t min_free_space, + uintmax_t max_files); //! Destructor ~file_collector(); @@ -578,7 +582,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { file::scan_method method, filesystem::path const& pattern, unsigned int* counter); //! The function updates storage restrictions - void update(uintmax_t max_size, uintmax_t min_free_space); + void update(uintmax_t max_size, uintmax_t min_free_space, uintmax_t max_files); //! The function checks if the directory is governed by this collector bool is_governed(filesystem::path const& dir) const @@ -631,7 +635,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { public: //! Finds or creates a file collector shared_ptr< file::collector > get_collector( - filesystem::path const& target_dir, uintmax_t max_size, uintmax_t min_free_space); + filesystem::path const& target_dir, uintmax_t max_size, uintmax_t min_free_space, uintmax_t max_files); //! Removes the file collector from the list void remove_collector(file_collector* p); @@ -649,11 +653,13 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { shared_ptr< file_collector_repository > const& repo, filesystem::path const& target_dir, uintmax_t max_size, - uintmax_t min_free_space + uintmax_t min_free_space, + uintmax_t max_files ) : m_pRepository(repo), m_MaxSize(max_size), m_MinFreeSpace(min_free_space), + m_MaxFiles(max_files), m_BasePath(filesystem::current_path()), m_TotalSize(0) { @@ -715,7 +721,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { uintmax_t free_space = m_MinFreeSpace ? filesystem::space(m_StorageDir).available : static_cast< uintmax_t >(0); file_list::iterator it = m_Files.begin(), end = m_Files.end(); while (it != end && - (m_TotalSize + info.m_Size > m_MaxSize || (m_MinFreeSpace && m_MinFreeSpace > free_space))) + (m_TotalSize + info.m_Size > m_MaxSize || (m_MinFreeSpace && m_MinFreeSpace > free_space) || m_MaxFiles <= m_Files.size())) { file_info& old_info = *it; if (filesystem::exists(old_info.m_Path) && filesystem::is_regular_file(old_info.m_Path)) @@ -830,18 +836,19 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { } //! The function updates storage restrictions - void file_collector::update(uintmax_t max_size, uintmax_t min_free_space) + void file_collector::update(uintmax_t max_size, uintmax_t min_free_space, uintmax_t max_files) { BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);) m_MaxSize = (std::min)(m_MaxSize, max_size); m_MinFreeSpace = (std::max)(m_MinFreeSpace, min_free_space); + m_MaxFiles = (std::min)(m_MaxFiles, max_files); } //! Finds or creates a file collector shared_ptr< file::collector > file_collector_repository::get_collector( - filesystem::path const& target_dir, uintmax_t max_size, uintmax_t min_free_space) + filesystem::path const& target_dir, uintmax_t max_size, uintmax_t min_free_space, uintmax_t max_files) { BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);) @@ -852,7 +859,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { { // This may throw if the collector is being currently destroyed p = it->shared_from_this(); - p->update(max_size, min_free_space); + p->update(max_size, min_free_space, max_files); } catch (bad_weak_ptr&) { @@ -861,7 +868,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { if (!p) { p = boost::make_shared< file_collector >( - file_collector_repository::get(), target_dir, max_size, min_free_space); + file_collector_repository::get(), target_dir, max_size, min_free_space, max_files); m_Collectors.push_back(*p); } @@ -908,9 +915,10 @@ namespace aux { BOOST_LOG_API shared_ptr< collector > make_collector( filesystem::path const& target_dir, uintmax_t max_size, - uintmax_t min_free_space) + uintmax_t min_free_space, + uintmax_t max_files) { - return file_collector_repository::get()->get_collector(target_dir, max_size, min_free_space); + return file_collector_repository::get()->get_collector(target_dir, max_size, min_free_space, max_files); } } // namespace aux From 2b9cf67a4a347ba525f67fecd008eda9c024679a Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Tue, 29 Dec 2015 11:16:51 -0800 Subject: [PATCH 2/4] Add max_files parameter to the examples that use make_file_collector --- example/doc/sinks_xml_file.cpp | 3 ++- example/rotating_file/main.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/example/doc/sinks_xml_file.cpp b/example/doc/sinks_xml_file.cpp index 415a116c17..256324dc55 100644 --- a/example/doc/sinks_xml_file.cpp +++ b/example/doc/sinks_xml_file.cpp @@ -33,7 +33,8 @@ void init_file_collecting(boost::shared_ptr< file_sink > sink) sink->locked_backend()->set_file_collector(sinks::file::make_collector( keywords::target = "logs", /*< the target directory >*/ keywords::max_size = 16 * 1024 * 1024, /*< maximum total size of the stored files, in bytes >*/ - keywords::min_free_space = 100 * 1024 * 1024 /*< minimum free space on the drive, in bytes >*/ + keywords::min_free_space = 100 * 1024 * 1024, /*< minimum free space on the drive, in bytes >*/ + keywords::max_files = 512 /*< maximum number of stored files>*/ )); } //] diff --git a/example/rotating_file/main.cpp b/example/rotating_file/main.cpp index 77d19922b1..d2144c8124 100644 --- a/example/rotating_file/main.cpp +++ b/example/rotating_file/main.cpp @@ -56,7 +56,8 @@ int main(int argc, char* argv[]) sink->locked_backend()->set_file_collector(sinks::file::make_collector( keywords::target = "logs", // where to store rotated files keywords::max_size = 16 * 1024 * 1024, // maximum total size of the stored files, in bytes - keywords::min_free_space = 100 * 1024 * 1024 // minimum free space on the drive, in bytes + keywords::min_free_space = 100 * 1024 * 1024, // minimum free space on the drive, in bytes + keywords::max_files = 512 // maximum number of stored files )); // Upon restart, scan the target directory for files matching the file_name pattern From 5b8575cfabc137e7ed1c0c7fca25d5311e50e809 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Tue, 29 Dec 2015 11:20:57 -0800 Subject: [PATCH 3/4] Added max_files to parser_utils and init_from_settings --- src/init_from_settings.cpp | 7 ++++++- src/parser_utils.hpp | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/init_from_settings.cpp b/src/init_from_settings.cpp index 6852f37db5..f52de6b80a 100644 --- a/src/init_from_settings.cpp +++ b/src/init_from_settings.cpp @@ -488,10 +488,15 @@ class default_text_file_sink_factory : if (optional< string_type > min_space_param = params["MinFreeSpace"]) space = param_cast_to_int< uintmax_t >("MinFreeSpace", min_space_param.get()); + uintmax_t max_files = (std::numeric_limits< uintmax_t >::max)(); + if (optional< string_type > max_files_param = params["MaxFiles"]) + max_files = param_cast_to_int< uintmax_t >("MaxFiles", max_files_param.get()); + backend->set_file_collector(sinks::file::make_collector( keywords::target = target_dir, keywords::max_size = max_size, - keywords::min_free_space = space)); + keywords::min_free_space = space, + keywords::max_files = max_files)); // Scan for log files if (optional< string_type > scan_param = params["ScanForFiles"]) diff --git a/src/parser_utils.hpp b/src/parser_utils.hpp index e667ccc3ef..299b72f1ba 100644 --- a/src/parser_utils.hpp +++ b/src/parser_utils.hpp @@ -106,6 +106,7 @@ struct char_constants< char > static const char_type* target_address_param_name() { return "TargetAddress"; } static const char_type* target_param_name() { return "Target"; } static const char_type* max_size_param_name() { return "MaxSize"; } + static const char_type* max_files_param_name() { return "MaxFiles"; } static const char_type* min_free_space_param_name() { return "MinFreeSpace"; } static const char_type* scan_for_files_param_name() { return "ScanForFiles"; } @@ -235,6 +236,7 @@ struct char_constants< wchar_t > static const char_type* target_address_param_name() { return L"TargetAddress"; } static const char_type* target_param_name() { return L"Target"; } static const char_type* max_size_param_name() { return L"MaxSize"; } + static const char_type* max_files_param_name() { return L"MaxFiles"; } static const char_type* min_free_space_param_name() { return L"MinFreeSpace"; } static const char_type* scan_for_files_param_name() { return L"ScanForFiles"; } From cd09f68d24407636727b242ec378fad53844fb85 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Tue, 29 Dec 2015 11:27:43 -0800 Subject: [PATCH 4/4] Fixed previous build issue with keyword specification --- include/boost/log/sinks/text_file_backend.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/boost/log/sinks/text_file_backend.hpp b/include/boost/log/sinks/text_file_backend.hpp index 143ef1f217..68f698848f 100644 --- a/include/boost/log/sinks/text_file_backend.hpp +++ b/include/boost/log/sinks/text_file_backend.hpp @@ -162,6 +162,11 @@ inline shared_ptr< collector > make_collector(T1 const& a1, T2 const& a2, T3 con { return aux::make_collector((a1, a2, a3)); } +template< typename T1, typename T2, typename T3, typename T4 > +inline shared_ptr< collector > make_collector(T1 const& a1, T2 const& a2, T3 const& a3, T4 const& a4) +{ + return aux::make_collector((a1, a2, a3, a4)); +} #else