internal_shared.hpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /// Internal shared header file. Not intended for external use.
  2. #pragma once
  3. #include <sys/file.h>
  4. #include "shared.h"
  5. #if __cplusplus >= 201703L
  6. #include <clickhouse/client.h>
  7. #include <clickhouse/exceptions.h>
  8. #endif
  9. #include <fmt/chrono.h>
  10. #include <fmt/core.h>
  11. #include <fmt/format.h>
  12. #include <fmt/std.h>
  13. #include <exception>
  14. #include <iterator>
  15. #include <string>
  16. #include <type_traits>
  17. #include <utility>
  18. namespace tsdb_shared {
  19. static void throw_errno(string_view msg = "errno") {
  20. throw std::runtime_error(fmt::format("{}: {}", msg, strerror(errno)));
  21. }
  22. static void check_errno(bool condition, string_view msg = "errno") {
  23. if (!condition) {
  24. throw_errno(msg);
  25. }
  26. }
  27. /// @brief RAII wrapper for a binary file. Better than std::fstream.
  28. struct bin_file {
  29. bin_file() : file_(nullptr) {}
  30. bin_file(std::nullptr_t) : file_(nullptr) {}
  31. bin_file(const std::string& path, const char* mode) {
  32. file_ = fopen(path.c_str(), mode);
  33. if (!file_) {
  34. throw_errno(fmt::format("Failed to open file `{}` with mode {}", path, mode));
  35. }
  36. }
  37. ~bin_file() {
  38. if (file_) {
  39. // Failures are ignored here
  40. fclose(file_);
  41. }
  42. }
  43. bin_file(const bin_file&) = delete;
  44. bin_file(bin_file&& other) : file_(other.file_) { other.file_ = nullptr; }
  45. bin_file& operator=(bin_file other) {
  46. std::swap(file_, other.file_);
  47. return *this;
  48. }
  49. operator bool() const { return file_ != nullptr; }
  50. void close() {
  51. // NOTE: C++11 does not support std::exchange
  52. auto file = file_;
  53. file_ = nullptr;
  54. if (file) {
  55. // check_errno(fclose(file) == 0, "Failed to close file");
  56. if (fclose(file) != 0) {
  57. fprintf(stderr, "[ERROR] File %p closed with errno=%d\n", (void*)file, errno);
  58. }
  59. }
  60. }
  61. bool is_open() const { return file_ != nullptr; }
  62. size_t tell() const {
  63. auto pos = ftell(file_);
  64. check_errno(pos != -1, "Failed to get file position");
  65. return pos;
  66. }
  67. void seek(ssize_t pos = 0, int whence = SEEK_SET) { check_errno(fseek(file_, pos, whence) == 0, "Failed to seek in file"); }
  68. void rewind() { check_errno(fseek(file_, 0, SEEK_SET) == 0, "Failed to rewind file"); }
  69. size_t read(void* data, size_t size) {
  70. auto count = fread(data, 1, size, file_);
  71. if (ferror(file_)) {
  72. throw_errno("Failed to read from file");
  73. }
  74. return count;
  75. }
  76. void read_exact(void* data, size_t size) { check_errno(fread(data, 1, size, file_) == size, "Failed to read from file"); }
  77. void write(const void* data, size_t size) { check_errno(fwrite(data, 1, size, file_) == size, "Failed to write to file"); }
  78. void flush() { check_errno(fflush(file_) == 0, "Failed to flush file"); }
  79. void lock() { check_errno(flock(fileno(file_), LOCK_EX) == 0, "Failed to lock file"); }
  80. void unlock() { check_errno(flock(fileno(file_), LOCK_UN) == 0, "Failed to unlock file"); }
  81. void try_lock() { check_errno(flock(fileno(file_), LOCK_EX | LOCK_NB) == 0, "Failed to try lock file"); }
  82. private:
  83. FILE* file_;
  84. };
  85. struct tsdb_exception : std::runtime_error {
  86. using std::runtime_error::runtime_error;
  87. tsdb_exception(const std::string& what, std::exception_ptr nested_exception)
  88. : std::runtime_error(what), nested_exception_(nested_exception) {}
  89. std::exception_ptr nested_exception() const noexcept { return nested_exception_; }
  90. private:
  91. std::exception_ptr nested_exception_ = nullptr;
  92. };
  93. struct mylogger {
  94. enum class loglevel { trace, debug, info, warn, error, critical };
  95. mylogger(std::string name) : mylogger(std::move(name), loglevel::info) {}
  96. mylogger(std::string name, loglevel level) : name_(std::move(name)), level_(level) {}
  97. mylogger(std::string name, loglevel level, bin_file log_file, bin_file err_file)
  98. : name_(std::move(name)), level_(level), log_file_(std::move(log_file)), err_file_(std::move(err_file)) {}
  99. static inline string_view to_string(loglevel lvl, bool can_color = false) {
  100. switch (lvl) {
  101. case loglevel::trace:
  102. return can_color ? "\033[37mtrace\033[0m" : "trace"; // white
  103. case loglevel::debug:
  104. return can_color ? "\033[36mdebug\033[0m" : "debug"; // cyan
  105. case loglevel::info:
  106. return can_color ? "\033[32minfo\033[0m" : "info"; // green
  107. case loglevel::warn:
  108. return can_color ? "\033[33mwarn\033[0m" : "warn"; // yellow
  109. case loglevel::error:
  110. return can_color ? "\033[31merror\033[0m" : "error"; // red
  111. case loglevel::critical:
  112. return can_color ? "\033[35mcritical\033[0m" : "critical"; // magenta
  113. default:
  114. return "unknown";
  115. }
  116. }
  117. bool should_log(loglevel lvl) const { return lvl >= level_; }
  118. template <typename... Args>
  119. void trace(fmt::format_string<Args...> fmt, Args&&... args) {
  120. log_(loglevel::trace, fmt, std::forward<Args>(args)...);
  121. }
  122. template <typename... Args>
  123. void debug(fmt::format_string<Args...> fmt, Args&&... args) {
  124. log_(loglevel::debug, fmt, std::forward<Args>(args)...);
  125. }
  126. template <typename... Args>
  127. void info(fmt::format_string<Args...> fmt, Args&&... args) {
  128. log_(loglevel::info, fmt, std::forward<Args>(args)...);
  129. }
  130. template <typename... Args>
  131. void warn(fmt::format_string<Args...> fmt, Args&&... args) {
  132. log_(loglevel::warn, fmt, std::forward<Args>(args)...);
  133. }
  134. template <typename... Args>
  135. void error(fmt::format_string<Args...> fmt, Args&&... args) {
  136. log_(loglevel::error, fmt, std::forward<Args>(args)...);
  137. }
  138. template <typename... Args>
  139. void critical(fmt::format_string<Args...> fmt, Args&&... args) {
  140. log_(loglevel::critical, fmt, std::forward<Args>(args)...);
  141. }
  142. private:
  143. template <typename... Args>
  144. void log_(loglevel lvl, fmt::string_view fmt, Args&&... args) {
  145. if (!should_log(lvl)) {
  146. return;
  147. }
  148. auto now = std::chrono::system_clock::now();
  149. // auto now_time_t = std::chrono::system_clock::to_time_t(now);
  150. // auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
  151. auto msg = fmt::format("[{:%Y-%m-%d %H:%M:%S}] [{}] [{}] ", now, to_string(lvl), name_);
  152. fmt::vformat_to(std::back_insert_iterator<std::string>(msg), fmt, fmt::make_format_args(args...));
  153. msg += '\n';
  154. fprintf(stdout, "%s", msg.c_str());
  155. if (log_file_) {
  156. log_file_.write(msg.data(), msg.size());
  157. log_file_.flush();
  158. }
  159. if (err_file_ && lvl >= loglevel::error) {
  160. err_file_.write(msg.data(), msg.size());
  161. err_file_.flush();
  162. }
  163. }
  164. std::string name_;
  165. loglevel level_ = loglevel::info;
  166. bin_file log_file_;
  167. bin_file err_file_;
  168. };
  169. void init_tsdb_env();
  170. mylogger& logger();
  171. std::string random_uuid();
  172. template <typename F, typename ErrRecoverFn>
  173. typename std::decay<decltype(std::declval<F>()())>::type ex_log_boundary(F&& f, ErrRecoverFn&& err_recover_fn) try {
  174. return f();
  175. #if __cplusplus >= 201703L
  176. } catch (const clickhouse::Error& e) {
  177. logger().error("Unhandled stck exception: {}", e.what());
  178. return err_recover_fn();
  179. // throw tsdb_exception(e.what(), std::current_exception());
  180. #endif
  181. } catch (const std::exception& e) {
  182. logger().error("Unhandled generic exception: {}", e.what());
  183. return err_recover_fn();
  184. // throw;
  185. }
  186. } // namespace tsdb_shared
  187. #if __cplusplus < 201703L
  188. // Support libfmt
  189. template <>
  190. struct fmt::formatter<tsdb_shared::string_view> : formatter<fmt::string_view> {
  191. template <typename FormatContext>
  192. auto format(tsdb_shared::string_view sv, FormatContext& ctx) const -> decltype(ctx.out()) {
  193. return formatter<fmt::string_view>::format(fmt::string_view(sv.data(), sv.size()), ctx);
  194. }
  195. };
  196. #endif
  197. // Preludes
  198. using tsdb_shared::bin_file;
  199. using tsdb_shared::check_errno;
  200. using tsdb_shared::ex_log_boundary;
  201. using tsdb_shared::logger;
  202. using tsdb_shared::throw_errno;