в Boost.Log Я хочу установить фильтры на основе каналов. Используя этот пример я реализовал с помощью text_file_backend. Но в моей программе имена каналов задаются пользователем в качестве входного аргумента. Поэтому я решил реализовать метод, который устанавливает фильтр серьезности для канала.
commons.h
#ifndef COMMONS_H_
#define COMMONS_H_
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/log/common.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/attributes.hpp>
#include <boost/log/sources/logger.hpp>
#include <boost/log/sources/severity_channel_logger.hpp>
#include <boost/log/sinks/syslog_backend.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/utility/manipulators/add_value.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/thread/thread.hpp>
namespace logging = boost::log;
namespace src = boost::log::sources;
namespace sinks = boost::log::sinks;
namespace expr = boost::log::expressions;
namespace keywords = boost::log::keywords;
enum severity_levels
{
normal,
notification,
warning,
error,
critical
};
// Define the attribute keywords
BOOST_LOG_ATTRIBUTE_KEYWORD(line_id, "LineID", unsigned int)
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_levels)
BOOST_LOG_ATTRIBUTE_KEYWORD(channel, "Channel", std::string)
typedef expr::channel_severity_filter_actor< std::string, severity_levels >
min_severity_filter;
typedef src::severity_channel_logger_mt< severity_levels, std::string >
logger_type_mt;
BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(test_lg, logger_type_mt)
typedef sinks::synchronous_sink< sinks::text_file_backend > File_sink;
#define ADD_LOG(severity, channel, msg, args...) add_log_message(__FILE__, __LINE__, severity, channel, boost::this_thread::get_id(), msg, args)
#define MY_GLOBAL_LOGGER(log_, channel, sv, file, line, thread) BOOST_LOG_CHANNEL_SEV( log_, channel, sv) \
<< boost::log::add_value("Line", line) \
<< boost::log::add_value("File", file) \
<< boost::log::add_value("Thread_id", thread)
std::ostream& operator<< (std::ostream& strm, severity_levels level)
{
static const char* strings[] =
{
"normal",
"notification",
"warning",
"error",
"critical"
};
if (static_cast< std::size_t >(level) < sizeof(strings) / sizeof(*strings))
strm << strings[level];
else
strm << static_cast< int >(level);
return strm;
}
#endif
Logger.h
#ifndef LOGGER_H_
#define LOGGER_H_
#define BOOST_LOG_DYN_LINK 1
#include <string.h>
#include <ctime>
#include <chrono>
#include "commons.h"
class Logger
{
public:
static min_severity_filter min_severity;
static void init_logging()
{
logging::add_common_attributes();
// Create a text file sink
boost::shared_ptr< sinks::text_file_backend> backend(new sinks::text_file_backend());
backend->set_file_name_pattern<std::string>("sample_%N.log");
backend->set_rotation_size(2 * 1024 * 1024);
boost::shared_ptr< File_sink > sink(new File_sink(backend));
// Set up where the rotated files will be stored
init_file_collecting <File_sink>(sink);
sink->set_formatter(&file_log_formatter);
sink->locked_backend()->scan_for_files();
logging::core::get()->add_sink(sink);
logging::core::get()->set_filter(min_severity || severity >= normal);
}
template <typename T>
static void init_file_collecting(boost::shared_ptr< T > sink)
{
sink->locked_backend()->set_file_collector(sinks::file::make_collector(
keywords::target = "logs", /*< the target directory >*/
keywords::max_size = 64 * 1024 * 1024, /*< maximum total size of the stored files, in bytes >*/
keywords::min_free_space = 100 * 1024 * 1024 /*< minimum free space on the drive, in bytes >*/
));
}
static void file_log_formatter(logging::record_view const& rec, logging::formatting_ostream& strm)
{
// Get the LineID attribute value and put it into the stream
strm << logging::extract< unsigned int >("LineID", rec) << ": ";
// TimeStamp
strm << "[";
strm << logging::extract<boost::posix_time::ptime>("TimeStamp", rec);
strm << "]";
// thread id
strm << "[" << logging::extract< boost::thread::id >("Thread_id", rec) << "] ";
strm << "[" << rec[channel] << "] ";
strm << "[";
strm << logging::extract< int >("Line", rec) << ", ";
logging::value_ref< std::string > fullpath = logging::extract< std::string >("File", rec);
strm << boost::filesystem::path(fullpath.get()).filename().string() << "] ";
// The same for the severity level.
// The simplified syntax is possible if attribute keywords are used.
strm << "<" << rec[severity] << "> ";
// Finally, put the record message to the stream
strm << rec[expr::smessage];
}
static void set_channel_filter(std::string channel, severity_levels min_level)
{
min_severity[channel] = min_level;
logging::core::get()->set_filter(min_severity);
}
static void add_log_message(const char* file, int line, severity_levels severity,
std::string channel, boost::thread::id thread_id,
const char* message, ...)
{
char buffer[256];
va_list ap;
va_start(ap, message);
vsnprintf(buffer, 256, message, ap);
MY_GLOBAL_LOGGER(test_lg::get(), channel, severity, file, line, thread_id) << buffer;
va_end(ap);
}
};
#endif
min_severity_filter Logger::min_severity = expr::channel_severity_filter(channel, severity);
На первом этапе программы вызов фильтра init_logging()
для всех каналов установлен на нормальное значение.
проблема в том, что когда я вызываю set_channel_filter()
с некоторым входом (например, "CHANNEL_1", предупреждение), я ожидаю установки фильтра только для "CHANNEL_1", Но фильтрация установлена для всех возможных каналов. (например, "CHANNEL_2, et c). Когда я добавляю, например," OTHER_CHANNEL "вручную в set_channel_filter (), это работает для него. Я хочу иметь карту c ++, подобную структуре данных, сохраняющую все фильтры серьезности для канала. и каждый раз, когда пользователь вызывает добавьте новый или существующий канал с фильтром, просто измените фильтрацию для этого конкретного канала, а не для всех.
main. cpp
int main()
{
Logger::init_logging();
Logger::ADD_LOG(severity_levels::normal, "NETWORK", "a warning message with id %d", 34);
Logger::ADD_LOG(severity_levels::notification, "NETWORK", "a warning message with id %d", 65);
Logger::ADD_LOG(severity_levels::notification, "GENERAL", "a notification message with id %d", 12);
Logger::ADD_LOG(severity_levels::warning, "GENERAL", "a warning message with id %d", 13);
// Logs in GENERAL category must have severity level of warning or higher in-order to record.
Logger::set_channel_filter("GENERAL", severity_levels::warning);
Logger::ADD_LOG(severity_levels::notification, "GENERAL", "a notification message with id %d", 14);
for (int i = 0; i < 2; i++)
{
Logger::ADD_LOG(severity_levels::warning, "GENERAL", "a warning message with id %d", 15);
}
Logger::ADD_LOG(severity_levels::normal, "NETWORK", "a warning message with id %d", 34); // Expected to sent to file. but filtered!!
Logger::ADD_LOG(severity_levels::notification, "NETWORK", "a warning message with id %d", 65); //Also filtered !!
}