Commit 27f564bb authored by Dominik Charousset's avatar Dominik Charousset

Allow users to print log output inline

parent 4043f82a
...@@ -272,6 +272,7 @@ public: ...@@ -272,6 +272,7 @@ public:
std::string logger_console_format; std::string logger_console_format;
std::string logger_component_filter; std::string logger_component_filter;
atom_value logger_verbosity; atom_value logger_verbosity;
bool logger_inline_output;
// -- backward compatibility ------------------------------------------------- // -- backward compatibility -------------------------------------------------
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#define CAF_LOGGER_HPP #define CAF_LOGGER_HPP
#include <thread> #include <thread>
#include <fstream>
#include <cstring> #include <cstring>
#include <sstream> #include <sstream>
#include <iostream> #include <iostream>
...@@ -252,6 +253,12 @@ public: ...@@ -252,6 +253,12 @@ public:
} }
private: private:
void handle_event(event& x);
void log_first_line();
void log_last_line();
logger(actor_system& sys); logger(actor_system& sys);
void init(actor_system_config& cfg); void init(actor_system_config& cfg);
...@@ -264,6 +271,7 @@ private: ...@@ -264,6 +271,7 @@ private:
actor_system& system_; actor_system& system_;
int level_; int level_;
bool inline_output_;
detail::shared_spinlock aids_lock_; detail::shared_spinlock aids_lock_;
std::unordered_map<std::thread::id, actor_id> aids_; std::unordered_map<std::thread::id, actor_id> aids_;
std::thread thread_; std::thread thread_;
...@@ -274,6 +282,7 @@ private: ...@@ -274,6 +282,7 @@ private:
timestamp t0_; timestamp t0_;
line_format file_format_; line_format file_format_;
line_format console_format_; line_format console_format_;
std::fstream file_;
}; };
std::string to_string(logger::field_type x); std::string to_string(logger::field_type x);
......
...@@ -267,6 +267,7 @@ actor_system::actor_system(actor_system_config& cfg) ...@@ -267,6 +267,7 @@ actor_system::actor_system(actor_system_config& cfg)
// initialize state for each module and give each module the opportunity // initialize state for each module and give each module the opportunity
// to influence the system configuration, e.g., by adding more types // to influence the system configuration, e.g., by adding more types
logger_->init(cfg); logger_->init(cfg);
CAF_SET_LOGGER_SYS(this);
for (auto& mod : modules_) for (auto& mod : modules_)
if (mod) if (mod)
mod->init(cfg); mod->init(cfg);
......
...@@ -128,6 +128,7 @@ actor_system_config::actor_system_config() ...@@ -128,6 +128,7 @@ actor_system_config::actor_system_config()
logger_console = atom("none"); logger_console = atom("none");
logger_console_format = "%m"; logger_console_format = "%m";
logger_verbosity = atom("trace"); logger_verbosity = atom("trace");
logger_inline_output = false;
middleman_network_backend = atom("default"); middleman_network_backend = atom("default");
middleman_enable_automatic_connections = false; middleman_enable_automatic_connections = false;
middleman_max_consecutive_reads = 50; middleman_max_consecutive_reads = 50;
...@@ -174,6 +175,8 @@ actor_system_config::actor_system_config() ...@@ -174,6 +175,8 @@ actor_system_config::actor_system_config()
"exclude all listed components from logging") "exclude all listed components from logging")
.add(logger_verbosity, "verbosity", .add(logger_verbosity, "verbosity",
"sets the verbosity (quiet|error|warning|info|debug|trace)") "sets the verbosity (quiet|error|warning|info|debug|trace)")
.add(logger_inline_output, "inline-output",
"sets whether a separate thread is used for I/O")
.add(logger_file_name, "filename", .add(logger_file_name, "filename",
"deprecated (use file-name instead)") "deprecated (use file-name instead)")
.add(logger_component_filter, "filter", .add(logger_component_filter, "filter",
......
...@@ -165,7 +165,12 @@ actor_id logger::thread_local_aid(actor_id aid) { ...@@ -165,7 +165,12 @@ actor_id logger::thread_local_aid(actor_id aid) {
void logger::log(event* x) { void logger::log(event* x) {
CAF_ASSERT(x->level >= 0 && x->level <= 4); CAF_ASSERT(x->level >= 0 && x->level <= 4);
queue_.synchronized_enqueue(queue_mtx_, queue_cv_,x); if (!inline_output_) {
queue_.synchronized_enqueue(queue_mtx_, queue_cv_,x);
} else {
std::unique_ptr<event> ptr{x};
handle_event(*ptr);
}
} }
void logger::set_current_actor_system(actor_system* x) { void logger::set_current_actor_system(actor_system* x) {
...@@ -199,14 +204,15 @@ logger::~logger() { ...@@ -199,14 +204,15 @@ logger::~logger() {
system_.logger_dtor_cv_.notify_one(); system_.logger_dtor_cv_.notify_one();
} }
logger::logger(actor_system& sys) : system_(sys) { logger::logger(actor_system& sys) : system_(sys), inline_output_(false) {
// nop // nop
} }
void logger::init(actor_system_config& cfg) { void logger::init(actor_system_config& cfg) {
CAF_IGNORE_UNUSED(cfg); CAF_IGNORE_UNUSED(cfg);
#if defined(CAF_LOG_LEVEL) #if defined(CAF_LOG_LEVEL)
// Parse the configured log leve. inline_output_ = cfg.logger_inline_output;
// Parse the configured log level.
switch (static_cast<uint64_t>(cfg.logger_verbosity)) { switch (static_cast<uint64_t>(cfg.logger_verbosity)) {
case atom_uint("error"): case atom_uint("error"):
case atom_uint("ERROR"): case atom_uint("ERROR"):
...@@ -368,8 +374,95 @@ logger::line_format logger::parse_format(const char* format_str) { ...@@ -368,8 +374,95 @@ logger::line_format logger::parse_format(const char* format_str) {
void logger::run() { void logger::run() {
#if defined(CAF_LOG_LEVEL) #if defined(CAF_LOG_LEVEL)
log_first_line();
// receive log entries from other threads and actors
std::unique_ptr<event> ptr;
for (;;) {
// make sure we have data to read
queue_.synchronized_await(queue_mtx_, queue_cv_);
// read & process event
ptr.reset(queue_.try_pop());
CAF_ASSERT(ptr != nullptr);
// empty message means: shut down
if (ptr->message.empty())
break;
handle_event(*ptr);
}
log_last_line();
#endif
}
void logger::handle_event(event& x) {
if (file_)
render(file_, file_format_, x);
if (system_.config().logger_console == atom("UNCOLORED")) {
render(std::clog, console_format_, x);
} else if (system_.config().logger_console == atom("COLORED")) {
switch (x.level) {
default:
break;
case CAF_LOG_LEVEL_ERROR:
std::clog << term::red;
break;
case CAF_LOG_LEVEL_WARNING:
std::clog << term::yellow;
break;
case CAF_LOG_LEVEL_INFO:
std::clog << term::green;
break;
case CAF_LOG_LEVEL_DEBUG:
std::clog << term::cyan;
break;
case CAF_LOG_LEVEL_TRACE:
std::clog << term::blue;
break;
}
render(std::clog, console_format_, x);
std::clog << term::reset_endl;
}
}
void logger::log_first_line() {
std::string msg = "level = ";
msg += to_string(system_.config().logger_verbosity);
msg += ", node = ";
msg += to_string(system_.node());
event tmp{nullptr,
nullptr,
CAF_LOG_LEVEL_INFO,
CAF_LOG_COMPONENT,
CAF_PRETTY_FUN,
__FILE__,
__LINE__,
std::move(msg),
std::this_thread::get_id(),
0,
make_timestamp()};
handle_event(tmp);
}
void logger::log_last_line() {
event tmp{nullptr,
nullptr,
CAF_LOG_LEVEL_INFO,
CAF_LOG_COMPONENT,
CAF_PRETTY_FUN,
__FILE__,
__LINE__,
"EOF",
std::this_thread::get_id(),
0,
make_timestamp()};
handle_event(tmp);
}
void logger::start() {
#if defined(CAF_LOG_LEVEL)
parent_thread_ = std::this_thread::get_id();
auto verbosity = system_.config().logger_verbosity;
if (verbosity == atom("quiet") || verbosity == atom("QUIET"))
return;
t0_ = make_timestamp(); t0_ = make_timestamp();
std::fstream file;
if (system_.config().logger_file_name.empty()) { if (system_.config().logger_file_name.empty()) {
// No need to continue if console and log file are disabled. // No need to continue if console and log file are disabled.
if (!(system_.config().logger_console == atom("UNCOLORED") if (!(system_.config().logger_console == atom("UNCOLORED")
...@@ -397,100 +490,25 @@ void logger::run() { ...@@ -397,100 +490,25 @@ void logger::run() {
auto nid = to_string(system_.node()); auto nid = to_string(system_.node());
f.replace(i, i + sizeof(node) - 1, nid); f.replace(i, i + sizeof(node) - 1, nid);
} }
file.open(f, std::ios::out | std::ios::app); file_.open(f, std::ios::out | std::ios::app);
if (!file) { if (!file_) {
std::cerr << "unable to open log file " << f << std::endl; std::cerr << "unable to open log file " << f << std::endl;
return; return;
} }
} }
if (file) { if (inline_output_)
// log first entry log_first_line();
std::string msg = "level = "; else
msg += to_string(system_.config().logger_verbosity); thread_ = std::thread{[this] { this->run(); }};
msg += ", node = ";
msg += to_string(system_.node());
event tmp{nullptr,
nullptr,
CAF_LOG_LEVEL_INFO,
CAF_LOG_COMPONENT,
CAF_PRETTY_FUN,
__FILE__,
__LINE__,
std::move(msg),
std::this_thread::get_id(),
0,
make_timestamp()};
render(file, file_format_, tmp);
}
// receive log entries from other threads and actors
std::unique_ptr<event> ptr;
for (;;) {
// make sure we have data to read
queue_.synchronized_await(queue_mtx_, queue_cv_);
// read & process event
ptr.reset(queue_.try_pop());
CAF_ASSERT(ptr != nullptr);
// empty message means: shut down
if (ptr->message.empty()) {
break;
}
if (file)
render(file, file_format_, *ptr);;
if (system_.config().logger_console == atom("UNCOLORED")) {
render(std::clog, console_format_, *ptr);
} else if (system_.config().logger_console == atom("COLORED")) {
switch (ptr->level) {
default:
break;
case CAF_LOG_LEVEL_ERROR:
std::clog << term::red;
break;
case CAF_LOG_LEVEL_WARNING:
std::clog << term::yellow;
break;
case CAF_LOG_LEVEL_INFO:
std::clog << term::green;
break;
case CAF_LOG_LEVEL_DEBUG:
std::clog << term::cyan;
break;
case CAF_LOG_LEVEL_TRACE:
std::clog << term::blue;
break;
}
render(std::clog, console_format_, *ptr);
std::clog << term::reset_endl;
}
}
if (file) {
event tmp{nullptr,
nullptr,
CAF_LOG_LEVEL_INFO,
CAF_LOG_COMPONENT,
CAF_PRETTY_FUN,
__FILE__,
__LINE__,
"EOF",
std::this_thread::get_id(),
0,
make_timestamp()};
render(file, file_format_, tmp);
}
#endif
}
void logger::start() {
#if defined(CAF_LOG_LEVEL)
parent_thread_ = std::this_thread::get_id();
auto verbosity = system_.config().logger_verbosity;
if (verbosity == atom("quiet") || verbosity == atom("QUIET"))
return;
thread_ = std::thread{[this] { this->run(); }};
#endif #endif
} }
void logger::stop() { void logger::stop() {
#if defined(CAF_LOG_LEVEL) #if defined(CAF_LOG_LEVEL)
if (inline_output_) {
log_last_line();
return;
}
if (!thread_.joinable()) if (!thread_.joinable())
return; return;
// an empty string means: shut down // an empty string means: shut down
......
...@@ -112,8 +112,10 @@ void test_coordinator::stop() { ...@@ -112,8 +112,10 @@ void test_coordinator::stop() {
} }
void test_coordinator::enqueue(resumable* ptr) { void test_coordinator::enqueue(resumable* ptr) {
CAF_LOG_TRACE("");
if (inline_enqueues_ > 0) { if (inline_enqueues_ > 0) {
--inline_enqueues_; --inline_enqueues_;
CAF_LOG_DEBUG("inline actor execution, remaining:" << inline_enqueues_);
dummy_worker worker{this}; dummy_worker worker{this};
switch (ptr->resume(&worker, 1)) { switch (ptr->resume(&worker, 1)) {
case resumable::resume_later: case resumable::resume_later:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment