Skip to content

Commit

Permalink
Merge pull request #498 from mtconnect/use_boost_log_channel
Browse files Browse the repository at this point in the history
  • Loading branch information
wsobel authored Nov 20, 2024
2 parents ccb0e40 + 103949c commit 5b941a1
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 106 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
set(AGENT_VERSION_MAJOR 2)
set(AGENT_VERSION_MINOR 4)
set(AGENT_VERSION_PATCH 0)
set(AGENT_VERSION_BUILD 5)
set(AGENT_VERSION_BUILD 6)
set(AGENT_VERSION_RC "")

# This minimum version is to support Visual Studio 2019 and C++ feature checking and FetchContent
Expand Down
2 changes: 1 addition & 1 deletion conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class MTConnectAgentConan(ConanFile):
name = "mtconnect_agent"
version = "2.3"
version = "2.4"
url = "https://github.com/mtconnect/cppagent.git"
license = "Apache License 2.0"
settings = "os", "compiler", "arch", "build_type"
Expand Down
159 changes: 99 additions & 60 deletions src/mtconnect/configuration/agent_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,6 @@ BOOST_LOG_ATTRIBUTE_KEYWORD(named_scope, "Scope", logr::attributes::named_scope:
BOOST_LOG_ATTRIBUTE_KEYWORD(utc_timestamp, "Timestamp", logr::attributes::utc_clock::value_type);

namespace mtconnect::configuration {
AGENT_LIB_API
boost::log::trivial::logger_type *gAgentLogger = nullptr;

AgentConfiguration::AgentConfiguration()
: m_context {make_unique<AsyncContext>()}, m_monitorTimer(m_context->get())
Expand Down Expand Up @@ -235,8 +233,10 @@ namespace mtconnect::configuration {
#endif
m_context.reset();

if (m_sink)
m_sink.reset();
for (auto &[channelName, logChannel] : m_logChannels)
logChannel.m_logSink.reset();

m_logChannels.clear();

logr::core::get()->remove_all_sinks();
}
Expand Down Expand Up @@ -432,9 +432,8 @@ namespace mtconnect::configuration {

void AgentConfiguration::setLoggingLevel(const logr::trivial::severity_level level)
{
using namespace logr::trivial;
m_logLevel = level;
logr::core::get()->set_filter(severity >= level);
for ( auto &[channelName, logChannel] : m_logChannels)
logChannel.m_logLevel = level;
}

static logr::trivial::severity_level StringToLogLevel(const std::string &level)
Expand Down Expand Up @@ -476,25 +475,54 @@ namespace mtconnect::configuration {
void AgentConfiguration::configureLogger(const ptree &config)
{
using namespace logr::trivial;
namespace kw = boost::log::keywords;
namespace expr = logr::expressions;

logr::core::get()->remove_all_sinks();
m_sink.reset();
auto core = logr::core::get();

core->remove_all_sinks();

//// Add the commonly used attributes; includes TimeStamp, ProcessID and ThreadID and others
logr::add_common_attributes();
logr::core::get()->add_global_attribute("Scope", logr::attributes::named_scope());
logr::core::get()->add_global_attribute(logr::aux::default_attribute_names::thread_id(),
core->add_global_attribute("Scope", logr::attributes::named_scope());
core->add_global_attribute(logr::aux::default_attribute_names::thread_id(),
logr::attributes::current_thread_id());
logr::core::get()->add_global_attribute("Timestamp", logr::attributes::utc_clock());
core->add_global_attribute("Timestamp", logr::attributes::utc_clock());

m_logger = &::boost::log::trivial::logger::get();

auto formatter =
expr::stream << expr::format_date_time<boost::posix_time::ptime>("Timestamp",
"%Y-%m-%dT%H:%M:%S.%fZ ")
<< "("
<< expr::attr<logr::attributes::current_thread_id::value_type>("ThreadID")
<< ") [" << severity << "] " << named_scope << ": " << expr::smessage;

configureLoggerChannel("agent", config, formatter);
}

void AgentConfiguration::configureLoggerChannel(const std::string &channelName, const ptree &config, std::optional<boost::log::basic_formatter<char>> formatter)
{
using namespace logr::trivial;
namespace expr = logr::expressions;
namespace kw = boost::log::keywords;

auto &logChannel = m_logChannels[channelName];
if (logChannel.m_channelName == "")
logChannel.m_channelName = channelName;

if (!formatter)
{
formatter =
expr::stream << expr::format_date_time<boost::posix_time::ptime>("Timestamp",
"%Y-%m-%dT%H:%M:%S.%fZ ")
<< std::setw(7) << std::left << boost::log::trivial::severity << " " << expr::message;
}

ptree empty;
auto logger = config.get_child_optional("logger_config").value_or(empty);
setLoggingLevel(severity_level::info);

static const string defaultFileName {"agent.log"};
static const string defaultArchivePattern("agent_%Y-%m-%d_%H-%M-%S_%N.log");
const string defaultFileName = channelName + ".log";
const string defaultArchivePattern = channelName + "_%Y-%m-%d_%H-%M-%S_%N.log";

ConfigOptions options;
AddDefaultedOptions(logger, options,
Expand All @@ -507,19 +535,10 @@ namespace mtconnect::configuration {
{{"output", string()}, {"level", string()}, {"logging_level", string()}});

auto output = GetOption<string>(options, "output");
auto level = setLoggingLevel(
auto level = StringToLogLevel(
GetOption<string>(options, "level")
.value_or(GetOption<string>(options, "logging_level").value_or("info"s)));

gAgentLogger = m_logger = &::boost::log::trivial::logger::get();

auto formatter =
expr::stream << expr::format_date_time<boost::posix_time::ptime>("Timestamp",
"%Y-%m-%dT%H:%M:%S.%fZ ")
<< "("
<< expr::attr<logr::attributes::current_thread_id::value_type>("ThreadID")
<< ") [" << severity << "] " << named_scope << ": " << expr::smessage;

if (m_isDebug || (output && (*output == "cout" || *output == "cerr")))
{
ostream *out;
Expand All @@ -528,11 +547,21 @@ namespace mtconnect::configuration {
else
out = &std::cout;

logr::add_console_log(*out, kw::format = formatter, kw::auto_flush = true);

if (m_isDebug && level >= severity_level::debug)
setLoggingLevel(severity_level::debug);
level = severity_level::debug;

auto sink = boost::make_shared<console_sink>();
logChannel.m_logSink = sink;
logChannel.m_logLevel = level;
logChannel.m_logFileName = output.value_or("debug");

sink->locked_backend()->add_stream(boost::shared_ptr<std::ostream>(out, boost::null_deleter()));
sink->locked_backend()->auto_flush(true);

sink->set_formatter(formatter.value());
sink->set_filter(expr::attr<std::string>("Channel") == logChannel.m_channelName && severity >= logChannel.m_logLevel);

logr::core::get()->add_sink(sink);
return;
}

Expand Down Expand Up @@ -560,16 +589,23 @@ namespace mtconnect::configuration {
}
}

m_maxLogFileSize = ConvertFileSize(options, "max_size", m_maxLogFileSize);
m_logRotationSize = ConvertFileSize(options, "rotation_size", m_logRotationSize);
auto &maxLogFileSize = logChannel.m_maxLogFileSize;
auto &logRotationSize = logChannel.m_logRotationSize;
auto &rotationLogInterval = logChannel.m_rotationLogInterval;
auto &logArchivePattern = logChannel.m_logArchivePattern;
auto &logDirectory = logChannel.m_logDirectory;
auto &logFileName = logChannel.m_logFileName;

maxLogFileSize = ConvertFileSize(options, "max_size", maxLogFileSize);
logRotationSize = ConvertFileSize(options, "rotation_size", logRotationSize);
int max_index = *GetOption<int>(options, "max_index");

if (auto sched = GetOption<string>(options, "schedule"))
{
if (*sched == "DAILY")
m_rotationLogInterval = 24;
rotationLogInterval = 24;
else if (*sched == "WEEKLY")
m_rotationLogInterval = 168;
rotationLogInterval = 168;
else if (*sched != "NEVER")
LOG(error) << "Invalid schedule value.";
}
Expand All @@ -578,52 +614,55 @@ namespace mtconnect::configuration {
auto file_name = *GetOption<string>(options, "file_name");
auto archive_pattern = *GetOption<string>(options, "archive_pattern");

m_logArchivePattern = fs::path(archive_pattern);
if (!m_logArchivePattern.has_filename())
logArchivePattern = fs::path(archive_pattern);
if (!logArchivePattern.has_filename())
{
m_logArchivePattern =
m_logArchivePattern / archiveFileName(get<string>(options["file_name"]));
logArchivePattern =
logArchivePattern / archiveFileName(get<string>(options["file_name"]));
}

if (m_logArchivePattern.is_relative())
m_logArchivePattern = fs::current_path() / m_logArchivePattern;
if (logArchivePattern.is_relative())
logArchivePattern = fs::current_path() / logArchivePattern;

// Get the log directory from the archive path.
m_logDirectory = m_logArchivePattern.parent_path();
logDirectory = logArchivePattern.parent_path();

// If the file name does not specify a log directory, use the
// archive directory
m_logFileName = fs::path(file_name);
if (!m_logFileName.has_parent_path())
m_logFileName = m_logDirectory / m_logFileName;
else if (m_logFileName.is_relative())
m_logFileName = fs::current_path() / m_logFileName;

boost::shared_ptr<logr::core> core = logr::core::get();
logFileName = fs::path(file_name);
if (!logFileName.has_parent_path())
logFileName = logDirectory / logFileName;
else if (logFileName.is_relative())
logFileName = fs::current_path() / logFileName;

// Create a text file sink
m_sink = boost::make_shared<text_sink>(
kw::file_name = m_logFileName, kw::target_file_name = m_logArchivePattern.filename(),
kw::auto_flush = true, kw::rotation_size = m_logRotationSize,
auto sink = boost::make_shared<text_sink>(
kw::file_name = logFileName, kw::target_file_name = logArchivePattern.filename(),
kw::auto_flush = true, kw::rotation_size = logRotationSize,
kw::open_mode = ios_base::out | ios_base::app, kw::format = formatter);

logChannel.m_logSink = sink;
logChannel.m_logLevel = level;

// Set up where the rotated files will be stored
m_sink->locked_backend()->set_file_collector(logr::sinks::file::make_collector(
kw::target = m_logDirectory, kw::max_size = m_maxLogFileSize, kw::max_files = max_index));
sink->locked_backend()->set_file_collector(logr::sinks::file::make_collector(
kw::target = logDirectory, kw::max_size = maxLogFileSize, kw::max_files = max_index));

if (m_rotationLogInterval > 0)
if (rotationLogInterval > 0)
{
m_sink->locked_backend()->set_time_based_rotation(
sink->locked_backend()->set_time_based_rotation(
logr::sinks::file::rotation_at_time_interval(
boost::posix_time::hours(m_rotationLogInterval)));
boost::posix_time::hours(rotationLogInterval)));
}

// Upon restart, scan the target directory for files matching the file_name pattern
m_sink->locked_backend()->scan_for_files();
m_sink->set_formatter(formatter);
sink->locked_backend()->scan_for_files();

sink->set_formatter(formatter.value());
sink->set_filter(expr::attr<std::string>("Channel") == logChannel.m_channelName && severity >= logChannel.m_logLevel);

// Formatter for the logger
core->add_sink(m_sink);
logr::core::get()->add_sink(sink);
}

static std::string ExpandValue(const std::map<std::string, std::string> &values,
Expand Down Expand Up @@ -736,8 +775,8 @@ namespace mtconnect::configuration {
cerr << "could not load config file: " << e.what() << endl;
throw e;
}
// if (!m_loggerFile)
if (!m_sink)

if (m_logChannels.empty())
{
configureLogger(config);
}
Expand Down
Loading

0 comments on commit 5b941a1

Please sign in to comment.