Refactor log code and add log file support

Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
David Shah 2018-11-21 17:08:45 +00:00
parent 01377d3f87
commit b550791d92
5 changed files with 55 additions and 109 deletions

View File

@ -40,7 +40,7 @@
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
CommandHandler::CommandHandler(int argc, char **argv) : argc(argc), argv(argv) { log_files.push_back(stdout); } CommandHandler::CommandHandler(int argc, char **argv) : argc(argc), argv(argv) { log_streams.clear(); }
bool CommandHandler::parseOptions() bool CommandHandler::parseOptions()
{ {
@ -64,14 +64,14 @@ bool CommandHandler::parseOptions()
bool CommandHandler::executeBeforeContext() bool CommandHandler::executeBeforeContext()
{ {
if (vm.count("help") || argc == 1) { if (vm.count("help") || argc == 1) {
std::cout << boost::filesystem::basename(argv[0]) std::cerr << boost::filesystem::basename(argv[0])
<< " -- Next Generation Place and Route (git sha1 " GIT_COMMIT_HASH_STR ")\n"; << " -- Next Generation Place and Route (git sha1 " GIT_COMMIT_HASH_STR ")\n";
std::cout << options << "\n"; std::cerr << options << "\n";
return argc != 1; return argc != 1;
} }
if (vm.count("version")) { if (vm.count("version")) {
std::cout << boost::filesystem::basename(argv[0]) std::cerr << boost::filesystem::basename(argv[0])
<< " -- Next Generation Place and Route (git sha1 " GIT_COMMIT_HASH_STR ")\n"; << " -- Next Generation Place and Route (git sha1 " GIT_COMMIT_HASH_STR ")\n";
return true; return true;
} }
@ -84,7 +84,9 @@ po::options_description CommandHandler::getGeneralOptions()
po::options_description general("General options"); po::options_description general("General options");
general.add_options()("help,h", "show help"); general.add_options()("help,h", "show help");
general.add_options()("verbose,v", "verbose output"); general.add_options()("verbose,v", "verbose output");
general.add_options()("quiet,q", "quiet mode, only errors displayed"); general.add_options()("quiet,q", "quiet mode, only errors and warnings displayed");
general.add_options()("log,l", po::value<std::string>(),
"log file, all log messages are written to this file regardless of -q");
general.add_options()("debug", "debug output"); general.add_options()("debug", "debug output");
general.add_options()("force,f", "keep running after errors"); general.add_options()("force,f", "keep running after errors");
#ifndef NO_GUI #ifndef NO_GUI
@ -128,7 +130,17 @@ void CommandHandler::setupContext(Context *ctx)
} }
if (vm.count("quiet")) { if (vm.count("quiet")) {
log_quiet_warnings = true; log_streams.push_back(std::make_pair(&std::cerr, LogLevel::WARNING));
} else {
log_streams.push_back(std::make_pair(&std::cerr, LogLevel::LOG));
}
if (vm.count("log")) {
std::string logfilename = vm["log"].as<std::string>();
logfile = std::ofstream(logfilename);
if (!logfile)
log_error("Failed to open log file '%s' for writing.\n", logfilename.c_str());
log_streams.push_back(std::make_pair(&logfile, LogLevel::LOG));
} }
if (vm.count("force")) { if (vm.count("force")) {
@ -144,7 +156,7 @@ void CommandHandler::setupContext(Context *ctx)
int r; int r;
do { do {
r = rand(); r = rand();
} while(r == 0); } while (r == 0);
ctx->rngseed(r); ctx->rngseed(r);
} }

View File

@ -66,6 +66,7 @@ class CommandHandler
int argc; int argc;
char **argv; char **argv;
ProjectHandler project; ProjectHandler project;
std::ofstream logfile;
}; };
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -32,18 +32,12 @@ NEXTPNR_NAMESPACE_BEGIN
NPNR_NORETURN void logv_error(const char *format, va_list ap) NPNR_ATTRIBUTE(noreturn); NPNR_NORETURN void logv_error(const char *format, va_list ap) NPNR_ATTRIBUTE(noreturn);
std::vector<FILE *> log_files; std::vector<std::pair<std::ostream *, LogLevel>> log_streams;
std::vector<std::ostream *> log_streams;
FILE *log_errfile = NULL;
log_write_type log_write_function = nullptr; log_write_type log_write_function = nullptr;
bool log_error_stderr = false;
bool log_cmd_error_throw = false;
bool log_quiet_warnings = false;
std::string log_last_error; std::string log_last_error;
void (*log_error_atexit)() = NULL; void (*log_error_atexit)() = NULL;
// static bool next_print_log = false;
static int log_newline_count = 0; static int log_newline_count = 0;
std::string stringf(const char *fmt, ...) std::string stringf(const char *fmt, ...)
@ -88,7 +82,7 @@ std::string vstringf(const char *fmt, va_list ap)
return string; return string;
} }
void logv(const char *format, va_list ap) void logv(const char *format, va_list ap, LogLevel level = LogLevel::LOG)
{ {
// //
// Trim newlines from the beginning // Trim newlines from the beginning
@ -108,90 +102,50 @@ void logv(const char *format, va_list ap)
else else
log_newline_count = str.size() - nnl_pos - 1; log_newline_count = str.size() - nnl_pos - 1;
for (auto f : log_files)
fputs(str.c_str(), f);
for (auto f : log_streams) for (auto f : log_streams)
*f << str; if (f.second <= level)
*f.first << str;
if (log_write_function) if (log_write_function)
log_write_function(str); log_write_function(str);
} }
void logv_info(const char *format, va_list ap) void log_with_level(LogLevel level, const char *format, ...)
{
va_list ap;
va_start(ap, format);
logv(format, ap, level);
va_end(ap);
}
void logv_prefixed(const char *prefix, const char *format, va_list ap, LogLevel level)
{ {
std::string message = vstringf(format, ap); std::string message = vstringf(format, ap);
log_always("Info: %s", message.c_str()); log_with_level(level, "%s%s", prefix, message.c_str());
log_flush(); log_flush();
} }
void logv_warning(const char *format, va_list ap)
{
std::string message = vstringf(format, ap);
log_always("Warning: %s", message.c_str());
log_flush();
}
void logv_warning_noprefix(const char *format, va_list ap)
{
std::string message = vstringf(format, ap);
log_always("%s", message.c_str());
}
void logv_error(const char *format, va_list ap)
{
#ifdef EMSCRIPTEN
auto backup_log_files = log_files;
#endif
if (log_errfile != NULL)
log_files.push_back(log_errfile);
if (log_error_stderr)
for (auto &f : log_files)
if (f == stdout)
f = stderr;
log_last_error = vstringf(format, ap);
log_always("ERROR: %s", log_last_error.c_str());
log_flush();
if (log_error_atexit)
log_error_atexit();
#ifdef EMSCRIPTEN
log_files = backup_log_files;
#endif
throw log_execution_error_exception();
}
void log_always(const char *format, ...) void log_always(const char *format, ...)
{ {
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
logv(format, ap); logv(format, ap, LogLevel::ALWAYS);
va_end(ap); va_end(ap);
} }
void log(const char *format, ...) void log(const char *format, ...)
{ {
if (log_quiet_warnings)
return;
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
logv(format, ap); logv(format, ap, LogLevel::LOG);
va_end(ap); va_end(ap);
} }
void log_info(const char *format, ...) void log_info(const char *format, ...)
{ {
if (log_quiet_warnings)
return;
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
logv_info(format, ap); logv_prefixed("Info: ", format, ap, LogLevel::INFO);
va_end(ap); va_end(ap);
} }
@ -199,15 +153,7 @@ void log_warning(const char *format, ...)
{ {
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
logv_warning(format, ap); logv_prefixed("Warning: ", format, ap, LogLevel::WARNING);
va_end(ap);
}
void log_warning_noprefix(const char *format, ...)
{
va_list ap;
va_start(ap, format);
logv_warning_noprefix(format, ap);
va_end(ap); va_end(ap);
} }
@ -215,41 +161,26 @@ void log_error(const char *format, ...)
{ {
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
logv_error(format, ap); logv_prefixed("ERROR: ", format, ap, LogLevel::ERROR);
}
void log_cmd_error(const char *format, ...) if (log_error_atexit)
{ log_error_atexit();
va_list ap;
va_start(ap, format);
if (log_cmd_error_throw) { throw log_execution_error_exception();
log_last_error = vstringf(format, ap);
log_always("ERROR: %s", log_last_error.c_str());
log_flush();
throw log_cmd_error_exception();
}
logv_error(format, ap);
} }
void log_break() void log_break()
{ {
if (log_quiet_warnings)
return;
if (log_newline_count < 2) if (log_newline_count < 2)
log_always("\n"); log("\n");
if (log_newline_count < 2) if (log_newline_count < 2)
log_always("\n"); log("\n");
} }
void log_flush() void log_flush()
{ {
for (auto f : log_files)
fflush(f);
for (auto f : log_streams) for (auto f : log_streams)
f->flush(); f.first->flush();
} }
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -42,12 +42,18 @@ struct log_execution_error_exception
{ {
}; };
extern std::vector<FILE *> log_files; enum class LogLevel
extern std::vector<std::ostream *> log_streams; {
extern FILE *log_errfile; LOG,
INFO,
WARNING,
ERROR,
ALWAYS
};
extern std::vector<std::pair<std::ostream *, LogLevel>> log_streams;
extern log_write_type log_write_function; extern log_write_type log_write_function;
extern bool log_quiet_warnings;
extern std::string log_last_error; extern std::string log_last_error;
extern void (*log_error_atexit)(); extern void (*log_error_atexit)();
@ -59,9 +65,7 @@ void log(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2));
void log_always(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2)); void log_always(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2));
void log_info(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2)); void log_info(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2));
void log_warning(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2)); void log_warning(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2));
void log_warning_noprefix(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2));
NPNR_NORETURN void log_error(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2), noreturn); NPNR_NORETURN void log_error(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2), noreturn);
NPNR_NORETURN void log_cmd_error(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2), noreturn);
void log_break(); void log_break();
void log_flush(); void log_flush();
@ -75,7 +79,6 @@ static inline void log_assert_worker(bool cond, const char *expr, const char *fi
NEXTPNR_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__) NEXTPNR_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__)
#define log_abort() log_error("Abort in %s:%d.\n", __FILE__, __LINE__) #define log_abort() log_error("Abort in %s:%d.\n", __FILE__, __LINE__)
#define log_ping() log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__)
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -44,7 +44,6 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, ArchArgs args,
initBasenameResource(); initBasenameResource();
qRegisterMetaType<std::string>(); qRegisterMetaType<std::string>();
log_files.clear();
log_streams.clear(); log_streams.clear();
setObjectName("BaseMainWindow"); setObjectName("BaseMainWindow");