Commit 9860e195 authored by Dominik Charousset's avatar Dominik Charousset

SE-0001: Restructure logging and add cav-vec tool

parent 7e027c3d
......@@ -20,6 +20,7 @@
#ifndef CAF_ACTOR_CONFIG_HPP
#define CAF_ACTOR_CONFIG_HPP
#include <string>
#include <functional>
#include "caf/fwd.hpp"
......@@ -28,6 +29,7 @@
namespace caf {
/// Stores spawn-time flags and groups.
class actor_config {
public:
execution_unit* host;
......@@ -35,12 +37,7 @@ public:
input_range<const group>* groups;
std::function<behavior (local_actor*)> init_fun;
explicit actor_config(execution_unit* ptr = nullptr)
: host(ptr),
flags(abstract_channel::is_abstract_actor_flag),
groups(nullptr) {
// nop
}
explicit actor_config(execution_unit* ptr = nullptr);
inline actor_config& add_flag(int x) {
flags |= x;
......@@ -48,6 +45,9 @@ public:
}
};
/// @relates actor_config
std::string to_string(const actor_config& x);
} // namespace caf
#endif // CAF_ACTOR_CONFIG_HPP
......@@ -122,8 +122,9 @@ std::string get_rtti_from_mpi(const uniform_type_info_map& types) {
/// such as a middleman.
class actor_system {
public:
friend class abstract_actor;
friend class logger;
friend class io::middleman;
friend class abstract_actor;
actor_system() = delete;
actor_system(const actor_system&) = delete;
......@@ -407,8 +408,8 @@ public:
template <spawn_options Os = no_spawn_options, class F, class... Ts>
infer_handle_from_fun_t<F>
spawn_in_group(const group& grp, F fun, Ts&&... xs) {
return spawn_fun_in_groups<Os>({grp}, std::move(fun),
std::forward<Ts>(xs)...);
return spawn_in_groups<Os>({grp}, std::move(fun),
std::forward<Ts>(xs)...);
}
/// Returns a new class-based actor subscribed to all groups in `gs`.
......@@ -492,10 +493,9 @@ private:
cfg.flags |= abstract_actor::is_detached_flag;
if (!cfg.host)
cfg.host = dummy_execution_unit();
CAF_SET_LOGGER_SYS(this);
auto res = make_actor<C>(next_actor_id(), node(), this,
cfg, std::forward<Ts>(xs)...);
CAF_SET_LOGGER_SYS(this);
CAF_LOG_DEBUG("spawned actor:" << CAF_ARG(res.id()));
CAF_PUSH_AID(res->id());
auto ptr = static_cast<C*>(actor_cast<abstract_actor*>(res));
ptr->launch(cfg.host, has_lazy_init_flag(Os), has_hide_flag(Os));
......@@ -505,7 +505,7 @@ private:
std::atomic<size_t> ids_;
uniform_type_info_map types_;
node_id node_;
caf::logger logger_;
intrusive_ptr<caf::logger> logger_;
actor_registry registry_;
group_manager groups_;
module_array modules_;
......@@ -519,6 +519,9 @@ private:
mutable std::mutex detached_mtx;
mutable std::condition_variable detached_cv;
actor_system_config& cfg_;
std::mutex logger_dtor_mtx_;
std::condition_variable logger_dtor_cv_;
volatile bool logger_dtor_done_;
};
} // namespace caf
......
......@@ -102,7 +102,8 @@ public:
/// Picks up user-defined `to_string` functions.
template <class T>
enable_if_tt<has_to_string<T>> consume(T& x) {
enable_if_t<!std::is_pointer<T>::value && has_to_string<T>::value>
consume(T& x) {
result_ += to_string(x);
}
......
......@@ -185,7 +185,7 @@ public:
/// Sends an exit message to `dest`.
template <class ActorHandle>
void send_exit(const ActorHandle& dest, error reason) {
dest->eq_impl(message_id::make(), nullptr, context(),
dest->eq_impl(message_id::make(), ctrl(), context(),
exit_msg{address(), std::move(reason)});
}
......
......@@ -31,6 +31,7 @@
#include "caf/fwd.hpp"
#include "caf/config.hpp"
#include "caf/unifyn.hpp"
#include "caf/ref_counted.hpp"
#include "caf/abstract_actor.hpp"
#include "caf/deep_to_string.hpp"
......@@ -57,7 +58,7 @@ namespace caf {
/// Centrally logs events from all actors in an actor system. To enable
/// logging in your application, you need to define `CAF_LOG_LEVEL`. Per
/// default, the logger generates log4j compatible output.
class logger {
class logger : public ref_counted {
public:
friend class actor_system;
......@@ -96,9 +97,7 @@ public:
line_builder& operator<<(const T& x) {
if (!str_.empty())
str_ += " ";
std::stringstream ss;
ss << x;
str_ += ss.str();
str_ += deep_to_string(x);
behind_arg_ = false;
return *this;
}
......@@ -170,6 +169,10 @@ private:
void stop();
void log_prefix(std::ostream& out, int level, const char* component,
const std::string& class_name, const char* function_name,
const char* file_name, int line_num);
actor_system& system_;
int level_;
detail::shared_spinlock aids_lock_;
......@@ -322,4 +325,41 @@ inline caf::actor_id caf_set_aid_dummy() { return 0; }
#endif // CAF_LOG_LEVEL
// -- Standardized CAF events according to SE-0001.
#define CAF_LOG_SPAWN_EVENT(aid, aargs) \
CAF_LOG_DEBUG("SPAWN ; ID =" << aid \
<< "; ARGS =" << deep_to_string(aargs).c_str())
#define CAF_LOG_INIT_EVENT(aName, aLazy, aHide) \
CAF_LOG_DEBUG("INIT ; NAME =" << aName << "; LAZY =" << aLazy \
<< "; HIDDEN =" << aHide)
/// Logs
#define CAF_LOG_SEND_EVENT(ptr) \
CAF_LOG_DEBUG("SEND ; TO =" \
<< deep_to_string(strong_actor_ptr{this->ctrl()}).c_str() \
<< "; FROM =" << deep_to_string(ptr->sender).c_str() \
<< "; STAGES =" << deep_to_string(ptr->stages).c_str() \
<< "; CONTENT =" << deep_to_string(ptr->content()).c_str())
#define CAF_LOG_RECEIVE_EVENT(ptr) \
CAF_LOG_DEBUG("RECEIVE ; FROM =" \
<< deep_to_string(ptr->sender).c_str() \
<< "; STAGES =" << deep_to_string(ptr->stages).c_str() \
<< "; CONTENT =" << deep_to_string(ptr->content()).c_str())
#define CAF_LOG_REJECT_EVENT() CAF_LOG_DEBUG("REJECT")
#define CAF_LOG_ACCEPT_EVENT() CAF_LOG_DEBUG("ACCEPT")
#define CAF_LOG_DROP_EVENT() CAF_LOG_DEBUG("DROP")
#define CAF_LOG_SKIP_EVENT() CAF_LOG_DEBUG("SKIP")
#define CAF_LOG_FINALIZE_EVENT() CAF_LOG_DEBUG("FINALIZE")
#define CAF_LOG_TERMINATE_EVENT(rsn) \
CAF_LOG_DEBUG("TERMINATE ; REASON =" << deep_to_string(rsn).c_str());
#endif // CAF_LOGGER_HPP
......@@ -23,6 +23,7 @@
#include <type_traits>
#include "caf/fwd.hpp"
#include "caf/logger.hpp"
#include "caf/ref_counted.hpp"
#include "caf/infer_handle.hpp"
#include "caf/intrusive_ptr.hpp"
......@@ -33,6 +34,7 @@ namespace caf {
template <class T, class R = infer_handle_from_class_t<T>, class... Ts>
R make_actor(actor_id aid, node_id nid, actor_system* sys, Ts&&... xs) {
CAF_LOG_SPAWN_EVENT(aid, std::forward_as_tuple(xs...));
auto ptr = new actor_storage<T>(aid, std::move(nid), sys,
std::forward<Ts>(xs)...);
return {&(ptr->ctrl), false};
......
......@@ -70,12 +70,10 @@ protected:
}
void stop() override {
CAF_LOG_TRACE("");
// shutdown workers
class shutdown_helper : public resumable, public ref_counted {
public:
resumable::resume_result resume(execution_unit* ptr, size_t) override {
CAF_LOG_DEBUG("shutdown_helper::resume => shutdown worker");
CAF_ASSERT(ptr != nullptr);
std::unique_lock<std::mutex> guard(mtx);
last_worker = ptr;
......@@ -104,7 +102,6 @@ protected:
alive_workers.insert(worker_by_id(i));
sh.ref(); // make sure reference count is high enough
}
CAF_LOG_DEBUG("enqueue shutdown_helper into each worker");
while (!alive_workers.empty()) {
(*alive_workers.begin())->external_enqueue(&sh);
// since jobs can be stolen, we cannot assume that we have
......
......@@ -55,7 +55,6 @@ public:
CAF_ASSERT(this_thread_.get_id() == std::thread::id{});
auto this_worker = this;
this_thread_ = std::thread{[this_worker] {
CAF_LOG_TRACE(CAF_ARG(this_worker->id()));
this_worker->run();
}};
}
......@@ -67,7 +66,6 @@ public:
/// source, i.e., from any other thread.
void external_enqueue(job_ptr job) {
CAF_ASSERT(job != nullptr);
CAF_LOG_TRACE(CAF_ARG(id()) << CAF_ARG(id_of(job)));
policy_.external_enqueue(this, job);
}
......@@ -76,7 +74,6 @@ public:
/// @warning Must not be called from other threads.
void exec_later(job_ptr job) override {
CAF_ASSERT(job != nullptr);
CAF_LOG_TRACE(CAF_ARG(id()) << CAF_ARG(id_of(job)));
policy_.internal_enqueue(this, job);
}
......@@ -109,13 +106,11 @@ public:
private:
void run() {
CAF_SET_LOGGER_SYS(&system());
CAF_LOG_TRACE(CAF_ARG(id_));
// scheduling loop
for (;;) {
auto job = policy_.dequeue(this);
CAF_ASSERT(job != nullptr);
CAF_ASSERT(job->subtype() != resumable::io_actor);
CAF_LOG_DEBUG("resume actor:" << CAF_ARG(id_of(job)));
CAF_PUSH_AID_FROM_PTR(dynamic_cast<abstract_actor*>(job));
policy_.before_resume(this, job);
auto res = job->resume(this, max_throughput_);
......
......@@ -83,6 +83,7 @@ void anon_send(const Dest& dest, Ts&&... xs) {
/// Anonymously sends `dest` an exit message.
template <class Dest>
void anon_send_exit(const Dest& dest, exit_reason reason) {
CAF_LOG_TRACE(CAF_ARG(dest) << CAF_ARG(reason));
if (dest)
dest->enqueue(nullptr, message_id::make(),
make_message(exit_msg{dest->address(), reason}), nullptr);
......
......@@ -131,7 +131,16 @@ void replace_all(std::string& str,
template<size_t S>
bool starts_with(const std::string& str, const char (&prefix)[S]) {
return str.compare(0, S, prefix) == 0;
return str.compare(0, S - 1, prefix) == 0;
}
template <size_t S>
bool ends_with(const std::string& str, const char (&suffix)[S]) {
auto n = str.size();
auto m = S - 1;
if (n >= m)
return str.compare(n - m, m, suffix) == 0;
return false;
}
template <class T>
......
......@@ -127,6 +127,10 @@ public:
}
}
}
const char* name() const override {
return "timer_actor";
}
};
using string_sink = std::function<void (std::string&&)>;
......@@ -222,77 +226,88 @@ sink_handle get_sink_handle(actor_system& sys, sink_cache& fc,
return {};
}
void printer_loop(blocking_actor* self) {
struct actor_data {
std::string current_line;
sink_handle redirect;
actor_data() {
// nop
}
};
using data_map = std::unordered_map<actor_id, actor_data>;
sink_cache fcache;
sink_handle global_redirect;
data_map data;
auto get_data = [&](actor_id addr, bool insert_missing) -> actor_data* {
if (addr == invalid_actor_id)
class printer_actor : public blocking_actor {
public:
printer_actor(actor_config& cfg) : blocking_actor(cfg) {
// nop
}
void act() override {
struct actor_data {
std::string current_line;
sink_handle redirect;
actor_data() {
// nop
}
};
using data_map = std::unordered_map<actor_id, actor_data>;
sink_cache fcache;
sink_handle global_redirect;
data_map data;
auto get_data = [&](actor_id addr, bool insert_missing) -> actor_data* {
if (addr == invalid_actor_id)
return nullptr;
auto i = data.find(addr);
if (i == data.end() && insert_missing)
i = data.emplace(addr, actor_data{}).first;
if (i != data.end())
return &(i->second);
return nullptr;
auto i = data.find(addr);
if (i == data.end() && insert_missing)
i = data.emplace(addr, actor_data{}).first;
if (i != data.end())
return &(i->second);
return nullptr;
};
auto flush = [&](actor_data* what, bool forced) {
if (!what)
return;
auto& line = what->current_line;
if (line.empty() || (line.back() != '\n' && !forced))
return;
if (what->redirect)
(*what->redirect)(std::move(line));
else if (global_redirect)
(*global_redirect)(std::move(line));
else
std::cout << line << std::flush;
line.clear();
};
bool done = false;
self->do_receive(
[&](add_atom, actor_id aid, std::string& str) {
if (str.empty() || aid == invalid_actor_id)
};
auto flush = [&](actor_data* what, bool forced) {
if (!what)
return;
auto d = get_data(aid, true);
if (d) {
d->current_line += str;
flush(d, false);
}
},
[&](flush_atom, actor_id aid) {
flush(get_data(aid, false), true);
},
[&](delete_atom, actor_id aid) {
auto data_ptr = get_data(aid, false);
if (data_ptr) {
flush(data_ptr, true);
data.erase(aid);
auto& line = what->current_line;
if (line.empty() || (line.back() != '\n' && !forced))
return;
if (what->redirect)
(*what->redirect)(std::move(line));
else if (global_redirect)
(*global_redirect)(std::move(line));
else
std::cout << line << std::flush;
line.clear();
};
bool done = false;
do_receive(
[&](add_atom, actor_id aid, std::string& str) {
if (str.empty() || aid == invalid_actor_id)
return;
auto d = get_data(aid, true);
if (d) {
d->current_line += str;
flush(d, false);
}
},
[&](flush_atom, actor_id aid) {
flush(get_data(aid, false), true);
},
[&](delete_atom, actor_id aid) {
auto data_ptr = get_data(aid, false);
if (data_ptr) {
flush(data_ptr, true);
data.erase(aid);
}
},
[&](redirect_atom, const std::string& fn, int flag) {
global_redirect = get_sink_handle(system(), fcache, fn, flag);
},
[&](redirect_atom, actor_id aid, const std::string& fn, int flag) {
auto d = get_data(aid, true);
if (d)
d->redirect = get_sink_handle(system(), fcache, fn, flag);
},
[&](exit_msg& em) {
fail_state(std::move(em.reason));
done = true;
}
},
[&](redirect_atom, const std::string& fn, int flag) {
global_redirect = get_sink_handle(self->system(), fcache, fn, flag);
},
[&](redirect_atom, actor_id aid, const std::string& fn, int flag) {
auto d = get_data(aid, true);
if (d)
d->redirect = get_sink_handle(self->system(), fcache, fn, flag);
},
[&](exit_msg& em) {
self->fail_state(std::move(em.reason));
done = true;
}
).until([&] { return done; });
}
).until([&] { return done; });
}
const char* name() const override {
return "printer_actor";
}
};
} // namespace <anonymous>
......@@ -308,7 +323,7 @@ void abstract_coordinator::start() {
CAF_LOG_TRACE("");
// launch utility actors
timer_ = actor_cast<strong_actor_ptr>(system_.spawn<timer_actor, hidden + detached>());
printer_ = actor_cast<strong_actor_ptr>(system_.spawn<hidden + detached>(printer_loop));
printer_ = actor_cast<strong_actor_ptr>(system_.spawn<printer_actor, hidden + detached>());
}
void abstract_coordinator::init(actor_system_config& cfg) {
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/actor_config.hpp"
namespace caf {
actor_config::actor_config(execution_unit* ptr)
: host(ptr),
flags(abstract_channel::is_abstract_actor_flag),
groups(nullptr) {
// nop
}
std::string to_string(const actor_config&) {
// TODO: print flags and groups
return "actor_config";
}
} // namespace caf
......@@ -52,7 +52,7 @@ struct kvstate {
}
};
const char* kvstate::name = "caf.config_server";
const char* kvstate::name = "config_server";
behavior config_serv_impl(stateful_actor<kvstate>* self) {
CAF_LOG_TRACE("");
......@@ -144,7 +144,13 @@ behavior config_serv_impl(stateful_actor<kvstate>* self) {
};
}
behavior spawn_serv_impl(event_based_actor* self) {
struct spawn_serv_state {
static const char* name;
};
const char* spawn_serv_state::name = "spawn_server";
behavior spawn_serv_impl(stateful_actor<spawn_serv_state>* self) {
CAF_LOG_TRACE("");
return {
[=](spawn_atom, const std::string& name,
......@@ -178,14 +184,15 @@ actor_system::module::~module() {
actor_system::actor_system(actor_system_config& cfg)
: ids_(0),
types_(*this),
logger_(*this),
logger_(new caf::logger(*this), false),
registry_(*this),
groups_(*this),
middleman_(nullptr),
dummy_execution_unit_(this),
await_actors_before_shutdown_(true),
detached(0),
cfg_(cfg) {
cfg_(cfg),
logger_dtor_done_(false) {
CAF_SET_LOGGER_SYS(this);
for (auto& f : cfg.module_factories) {
auto mod_ptr = f(*this);
......@@ -242,8 +249,6 @@ actor_system::actor_system(actor_system_config& cfg)
if (mod)
mod->init(cfg);
groups_.init(cfg);
// start logger before spawning actors (since that uses the logger)
logger_.start();
// spawn config and spawn servers (lazily to not access the scheduler yet)
static constexpr auto Flags = hidden + lazy_init;
spawn_serv_ = actor_cast<strong_actor_ptr>(spawn<Flags>(spawn_serv_impl));
......@@ -256,9 +261,11 @@ actor_system::actor_system(actor_system_config& cfg)
if (mod)
mod->start();
groups_.start();
logger_->start();
}
actor_system::~actor_system() {
CAF_LOG_DEBUG("shutdown actor system");
if (await_actors_before_shutdown_)
await_all_actors_done();
// shutdown system-level servers
......@@ -277,8 +284,12 @@ actor_system::~actor_system() {
(*i)->stop();
await_detached_threads();
registry_.stop();
logger_.stop();
// reset logger and wait until dtor was called
CAF_SET_LOGGER_SYS(nullptr);
logger_.reset();
std::unique_lock<std::mutex> guard{logger_dtor_mtx_};
while (!logger_dtor_done_)
logger_dtor_cv_.wait(guard);
}
/// Returns the host-local identifier for this system.
......@@ -293,7 +304,7 @@ scheduler::abstract_coordinator& actor_system::scheduler() {
}
caf::logger& actor_system::logger() {
return logger_;
return *logger_;
}
actor_registry& actor_system::registry() {
......
......@@ -59,14 +59,21 @@ blocking_actor::~blocking_actor() {
}
void blocking_actor::enqueue(mailbox_element_ptr ptr, execution_unit*) {
CAF_ASSERT(ptr != nullptr);
CAF_ASSERT(getf(is_blocking_flag));
CAF_LOG_TRACE(CAF_ARG(*ptr));
CAF_LOG_SEND_EVENT(ptr);
auto mid = ptr->mid;
auto src = ptr->sender;
// returns false if mailbox has been closed
if (!mailbox().synchronized_enqueue(mtx_, cv_, ptr.release())) {
CAF_LOG_REJECT_EVENT();
if (mid.is_request()) {
detail::sync_request_bouncer srb{exit_reason()};
srb(src, mid);
}
} else {
CAF_LOG_ACCEPT_EVENT();
}
}
......@@ -75,6 +82,7 @@ const char* blocking_actor::name() const {
}
void blocking_actor::launch(execution_unit*, bool, bool hide) {
CAF_LOG_INIT_EVENT(name(), false, hide);
CAF_LOG_TRACE(CAF_ARG(hide));
CAF_ASSERT(getf(is_blocking_flag));
if (!hide)
......@@ -85,6 +93,8 @@ void blocking_actor::launch(execution_unit*, bool, bool hide) {
auto this_ptr = ptr->get();
CAF_ASSERT(dynamic_cast<blocking_actor*>(this_ptr) != 0);
auto self = static_cast<blocking_actor*>(this_ptr);
CAF_SET_LOGGER_SYS(ptr->home_system);
CAF_PUSH_AID_FROM_PTR(self);
error rsn;
# ifndef CAF_NO_EXCEPTIONS
try {
......@@ -332,18 +342,21 @@ void blocking_actor::receive_impl(receive_cond& rcc,
skipped = false;
timed_out = false;
auto& x = seq.value();
CAF_LOG_RECEIVE_EVENT((&x));
// skip messages that don't match our message ID
if ((mid.valid() && mid != x.mid)
|| (!mid.valid() && x.mid.is_response())) {
skipped = true;
CAF_LOG_SKIP_EVENT();
} else {
// blocking actors can use nested receives => restore current_element_
auto prev_element = current_element_;
current_element_ = &x;
switch (bhvr.nested(visitor, x.content())) {
case match_case::skip:
skipped = true;
break;
skipped = true;
CAF_LOG_SKIP_EVENT();
break;
default:
break;
case match_case::no_match: {
......@@ -353,6 +366,7 @@ void blocking_actor::receive_impl(receive_cond& rcc,
// get a match on the second (error) handler
if (sres.flag != rt_skip) {
visitor.visit(sres);
CAF_LOG_FINALIZE_EVENT();
} else if (mid.valid()) {
// invoke again with an unexpected_response error
auto& old = *current_element_;
......@@ -362,8 +376,10 @@ void blocking_actor::receive_impl(receive_cond& rcc,
std::move(old.stages), err};
current_element_ = &tmp;
bhvr.nested(tmp.content());
CAF_LOG_FINALIZE_EVENT();
} else {
skipped = true;
CAF_LOG_SKIP_EVENT();
}
}
}
......
......@@ -54,11 +54,7 @@ local_actor::~local_actor() {
}
void local_actor::on_destroy() {
// disable logging from this point on, because on_destroy can
// be called after the logger is already destroyed;
// alternatively, we would have to use a reference-counted,
// heap-allocated logger
CAF_SET_LOGGER_SYS(nullptr);
CAF_PUSH_AID_FROM_PTR(this);
if (!getf(is_cleaned_up_flag)) {
on_exit();
cleanup(exit_reason::unreachable, nullptr);
......@@ -190,6 +186,7 @@ bool local_actor::cleanup(error&& fail_state, execution_unit* host) {
// tell registry we're done
unregister_from_system();
monitorable_actor::cleanup(std::move(fail_state), host);
CAF_LOG_TERMINATE_EVENT(fail_state)
return true;
}
......
......@@ -58,29 +58,54 @@ constexpr const char* log_level_name[] = {
};
#ifdef CAF_LOG_LEVEL
static_assert(CAF_LOG_LEVEL >= 0 && CAF_LOG_LEVEL <= 4,
"assertion: 0 <= CAF_LOG_LEVEL <= 4");
#ifdef CAF_MSVC
thread_local
#else
__thread
#endif
actor_system* current_logger_system_ptr = nullptr;
inline actor_system* current_logger_system() {
return current_logger_system_ptr;
}
thread_local intrusive_ptr<logger> current_logger;
inline void current_logger_system(actor_system* x) {
current_logger_system_ptr = x;
inline void set_current_logger(logger* x) {
current_logger.reset(x);
}
inline logger* get_current_logger() {
auto sys = current_logger_system();
return sys ? &sys->logger() : nullptr;
return current_logger.get();
}
#else // CAF_MSVC
pthread_key_t s_key;
pthread_once_t s_key_once = PTHREAD_ONCE_INIT;
void logger_ptr_destructor(void* ptr) {
if (ptr) {
intrusive_ptr_release(reinterpret_cast<logger*>(ptr));
}
}
void make_logger_ptr() {
pthread_key_create(&s_key, logger_ptr_destructor);
}
void set_current_logger(logger* x) {
pthread_once(&s_key_once, make_logger_ptr);
logger_ptr_destructor(pthread_getspecific(s_key));
if (x)
intrusive_ptr_add_ref(x);
pthread_setspecific(s_key, x);
}
#else
logger* get_current_logger() {
pthread_once(&s_key_once, make_logger_ptr);
return reinterpret_cast<logger*>(pthread_getspecific(s_key));
}
#endif // CAF_MSVC
#else // CAF_LOG_LEVEL
inline void current_logger_system(actor_system*) {
// nop
}
......@@ -88,7 +113,7 @@ inline void current_logger_system(actor_system*) {
inline logger* get_current_logger() {
return nullptr;
}
#endif
#endif // CAF_LOG_LEVEL
void prettify_type_name(std::string& class_name) {
//replace_all(class_name, " ", "");
......@@ -108,6 +133,8 @@ void prettify_type_name(std::string& class_name) {
};
char prefix1[] = "caf.detail.embedded<";
strip_magic(prefix1, prefix1 + (sizeof(prefix1) - 1));
// finally, replace any whitespace with %20
replace_all(class_name, " ", "%20");
}
void prettify_type_name(std::string& class_name, const char* c_class_name) {
......@@ -222,13 +249,10 @@ actor_id logger::thread_local_aid(actor_id aid) {
return 0; // was empty before
}
void logger::log(int level, const char* component,
const std::string& class_name, const char* function_name,
const char* c_full_file_name, int line_num,
const std::string& msg) {
CAF_ASSERT(level >= 0 && level <= 4);
if (level > level_)
return;
void logger::log_prefix(std::ostream& out, int level, const char* component,
const std::string& class_name,
const char* function_name, const char* c_full_file_name,
int line_num) {
std::string file_name;
std::string full_file_name = c_full_file_name;
auto ri = find(full_file_name.rbegin(), full_file_name.rend(), '/');
......@@ -242,17 +266,32 @@ void logger::log(int level, const char* component,
file_name = std::move(full_file_name);
}
std::ostringstream prefix;
prefix << timestamp_to_string(make_timestamp()) << " " << component << " "
<< log_level_name[level] << " "
<< "actor" << thread_local_aid() << " " << std::this_thread::get_id()
<< " " << class_name << " " << function_name << " " << file_name << ":"
<< line_num;
out << timestamp_to_string(make_timestamp()) << " " << component << " "
<< log_level_name[level] << " "
<< "actor" << thread_local_aid() << " " << std::this_thread::get_id()
<< " " << class_name << " " << function_name << " " << file_name << ":"
<< line_num;
}
void logger::log(int level, const char* component,
const std::string& class_name, const char* function_name,
const char* c_full_file_name, int line_num,
const std::string& msg) {
CAF_ASSERT(level >= 0 && level <= 4);
if (level > level_)
return;
std::ostringstream prefix;
log_prefix(prefix, level, component, class_name, function_name,
c_full_file_name, line_num);
queue_.synchronized_enqueue(queue_mtx_, queue_cv_,
new event{level, component, prefix.str(), msg});
}
void logger::set_current_actor_system(actor_system* x) {
current_logger_system(x);
if (x)
set_current_logger(&x->logger());
else
set_current_logger(nullptr);
}
logger* logger::current_logger() {
......@@ -270,7 +309,11 @@ void logger::log_static(int level, const char* component,
}
logger::~logger() {
// nop
stop();
// tell system our dtor is done
std::unique_lock<std::mutex> guard{system_.logger_dtor_mtx_};
system_.logger_dtor_done_ = true;
system_.logger_dtor_cv_.notify_one();
}
logger::logger(actor_system& sys) : system_(sys) {
......@@ -299,6 +342,42 @@ void logger::run() {
f.replace(i, i + sizeof(node) - 1, nid);
}
std::fstream file(f, std::ios::out | std::ios::app);
if (!file) {
std::cerr << "unable to open log file " << f << std::endl;
return;
}
// log first entry
auto lvl_atom = system_.config().logger_verbosity;
switch (static_cast<uint64_t>(lvl_atom)) {
case error_log_lvl_atom::uint_value():
level_ = CAF_LOG_LEVEL_ERROR;
break;
case warning_log_lvl_atom::uint_value():
level_ = CAF_LOG_LEVEL_WARNING;
break;
case info_log_lvl_atom::uint_value():
level_ = CAF_LOG_LEVEL_INFO;
break;
case debug_log_lvl_atom::uint_value():
level_ = CAF_LOG_LEVEL_DEBUG;
break;
case trace_log_lvl_atom::uint_value():
level_ = CAF_LOG_LEVEL_TRACE;
break;
default: {
constexpr atom_value level_names[] = {
error_log_lvl_atom::value, warning_log_lvl_atom::value,
info_log_lvl_atom::value, debug_log_lvl_atom::value,
trace_log_lvl_atom::value};
lvl_atom = level_names[CAF_LOG_LEVEL];
level_ = CAF_LOG_LEVEL;
}
}
log_prefix(file, CAF_LOG_LEVEL_INFO, "caf", "caf.logger", "start",
__FILE__, __LINE__);
file << " level = " << to_string(lvl_atom) << ", node = " << to_string(system_.node())
<< std::endl;
// receive log entries from other threads and actors
std::unique_ptr<event> ptr;
for (;;) {
// make sure we have data to read
......@@ -306,10 +385,9 @@ void logger::run() {
// read & process event
ptr.reset(queue_.try_pop());
CAF_ASSERT(ptr != nullptr);
if (ptr->msg.empty()) {
file.close();
return;
}
// empty message means: shut down
if (ptr->msg.empty())
break;
file << ptr->prefix << ' ' << ptr->msg << std::endl;
// TODO: once we've phased out GCC 4.8, we can upgarde this to a regex.
if (!system_.config().logger_filter.empty()
......@@ -340,44 +418,17 @@ void logger::run() {
std::clog << ptr->msg << color(reset) << std::endl;
}
}
log_prefix(file, CAF_LOG_LEVEL_INFO, "caf", "caf.logger", "stop",
__FILE__, __LINE__);
file << " EOF" << std::endl;
file.close();
}
void logger::start() {
#if defined(CAF_LOG_LEVEL)
auto lvl_atom = system_.config().logger_verbosity;
switch (static_cast<uint64_t>(lvl_atom)) {
case quiet_log_lvl_atom::uint_value():
return;
case error_log_lvl_atom::uint_value():
level_ = CAF_LOG_LEVEL_ERROR;
break;
case warning_log_lvl_atom::uint_value():
level_ = CAF_LOG_LEVEL_WARNING;
break;
case info_log_lvl_atom::uint_value():
level_ = CAF_LOG_LEVEL_INFO;
break;
case debug_log_lvl_atom::uint_value():
level_ = CAF_LOG_LEVEL_DEBUG;
break;
case trace_log_lvl_atom::uint_value():
level_ = CAF_LOG_LEVEL_TRACE;
break;
default: {
constexpr atom_value level_names[] = {
error_log_lvl_atom::value, warning_log_lvl_atom::value,
info_log_lvl_atom::value, debug_log_lvl_atom::value,
trace_log_lvl_atom::value};
lvl_atom = level_names[CAF_LOG_LEVEL];
level_ = CAF_LOG_LEVEL;
}
}
if (system_.config().logger_verbosity == quiet_log_lvl_atom::value)
return;
thread_ = std::thread{[this] { this->run(); }};
std::string msg = "ENTRY level = ";
msg += to_string(lvl_atom);
msg += ", node = ";
msg += to_string(system_.node());
log(CAF_LOG_LEVEL_INFO, "caf", "caf::logger", "run", __FILE__, __LINE__, msg);
#endif
}
......@@ -385,8 +436,6 @@ void logger::stop() {
#if defined(CAF_LOG_LEVEL)
if (!thread_.joinable())
return;
log(CAF_LOG_LEVEL_INFO, "caf", "caf::logger", "run", __FILE__, __LINE__,
"EXIT");
// an empty string means: shut down
queue_.synchronized_enqueue(queue_mtx_, queue_cv_, new event);
thread_.join();
......
......@@ -35,6 +35,7 @@ private_thread::private_thread(scheduled_actor* self)
void private_thread::run() {
auto job = const_cast<scheduled_actor*>(self_);
CAF_SET_LOGGER_SYS(&job->system());
CAF_PUSH_AID(job->id());
CAF_LOG_TRACE("");
scoped_execution_unit ctx{&job->system()};
......
......@@ -118,16 +118,16 @@ scheduled_actor::~scheduled_actor() {
// -- overridden functions of abstract_actor -----------------------------------
void scheduled_actor::enqueue(mailbox_element_ptr ptr,
execution_unit* eu) {
CAF_PUSH_AID(id());
CAF_LOG_TRACE(CAF_ARG(*ptr));
void scheduled_actor::enqueue(mailbox_element_ptr ptr, execution_unit* eu) {
CAF_ASSERT(ptr != nullptr);
CAF_ASSERT(!getf(is_blocking_flag));
CAF_LOG_TRACE(CAF_ARG(*ptr));
CAF_LOG_SEND_EVENT(ptr);
auto mid = ptr->mid;
auto sender = ptr->sender;
switch (mailbox().enqueue(ptr.release())) {
case detail::enqueue_result::unblocked_reader: {
CAF_LOG_ACCEPT_EVENT();
// add a reference count to this actor and re-schedule it
intrusive_ptr_add_ref(ctrl());
if (getf(is_detached_flag)) {
......@@ -142,6 +142,7 @@ void scheduled_actor::enqueue(mailbox_element_ptr ptr,
break;
}
case detail::enqueue_result::queue_closed: {
CAF_LOG_REJECT_EVENT();
if (mid.is_request()) {
detail::sync_request_bouncer f{exit_reason()};
f(sender, mid);
......@@ -150,6 +151,7 @@ void scheduled_actor::enqueue(mailbox_element_ptr ptr,
}
case detail::enqueue_result::success:
// enqueued to a running actors' mailbox; nothing to do
CAF_LOG_ACCEPT_EVENT();
break;
}
}
......@@ -161,6 +163,7 @@ const char* scheduled_actor::name() const {
}
void scheduled_actor::launch(execution_unit* eu, bool lazy, bool hide) {
CAF_LOG_INIT_EVENT(name(), lazy, hide);
CAF_LOG_TRACE(CAF_ARG(lazy) << CAF_ARG(hide));
CAF_ASSERT(!getf(is_blocking_flag));
if (!hide)
......@@ -376,6 +379,7 @@ scheduled_actor::categorize(mailbox_element& x) {
invoke_message_result scheduled_actor::consume(mailbox_element& x) {
CAF_LOG_TRACE(CAF_ARG(x));
current_element_ = &x;
CAF_LOG_RECEIVE_EVENT(current_element_);
// short-circuit awaited responses
if (!awaited_responses_.empty()) {
auto& pr = awaited_responses_.front();
......
......@@ -49,22 +49,19 @@ scoped_actor::scoped_actor(actor_system& sys, bool hide) : context_(&sys) {
actor_config cfg{&context_};
self_ = make_actor<impl, strong_actor_ptr>(sys.next_actor_id(), sys.node(),
&sys, cfg);
if (!hide)
prev_ = CAF_SET_AID(self_->id());
CAF_LOG_TRACE(CAF_ARG(hide));
prev_ = CAF_SET_AID(self_->id());
CAF_LOG_INIT_EVENT("scoped_actor", false, hide);
if (!hide)
ptr()->register_at_system();
}
scoped_actor::~scoped_actor() {
CAF_LOG_TRACE("");
if (!self_)
return;
auto x = ptr();
if (x->getf(abstract_actor::is_registered_flag))
CAF_SET_AID(prev_);
if (!x->getf(abstract_actor::is_terminated_flag))
x->cleanup(exit_reason::normal, &context_);
CAF_SET_AID(prev_);
}
blocking_actor* scoped_actor::ptr() const {
......
......@@ -47,6 +47,7 @@ void abstract_broker::enqueue(mailbox_element_ptr ptr, execution_unit*) {
}
void abstract_broker::launch(execution_unit* eu, bool is_lazy, bool is_hidden) {
CAF_LOG_INIT_EVENT(name(), is_lazy, is_hidden);
CAF_ASSERT(eu != nullptr);
CAF_ASSERT(eu == &backend());
// add implicit reference count held by middleman/multiplexer
......
......@@ -978,7 +978,6 @@ event_handler::event_handler(default_multiplexer& dm, native_socket sockfd)
fd_(sockfd),
read_channel_closed_(false),
backend_(dm) {
CAF_LOG_TRACE(CAF_ARG(sockfd));
set_fd_flags();
}
......
......@@ -27,3 +27,5 @@ if(WIN32)
else()
add(caf-run)
endif()
add(caf-vec)
This diff is collapsed.
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