logger.h.xml 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. <chapter xml:id="logger.h">
  2. <title><tt>__vic/logger.h</tt></title>
  3. <chapter xml:id="logger">
  4. <title><tt>logger</tt></title>
  5. <code-block lang="C++"><![CDATA[
  6. class logger : private non_copyable
  7. {
  8. public:
  9. enum class severity : unsigned char
  10. {
  11. trace,
  12. debug,
  13. info,
  14. notice,
  15. warning,
  16. error,
  17. fatal
  18. };
  19. using severity_t = severity; // use this alias as a type name
  20. struct output
  21. {
  22. virtual void publish_record(severity_t , const char * , size_t ) = 0;
  23. protected:
  24. ~output() = default;
  25. };
  26. class settings_t
  27. {
  28. struct output &output() const;
  29. severity_t level() const;
  30. };
  31. class record;
  32. explicit logger(output &out, severity_t = severity::info);
  33. explicit logger(settings_t s);
  34. ~logger();
  35. severity_t level() const;
  36. void level(severity_t new_level);
  37. settings_t settings() const;
  38. output &reset_output(output &out);
  39. output &get_output();
  40. const output &get_output() const;
  41. static constexpr size_t min_buffer_size = ...;
  42. void shrink_buffer(size_t limit);
  43. void message(severity_t severity, const char *msg, size_t msg_len);
  44. #if __cpp_lib_string_view // C++17
  45. void message(severity_t severity, std::string_view msg);
  46. void trace(std::string_view msg);
  47. void debug(std::string_view msg);
  48. void info(std::string_view msg);
  49. void notice(std::string_view msg);
  50. void warning(std::string_view msg);
  51. void error(std::string_view msg);
  52. void fatal(std::string_view msg);
  53. #else // until C++17
  54. void message(severity_t severity, const char *msg);
  55. void message(severity_t severity, const std::string &msg);
  56. void trace(const char *msg);
  57. void debug(const char *msg);
  58. void info(const char *msg);
  59. void notice(const char *msg);
  60. void warning(const char *msg);
  61. void error(const char *msg);
  62. void fatal(const char *msg);
  63. void trace(const std::string &msg);
  64. void debug(const std::string &msg);
  65. void info(const std::string &msg);
  66. void notice(const std::string &msg);
  67. void warning(const std::string &msg);
  68. void error(const std::string &msg);
  69. void fatal(const std::string &msg);
  70. #endif
  71. #if __cpp_lib_format >= 202106L // C++20 + P2508
  72. template<class... Args>
  73. void format(severity_t s,
  74. std::format_string<Args...> fmt, Args&&... args);
  75. template<class Arg1, class... Args>
  76. void trace(
  77. std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args);
  78. template<class Arg1, class... Args>
  79. void debug(
  80. std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args);
  81. template<class Arg1, class... Args>
  82. void info(
  83. std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args);
  84. template<class Arg1, class... Args>
  85. void notice(
  86. std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args);
  87. template<class Arg1, class... Args>
  88. void warning(
  89. std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args);
  90. template<class Arg1, class... Args>
  91. void error(
  92. std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args);
  93. template<class Arg1, class... Args>
  94. void fatal(
  95. std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args);
  96. #endif
  97. record trace();
  98. record debug();
  99. record info();
  100. record notice();
  101. record warning();
  102. record error();
  103. record fatal();
  104. bool trace_visible() const;
  105. bool debug_visible() const;
  106. bool info_visible() const;
  107. bool notice_visible() const;
  108. bool warning_visible() const;
  109. bool error_visible() const;
  110. bool fatal_visible() const;
  111. };
  112. class logger::record
  113. {
  114. public:
  115. record(logger &log, severity_t sev);
  116. ~record();
  117. record append(const char *str, size_t str_len);
  118. template<class T> record operator<<(const T &v);
  119. };
  120. const char *to_string(logger::severity_t s);
  121. #if __cpp_lib_string_view // C++17
  122. constexpr std::string_view to_string_view(logger::severity s);
  123. #endif
  124. ]]></code-block>
  125. <p>Logging front-end. Provides building of the
  126. log records using operator <tt>&lt;&lt;</tt>, like <tt>iostream</tt>. Each log
  127. record has the associated severity. The logger itself can filter out the
  128. records by severity. There are 7 predefined levels of the severity (in
  129. ascending order):</p>
  130. <list style="numbered">
  131. <item>TRACE - detailed debug,</item>
  132. <item>DEBUG - debug,</item>
  133. <item>INFO - informational,</item>
  134. <item>NOTICE - normal but significant event,</item>
  135. <item>WARNING - insignificant error or suspicious situation,</item>
  136. <item>ERROR - severe error but the application can continue,</item>
  137. <item>FATAL - critical unrecoverable error, the application can't
  138. continue.</item>
  139. </list>
  140. <p>INFO is the default logging level but any other can be chosen. If severity
  141. of the log message (record) is below the logging level, it will be ignored and
  142. will not be published in the log's output.</p>
  143. <p>For creation of messages with the required severity, the set of functions
  144. with the same name as the severity is available. For instance <tt>info()</tt>
  145. for INFO messages. Or alternatively the universal function <tt>message()</tt>
  146. can be used, in which the severity is the argument. Usually the specific
  147. functions should be used.</p>
  148. <p>There are two ways of logging. The first is plain and common:</p>
  149. <code-block lang="C++">
  150. log.trace("Trace message");
  151. log.debug("Debug message");
  152. log.info("Info message");
  153. log.notice("Notice");
  154. log.warning("Warning");
  155. log.error("Recoverable error");
  156. log.fatal("Fatal error");
  157. </code-block>
  158. <p>The second is slightly more complex but provides more capabilities:</p>
  159. <code-block lang="C++"><![CDATA[
  160. log.error() << "Cannot open file " << filename << '!';
  161. log.warning() << "Loop iteration no " << i;
  162. ]]></code-block>
  163. <p>The call without parameters creates the object of type
  164. <tt>logger::record</tt> with the corresponding severity. Futher, the message
  165. is formed using operators <tt>&lt;&lt;</tt>. The message will be output to the
  166. log at the end of the full-expression (term from the Standard).</p>
  167. <p>If the message can't or shouldn't be formed with a single expression,
  168. the named object of type <tt>logger::record</tt> has to be created, and parts
  169. of the message have to be written to it. The resulting message will be output
  170. to the log by it's destructor:</p>
  171. <code-block lang="C++"><![CDATA[
  172. {
  173. logger::record rec = log.info(); // Begin new record
  174. rec << "List elements: ";
  175. for(auto el : list) rec << el << ", ";
  176. // Constructed record will be printed to the log when the block exits
  177. }
  178. ]]></code-block>
  179. <note>In order to optimize the performace, use the plain functional notation
  180. when the complete message is available:</note>
  181. <code-block lang="C++"><![CDATA[
  182. log.info("Message");
  183. // but not
  184. log.info() << "Message";
  185. ]]></code-block>
  186. <p>Output of the records with the severities DEBUG and TRACE is usually disabled.
  187. Such records will not be published in the log but the program will waste
  188. time to format it. Therefore before creating any debug message using operator
  189. <tt>&lt;&lt;</tt> one should check if debug is enabled using
  190. <tt>debug_visible()</tt> or <tt>trace_visible()</tt> call:</p>
  191. <code-block lang="C++"><![CDATA[
  192. if(log.debug_visible())
  193. log.debug() << ...; // build the message
  194. ]]></code-block>
  195. <p>This advice doesn't cover plain calls <tt>debug(msg)</tt> and
  196. <tt>trace(msg)</tt>, which have a prepared message already and don't perform any
  197. formatting.</p>
  198. <p>To use <tt>logger</tt> one has to implement abstract base class
  199. <tt>logger::output</tt> (override <tt>publish_record()</tt>). The implementation
  200. has to output the passed record somewhere, e.g. to file, terminal or DB. The
  201. output specified during <tt>logger</tt> construction can be replaced later
  202. using <tt>reset_output()</tt>.</p>
  203. <section><title>Class members</title>
  204. <synopsis>
  205. <prototype>severity::trace</prototype>
  206. <prototype>severity::debug</prototype>
  207. <prototype>severity::info</prototype>
  208. <prototype>severity::notice</prototype>
  209. <prototype>severity::warning</prototype>
  210. <prototype>severity::error</prototype>
  211. <prototype>severity::fatal</prototype>
  212. <p>Severity constants. Use this form for both C++11 and C++98 mode.</p>
  213. </synopsis>
  214. <synopsis>
  215. <prototype>typename severity_t</prototype>
  216. <p>Use this identifier as a type name if your code has to be C++98-compatible.
  217. Since C++11 it is just a synonym for <tt>severity</tt>.</p>
  218. </synopsis>
  219. <synopsis>
  220. <prototype>class output</prototype>
  221. <p>Logging back-end interface.</p>
  222. </synopsis>
  223. <synopsis>
  224. <prototype>void output::publish_record(severity_t sev, const char *buf, size_t buf_len)</prototype>
  225. <p>The implementaion of this pure virtual function has to output the content of
  226. <tt>buf</tt> to the log as one record. <tt>buf_len</tt> is the length of
  227. <tt>buf</tt>. The function is always called with <tt>sev >= level()</tt>.
  228. The implementation can rely on it.</p>
  229. </synopsis>
  230. <synopsis>
  231. <prototype>class settings_t</prototype>
  232. <p>Keeps the logger settings: logging level and reference to output
  233. (<tt>level()</tt> + <tt>get_output()</tt>).</p>
  234. </synopsis>
  235. <synopsis>
  236. <prototype>explicit logger(output &amp;out, severity_t level = severity::info)</prototype>
  237. <p>Creates logger with the specified output and logging level. The output object
  238. must outlive the logger object!</p>
  239. <postcondition><tt>this->level() == level &amp;&amp; &amp;this->get_output() == &amp;out</tt></postcondition>
  240. </synopsis>
  241. <synopsis>
  242. <prototype>explicit logger(settings_t s)</prototype>
  243. <p>Creates logger using the specified settings.</p>
  244. </synopsis>
  245. <synopsis>
  246. <prototype>severity_t level() const</prototype>
  247. <p>Returns current logging level.</p>
  248. </synopsis>
  249. <synopsis>
  250. <prototype>void level(severity_t new_level)</prototype>
  251. <p>Sets the logging level.</p>
  252. <postcondition><tt>level() == new_level</tt></postcondition>
  253. </synopsis>
  254. <synopsis>
  255. <prototype>settings_t settings() const</prototype>
  256. <p>Returns current logging settings.</p>
  257. </synopsis>
  258. <synopsis>
  259. <prototype>output &amp;reset_output(output &amp;out)</prototype>
  260. <p>Sets new output and returns the previous one.</p>
  261. <postcondition><tt>&amp;get_output() == &amp;out</tt></postcondition>
  262. </synopsis>
  263. <synopsis>
  264. <prototype>output &amp;get_output()</prototype>
  265. <prototype>const output &amp;get_output() const</prototype>
  266. <p>Returns reference to the current logging output.</p>
  267. </synopsis>
  268. <synopsis>
  269. <prototype>static constexpr size_t min_buffer_size</prototype>
  270. <p>Minimal size of the internal buffer in bytes.</p>
  271. </synopsis>
  272. <synopsis>
  273. <prototype>void shrink_buffer(size_t limit)</prototype>
  274. <p>Sets the internal buffer size to <tt>min_buffer_size</tt> if it is more than
  275. <tt>limit</tt> bytes. Allows to restrict the buffer growth when long records
  276. are formed.</p>
  277. </synopsis>
  278. <synopsis>
  279. <prototype>void message(severity_t severity, const char *msg, size_t msg_len)</prototype>
  280. <prototype>void message(severity_t severity, std::string_view msg) <sign>C++17</sign></prototype>
  281. <prototype>void message(severity_t severity, const char *msg) <sign>until C++17</sign></prototype>
  282. <prototype>void message(severity_t severity, const std::string &amp;msg) <sign>until C++17</sign></prototype>
  283. <p>Writes the message with the specified severity.</p>
  284. </synopsis>
  285. <synopsis>
  286. <prototype>void trace(std::string_view msg) <sign>C++17</sign></prototype>
  287. <prototype>void trace(const char *msg) <sign>until C++17</sign></prototype>
  288. <prototype>void trace(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  289. <prototype>void debug(std::string_view msg) <sign>C++17</sign></prototype>
  290. <prototype>void debug(const char *msg) <sign>until C++17</sign></prototype>
  291. <prototype>void debug(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  292. <prototype>void info(std::string_view msg) <sign>C++17</sign></prototype>
  293. <prototype>void info(const char *msg) <sign>until C++17</sign></prototype>
  294. <prototype>void info(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  295. <prototype>void notice(std::string_view msg) <sign>C++17</sign></prototype>
  296. <prototype>void notice(const char *msg) <sign>until C++17</sign></prototype>
  297. <prototype>void notice(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  298. <prototype>void warning(std::string_view msg) <sign>C++17</sign></prototype>
  299. <prototype>void warning(const char *msg) <sign>until C++17</sign></prototype>
  300. <prototype>void warning(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  301. <prototype>void error(std::string_view msg) <sign>C++17</sign></prototype>
  302. <prototype>void error(const char *msg) <sign>until C++17</sign></prototype>
  303. <prototype>void error(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  304. <prototype>void fatal(std::string_view msg) <sign>C++17</sign></prototype>
  305. <prototype>void fatal(const char *msg) <sign>until C++17</sign></prototype>
  306. <prototype>void fatal(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  307. <p>Writes the message with the corresponding severity.</p>
  308. </synopsis>
  309. <synopsis>
  310. <prototype><![CDATA[template<class... Args>
  311. void format(severity_t s,
  312. std::format_string<Args...> fmt, Args&&... args)]]> <sign>C++20</sign></prototype>
  313. <p>Formats the message using the specified format string and arguments (like
  314. <tt>std::format</tt> does) then writes it with the specified severity.</p>
  315. </synopsis>
  316. <synopsis>
  317. <prototype><![CDATA[template<class Arg1, class... Args>
  318. void trace(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args)]]> <sign>C++20</sign></prototype>
  319. <prototype><![CDATA[template<class Arg1, class... Args>
  320. void debug(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args)]]> <sign>C++20</sign></prototype>
  321. <prototype><![CDATA[template<class Arg1, class... Args>
  322. void info(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args)]]> <sign>C++20</sign></prototype>
  323. <prototype><![CDATA[template<class Arg1, class... Args>
  324. void notice(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args)]]> <sign>C++20</sign></prototype>
  325. <prototype><![CDATA[template<class Arg1, class... Args>
  326. void warning(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args)]]> <sign>C++20</sign></prototype>
  327. <prototype><![CDATA[template<class Arg1, class... Args>
  328. void error(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args)]]> <sign>C++20</sign></prototype>
  329. <prototype><![CDATA[template<class Arg1, class... Args>
  330. void fatal(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args)]]> <sign>C++20</sign></prototype>
  331. <p>Formats the message using the specified format string and arguments (like
  332. <tt>std::format</tt> does) then writes it with the corresponding severity.</p>
  333. </synopsis>
  334. <synopsis>
  335. <prototype>logger::record trace()</prototype>
  336. <prototype>logger::record debug()</prototype>
  337. <prototype>logger::record info()</prototype>
  338. <prototype>logger::record notice()</prototype>
  339. <prototype>logger::record warning()</prototype>
  340. <prototype>logger::record error()</prototype>
  341. <prototype>logger::record fatal()</prototype>
  342. <p>Creates new record with the corresponding severity. Message parts can be
  343. added using operators <tt>&lt;&lt;</tt>.</p>
  344. </synopsis>
  345. <synopsis>
  346. <prototype>bool trace_visible() const</prototype>
  347. <prototype>bool debug_visible() const</prototype>
  348. <prototype>bool info_visible() const</prototype>
  349. <prototype>bool notice_visible() const</prototype>
  350. <prototype>bool warning_visible() const</prototype>
  351. <prototype>bool error_visible() const</prototype>
  352. <prototype>bool fatal_visible() const</prototype>
  353. <p>Returns <tt>true</tt> if a record with the corresponding severity will be
  354. published. Usage of this functions enables to avoid formatting of the
  355. messages which eventually will not be published.</p>
  356. </synopsis>
  357. <synopsis>
  358. <prototype>record::record(logger &amp;log, severity_t sev)</prototype>
  359. <p>Creates the log record with the specified severity. Usually the <tt>logger</tt>'s
  360. functions like <tt>info()</tt> without parameters should be used instead.</p>
  361. </synopsis>
  362. <synopsis>
  363. <prototype>record::~record()</prototype>
  364. <p>Outputs the constructed record to the log.</p>
  365. </synopsis>
  366. <synopsis>
  367. <prototype>record record::append(const char *str, size_t str_len)</prototype>
  368. <p>Appends the string to the message.</p>
  369. </synopsis>
  370. <synopsis>
  371. <prototype>template&lt;class T> record record::operator&lt;&lt;(const T &amp;v)</prototype>
  372. <p>The set of inserters for various data types. Call <tt>sb &lt;&lt; v</tt>
  373. where type of <tt>sb</tt> is <tt>__vic::string_buffer</tt>.</p>
  374. </synopsis>
  375. </section>
  376. <section><title>Free functions</title>
  377. <synopsis>
  378. <prototype>const char *to_string(logger::severity_t s)</prototype>
  379. <prototype>constexpr std::string_view to_string_view(logger::severity s) <sign>C++17</sign></prototype>
  380. <p>Returns text label for the specified severity that can be printed to the
  381. log. For example, <tt>"DEBUG"</tt> will be returned for
  382. <tt>severity::debug</tt>.</p>
  383. </synopsis>
  384. </section>
  385. <section><title>Example</title>
  386. <code-block lang="C++"><![CDATA[
  387. /////////////////////////////////////////////////////////////////////////////
  388. // Output messages to std::clog with the severity label
  389. class coutput : public __vic::logger::output
  390. {
  391. public:
  392. void publish_record(__vic::logger::severity_t s,
  393. const char *rec, size_t rec_n)
  394. {
  395. std::clog << to_string(s) << ": ";
  396. std::clog.write(rec, rec_n) << std::endl;
  397. }
  398. };
  399. /////////////////////////////////////////////////////////////////////////////
  400. int main()
  401. {
  402. coutput log_output:
  403. __vic::logger log(log_output, __vic::logger::severity::debug);
  404. log.info("Application is started");
  405. for(int i = 0; i < 5; i++)
  406. log.debug() << "Loop i = " << i;
  407. log.warning("Application end");
  408. }
  409. ]]></code-block>
  410. <p>Output:</p>
  411. <tty>
  412. INFO: Application is started
  413. DEBUG: Loop i = 0
  414. DEBUG: Loop i = 1
  415. DEBUG: Loop i = 2
  416. DEBUG: Loop i = 3
  417. DEBUG: Loop i = 4
  418. WARNING: Application end
  419. </tty>
  420. </section>
  421. </chapter>
  422. </chapter>