dinit-log.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. #ifndef DINIT_LOG_H
  2. #define DINIT_LOG_H
  3. // Logging for Dinit.
  4. //
  5. // The main log function is the variadic template 'log' function:
  6. //
  7. // void log(loglevel_t, ...)
  8. //
  9. // It takes a list of items comprising a single log message, including strings (C/C++ style), and integers.
  10. // The loglevel argument determines if the message will actually be logged (according to the configured log
  11. // level of the log mechanisms).
  12. //
  13. // We have two separate log "streams": one for the console/stdout, one for the syslog facility (or log
  14. // file). Both have a circular buffer. Log messages are appended to the circular buffer (for a syslog
  15. // stream, the messages are prepended with a syslog priority indicator). Both streams start out inactive
  16. // (release = true in buffered_log_stream), which means they will buffer messages but not write them.
  17. //
  18. // Service start/stop messages for the console stream are formatted differently, with a "visual" flavour.
  19. // The console stream is treated as informational and in some circumstances messages will be discarded
  20. // from its buffer with no warning.
  21. //
  22. // If a stream buffer becomes full mid-message, the message is discarded and we mark the stream as "message
  23. // discarded". Once the message at the front of the buffer has been fully output we check for the mark and
  24. // if set, issue a message informing that log messages have been discarded, before resuming regular output
  25. // from the buffer. (Because the buffer is full, we can't store the "message discarded" message in it; we
  26. // temporarily switch to a "special buffer" which just contains the "message discarded" text. Current the
  27. // special buffer mechanism is used only for this purpose).
  28. //
  29. // The console log stream needs to be able to release the console, if a service is waiting to acquire it.
  30. // This is accomplished by calling flush_for_release() which then completes the output of the current
  31. // message (if any) and then assigns the console to a waiting service. Once the console is no longer used
  32. // by any service, the service_set will return it to the log; the time between release and re-acquire is
  33. // checked and, if it's too large, the entire buffer is discarded; this avoids suddenly and confusingly
  34. // displaying stale messages.
  35. #include <string>
  36. #include <cstdio>
  37. #include <climits>
  38. class service_set;
  39. enum class loglevel_t {
  40. DEBUG,
  41. NOTICE,
  42. WARN,
  43. ERROR,
  44. ZERO // log absolutely nothing
  45. };
  46. constexpr static int DLOG_MAIN = 0; // main log facility
  47. constexpr static int DLOG_CONS = 1; // console
  48. constexpr static int DLOG_NUM = 2;
  49. // These are defined in dinit-log.cc:
  50. extern loglevel_t log_level[2];
  51. extern bool console_service_status; // show service status messages to console?
  52. void enable_console_log(bool do_enable) noexcept;
  53. void init_log(bool syslog_format);
  54. void setup_log_console_handoff(service_set *sset);
  55. void close_log();
  56. void setup_main_log(int fd);
  57. bool is_log_flushed() noexcept;
  58. void discard_console_log_buffer() noexcept;
  59. // Log a simple string:
  60. void log(loglevel_t lvl, const char *msg) noexcept;
  61. // Log a simple string, optionally without logging to console:
  62. void log(loglevel_t lvl, bool to_cons, const char *msg) noexcept;
  63. // Log a message in parts; a beginnning, various middle parts, and an end part. Calls to these functions
  64. // must not be interleaved with calls to other logging functions.
  65. void log_msg_begin(loglevel_t lvl, const char *msg) noexcept;
  66. void log_msg_part(const char *msg) noexcept;
  67. void log_msg_end(const char *msg) noexcept;
  68. void log_service_started(const char *service_name) noexcept;
  69. void log_service_failed(const char *service_name, bool dep_failed) noexcept;
  70. void log_service_stopped(const char *service_name) noexcept;
  71. // Convenience methods which perform type conversion of the argument.
  72. static inline void log(loglevel_t lvl, const std::string &str) noexcept
  73. {
  74. log(lvl, str.c_str());
  75. }
  76. static inline void log_msg_begin(loglevel_t lvl, const std::string &str) noexcept
  77. {
  78. log_msg_begin(lvl, str.c_str());
  79. }
  80. static inline void log_msg_begin(loglevel_t lvl, int a) noexcept
  81. {
  82. constexpr int bufsz = (CHAR_BIT * sizeof(int) - 1) / 3 + 2;
  83. char nbuf[bufsz];
  84. snprintf(nbuf, bufsz, "%d", a);
  85. log_msg_begin(lvl, nbuf);
  86. }
  87. static inline void log_msg_part(const std::string &str) noexcept
  88. {
  89. log_msg_part(str.c_str());
  90. }
  91. static inline void log_msg_part(int a) noexcept
  92. {
  93. constexpr int bufsz = (CHAR_BIT * sizeof(int) - 1) / 3 + 2;
  94. char nbuf[bufsz];
  95. snprintf(nbuf, bufsz, "%d", a);
  96. log_msg_part(nbuf);
  97. }
  98. static inline void log_msg_end(const std::string &str) noexcept
  99. {
  100. log_msg_end(str.c_str());
  101. }
  102. static inline void log_msg_end(int a) noexcept
  103. {
  104. constexpr int bufsz = (CHAR_BIT * sizeof(int) - 1) / 3 + 2;
  105. char nbuf[bufsz];
  106. snprintf(nbuf, bufsz, "%d", a);
  107. log_msg_end(nbuf);
  108. }
  109. static inline void log_service_started(const std::string &str) noexcept
  110. {
  111. log_service_started(str.c_str());
  112. }
  113. static inline void log_service_failed(const std::string &str, bool dep_failed) noexcept
  114. {
  115. log_service_failed(str.c_str(), dep_failed);
  116. }
  117. static inline void log_service_stopped(const std::string &str) noexcept
  118. {
  119. log_service_stopped(str.c_str());
  120. }
  121. // It's not intended that methods in this namespace be called directly from outside the logging
  122. // subsystem:
  123. namespace dinit_log {
  124. template <typename A> static inline void log_parts(const A &a) noexcept
  125. {
  126. log_msg_end(a);
  127. }
  128. template <typename A, typename ...B> static inline void log_parts(const A &a, const B & ...b) noexcept
  129. {
  130. log_msg_part(a);
  131. log_parts(b...);
  132. }
  133. }
  134. // Variadic 'log' method.
  135. template <typename A, typename ...B> static inline void log(loglevel_t lvl, const A &a, const B & ...b) noexcept
  136. {
  137. log_msg_begin(lvl, a);
  138. dinit_log::log_parts(b...);
  139. }
  140. #endif