Files
spark/src/lib/logging/logging.cpp
T
2020-07-11 12:30:06 -04:00

232 lines
7.2 KiB
C++

#include "logging.h"
#include "LoggerHub.h"
#include "lib/config/config.h"
#include "lib/os/os.h"
#include "lib/utils/bts_assert.h"
#include "lib/utils/bts_chrono.h"
#include "lib/config/protos/logging.pb.h"
#include "lib/utils/file_utils.h"
#include "lib/utils/Dispatcher.h"
#include "lib/config/protos/system.pb.h"
#include "lib/utils/thread_manager.h"
#include <google/protobuf/text_format.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/gzip_stream.h>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/container/flat_set.hpp>
#include <fstream>
#include <mutex>
namespace bts {
namespace log {
static LoggerHub _default_logger_hub("logger");
thread_local LoggerHandle _thread_logger(_default_logger_hub.make_logger());
template <class M>
typename M::const_iterator find_key(M const&m, typename M::mapped_type const &v)
{
for (auto it = m.begin(); it != m.end();it++)
if (it->second == v)
return it;
return m.end();
}
boost::filesystem::path log_path ()
{
auto store_root = os::bts_data_path();
std::string base_path = store_root;
boost::filesystem::path result = utils::normalize_data_path (base_path);
result /= "logging";
return result;
}
void start_default_logging_thread()
{
_default_logger_hub.start();
}
Filter get_filter (LoggingConfig &cfg,
config::Logging::SinkConfig const&scfg)
{
Filter result;
for (auto &l : result)
l = Info;
auto it = find_key(cfg.level_names,scfg.default_level());
if (it == cfg.level_names.end())
return result;
auto default_level = it->first;
for (auto &l : result)
l = default_level;
for (auto const &sub_system : scfg.subsystem()) {
auto ss_it = find_key(cfg.subsystem_names,sub_system.name());
if (ss_it == cfg.subsystem_names.end())
continue;
auto ss = ss_it->first;
auto level_it = find_key(cfg.level_names,sub_system.level());
if (level_it == cfg.level_names.end())
continue;
auto level = level_it->first;
result[ss.ordinal] = level;
}
return result;
}
void configure_logging(LoggingConfig const&cfg) {_default_logger_hub.config(cfg);}
void configure_logging(bts::config::Logging const&cfg) {configure_logging(cfg,bts::config::ThreadGroupCfg ());}
void configure_logging(bts::config::Logging const&cfg, bts::config::ThreadGroupCfg const&thread_cfg)
{
LoggingConfig real_cfg;
real_cfg.deployment_type = config::get<config::DeploymentType>().type();
real_cfg.logger_initial_queue_size = cfg.initial_queue_size();
real_cfg.logger_max_queue_growth = cfg.max_queue_growth();
real_cfg.level_names = { {NoLog,"NoLog"},{Diag,"Diag"},{Info,"Info"},
{Warn,"Warn"},{Error,"Error"},
{Fatal,"Fatal"},{Sys,"Sys"} };
real_cfg.subsystem_names = { {log::Gen,"Gen"},
{log::Cfg,"Cfg"},
{log::QBus,"QBus"},
{log::Log,"Log"},
{log::Jetfix,"Jetfix"},
{log::md,"md"},
{log::Api,"Api"},
{log::persist,"persist"},
{log::User,"User"},
{log::OrderMan,"OrderMan"},
{log::Assert,"Assert"},
{log::Engine,"Engine"},
{log::Ui,"UI"},
{log::ExSim,"ExSim"},
{log::Mercury,"Mercury"},
{log::Testing,"Testing"},
{log::Latency,"Latency"},
{log::DataFlow,"DataFlow"},
{log::Plugin,"Plugin"},
{log::Sdk,"Sdk"},
{log::Http,"Http"},
{log::Spartan,"Spartan"},
{log::iLink3,"ilink3"},
};
real_cfg.sinks["console"] =
std::make_pair (console_sink(real_cfg),get_filter(real_cfg,cfg.console()));
real_cfg.sinks["syslog"] =
std::make_pair (syslog_sink(real_cfg),get_filter(real_cfg,cfg.syslog()));
real_cfg.sinks["file"] =
std::make_pair (file_sink(real_cfg),get_filter(real_cfg,cfg.file()));
real_cfg.thread_cfg = thread_cfg;
configure_logging(real_cfg);
}
boost::filesystem::path log_cache_file_path ()
{
auto store_root = os::bts_data_path();
boost::filesystem::path result = utils::normalize_data_path (store_root);
result /= "logging";
result /= "log_control";
return result;
}
LoggingConfigPoller::LoggingConfigPoller (bts::config::Logging const&cfg, bts::config::ThreadGroupCfg const&thread_cfg)
: _poller(utils::Dispatcher::background(), 1000, [=]() { poll_once(); }),
_last_ts(std::time(nullptr)),
_log_cache_file(log_cache_file_path()),
_done(false)
{
init(cfg,thread_cfg);
}
LoggingConfigPoller::LoggingConfigPoller () : LoggingConfigPoller(config::get<config::Logging>(),
threading::get_thread_cfg("logger"))
{ }
void LoggingConfigPoller::init (bts::config::Logging const&cfg,bts::config::ThreadGroupCfg const&thread_cfg)
{
auto parent = _log_cache_file.parent_path();
if (!boost::filesystem::is_directory(parent))
bts_assert(boost::filesystem::create_directories(parent));
std::ofstream fs (_log_cache_file.string());
google::protobuf::io::OstreamOutputStream gs (&fs);
google::protobuf::TextFormat::Print (cfg,&gs);
// initialize logging
configure_logging(cfg,thread_cfg);
_poller.start();
}
void LoggingConfigPoller::poll_once() {
if (_done) return;
auto current_ts =
boost::filesystem::last_write_time(_log_cache_file) ;
if (current_ts != _last_ts) {
_last_ts = current_ts;
bts::config::Logging cfg;
std::ifstream fs (_log_cache_file.string());
google::protobuf::io::IstreamInputStream gs (&fs);
if (google::protobuf::TextFormat::Parse (&gs,&cfg)) {
LOG(Log,Info,"Detected logging configuration change. Reconfiguring logging.");
configure_logging(cfg);
}
else
LOG(Log,Error,"Detected invalid logging configuration. Ignoring.");
}
}
LoggingConfigPoller::~LoggingConfigPoller ()
{
_done = true;
_poller.stop();
}
namespace interop {
const char* intern(const char* str) {
static std::mutex mutex;
static boost::container::flat_set<const char*> set;
std::lock_guard<std::mutex> lock(mutex);
const auto iter = set.find(str);
if (iter != set.end()) {
return *iter;
}
else {
#ifdef _WIN32
const char* v = _strdup(str);
#else
const char* v = strdup(str);
#endif
set.insert(v);
return v;
}
}
extern "C" BTS_EXPORT void Logger_log (int level, int subsystem, const char *message, const char *file, int line)
{
if (bts::log::_thread_logger.logger != nullptr) {
bts::log::_thread_logger.logger->enqueue(log::log_ts(), log::Subsystem{ (uint8_t)subsystem }, log::Level{ (uint8_t)level }, intern(file), line, "{}", std::string(message));
}
}
}
}}