blob: 1f779c951b5faee65bb56c32cfdf02db02399c6d [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "status.h"
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#include <memory>
#include <string>
#include <utility>
#include "src/lib/fxl/strings/string_printf.h"
#include "util.h"
namespace hwstress {
LogLevel LogLevelFromString(const std::string& value) {
std::string value_lower(value);
std::for_each(value_lower.begin(), value_lower.end(), [](char& c) { c = std::tolower(c); });
if (value_lower == "terse") {
return LogLevel::kTerse;
}
if (value_lower == "normal") {
return LogLevel::kNormal;
}
if (value_lower == "verbose") {
return LogLevel::kVerbose;
}
return LogLevel::kInvalid;
}
namespace {
// Return a copy of |s| with newlines stripped from it.
std::string StripNewlines(std::string_view s) {
std::string result;
result.reserve(s.size());
for (size_t i = 0; i < s.size(); i++) {
if (s[i] != '\n') {
result.push_back(s[i]);
}
}
return result;
}
} // namespace
StatusLine::StatusLine(LogLevel level) : log_level_(level) {}
void StatusLine::Log(std::string_view s) {
if (log_level_ == LogLevel::kTerse) {
return;
}
// Remove any status already on the current line.
ClearLineIfNeeded();
// Log the current line, adding a trailing newline if needed.
printf("%*s", static_cast<int>(s.size()), s.data());
if (s.back() != '\n') {
printf("\n");
}
fflush(stdout);
// Re-display the current status.
PrintStatus();
}
void StatusLine::Log(const char* fmt, va_list ap) {
std::string s = fxl::StringVPrintf(fmt, ap);
Log(std::string_view(s.data(), s.size()));
}
void StatusLine::Log(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
Log(fmt, ap);
va_end(ap);
}
void StatusLine::Set(std::string_view status) {
// If the new value matches the old, we have nothing to do.
if (status == current_status_ || log_level_ == LogLevel::kTerse) {
return;
}
// Otherwise, clear off the old status and print out the new.
ClearLineIfNeeded();
current_status_ = StripNewlines(status);
PrintStatus();
}
void StatusLine::Set(const char* fmt, va_list ap) {
std::string s = fxl::StringVPrintf(fmt, ap);
Set(std::string_view(s.data(), s.size()));
}
void StatusLine::Set(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
Set(fmt, ap);
va_end(ap);
}
void StatusLine::Verbose(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
if (log_level_ == LogLevel::kVerbose) {
Log(fmt, ap);
}
va_end(ap);
}
void StatusLine::Verbose(std::string_view status) {
if (log_level_ == LogLevel::kVerbose) {
Log(status);
}
}
// Remove the status line from the console.
void StatusLine::ClearLineIfNeeded() {
if (!line_needs_clear_) {
return;
}
// "\r" and ANSI escape code for clearing the current line.
printf("\r\033[2K");
line_needs_clear_ = false;
}
// Print |current_status_| to the console.
void StatusLine::PrintStatus() {
if (current_status_.empty()) {
return;
}
printf("%s", current_status_.c_str());
fflush(stdout);
line_needs_clear_ = true;
}
} // namespace hwstress