Commit a6b6130b authored by Dominik Charousset's avatar Dominik Charousset

Merge branch 'issue/1116'

Close #1116.
parents 13b5d670 c6f9177e
...@@ -54,14 +54,6 @@ is based on [Keep a Changelog](https://keepachangelog.com). ...@@ -54,14 +54,6 @@ is based on [Keep a Changelog](https://keepachangelog.com).
- The `to_string` output for `error` now renders the error code enum by default. - The `to_string` output for `error` now renders the error code enum by default.
This renders the member functions `actor_system::render` and This renders the member functions `actor_system::render` and
`actor_system_config::render` obsolete. `actor_system_config::render` obsolete.
- The configuration format of CAF has come a long way since first starting to
allow user-defined configuration via `.ini` files. Rather than sticking with
the weird hybrid that evolved over the years, we are going to get rid of the
last pieces of INI syntax and go with the much cleaner, scoped syntax. CAF is
still picking up `caf-application.ini` with this release and uses the
deprecated INI parser when given any other file name that ends in `.ini`.
However, the next version of CAF is only going to recognize the new format.
The new default file name is `caf-application.conf`.
### Changed ### Changed
...@@ -148,6 +140,11 @@ is based on [Keep a Changelog](https://keepachangelog.com). ...@@ -148,6 +140,11 @@ is based on [Keep a Changelog](https://keepachangelog.com).
- All member functions of `scheduled_actor` for adding stream managers (such as - All member functions of `scheduled_actor` for adding stream managers (such as
`make_source`) were removed in favor their free-function equivalent, e.g., `make_source`) were removed in favor their free-function equivalent, e.g.,
`attach_stream_source` `attach_stream_source`
- The configuration format of CAF has come a long way since first starting to
allow user-defined configuration via `.ini` files. Rather than sticking with
the weird hybrid that evolved over the years, we finally get rid of the last
pieces of INI syntax and go with the much cleaner, scoped syntax. The new
default file name for configuration files is `caf-application.conf`.
### Fixed ### Fixed
......
# This file shows all possible parameters with defaults. For some values, CAF # This file shows all possible parameters with defaults. For some values, CAF
# computes a value at runtime if the configuration does not provide a value. For # computes a value at runtime if the configuration does not provide a value. For
# example, "scheduler.max-threads" has no hard-coded default and instead adjusts # example, "caf.scheduler.max-threads" has no hard-coded default and instead
# to the number of cores available. # adjusts to the number of cores available.
caf {
# when using the default scheduler # Parameters selecting a default scheduler.
scheduler { scheduler {
# accepted alternative: "sharing" # Use the work stealing implementation. Accepted alternative: "sharing".
policy="stealing" policy = "stealing"
# configures whether the scheduler generates profiling output # Maximum number of messages actors can consume in single run (int64 max).
enable-profiling=false max-throughput = 9223372036854775807
# forces a fixed number of threads if set # # Maximum number of threads for the scheduler. No hardcoded default.
# max-threads=... (detected at runtime) # max-threads = ... (detected at runtime)
# maximum number of messages actors can consume in one run (int64 max) }
max-throughput=9223372036854775807 # Prameters for the work stealing scheduler. Only takes effect if
# measurement resolution in milliseconds (only if profiling is enabled) # caf.scheduler.policy is set to "stealing".
profiling-resolution=100ms work-stealing {
# output file for profiler data (only if profiling is enabled) # Number of zero-sleep-interval polling attempts.
profiling-output-file="/dev/null" aggressive-poll-attempts = 100
} # Frequency of steal attempts during aggressive polling.
aggressive-steal-interval = 10
# when using "stealing" as scheduler policy # Number of moderately aggressive polling attempts.
work-stealing { moderate-poll-attempts = 500
# number of zero-sleep-interval polling attempts # Frequency of steal attempts during moderate polling.
aggressive-poll-attempts=100 moderate-steal-interval = 5
# frequency of steal attempts during aggressive polling # Sleep interval between poll attempts.
aggressive-steal-interval=10 moderate-sleep-duration = 50us
# number of moderately aggressive polling attempts # Frequency of steal attempts during relaxed polling.
moderate-poll-attempts=500 relaxed-steal-interval = 1
# frequency of steal attempts during moderate polling # Sleep interval between poll attempts.
moderate-steal-interval=5 relaxed-sleep-duration = 10ms
# sleep interval between poll attempts }
moderate-sleep-duration=50us # Parameters for the I/O module.
# frequency of steal attempts during relaxed polling middleman {
relaxed-steal-interval=1 # Configures whether MMs try to span a full mesh.
# sleep interval between poll attempts enable-automatic-connections = false
relaxed-sleep-duration=10ms # Application identifiers of this node, prevents connection to other CAF
} # instances with incompatible identifiers.
app-identifiers = ["generic-caf-app"]
# when loading io::middleman # Maximum number of consecutive I/O reads per broker.
middleman { max-consecutive-reads = 50
# configures whether MMs try to span a full mesh # Heartbeat message interval in ms (0 disables heartbeating).
enable-automatic-connections=false heartbeat-interval = 0ms
# application identifier of this node, prevents connection to other CAF # Configures whether the MM attaches its internal utility actors to the
# instances with different identifier # scheduler instead of dedicating individual threads (needed only for
app-identifier="" # deterministic testing).
# maximum number of consecutive I/O reads per broker attach-utility-actors = false
max-consecutive-reads=50 # Configures whether the MM starts a background thread for I/O activity.
# heartbeat message interval in ms (0 disables heartbeating) # Setting this to true allows fully deterministic execution in unit test and
heartbeat-interval=0ms # requires the user to trigger I/O manually.
# configures whether the MM attaches its internal utility actors to the manual-multiplexing = false
# scheduler instead of dedicating individual threads (needed only for # # Configures how many background workers are spawned for deserialization.
# deterministic testing) # # No hardcoded default.
attach-utility-actors=false # workers = ... (detected at runtime)
# configures whether the MM starts a background thread for I/O activity, }
# setting this to true allows fully deterministic execution in unit test and # Parameters for logging.
# requires the user to trigger I/O manually logger {
manual-multiplexing=false # # Note: File logging is disabled unless a 'file' section exists that
# disables communication via TCP # # contains a setting for 'verbosity'.
disable-tcp=false # file {
# enable communication via UDP # # File name template for output log files.
enable-udp=false # path = "actor_log_[PID]_[TIMESTAMP]_[NODE].log"
# configures how many background workers are spawned for deserialization, # # Format for rendering individual log file entries.
# by default CAF uses 1-4 workers depending on the number of cores # format = "%r %c %p %a %t %C %M %F:%L %m%n"
# workers=... (detected at runtime) # # Minimum severity of messages that are written to the log. One of:
} # # 'quiet', 'error', 'warning', 'info', 'debug', or 'trace'.
# verbosity = "trace"
# when compiling with logging enabled # # A list of components to exclude in file output.
logger { # excluded-components = []
# file name template for output log file files (empty string disables logging) # }
file-name="actor_log_[PID]_[TIMESTAMP]_[NODE].log" # # Note: Console output is disabled unless a 'console' section exists that
# format for rendering individual log file entries # # contains a setting for 'verbosity'.
file-format="%r %c %p %a %t %C %M %F:%L %m%n" # console {
# configures the minimum severity of messages that are written to the log file # # Enabled colored output when writing to a TTY if set to true.
# (quiet|error|warning|info|debug|trace) # colored = true
file-verbosity="trace" # # Format for printing log lines (implicit newline at the end).
# mode for console log output generation (none|colored|uncolored) # format = "[%c:%p] %d %m"
console="none" # # Minimum severity of messages that are written to the console. One of:
# format for printing individual log entries to the console # # 'quiet', 'error', 'warning', 'info', 'debug', or 'trace'.
console-format="%m" # verbosity = "trace"
# configures the minimum severity of messages that are written to the console # # A list of components to exclude in console output.
# (quiet|error|warning|info|debug|trace) # excluded-components = []
console-verbosity="trace" # }
# excludes listed components from logging (list of strings) }
component-blacklist=[]
} }
...@@ -84,7 +84,6 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS} ...@@ -84,7 +84,6 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/detail/get_process_id.cpp src/detail/get_process_id.cpp
src/detail/get_root_uuid.cpp src/detail/get_root_uuid.cpp
src/detail/glob_match.cpp src/detail/glob_match.cpp
src/detail/ini_consumer.cpp
src/detail/invoke_result_visitor.cpp src/detail/invoke_result_visitor.cpp
src/detail/message_builder_element.cpp src/detail/message_builder_element.cpp
src/detail/message_data.cpp src/detail/message_data.cpp
...@@ -237,14 +236,12 @@ caf_add_test_suites(caf-core-test ...@@ -237,14 +236,12 @@ caf_add_test_suites(caf-core-test
detail.bounds_checker detail.bounds_checker
detail.config_consumer detail.config_consumer
detail.ieee_754 detail.ieee_754
detail.ini_consumer
detail.limited_vector detail.limited_vector
detail.meta_object detail.meta_object
detail.parse detail.parse
detail.parser.read_bool detail.parser.read_bool
detail.parser.read_config detail.parser.read_config
detail.parser.read_floating_point detail.parser.read_floating_point
detail.parser.read_ini
detail.parser.read_number detail.parser.read_number
detail.parser.read_number_or_timespan detail.parser.read_number_or_timespan
detail.parser.read_signed_integer detail.parser.read_signed_integer
......
...@@ -99,7 +99,7 @@ public: ...@@ -99,7 +99,7 @@ public:
/// values. /// values.
virtual settings dump_content() const; virtual settings dump_content() const;
/// Sets a config by using its INI name `config_name` to `config_value`. /// Sets a config by using its name `config_name` to `config_value`.
template <class T> template <class T>
actor_system_config& set(string_view name, T&& value) { actor_system_config& set(string_view name, T&& value) {
return set_impl(name, config_value{std::forward<T>(value)}); return set_impl(name, config_value{std::forward<T>(value)});
...@@ -113,16 +113,15 @@ public: ...@@ -113,16 +113,15 @@ public:
/// Parses `args` as tuple of strings containing CLI options and tries to open /// Parses `args` as tuple of strings containing CLI options and tries to open
/// `config_file_cstr` as config file. The parsers tries to open /// `config_file_cstr` as config file. The parsers tries to open
/// `caf-application.conf` or `caf-application.ini` (deprecated) if /// `caf-application.conf` if `config_file_cstr` is `nullptr`.
/// `config_file_cstr` is `nullptr`.
error parse(string_list args, const char* config_file_cstr = nullptr); error parse(string_list args, const char* config_file_cstr = nullptr);
/// Parses the CLI options `{argc, argv}` and `config` as configuration file. /// Parses the CLI options `{argc, argv}` and `config` as configuration file.
error parse(int argc, char** argv, std::istream& config); error parse(int argc, char** argv, std::istream& config);
/// Parses the CLI options `{argc, argv}` and tries to open `config_file_cstr` /// Parses the CLI options `{argc, argv}` and tries to open `config_file_cstr`
/// as config file. The parsers tries to open `caf-application.conf` or /// as config file. The parsers tries to open `caf-application.conf` if
/// `caf-application.ini` (deprecated) if `config_file_cstr` is `nullptr`. /// `config_file_cstr` is `nullptr`.
error parse(int argc, char** argv, const char* config_file_cstr = nullptr); error parse(int argc, char** argv, const char* config_file_cstr = nullptr);
/// Allows other nodes to spawn actors created by `fun` /// Allows other nodes to spawn actors created by `fun`
...@@ -247,7 +246,7 @@ public: ...@@ -247,7 +246,7 @@ public:
// -- parsing parameters ----------------------------------------------------- // -- parsing parameters -----------------------------------------------------
/// Configures the file path for the INI file, `caf-application.ini` per /// Configures the file path for the config file, `caf-application.conf` per
/// default. /// default.
std::string config_file_path; std::string config_file_path;
...@@ -324,17 +323,9 @@ protected: ...@@ -324,17 +323,9 @@ protected:
config_option_set custom_options_; config_option_set custom_options_;
private: private:
// TODO: deprecated. Remove with CAF 0.19.
static error parse_ini(std::istream& source, const config_option_set& opts,
settings& result);
actor_system_config& set_impl(string_view name, config_value value); actor_system_config& set_impl(string_view name, config_value value);
error extract_config_file_path(string_list& args); error extract_config_file_path(string_list& args);
/// Adjusts the content of the configuration, e.g., for ensuring backwards
/// compatibility with older options.
error adjust_content();
}; };
/// Returns all user-provided configuration parameters. /// Returns all user-provided configuration parameters.
......
...@@ -68,33 +68,19 @@ constexpr auto relaxed_sleep_duration = timespan{10'000'000}; ...@@ -68,33 +68,19 @@ constexpr auto relaxed_sleep_duration = timespan{10'000'000};
} // namespace caf::defaults::work_stealing } // namespace caf::defaults::work_stealing
namespace caf::defaults::logger { namespace caf::defaults::logger::file {
constexpr auto default_log_level = string_view { constexpr auto format = string_view{"%r %c %p %a %t %C %M %F:%L %m%n"};
#if CAF_LOG_LEVEL == CAF_LOG_LEVEL_TRACE constexpr auto path = string_view{"actor_log_[PID]_[TIMESTAMP]_[NODE].log"};
"trace"
#elif CAF_LOG_LEVEL == CAF_LOG_LEVEL_DEBUG } // namespace caf::defaults::logger::file
"debug"
#elif CAF_LOG_LEVEL == CAF_LOG_LEVEL_INFO namespace caf::defaults::logger::console {
"info"
#elif CAF_LOG_LEVEL == CAF_LOG_LEVEL_WARNING constexpr auto colored = true;
"warning" constexpr auto format = string_view{"[%c:%p] %d %m"};
#elif CAF_LOG_LEVEL == CAF_LOG_LEVEL_ERROR
"error" } // namespace caf::defaults::logger::console
#else
"quiet"
#endif
};
constexpr auto console = string_view{"none"};
constexpr auto console_format = string_view{"%m"};
constexpr auto console_verbosity = default_log_level;
constexpr auto file_format = string_view{"%r %c %p %a %t %C %M %F:%L %m%n"};
constexpr auto file_verbosity = default_log_level;
constexpr auto file_name
= string_view{"actor_log_[PID]_[TIMESTAMP]_[NODE].log"};
} // namespace caf::defaults::logger
namespace caf::defaults::middleman { namespace caf::defaults::middleman {
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* 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. *
******************************************************************************/
#pragma once
#include <string>
#include "caf/config_option_set.hpp"
#include "caf/config_value.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/dictionary.hpp"
#include "caf/settings.hpp"
namespace caf::detail {
class ini_consumer;
class ini_list_consumer;
class ini_map_consumer;
class CAF_CORE_EXPORT abstract_ini_consumer {
public:
// -- constructors, destructors, and assignment operators --------------------
explicit abstract_ini_consumer(abstract_ini_consumer* parent = nullptr);
abstract_ini_consumer(const abstract_ini_consumer&) = delete;
abstract_ini_consumer& operator=(const abstract_ini_consumer&) = delete;
virtual ~abstract_ini_consumer();
// -- properties -------------------------------------------------------------
virtual void value_impl(config_value&& x) = 0;
template <class T>
void value(T&& x) {
value_impl(config_value{std::forward<T>(x)});
}
abstract_ini_consumer* parent() {
return parent_;
}
ini_map_consumer begin_map();
ini_list_consumer begin_list();
protected:
// -- member variables -------------------------------------------------------
abstract_ini_consumer* parent_;
};
class CAF_CORE_EXPORT ini_map_consumer : public abstract_ini_consumer {
public:
// -- member types -----------------------------------------------------------
using super = abstract_ini_consumer;
using map_type = config_value::dictionary;
using iterator = map_type::iterator;
// -- constructors, destructors, and assignment operators --------------------
ini_map_consumer(abstract_ini_consumer* ptr);
ini_map_consumer(ini_map_consumer&& other);
~ini_map_consumer() override;
// -- properties -------------------------------------------------------------
void end_map();
void key(std::string name);
void value_impl(config_value&& x) override;
private:
// -- member variables -------------------------------------------------------
map_type xs_;
iterator i_;
};
class CAF_CORE_EXPORT ini_list_consumer : public abstract_ini_consumer {
public:
// -- member types -----------------------------------------------------------
using super = abstract_ini_consumer;
// -- constructors, destructors, and assignment operators --------------------
ini_list_consumer(abstract_ini_consumer* ptr);
ini_list_consumer(ini_list_consumer&& other);
// -- properties -------------------------------------------------------------
void end_list();
void value_impl(config_value&& x) override;
private:
// -- member variables -------------------------------------------------------
config_value::list xs_;
};
/// Consumes a single value from an INI parser.
class CAF_CORE_EXPORT ini_value_consumer : public abstract_ini_consumer {
public:
// -- member types -----------------------------------------------------------
using super = abstract_ini_consumer;
// -- constructors, destructors, and assignment operators --------------------
explicit ini_value_consumer(abstract_ini_consumer* parent = nullptr);
// -- properties -------------------------------------------------------------
void value_impl(config_value&& x) override;
// -- member variables -------------------------------------------------------
config_value result;
};
/// Consumes a config category.
class CAF_CORE_EXPORT ini_category_consumer : public abstract_ini_consumer {
public:
// -- member types -----------------------------------------------------------
using super = abstract_ini_consumer;
// -- constructors, destructors, and assignment operators --------------------
ini_category_consumer(ini_consumer* parent, std::string category);
ini_category_consumer(ini_category_consumer&&);
// -- properties -------------------------------------------------------------
void end_map();
void key(std::string name);
void value_impl(config_value&& x) override;
private:
// -- properties -------------------------------------------------------------
ini_consumer* dparent();
// -- member variables -------------------------------------------------------
std::string category_;
config_value::dictionary xs_;
std::string current_key;
};
/// Consumes a series of dictionaries forming a application configuration.
class CAF_CORE_EXPORT ini_consumer : public abstract_ini_consumer {
public:
// -- friends ----------------------------------------------------------------
friend class ini_category_consumer;
// -- member types -----------------------------------------------------------
using super = abstract_ini_consumer;
using config_map = dictionary<config_value::dictionary>;
// -- constructors, destructors, and assignment operators --------------------
ini_consumer(const config_option_set& options, settings& cfg);
// -- properties -------------------------------------------------------------
ini_category_consumer begin_map();
void key(std::string name);
void value_impl(config_value&& x) override;
private:
// -- member variables -------------------------------------------------------
const config_option_set& options_;
settings& cfg_;
std::string current_key_;
std::vector<error> warnings_;
};
} // namespace caf::detail
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* 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. *
******************************************************************************/
#pragma once
#include <ctype.h>
#include <stack>
#include "caf/config.hpp"
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/read_bool.hpp"
#include "caf/detail/parser/read_number_or_timespan.hpp"
#include "caf/detail/parser/read_string.hpp"
#include "caf/detail/parser/read_uri.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
#include "caf/uri_builder.hpp"
CAF_PUSH_UNUSED_LABEL_WARNING
#include "caf/detail/parser/fsm.hpp"
namespace caf::detail::parser {
// Example input:
//
// [section1]
// value1 = 123
// value2 = "string"
// subsection1 = {
// value3 = 1.23
// value4 = 4e20
// }
// [section2]
// value5 = 'atom'
// value6 = [1, 'two', "three", {
// a = "b",
// b = "c",
// }]
//
template <class State, class Consumer>
void read_ini_comment(State& ps, Consumer&&) {
// clang-format off
start();
term_state(init) {
transition(done, '\n')
transition(init)
}
term_state(done) {
// nop
}
fin();
// clang-format on
}
template <class State, class Consumer, class InsideList = std::false_type>
void read_ini_value(State& ps, Consumer&& consumer,
InsideList inside_list = {});
template <class State, class Consumer>
void read_ini_list(State& ps, Consumer&& consumer) {
// clang-format off
start();
state(init) {
epsilon(before_value)
}
state(before_value) {
transition(before_value, " \t\n")
transition(done, ']', consumer.end_list())
fsm_epsilon(read_ini_comment(ps, consumer), before_value, ';')
fsm_epsilon(read_ini_value(ps, consumer, std::true_type{}), after_value)
}
state(after_value) {
transition(after_value, " \t\n")
transition(before_value, ',')
transition(done, ']', consumer.end_list())
fsm_epsilon(read_ini_comment(ps, consumer), after_value, ';')
}
term_state(done) {
// nop
}
fin();
// clang-format on
}
template <class State, class Consumer>
void read_ini_map(State& ps, Consumer&& consumer) {
std::string key;
auto alnum_or_dash
= [](char x) { return isalnum(x) || x == '-' || x == '_'; };
// clang-format off
start();
state(init) {
epsilon(await_key_name)
}
state(await_key_name) {
transition(await_key_name, " \t\n")
fsm_epsilon(read_ini_comment(ps, consumer), await_key_name, ';')
transition(read_key_name, alphanumeric_chars, key = ch)
transition(done, '}', consumer.end_map())
}
// Reads a key of a "key=value" line.
state(read_key_name) {
transition(read_key_name, alnum_or_dash, key += ch)
epsilon(await_assignment)
}
// Reads the assignment operator in a "key=value" line.
state(await_assignment) {
transition(await_assignment, " \t")
transition(await_value, '=', consumer.key(std::move(key)))
epsilon(await_value, '{', consumer.key(std::move(key)))
}
// Reads the value in a "key=value" line.
state(await_value) {
transition(await_value, " \t")
fsm_epsilon(read_ini_value(ps, consumer), after_value)
}
// Waits for end-of-line after reading a value
state(after_value) {
transition(after_value, " \t")
transition(had_newline, "\n")
transition(await_key_name, ',')
transition(done, '}', consumer.end_map())
fsm_epsilon(read_ini_comment(ps, consumer), had_newline, ';')
}
// Allows users to skip the ',' for separating key/value pairs
state(had_newline) {
transition(had_newline, " \t\n")
transition(await_key_name, ',')
transition(done, '}', consumer.end_map())
fsm_epsilon(read_ini_comment(ps, consumer), had_newline, ';')
epsilon(read_key_name, alnum_or_dash)
}
term_state(done) {
//nop
}
fin();
// clang-format on
}
template <class State, class Consumer>
void read_ini_uri(State& ps, Consumer&& consumer) {
uri_builder builder;
auto g = make_scope_guard([&] {
if (ps.code <= pec::trailing_character)
consumer.value(builder.make());
});
// clang-format off
start();
state(init) {
transition(init, " \t\n")
transition(before_uri, '<')
}
state(before_uri) {
transition(before_uri, " \t\n")
fsm_epsilon(read_uri(ps, builder), after_uri)
}
state(after_uri) {
transition(after_uri, " \t\n")
transition(done, '>')
}
term_state(done) {
// nop
}
fin();
// clang-format on
}
template <class State, class Consumer, class InsideList>
void read_ini_value(State& ps, Consumer&& consumer, InsideList inside_list) {
// clang-format off
start();
state(init) {
fsm_epsilon(read_string(ps, consumer), done, quote_marks)
fsm_epsilon(read_number(ps, consumer), done, '.')
fsm_epsilon(read_bool(ps, consumer), done, "ft")
fsm_epsilon(read_number_or_timespan(ps, consumer, inside_list),
done, "0123456789+-")
fsm_epsilon(read_ini_uri(ps, consumer), done, '<')
fsm_transition(read_ini_list(ps, consumer.begin_list()), done, '[')
fsm_transition(read_ini_map(ps, consumer.begin_map()), done, '{')
}
term_state(done) {
// nop
}
fin();
// clang-format on
}
/// Reads an INI formatted input.
template <class State, class Consumer>
void read_ini_section(State& ps, Consumer&& consumer) {
using std::swap;
std::string tmp;
auto alnum = [](char x) { return isalnum(x) || x == '_'; };
auto alnum_or_dash
= [](char x) { return isalnum(x) || x == '_' || x == '-'; };
auto emit_key = [&] {
std::string key;
swap(tmp, key);
consumer.key(std::move(key));
};
auto g = make_scope_guard([&] {
if (ps.code <= pec::trailing_character)
consumer.end_map();
});
// clang-format off
start();
// Dispatches to read sections, comments, or key/value pairs.
term_state(init) {
transition(init, " \t\n")
fsm_epsilon(read_ini_comment(ps, consumer), init, ';')
transition(read_key_name, alnum, tmp = ch)
}
// Reads a key of a "key=value" line.
state(read_key_name) {
transition(read_key_name, alnum_or_dash, tmp += ch)
epsilon(await_assignment)
}
// Reads the assignment operator in a "key=value" line.
state(await_assignment) {
transition(await_assignment, " \t")
transition(await_value, '=', emit_key())
// The '=' is optional for maps, i.e., `key = {}` == `key {}`.
epsilon(await_value, '{', emit_key())
}
// Reads the value in a "key=value" line.
state(await_value) {
transition(await_value, " \t")
fsm_epsilon(read_ini_value(ps, consumer), await_eol)
}
// Waits for end-of-line after reading a value
term_state(await_eol) {
transition(await_eol, " \t")
fsm_epsilon(read_ini_comment(ps, consumer), init, ';')
transition(init, '\n')
}
fin();
// clang-format on
}
/// Reads a nested group, e.g., "[foo.bar]" would consume "[foo.]" in read_ini
/// and then delegate to this function for parsing "bar]".
template <class State, class Consumer>
void read_nested_group(State& ps, Consumer&& consumer) {
using std::swap;
std::string key;
auto alnum = [](char x) { return isalnum(x) || x == '_'; };
auto alnum_or_dash
= [](char x) { return isalnum(x) || x == '_' || x == '-'; };
auto begin_section = [&]() -> decltype(consumer.begin_map()) {
consumer.key(std::move(key));
return consumer.begin_map();
};
auto g = make_scope_guard([&] {
if (ps.code <= pec::trailing_character)
consumer.end_map();
});
// clang-format off
start();
// Scanning for first section.
state(init) {
epsilon(read_sub_section, alnum)
}
// Read the sub section key after reading an '[xxx.'.
state(read_sub_section) {
transition(read_sub_section, alnum_or_dash, key += ch)
fsm_transition(read_nested_group(ps, begin_section()), done, '.')
fsm_transition(read_ini_section(ps, begin_section()), done, ']')
}
term_state(done) {
// nop
}
fin();
// clang-format on
}
/// Reads an INI formatted input.
template <class State, class Consumer>
void read_ini(State& ps, Consumer&& consumer) {
using std::swap;
std::string tmp{"global"};
auto alnum = [](char x) { return isalnum(x) || x == '_'; };
auto alnum_or_dash
= [](char x) { return isalnum(x) || x == '_' || x == '-'; };
auto begin_section = [&]() -> decltype(consumer.begin_map()) {
std::string key;
swap(tmp, key);
consumer.key(std::move(key));
return consumer.begin_map();
};
// clang-format off
start();
// Scanning for first section.
term_state(init) {
transition(init, " \t\n")
fsm_epsilon(read_ini_comment(ps, consumer), init, ';')
transition(start_section, '[')
fsm_epsilon_if(tmp == "global", read_ini_section(ps, begin_section()),
return_to_global, alnum)
}
// Read the section key after reading an '['.
state(start_section) {
transition(start_section, " \t")
transition(read_section_name, alnum, tmp = ch)
}
// Reads a section name such as "[foo]".
state(read_section_name) {
transition(read_section_name, alnum_or_dash, tmp += ch)
fsm_transition(read_nested_group(ps, begin_section()), return_to_global, '.')
epsilon(close_section)
}
// Wait for the closing ']', preceded by any number of whitespaces.
state(close_section) {
transition(close_section, " \t")
fsm_transition(read_ini_section(ps, begin_section()), return_to_global, ']')
}
unstable_state(return_to_global) {
epsilon(init, any_char, tmp = "global")
}
fin();
// clang-format on
}
} // namespace caf::detail::parser
#include "caf/detail/parser/fsm_undef.hpp"
CAF_POP_WARNINGS
...@@ -340,8 +340,15 @@ private: ...@@ -340,8 +340,15 @@ private:
// Configures verbosity and output generation. // Configures verbosity and output generation.
config cfg_; config cfg_;
// Filters events by component name. // Filters events by component name before enqueuing a log event. Union of
std::vector<std::string> component_blacklist; // file_filter_ and console_filter_ if both outputs are enabled.
std::vector<std::string> global_filter_;
// Filters events by component name for file output.
std::vector<std::string> file_filter_;
// Filters events by component name for console output.
std::vector<std::string> console_filter_;
// References the parent system. // References the parent system.
actor_system& system_; actor_system& system_;
......
...@@ -320,7 +320,7 @@ actor_system::actor_system(actor_system_config& cfg) ...@@ -320,7 +320,7 @@ actor_system::actor_system(actor_system_config& cfg)
}; };
sched_conf sc = stealing; sched_conf sc = stealing;
namespace sr = defaults::scheduler; namespace sr = defaults::scheduler;
auto sr_policy = get_or(cfg, "scheduler.policy", sr::policy); auto sr_policy = get_or(cfg, "caf.scheduler.policy", sr::policy);
if (sr_policy == "sharing") if (sr_policy == "sharing")
sc = sharing; sc = sharing;
else if (sr_policy == "testing") else if (sr_policy == "testing")
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include "caf/detail/config_consumer.hpp" #include "caf/detail/config_consumer.hpp"
#include "caf/detail/gcd.hpp" #include "caf/detail/gcd.hpp"
#include "caf/detail/parser/read_config.hpp" #include "caf/detail/parser/read_config.hpp"
#include "caf/detail/parser/read_ini.hpp"
#include "caf/detail/parser/read_string.hpp" #include "caf/detail/parser/read_string.hpp"
#include "caf/message_builder.hpp" #include "caf/message_builder.hpp"
#include "caf/pec.hpp" #include "caf/pec.hpp"
...@@ -50,7 +49,7 @@ actor_system_config::~actor_system_config() { ...@@ -50,7 +49,7 @@ actor_system_config::~actor_system_config() {
} }
// in this config class, we have (1) hard-coded defaults that are overridden // in this config class, we have (1) hard-coded defaults that are overridden
// by (2) INI-file contents that are in turn overridden by (3) CLI arguments // by (2) config file contents that are in turn overridden by (3) CLI arguments
actor_system_config::actor_system_config() actor_system_config::actor_system_config()
: cli_helptext_printed(false), : cli_helptext_printed(false),
...@@ -61,31 +60,32 @@ actor_system_config::actor_system_config() ...@@ -61,31 +60,32 @@ actor_system_config::actor_system_config()
stream_desired_batch_complexity = defaults::stream::desired_batch_complexity; stream_desired_batch_complexity = defaults::stream::desired_batch_complexity;
stream_max_batch_delay = defaults::stream::max_batch_delay; stream_max_batch_delay = defaults::stream::max_batch_delay;
stream_credit_round_interval = defaults::stream::credit_round_interval; stream_credit_round_interval = defaults::stream::credit_round_interval;
// fill our options vector for creating INI and CLI parsers // fill our options vector for creating config file and CLI parsers
using std::string; using std::string;
using string_list = std::vector<string>;
opt_group{custom_options_, "global"} opt_group{custom_options_, "global"}
.add<bool>("help,h?", "print help text to STDERR and exit") .add<bool>("help,h?", "print help text to STDERR and exit")
.add<bool>("long-help", "print long help text to STDERR and exit") .add<bool>("long-help", "print long help text to STDERR and exit")
.add<bool>("dump-config", "print configuration to STDERR and exit") .add<bool>("dump-config", "print configuration to STDERR and exit")
.add<string>(config_file_path, "config-file", .add<string>(config_file_path, "config-file",
"set config file (default: caf-application.ini)"); "set config file (default: caf-application.conf)");
opt_group{custom_options_, "stream"} opt_group{custom_options_, "caf.stream"}
.add<timespan>(stream_desired_batch_complexity, "desired-batch-complexity", .add<timespan>(stream_desired_batch_complexity, "desired-batch-complexity",
"processing time per batch") "processing time per batch")
.add<timespan>(stream_max_batch_delay, "max-batch-delay", .add<timespan>(stream_max_batch_delay, "max-batch-delay",
"maximum delay for partial batches") "maximum delay for partial batches")
.add<timespan>(stream_credit_round_interval, "credit-round-interval", .add<timespan>(stream_credit_round_interval, "credit-round-interval",
"time between emitting credit") "time between emitting credit")
.add<std::string>("credit-policy", .add<string>("credit-policy",
"selects an algorithm for credit computation"); "selects an algorithm for credit computation");
opt_group{custom_options_, "scheduler"} opt_group{custom_options_, "caf.scheduler"}
.add<std::string>("policy", "'stealing' (default) or 'sharing'") .add<string>("policy", "'stealing' (default) or 'sharing'")
.add<size_t>("max-threads", "maximum number of worker threads") .add<size_t>("max-threads", "maximum number of worker threads")
.add<size_t>("max-throughput", "nr. of messages actors can consume per run") .add<size_t>("max-throughput", "nr. of messages actors can consume per run")
.add<bool>("enable-profiling", "enables profiler output") .add<bool>("enable-profiling", "enables profiler output")
.add<timespan>("profiling-resolution", "data collection rate") .add<timespan>("profiling-resolution", "data collection rate")
.add<string>("profiling-output-file", "output file for the profiler"); .add<string>("profiling-output-file", "output file for the profiler");
opt_group(custom_options_, "work-stealing") opt_group(custom_options_, "caf.work-stealing")
.add<size_t>("aggressive-poll-attempts", "nr. of aggressive steal attempts") .add<size_t>("aggressive-poll-attempts", "nr. of aggressive steal attempts")
.add<size_t>("aggressive-steal-interval", .add<size_t>("aggressive-steal-interval",
"frequency of aggressive steal attempts") "frequency of aggressive steal attempts")
...@@ -98,24 +98,23 @@ actor_system_config::actor_system_config() ...@@ -98,24 +98,23 @@ actor_system_config::actor_system_config()
"frequency of relaxed steal attempts") "frequency of relaxed steal attempts")
.add<timespan>("relaxed-sleep-duration", .add<timespan>("relaxed-sleep-duration",
"sleep duration between relaxed steal attempts"); "sleep duration between relaxed steal attempts");
opt_group{custom_options_, "logger"} opt_group{custom_options_, "caf.logger"} //
.add<std::string>("verbosity", "default verbosity for file and console")
.add<string>("file-name", "filesystem path of the log file")
.add<string>("file-format", "line format for individual log file entries")
.add<std::string>("file-verbosity", "file output verbosity")
.add<std::string>("console",
"std::clog output: none, colored, or uncolored")
.add<string>("console-format", "line format for printed log entries")
.add<std::string>("console-verbosity", "console output verbosity")
.add<std::vector<std::string>>("component-blacklist",
"excluded components for logging")
.add<bool>("inline-output", "disable logger thread (for testing only!)"); .add<bool>("inline-output", "disable logger thread (for testing only!)");
opt_group{custom_options_, "middleman"} opt_group{custom_options_, "caf.logger.file"}
.add<string>("path", "filesystem path for the log file")
.add<string>("format", "format for individual log file entries")
.add<string>("verbosity", "minimum severity level for file output")
.add<string_list>("excluded-components", "excluded components in files");
opt_group{custom_options_, "caf.logger.console"}
.add<bool>("colored", "forces colored or uncolored output")
.add<string>("format", "format for printed console lines")
.add<string>("verbosity", "minimum severity level for console output")
.add<string_list>("excluded-components", "excluded components on console");
opt_group{custom_options_, "caf.middleman"}
.add<std::string>("network-backend", .add<std::string>("network-backend",
"either 'default' or 'asio' (if available)") "either 'default' or 'asio' (if available)")
.add<std::vector<string>>("app-identifiers", .add<std::vector<string>>("app-identifiers",
"valid application identifiers of this node") "valid application identifiers of this node")
.add<string>("app-identifier", "DEPRECATED: use app-identifiers instead")
.add<bool>("enable-automatic-connections", .add<bool>("enable-automatic-connections",
"enables automatic connection management") "enables automatic connection management")
.add<size_t>("max-consecutive-reads", .add<size_t>("max-consecutive-reads",
...@@ -126,7 +125,7 @@ actor_system_config::actor_system_config() ...@@ -126,7 +125,7 @@ actor_system_config::actor_system_config()
.add<bool>("manual-multiplexing", .add<bool>("manual-multiplexing",
"disables background activity of the multiplexer") "disables background activity of the multiplexer")
.add<size_t>("workers", "number of deserialization workers"); .add<size_t>("workers", "number of deserialization workers");
opt_group(custom_options_, "openssl") opt_group(custom_options_, "caf.openssl")
.add<string>(openssl_certificate, "certificate", .add<string>(openssl_certificate, "certificate",
"path to the PEM-formatted certificate file") "path to the PEM-formatted certificate file")
.add<string>(openssl_key, "key", .add<string>(openssl_key, "key",
...@@ -141,8 +140,9 @@ actor_system_config::actor_system_config() ...@@ -141,8 +140,9 @@ actor_system_config::actor_system_config()
settings actor_system_config::dump_content() const { settings actor_system_config::dump_content() const {
settings result = content; settings result = content;
auto& caf_group = result["caf"].as_dictionary();
// -- streaming parameters // -- streaming parameters
auto& stream_group = result["stream"].as_dictionary(); auto& stream_group = caf_group["stream"].as_dictionary();
put_missing(stream_group, "desired-batch-complexity", put_missing(stream_group, "desired-batch-complexity",
defaults::stream::desired_batch_complexity); defaults::stream::desired_batch_complexity);
put_missing(stream_group, "max-batch-delay", put_missing(stream_group, "max-batch-delay",
...@@ -155,7 +155,7 @@ settings actor_system_config::dump_content() const { ...@@ -155,7 +155,7 @@ settings actor_system_config::dump_content() const {
put_missing(stream_group, "size-policy.bytes-per-batch", put_missing(stream_group, "size-policy.bytes-per-batch",
defaults::stream::size_policy::bytes_per_batch); defaults::stream::size_policy::bytes_per_batch);
// -- scheduler parameters // -- scheduler parameters
auto& scheduler_group = result["scheduler"].as_dictionary(); auto& scheduler_group = caf_group["scheduler"].as_dictionary();
put_missing(scheduler_group, "policy", defaults::scheduler::policy); put_missing(scheduler_group, "policy", defaults::scheduler::policy);
put_missing(scheduler_group, "max-throughput", put_missing(scheduler_group, "max-throughput",
defaults::scheduler::max_throughput); defaults::scheduler::max_throughput);
...@@ -164,7 +164,7 @@ settings actor_system_config::dump_content() const { ...@@ -164,7 +164,7 @@ settings actor_system_config::dump_content() const {
defaults::scheduler::profiling_resolution); defaults::scheduler::profiling_resolution);
put_missing(scheduler_group, "profiling-output-file", std::string{}); put_missing(scheduler_group, "profiling-output-file", std::string{});
// -- work-stealing parameters // -- work-stealing parameters
auto& work_stealing_group = result["work-stealing"].as_dictionary(); auto& work_stealing_group = caf_group["work-stealing"].as_dictionary();
put_missing(work_stealing_group, "aggressive-poll-attempts", put_missing(work_stealing_group, "aggressive-poll-attempts",
defaults::work_stealing::aggressive_poll_attempts); defaults::work_stealing::aggressive_poll_attempts);
put_missing(work_stealing_group, "aggressive-steal-interval", put_missing(work_stealing_group, "aggressive-steal-interval",
...@@ -180,18 +180,18 @@ settings actor_system_config::dump_content() const { ...@@ -180,18 +180,18 @@ settings actor_system_config::dump_content() const {
put_missing(work_stealing_group, "relaxed-sleep-duration", put_missing(work_stealing_group, "relaxed-sleep-duration",
defaults::work_stealing::relaxed_sleep_duration); defaults::work_stealing::relaxed_sleep_duration);
// -- logger parameters // -- logger parameters
auto& logger_group = result["logger"].as_dictionary(); auto& logger_group = caf_group["logger"].as_dictionary();
put_missing(logger_group, "file-name", defaults::logger::file_name);
put_missing(logger_group, "file-format", defaults::logger::file_format);
put_missing(logger_group, "file-verbosity", defaults::logger::file_verbosity);
put_missing(logger_group, "console", defaults::logger::console);
put_missing(logger_group, "console-format", defaults::logger::console_format);
put_missing(logger_group, "console-verbosity",
defaults::logger::console_verbosity);
put_missing(logger_group, "component-blacklist", std::vector<std::string>{});
put_missing(logger_group, "inline-output", false); put_missing(logger_group, "inline-output", false);
auto& file_group = logger_group["file"].as_dictionary();
put_missing(file_group, "path", defaults::logger::file::path);
put_missing(file_group, "format", defaults::logger::file::format);
put_missing(file_group, "excluded-components", std::vector<std::string>{});
auto& console_group = logger_group["console"].as_dictionary();
put_missing(console_group, "colored", defaults::logger::console::colored);
put_missing(console_group, "format", defaults::logger::console::format);
put_missing(console_group, "excluded-components", std::vector<std::string>{});
// -- middleman parameters // -- middleman parameters
auto& middleman_group = result["middleman"].as_dictionary(); auto& middleman_group = caf_group["middleman"].as_dictionary();
auto default_id = to_string(defaults::middleman::app_identifier); auto default_id = to_string(defaults::middleman::app_identifier);
put_missing(middleman_group, "app-identifiers", put_missing(middleman_group, "app-identifiers",
std::vector<std::string>{std::move(default_id)}); std::vector<std::string>{std::move(default_id)});
...@@ -201,7 +201,7 @@ settings actor_system_config::dump_content() const { ...@@ -201,7 +201,7 @@ settings actor_system_config::dump_content() const {
put_missing(middleman_group, "heartbeat-interval", put_missing(middleman_group, "heartbeat-interval",
defaults::middleman::heartbeat_interval); defaults::middleman::heartbeat_interval);
// -- openssl parameters // -- openssl parameters
auto& openssl_group = result["openssl"].as_dictionary(); auto& openssl_group = caf_group["openssl"].as_dictionary();
put_missing(openssl_group, "certificate", std::string{}); put_missing(openssl_group, "certificate", std::string{});
put_missing(openssl_group, "key", std::string{}); put_missing(openssl_group, "key", std::string{});
put_missing(openssl_group, "passphrase", std::string{}); put_missing(openssl_group, "passphrase", std::string{});
...@@ -211,31 +211,31 @@ settings actor_system_config::dump_content() const { ...@@ -211,31 +211,31 @@ settings actor_system_config::dump_content() const {
} }
error actor_system_config::parse(int argc, char** argv, error actor_system_config::parse(int argc, char** argv,
const char* ini_file_cstr) { const char* config_file_cstr) {
string_list args; string_list args;
if (argc > 1) if (argc > 1)
args.assign(argv + 1, argv + argc); args.assign(argv + 1, argv + argc);
return parse(std::move(args), ini_file_cstr); return parse(std::move(args), config_file_cstr);
} }
error actor_system_config::parse(int argc, char** argv, std::istream& ini) { error actor_system_config::parse(int argc, char** argv, std::istream& conf) {
string_list args; string_list args;
if (argc > 1) if (argc > 1)
args.assign(argv + 1, argv + argc); args.assign(argv + 1, argv + argc);
return parse(std::move(args), ini); return parse(std::move(args), conf);
} }
namespace { namespace {
struct config_iter { struct config_iter {
std::istream* ini; std::istream* conf;
char ch; char ch;
explicit config_iter(std::istream* istr) : ini(istr) { explicit config_iter(std::istream* istr) : conf(istr) {
ini->get(ch); conf->get(ch);
} }
config_iter() : ini(nullptr), ch('\0') { config_iter() : conf(nullptr), ch('\0') {
// nop // nop
} }
...@@ -248,7 +248,7 @@ struct config_iter { ...@@ -248,7 +248,7 @@ struct config_iter {
} }
inline config_iter& operator++() { inline config_iter& operator++() {
ini->get(ch); conf->get(ch);
return *this; return *this;
} }
}; };
...@@ -256,7 +256,7 @@ struct config_iter { ...@@ -256,7 +256,7 @@ struct config_iter {
struct config_sentinel {}; struct config_sentinel {};
bool operator!=(config_iter iter, config_sentinel) { bool operator!=(config_iter iter, config_sentinel) {
return !iter.ini->fail(); return !iter.conf->fail();
} }
struct indentation { struct indentation {
...@@ -335,7 +335,7 @@ error actor_system_config::parse(string_list args, std::istream& config) { ...@@ -335,7 +335,7 @@ error actor_system_config::parse(string_list args, std::istream& config) {
std::cout << std::flush; std::cout << std::flush;
cli_helptext_printed = true; cli_helptext_printed = true;
} }
return adjust_content(); return none;
} }
error actor_system_config::parse(string_list args, error actor_system_config::parse(string_list args,
...@@ -348,18 +348,6 @@ error actor_system_config::parse(string_list args, ...@@ -348,18 +348,6 @@ error actor_system_config::parse(string_list args,
return err; return err;
if (config_file_path == "$DEFAULT") { if (config_file_path == "$DEFAULT") {
std::ifstream conf{"caf-application.conf"}; std::ifstream conf{"caf-application.conf"};
// TODO: The .ini parser is deprecated. Remove with CAF 0.19.
if (!conf.is_open()) {
conf.open("caf-application.ini");
if (conf.is_open()) {
// Consume the ini file here, because the parse() overload that takes
// an istream assumes the new config format.
if (auto err = parse_ini(conf, custom_options_, content))
return err;
std::ifstream dummy;
return parse(std::move(args), dummy);
}
}
return parse(std::move(args), conf); return parse(std::move(args), conf);
} }
std::ifstream conf{config_file_path}; std::ifstream conf{config_file_path};
...@@ -374,11 +362,6 @@ actor_system_config& actor_system_config::add_actor_factory(std::string name, ...@@ -374,11 +362,6 @@ actor_system_config& actor_system_config::add_actor_factory(std::string name,
actor_system_config& actor_system_config::set_impl(string_view name, actor_system_config& actor_system_config::set_impl(string_view name,
config_value value) { config_value value) {
if (name == "middleman.app-identifier") {
// TODO: Print a warning with 0.18 and remove this code with 0.19.
value.convert_to_list();
return set_impl("middleman.app-identifiers", std::move(value));
}
auto opt = custom_options_.qualified_name_lookup(name); auto opt = custom_options_.qualified_name_lookup(name);
if (opt == nullptr) { if (opt == nullptr) {
std::cerr << "*** failed to set config parameter " << name std::cerr << "*** failed to set config parameter " << name
...@@ -389,9 +372,10 @@ actor_system_config& actor_system_config::set_impl(string_view name, ...@@ -389,9 +372,10 @@ actor_system_config& actor_system_config::set_impl(string_view name,
} else { } else {
opt->store(value); opt->store(value);
auto category = opt->category(); auto category = opt->category();
auto& dict = category == "global" ? content if (category == "global")
: content[category].as_dictionary(); content[opt->long_name()] = std::move(value);
dict[opt->long_name()] = std::move(value); else
put(content, name, std::move(value));
} }
return *this; return *this;
} }
...@@ -418,14 +402,6 @@ actor_system_config::parse_config_file(const char* filename, ...@@ -418,14 +402,6 @@ actor_system_config::parse_config_file(const char* filename,
std::ifstream f{filename}; std::ifstream f{filename};
if (!f.is_open()) if (!f.is_open())
return make_error(sec::cannot_open_file, filename); return make_error(sec::cannot_open_file, filename);
// TODO: The .ini parser is deprecated. Remove this block with CAF 0.19.
string_view fname{filename, strlen(filename)};
if (ends_with(fname, ".ini")) {
settings result;
if (auto err = parse_ini(f, opts, result))
return err;
return result;
}
return parse_config(f, opts); return parse_config(f, opts);
} }
...@@ -456,19 +432,6 @@ error actor_system_config::parse_config(std::istream& source, ...@@ -456,19 +432,6 @@ error actor_system_config::parse_config(std::istream& source,
return none; return none;
} }
error actor_system_config::parse_ini(std::istream& source,
const config_option_set& opts,
settings& result) {
if (!source)
return make_error(sec::runtime_error, "source stream invalid");
detail::config_consumer consumer{opts, result};
parser_state<config_iter, config_sentinel> res{config_iter{&source}};
detail::parser::read_ini(res, consumer);
if (res.i != res.e)
return make_error(res.code, res.line, res.column);
return none;
}
error actor_system_config::extract_config_file_path(string_list& args) { error actor_system_config::extract_config_file_path(string_list& args) {
auto ptr = custom_options_.qualified_name_lookup("global.config-file"); auto ptr = custom_options_.qualified_name_lookup("global.config-file");
CAF_ASSERT(ptr != nullptr); CAF_ASSERT(ptr != nullptr);
...@@ -489,25 +452,6 @@ error actor_system_config::extract_config_file_path(string_list& args) { ...@@ -489,25 +452,6 @@ error actor_system_config::extract_config_file_path(string_list& args) {
return none; return none;
} }
error actor_system_config::adjust_content() {
// TODO: Print a warning to STDERR if 'app-identifier' is present with 0.18
// and remove this code with 0.19.
auto i = content.find("middleman");
if (i != content.end()) {
if (auto mm = get_if<settings>(&i->second)) {
auto j = mm->find("app-identifier");
if (j != mm->end()) {
if (!mm->contains("app-identifiers")) {
j->second.convert_to_list();
mm->emplace("app-identifiers", std::move(j->second));
}
mm->container().erase(j);
}
}
}
return none;
}
const settings& content(const actor_system_config& cfg) { const settings& content(const actor_system_config& cfg) {
return cfg.content; return cfg.content;
} }
......
...@@ -236,9 +236,7 @@ config_option_set::parse(settings& config, ...@@ -236,9 +236,7 @@ config_option_set::parse(settings& config,
} }
config_option_set::option_pointer config_option_set::option_pointer
config_option_set::cli_long_name_lookup(string_view input) const { config_option_set::cli_long_name_lookup(string_view name) const {
// We accept "caf#" prefixes for backward compatibility, but ignore them.
auto name = input.substr(input.compare(0, 4, "caf#") != 0 ? 0u : 4u);
// Extract category and long name. // Extract category and long name.
string_view category; string_view category;
string_view long_name; string_view long_name;
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* 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/ini_consumer.hpp"
#include "caf/pec.hpp"
namespace caf::detail {
// -- abstract_ini_consumer ----------------------------------------------------
abstract_ini_consumer::abstract_ini_consumer(abstract_ini_consumer* parent)
: parent_(parent) {
// nop
}
abstract_ini_consumer::~abstract_ini_consumer() {
// nop
}
ini_map_consumer abstract_ini_consumer::begin_map() {
return {this};
}
ini_list_consumer abstract_ini_consumer::begin_list() {
return {this};
}
// -- map_consumer -------------------------------------------------------------
ini_map_consumer::ini_map_consumer(abstract_ini_consumer* parent)
: super(parent), i_(xs_.end()) {
CAF_ASSERT(parent != nullptr);
}
ini_map_consumer::ini_map_consumer(ini_map_consumer&& other)
: super(other.parent()) {
}
ini_map_consumer::~ini_map_consumer() {
// nop
}
void ini_map_consumer::end_map() {
parent_->value_impl(config_value{std::move(xs_)});
}
void ini_map_consumer::key(std::string name) {
i_ = xs_.emplace(std::move(name), config_value{}).first;
}
void ini_map_consumer::value_impl(config_value&& x) {
CAF_ASSERT(i_ != xs_.end());
i_->second = std::move(x);
}
// -- ini_list_consumer --------------------------------------------------------
ini_list_consumer::ini_list_consumer(abstract_ini_consumer* parent)
: super(parent) {
CAF_ASSERT(parent != nullptr);
}
ini_list_consumer::ini_list_consumer(ini_list_consumer&& other)
: super(other.parent()), xs_(std::move(other.xs_)) {
// nop
}
void ini_list_consumer::end_list() {
parent_->value_impl(config_value{std::move(xs_)});
}
void ini_list_consumer::value_impl(config_value&& x) {
xs_.emplace_back(std::move(x));
}
// -- ini_value_consumer -------------------------------------------------------
ini_value_consumer::ini_value_consumer(abstract_ini_consumer* parent)
: super(parent) {
// nop
}
void ini_value_consumer::value_impl(config_value&& x) {
result = std::move(x);
}
// -- ini_category_consumer ----------------------------------------------------
ini_category_consumer::ini_category_consumer(ini_consumer* parent,
std::string category)
: super(parent), category_(std::move(category)) {
CAF_ASSERT(parent_ != nullptr);
}
ini_category_consumer::ini_category_consumer(ini_category_consumer&& other)
: super(other.parent()),
category_(std::move(other.category_)),
xs_(std::move(other.xs_)),
current_key(std::move(other.current_key)) {
CAF_ASSERT(parent_ != nullptr);
}
void ini_category_consumer::end_map() {
parent_->value_impl(config_value{std::move(xs_)});
}
void ini_category_consumer::key(std::string name) {
current_key = std::move(name);
}
void ini_category_consumer::value_impl(config_value&& x) {
// See whether there's an config_option associated to this category and key.
auto opt = dparent()->options_.qualified_name_lookup(category_, current_key);
if (opt == nullptr) {
// Simply store in config if no option was found.
xs_.emplace(std::move(current_key), std::move(x));
} else {
// Perform a type check to see whether this is a valid input.
if (opt->check(x) == none) {
opt->store(x);
xs_.emplace(std::move(current_key), std::move(x));
} else {
dparent()->warnings_.emplace_back(make_error(pec::type_mismatch));
}
}
}
ini_consumer* ini_category_consumer::dparent() {
// Safe, because our constructor only accepts ini_consumer parents.
return static_cast<ini_consumer*>(parent());
}
// -- ini_consumer -------------------------------------------------------------
ini_consumer::ini_consumer(const config_option_set& options, settings& cfg)
: options_(options), cfg_(cfg), current_key_("global") {
// nop
}
ini_category_consumer ini_consumer::begin_map() {
return {this, current_key_};
}
void ini_consumer::key(std::string name) {
current_key_ = std::move(name);
}
void ini_consumer::value_impl(config_value&& x) {
using dict_type = config_value::dictionary;
auto dict = get_if<dict_type>(&x);
if (dict == nullptr) {
warnings_.emplace_back(
make_error(pec::type_mismatch, "expected a dictionary at top level"));
return;
}
if (current_key_ != "global") {
auto& dst = cfg_.emplace(current_key_, dict_type{}).first->second;
if (dict != nullptr && !dict->empty()
&& holds_alternative<dict_type>(dst)) {
auto& dst_dict = get<dict_type>(dst);
// We need to "merge" values into the destination, because it can already
// contain any number of unrelated entries.
for (auto& entry : *dict)
dst_dict.insert_or_assign(entry.first, std::move(entry.second));
}
} else {
std::string prev_key;
swap(current_key_, prev_key);
for (auto& entry : *dict) {
if (holds_alternative<dict_type>(entry.second)) {
// Recurse into top-level maps.
current_key_ = std::move(entry.first);
value_impl(std::move(entry.second));
} else {
cfg_.insert_or_assign(entry.first, std::move(entry.second));
}
}
swap(prev_key, current_key_);
}
}
} // namespace caf::detail
...@@ -55,7 +55,7 @@ void await_all_locals_down(actor_system& sys, std::initializer_list<actor> xs) { ...@@ -55,7 +55,7 @@ void await_all_locals_down(actor_system& sys, std::initializer_list<actor> xs) {
ys.push_back(x); ys.push_back(x);
} }
// Don't block when using the test coordinator. // Don't block when using the test coordinator.
if (auto policy = get_if<std::string>(&sys.config(), "scheduler.policy"); if (auto policy = get_if<std::string>(&sys.config(), "caf.scheduler.policy");
policy && *policy != "testing") policy && *policy != "testing")
self->wait_for(ys); self->wait_for(ys);
} }
......
...@@ -78,7 +78,7 @@ inbound_path::inbound_path(stream_manager_ptr mgr_ptr, stream_slots id, ...@@ -78,7 +78,7 @@ inbound_path::inbound_path(stream_manager_ptr mgr_ptr, stream_slots id,
<< detail::global_meta_object(in_type)->type_name << detail::global_meta_object(in_type)->type_name
<< "at slot" << id.receiver << "from" << hdl); << "at slot" << id.receiver << "from" << hdl);
if (auto str = get_if<std::string>(&self()->system().config(), if (auto str = get_if<std::string>(&self()->system().config(),
"stream.credit-policy")) { "caf.stream.credit-policy")) {
if (*str == "testing") if (*str == "testing")
controller_.reset(new detail::test_credit_controller(self())); controller_.reset(new detail::test_credit_controller(self()));
else if (*str == "size") else if (*str == "size")
......
...@@ -283,7 +283,7 @@ logger* logger::current_logger() { ...@@ -283,7 +283,7 @@ logger* logger::current_logger() {
bool logger::accepts(unsigned level, string_view cname) { bool logger::accepts(unsigned level, string_view cname) {
if (level > cfg_.verbosity) if (level > cfg_.verbosity)
return false; return false;
return !std::any_of(component_blacklist.begin(), component_blacklist.end(), return std::none_of(global_filter_.begin(), global_filter_.end(),
[=](string_view name) { return name == cname; }); [=](string_view name) { return name == cname; });
} }
...@@ -302,51 +302,48 @@ logger::~logger() { ...@@ -302,51 +302,48 @@ logger::~logger() {
void logger::init(actor_system_config& cfg) { void logger::init(actor_system_config& cfg) {
CAF_IGNORE_UNUSED(cfg); CAF_IGNORE_UNUSED(cfg);
namespace lg = defaults::logger; namespace lg = defaults::logger;
using std::string;
using string_list = std::vector<std::string>; using string_list = std::vector<std::string>;
auto blacklist = get_if<string_list>(&cfg, "logger.component-blacklist"); auto get_verbosity = [&cfg](string_view key) -> unsigned {
if (blacklist) if (auto str = get_if<string>(&cfg, key))
component_blacklist = move_if_optional(blacklist); return to_level_int(*str);
// Parse the configured log level. We only store a string_view to the return CAF_LOG_LEVEL_QUIET;
// verbosity levels, so we make sure we actually get a string pointer here };
// (and not an optional<string>). auto read_filter = [&cfg](string_list& var, string_view key) {
const std::string* verbosity = get_if<std::string>(&cfg, "logger.verbosity"); if (auto lst = get_if<string_list>(&cfg, key))
auto set_level = [&](auto& var, auto var_default, string_view var_key) { var = std::move(*lst);
// User-provided overrides have the highest priority.
if (const std::string* var_override = get_if<std::string>(&cfg, var_key)) {
var = *var_override;
return;
}
// If present, "logger.verbosity" overrides the defaults for both file and
// console verbosity level.
if (verbosity) {
var = *verbosity;
return;
}
var = var_default;
}; };
string_view file_str; cfg_.file_verbosity = get_verbosity("caf.logger.file.verbosity");
string_view console_str; cfg_.console_verbosity = get_verbosity("caf.logger.console.verbosity");
set_level(file_str, lg::file_verbosity, "logger.file-verbosity");
set_level(console_str, lg::console_verbosity, "logger.console-verbosity");
cfg_.file_verbosity = to_level_int(file_str);
cfg_.console_verbosity = to_level_int(console_str);
cfg_.verbosity = std::max(cfg_.file_verbosity, cfg_.console_verbosity); cfg_.verbosity = std::max(cfg_.file_verbosity, cfg_.console_verbosity);
if (cfg_.verbosity == CAF_LOG_LEVEL_QUIET)
return;
if (cfg_.file_verbosity > CAF_LOG_LEVEL_QUIET
&& cfg_.console_verbosity > CAF_LOG_LEVEL_QUIET) {
read_filter(file_filter_, "caf.logger.file.excluded-components");
read_filter(console_filter_, "caf.logger.console.excluded-components");
std::sort(file_filter_.begin(), file_filter_.end());
std::sort(console_filter_.begin(), console_filter_.end());
std::set_union(file_filter_.begin(), file_filter_.end(),
console_filter_.begin(), console_filter_.end(),
std::back_inserter(global_filter_));
} else if (cfg_.file_verbosity > CAF_LOG_LEVEL_QUIET) {
read_filter(file_filter_, "caf.logger.file.excluded-components");
global_filter_ = file_filter_;
} else {
read_filter(console_filter_, "caf.logger.console.excluded-components");
global_filter_ = console_filter_;
}
// Parse the format string. // Parse the format string.
file_format_ = file_format_
parse_format(get_or(cfg, "logger.file-format", lg::file_format)); = parse_format(get_or(cfg, "caf.logger.file.format", lg::file::format));
console_format_ = parse_format(get_or(cfg,"logger.console-format", console_format_ = parse_format(
lg::console_format)); get_or(cfg, "caf.logger.console.format", lg::console::format));
// Set flags. // Set flags.
if (get_or(cfg, "logger.inline-output", false)) if (get_or(cfg, "caf.logger.inline-output", false))
cfg_.inline_output = true; cfg_.inline_output = true;
auto con = get_or(cfg, "logger.console", lg::console); // If not set to `false`, CAF enables colored output when writing to TTYs.
if (con == "colored") { cfg_.console_coloring = get_or(cfg, "caf.logger.console.colored", true);
cfg_.console_coloring = true;
} else if (con != "uncolored") {
// Disable console output if neither 'colored' nor 'uncolored' are present.
cfg_.console_verbosity = CAF_LOG_LEVEL_QUIET;
cfg_.verbosity = cfg_.file_verbosity;
}
} }
bool logger::open_file() { bool logger::open_file() {
...@@ -530,13 +527,18 @@ void logger::run() { ...@@ -530,13 +527,18 @@ void logger::run() {
void logger::handle_file_event(const event& x) { void logger::handle_file_event(const event& x) {
// Print to file if available. // Print to file if available.
if (file_ && x.level <= file_verbosity()) if (file_ && x.level <= file_verbosity()
&& none_of(file_filter_.begin(), file_filter_.end(),
[&x](string_view name) { return name == x.category_name; }))
render(file_, file_format_, x); render(file_, file_format_, x);
} }
void logger::handle_console_event(const event& x) { void logger::handle_console_event(const event& x) {
if (x.level > console_verbosity()) if (x.level > console_verbosity())
return; return;
if (std::any_of(console_filter_.begin(), console_filter_.end(),
[&x](string_view name) { return name == x.category_name; }))
return;
if (cfg_.console_coloring) { if (cfg_.console_coloring) {
switch (x.level) { switch (x.level) {
default: default:
...@@ -572,21 +574,20 @@ void logger::handle_event(const event& x) { ...@@ -572,21 +574,20 @@ void logger::handle_event(const event& x) {
void logger::log_first_line() { void logger::log_first_line() {
auto e = CAF_LOG_MAKE_EVENT(0, CAF_LOG_COMPONENT, CAF_LOG_LEVEL_DEBUG, ""); auto e = CAF_LOG_MAKE_EVENT(0, CAF_LOG_COMPONENT, CAF_LOG_LEVEL_DEBUG, "");
auto make_message = [&](string_view config_name, std::string default_value) { auto make_message = [&](int level, const auto& filter) {
std::string msg = "level = "; auto lvl_str = log_level_name[level];
msg += get_or(system_.config(), config_name, default_value); std::string msg = "verbosity = ";
msg.insert(msg.end(), lvl_str.begin(), lvl_str.end());
msg += ", node = "; msg += ", node = ";
msg += to_string(system_.node()); msg += to_string(system_.node());
msg += ", component-blacklist = "; msg += ", excluded-components = ";
msg += deep_to_string(component_blacklist); msg += deep_to_string(filter);
return msg; return msg;
}; };
namespace lg = defaults::logger; namespace lg = defaults::logger;
e.message = make_message("logger.file-verbosity", e.message = make_message(cfg_.file_verbosity, file_filter_);
to_string(lg::file_verbosity));
handle_file_event(e); handle_file_event(e);
e.message = make_message("logger.console-verbosity", e.message = make_message(cfg_.console_verbosity, console_filter_);
to_string(lg::console_verbosity));
handle_console_event(e); handle_console_event(e);
} }
...@@ -599,8 +600,8 @@ void logger::start() { ...@@ -599,8 +600,8 @@ void logger::start() {
parent_thread_ = std::this_thread::get_id(); parent_thread_ = std::this_thread::get_id();
if (verbosity() == CAF_LOG_LEVEL_QUIET) if (verbosity() == CAF_LOG_LEVEL_QUIET)
return; return;
file_name_ = get_or(system_.config(), "logger.file-name", file_name_ = get_or(system_.config(), "caf.logger.file.path",
defaults::logger::file_name); defaults::logger::file::path);
if (file_name_.empty()) { if (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 (console_verbosity() == CAF_LOG_LEVEL_QUIET) if (console_verbosity() == CAF_LOG_LEVEL_QUIET)
......
...@@ -247,8 +247,9 @@ void abstract_coordinator::start() { ...@@ -247,8 +247,9 @@ void abstract_coordinator::start() {
void abstract_coordinator::init(actor_system_config& cfg) { void abstract_coordinator::init(actor_system_config& cfg) {
namespace sr = defaults::scheduler; namespace sr = defaults::scheduler;
max_throughput_ = get_or(cfg, "scheduler.max-throughput", sr::max_throughput); max_throughput_ = get_or(cfg, "caf.scheduler.max-throughput",
if (auto num_workers = get_if<size_t>(&cfg, "scheduler.max-threads")) sr::max_throughput);
if (auto num_workers = get_if<size_t>(&cfg, "caf.scheduler.max-threads"))
num_workers_ = *num_workers; num_workers_ = *num_workers;
else else
num_workers_ = default_thread_count(); num_workers_ = default_thread_count();
......
...@@ -109,7 +109,7 @@ behavior tester(event_based_actor* self, const actor& aut) { ...@@ -109,7 +109,7 @@ behavior tester(event_based_actor* self, const actor& aut) {
struct config : actor_system_config { struct config : actor_system_config {
config() { config() {
set("scheduler.policy", "testing"); set("caf.scheduler.policy", "testing");
} }
}; };
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* 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. *
******************************************************************************/
#define CAF_SUITE detail.ini_consumer
#include "caf/detail/ini_consumer.hpp"
#include "caf/test/dsl.hpp"
#include "caf/detail/parser/read_ini.hpp"
using std::string;
using namespace caf;
// List-of-strings.
using ls = std::vector<std::string>;
namespace {
constexpr const string_view test_ini = R"(
is_server=true
port=4242
nodes=["sun", "venus", ]
[logger]
file-name = "foobar.ini" ; our file name
[scheduler] ; more settings
timing = 2us ; using microsecond resolution
)";
constexpr const string_view test_ini2 = R"(
is_server = true
logger = {
file-name = "foobar.ini"
}
port = 4242
scheduler = {
timing = 2us,
}
nodes = ["sun", "venus"]
)";
struct fixture {
config_option_set options;
settings config;
fixture() {
options.add<bool>("global", "is_server", "enables server mode")
.add<uint16_t>("global", "port", "sets local or remote port")
.add<ls>("global", "nodes", "list of remote nodes")
.add<string>("logger", "file-name", "log output file")
.add<int>("scheduler", "padding", "some integer")
.add<timespan>("scheduler", "timing", "some timespan");
}
};
} // namespace
CAF_TEST_FIXTURE_SCOPE(ini_consumer_tests, fixture)
CAF_TEST(ini_value_consumer) {
string_view str = R"("hello world")";
detail::ini_value_consumer consumer;
string_parser_state res{str.begin(), str.end()};
detail::parser::read_ini_value(res, consumer);
CAF_CHECK_EQUAL(res.code, pec::success);
CAF_CHECK_EQUAL(get<string>(consumer.result), "hello world");
}
CAF_TEST(ini_consumer) {
string_view str = test_ini;
detail::ini_consumer consumer{options, config};
string_parser_state res{str.begin(), str.end()};
detail::parser::read_ini(res, consumer);
CAF_CHECK_EQUAL(res.code, pec::success);
CAF_CHECK_EQUAL(get<bool>(config, "is_server"), true);
CAF_CHECK_EQUAL(get<uint16_t>(config, "port"), 4242u);
CAF_CHECK_EQUAL(get<ls>(config, "nodes"), ls({"sun", "venus"}));
CAF_CHECK_EQUAL(get<string>(config, "logger.file-name"), "foobar.ini");
CAF_MESSAGE(config);
CAF_CHECK_EQUAL(get<timespan>(config, "scheduler.timing"), timespan(2000));
}
CAF_TEST(simplified syntax) {
CAF_MESSAGE("read test_ini");
{
detail::ini_consumer consumer{options, config};
string_parser_state res{test_ini.begin(), test_ini.end()};
detail::parser::read_ini(res, consumer);
CAF_CHECK_EQUAL(res.code, pec::success);
}
settings config2;
CAF_MESSAGE("read test_ini2");
{
detail::ini_consumer consumer{options, config2};
string_parser_state res{test_ini2.begin(), test_ini2.end()};
detail::parser::read_ini(res, consumer);
CAF_CHECK_EQUAL(res.code, pec::success);
}
CAF_CHECK_EQUAL(config, config2);
}
CAF_TEST_FIXTURE_SCOPE_END()
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* 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. *
******************************************************************************/
#define CAF_SUITE detail.parser.read_ini
#include "caf/detail/parser/read_ini.hpp"
#include "caf/test/dsl.hpp"
#include <string>
#include <vector>
#include "caf/config_value.hpp"
#include "caf/parser_state.hpp"
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
using namespace caf;
namespace {
using log_type = std::vector<std::string>;
struct test_consumer {
log_type log;
test_consumer() = default;
test_consumer(const test_consumer&) = delete;
test_consumer& operator=(const test_consumer&) = delete;
test_consumer& begin_map() {
log.emplace_back("{");
return *this;
}
void end_map() {
log.emplace_back("}");
}
test_consumer& begin_list() {
log.emplace_back("[");
return *this;
}
void end_list() {
log.emplace_back("]");
}
void key(std::string name) {
add_entry("key: ", std::move(name));
}
template <class T>
void value(T x) {
config_value cv{std::move(x)};
std::string entry = "value (";
entry += cv.type_name();
entry += "): ";
entry += to_string(cv);
log.emplace_back(std::move(entry));
}
void add_entry(const char* prefix, std::string str) {
str.insert(0, prefix);
log.emplace_back(std::move(str));
}
};
struct fixture {
expected<log_type> parse(string_view str, bool expect_success = true) {
test_consumer f;
string_parser_state res{str.begin(), str.end()};
detail::parser::read_ini(res, f);
if ((res.code == pec::success) != expect_success) {
CAF_MESSAGE("unexpected parser result state: " << res.code);
CAF_MESSAGE("input remainder: " << std::string(res.i, res.e));
}
return std::move(f.log);
}
};
template <class... Ts>
log_type make_log(Ts&&... xs) {
return log_type{std::forward<Ts>(xs)...};
}
// Tests basic functionality.
constexpr const string_view ini0 = R"(
[1group]
1value=321
[_foo]
_bar=11
[logger]
padding= 10
file-name = "foobar.ini" ; our file name
[scheduler] ; more settings
timing = 2us ; using microsecond resolution
x_ =.123
some-bool=true
some-other-bool=false
some-list=[
; here we have some list entries
123,
1..3,
23 ; twenty-three!
,2..4..2,
"abc", ; some comment and a trailing comma
]
some-map{
; here we have some list entries
entry1=123,
entry2=23 ; twenty-three! btw, comma is not mandatory
entry3= "abc" , ; some comment and a trailing comma
}
[middleman]
preconnect=[<
tcp://localhost:8080
>,<udp://remotehost?trust=false>]
)";
// clang-format off
const auto ini0_log = make_log(
"key: 1group",
"{",
"key: 1value",
"value (integer): 321",
"}",
"key: _foo",
"{",
"key: _bar",
"value (integer): 11",
"}",
"key: logger",
"{",
"key: padding",
"value (integer): 10",
"key: file-name",
"value (string): \"foobar.ini\"",
"}",
"key: scheduler",
"{",
"key: timing",
"value (timespan): 2us",
"key: x_",
"value (real): " + deep_to_string(.123),
"key: some-bool",
"value (boolean): true",
"key: some-other-bool",
"value (boolean): false",
"key: some-list",
"[",
"value (integer): 123",
"value (integer): 1",
"value (integer): 2",
"value (integer): 3",
"value (integer): 23",
"value (integer): 2",
"value (integer): 4",
"value (string): \"abc\"",
"]",
"key: some-map",
"{",
"key: entry1",
"value (integer): 123",
"key: entry2",
"value (integer): 23",
"key: entry3",
"value (string): \"abc\"",
"}",
"}",
"key: middleman",
"{",
"key: preconnect",
"[",
"value (uri): tcp://localhost:8080",
"value (uri): udp://remotehost?trust=false",
"]",
"}"
);
// clang-format on
// Tests nested parameters.
constexpr const string_view ini1 = R"(
foo {
bar = {
value1 = 1
}
value2 = 2
}
[bar.foo]
value3 = 3
)";
// clang-format off
const auto ini1_log = make_log(
"key: global",
"{",
"key: foo",
"{",
"key: bar",
"{",
"key: value1",
"value (integer): 1",
"}",
"key: value2",
"value (integer): 2",
"}",
"}",
"key: bar",
"{",
"key: foo",
"{",
"key: value3",
"value (integer): 3",
"}",
"}"
);
// clang-format on
constexpr const string_view ini2 = "#";
const auto ini2_log = make_log();
constexpr const string_view ini3 = "; foobar\n!";
const auto ini3_log = make_log();
} // namespace
CAF_TEST_FIXTURE_SCOPE(read_ini_tests, fixture)
CAF_TEST(empty inis) {
CAF_CHECK_EQUAL(parse(";foo"), make_log());
CAF_CHECK_EQUAL(parse(""), make_log());
CAF_CHECK_EQUAL(parse(" "), make_log());
CAF_CHECK_EQUAL(parse(" \n "), make_log());
CAF_CHECK_EQUAL(parse(";hello\n;world"), make_log());
}
CAF_TEST(section with valid key - value pairs) {
CAF_CHECK_EQUAL(parse("[foo]"), make_log("key: foo", "{", "}"));
CAF_CHECK_EQUAL(parse(" [foo]"), make_log("key: foo", "{", "}"));
CAF_CHECK_EQUAL(parse(" [ foo] "), make_log("key: foo", "{", "}"));
CAF_CHECK_EQUAL(parse(" [ foo ] "), make_log("key: foo", "{", "}"));
CAF_CHECK_EQUAL(parse("\n[a-b];foo\n;bar"), make_log("key: a-b", "{", "}"));
CAF_CHECK_EQUAL(parse(ini0), ini0_log);
CAF_CHECK_EQUAL(parse(ini1), ini1_log);
}
CAF_TEST(invalid inis) {
CAF_CHECK_EQUAL(parse(ini2), ini2_log);
CAF_CHECK_EQUAL(parse(ini3), ini3_log);
}
CAF_TEST(integer keys are legal in INI syntax) {
static constexpr string_view ini = R"__(
[foo.bar]
1 = 10
2 = 20
)__";
// clang-format off
auto log = make_log(
"key: foo",
"{",
"key: bar",
"{",
"key: 1",
"value (integer): 10",
"key: 2",
"value (integer): 20",
"}",
"}"
);
// clang-format on
CAF_CHECK_EQUAL(parse(ini), log);
}
CAF_TEST(integer keys are legal in config syntax) {
static constexpr string_view ini = R"__(
foo {
bar {
1 = 10
2 = 20
}
}
)__";
// clang-format off
auto log = make_log(
"key: global",
"{",
"key: foo",
"{",
"key: bar",
"{",
"key: 1",
"value (integer): 10",
"key: 2",
"value (integer): 20",
"}",
"}",
"}"
);
// clang-format on
CAF_CHECK_EQUAL(parse(ini), log);
}
CAF_TEST_FIXTURE_SCOPE_END()
...@@ -61,7 +61,9 @@ namespace { ...@@ -61,7 +61,9 @@ namespace {
struct fixture { struct fixture {
fixture() { fixture() {
cfg.set("scheduler.policy", "testing"); cfg.set("caf.scheduler.policy", "testing");
cfg.set("caf.logger.file.verbosity", "debug");
cfg.set("caf.logger.file.path", "");
} }
void add(logger::field_type kind) { void add(logger::field_type kind) {
...@@ -161,10 +163,7 @@ CAF_TEST(parse_default_format_strings) { ...@@ -161,10 +163,7 @@ CAF_TEST(parse_default_format_strings) {
add(logger::message_field); add(logger::message_field);
add(logger::newline_field); add(logger::newline_field);
CAF_CHECK_EQUAL(logger::parse_format(file_format), lf); CAF_CHECK_EQUAL(logger::parse_format(file_format), lf);
#if CAF_LOG_LEVEL >= 0
// Not parsed when compiling without logging enabled.
CAF_CHECK_EQUAL(sys.logger().file_format(), lf); CAF_CHECK_EQUAL(sys.logger().file_format(), lf);
#endif
} }
CAF_TEST(rendering) { CAF_TEST(rendering) {
......
...@@ -530,7 +530,7 @@ struct fixture { ...@@ -530,7 +530,7 @@ struct fixture {
if (auto err = cfg.parse(caf::test::engine::argc(), if (auto err = cfg.parse(caf::test::engine::argc(),
caf::test::engine::argv())) caf::test::engine::argv()))
CAF_FAIL("parsing the config failed: " << to_string(err)); CAF_FAIL("parsing the config failed: " << to_string(err));
cfg.set("scheduler.policy", "testing"); cfg.set("caf.scheduler.policy", "testing");
return cfg; return cfg;
} }
......
...@@ -116,7 +116,7 @@ CAF_TEST_FIXTURE_SCOPE(counting_hook, fixture<counting_thread_hook>) ...@@ -116,7 +116,7 @@ CAF_TEST_FIXTURE_SCOPE(counting_hook, fixture<counting_thread_hook>)
CAF_TEST(counting_system_without_actor) { CAF_TEST(counting_system_without_actor) {
assumed_init_calls = 1; assumed_init_calls = 1;
auto fallback = scheduler::abstract_coordinator::default_thread_count(); auto fallback = scheduler::abstract_coordinator::default_thread_count();
assumed_thread_count = get_or(cfg, "scheduler.max-threads", fallback) assumed_thread_count = get_or(cfg, "caf.scheduler.max-threads", fallback)
+ 1; // caf.clock + 1; // caf.clock
auto& sched = sys.scheduler(); auto& sched = sys.scheduler();
if (sched.detaches_utility_actors()) if (sched.detaches_utility_actors())
...@@ -126,7 +126,7 @@ CAF_TEST(counting_system_without_actor) { ...@@ -126,7 +126,7 @@ CAF_TEST(counting_system_without_actor) {
CAF_TEST(counting_system_with_actor) { CAF_TEST(counting_system_with_actor) {
assumed_init_calls = 1; assumed_init_calls = 1;
auto fallback = scheduler::abstract_coordinator::default_thread_count(); auto fallback = scheduler::abstract_coordinator::default_thread_count();
assumed_thread_count = get_or(cfg, "scheduler.max-threads", fallback) assumed_thread_count = get_or(cfg, "caf.scheduler.max-threads", fallback)
+ 2; // caf.clock and detached actor + 2; // caf.clock and detached actor
auto& sched = sys.scheduler(); auto& sched = sys.scheduler();
if (sched.detaches_utility_actors()) if (sched.detaches_utility_actors())
......
...@@ -44,7 +44,7 @@ instance::instance(abstract_broker* parent, callee& lstnr) ...@@ -44,7 +44,7 @@ instance::instance(abstract_broker* parent, callee& lstnr)
: tbl_(parent), this_node_(parent->system().node()), callee_(lstnr) { : tbl_(parent), this_node_(parent->system().node()), callee_(lstnr) {
CAF_ASSERT(this_node_ != none); CAF_ASSERT(this_node_ != none);
size_t workers; size_t workers;
if (auto workers_cfg = get_if<size_t>(&config(), "middleman.workers")) if (auto workers_cfg = get_if<size_t>(&config(), "caf.middleman.workers"))
workers = *workers_cfg; workers = *workers_cfg;
else else
workers = std::min(3u, std::thread::hardware_concurrency() / 4u) + 1; workers = std::min(3u, std::thread::hardware_concurrency() / 4u) + 1;
...@@ -231,7 +231,8 @@ void instance::write_server_handshake(execution_unit* ctx, byte_buffer& out_buf, ...@@ -231,7 +231,8 @@ void instance::write_server_handshake(execution_unit* ctx, byte_buffer& out_buf,
auto writer = make_callback([&](binary_serializer& sink) { auto writer = make_callback([&](binary_serializer& sink) {
using string_list = std::vector<std::string>; using string_list = std::vector<std::string>;
string_list app_ids; string_list app_ids;
if (auto ids = get_if<string_list>(&config(), "middleman.app-identifiers")) if (auto ids = get_if<string_list>(&config(),
"caf.middleman.app-identifiers"))
app_ids = std::move(*ids); app_ids = std::move(*ids);
else else
app_ids.emplace_back(to_string(defaults::middleman::app_identifier)); app_ids.emplace_back(to_string(defaults::middleman::app_identifier));
...@@ -323,7 +324,8 @@ connection_state instance::handle(execution_unit* ctx, connection_handle hdl, ...@@ -323,7 +324,8 @@ connection_state instance::handle(execution_unit* ctx, connection_handle hdl,
} }
// Check the application ID. // Check the application ID.
string_list whitelist; string_list whitelist;
if (auto ls = get_if<string_list>(&config(), "middleman.app-identifiers")) if (auto ls = get_if<string_list>(&config(),
"caf.middleman.app-identifiers"))
whitelist = std::move(*ls); whitelist = std::move(*ls);
else else
whitelist.emplace_back(to_string(defaults::middleman::app_identifier)); whitelist.emplace_back(to_string(defaults::middleman::app_identifier));
......
...@@ -105,7 +105,7 @@ behavior basp_broker::make_behavior() { ...@@ -105,7 +105,7 @@ behavior basp_broker::make_behavior() {
set_down_handler([](local_actor* ptr, down_msg& x) { set_down_handler([](local_actor* ptr, down_msg& x) {
static_cast<basp_broker*>(ptr)->handle_down_msg(x); static_cast<basp_broker*>(ptr)->handle_down_msg(x);
}); });
if (get_or(config(), "middleman.enable-automatic-connections", false)) { if (get_or(config(), "caf.middleman.enable-automatic-connections", false)) {
CAF_LOG_DEBUG("enable automatic connections"); CAF_LOG_DEBUG("enable automatic connections");
// open a random port and store a record for our peers how to // open a random port and store a record for our peers how to
// connect to this broker directly in the configuration server // connect to this broker directly in the configuration server
...@@ -120,7 +120,7 @@ behavior basp_broker::make_behavior() { ...@@ -120,7 +120,7 @@ behavior basp_broker::make_behavior() {
} }
automatic_connections = true; automatic_connections = true;
} }
auto heartbeat_interval = get_or(config(), "middleman.heartbeat-interval", auto heartbeat_interval = get_or(config(), "caf.middleman.heartbeat-interval",
defaults::middleman::heartbeat_interval); defaults::middleman::heartbeat_interval);
if (heartbeat_interval > 0) { if (heartbeat_interval > 0) {
CAF_LOG_DEBUG("enable heartbeat" << CAF_ARG(heartbeat_interval)); CAF_LOG_DEBUG("enable heartbeat" << CAF_ARG(heartbeat_interval));
...@@ -585,7 +585,7 @@ void basp_broker::learned_new_node_indirectly(const node_id& nid) { ...@@ -585,7 +585,7 @@ void basp_broker::learned_new_node_indirectly(const node_id& nid) {
// connection to the routing table; hence, spawning our helper here exactly // connection to the routing table; hence, spawning our helper here exactly
// once and there is no need to track in-flight connection requests. // once and there is no need to track in-flight connection requests.
using namespace detail; using namespace detail;
auto tmp = get_or(config(), "middleman.attach-utility-actors", false) auto tmp = get_or(config(), "caf.middleman.attach-utility-actors", false)
? system().spawn<hidden>(connection_helper, this) ? system().spawn<hidden>(connection_helper, this)
: system().spawn<detached + hidden>(connection_helper, this); : system().spawn<detached + hidden>(connection_helper, this);
auto sender = actor_cast<strong_actor_ptr>(tmp); auto sender = actor_cast<strong_actor_ptr>(tmp);
......
...@@ -87,7 +87,7 @@ void middleman::init_global_meta_objects() { ...@@ -87,7 +87,7 @@ void middleman::init_global_meta_objects() {
} }
actor_system::module* middleman::make(actor_system& sys, detail::type_list<>) { actor_system::module* middleman::make(actor_system& sys, detail::type_list<>) {
auto impl = get_or(sys.config(), "middleman.network-backend", auto impl = get_or(sys.config(), "caf.middleman.network-backend",
defaults::middleman::network_backend); defaults::middleman::network_backend);
if (impl == "testing") if (impl == "testing")
return new mm_impl<network::test_multiplexer>(sys); return new mm_impl<network::test_multiplexer>(sys);
...@@ -272,7 +272,7 @@ strong_actor_ptr middleman::remote_lookup(std::string name, ...@@ -272,7 +272,7 @@ strong_actor_ptr middleman::remote_lookup(std::string name,
void middleman::start() { void middleman::start() {
CAF_LOG_TRACE(""); CAF_LOG_TRACE("");
// Launch backend. // Launch backend.
if (!get_or(config(), "middleman.manual-multiplexing", false)) if (!get_or(config(), "caf.middleman.manual-multiplexing", false))
backend_supervisor_ = backend().make_supervisor(); backend_supervisor_ = backend().make_supervisor();
// The only backend that returns a `nullptr` by default is the // The only backend that returns a `nullptr` by default is the
// `test_multiplexer` which does not have its own thread but uses the main // `test_multiplexer` which does not have its own thread but uses the main
...@@ -332,7 +332,7 @@ void middleman::stop() { ...@@ -332,7 +332,7 @@ void middleman::stop() {
} }
} }
}); });
if (!get_or(config(), "middleman.manual-multiplexing", false)) { if (!get_or(config(), "caf.middleman.manual-multiplexing", false)) {
backend_supervisor_.reset(); backend_supervisor_.reset();
if (thread_.joinable()) if (thread_.joinable())
thread_.join(); thread_.join();
...@@ -343,7 +343,7 @@ void middleman::stop() { ...@@ -343,7 +343,7 @@ void middleman::stop() {
named_brokers_.clear(); named_brokers_.clear();
scoped_actor self{system(), true}; scoped_actor self{system(), true};
self->send_exit(manager_, exit_reason::kill); self->send_exit(manager_, exit_reason::kill);
if (!get_or(config(), "middleman.attach-utility-actors", false)) if (!get_or(config(), "caf.middleman.attach-utility-actors", false))
self->wait_for(manager_); self->wait_for(manager_);
destroy(manager_); destroy(manager_);
} }
...@@ -351,11 +351,11 @@ void middleman::stop() { ...@@ -351,11 +351,11 @@ void middleman::stop() {
void middleman::init(actor_system_config& cfg) { void middleman::init(actor_system_config& cfg) {
// Note: logging is not available at this stage. // Note: logging is not available at this stage.
// Never detach actors when using the testing multiplexer. // Never detach actors when using the testing multiplexer.
auto network_backend = get_or(cfg, "middleman.network-backend", auto network_backend = get_or(cfg, "caf.middleman.network-backend",
defaults::middleman::network_backend); defaults::middleman::network_backend);
if (network_backend == "testing") { if (network_backend == "testing") {
cfg.set("middleman.attach-utility-actors", true) cfg.set("caf.middleman.attach-utility-actors", true)
.set("middleman.manual-multiplexing", true); .set("caf.middleman.manual-multiplexing", true);
} }
// Add remote group module to config. // Add remote group module to config.
struct remote_groups : group_module { struct remote_groups : group_module {
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
namespace caf::io { namespace caf::io {
middleman_actor make_middleman_actor(actor_system& sys, actor db) { middleman_actor make_middleman_actor(actor_system& sys, actor db) {
return get_or(sys.config(), "middleman.attach-utility-actors", false) return get_or(sys.config(), "caf.middleman.attach-utility-actors", false)
? sys.spawn<middleman_actor_impl, hidden>(std::move(db)) ? sys.spawn<middleman_actor_impl, hidden>(std::move(db))
: sys.spawn<middleman_actor_impl, detached + hidden>(std::move(db)); : sys.spawn<middleman_actor_impl, detached + hidden>(std::move(db));
} }
......
...@@ -39,7 +39,7 @@ datagram_handler::datagram_handler(default_multiplexer& backend_ref, ...@@ -39,7 +39,7 @@ datagram_handler::datagram_handler(default_multiplexer& backend_ref,
native_socket sockfd) native_socket sockfd)
: event_handler(backend_ref, sockfd), : event_handler(backend_ref, sockfd),
max_consecutive_reads_(get_or(backend().system().config(), max_consecutive_reads_(get_or(backend().system().config(),
"middleman.max-consecutive-reads", "caf.middleman.max-consecutive-reads",
defaults::middleman::max_consecutive_reads)), defaults::middleman::max_consecutive_reads)),
max_datagram_size_(receive_buffer_size), max_datagram_size_(receive_buffer_size),
rd_buf_(receive_buffer_size), rd_buf_(receive_buffer_size),
......
...@@ -589,8 +589,8 @@ void default_multiplexer::init() { ...@@ -589,8 +589,8 @@ void default_multiplexer::init() {
} }
#endif #endif
namespace sr = defaults::scheduler; namespace sr = defaults::scheduler;
max_throughput_ max_throughput_ = get_or(system().config(), "caf.scheduler.max-throughput",
= get_or(system().config(), "scheduler.max-throughput", sr::max_throughput); sr::max_throughput);
} }
bool default_multiplexer::poll_once(bool block) { bool default_multiplexer::poll_once(bool block) {
......
...@@ -31,7 +31,7 @@ namespace caf::io::network { ...@@ -31,7 +31,7 @@ namespace caf::io::network {
stream::stream(default_multiplexer& backend_ref, native_socket sockfd) stream::stream(default_multiplexer& backend_ref, native_socket sockfd)
: event_handler(backend_ref, sockfd), : event_handler(backend_ref, sockfd),
max_consecutive_reads_(get_or(backend().system().config(), max_consecutive_reads_(get_or(backend().system().config(),
"middleman.max-consecutive-reads", "caf.middleman.max-consecutive-reads",
defaults::middleman::max_consecutive_reads)), defaults::middleman::max_consecutive_reads)),
read_threshold_(1), read_threshold_(1),
collected_(0), collected_(0),
......
...@@ -105,10 +105,10 @@ class fixture { ...@@ -105,10 +105,10 @@ class fixture {
public: public:
fixture(bool autoconn = false) fixture(bool autoconn = false)
: sys(cfg.load<io::middleman, network::test_multiplexer>() : sys(cfg.load<io::middleman, network::test_multiplexer>()
.set("middleman.enable-automatic-connections", autoconn) .set("caf.middleman.enable-automatic-connections", autoconn)
.set("middleman.workers", size_t{0}) .set("caf.middleman.workers", size_t{0})
.set("scheduler.policy", autoconn ? "testing" : "stealing") .set("caf.scheduler.policy", autoconn ? "testing" : "stealing")
.set("middleman.attach-utility-actors", autoconn)) { .set("caf.middleman.attach-utility-actors", autoconn)) {
app_ids.emplace_back(to_string(defaults::middleman::app_identifier)); app_ids.emplace_back(to_string(defaults::middleman::app_identifier));
auto& mm = sys.middleman(); auto& mm = sys.middleman();
mpx_ = dynamic_cast<network::test_multiplexer*>(&mm.backend()); mpx_ = dynamic_cast<network::test_multiplexer*>(&mm.backend());
......
...@@ -104,7 +104,7 @@ void manager::stop() { ...@@ -104,7 +104,7 @@ void manager::stop() {
CAF_LOG_TRACE(""); CAF_LOG_TRACE("");
scoped_actor self{system(), true}; scoped_actor self{system(), true};
self->send_exit(manager_, exit_reason::kill); self->send_exit(manager_, exit_reason::kill);
if (!get_or(config(), "middleman.attach-utility-actors", false)) if (!get_or(config(), "caf.middleman.attach-utility-actors", false))
self->wait_for(manager_); self->wait_for(manager_);
manager_ = nullptr; manager_ = nullptr;
} }
......
...@@ -284,7 +284,7 @@ private: ...@@ -284,7 +284,7 @@ private:
} // namespace } // namespace
io::middleman_actor make_middleman_actor(actor_system& sys, actor db) { io::middleman_actor make_middleman_actor(actor_system& sys, actor db) {
return !get_or(sys.config(), "middleman.attach-utility-actors", false) return !get_or(sys.config(), "caf.middleman.attach-utility-actors", false)
? sys.spawn<middleman_actor_impl, detached + hidden>(std::move(db)) ? sys.spawn<middleman_actor_impl, detached + hidden>(std::move(db))
: sys.spawn<middleman_actor_impl, hidden>(std::move(db)); : sys.spawn<middleman_actor_impl, hidden>(std::move(db));
} }
......
...@@ -54,9 +54,9 @@ public: ...@@ -54,9 +54,9 @@ public:
config() { config() {
load<io::middleman>(); load<io::middleman>();
load<openssl::manager>(); load<openssl::manager>();
set("middleman.manual-multiplexing", true); set("caf.middleman.manual-multiplexing", true);
set("middleman.attach-utility-actors", true); set("caf.middleman.attach-utility-actors", true);
set("scheduler.policy", "testing"); set("caf.scheduler.policy", "testing");
} }
static std::string data_dir() { static std::string data_dir() {
......
...@@ -45,7 +45,7 @@ public: ...@@ -45,7 +45,7 @@ public:
// OpenSSL to buffer data internally and report "pending" data after a read // OpenSSL to buffer data internally and report "pending" data after a read
// operation. This will trigger `must_read_more` in the SSL read policy // operation. This will trigger `must_read_more` in the SSL read policy
// with high probability. // with high probability.
set("middleman.max-consecutive-reads", 1); set("caf.middleman.max-consecutive-reads", 1);
} }
}; };
......
...@@ -674,16 +674,15 @@ public: ...@@ -674,16 +674,15 @@ public:
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
static Config& init_config(Config& cfg) { static Config& init_config(Config& cfg) {
cfg.set("logger.file-verbosity", "quiet");
if (auto err = cfg.parse(caf::test::engine::argc(), if (auto err = cfg.parse(caf::test::engine::argc(),
caf::test::engine::argv())) caf::test::engine::argv()))
CAF_FAIL("failed to parse config: " << to_string(err)); CAF_FAIL("failed to parse config: " << to_string(err));
cfg.set("scheduler.policy", "testing"); cfg.set("caf.scheduler.policy", "testing");
cfg.set("logger.inline-output", true); cfg.set("caf.logger.inline-output", true);
cfg.set("middleman.network-backend", "testing"); cfg.set("caf.middleman.network-backend", "testing");
cfg.set("middleman.manual-multiplexing", true); cfg.set("caf.middleman.manual-multiplexing", true);
cfg.set("middleman.workers", size_t{0}); cfg.set("caf.middleman.workers", size_t{0});
cfg.set("stream.credit-policy", "testing"); cfg.set("caf.stream.credit-policy", "testing");
return cfg; return cfg;
} }
......
...@@ -124,8 +124,8 @@ object *before* initializing an actor system with it. ...@@ -124,8 +124,8 @@ object *before* initializing an actor system with it.
.. _system-config-options: .. _system-config-options:
Command Line Options and Configuration Files Program Options
-------------------------------------------- ---------------
CAF organizes program options in categories and parses CLI arguments as well as CAF organizes program options in categories and parses CLI arguments as well as
configuration files. CLI arguments override values in the configuration file configuration files. CLI arguments override values in the configuration file
...@@ -137,13 +137,13 @@ adds three options to the ``global`` category. ...@@ -137,13 +137,13 @@ adds three options to the ``global`` category.
:language: C++ :language: C++
:lines: 206-218 :lines: 206-218
We create a new ``global`` category in ``custom_options_``. We create a new ``global`` category in ``custom_options_``. Each following call
Each following call to ``add`` then appends individual options to the to ``add`` then appends individual options to the category. The first argument
category. The first argument to ``add`` is the associated variable. The to ``add`` is the associated variable. The second argument is the name for the
second argument is the name for the parameter, optionally suffixed with a parameter, optionally suffixed with a comma-separated single-character short
comma-separated single-character short name. The short name is only considered name. The short name is only considered for CLI parsing and allows users to
for CLI parsing and allows users to abbreviate commonly used option names. The abbreviate commonly used option names. The third and final argument to ``add``
third and final argument to ``add`` is a help text. is a help text.
The custom ``config`` class allows end users to set the port for the application The custom ``config`` class allows end users to set the port for the application
to 42 with either ``-p 42`` (short name) or ``--port=42`` (long name). The long to 42 with either ``-p 42`` (short name) or ``--port=42`` (long name). The long
...@@ -152,27 +152,28 @@ option name is prefixed by the category when using a different category than ...@@ -152,27 +152,28 @@ option name is prefixed by the category when using a different category than
end users have to type ``--foo.port=42`` when using the long name. Short names end users have to type ``--foo.port=42`` when using the long name. Short names
are unaffected by the category, but have to be unique. are unaffected by the category, but have to be unique.
Boolean options do not require arguments. The member variable Boolean options do not require arguments. The member variable ``server_mode`` is
``server_mode`` is set to ``true`` if the command line contains set to ``true`` if the command line contains either ``--server-mode`` or ``-s``.
either ``--server-mode`` or ``-s``.
The example uses member variables for capturing user-provided settings for The example uses member variables for capturing user-provided settings for
simplicity. However, this is not required. For example, simplicity. However, this is not required. For example, ``add<bool>(...)``
``add<bool>(...)`` allows omitting the first argument entirely. All allows omitting the first argument entirely. All values of the configuration are
values of the configuration are accessible with ``get_or``. Note that accessible with ``get_or``. Note that all global options can omit the
all global options can omit the ``"global."`` prefix. ``"global."`` prefix.
CAF adds the program options ``help`` (with short names ``-h`` and ``-?``) as
well as ``long-help`` to the ``global`` category.
CAF adds the program options ``help`` (with short names ``-h`` Configuration Files
and ``-?``) as well as ``long-help`` to the ``global`` -------------------
category.
The default name for the configuration file is ``caf-application.conf``. Users The default name for the configuration file is ``caf-application.conf``. Users
can change the file name and path by passing ``--config-file=<path>`` on the can change the file path by passing ``--config-file=<path>`` on the command
command line. line.
The syntax for the configuration files provides a clean JSON-like grammar that The syntax for the configuration files provides a clean JSON-like grammar that
is similar to commonly used configuration formats such as the file format of is similar to other commonly used configuration formats. In a nutshell, instead
``lighttpd``. In a nutshell, instead of writing: of writing:
.. code-block:: JSON .. code-block:: JSON
...@@ -341,31 +342,33 @@ system-config-options_ are silently ignored if logging is disabled. ...@@ -341,31 +342,33 @@ system-config-options_ are silently ignored if logging is disabled.
.. _log-output-file-name: .. _log-output-file-name:
File Name File
~~~~~~~~~ ~~~~
File output is disabled per default. Setting ``caf.logger.file.verbosity`` to a
valid severity level causes CAF to print log events to the file specified in
``caf.logger.file.path``.
The output file is generated from the template configured by The ``caf.logger.file.path`` may contain one or more of the following
``logger-file-name``. This template supports the following variables. placeholders:
+----------------+--------------------------------+ +-----------------+--------------------------------+
| **Variable** | **Output** | | **Variable** | **Output** |
+----------------+--------------------------------+ +-----------------+--------------------------------+
| ``[PID]`` | The OS-specific process ID. | | ``[PID]`` | The OS-specific process ID. |
+----------------+--------------------------------+ +-----------------+--------------------------------+
| ``[TIMESTAMP]``| The UNIX timestamp on startup. | | ``[TIMESTAMP]`` | The UNIX timestamp on startup. |
+----------------+--------------------------------+ +-----------------+--------------------------------+
| ``[NODE]`` | The node ID of the CAF system. | | ``[NODE]`` | The node ID of the CAF system. |
+----------------+--------------------------------+ +-----------------+--------------------------------+
.. _log-output-console: .. _log-output-console:
Console Console
~~~~~~~ ~~~~~~~
Console output is disabled per default. Setting ``logger-console`` to Console output is disabled per default. Setting ``caf.logger.console.verbosity``
either ``"uncolored"`` or ``"colored"`` prints log events to to a valid severity level causes CAF to print log events to ``std::clog``.
``std::clog``. Using the ``"colored"`` option will print the
log events in different colors depending on the severity level.
.. _log-output-format-strings: .. _log-output-format-strings:
...@@ -373,47 +376,46 @@ Format Strings ...@@ -373,47 +376,46 @@ Format Strings
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
CAF uses log4j-like format strings for configuring printing of individual CAF uses log4j-like format strings for configuring printing of individual
events via ``logger-file-format`` and events via ``caf.logger.file.format`` and
``logger-console-format``. Note that format modifiers are not supported ``caf.logger.console.format``. Note that format modifiers are not supported
at the moment. The recognized field identifiers are: at the moment. The recognized field identifiers are:
+--------------+-----------------------------------------------------------------------------------------------------------------------------+ +---------------+-----------------------------------------------------------------------------------------------------------------------------+
| **Character**| **Output** | | **Character** | **Output** |
+--------------+-----------------------------------------------------------------------------------------------------------------------------+ +---------------+-----------------------------------------------------------------------------------------------------------------------------+
| ``c`` | The category/component. | | ``c`` | The category/component. |
+--------------+-----------------------------------------------------------------------------------------------------------------------------+ +---------------+-----------------------------------------------------------------------------------------------------------------------------+
| ``C`` | The full qualifier of the current function. For example, the qualifier of ``void ns::foo::bar()`` is printed as ``ns.foo``. | | ``C`` | The full qualifier of the current function. For example, the qualifier of ``void ns::foo::bar()`` is printed as ``ns.foo``. |
+--------------+-----------------------------------------------------------------------------------------------------------------------------+ +---------------+-----------------------------------------------------------------------------------------------------------------------------+
| ``d`` | The date in ISO 8601 format, i.e., ``"YYYY-MM-DDThh:mm:ss"``. | | ``d`` | The date in ISO 8601 format, i.e., ``"YYYY-MM-DDThh:mm:ss"``. |
+--------------+-----------------------------------------------------------------------------------------------------------------------------+ +---------------+-----------------------------------------------------------------------------------------------------------------------------+
| ``F`` | The file name. | | ``F`` | The file name. |
+--------------+-----------------------------------------------------------------------------------------------------------------------------+ +---------------+-----------------------------------------------------------------------------------------------------------------------------+
| ``L`` | The line number. | | ``L`` | The line number. |
+--------------+-----------------------------------------------------------------------------------------------------------------------------+ +---------------+-----------------------------------------------------------------------------------------------------------------------------+
| ``m`` | The user-defined log message. | | ``m`` | The user-defined log message. |
+--------------+-----------------------------------------------------------------------------------------------------------------------------+ +---------------+-----------------------------------------------------------------------------------------------------------------------------+
| ``M`` | The name of the current function. For example, the name of ``void ns::foo::bar()`` is printed as ``bar``. | | ``M`` | The name of the current function. For example, the name of ``void ns::foo::bar()`` is printed as ``bar``. |
+--------------+-----------------------------------------------------------------------------------------------------------------------------+ +---------------+-----------------------------------------------------------------------------------------------------------------------------+
| ``n`` | A newline. | | ``n`` | A newline. |
+--------------+-----------------------------------------------------------------------------------------------------------------------------+ +---------------+-----------------------------------------------------------------------------------------------------------------------------+
| ``p`` | The priority (severity level). | | ``p`` | The priority (severity level). |
+--------------+-----------------------------------------------------------------------------------------------------------------------------+ +---------------+-----------------------------------------------------------------------------------------------------------------------------+
| ``r`` | Elapsed time since starting the application in milliseconds. | | ``r`` | Elapsed time since starting the application in milliseconds. |
+--------------+-----------------------------------------------------------------------------------------------------------------------------+ +---------------+-----------------------------------------------------------------------------------------------------------------------------+
| ``t`` | ID of the current thread. | | ``t`` | ID of the current thread. |
+--------------+-----------------------------------------------------------------------------------------------------------------------------+ +---------------+-----------------------------------------------------------------------------------------------------------------------------+
| ``a`` | ID of the current actor (or ``actor0`` when not logging inside an actor). | | ``a`` | ID of the current actor (or ``actor0`` when not logging inside an actor). |
+--------------+-----------------------------------------------------------------------------------------------------------------------------+ +---------------+-----------------------------------------------------------------------------------------------------------------------------+
| ``%`` | A single percent sign. | | ``%`` | A single percent sign. |
+--------------+-----------------------------------------------------------------------------------------------------------------------------+ +---------------+-----------------------------------------------------------------------------------------------------------------------------+
.. _log-output-filtering: .. _log-output-filtering:
Filtering Filtering
~~~~~~~~~ ~~~~~~~~~
The two configuration options ``logger.component-blacklist`` and The two configuration options ``caf.logger.file.excluded-components`` and
``logger.(file|console)-verbosity`` reduce the amount of generated log events. ``caf.logger.console.excluded-components`` reduce the amount of generated log
The former is a list of excluded component names and the latter can increase the events in addition to the minimum severity level. These parameters are lists of
reported severity level (but not decrease it beyond the level defined at compile component names that shall be excluded from any output.
time).
...@@ -176,10 +176,10 @@ void bootstrap(actor_system& system, const string& wdir, ...@@ -176,10 +176,10 @@ void bootstrap(actor_system& system, const string& wdir,
std::ostringstream oss; std::ostringstream oss;
oss << cmd; oss << cmd;
if (slave.cpu_slots > 0) if (slave.cpu_slots > 0)
oss << " --caf#scheduler.max-threads=" << slave.cpu_slots; oss << " --caf.scheduler.max-threads=" << slave.cpu_slots;
oss << " --caf#slave-mode" oss << " --caf.slave-mode"
<< " --caf#slave-name=" << slave.host << " --caf.slave-name=" << slave.host
<< " --caf#bootstrap-node="; << " --caf.bootstrap-node=";
bool is_first = true; bool is_first = true;
interfaces::traverse({protocol::ipv4, protocol::ipv6}, interfaces::traverse({protocol::ipv4, protocol::ipv6},
[&](const char*, protocol::network, [&](const char*, protocol::network,
...@@ -216,7 +216,7 @@ void bootstrap(actor_system& system, const string& wdir, ...@@ -216,7 +216,7 @@ void bootstrap(actor_system& system, const string& wdir,
} }
// run (and wait for) master // run (and wait for) master
std::ostringstream oss; std::ostringstream oss;
oss << cmd << " --caf#slave-nodes=" << slaveslist << " " << join(args, " "); oss << cmd << " --caf.slave-nodes=" << slaveslist << " " << join(args, " ");
run_ssh(system, wdir, oss.str(), master.host); run_ssh(system, wdir, oss.str(), master.host);
} }
......
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