Chris@16: /* Chris@101: * Copyright Andrey Semashev 2007 - 2015. Chris@16: * Distributed under the Boost Software License, Version 1.0. Chris@16: * (See accompanying file LICENSE_1_0.txt or copy at Chris@16: * http://www.boost.org/LICENSE_1_0.txt) Chris@16: */ Chris@16: /*! Chris@16: * \file text_file_backend.hpp Chris@16: * \author Andrey Semashev Chris@16: * \date 09.06.2009 Chris@16: * Chris@16: * The header contains implementation of a text file sink backend. Chris@16: */ Chris@16: Chris@16: #ifndef BOOST_LOG_SINKS_TEXT_FILE_BACKEND_HPP_INCLUDED_ Chris@16: #define BOOST_LOG_SINKS_TEXT_FILE_BACKEND_HPP_INCLUDED_ Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #ifdef BOOST_HAS_PRAGMA_ONCE Chris@16: #pragma once Chris@16: #endif Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: BOOST_LOG_OPEN_NAMESPACE Chris@16: Chris@16: namespace sinks { Chris@16: Chris@16: namespace file { Chris@16: Chris@16: //! The enumeration of the stored files scan methods Chris@16: enum scan_method Chris@16: { Chris@16: no_scan, //!< Don't scan for stored files Chris@16: scan_matching, //!< Scan for files with names matching the specified mask Chris@16: scan_all //!< Scan for all files in the directory Chris@16: }; Chris@16: Chris@16: /*! Chris@16: * \brief Base class for file collectors Chris@16: * Chris@16: * All file collectors, supported by file sink backends, should inherit this class. Chris@16: */ Chris@16: struct BOOST_LOG_NO_VTABLE collector Chris@16: { Chris@16: /*! Chris@16: * Default constructor Chris@16: */ Chris@16: BOOST_DEFAULTED_FUNCTION(collector(), {}) Chris@16: Chris@16: /*! Chris@16: * Virtual destructor Chris@16: */ Chris@16: virtual ~collector() {} Chris@16: Chris@16: /*! Chris@16: * The function stores the specified file in the storage. May lead to an older file Chris@16: * deletion and a long file moving. Chris@16: * Chris@16: * \param src_path The name of the file to be stored Chris@16: */ Chris@16: virtual void store_file(filesystem::path const& src_path) = 0; Chris@16: Chris@16: /*! Chris@16: * Scans the target directory for the files that have already been stored. The found Chris@16: * files are added to the collector in order to be tracked and erased, if needed. Chris@16: * Chris@16: * The function may scan the directory in two ways: it will either consider every Chris@16: * file in the directory a log file, or will only consider files with names that Chris@16: * match the specified pattern. The pattern may contain the following placeholders: Chris@16: * Chris@16: * \li %y, %Y, %m, %d - date components, in Boost.DateTime meaning. Chris@16: * \li %H, %M, %S, %f - time components, in Boost.DateTime meaning. Chris@16: * \li %N - numeric file counter. May also contain width specification Chris@16: * in printf-compatible form (e.g. %5N). The resulting number will always be zero-filled. Chris@16: * \li %% - a percent sign Chris@16: * Chris@16: * All other placeholders are not supported. Chris@16: * Chris@16: * \param method The method of scanning. If \c no_scan is specified, the call has no effect. Chris@16: * \param pattern The file name pattern if \a method is \c scan_matching. Otherwise the parameter Chris@16: * is not used. Chris@16: * \param counter If not \c NULL and \a method is \c scan_matching, the method suggests initial value Chris@16: * of a file counter that may be used in the file name pattern. The parameter Chris@16: * is not used otherwise. Chris@16: * \return The number of found files. Chris@16: * Chris@16: * \note In case if \a method is \c scan_matching the effect of this function is highly dependent Chris@16: * on the \a pattern definition. It is recommended to choose patterns with easily Chris@16: * distinguished placeholders (i.e. having delimiters between them). Otherwise Chris@16: * either some files can be mistakenly found or not found, which in turn may lead Chris@16: * to an incorrect file deletion. Chris@16: */ Chris@16: virtual uintmax_t scan_for_files( Chris@16: scan_method method, filesystem::path const& pattern = filesystem::path(), unsigned int* counter = 0) = 0; Chris@16: Chris@16: BOOST_DELETED_FUNCTION(collector(collector const&)) Chris@16: BOOST_DELETED_FUNCTION(collector& operator= (collector const&)) Chris@16: }; Chris@16: Chris@16: namespace aux { Chris@16: Chris@16: //! Creates and returns a file collector with the specified parameters Chris@16: BOOST_LOG_API shared_ptr< collector > make_collector( Chris@16: filesystem::path const& target_dir, Chris@16: uintmax_t max_size, Chris@16: uintmax_t min_free_space Chris@16: ); Chris@16: template< typename ArgsT > Chris@16: inline shared_ptr< collector > make_collector(ArgsT const& args) Chris@16: { Chris@16: return aux::make_collector( Chris@16: filesystem::path(args[keywords::target]), Chris@16: args[keywords::max_size | (std::numeric_limits< uintmax_t >::max)()], Chris@16: args[keywords::min_free_space | static_cast< uintmax_t >(0)]); Chris@16: } Chris@16: Chris@16: } // namespace aux Chris@16: Chris@16: #ifndef BOOST_LOG_DOXYGEN_PASS Chris@16: Chris@16: template< typename T1 > Chris@16: inline shared_ptr< collector > make_collector(T1 const& a1) Chris@16: { Chris@16: return aux::make_collector(a1); Chris@16: } Chris@16: template< typename T1, typename T2 > Chris@16: inline shared_ptr< collector > make_collector(T1 const& a1, T2 const& a2) Chris@16: { Chris@16: return aux::make_collector((a1, a2)); Chris@16: } Chris@16: template< typename T1, typename T2, typename T3 > Chris@16: inline shared_ptr< collector > make_collector(T1 const& a1, T2 const& a2, T3 const& a3) Chris@16: { Chris@16: return aux::make_collector((a1, a2, a3)); Chris@16: } Chris@16: Chris@16: #else Chris@16: Chris@16: /*! Chris@16: * The function creates a file collector for the specified target directory. Chris@16: * Each target directory is managed by a single file collector, so if Chris@16: * this function is called several times for the same directory, Chris@16: * it will return a reference to the same file collector. It is safe Chris@16: * to use the same collector in different sinks, even in a multithreaded Chris@16: * application. Chris@16: * Chris@16: * One can specify certain restrictions for the stored files, such as Chris@16: * maximum total size or minimum free space left in the target directory. Chris@16: * If any of the specified restrictions is not met, the oldest stored file Chris@16: * is deleted. If the same collector is requested more than once with Chris@16: * different restrictions, the collector will act according to the most strict Chris@16: * combination of all specified restrictions. Chris@16: * Chris@16: * The following named parameters are supported: Chris@16: * Chris@16: * \li \c target - Specifies the target directory for the files being stored in. This parameter Chris@16: * is mandatory. Chris@16: * \li \c max_size - Specifies the maximum total size, in bytes, of stored files that the collector Chris@16: * will try not to exceed. If the size exceeds this threshold the oldest file(s) is Chris@16: * deleted to free space. Note that the threshold may be exceeded if the size of Chris@16: * individual files exceed the \c max_size value. The threshold is not maintained, Chris@16: * if not specified. Chris@16: * \li \c min_free_space - Specifies the minimum free space, in bytes, in the target directory that Chris@16: * the collector tries to maintain. If the threshold is exceeded, the oldest Chris@16: * file(s) is deleted to free space. The threshold is not maintained, if not Chris@16: * specified. Chris@16: * Chris@16: * \return The file collector. Chris@16: */ Chris@16: template< typename... ArgsT > Chris@16: shared_ptr< collector > make_collector(ArgsT... const& args); Chris@16: Chris@16: #endif // BOOST_LOG_DOXYGEN_PASS Chris@16: Chris@16: /*! Chris@16: * The class represents the time point of log file rotation. One can specify one of three Chris@16: * types of time point based rotation: Chris@16: * Chris@16: * \li rotation takes place every day, at the specified time Chris@16: * \li rotation takes place on the specified day of every week, at the specified time Chris@16: * \li rotation takes place on the specified day of every month, at the specified time Chris@16: * Chris@16: * The time points are considered to be local time. Chris@16: */ Chris@16: class rotation_at_time_point Chris@16: { Chris@16: public: Chris@16: typedef bool result_type; Chris@16: Chris@16: private: Chris@16: enum day_kind Chris@16: { Chris@16: not_specified, Chris@16: weekday, Chris@16: monthday Chris@16: }; Chris@16: Chris@16: day_kind m_DayKind : 2; Chris@16: unsigned char m_Day : 6; Chris@16: unsigned char m_Hour, m_Minute, m_Second; Chris@16: Chris@16: mutable posix_time::ptime m_Previous; Chris@16: Chris@16: public: Chris@16: /*! Chris@16: * Creates a rotation time point of every day at the specified time Chris@16: * Chris@16: * \param hour The rotation hour, should be within 0 and 23 Chris@16: * \param minute The rotation minute, should be within 0 and 59 Chris@16: * \param second The rotation second, should be within 0 and 59 Chris@16: */ Chris@16: BOOST_LOG_API explicit rotation_at_time_point(unsigned char hour, unsigned char minute, unsigned char second); Chris@16: Chris@16: /*! Chris@16: * Creates a rotation time point of each specified weekday at the specified time Chris@16: * Chris@16: * \param wday The weekday of the rotation Chris@16: * \param hour The rotation hour, should be within 0 and 23 Chris@16: * \param minute The rotation minute, should be within 0 and 59 Chris@16: * \param second The rotation second, should be within 0 and 59 Chris@16: */ Chris@16: BOOST_LOG_API explicit rotation_at_time_point( Chris@16: date_time::weekdays wday, Chris@16: unsigned char hour = 0, Chris@16: unsigned char minute = 0, Chris@16: unsigned char second = 0); Chris@16: Chris@16: /*! Chris@16: * Creates a rotation time point of each specified day of month at the specified time Chris@16: * Chris@16: * \param mday The monthday of the rotation, should be within 1 and 31 Chris@16: * \param hour The rotation hour, should be within 0 and 23 Chris@16: * \param minute The rotation minute, should be within 0 and 59 Chris@16: * \param second The rotation second, should be within 0 and 59 Chris@16: */ Chris@16: BOOST_LOG_API explicit rotation_at_time_point( Chris@16: gregorian::greg_day mday, Chris@16: unsigned char hour = 0, Chris@16: unsigned char minute = 0, Chris@16: unsigned char second = 0); Chris@16: Chris@16: /*! Chris@16: * Checks if it's time to rotate the file Chris@16: */ Chris@16: BOOST_LOG_API bool operator() () const; Chris@16: }; Chris@16: Chris@16: /*! Chris@16: * The class represents the time interval of log file rotation. The log file will be rotated Chris@16: * after the specified time interval has passed. Chris@16: */ Chris@16: class rotation_at_time_interval Chris@16: { Chris@16: public: Chris@16: typedef bool result_type; Chris@16: Chris@16: private: Chris@16: posix_time::time_duration m_Interval; Chris@16: mutable posix_time::ptime m_Previous; Chris@16: Chris@16: public: Chris@16: /*! Chris@16: * Creates a rotation time interval of the specified duration Chris@16: * Chris@16: * \param interval The interval of the rotation, should be no less than 1 second Chris@16: */ Chris@16: explicit rotation_at_time_interval(posix_time::time_duration const& interval) : Chris@16: m_Interval(interval) Chris@16: { Chris@16: BOOST_ASSERT(!interval.is_special()); Chris@16: BOOST_ASSERT(interval.total_seconds() > 0); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Checks if it's time to rotate the file Chris@16: */ Chris@16: BOOST_LOG_API bool operator() () const; Chris@16: }; Chris@16: Chris@16: } // namespace file Chris@16: Chris@16: Chris@16: /*! Chris@16: * \brief An implementation of a text file logging sink backend Chris@16: * Chris@16: * The sink backend puts formatted log records to a text file. Chris@16: * The sink supports file rotation and advanced file control, such as Chris@16: * size and file count restriction. Chris@16: */ Chris@16: class text_file_backend : Chris@16: public basic_formatted_sink_backend< Chris@16: char, Chris@16: combine_requirements< synchronized_feeding, flushing >::type Chris@16: > Chris@16: { Chris@16: //! Base type Chris@16: typedef basic_formatted_sink_backend< Chris@16: char, Chris@16: combine_requirements< synchronized_feeding, flushing >::type Chris@16: > base_type; Chris@16: Chris@16: public: Chris@16: //! Character type Chris@16: typedef base_type::char_type char_type; Chris@16: //! String type to be used as a message text holder Chris@16: typedef base_type::string_type string_type; Chris@16: //! Stream type Chris@16: typedef std::basic_ostream< char_type > stream_type; Chris@16: Chris@16: //! File open handler Chris@16: typedef boost::log::aux::light_function< void (stream_type&) > open_handler_type; Chris@16: //! File close handler Chris@16: typedef boost::log::aux::light_function< void (stream_type&) > close_handler_type; Chris@16: Chris@16: //! Predicate that defines the time-based condition for file rotation Chris@16: typedef boost::log::aux::light_function< bool () > time_based_rotation_predicate; Chris@16: Chris@16: private: Chris@16: //! \cond Chris@16: Chris@16: struct implementation; Chris@16: implementation* m_pImpl; Chris@16: Chris@16: //! \endcond Chris@16: Chris@16: public: Chris@16: /*! Chris@16: * Default constructor. The constructed sink backend uses default values of all the parameters. Chris@16: */ Chris@16: BOOST_LOG_API text_file_backend(); Chris@16: Chris@16: /*! Chris@16: * Constructor. Creates a sink backend with the specified named parameters. Chris@16: * The following named parameters are supported: Chris@16: * Chris@16: * \li \c file_name - Specifies the file name pattern where logs are actually written to. The pattern may Chris@16: * contain directory and file name portions, but only the file name may contain Chris@16: * placeholders. The backend supports Boost.DateTime placeholders for injecting Chris@16: * current time and date into the file name. Also, an additional %N placeholder is Chris@16: * supported, it will be replaced with an integral increasing file counter. The placeholder Chris@16: * may also contain width specification in the printf-compatible form (e.g. %5N). The Chris@16: * printed file counter will always be zero-filled. If \c file_name is not specified, Chris@16: * pattern "%5N.log" will be used. Chris@16: * \li \c open_mode - File open mode. The mode should be presented in form of mask compatible to Chris@16: * std::ios_base::openmode. If not specified, trunc | out will be used. Chris@16: * \li \c rotation_size - Specifies the approximate size, in characters written, of the temporary file Chris@16: * upon which the file is passed to the file collector. Note the size does Chris@16: * not count any possible character conversions that may take place during Chris@16: * writing to the file. If not specified, the file won't be rotated upon reaching Chris@16: * any size. Chris@16: * \li \c time_based_rotation - Specifies the predicate for time-based file rotation. Chris@16: * No time-based file rotations will be performed, if not specified. Chris@16: * \li \c auto_flush - Specifies a flag, whether or not to automatically flush the file after each Chris@16: * written log record. By default, is \c false. Chris@16: * Chris@16: * \note Read the caution note regarding file name pattern in the sinks::file::collector::scan_for_files Chris@16: * documentation. Chris@16: */ Chris@16: #ifndef BOOST_LOG_DOXYGEN_PASS Chris@16: BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_CALL(text_file_backend, construct) Chris@16: #else Chris@16: template< typename... ArgsT > Chris@16: explicit text_file_backend(ArgsT... const& args); Chris@16: #endif Chris@16: Chris@16: /*! Chris@16: * Destructor Chris@16: */ Chris@16: BOOST_LOG_API ~text_file_backend(); Chris@16: Chris@16: /*! Chris@16: * The method sets file name wildcard for the files being written. The wildcard supports Chris@16: * date and time injection into the file name. Chris@16: * Chris@16: * \param pattern The name pattern for the file being written. Chris@16: */ Chris@16: template< typename PathT > Chris@16: void set_file_name_pattern(PathT const& pattern) Chris@16: { Chris@16: set_file_name_pattern_internal(filesystem::path(pattern)); Chris@16: } Chris@16: Chris@16: /*! Chris@16: * The method sets the file open mode Chris@16: * Chris@16: * \param mode File open mode Chris@16: */ Chris@16: BOOST_LOG_API void set_open_mode(std::ios_base::openmode mode); Chris@16: Chris@16: /*! Chris@16: * The method sets the log file collector function. The function is called Chris@16: * on file rotation and is being passed the written file name. Chris@16: * Chris@16: * \param collector The file collector function object Chris@16: */ Chris@16: BOOST_LOG_API void set_file_collector(shared_ptr< file::collector > const& collector); Chris@16: Chris@16: /*! Chris@16: * The method sets file opening handler. The handler will be called every time Chris@16: * the backend opens a new temporary file. The handler may write a header to the Chris@16: * opened file in order to maintain file validity. Chris@16: * Chris@16: * \param handler The file open handler function object Chris@16: */ Chris@16: BOOST_LOG_API void set_open_handler(open_handler_type const& handler); Chris@16: Chris@16: /*! Chris@16: * The method sets file closing handler. The handler will be called every time Chris@16: * the backend closes a temporary file. The handler may write a footer to the Chris@16: * opened file in order to maintain file validity. Chris@16: * Chris@16: * \param handler The file close handler function object Chris@16: */ Chris@16: BOOST_LOG_API void set_close_handler(close_handler_type const& handler); Chris@16: Chris@16: /*! Chris@16: * The method sets maximum file size. When the size is reached, file rotation is performed. Chris@16: * Chris@16: * \note The size does not count any possible character translations that may happen in Chris@16: * the underlying API. This may result in greater actual sizes of the written files. Chris@16: * Chris@16: * \param size The maximum file size, in characters. Chris@16: */ Chris@16: BOOST_LOG_API void set_rotation_size(uintmax_t size); Chris@16: Chris@16: /*! Chris@16: * The method sets the predicate that defines the time-based condition for file rotation. Chris@16: * Chris@16: * \note The rotation always occurs on writing a log record, so the rotation is Chris@16: * not strictly bound to the specified condition. Chris@16: * Chris@16: * \param predicate The predicate that defines the time-based condition for file rotation. Chris@16: * If empty, no time-based rotation will take place. Chris@16: */ Chris@16: BOOST_LOG_API void set_time_based_rotation(time_based_rotation_predicate const& predicate); Chris@16: Chris@16: /*! Chris@16: * Sets the flag to automatically flush buffers of all attached streams after each log record Chris@16: */ Chris@16: BOOST_LOG_API void auto_flush(bool f = true); Chris@16: Chris@16: /*! Chris@16: * Performs scanning of the target directory for log files that may have been left from Chris@16: * previous runs of the application. The found files are considered by the file collector Chris@16: * as if they were rotated. Chris@16: * Chris@16: * The file scan can be performed in two ways: either all files in the target directory will Chris@16: * be considered as log files, or only those files that satisfy the file name pattern. Chris@16: * See documentation on sinks::file::collector::scan_for_files for more information. Chris@16: * Chris@16: * \pre File collector and the proper file name pattern have already been set. Chris@16: * Chris@16: * \param method File scanning method Chris@16: * \param update_counter If \c true and \a method is \c scan_matching, the method attempts Chris@16: * to update the internal file counter according to the found files. The counter Chris@16: * is unaffected otherwise. Chris@16: * \return The number of files found. Chris@16: * Chris@16: * \note The method essentially delegates to the same-named function of the file collector. Chris@16: */ Chris@16: BOOST_LOG_API uintmax_t scan_for_files( Chris@16: file::scan_method method = file::scan_matching, bool update_counter = true); Chris@16: Chris@16: /*! Chris@16: * The method writes the message to the sink Chris@16: */ Chris@16: BOOST_LOG_API void consume(record_view const& rec, string_type const& formatted_message); Chris@16: Chris@16: /*! Chris@16: * The method flushes the currently open log file Chris@16: */ Chris@16: BOOST_LOG_API void flush(); Chris@16: Chris@16: /*! Chris@16: * The method rotates the file Chris@16: */ Chris@16: BOOST_LOG_API void rotate_file(); Chris@16: Chris@16: private: Chris@16: #ifndef BOOST_LOG_DOXYGEN_PASS Chris@16: //! Constructor implementation Chris@16: template< typename ArgsT > Chris@16: void construct(ArgsT const& args) Chris@16: { Chris@16: construct( Chris@16: filesystem::path(args[keywords::file_name | filesystem::path()]), Chris@16: args[keywords::open_mode | (std::ios_base::trunc | std::ios_base::out)], Chris@16: args[keywords::rotation_size | (std::numeric_limits< uintmax_t >::max)()], Chris@16: args[keywords::time_based_rotation | time_based_rotation_predicate()], Chris@16: args[keywords::auto_flush | false]); Chris@16: } Chris@16: //! Constructor implementation Chris@16: BOOST_LOG_API void construct( Chris@16: filesystem::path const& pattern, Chris@16: std::ios_base::openmode mode, Chris@16: uintmax_t rotation_size, Chris@16: time_based_rotation_predicate const& time_based_rotation, Chris@16: bool auto_flush); Chris@16: Chris@16: //! The method sets file name mask Chris@16: BOOST_LOG_API void set_file_name_pattern_internal(filesystem::path const& pattern); Chris@101: Chris@101: //! Closes the currently open file Chris@101: void close_file(); Chris@16: #endif // BOOST_LOG_DOXYGEN_PASS Chris@16: }; Chris@16: Chris@16: } // namespace sinks Chris@16: Chris@16: BOOST_LOG_CLOSE_NAMESPACE // namespace log Chris@16: Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // BOOST_LOG_SINKS_TEXT_FILE_BACKEND_HPP_INCLUDED_