123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- /// Internal shared header file. Not intended for external use.
- #pragma once
- #include <sys/file.h>
- #include "shared.h"
- #if __cplusplus >= 201703L
- #include <clickhouse/client.h>
- #include <clickhouse/exceptions.h>
- #endif
- #include <fmt/chrono.h>
- #include <fmt/core.h>
- #include <fmt/format.h>
- #include <fmt/std.h>
- #include <exception>
- #include <iterator>
- #include <string>
- #include <type_traits>
- #include <utility>
- namespace tsdb_shared {
- static void throw_errno(string_view msg = "errno") {
- throw std::runtime_error(fmt::format("{}: {}", msg, strerror(errno)));
- }
- static void check_errno(bool condition, string_view msg = "errno") {
- if (!condition) {
- throw_errno(msg);
- }
- }
- /// @brief RAII wrapper for a binary file. Better than std::fstream.
- struct bin_file {
- bin_file() : file_(nullptr) {}
- bin_file(std::nullptr_t) : file_(nullptr) {}
- bin_file(const std::string& path, const char* mode) {
- file_ = fopen(path.c_str(), mode);
- if (!file_) {
- throw_errno(fmt::format("Failed to open file `{}` with mode {}", path, mode));
- }
- }
- ~bin_file() {
- if (file_) {
- // Failures are ignored here
- fclose(file_);
- }
- }
- bin_file(const bin_file&) = delete;
- bin_file(bin_file&& other) : file_(other.file_) { other.file_ = nullptr; }
- bin_file& operator=(bin_file other) {
- std::swap(file_, other.file_);
- return *this;
- }
- operator bool() const { return file_ != nullptr; }
- void close() {
- // NOTE: C++11 does not support std::exchange
- auto file = file_;
- file_ = nullptr;
- if (file) {
- // check_errno(fclose(file) == 0, "Failed to close file");
- if (fclose(file) != 0) {
- fprintf(stderr, "[ERROR] File %p closed with errno=%d\n", (void*)file, errno);
- }
- }
- }
- bool is_open() const { return file_ != nullptr; }
- size_t tell() const {
- auto pos = ftell(file_);
- check_errno(pos != -1, "Failed to get file position");
- return pos;
- }
- void seek(ssize_t pos = 0, int whence = SEEK_SET) { check_errno(fseek(file_, pos, whence) == 0, "Failed to seek in file"); }
- void rewind() { check_errno(fseek(file_, 0, SEEK_SET) == 0, "Failed to rewind file"); }
- size_t read(void* data, size_t size) {
- auto count = fread(data, 1, size, file_);
- if (ferror(file_)) {
- throw_errno("Failed to read from file");
- }
- return count;
- }
- void read_exact(void* data, size_t size) { check_errno(fread(data, 1, size, file_) == size, "Failed to read from file"); }
- void write(const void* data, size_t size) { check_errno(fwrite(data, 1, size, file_) == size, "Failed to write to file"); }
- void flush() { check_errno(fflush(file_) == 0, "Failed to flush file"); }
- void lock() { check_errno(flock(fileno(file_), LOCK_EX) == 0, "Failed to lock file"); }
- void unlock() { check_errno(flock(fileno(file_), LOCK_UN) == 0, "Failed to unlock file"); }
- void try_lock() { check_errno(flock(fileno(file_), LOCK_EX | LOCK_NB) == 0, "Failed to try lock file"); }
- private:
- FILE* file_;
- };
- struct tsdb_exception : std::runtime_error {
- using std::runtime_error::runtime_error;
- tsdb_exception(const std::string& what, std::exception_ptr nested_exception)
- : std::runtime_error(what), nested_exception_(nested_exception) {}
- std::exception_ptr nested_exception() const noexcept { return nested_exception_; }
- private:
- std::exception_ptr nested_exception_ = nullptr;
- };
- struct mylogger {
- enum class loglevel { trace, debug, info, warn, error, critical };
- mylogger(std::string name) : mylogger(std::move(name), loglevel::info) {}
- mylogger(std::string name, loglevel level) : name_(std::move(name)), level_(level) {}
- mylogger(std::string name, loglevel level, bin_file log_file, bin_file err_file)
- : name_(std::move(name)), level_(level), log_file_(std::move(log_file)), err_file_(std::move(err_file)) {}
- static inline string_view to_string(loglevel lvl, bool can_color = false) {
- switch (lvl) {
- case loglevel::trace:
- return can_color ? "\033[37mtrace\033[0m" : "trace"; // white
- case loglevel::debug:
- return can_color ? "\033[36mdebug\033[0m" : "debug"; // cyan
- case loglevel::info:
- return can_color ? "\033[32minfo\033[0m" : "info"; // green
- case loglevel::warn:
- return can_color ? "\033[33mwarn\033[0m" : "warn"; // yellow
- case loglevel::error:
- return can_color ? "\033[31merror\033[0m" : "error"; // red
- case loglevel::critical:
- return can_color ? "\033[35mcritical\033[0m" : "critical"; // magenta
- default:
- return "unknown";
- }
- }
- bool should_log(loglevel lvl) const { return lvl >= level_; }
- template <typename... Args>
- void trace(fmt::format_string<Args...> fmt, Args&&... args) {
- log_(loglevel::trace, fmt, std::forward<Args>(args)...);
- }
- template <typename... Args>
- void debug(fmt::format_string<Args...> fmt, Args&&... args) {
- log_(loglevel::debug, fmt, std::forward<Args>(args)...);
- }
- template <typename... Args>
- void info(fmt::format_string<Args...> fmt, Args&&... args) {
- log_(loglevel::info, fmt, std::forward<Args>(args)...);
- }
- template <typename... Args>
- void warn(fmt::format_string<Args...> fmt, Args&&... args) {
- log_(loglevel::warn, fmt, std::forward<Args>(args)...);
- }
- template <typename... Args>
- void error(fmt::format_string<Args...> fmt, Args&&... args) {
- log_(loglevel::error, fmt, std::forward<Args>(args)...);
- }
- template <typename... Args>
- void critical(fmt::format_string<Args...> fmt, Args&&... args) {
- log_(loglevel::critical, fmt, std::forward<Args>(args)...);
- }
- private:
- template <typename... Args>
- void log_(loglevel lvl, fmt::string_view fmt, Args&&... args) {
- if (!should_log(lvl)) {
- return;
- }
- auto now = std::chrono::system_clock::now();
- // auto now_time_t = std::chrono::system_clock::to_time_t(now);
- // auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
- auto msg = fmt::format("[{:%Y-%m-%d %H:%M:%S}] [{}] [{}] ", now, to_string(lvl), name_);
- fmt::vformat_to(std::back_insert_iterator<std::string>(msg), fmt, fmt::make_format_args(args...));
- msg += '\n';
- fprintf(stdout, "%s", msg.c_str());
- if (log_file_) {
- log_file_.write(msg.data(), msg.size());
- log_file_.flush();
- }
- if (err_file_ && lvl >= loglevel::error) {
- err_file_.write(msg.data(), msg.size());
- err_file_.flush();
- }
- }
- std::string name_;
- loglevel level_ = loglevel::info;
- bin_file log_file_;
- bin_file err_file_;
- };
- void init_tsdb_env();
- mylogger& logger();
- std::string random_uuid();
- template <typename F, typename ErrRecoverFn>
- typename std::decay<decltype(std::declval<F>()())>::type ex_log_boundary(F&& f, ErrRecoverFn&& err_recover_fn) try {
- return f();
- #if __cplusplus >= 201703L
- } catch (const clickhouse::Error& e) {
- logger().error("Unhandled stck exception: {}", e.what());
- return err_recover_fn();
- // throw tsdb_exception(e.what(), std::current_exception());
- #endif
- } catch (const std::exception& e) {
- logger().error("Unhandled generic exception: {}", e.what());
- return err_recover_fn();
- // throw;
- }
- } // namespace tsdb_shared
- #if __cplusplus < 201703L
- // Support libfmt
- template <>
- struct fmt::formatter<tsdb_shared::string_view> : formatter<fmt::string_view> {
- template <typename FormatContext>
- auto format(tsdb_shared::string_view sv, FormatContext& ctx) const -> decltype(ctx.out()) {
- return formatter<fmt::string_view>::format(fmt::string_view(sv.data(), sv.size()), ctx);
- }
- };
- #endif
- // Preludes
- using tsdb_shared::bin_file;
- using tsdb_shared::check_errno;
- using tsdb_shared::ex_log_boundary;
- using tsdb_shared::logger;
- using tsdb_shared::throw_errno;
|