logger.h.xml 15 KB

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