Я реализовал приемник, который записывает записи в std :: vector и сбрасывает все журналы в консоль при вызове функции flush.Я добавил четыре атрибута в соответствии с:
BOOST_LOG_ATTRIBUTE_KEYWORD(a_timestamp, "TimeStamp", boost::log::attributes::local_clock::value_type)
BOOST_LOG_ATTRIBUTE_KEYWORD(a_severity, "Severity", boost::log::trivial::severity_level)
BOOST_LOG_ATTRIBUTE_KEYWORD(a_file, "File", std::string)
BOOST_LOG_ATTRIBUTE_KEYWORD(a_line, "Line", std::string)
Однако, когда я использую функцию set_formatter, я получаю ошибку компилятора (MSVC17), говорящую:
Ошибка C2679 бинарная '<<': не найден оператор, который принимает правый операнд типа' const T '(или нет приемлемого преобразования) ControllerSoftware c: \ local \ boost_1_68_0 \ boost \ log \ utility \ formatting_ostream.hpp 870 </p>
Для ясности я предоставлю полный код:
// cswlogger.h
#pragma once
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/attributes/mutable_constant.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/sources/global_logger_storage.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/utility/manipulators/add_value.hpp>
#include <boost/log/core.hpp>
#include <boost/log/sinks/basic_sink_backend.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <vector>
#include <string>
namespace sinks = boost::log::sinks;
BOOST_LOG_GLOBAL_LOGGER(sysLogger,
boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level>);
class CswLogger
{
public:
/// Init with default info level logging
static void init(bool useRamLog = false, boost::log::trivial::severity_level level = boost::log::trivial::info);
/// Disable logging
static void disable();
// Flush log
static void flushLogs();
// Convert file path to only the filename
static std::string path_to_filename(std::string path)
{
return path.substr(path.find_last_of("/\\") + 1);
}
private:
static void registerRamLog();
};
class RamLogSink :
public sinks::basic_formatted_sink_backend<
char,
sinks::combine_requirements<
sinks::synchronized_feeding,
sinks::flushing
>::type
>
{
public:
// The function consumes the log records that come from the frontend
void consume(boost::log::record_view const& rec, string_type const& strType);
// The function flushes the logs in vector
void flush();
private:
std::vector<std::string> logEntries_;
};
// Complete sink type
typedef sinks::synchronous_sink< RamLogSink > sink_t;
#define LOG_LOG_LOCATION(LOGGER, LEVEL, ARG) \
BOOST_LOG_SEV(LOGGER, boost::log::trivial::LEVEL) \
<< boost::log::add_value("Line", std::to_string(__LINE__)) \
<< boost::log::add_value("File", CswLogger::path_to_filename(__FILE__)) << ARG
// System Log macros.
// TRACE < DEBUG < INFO < WARN < ERROR < FATAL
#define LOG_TRACE(ARG) LOG_LOG_LOCATION(sysLogger::get(), trace, ARG);
#define LOG_DEBUG(ARG) LOG_LOG_LOCATION(sysLogger::get(), debug, ARG);
#define LOG_INFO(ARG) LOG_LOG_LOCATION(sysLogger::get(), info, ARG);
#define LOG_WARN(ARG) LOG_LOG_LOCATION(sysLogger::get(), warning, ARG);
#define LOG_ERROR(ARG) LOG_LOG_LOCATION(sysLogger::get(), error, ARG);
#define LOG_FATAL(ARG) LOG_LOG_LOCATION(sysLogger::get(), fatal, ARG);
Исходный файл:
// cswlogger.cpp
#include "cswlogger.h"
#include <boost/log/core.hpp>
#include <boost/log/common.hpp>
#include <boost/log/attributes.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/utility/setup/settings.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <string>
#include <iostream>
BOOST_LOG_GLOBAL_LOGGER_DEFAULT(sysLogger,
boost::log::sources::severity_channel_logger_mt<boost::log::trivial::severity_level>);
BOOST_LOG_ATTRIBUTE_KEYWORD(a_timestamp, "TimeStamp", boost::log::attributes::local_clock::value_type)
BOOST_LOG_ATTRIBUTE_KEYWORD(a_severity, "Severity", boost::log::trivial::severity_level)
BOOST_LOG_ATTRIBUTE_KEYWORD(a_file, "File", std::string)
BOOST_LOG_ATTRIBUTE_KEYWORD(a_line, "Line", std::string)
void CswLogger::init(bool useRamLog, boost::log::trivial::severity_level level)
{
boost::log::register_simple_formatter_factory<boost::log::trivial::severity_level, char>("Severity");
if (useRamLog)
{
registerRamLog();
}
else
{
boost::log::add_console_log
(
std::clog,
boost::log::keywords::format = "[%TimeStamp%] [%Severity%] %File%(%Line%): %Message%"
);
}
boost::log::add_common_attributes();
boost::log::core::get()->set_filter
(
boost::log::trivial::severity >= level
);
// Indicate start of logging
LOG_INFO("Log Start");
}
void CswLogger::disable()
{
boost::log::core::get()->set_logging_enabled(false);
}
void CswLogger::flushLogs()
{
boost::log::core::get()->flush();
}
void CswLogger::registerRamLog()
{
boost::shared_ptr< RamLogSink > backend(new RamLogSink());
boost::shared_ptr< sink_t > sink(new sink_t(backend));
sink->set_formatter(boost::log::expressions::stream
<< "[" << a_timestamp << "] " // <--- Compile error here
<< "[" << a_severity << "] "
<< "[" << a_file << "(" << a_line << ")] "
<< boost::log::expressions::message);
boost::log::core::get()->add_sink(sink);
}
// RamlogSink Class declarations
void RamLogSink::consume(boost::log::record_view const& rec, string_type const& strType)
{
logEntries_.emplace_back(strType);
}
void RamLogSink::flush()
{
for (auto const& entry : logEntries_)
{
std::cout << entry << std::endl;
}
logEntries_.clear();
}
main.cpp:
#include "cswlogger.h"
CswLogger::init(true);
LOG_TRACE("This should not be printed");
LOG_ERROR("Very bad error that needs to be printed");
int theInt = 234;
LOG_FATAL("TheInt integer is: " << theInt);
CswLogger::flushLogs();
Я такжеВозникла проблема при добавлении атрибута "Line" с помощью:
BOOST_LOG_ATTRIBUTE_KEYWORD(a_line, "Line", int)
Я должен изменить на std :: string и преобразовать целое число в строку в
#define LOG_LOG_LOCATION(LOGGER, LEVEL, ARG) \
BOOST_LOG_SEV(LOGGER, boost::log::trivial::LEVEL) \
<< boost::log::add_value("Line", std::to_string(__LINE__)) \
<< boost::log::add_value("File", CswLogger::path_to_filename(__FILE__)) << ARG
В противном случае строкачисло вышло в виде пустой строки.