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

Allow users to print log output inline

parent 4043f82a
......@@ -272,6 +272,7 @@ public:
std::string logger_console_format;
std::string logger_component_filter;
atom_value logger_verbosity;
bool logger_inline_output;
// -- backward compatibility -------------------------------------------------
......
......@@ -21,6 +21,7 @@
#define CAF_LOGGER_HPP
#include <thread>
#include <fstream>
#include <cstring>
#include <sstream>
#include <iostream>
......@@ -252,6 +253,12 @@ public:
}
private:
void handle_event(event& x);
void log_first_line();
void log_last_line();
logger(actor_system& sys);
void init(actor_system_config& cfg);
......@@ -264,6 +271,7 @@ private:
actor_system& system_;
int level_;
bool inline_output_;
detail::shared_spinlock aids_lock_;
std::unordered_map<std::thread::id, actor_id> aids_;
std::thread thread_;
......@@ -274,6 +282,7 @@ private:
timestamp t0_;
line_format file_format_;
line_format console_format_;
std::fstream file_;
};
std::string to_string(logger::field_type x);
......
......@@ -267,6 +267,7 @@ actor_system::actor_system(actor_system_config& cfg)
// initialize state for each module and give each module the opportunity
// to influence the system configuration, e.g., by adding more types
logger_->init(cfg);
CAF_SET_LOGGER_SYS(this);
for (auto& mod : modules_)
if (mod)
mod->init(cfg);
......
......@@ -128,6 +128,7 @@ actor_system_config::actor_system_config()
logger_console = atom("none");
logger_console_format = "%m";
logger_verbosity = atom("trace");
logger_inline_output = false;
middleman_network_backend = atom("default");
middleman_enable_automatic_connections = false;
middleman_max_consecutive_reads = 50;
......@@ -174,6 +175,8 @@ actor_system_config::actor_system_config()
"exclude all listed components from logging")
.add(logger_verbosity, "verbosity",
"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",
"deprecated (use file-name instead)")
.add(logger_component_filter, "filter",
......
......@@ -165,7 +165,12 @@ actor_id logger::thread_local_aid(actor_id aid) {
void logger::log(event* x) {
CAF_ASSERT(x->level >= 0 && x->level <= 4);
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) {
......@@ -199,14 +204,15 @@ logger::~logger() {
system_.logger_dtor_cv_.notify_one();
}
logger::logger(actor_system& sys) : system_(sys) {
logger::logger(actor_system& sys) : system_(sys), inline_output_(false) {
// nop
}
void logger::init(actor_system_config& cfg) {
CAF_IGNORE_UNUSED(cfg);
#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)) {
case atom_uint("error"):
case atom_uint("ERROR"):
......@@ -368,60 +374,7 @@ logger::line_format logger::parse_format(const char* format_str) {
void logger::run() {
#if defined(CAF_LOG_LEVEL)
t0_ = make_timestamp();
std::fstream file;
if (system_.config().logger_file_name.empty()) {
// No need to continue if console and log file are disabled.
if (!(system_.config().logger_console == atom("UNCOLORED")
|| system_.config().logger_console == atom("COLORED")))
return;
} else {
auto f = system_.config().logger_file_name;
// Replace placeholders.
const char pid[] = "[PID]";
auto i = std::search(f.begin(), f.end(), std::begin(pid),
std::end(pid) - 1);
if (i != f.end()) {
auto id = std::to_string(detail::get_process_id());
f.replace(i, i + sizeof(pid) - 1, id);
}
const char ts[] = "[TIMESTAMP]";
i = std::search(f.begin(), f.end(), std::begin(ts), std::end(ts) - 1);
if (i != f.end()) {
auto t0_str = timestamp_to_string(t0_);
f.replace(i, i + sizeof(ts) - 1, t0_str);
}
const char node[] = "[NODE]";
i = std::search(f.begin(), f.end(), std::begin(node), std::end(node) - 1);
if (i != f.end()) {
auto nid = to_string(system_.node());
f.replace(i, i + sizeof(node) - 1, nid);
}
file.open(f, std::ios::out | std::ios::app);
if (!file) {
std::cerr << "unable to open log file " << f << std::endl;
return;
}
}
if (file) {
// log first entry
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()};
render(file, file_format_, tmp);
}
log_first_line();
// receive log entries from other threads and actors
std::unique_ptr<event> ptr;
for (;;) {
......@@ -431,15 +384,21 @@ void logger::run() {
ptr.reset(queue_.try_pop());
CAF_ASSERT(ptr != nullptr);
// empty message means: shut down
if (ptr->message.empty()) {
if (ptr->message.empty())
break;
handle_event(*ptr);
}
if (file)
render(file, file_format_, *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_, *ptr);
render(std::clog, console_format_, x);
} else if (system_.config().logger_console == atom("COLORED")) {
switch (ptr->level) {
switch (x.level) {
default:
break;
case CAF_LOG_LEVEL_ERROR:
......@@ -458,11 +417,31 @@ void logger::run() {
std::clog << term::blue;
break;
}
render(std::clog, console_format_, *ptr);
render(std::clog, console_format_, x);
std::clog << term::reset_endl;
}
}
if (file) {
}
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,
......@@ -474,9 +453,7 @@ void logger::run() {
std::this_thread::get_id(),
0,
make_timestamp()};
render(file, file_format_, tmp);
}
#endif
handle_event(tmp);
}
void logger::start() {
......@@ -485,12 +462,53 @@ void logger::start() {
auto verbosity = system_.config().logger_verbosity;
if (verbosity == atom("quiet") || verbosity == atom("QUIET"))
return;
t0_ = make_timestamp();
if (system_.config().logger_file_name.empty()) {
// No need to continue if console and log file are disabled.
if (!(system_.config().logger_console == atom("UNCOLORED")
|| system_.config().logger_console == atom("COLORED")))
return;
} else {
auto f = system_.config().logger_file_name;
// Replace placeholders.
const char pid[] = "[PID]";
auto i = std::search(f.begin(), f.end(), std::begin(pid),
std::end(pid) - 1);
if (i != f.end()) {
auto id = std::to_string(detail::get_process_id());
f.replace(i, i + sizeof(pid) - 1, id);
}
const char ts[] = "[TIMESTAMP]";
i = std::search(f.begin(), f.end(), std::begin(ts), std::end(ts) - 1);
if (i != f.end()) {
auto t0_str = timestamp_to_string(t0_);
f.replace(i, i + sizeof(ts) - 1, t0_str);
}
const char node[] = "[NODE]";
i = std::search(f.begin(), f.end(), std::begin(node), std::end(node) - 1);
if (i != f.end()) {
auto nid = to_string(system_.node());
f.replace(i, i + sizeof(node) - 1, nid);
}
file_.open(f, std::ios::out | std::ios::app);
if (!file_) {
std::cerr << "unable to open log file " << f << std::endl;
return;
}
}
if (inline_output_)
log_first_line();
else
thread_ = std::thread{[this] { this->run(); }};
#endif
}
void logger::stop() {
#if defined(CAF_LOG_LEVEL)
if (inline_output_) {
log_last_line();
return;
}
if (!thread_.joinable())
return;
// an empty string means: shut down
......
......@@ -112,8 +112,10 @@ void test_coordinator::stop() {
}
void test_coordinator::enqueue(resumable* ptr) {
CAF_LOG_TRACE("");
if (inline_enqueues_ > 0) {
--inline_enqueues_;
CAF_LOG_DEBUG("inline actor execution, remaining:" << inline_enqueues_);
dummy_worker worker{this};
switch (ptr->resume(&worker, 1)) {
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