Commit a4aa1c36 authored by Dominik Charousset's avatar Dominik Charousset

Implement format strings for log output

parent a0462d6c
......@@ -47,3 +47,18 @@ max-consecutive-reads=50
heartbeat-interval=0
; configures whether the MM detaches its internal utility actors
middleman-detach-utility-actors=true
; when compiling with logging enabled
[logger]
; file name template for output log file files (empty string disables logging)
file-name="actor_log_[PID]_[TIMESTAMP]_[NODE].log"
; format for rendering individual log file entries
file-format="%r %c %p %a %t %C %M %F:%L %m%n"
; mode for console log output generation (none|colored|uncolored)
console='none'
; format for printing individual log entries to the console
console-format="%m"
; excludes listed components from logging
component-filter=""
; configures the severity level for logs (quiet|error|warning|info|debug|trace)
verbosity='trace'
......@@ -72,6 +72,7 @@ set (LIBCAF_CORE_SRCS
src/node_id.cpp
src/outgoing_stream_multiplexer.cpp
src/parse_ini.cpp
src/pretty_type_name.cpp
src/private_thread.cpp
src/proxy_registry.cpp
src/pull5.cpp
......
......@@ -266,10 +266,17 @@ public:
// -- config parameters for the logger ---------------------------------------
std::string logger_filename;
atom_value logger_verbosity;
std::string logger_file_name;
std::string logger_file_format;
atom_value logger_console;
std::string logger_filter;
std::string logger_console_format;
std::string logger_component_filter;
atom_value logger_verbosity;
// -- backward compatibility -------------------------------------------------
std::string& logger_filename CAF_DEPRECATED = logger_file_name;
std::string& logger_filter CAF_DEPRECATED = logger_component_filter;
// -- config parameters of the middleman -------------------------------------
......
......@@ -48,6 +48,19 @@ constexpr atom_value atom(char const (&str)[Size]) {
return static_cast<atom_value>(detail::atom_val(str));
}
/// Creates an atom from given string literal and return an integer
/// representation of the atom..
template <size_t Size>
constexpr uint64_t atom_uint(char const (&str)[Size]) {
static_assert(Size <= 11, "only 10 characters are allowed");
return detail::atom_val(str);
}
/// Converts an atom to its integer representation.
constexpr uint64_t atom_uint(atom_value x) {
return static_cast<uint64_t>(x);
}
/// Lifts an `atom_value` to a compile-time constant.
template <atom_value V>
struct atom_constant {
......@@ -155,24 +168,6 @@ using migrate_atom = atom_constant<atom("migrate")>;
/// Used for triggering periodic operations.
using tick_atom = atom_constant<atom("tick")>;
/// Used as config parameter for the `logger`.
using trace_log_lvl_atom = atom_constant<atom("TRACE")>;
/// Used as config parameter for the `logger`.
using debug_log_lvl_atom = atom_constant<atom("DEBUG")>;
/// Used as config parameter for the `logger`.
using info_log_lvl_atom = atom_constant<atom("INFO")>;
/// Used as config parameter for the `logger`.
using warning_log_lvl_atom = atom_constant<atom("WARNING")>;
/// Used as config parameter for the `logger`.
using error_log_lvl_atom = atom_constant<atom("ERROR")>;
/// Used as config parameter for the `logger`.
using quiet_log_lvl_atom = atom_constant<atom("QUIET")>;
} // namespace caf
namespace std {
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* 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. *
******************************************************************************/
// The rationale of this header is to provide a serialization API
// that is compatbile to boost.serialization. In particular, the
// design goals are:
// - allow users to integrate existing boost.serialization-based code easily
// - allow to switch out this header with the actual boost header in boost.actor
//
// Differences in semantics are:
// - CAF does *not* respect class versions
// - the `unsigned int` argument is always 0 and ignored by CAF
//
// Since CAF requires all runtime instances to have the same types
// announced, different class versions in a single actor system would
// cause inconsistencies that are not recoverable.
#ifndef CAF_DETAIL_PRETTY_TYPE_NAME_HPP
#define CAF_DETAIL_PRETTY_TYPE_NAME_HPP
#include <string>
#include <typeinfo>
namespace caf {
namespace detail {
void prettify_type_name(std::string& class_name);
void prettify_type_name(std::string& class_name, const char* input_class_name);
std::string pretty_type_name(const std::type_info& x);
} // namespace detail
} // namespace caf
#endif // CAF_DETAIL_PRETTY_TYPE_NAME_HPP
This diff is collapsed.
......@@ -28,6 +28,7 @@
#include <algorithm>
#include <type_traits>
#include "caf/config.hpp"
#include "caf/detail/type_traits.hpp"
namespace caf {
......
......@@ -41,10 +41,10 @@ public:
using path_uptr = std::unique_ptr<upstream_path>;
/// Stores all available paths.
using path_uptr_list = std::vector<path_uptr>;
using path_uptr_vec = std::vector<path_uptr>;
/// List of views to paths.
using path_ptr_list = std::vector<path_ptr>;
using path_ptr_vec = std::vector<path_ptr>;
/// Describes an assignment of credit to an upstream actor.
using assignment_pair = std::pair<upstream_path*, long>;
......@@ -98,6 +98,10 @@ public:
upstream_path* find(const strong_actor_ptr& x) const;
inline const path_uptr_vec& paths() const {
return paths_;
}
// -- required state ---------------------------------------------------------
inline local_actor* self() const {
......@@ -149,7 +153,7 @@ protected:
local_actor* self_;
/// List of all known paths.
path_uptr_list paths_;
path_uptr_vec paths_;
/// An assignment vector that's re-used whenever calling the policy.
assignment_vec assignment_vec_;
......
......@@ -123,8 +123,11 @@ actor_system_config::actor_system_config()
work_stealing_moderate_sleep_duration_us = 50;
work_stealing_relaxed_steal_interval = 1;
work_stealing_relaxed_sleep_duration_us = 10000;
logger_filename = "actor_log_[PID]_[TIMESTAMP]_[NODE].log";
logger_console = atom("NONE");
logger_file_name = "actor_log_[PID]_[TIMESTAMP]_[NODE].log";
logger_file_format = "%r %c %p %a %t %C %M %F:%L %m%n";
logger_console = atom("none");
logger_console_format = "%m";
logger_verbosity = atom("trace");
middleman_network_backend = atom("default");
middleman_enable_automatic_connections = false;
middleman_max_consecutive_reads = 50;
......@@ -159,14 +162,22 @@ actor_system_config::actor_system_config()
.add(work_stealing_relaxed_sleep_duration_us, "relaxed-sleep-duration",
"sets the sleep interval between poll attempts during relaxed polling");
opt_group{options_, "logger"}
.add(logger_filename, "filename",
.add(logger_file_name, "file-name",
"sets the filesystem path of the log file")
.add(logger_verbosity, "verbosity",
"sets the verbosity (QUIET|ERROR|WARNING|INFO|DEBUG|TRACE)")
.add(logger_file_format, "file-format",
"sets the line format for individual log file entires")
.add(logger_console, "console",
"enables logging to the console via std::clog")
.add(logger_filter, "filter",
"sets a component filter for console log messages");
"sets the type of output to std::clog (none|colored|uncolored)")
.add(logger_console_format, "console-format",
"sets the line format for printing individual log entires")
.add(logger_component_filter, "component-filter",
"exclude all listed components from logging")
.add(logger_verbosity, "verbosity",
"sets the verbosity (quiet|error|warning|info|debug|trace)")
.add(logger_file_name, "filename",
"deprecated (use file-name instead)")
.add(logger_component_filter, "filter",
"deprecated (use console-component-filter instead)");
opt_group{options_, "middleman"}
.add(middleman_network_backend, "network-backend",
"sets the network backend to either 'default' or 'asio' (if available)")
......
......@@ -20,6 +20,8 @@
#include "caf/message_id.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/detail/pretty_type_name.hpp"
namespace caf {
event_based_actor::event_based_actor(actor_config& cfg) : extended_base(cfg) {
......@@ -31,7 +33,7 @@ event_based_actor::~event_based_actor() {
}
void event_based_actor::initialize() {
CAF_LOG_TRACE("subtype =" << logger::render_type_name(typeid(*this)).c_str());
CAF_LOG_TRACE("subtype =" << detail::pretty_type_name(typeid(*this)).c_str());
setf(is_initialized_flag);
auto bhvr = make_behavior();
CAF_LOG_DEBUG_IF(!bhvr, "make_behavior() did not return a behavior:"
......
This diff is collapsed.
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* 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/detail/pretty_type_name.hpp"
#include "caf/config.hpp"
#if defined(CAF_LINUX) || defined(CAF_MACOS)
#include <unistd.h>
#include <cxxabi.h>
#include <sys/types.h>
#endif
#include "caf/string_algorithms.hpp"
namespace caf {
namespace detail {
void prettify_type_name(std::string& class_name) {
//replace_all(class_name, " ", "");
replace_all(class_name, "::", ".");
replace_all(class_name, "(anonymousnamespace)", "ANON");
replace_all(class_name, ".__1.", "."); // gets rid of weird Clang-lib names
// hide CAF magic in logs
auto strip_magic = [&](const char* prefix_begin, const char* prefix_end) {
auto last = class_name.end();
auto i = std::search(class_name.begin(), last, prefix_begin, prefix_end);
auto comma_or_angle_bracket = [](char c) { return c == ',' || c == '>'; };
auto e = std::find_if(i, last, comma_or_angle_bracket);
if (i != e) {
std::string substr(i + (prefix_end - prefix_begin), e);
class_name.swap(substr);
}
};
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) {
# if defined(CAF_LINUX) || defined(CAF_MACOS)
int stat = 0;
std::unique_ptr<char, decltype(free)*> real_class_name{nullptr, free};
auto tmp = abi::__cxa_demangle(c_class_name, nullptr, nullptr, &stat);
real_class_name.reset(tmp);
class_name = stat == 0 ? real_class_name.get() : c_class_name;
# else
class_name = c_class_name;
# endif
prettify_type_name(class_name);
}
std::string pretty_type_name(const std::type_info& x) {
std::string result;
prettify_type_name(result, x.name());
return result;
}
} // namespace detail
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* 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/config.hpp"
#define CAF_SUITE logger
#include "caf/test/unit_test.hpp"
#include <string>
#include "caf/all.hpp"
using namespace caf;
using namespace std;
using namespace std::chrono;
namespace {
struct fixture {
fixture() {
cfg.scheduler_policy = caf::atom("testing");
}
void add(logger::field_type kind) {
lf.emplace_back(logger::field{kind, nullptr, nullptr});
}
template <size_t N>
void add(logger::field_type kind, const char (&str)[N]) {
lf.emplace_back(logger::field{kind, str, str + (N - 1)}); // exclude \0
}
template <class F, class... Ts>
string render(F f, Ts&&... xs) {
ostringstream oss;
f(oss, forward<Ts>(xs)...);
return oss.str();
}
actor_system_config cfg;
logger::line_format lf;
};
} // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(logger_tests, fixture)
// copy construction, copy assign, move construction, move assign
// and finally serialization round-trip
CAF_TEST(parse_default_format_strings) {
actor_system sys{cfg};
CAF_CHECK_EQUAL(cfg.logger_file_format, "%r %c %p %a %t %C %M %F:%L %m%n");
add(logger::runtime_field);
add(logger::plain_text_field, " ");
add(logger::category_field);
add(logger::plain_text_field, " ");
add(logger::priority_field);
add(logger::plain_text_field, " ");
add(logger::actor_field);
add(logger::plain_text_field, " ");
add(logger::thread_field);
add(logger::plain_text_field, " ");
add(logger::class_name_field);
add(logger::plain_text_field, " ");
add(logger::method_field);
add(logger::plain_text_field, " ");
add(logger::file_field);
add(logger::plain_text_field, ":");
add(logger::line_field);
add(logger::plain_text_field, " ");
add(logger::message_field);
add(logger::newline_field);
CAF_CHECK_EQUAL(sys.logger().file_format(), lf);
CAF_CHECK_EQUAL(logger::parse_format("%r %c %p %a %t %C %M %F:%L %m%n"), lf);
}
CAF_TEST(rendering) {
// Rendering of type names and function names.
const char* foobar = "void ns::foo::bar()";
CAF_CHECK_EQUAL(render(logger::render_fun_name, foobar), "bar");
CAF_CHECK_EQUAL(render(logger::render_fun_prefix, foobar), "ns.foo");
// Rendering of time points.
timestamp t0;
timestamp t1{timestamp::duration{5000000}}; // epoch + 5000000ns (5ms)
CAF_CHECK_EQUAL(render(logger::render_time_diff, t0, t1), "5");
ostringstream t0_iso8601;
auto t0_t = system_clock::to_time_t(system_clock::time_point{});
t0_iso8601 << put_time(localtime(&t0_t), "%F %T");
CAF_CHECK_EQUAL(render(logger::render_date, t0), t0_iso8601.str());
// Rendering of events.
logger::event e{
nullptr,
nullptr,
CAF_LOG_LEVEL_WARNING,
"unit.test",
"void ns::foo::bar()",
"foo.cpp",
42,
"hello world",
this_thread::get_id(),
0,
t0
};
// Exclude %r and %t from rendering test because they are nondeterministic.
actor_system sys{cfg};
auto lf = logger::parse_format("%c %p %a %C %M %F:%L %m");
auto& lg = sys.logger();
using namespace std::placeholders;
auto render_event = bind(&logger::render, &lg, _1, _2, _3);
CAF_CHECK_EQUAL(render(render_event, lf, e),
"unit.test WARN actor0 ns.foo bar foo.cpp:42 hello world");
}
CAF_TEST_FIXTURE_SCOPE_END()
......@@ -652,7 +652,7 @@ struct config : actor_system_config {
public:
config() {
add_message_type<element_type>("element");
logger_filename = "streamlog";
logger_file_name = "streamlog";
}
};
......
......@@ -758,7 +758,7 @@ struct config : public actor_system_config {
"Include hidden (system-level) actors")
.add(verbosity, "verbosity,v", "Debug output (from 0 to 2)");
// shutdown logging per default
logger_verbosity = quiet_log_lvl_atom::value;
logger_verbosity = atom("quiet");
}
};
......
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