text_file_backend.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. /*
  2. * Copyright Andrey Semashev 2007 - 2013.
  3. * Distributed under the Boost Software License, Version 1.0.
  4. * (See accompanying file LICENSE_1_0.txt or copy at
  5. * http://www.boost.org/LICENSE_1_0.txt)
  6. */
  7. /*!
  8. * \file text_file_backend.hpp
  9. * \author Andrey Semashev
  10. * \date 09.06.2009
  11. *
  12. * The header contains implementation of a text file sink backend.
  13. */
  14. #ifndef BOOST_LOG_SINKS_TEXT_FILE_BACKEND_HPP_INCLUDED_
  15. #define BOOST_LOG_SINKS_TEXT_FILE_BACKEND_HPP_INCLUDED_
  16. #include <ios>
  17. #include <string>
  18. #include <ostream>
  19. #include <boost/limits.hpp>
  20. #include <boost/cstdint.hpp>
  21. #include <boost/smart_ptr/shared_ptr.hpp>
  22. #include <boost/date_time/date_defs.hpp>
  23. #include <boost/date_time/special_defs.hpp>
  24. #include <boost/date_time/gregorian/greg_day.hpp>
  25. #include <boost/date_time/posix_time/posix_time_types.hpp>
  26. #include <boost/filesystem/path.hpp>
  27. #include <boost/log/keywords/max_size.hpp>
  28. #include <boost/log/keywords/min_free_space.hpp>
  29. #include <boost/log/keywords/target.hpp>
  30. #include <boost/log/keywords/file_name.hpp>
  31. #include <boost/log/keywords/open_mode.hpp>
  32. #include <boost/log/keywords/auto_flush.hpp>
  33. #include <boost/log/keywords/rotation_size.hpp>
  34. #include <boost/log/keywords/time_based_rotation.hpp>
  35. #include <boost/log/detail/config.hpp>
  36. #include <boost/log/detail/light_function.hpp>
  37. #include <boost/log/detail/parameter_tools.hpp>
  38. #include <boost/log/sinks/basic_sink_backend.hpp>
  39. #include <boost/log/sinks/frontend_requirements.hpp>
  40. #include <boost/log/detail/header.hpp>
  41. #ifdef BOOST_HAS_PRAGMA_ONCE
  42. #pragma once
  43. #endif
  44. namespace boost {
  45. BOOST_LOG_OPEN_NAMESPACE
  46. namespace sinks {
  47. namespace file {
  48. //! The enumeration of the stored files scan methods
  49. enum scan_method
  50. {
  51. no_scan, //!< Don't scan for stored files
  52. scan_matching, //!< Scan for files with names matching the specified mask
  53. scan_all //!< Scan for all files in the directory
  54. };
  55. /*!
  56. * \brief Base class for file collectors
  57. *
  58. * All file collectors, supported by file sink backends, should inherit this class.
  59. */
  60. struct BOOST_LOG_NO_VTABLE collector
  61. {
  62. /*!
  63. * Default constructor
  64. */
  65. BOOST_DEFAULTED_FUNCTION(collector(), {})
  66. /*!
  67. * Virtual destructor
  68. */
  69. virtual ~collector() {}
  70. /*!
  71. * The function stores the specified file in the storage. May lead to an older file
  72. * deletion and a long file moving.
  73. *
  74. * \param src_path The name of the file to be stored
  75. */
  76. virtual void store_file(filesystem::path const& src_path) = 0;
  77. /*!
  78. * Scans the target directory for the files that have already been stored. The found
  79. * files are added to the collector in order to be tracked and erased, if needed.
  80. *
  81. * The function may scan the directory in two ways: it will either consider every
  82. * file in the directory a log file, or will only consider files with names that
  83. * match the specified pattern. The pattern may contain the following placeholders:
  84. *
  85. * \li %y, %Y, %m, %d - date components, in Boost.DateTime meaning.
  86. * \li %H, %M, %S, %f - time components, in Boost.DateTime meaning.
  87. * \li %N - numeric file counter. May also contain width specification
  88. * in printf-compatible form (e.g. %5N). The resulting number will always be zero-filled.
  89. * \li %% - a percent sign
  90. *
  91. * All other placeholders are not supported.
  92. *
  93. * \param method The method of scanning. If \c no_scan is specified, the call has no effect.
  94. * \param pattern The file name pattern if \a method is \c scan_matching. Otherwise the parameter
  95. * is not used.
  96. * \param counter If not \c NULL and \a method is \c scan_matching, the method suggests initial value
  97. * of a file counter that may be used in the file name pattern. The parameter
  98. * is not used otherwise.
  99. * \return The number of found files.
  100. *
  101. * \note In case if \a method is \c scan_matching the effect of this function is highly dependent
  102. * on the \a pattern definition. It is recommended to choose patterns with easily
  103. * distinguished placeholders (i.e. having delimiters between them). Otherwise
  104. * either some files can be mistakenly found or not found, which in turn may lead
  105. * to an incorrect file deletion.
  106. */
  107. virtual uintmax_t scan_for_files(
  108. scan_method method, filesystem::path const& pattern = filesystem::path(), unsigned int* counter = 0) = 0;
  109. BOOST_DELETED_FUNCTION(collector(collector const&))
  110. BOOST_DELETED_FUNCTION(collector& operator= (collector const&))
  111. };
  112. namespace aux {
  113. //! Creates and returns a file collector with the specified parameters
  114. BOOST_LOG_API shared_ptr< collector > make_collector(
  115. filesystem::path const& target_dir,
  116. uintmax_t max_size,
  117. uintmax_t min_free_space
  118. );
  119. template< typename ArgsT >
  120. inline shared_ptr< collector > make_collector(ArgsT const& args)
  121. {
  122. return aux::make_collector(
  123. filesystem::path(args[keywords::target]),
  124. args[keywords::max_size | (std::numeric_limits< uintmax_t >::max)()],
  125. args[keywords::min_free_space | static_cast< uintmax_t >(0)]);
  126. }
  127. } // namespace aux
  128. #ifndef BOOST_LOG_DOXYGEN_PASS
  129. template< typename T1 >
  130. inline shared_ptr< collector > make_collector(T1 const& a1)
  131. {
  132. return aux::make_collector(a1);
  133. }
  134. template< typename T1, typename T2 >
  135. inline shared_ptr< collector > make_collector(T1 const& a1, T2 const& a2)
  136. {
  137. return aux::make_collector((a1, a2));
  138. }
  139. template< typename T1, typename T2, typename T3 >
  140. inline shared_ptr< collector > make_collector(T1 const& a1, T2 const& a2, T3 const& a3)
  141. {
  142. return aux::make_collector((a1, a2, a3));
  143. }
  144. #else
  145. /*!
  146. * The function creates a file collector for the specified target directory.
  147. * Each target directory is managed by a single file collector, so if
  148. * this function is called several times for the same directory,
  149. * it will return a reference to the same file collector. It is safe
  150. * to use the same collector in different sinks, even in a multithreaded
  151. * application.
  152. *
  153. * One can specify certain restrictions for the stored files, such as
  154. * maximum total size or minimum free space left in the target directory.
  155. * If any of the specified restrictions is not met, the oldest stored file
  156. * is deleted. If the same collector is requested more than once with
  157. * different restrictions, the collector will act according to the most strict
  158. * combination of all specified restrictions.
  159. *
  160. * The following named parameters are supported:
  161. *
  162. * \li \c target - Specifies the target directory for the files being stored in. This parameter
  163. * is mandatory.
  164. * \li \c max_size - Specifies the maximum total size, in bytes, of stored files that the collector
  165. * will try not to exceed. If the size exceeds this threshold the oldest file(s) is
  166. * deleted to free space. Note that the threshold may be exceeded if the size of
  167. * individual files exceed the \c max_size value. The threshold is not maintained,
  168. * if not specified.
  169. * \li \c min_free_space - Specifies the minimum free space, in bytes, in the target directory that
  170. * the collector tries to maintain. If the threshold is exceeded, the oldest
  171. * file(s) is deleted to free space. The threshold is not maintained, if not
  172. * specified.
  173. *
  174. * \return The file collector.
  175. */
  176. template< typename... ArgsT >
  177. shared_ptr< collector > make_collector(ArgsT... const& args);
  178. #endif // BOOST_LOG_DOXYGEN_PASS
  179. /*!
  180. * The class represents the time point of log file rotation. One can specify one of three
  181. * types of time point based rotation:
  182. *
  183. * \li rotation takes place every day, at the specified time
  184. * \li rotation takes place on the specified day of every week, at the specified time
  185. * \li rotation takes place on the specified day of every month, at the specified time
  186. *
  187. * The time points are considered to be local time.
  188. */
  189. class rotation_at_time_point
  190. {
  191. public:
  192. typedef bool result_type;
  193. private:
  194. enum day_kind
  195. {
  196. not_specified,
  197. weekday,
  198. monthday
  199. };
  200. day_kind m_DayKind : 2;
  201. unsigned char m_Day : 6;
  202. unsigned char m_Hour, m_Minute, m_Second;
  203. mutable posix_time::ptime m_Previous;
  204. public:
  205. /*!
  206. * Creates a rotation time point of every day at the specified time
  207. *
  208. * \param hour The rotation hour, should be within 0 and 23
  209. * \param minute The rotation minute, should be within 0 and 59
  210. * \param second The rotation second, should be within 0 and 59
  211. */
  212. BOOST_LOG_API explicit rotation_at_time_point(unsigned char hour, unsigned char minute, unsigned char second);
  213. /*!
  214. * Creates a rotation time point of each specified weekday at the specified time
  215. *
  216. * \param wday The weekday of the rotation
  217. * \param hour The rotation hour, should be within 0 and 23
  218. * \param minute The rotation minute, should be within 0 and 59
  219. * \param second The rotation second, should be within 0 and 59
  220. */
  221. BOOST_LOG_API explicit rotation_at_time_point(
  222. date_time::weekdays wday,
  223. unsigned char hour = 0,
  224. unsigned char minute = 0,
  225. unsigned char second = 0);
  226. /*!
  227. * Creates a rotation time point of each specified day of month at the specified time
  228. *
  229. * \param mday The monthday of the rotation, should be within 1 and 31
  230. * \param hour The rotation hour, should be within 0 and 23
  231. * \param minute The rotation minute, should be within 0 and 59
  232. * \param second The rotation second, should be within 0 and 59
  233. */
  234. BOOST_LOG_API explicit rotation_at_time_point(
  235. gregorian::greg_day mday,
  236. unsigned char hour = 0,
  237. unsigned char minute = 0,
  238. unsigned char second = 0);
  239. /*!
  240. * Checks if it's time to rotate the file
  241. */
  242. BOOST_LOG_API bool operator() () const;
  243. };
  244. /*!
  245. * The class represents the time interval of log file rotation. The log file will be rotated
  246. * after the specified time interval has passed.
  247. */
  248. class rotation_at_time_interval
  249. {
  250. public:
  251. typedef bool result_type;
  252. private:
  253. posix_time::time_duration m_Interval;
  254. mutable posix_time::ptime m_Previous;
  255. public:
  256. /*!
  257. * Creates a rotation time interval of the specified duration
  258. *
  259. * \param interval The interval of the rotation, should be no less than 1 second
  260. */
  261. explicit rotation_at_time_interval(posix_time::time_duration const& interval) :
  262. m_Interval(interval)
  263. {
  264. BOOST_ASSERT(!interval.is_special());
  265. BOOST_ASSERT(interval.total_seconds() > 0);
  266. }
  267. /*!
  268. * Checks if it's time to rotate the file
  269. */
  270. BOOST_LOG_API bool operator() () const;
  271. };
  272. } // namespace file
  273. /*!
  274. * \brief An implementation of a text file logging sink backend
  275. *
  276. * The sink backend puts formatted log records to a text file.
  277. * The sink supports file rotation and advanced file control, such as
  278. * size and file count restriction.
  279. */
  280. class text_file_backend :
  281. public basic_formatted_sink_backend<
  282. char,
  283. combine_requirements< synchronized_feeding, flushing >::type
  284. >
  285. {
  286. //! Base type
  287. typedef basic_formatted_sink_backend<
  288. char,
  289. combine_requirements< synchronized_feeding, flushing >::type
  290. > base_type;
  291. public:
  292. //! Character type
  293. typedef base_type::char_type char_type;
  294. //! String type to be used as a message text holder
  295. typedef base_type::string_type string_type;
  296. //! Stream type
  297. typedef std::basic_ostream< char_type > stream_type;
  298. //! File open handler
  299. typedef boost::log::aux::light_function< void (stream_type&) > open_handler_type;
  300. //! File close handler
  301. typedef boost::log::aux::light_function< void (stream_type&) > close_handler_type;
  302. //! Predicate that defines the time-based condition for file rotation
  303. typedef boost::log::aux::light_function< bool () > time_based_rotation_predicate;
  304. private:
  305. //! \cond
  306. struct implementation;
  307. implementation* m_pImpl;
  308. //! \endcond
  309. public:
  310. /*!
  311. * Default constructor. The constructed sink backend uses default values of all the parameters.
  312. */
  313. BOOST_LOG_API text_file_backend();
  314. /*!
  315. * Constructor. Creates a sink backend with the specified named parameters.
  316. * The following named parameters are supported:
  317. *
  318. * \li \c file_name - Specifies the file name pattern where logs are actually written to. The pattern may
  319. * contain directory and file name portions, but only the file name may contain
  320. * placeholders. The backend supports Boost.DateTime placeholders for injecting
  321. * current time and date into the file name. Also, an additional %N placeholder is
  322. * supported, it will be replaced with an integral increasing file counter. The placeholder
  323. * may also contain width specification in the printf-compatible form (e.g. %5N). The
  324. * printed file counter will always be zero-filled. If \c file_name is not specified,
  325. * pattern "%5N.log" will be used.
  326. * \li \c open_mode - File open mode. The mode should be presented in form of mask compatible to
  327. * <tt>std::ios_base::openmode</tt>. If not specified, <tt>trunc | out</tt> will be used.
  328. * \li \c rotation_size - Specifies the approximate size, in characters written, of the temporary file
  329. * upon which the file is passed to the file collector. Note the size does
  330. * not count any possible character conversions that may take place during
  331. * writing to the file. If not specified, the file won't be rotated upon reaching
  332. * any size.
  333. * \li \c time_based_rotation - Specifies the predicate for time-based file rotation.
  334. * No time-based file rotations will be performed, if not specified.
  335. * \li \c auto_flush - Specifies a flag, whether or not to automatically flush the file after each
  336. * written log record. By default, is \c false.
  337. *
  338. * \note Read the caution note regarding file name pattern in the <tt>sinks::file::collector::scan_for_files</tt>
  339. * documentation.
  340. */
  341. #ifndef BOOST_LOG_DOXYGEN_PASS
  342. BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_CALL(text_file_backend, construct)
  343. #else
  344. template< typename... ArgsT >
  345. explicit text_file_backend(ArgsT... const& args);
  346. #endif
  347. /*!
  348. * Destructor
  349. */
  350. BOOST_LOG_API ~text_file_backend();
  351. /*!
  352. * The method sets file name wildcard for the files being written. The wildcard supports
  353. * date and time injection into the file name.
  354. *
  355. * \param pattern The name pattern for the file being written.
  356. */
  357. template< typename PathT >
  358. void set_file_name_pattern(PathT const& pattern)
  359. {
  360. set_file_name_pattern_internal(filesystem::path(pattern));
  361. }
  362. /*!
  363. * The method sets the file open mode
  364. *
  365. * \param mode File open mode
  366. */
  367. BOOST_LOG_API void set_open_mode(std::ios_base::openmode mode);
  368. /*!
  369. * The method sets the log file collector function. The function is called
  370. * on file rotation and is being passed the written file name.
  371. *
  372. * \param collector The file collector function object
  373. */
  374. BOOST_LOG_API void set_file_collector(shared_ptr< file::collector > const& collector);
  375. /*!
  376. * The method sets file opening handler. The handler will be called every time
  377. * the backend opens a new temporary file. The handler may write a header to the
  378. * opened file in order to maintain file validity.
  379. *
  380. * \param handler The file open handler function object
  381. */
  382. BOOST_LOG_API void set_open_handler(open_handler_type const& handler);
  383. /*!
  384. * The method sets file closing handler. The handler will be called every time
  385. * the backend closes a temporary file. The handler may write a footer to the
  386. * opened file in order to maintain file validity.
  387. *
  388. * \param handler The file close handler function object
  389. */
  390. BOOST_LOG_API void set_close_handler(close_handler_type const& handler);
  391. /*!
  392. * The method sets maximum file size. When the size is reached, file rotation is performed.
  393. *
  394. * \note The size does not count any possible character translations that may happen in
  395. * the underlying API. This may result in greater actual sizes of the written files.
  396. *
  397. * \param size The maximum file size, in characters.
  398. */
  399. BOOST_LOG_API void set_rotation_size(uintmax_t size);
  400. /*!
  401. * The method sets the predicate that defines the time-based condition for file rotation.
  402. *
  403. * \note The rotation always occurs on writing a log record, so the rotation is
  404. * not strictly bound to the specified condition.
  405. *
  406. * \param predicate The predicate that defines the time-based condition for file rotation.
  407. * If empty, no time-based rotation will take place.
  408. */
  409. BOOST_LOG_API void set_time_based_rotation(time_based_rotation_predicate const& predicate);
  410. /*!
  411. * Sets the flag to automatically flush buffers of all attached streams after each log record
  412. */
  413. BOOST_LOG_API void auto_flush(bool f = true);
  414. /*!
  415. * Performs scanning of the target directory for log files that may have been left from
  416. * previous runs of the application. The found files are considered by the file collector
  417. * as if they were rotated.
  418. *
  419. * The file scan can be performed in two ways: either all files in the target directory will
  420. * be considered as log files, or only those files that satisfy the file name pattern.
  421. * See documentation on <tt>sinks::file::collector::scan_for_files</tt> for more information.
  422. *
  423. * \pre File collector and the proper file name pattern have already been set.
  424. *
  425. * \param method File scanning method
  426. * \param update_counter If \c true and \a method is \c scan_matching, the method attempts
  427. * to update the internal file counter according to the found files. The counter
  428. * is unaffected otherwise.
  429. * \return The number of files found.
  430. *
  431. * \note The method essentially delegates to the same-named function of the file collector.
  432. */
  433. BOOST_LOG_API uintmax_t scan_for_files(
  434. file::scan_method method = file::scan_matching, bool update_counter = true);
  435. /*!
  436. * The method writes the message to the sink
  437. */
  438. BOOST_LOG_API void consume(record_view const& rec, string_type const& formatted_message);
  439. /*!
  440. * The method flushes the currently open log file
  441. */
  442. BOOST_LOG_API void flush();
  443. /*!
  444. * The method rotates the file
  445. */
  446. BOOST_LOG_API void rotate_file();
  447. private:
  448. #ifndef BOOST_LOG_DOXYGEN_PASS
  449. //! Constructor implementation
  450. template< typename ArgsT >
  451. void construct(ArgsT const& args)
  452. {
  453. construct(
  454. filesystem::path(args[keywords::file_name | filesystem::path()]),
  455. args[keywords::open_mode | (std::ios_base::trunc | std::ios_base::out)],
  456. args[keywords::rotation_size | (std::numeric_limits< uintmax_t >::max)()],
  457. args[keywords::time_based_rotation | time_based_rotation_predicate()],
  458. args[keywords::auto_flush | false]);
  459. }
  460. //! Constructor implementation
  461. BOOST_LOG_API void construct(
  462. filesystem::path const& pattern,
  463. std::ios_base::openmode mode,
  464. uintmax_t rotation_size,
  465. time_based_rotation_predicate const& time_based_rotation,
  466. bool auto_flush);
  467. //! The method sets file name mask
  468. BOOST_LOG_API void set_file_name_pattern_internal(filesystem::path const& pattern);
  469. #endif // BOOST_LOG_DOXYGEN_PASS
  470. };
  471. } // namespace sinks
  472. BOOST_LOG_CLOSE_NAMESPACE // namespace log
  473. } // namespace boost
  474. #include <boost/log/detail/footer.hpp>
  475. #endif // BOOST_LOG_SINKS_TEXT_FILE_BACKEND_HPP_INCLUDED_