diff --git a/include/dwarfs/console_writer.h b/include/dwarfs/console_writer.h index 3c789880..40c04c6b 100644 --- a/include/dwarfs/console_writer.h +++ b/include/dwarfs/console_writer.h @@ -35,7 +35,7 @@ namespace dwarfs { class progress; -class console_writer : public logger { +class console_writer : public stream_logger { public: using get_term_width_type = std::function; @@ -46,25 +46,20 @@ class console_writer : public logger { get_term_width_type get_term_width, level_type threshold, display_mode mode = NORMAL, bool verbose = false); - void write(level_type level, const std::string& output, char const* file, - int line) override; - void update(const progress& p, bool last); private: + void preamble() override; + void postamble() override; + std::string_view get_newline() const override; void rewind(); - std::ostream& os_; - std::mutex mx_; - std::atomic threshold_; std::string statebuf_; double frac_; std::atomic counter_{0}; progress_mode const pg_mode_; get_term_width_type get_term_width_; display_mode const mode_; - bool const color_; - bool const with_context_; bool const debug_progress_; bool writing_{false}; speedometer read_speed_; diff --git a/include/dwarfs/logger.h b/include/dwarfs/logger.h index af50a289..4d882956 100644 --- a/include/dwarfs/logger.h +++ b/include/dwarfs/logger.h @@ -88,9 +88,19 @@ class stream_logger : public logger { void set_threshold(level_type threshold); void set_with_context(bool with_context) { with_context_ = with_context; } + protected: + virtual void preamble(); + virtual void postamble(); + virtual std::string_view get_newline() const; + + std::ostream& log_stream() const { return os_; } + std::mutex& log_mutex() const { return mx_; } + bool log_is_colored() const { return color_; } + level_type log_threshold() const { return threshold_.load(); } + private: std::ostream& os_; - std::mutex mx_; + std::mutex mutable mx_; std::atomic threshold_; bool const color_; bool with_context_; diff --git a/src/dwarfs/console_writer.cpp b/src/dwarfs/console_writer.cpp index 014f38b6..8e427b08 100644 --- a/src/dwarfs/console_writer.cpp +++ b/src/dwarfs/console_writer.cpp @@ -84,22 +84,13 @@ console_writer::console_writer(std::ostream& os, progress_mode pg_mode, get_term_width_type get_term_width, level_type threshold, display_mode mode, bool with_context) - : os_(os) - , threshold_(threshold) + : stream_logger(os, threshold, with_context) , frac_(0.0) , pg_mode_(pg_mode) , get_term_width_(get_term_width) , mode_(mode) - , color_(stream_is_fancy_terminal(os)) - , with_context_(with_context) , debug_progress_(is_debug_progress()) - , read_speed_{std::chrono::seconds(5)} { - if (threshold > level_type::INFO) { - set_policy(); - } else { - set_policy(); - } -} + , read_speed_{std::chrono::seconds(5)} {} void console_writer::rewind() { if (!statebuf_.empty()) { @@ -114,83 +105,34 @@ void console_writer::rewind() { break; } - os_ << '\r'; + auto& os = log_stream(); + + os << '\r'; for (int i = 0; i < lines; ++i) { - os_ << "\x1b[A"; + os << "\x1b[A"; } } } -void console_writer::write(level_type level, const std::string& output, - char const* file, int line) { - if (level <= threshold_) { - auto t = get_current_time_string(); - const char* prefix = ""; - const char* suffix = ""; - const char* newline = pg_mode_ != NONE ? "\x1b[K\n" : "\n"; +void console_writer::preamble() { rewind(); } - if (color_) { - switch (level) { - case ERROR: - prefix = terminal_color(termcolor::BOLD_RED); - suffix = terminal_color(termcolor::NORMAL); - break; - - case WARN: - prefix = terminal_color(termcolor::BOLD_YELLOW); - suffix = terminal_color(termcolor::NORMAL); - break; - - default: - break; - } - } - - char lchar = logger::level_char(level); - std::string context; - size_t context_len = 0; - - if (with_context_ && file) { - context = get_logger_context(file, line); - context_len = context.size(); - if (color_) { - context = folly::to( - suffix, terminal_color(termcolor::MAGENTA), context, - terminal_color(termcolor::NORMAL), prefix); - } - } - - folly::small_vector lines; - folly::split('\n', output, lines); - - if (lines.back().empty()) { - lines.pop_back(); - } - - std::lock_guard lock(mx_); - - rewind(); - - for (auto l : lines) { - os_ << prefix << lchar << ' ' << t << ' ' << context << l << suffix - << newline; - std::fill(t.begin(), t.end(), '.'); - context.assign(context_len, ' '); - } - - if (pg_mode_ == UNICODE || pg_mode_ == ASCII) { - os_ << statebuf_; - } +void console_writer::postamble() { + if (pg_mode_ == UNICODE || pg_mode_ == ASCII) { + log_stream() << statebuf_; } } +std::string_view console_writer::get_newline() const { + return pg_mode_ != NONE ? "\x1b[K\n" : "\n"; +} + void console_writer::update(const progress& p, bool last) { if (pg_mode_ == NONE && !last) { return; } - const char* newline = pg_mode_ != NONE ? "\x1b[K\n" : "\n"; + auto newline = get_newline(); std::ostringstream oss; lazy_value width(get_term_width_); @@ -220,7 +162,7 @@ void console_writer::update(const progress& p, bool last) { if (fancy) { oss << terminal_colored(p.status(width.get()), termcolor::BOLD_CYAN, - color_) + log_is_colored()) << newline; } @@ -282,9 +224,9 @@ void console_writer::update(const progress& p, bool last) { } if (pg_mode_ == NONE) { - if (INFO <= threshold_) { - std::lock_guard lock(mx_); - os_ << oss.str(); + if (INFO <= log_threshold()) { + std::lock_guard lock(log_mutex()); + log_stream() << oss.str(); } return; } @@ -312,12 +254,12 @@ void console_writer::update(const progress& p, bool last) { if (tmp != statebuf_) { auto t = get_current_time_string(); statebuf_ = tmp; - std::lock_guard lock(mx_); - os_ << "- " << t << statebuf_ << "\n"; + std::lock_guard lock(log_mutex()); + log_stream() << "- " << t << statebuf_ << "\n"; } if (last) { - std::lock_guard lock(mx_); - os_ << oss.str(); + std::lock_guard lock(log_mutex()); + log_stream() << oss.str(); } } else { oss << progress_bar(width.get() - 6, frac_, pg_mode_ == UNICODE) @@ -326,13 +268,13 @@ void console_writer::update(const progress& p, bool last) { ++counter_; - std::lock_guard lock(mx_); + std::lock_guard lock(log_mutex()); rewind(); statebuf_ = oss.str(); - os_ << statebuf_; + log_stream() << statebuf_; } } diff --git a/src/dwarfs/logger.cpp b/src/dwarfs/logger.cpp index a07b2e8a..8f36b091 100644 --- a/src/dwarfs/logger.cpp +++ b/src/dwarfs/logger.cpp @@ -70,12 +70,17 @@ stream_logger::stream_logger(std::ostream& os, level_type threshold, set_threshold(threshold); } +void stream_logger::preamble() {} +void stream_logger::postamble() {} +std::string_view stream_logger::get_newline() const { return "\n"; } + void stream_logger::write(level_type level, const std::string& output, char const* file, int line) { if (level <= threshold_) { auto t = get_current_time_string(); const char* prefix = ""; const char* suffix = ""; + auto newline = get_newline(); if (color_) { switch (level) { @@ -130,13 +135,19 @@ void stream_logger::write(level_type level, const std::string& output, } std::lock_guard lock(mx_); + + preamble(); + for (auto l : lines) { os_ << prefix << lchar << ' ' << t << ' ' << context << l << suffix - << "\n"; + << newline; std::fill(t.begin(), t.end(), '.'); context.assign(context_len, ' '); } + postamble(); + + // TODO: this needs to be done differently for console_writer #if DWARFS_SYMBOLIZE if (threshold_ == TRACE) { os_ << printer.str();