Skip to content

Commit

Permalink
Rust: init logging only once (#207)
Browse files Browse the repository at this point in the history
* Everestrs: Change logging

Signed-off-by: Dima Dorezyuk <ddo@qwello.eu>

* Don't call again config

Signed-off-by: Dima Dorezyuk <ddo@qwello.eu>

---------

Signed-off-by: Dima Dorezyuk <ddo@qwello.eu>
Co-authored-by: Dima Dorezyuk <ddo@qwello.eu>
  • Loading branch information
dorezyuk and Dima Dorezyuk authored Oct 14, 2024
1 parent 313709f commit f7570f8
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 61 deletions.
2 changes: 1 addition & 1 deletion everestrs/everestrs-build/jinja/module.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ impl Module {
{% endfor %}
) -> ::std::sync::Arc<Self> {
let runtime = ::everestrs::Runtime::new();
let connections = ::everestrs::get_module_connections();
let connections = runtime.get_module_connections();
let this = ::std::sync::Arc::new(Self {
on_ready,
{% for provide in provides %}
Expand Down
34 changes: 16 additions & 18 deletions everestrs/everestrs/src/everestrs_sys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,6 @@ std::unique_ptr<Everest::Everest> create_everest_instance(const std::string& mod
rs->mqtt_external_prefix, rs->telemetry_prefix, rs->telemetry_enabled);
}

std::unique_ptr<Everest::Config> create_config_instance(std::shared_ptr<Everest::RuntimeSettings> rs) {
// FIXME (aw): where to initialize the logger?
Everest::Logging::init(rs->logging_config_file);
return std::make_unique<Everest::Config>(rs);
}

JsonBlob json2blob(const json& j) {
// I did not find a way to not copy the data at least once here.
const std::string dumped = j.dump();
Expand Down Expand Up @@ -83,7 +77,7 @@ inline ConfigField get_config_field(const std::string& _name, int _value) {
Module::Module(const std::string& module_id, const std::string& prefix, const std::string& config_file) :
module_id_(module_id),
rs_(std::make_shared<Everest::RuntimeSettings>(prefix, config_file)),
config_(create_config_instance(rs_)),
config_(std::make_unique<Everest::Config>(rs_)),
handle_(create_everest_instance(module_id, rs_, *config_)) {
}

Expand Down Expand Up @@ -161,11 +155,8 @@ rust::Vec<RsModuleConfig> get_module_configs(rust::Str module_id, rust::Str pref
return out;
}

rust::Vec<RsModuleConnections> get_module_connections(rust::Str module_id, rust::Str prefix, rust::Str config_file) {
const auto rs = std::make_shared<Everest::RuntimeSettings>(std::string(prefix), std::string(config_file));
Everest::Config config{rs};

const auto connections = config.get_main_config().at(std::string(module_id))["connections"];
rust::Vec<RsModuleConnections> Module::get_module_connections() const {
const auto connections = config_->get_main_config().at(std::string(module_id_))["connections"];

// Iterate over the connections block.
rust::Vec<RsModuleConnections> out;
Expand All @@ -176,18 +167,25 @@ rust::Vec<RsModuleConnections> get_module_connections(rust::Str module_id, rust:
return out;
}

int Module::get_log_level() const {
int init_logging(rust::Str module_id, rust::Str prefix, rust::Str config_file) {
using namespace boost::log;
using namespace Everest::Logging;

const std::string module_id_cpp{module_id};
const std::string prefix_cpp{prefix};
const std::string config_file_cpp{config_file};

// Init the CPP logger.
Everest::RuntimeSettings rs{prefix_cpp, config_file_cpp};
init(rs.logging_config_file, module_id_cpp);

// Below is something really ugly. Boost's log filter rules may actually be
// quite "complex" but the library does not expose any way to check the
// already installed filters. We therefore reopen the config and construct
// or own filter - and feed it with dummy values to determine its filtering
// behaviour (the lowest severity which is accepted by the filter)
std::filesystem::path logging_path{rs_->logging_config_file};
std::filesystem::path logging_path{rs.logging_config_file};
std::ifstream logging_config(logging_path.c_str());

using namespace boost::log;
using namespace Everest::Logging;

if (!logging_config.is_open()) {
return info;
}
Expand Down
5 changes: 3 additions & 2 deletions everestrs/everestrs/src/everestrs_sys.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class Module {
JsonBlob call_command(rust::Str implementation_id, size_t index, rust::Str name, JsonBlob args) const;
void subscribe_variable(const Runtime& rt, rust::String implementation_id, size_t index, rust::String name) const;
void publish_variable(rust::Str implementation_id, rust::Str name, JsonBlob blob) const;
int get_log_level() const;
rust::Vec<RsModuleConnections> get_module_connections() const;

private:
const std::string module_id_;
Expand All @@ -39,5 +39,6 @@ class Module {
std::unique_ptr<Module> create_module(rust::Str module_name, rust::Str prefix, rust::Str conf);

rust::Vec<RsModuleConfig> get_module_configs(rust::Str module_name, rust::Str prefix, rust::Str conf);
rust::Vec<RsModuleConnections> get_module_connections(rust::Str module_name, rust::Str prefix, rust::Str conf);

int init_logging(rust::Str module_name, rust::Str prefix, rust::Str conf);
void log2cxx(int level, int line, rust::Str file, rust::Str message);
89 changes: 49 additions & 40 deletions everestrs/everestrs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ use std::convert::TryFrom;
use std::path::PathBuf;
use std::pin::Pin;
use std::sync::Arc;
use std::sync::Once;
use std::sync::RwLock;
use std::sync::Weak;
use thiserror::Error;

/// Prevent calling the init of loggers more than once.
static INIT_LOGGER_ONCE: Once = Once::new();

// Reexport everything so the clients can use it.
pub use serde;
pub use serde_json;
Expand Down Expand Up @@ -155,22 +159,18 @@ mod ffi {
name: String,
);

/// Returns the `connections` block defined in the `config.yaml` for
/// the current module.
fn get_module_connections(self: &Module) -> Vec<RsModuleConnections>;

/// Publishes the given `blob` under the `implementation_id` and `name`.
fn publish_variable(self: &Module, implementation_id: &str, name: &str, blob: JsonBlob);

/// Returns the severity for the cxx logger.
fn get_log_level(self: &Module) -> i32;

/// Returns the module config from cpp.
fn get_module_configs(module_id: &str, prefix: &str, conf: &str) -> Vec<RsModuleConfig>;

/// Returns the `connections` block defined in the `config.yaml` for
/// the current module.
fn get_module_connections(
module_id: &str,
prefix: &str,
conf: &str,
) -> Vec<RsModuleConnections>;
/// Call this once.
fn init_logging(module_id: &str, prefix: &str, conf: &str) -> i32;

/// Logging sink for the EVerest module.
fn log2cxx(level: i32, line: i32, file: &str, message: &str);
Expand All @@ -195,6 +195,7 @@ impl ffi::JsonBlob {
/// Very simple logger to use by the Rust modules.
mod logger {
use super::ffi;
use crate::INIT_LOGGER_ONCE;

pub(crate) struct Logger {
level: log::Level,
Expand Down Expand Up @@ -237,19 +238,21 @@ mod logger {
/// Init the logger for everest.
///
/// Don't do this on your own as we must also control some cxx code.
pub(crate) fn init_logger(module: &ffi::Module) {
let level = match module.get_log_level() {
0 => log::Level::Trace,
1 => log::Level::Debug,
2 => log::Level::Info,
3 => log::Level::Warn,
4 => log::Level::Error,
_ => log::Level::Info,
};
pub(crate) fn init_logger(module_name: &str, prefix: &str, conf: &str) {
INIT_LOGGER_ONCE.call_once(|| {
let level = match ffi::init_logging(module_name, prefix, conf) {
0 => log::Level::Trace,
1 => log::Level::Debug,
2 => log::Level::Info,
3 => log::Level::Warn,
4 => log::Level::Error,
_ => log::Level::Info,
};

let logger = Self { level };
log::set_boxed_logger(Box::new(logger)).unwrap();
log::set_max_level(level.to_level_filter());
let logger = Self { level };
log::set_boxed_logger(Box::new(logger)).unwrap();
log::set_max_level(level.to_level_filter());
});
}
}
}
Expand Down Expand Up @@ -395,13 +398,17 @@ impl Runtime {
// TODO(hrapp): This function could use some error handling.
pub fn new() -> Pin<Arc<Self>> {
let args: Args = argh::from_env();
let cpp_module = ffi::create_module(
logger::Logger::init_logger(
&args.module,
&args.prefix.to_string_lossy(),
&args.conf.to_string_lossy(),
);

logger::Logger::init_logger(&cpp_module);
let cpp_module = ffi::create_module(
&args.module,
&args.prefix.to_string_lossy(),
&args.conf.to_string_lossy(),
);

Arc::pin(Self {
cpp_module,
Expand All @@ -428,7 +435,7 @@ impl Runtime {
}
}

let connections = get_module_connections();
let connections = self.get_module_connections();

// Subscribe to all variables that might be of interest.
for (implementation_id, requires) in manifest.requires {
Expand All @@ -452,6 +459,15 @@ impl Runtime {
// again.
(self.cpp_module).as_ref().unwrap().signal_ready(self);
}

/// The interface for fetching the module connections though the C++ runtime.
pub fn get_module_connections(&self) -> HashMap<String, usize> {
let raw_connections = self.cpp_module.as_ref().unwrap().get_module_connections();
raw_connections
.into_iter()
.map(|connection| (connection.implementation_id, connection.slots))
.collect()
}
}

/// A store for our config values. The type is closely related to
Expand Down Expand Up @@ -505,8 +521,16 @@ impl TryFrom<&Config> for i64 {
}

/// Interface for fetching the configurations through the C++ runtime.
///
/// This is separetated from the module since the user might need the config
/// to create the [Runtime].
pub fn get_module_configs() -> HashMap<String, HashMap<String, Config>> {
let args: Args = argh::from_env();
logger::Logger::init_logger(
&args.module,
&args.prefix.to_string_lossy(),
&args.conf.to_string_lossy(),
);
let raw_config = ffi::get_module_configs(
&args.module,
&args.prefix.to_string_lossy(),
Expand Down Expand Up @@ -541,18 +565,3 @@ pub fn get_module_configs() -> HashMap<String, HashMap<String, Config>> {

out
}

/// The interface for fetching the module connections though the C++ runtime.
pub fn get_module_connections() -> HashMap<String, usize> {
let args: Args = argh::from_env();
let raw_connections = ffi::get_module_connections(
&args.module,
&args.prefix.to_string_lossy(),
&args.conf.to_string_lossy(),
);

raw_connections
.into_iter()
.map(|connection| (connection.implementation_id, connection.slots))
.collect()
}

0 comments on commit f7570f8

Please sign in to comment.