Assume there is only a single sink (for example a file) and couple of threads are writing their logs on that.
I've searched a lot but unfortunately could not find a good example.
I've tried multiple channels per threads and got crash.
#include <iostream>
#include <boost/log/expressions.hpp>
#include <boost/log/sources/severity_channel_logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/sinks.hpp>
#include <thread>
namespace logging = boost::log;
namespace src = boost::log::sources;
namespace expr = boost::log::expressions;
namespace keywords = boost::log::keywords;
namespace sinks = boost::log::sinks;
// We define our own severity levels
enum severity_level
{
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_level)
BOOST_LOG_ATTRIBUTE_KEYWORD(channel, "Channel", std::string)
std::ostream& operator<< (std::ostream& strm, severity_level 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;
}
void init()
{
// Create a minimal severity table filter
typedef expr::channel_severity_filter_actor< std::string, severity_level > min_severity_filter;
min_severity_filter min_severity = expr::channel_severity_filter(channel, severity);
// Set up the minimum severity levels for different channels
min_severity["general"] = notification;
min_severity["network"] = warning;
min_severity["gui"] = error;
logging::add_file_log
(
keywords::file_name = "sample_%N.log",
keywords::rotation_size = 1000 * 1024 * 1024,
keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0),
keywords::filter = min_severity || severity >= critical,
keywords::format =
(
expr::stream
<< line_id
<< ": <" << severity
<< "> [" << channel << "] "
<< expr::smessage
)
);
logging::add_console_log
(
std::clog,
keywords::filter = min_severity || severity >= critical,
keywords::format =
(
expr::stream
<< line_id
<< ": <" << severity
<< "> [" << channel << "] "
<< expr::smessage
)
);
// Define our logger type
typedef src::severity_channel_logger< severity_level, std::string > logger_type;
void test_logging(logger_type lg, std::string const channel_name)
{
for(int i=0; i<1000; i++) {
BOOST_LOG_CHANNEL_SEV(lg, channel_name, normal) << "A normal severity level message";
BOOST_LOG_CHANNEL_SEV(lg, channel_name, notification) << "A notification severity level message";
BOOST_LOG_CHANNEL_SEV(lg, channel_name, warning) << "A warning severity level message";
BOOST_LOG_CHANNEL_SEV(lg, channel_name, error) << "An error severity level message";
BOOST_LOG_CHANNEL_SEV(lg, channel_name, critical) << "A critical severity level message";
}
}
int main(int, char*[])
{
init();
logging::add_common_attributes();
logger_type lg;
std::thread t1(test_logging, lg, "general");
std::thread t2(test_logging, lg, "network");
std::thread t3(test_logging, lg, "gui");
std::thread t4(test_logging, lg, "filesystem");
getchar();
return 0;
}
Related
I have a code similar to this:
const auto jsonFormatter = boost::log::expressions::stream << boost::log::expressions::smessage;
I want to escape the message using nlohmann::json, something like:
nlohmann::json json{boost::log::expressions::smessage};
I can do following to convert boost::log::expressions::smessage to std::string:
std::stringstream ss;
ss << boost::log::expressions::smessage;
std::string message = ss.str();
nlohmann::json json{message};
, but I need to put it inside the formatter, because the
const auto jsonFormatter = boost::log::expressions::stream << nlohmann::json{boost::log::expressions::smessage};
can't convert the boost::log::expressions::smessage argument to any nlohmann::json constructor.
Any suggestions how to make it work?
Log formatters look like normal C++, but they are expression templates that compose deferred calleable that do the corresponding action.
Here's how you can make a wrapper expression that knows how to do this:
namespace {
struct as_json_t {
template <typename E> auto operator[](E fmt) const {
return expr::wrap_formatter(
[fmt](logging::record_view const& rec,
logging::formatting_ostream& strm) {
logging::formatting_ostream tmp;
std::string text;
tmp.attach(text);
fmt(rec, tmp);
strm << nlohmann::json{text};
});
}
};
inline constexpr as_json_t as_json;
} // namespace
Now you can make your formatter e.g.
logging::formatter formatter = expr::stream
<< expr::format_date_time(timestamp, "%Y-%m-%d, %H:%M:%S.%f") << " "
<< logging::trivial::severity
<< " - " << as_json[expr::stream << expr::smessage]
;
ANd the result is e.g.
2021-01-15, 23:34:08.489173 error - ["this is an error message"]
Live Demo
Live On Wandbox
File simpleLogger.h
#ifndef _HOME_SEHE_PROJECTS_STACKOVERFLOW_SIMPLELOGGER_H
#define _HOME_SEHE_PROJECTS_STACKOVERFLOW_SIMPLELOGGER_H
#pragma once
#define BOOST_LOG_DYN_LINK \
1 // necessary when linking the boost_log library dynamically
#include <boost/log/sources/global_logger_storage.hpp>
#include <boost/log/trivial.hpp>
// the logs are also written to LOGFILE
#define LOGFILE "logfile.log"
// just log messages with severity >= SEVERITY_THRESHOLD are written
#define SEVERITY_THRESHOLD logging::trivial::warning
// register a global logger
BOOST_LOG_GLOBAL_LOGGER(logger, boost::log::sources::severity_logger_mt<
boost::log::trivial::severity_level>)
// just a helper macro used by the macros below - don't use it in your code
#define LOG(severity) \
BOOST_LOG_SEV(logger::get(), boost::log::trivial::severity)
// ===== log macros =====
#define LOG_TRACE LOG(trace)
#define LOG_DEBUG LOG(debug)
#define LOG_INFO LOG(info)
#define LOG_WARNING LOG(warning)
#define LOG_ERROR LOG(error)
#define LOG_FATAL LOG(fatal)
#endif
File simpleLogger.cpp
#include "simpleLogger.h"
#include <boost/core/null_deleter.hpp>
#include <boost/log/core/core.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/expressions/formatters/char_decorator.hpp>
#include <boost/log/expressions/formatters/date_time.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <nlohmann/json.hpp>
#include <fstream>
namespace logging = boost::log;
namespace src = boost::log::sources;
namespace expr = boost::log::expressions;
namespace sinks = boost::log::sinks;
namespace attrs = boost::log::attributes;
BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "TimeStamp", boost::posix_time::ptime)
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", logging::trivial::severity_level)
namespace {
struct as_json_t {
template <typename E> auto operator[](E fmt) const {
return expr::wrap_formatter(
[fmt](logging::record_view const& rec,
logging::formatting_ostream& strm) {
logging::formatting_ostream tmp;
std::string text;
tmp.attach(text);
fmt(rec, tmp);
strm << nlohmann::json{text};
});
}
};
inline constexpr as_json_t as_json;
} // namespace
BOOST_LOG_GLOBAL_LOGGER_INIT(logger, src::severity_logger_mt) {
src::severity_logger_mt<boost::log::trivial::severity_level> logger;
// add attributes
logger.add_attribute("TimeStamp", attrs::local_clock()); // each log line gets a timestamp
// add a text sink
using text_sink = sinks::synchronous_sink<sinks::text_ostream_backend>;
boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>();
// add a logfile stream to our sink
sink->locked_backend()->add_stream(
boost::make_shared<std::ofstream>(LOGFILE));
// add "console" output stream to our sink
sink->locked_backend()->add_stream(
boost::shared_ptr<std::ostream>(&std::clog, boost::null_deleter()));
// specify the format of the log message
logging::formatter formatter = expr::stream
<< expr::format_date_time(timestamp, "%Y-%m-%d, %H:%M:%S.%f") << " "
<< logging::trivial::severity
<< " - " << as_json[expr::stream << expr::smessage]
;
sink->set_formatter(formatter);
// only messages with severity >= SEVERITY_THRESHOLD are written
sink->set_filter(severity >= SEVERITY_THRESHOLD);
// "register" our sink
logging::core::get()->add_sink(sink);
return logger;
}
File test.cpp
#include "simpleLogger.h"
int main() {
LOG_TRACE << "this is a trace message";
LOG_DEBUG << "this is a debug message";
LOG_WARNING << "this is a warning message";
LOG_ERROR << "this is an error message";
LOG_FATAL << "this is a fatal error message";
return 0;
}
Prints
2021-01-15, 23:50:03.130250 warning - ["this is a warning message"]
2021-01-15, 23:50:03.130327 error - ["this is an error message"]
2021-01-15, 23:50:03.130354 fatal - ["this is a fatal error message"]
In addition to sehe's answer, you could achieve the JSON-like format using Boost.Log components. The essential part is the c_decor character decorator, which ensures that its output can be used as a C-style string literal.
namespace expr = boost::log::expressions;
const auto jsonFormatter =
expr::stream << "[\""
<< expr::c_decor[ expr::stream << expr::smessage ]
<< "\"]";
First, c_decor will escape any control characters in the messages to C-style escape sequences, like \n, \t. It will also escape double quote characters. Then, the surrounding brackets and double quotes are added to make the output compatible with JSON format.
If you have non-ASCII characters in your log messages and you want the formatted log records to be strictly ASCII, you can use c_ascii_decor instead of c_decor. In addition to what c_decor does, it will also escape any bytes greater than 127 to their hex escape sequences, e.g. \x8c.
I really appreciate help and the other answers, which may be better in other cases, but long story short, I tried a lot of solutions and went with this one in the end (I can update it if it can be improved):
#include <boost/phoenix/bind/bind_function.hpp>
..
nlohmann::json EscapeMessage(
boost::log::value_ref<std::string, boost::log::expressions::tag::smessage> const& message)
{
return message ? nlohmann::json(message.get()) : nlohmann::json();
}
..
const auto jsonFormatter = boost::log::expressions::stream << boost::phoenix::bind(&EscapeMessage, boost::log::expressions::smessage.or_none())
boost::log::add_console_log(std::cout, boost::log::keywords::format = jsonFormatter);
I have written C++ code for capturing the various severity levels of messages. I have used https://github.com/gklingler/simpleLogger for this.
File simpleLogger.cpp
#include "simpleLogger.h"
#include <boost/log/core/core.hpp>
#include <boost/log/expressions/formatters/date_time.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/trivial.hpp>
#include <boost/core/null_deleter.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <fstream>
#include <ostream>
namespace logging = boost::log;
namespace src = boost::log::sources;
namespace expr = boost::log::expressions;
namespace sinks = boost::log::sinks;
namespace attrs = boost::log::attributes;
BOOST_LOG_ATTRIBUTE_KEYWORD(line_id, "LineID", unsigned int)
BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "TimeStamp", boost::posix_time::ptime)
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", logging::trivial::severity_level)
BOOST_LOG_GLOBAL_LOGGER_INIT(logger, src::severity_logger_mt) {
src::severity_logger_mt<boost::log::trivial::severity_level> logger;
// add attributes
logger.add_attribute("LineID", attrs::counter<unsigned int>(1)); // lines are sequentially numbered
logger.add_attribute("TimeStamp", attrs::local_clock()); // each log line gets a timestamp
// add a text sink
typedef sinks::synchronous_sink<sinks::text_ostream_backend> text_sink;
boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>();
// add a logfile stream to our sink
sink->locked_backend()->add_stream(boost::make_shared<std::ofstream>(LOGFILE));
// add "console" output stream to our sink
sink->locked_backend()->add_stream(boost::shared_ptr<std::ostream>(&std::clog, boost::null_deleter()));
// specify the format of the log message
logging::formatter formatter = expr::stream
<< std::setw(7) << std::setfill('0') << line_id << std::setfill(' ') << " | "
<< expr::format_date_time(timestamp, "%Y-%m-%d, %H:%M:%S.%f") << " "
<< "[" << logging::trivial::severity << "]"
<< " - " << expr::smessage;
sink->set_formatter(formatter);
// only messages with severity >= SEVERITY_THRESHOLD are written
sink->set_filter(severity >= SEVERITY_THRESHOLD);
// "register" our sink
logging::core::get()->add_sink(sink);
return logger;
}
File simpleLogger.h
#ifndef simpleLogger_h__
#define simpleLogger_h__
#define BOOST_LOG_DYN_LINK // necessary when linking the boost_log library dynamically
#include <boost/log/trivial.hpp>
#include <boost/log/sources/global_logger_storage.hpp>
// the logs are also written to LOGFILE
#define LOGFILE "logfile.log"
// just log messages with severity >= SEVERITY_THRESHOLD are written
#define SEVERITY_THRESHOLD logging::trivial::warning
// register a global logger
BOOST_LOG_GLOBAL_LOGGER(logger, boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level>)
// just a helper macro used by the macros below - don't use it in your code
#define LOG(severity) BOOST_LOG_SEV(logger::get(),boost::log::trivial::severity)
// ===== log macros =====
#define LOG_TRACE LOG(trace)
#define LOG_DEBUG LOG(debug)
#define LOG_INFO LOG(info)
#define LOG_WARNING LOG(warning)
#define LOG_ERROR LOG(error)
#define LOG_FATAL LOG(fatal)
#endif
File app.cpp
#include "simpleLogger.h"
int main() {
LOG_TRACE << "this is a trace message";
LOG_DEBUG << "this is a debug message";
LOG_WARNING << "this is a warning message";
LOG_ERROR << "this is an error message";
LOG_FATAL << "this is a fatal error message";
return 0;
}
So I would send my message as
LOG_INFO << "This is info message"
But this log message I need to send it to some other function as an argument. In that function I will be doing some other changes on the log message i.e "This is info message".
How to send the boost log message as an argument to function?
I didn't find relevant source for this.
Thanks in advance
You can define a "lazy actor" that you can put into a wrapped formatter expression. This is pretty much the rocket science of Boost Log, but perhaps this simple example will help you:
auto reverse_expr = [](auto fmt) {
return expr::wrap_formatter([fmt](logging::record_view const& rec, logging::formatting_ostream& strm) {
logging::formatting_ostream tmp;
std::string text;
tmp.attach(text);
fmt(rec, tmp);
std::reverse(text.begin(), text.end());
strm << text;
});
};
// specify the format of the log message
logging::formatter formatter = expr::stream
<< reverse_expr(expr::stream << std::setw(7) << std::setfill('0') << line_id)
<< " | "
<< expr::format_date_time(timestamp, "%Y-%m-%d, %H:%M:%S.%f") << " "
<< "[" << logging::trivial::severity << "]"
<< " - "
<< reverse_expr(expr::stream << expr::smessage);
sink->set_formatter(formatter);
Results in:
3000000 | 2020-04-28, 16:15:15.779204 [warning] - egassem gninraw a si siht
4000000 | 2020-04-28, 16:15:15.779308 [error] - egassem rorre na si siht
5000000 | 2020-04-28, 16:15:15.779324 [fatal] - egassem rorre lataf a si siht
Notes: it will not be overly efficient because it involves "double buffering" with a temporary stream, but it is highly flexible, as you can see.
UPDATE Improved method below (see section BONUS)
A slightly more generic implementation might look like:
template <typename F> struct Xfrm {
Xfrm(F f) : _f(f) {}
F _f;
template <typename E> auto operator[](E fmt) const {
return expr::wrap_formatter(
[f=_f,fmt](logging::record_view const& rec, logging::formatting_ostream& strm) {
logging::formatting_ostream tmp;
std::string text;
tmp.attach(text);
fmt(rec, tmp);
strm << f(text);
});
}
};
So you can actually use it for other functions:
std::string reversed(std::string v) {
std::reverse(v.begin(), v.end());
return v;
}
std::string to_uppercase(std::string v) {
for (auto& ch : v) ch = std::toupper(ch);
return v;
}
Which you could then use like:
logging::formatter formatter = expr::stream
<< Xfrm(reversed)[expr::stream << std::setw(7) << std::setfill('0') << line_id]
<< " | "
<< expr::format_date_time(timestamp, "%Y-%m-%d, %H:%M:%S.%f") << " "
<< "[" << logging::trivial::severity << "]"
<< " - "
<< Xfrm(to_uppercase)[ expr::stream << expr::smessage ];
Or put the manipulators in your header file:
static inline constexpr Xfrm UC{to_uppercase};
static inline constexpr Xfrm REV{reversed};
So you can use it pre-fab:
logging::formatter formatter = expr::stream
<< REV[ expr::stream << std::setw(7) << std::setfill('0') << line_id ]
<< " | "
<< expr::format_date_time(timestamp, "%Y-%m-%d, %H:%M:%S.%f") << " "
<< "[" << logging::trivial::severity << "]"
<< " - "
<< UC[ expr::stream << expr::smessage ];
Output
3000000 | 2020-04-28, 16:36:46.184958 [warning] - THIS IS A WARNING MESSAGE
4000000 | 2020-04-28, 16:36:46.185034 [error] - THIS IS AN ERROR MESSAGE
5000000 | 2020-04-28, 16:36:46.185045 [fatal] - THIS IS A FATAL ERROR MESSAGE
Live Demo
Live On Wandbox
File simpleLogger.h
#ifndef _HOME_SEHE_PROJECTS_STACKOVERFLOW_SIMPLELOGGER_H
#define _HOME_SEHE_PROJECTS_STACKOVERFLOW_SIMPLELOGGER_H
#pragma once
#define BOOST_LOG_DYN_LINK \
1 // necessary when linking the boost_log library dynamically
#include <boost/log/sources/global_logger_storage.hpp>
#include <boost/log/trivial.hpp>
// the logs are also written to LOGFILE
#define LOGFILE "logfile.log"
// just log messages with severity >= SEVERITY_THRESHOLD are written
#define SEVERITY_THRESHOLD logging::trivial::warning
// register a global logger
BOOST_LOG_GLOBAL_LOGGER(logger, boost::log::sources::severity_logger_mt<
boost::log::trivial::severity_level>)
// just a helper macro used by the macros below - don't use it in your code
#define LOG(severity) \
BOOST_LOG_SEV(logger::get(), boost::log::trivial::severity)
// ===== log macros =====
#define LOG_TRACE LOG(trace)
#define LOG_DEBUG LOG(debug)
#define LOG_INFO LOG(info)
#define LOG_WARNING LOG(warning)
#define LOG_ERROR LOG(error)
#define LOG_FATAL LOG(fatal)
#endif
File simpleLogger.cpp
#include "simpleLogger.h"
#include <boost/core/null_deleter.hpp>
#include <boost/log/core/core.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/expressions/formatters/char_decorator.hpp>
#include <boost/log/expressions/formatters/date_time.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/make_shared.hpp>
#include <boost/phoenix.hpp>
#include <boost/phoenix/function.hpp>
#include <boost/shared_ptr.hpp>
#include <fstream>
#include <ostream>
namespace logging = boost::log;
namespace src = boost::log::sources;
namespace expr = boost::log::expressions;
namespace sinks = boost::log::sinks;
namespace attrs = boost::log::attributes;
BOOST_LOG_ATTRIBUTE_KEYWORD(line_id, "LineID", unsigned int)
BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "TimeStamp", boost::posix_time::ptime)
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity",
logging::trivial::severity_level)
namespace /*extend locally*/ {
template <typename F> struct Xfrm {
constexpr Xfrm(F f) : _f(f) {}
F _f;
template <typename E> auto operator[](E fmt) const {
return expr::wrap_formatter(
[f = _f, fmt](logging::record_view const& rec,
logging::formatting_ostream& strm) {
logging::formatting_ostream tmp;
std::string text;
tmp.attach(text);
fmt(rec, tmp);
strm << f(text);
});
}
};
std::string reversed(std::string v) {
std::reverse(v.begin(), v.end());
return v;
}
std::string to_uppercase(std::string v) {
for (auto& ch : v) {
ch = std::toupper(ch);
}
return v;
}
inline constexpr Xfrm UC{ to_uppercase };
inline constexpr Xfrm REV{ reversed };
} // namespace
BOOST_LOG_GLOBAL_LOGGER_INIT(logger, src::severity_logger_mt) {
src::severity_logger_mt<boost::log::trivial::severity_level> logger;
// add attributes
logger.add_attribute("LineID", attrs::counter<unsigned int>(
1)); // lines are sequentially numbered
logger.add_attribute(
"TimeStamp", attrs::local_clock()); // each log line gets a timestamp
// add a text sink
using text_sink = sinks::synchronous_sink<sinks::text_ostream_backend>;
boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>();
// add a logfile stream to our sink
sink->locked_backend()->add_stream(
boost::make_shared<std::ofstream>(LOGFILE));
// add "console" output stream to our sink
sink->locked_backend()->add_stream(
boost::shared_ptr<std::ostream>(&std::clog, boost::null_deleter()));
// specify the format of the log message
logging::formatter formatter =
expr::stream
<< REV[expr::stream << std::setw(7) << std::setfill('0') << line_id]
<< " | "
<< expr::format_date_time(timestamp, "%Y-%m-%d, %H:%M:%S.%f") << " "
<< "[" << logging::trivial::severity << "]"
<< " - " << UC[expr::stream << expr::smessage];
sink->set_formatter(formatter);
// only messages with severity >= SEVERITY_THRESHOLD are written
sink->set_filter(severity >= SEVERITY_THRESHOLD);
// "register" our sink
logging::core::get()->add_sink(sink);
return logger;
}
File test.cpp
#include "simpleLogger.h"
int main() {
LOG_TRACE << "this is a trace message";
LOG_DEBUG << "this is a debug message";
LOG_WARNING << "this is a warning message";
LOG_ERROR << "this is an error message";
LOG_FATAL << "this is a fatal error message";
return 0;
}
BONUS: More Efficient
To avoid double-buffering, we can avoid using the original formatter. This works best for known attributes:
struct OddEvenId {
void operator()(logging::record_view const& rec, logging::formatting_ostream& strm) const {
auto vr = line_id.or_throw()(rec);
if (!vr.empty()) {
strm << std::setw(4) << (vr.get<uint32_t>()%2? "Odd":"Even");
}
}
};
struct QuotedMessage {
void operator()(logging::record_view const& rec, logging::formatting_ostream& strm) const {
auto vr = expr::smessage.or_throw()(rec);
if (!vr.empty())
strm << std::quoted(vr.get<std::string>());
}
};
static inline auto oddeven_id = expr::wrap_formatter(OddEvenId{});
static inline auto qmessage = expr::wrap_formatter(QuotedMessage{});
Now we can simply say qmessage instead of expr::smessage to get the quoted message value:
Live On Wandbox
logging::formatter formatter = expr::stream
<< oddeven_id
<< " | "
<< expr::format_date_time(timestamp, "%Y-%m-%d, %H:%M:%S.%f") << " "
<< "[" << logging::trivial::severity << "]"
<< " - " << qmessage;
Prints
Odd | 2020-04-28, 17:21:12.619565 [warning] - "this is a warning message"
Even | 2020-04-28, 17:21:12.619666 [error] - "this is an error message"
Odd | 2020-04-28, 17:21:12.619684 [fatal] - "this is a fatal error message"
in Boost.Log I want to set filters based on channels. Using this example I implemented using text_file_backend. But in my program, channel names are given by user as input argument. So I decided to implement a method that set severity filter for channel.
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);
At the first of program by calling init_logging() filter for all channels is set to normal.
the problem is when I invoke set_channel_filter() with some input (e.g. "CHANNEL_1", warning), I expect setting filter only for "CHANNEL_1", But filtering is set for all possible channels. (e.g. "CHANNEL_2, etc). When I add for example "OTHER_CHANNEL" manually to set_channel_filter() it works for it. I want to have c++ map like data structure saving all severity filter per channel. and anytime user invoke to add a new or existing channel with a filter, it just change filtering for that particular channel, not for all.
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 !!
}
The problem is that initially, in init_logging, you set the filter as follows:
logging::core::get()->set_filter(min_severity || severity >= normal);
At this point, min_severity is empty, as you haven't added any channels/severity thresholds. By default, min_severity will return false when a channel is not found in the channel/severity mapping, which means the filter you set here is effectively severity >= normal.
Later, when you call set_channel_filter, you add the first entry to the min_severity mapping, so that it works for the "GENERAL" channel but not for any other. However, you set a different filter this time:
logging::core::get()->set_filter(min_severity);
This time, if min_severity returns false the log record is discarded, which is what happens with the last two records in the "NETWORK" channel. You need to set the same filter expression every time to have a consistent behavior.
I try to set dynamic date for my boost multi-file logger to separate log files for everyday in different files like this :'log___2018-07-10__172.17.18.199.log'.
I don't want to set the date in each functions in my code a BOOST_LOG_SCOPED_THREAD_TAG!
I want the boost core logger to do that and I just want to set local clock in global attributes, but I do NOT know how to do that.
Here is me code:
#include <boost/shared_ptr.hpp>
#include <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/common.hpp>
#include <boost/log/attributes.hpp>
#include <boost/log/sources/logger.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_multifile_backend.hpp>
#include <boost/log/support/date_time.hpp>
enum SeverityLevel {
TRACE,
DEBUG,
WARNING,
INFO,
ERROR,
FATAL
};
enum
{
THREAD_COUNT = 5,
LOG_RECORDS_TO_WRITE = 10
};
boost::log::sources::severity_logger_mt< SeverityLevel > myLogger;
#define LOG_ERROR BOOST_LOG_SEV(myLogger, ERROR)
#define LOG_FATAL BOOST_LOG_SEV(myLogger, FATAL)
#define LOG_INFO BOOST_LOG_SEV(myLogger, INFO)
#define LOG_WARNING BOOST_LOG_SEV(myLogger, WARNING)
#define LOG_DEBUG BOOST_LOG_SEV(myLogger, DEBUG)
#define LOG_TRACE BOOST_LOG_SEV(myLogger, TRACE)
// This function is executed in a separate thread
void thread_fooMain()
{
BOOST_LOG_NAMED_SCOPE("thread_fooMain");
for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i)
{
LOG_ERROR << "Log record " << i;
}
}
void thread_foo2()
{
BOOST_LOG_SCOPED_THREAD_TAG("TerminalIP", "172.17.18.102");
BOOST_LOG_NAMED_SCOPE("thread_fooMain");
for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i)
{
LOG_TRACE << "Log record " << i;
}
}
void thread_foo3()
{
BOOST_LOG_SCOPED_THREAD_TAG("TerminalIP", "172.17.18.103");
BOOST_LOG_NAMED_SCOPE("thread_fooMain");
for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i)
{
LOG_INFO << "Log record " << i;
}
}
void thread_foo4()
{
BOOST_LOG_SCOPED_THREAD_TAG("TerminalIP", "172.17.18.104");
BOOST_LOG_NAMED_SCOPE("thread_fooMain");
for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i)
{
LOG_INFO << "Log record " << i;
}
}
void thread_foo5()
{
BOOST_LOG_SCOPED_THREAD_TAG("TerminalIP", "172.17.18.105");
BOOST_LOG_NAMED_SCOPE("thread_fooMain");
for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i)
{
LOG_INFO << "Log record " << i;
}
}
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", SeverityLevel)
BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "Timestamp", boost::posix_time::ptime)
BOOST_LOG_ATTRIBUTE_KEYWORD(dateStream, "DateStream", boost::posix_time::ptime)
BOOST_LOG_ATTRIBUTE_KEYWORD(thread_id, "ThreadID", boost::log::attributes::current_thread_id::value_type)
// The operator puts a human-friendly representation of the severity level to the stream
std::ostream & operator<< (std::ostream & strm, SeverityLevel level)
{
static const char* strings[] =
{
"TRACE",
"DEBUG",
"WARNING",
"INFO",
"ERROR",
"FATAL"
};
if (static_cast< std::size_t >(level) < sizeof(strings) / sizeof(*strings))
strm << strings[level];
else
strm << static_cast< int >(level);
return strm;
}
int main(int argc, char* argv[])
{
try
{
// Create a text file sink
typedef boost::log::sinks::synchronous_sink< boost::log::sinks::text_multifile_backend > file_sink;
boost::shared_ptr< file_sink > sink(new file_sink);
// Set up how the file names will be generated
sink->locked_backend()->set_file_name_composer(
boost::log::sinks::file::as_file_name_composer(
boost::log::expressions::stream <<
"log/log_" <<
boost::log::expressions::format_date_time(dateStream, "__%Y_%m_%d__") <<
boost::log::expressions::attr< std::string >("TerminalIP") <<
".log"
)
);
sink->set_formatter
(
boost::log::expressions::stream <<
boost::log::expressions::format_date_time< boost::posix_time::ptime >("TimeStamp", "[%Y/%m/%d %H:%M:%S.%f]") <<
"<" << severity << ">" <<
"[" << thread_id << "]:" <<
"<" << boost::log::expressions::format_named_scope("Scope", boost::log::keywords::format = "%n") << "> " <<
boost::log::expressions::smessage
);
// Add it to the core
boost::log::core::get()->add_sink(sink);
boost::log::core::get()->set_filter
(
severity >= WARNING
);
// Add some attributes too
boost::log::core::get()->add_global_attribute("TimeStamp", boost::log::attributes::local_clock());
boost::log::core::get()->add_global_attribute("DateStream", boost::log::attributes::local_clock());
boost::log::core::get()->add_global_attribute("Scope", boost::log::attributes::named_scope());
boost::log::core::get()->add_global_attribute("ThreadID", boost::log::attributes::current_thread_id());
// Create threads and make some logs
boost::thread_group threads;
threads.create_thread(&thread_fooMain);
threads.create_thread(&thread_foo2);
threads.create_thread(&thread_foo3);
threads.create_thread(&thread_foo4);
threads.create_thread(&thread_foo5);
threads.join_all();
return 0;
}
catch (std::exception& e)
{
std::cout << "FAILURE: " << e.what() << std::endl;
return 1;
}
}
but got this linker error:
ErrorC2664 'boost::log::v2s_mt_nt6::aux::light_function<void (boost::log::v2s_mt_nt6::basic_formatting_ostream<char,std::char_traits<char>,std::allocator<char>> &,const boost::posix_time::ptime &)>::result_type boost::log::v2s_mt_nt6::aux::light_function<void (boost::log::v2s_mt_nt6::basic_formatting_ostream<char,std::char_traits<char>,std::allocator<char>> &,const boost::posix_time::ptime &)>::operator ()(boost::log::v2s_mt_nt6::basic_formatting_ostream<char,std::char_traits<char>,std::allocator<char>> &,const boost::posix_time::ptime &) const':
cannot convert argument 1 from 'boost::log::v2s_mt_nt6::basic_formatting_ostream<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>' to 'boost::log::v2s_mt_nt6::basic_formatting_ostream<char,std::char_traits<char>,std::allocator<char>> &' sample.boost.asio e:\programming\c++\boost libraries\boost_1_66_0\boost\log\utility\functional\bind.hpp 93
Can anyone explain to me why this happened?
In Windows
boost::log::expressions::format_date_time<boost::posix_time::ptime,wchar_t>("TimeStamp",L"__%Y_%m_%d__")
In Unix
boost::log::expressions::format_date_time<boost::posix_time::ptime>("TimeStamp","__%Y_%m_%d__")
See text_multifile_backend.hpp
The essential is typedef filesystem::path result_type;
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I have written an application in c++ with OpenCV and boost and it is running well and correct, but before exiting it crashes (if I debug step by step, it crashes when return 0; at the end of main) saying:
in kdevelop:
*** Error in `/home/xxx/git_repos/my_proj/build/my_proj': free(): invalid pointer: 0x00000000008939c0 ***
*** Crashed with return code: 0 ***
in command line:
*** Error in `./my_proj': free(): invalid pointer: 0x00000000008939c0 ***
Aborted (core dumped)
if I use gdb:
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
*** Error in `/home/xxx/git_repos/my_proj/build/plate_info_extractor': free(): invalid pointer: 0x00000000008939c0 ***
Program received signal SIGABRT, Aborted.
0x00007ffff5b83cc9 in __GI_raise (sig=sig#entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56 ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
Any help please? I cannot figure out what is wrong.
I have commented some code parts and it seems that the problem is in the code that I use to log the errors/info... So:
#include "CLogger.hpp"
static void help(const std::string& appNameIn)
{
std::cerr << "Usage: " << appNameIn << " <option(s)> SOURCES" << std::endl
<< "Options:" << std::endl
<< " -h,--help Show this help message" << std::endl
<< " -c,--config CONFIG FILE Specify the name and path to the config file" << std::endl
<< std::endl
<< std::endl;
}
enum RetVals
{
NO_ERRORS,
NOT_ENOUGH_PARAMETERS,
UNKNOWN_OPTION,
SHOW_USAGE,
UNKNOWN_EXCEPTION,
OTHER_EXCEPTION,
};
int main(int argc, char **argv)
{
Logger::initFilesList();
Logger::initLogging();
BoostLogger lg = setClassNameAttribute("main");
if (argc == 3)
{
std::string opt = argv[1];
if (opt == "-c" || opt == "--config")
{
try
{
std::cout << "running" << std::endl;
}
catch (std::exception& e)
{
BOOST_LOG_SEV(lg, Logger::SeverityLevels::error) << "Other exception: " << e.what();
return OTHER_EXCEPTION;
}
catch (...)
{
BOOST_LOG_SEV(lg, Logger::SeverityLevels::error) << "Unkown exception ...";
return UNKNOWN_EXCEPTION;
}
}
else
{
help(argv[0]);
BOOST_LOG_SEV(lg, Logger::SeverityLevels::debug) << "The options are -c or --config, -h or --help";
return UNKNOWN_OPTION;
}
}
else if (argc == 2 && (std::string(argv[1]) == "-h" || std::string(argv[1]) == "--help"))
{
help(argv[0]);
BOOST_LOG_SEV(lg, Logger::SeverityLevels::debug) << "Call help function";
return SHOW_USAGE;
}
else
{
help(argv[0]);
BOOST_LOG_SEV(lg, Logger::SeverityLevels::debug) << "The number of input parameters is wrong";
return NOT_ENOUGH_PARAMETERS;
}
return NO_ERRORS;
}
and the CLogger.hpp:
#pragma once
#include <list>
#include <string>
#include <boost/log/common.hpp>
#include <boost/log/sinks/text_file_backend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/concept_check.hpp>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
class Logger
{
private:
static std::list< std::string > sm_logFilesList;
static const std::string sm_folderOfLogFiles;
/** the function adds the input log file to the list
*
* #param logFilePathIn : input log file path
*/
static void addNewLogFileToList(const std::string& logFilePathIn, bool sorting = false);
/** The function adds new logs to new log file and remove the oltest ones to have always 2 log files */
static void addNewRemoveOldLogs(bool sorting = false);
/** #returns : if the input path is valid or not */
static bool checkPath(const boost::filesystem::path& pathIn);
/** #returns if the file with the first input path was more recent accesed than the file with the second input path
*/
static bool compareAccessTime(const std::string& path1In, const std::string& path2In);
/** The function remove the old log files and keeps just the most recent two */
static void removeOldLogFiles();
/** The function is calles at the end of each file and removes the old files keeping just the last two */
static void openingHandler(boost::log::sinks::text_file_backend::stream_type& file);
public:
enum SeverityLevels
{
debug,
info,
warning,
error
};
/** The function sets the sm_logFilesList to contain the files if there are log files from earlier runs */
static void initFilesList();
/** The fuction is initializing the sinks and the formatter of the logger */
static void initLogging();
};
typedef boost::log::sources::severity_logger< Logger::SeverityLevels > BoostLogger;
/** the overloaded << operator of the BoostLogger */
std::ostream& operator<< (std::ostream& strm, Logger::SeverityLevels level);
/** The function sets the logger attribute ClassName to the specified string and returns the initialized logger
*
* #param classNameIn : input string name of the class
*
* #returns : initialized BoostLogger
*/
BoostLogger setClassNameAttribute(const std::string& classNameIn);
and the implementation:
#include "CLogger.hpp"
#include <boost/log/attributes.hpp>
#include <boost/log/attributes/current_process_id.hpp>
#include <boost/log/attributes/current_process_name.hpp>
#include <boost/log/core/core.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_file_backend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/utility/setup/file.hpp>
typedef boost::log::sinks::synchronous_sink< boost::log::sinks::text_file_backend > SinkTextFileBakend;
BOOST_LOG_ATTRIBUTE_KEYWORD(correlid, "CorrelationID", std::string)
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", Logger::SeverityLevels)
BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "TimeStamp", boost::posix_time::ptime)
BOOST_LOG_ATTRIBUTE_KEYWORD(threadid, "ThreadID", boost::log::attributes::current_thread_id)
BOOST_LOG_ATTRIBUTE_KEYWORD(classname, "ClassName", std::string)
std::list< std::string > Logger::sm_logFilesList;
const std::string Logger::sm_folderOfLogFiles = "../logs/";
std::ostream& operator<<(std::ostream& strm, Logger::SeverityLevels level)
{
static const char* strings[] =
{
"DEBUG",
"INFO",
"WARN",
"ERROR"
};
if (static_cast< std::size_t >(level) < sizeof(strings) / sizeof(*strings))
strm << strings[level];
else
strm << static_cast< int >(level);
return strm;
}
BoostLogger setClassNameAttribute(const std::string& classNameIn)
{
BoostLogger lg;
lg.add_attribute("ClassName", boost::log::attributes::constant<std::string>(classNameIn));
return lg;
}
void Logger::removeOldLogFiles()
{
while (sm_logFilesList.size() > 2)
{
std::string fileToDelete = sm_logFilesList.front();
if (fs::exists(fs::path(fileToDelete)))
{
fs::remove(fs::path(fileToDelete));
sm_logFilesList.pop_front();
}
}
}
bool Logger::compareAccessTime(const std::string& path1In, const std::string& path2In)
{
return (fs::last_write_time(fs::path(path1In)) < fs::last_write_time(fs::path(path2In)));
}
void Logger::addNewLogFileToList(const std::string& logFilePathIn, bool sorting)
{
if (std::find(sm_logFilesList.begin(), sm_logFilesList.end(), logFilePathIn) == sm_logFilesList.end())
{
sm_logFilesList.push_back(logFilePathIn);
if (sorting)
{
sm_logFilesList.sort(compareAccessTime);
}
removeOldLogFiles();
}
}
void Logger::addNewRemoveOldLogs(bool sorting)
{
fs::path path(sm_folderOfLogFiles);
fs::directory_iterator endDir;
if (checkPath(path))
{
for (fs::directory_iterator it(path); it != endDir; it++)
{
if (fs::is_regular_file(it->status()))
{
if (fs::extension(*it) == ".log")
{
std::string fileToPush = it->path().string();
addNewLogFileToList(fileToPush, sorting);
}
}
}
}
}
bool Logger::checkPath(const boost::filesystem::path& pathIn)
{
if (!fs::exists(pathIn))
{
return false;
}
if (!fs::is_directory(pathIn))
{
return false;
}
return true;
}
void Logger::openingHandler(boost::log::sinks::text_file_backend::stream_type& file)
{
addNewRemoveOldLogs();
}
void Logger::initFilesList()
{
addNewRemoveOldLogs(true);
}
void Logger::initLogging()
{
// Create a backend
boost::shared_ptr< SinkTextFileBakend > sink = boost::log::add_file_log(
sm_folderOfLogFiles + "plate_info_extractor_%Y-%m-%d_%H-%M-%S.%N.log",
boost::log::keywords::format = boost::log::expressions::stream
<< boost::log::expressions::attr< boost::log::attributes::current_process_name::value_type >("Executable") << "("
<< boost::log::expressions::attr< boost::log::attributes::current_process_id::value_type >("ExeUID") << ") CID("
<< correlid << ") " << severity << "["
<< boost::log::expressions::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S.%f")
<< "] [" << boost::log::expressions::attr< boost::log::attributes::current_thread_id::value_type >("ThreadID")
<< "] " << classname << " - " << boost::log::expressions::smessage,
boost::log::keywords::open_mode = (std::ios::out | std::ios::app),
boost::log::keywords::rotation_size = 2 * 1024 * 1024,
boost::log::keywords::auto_flush = true
);
sink->locked_backend()->set_open_handler(&openingHandler);
boost::log::core::get()->set_filter(severity >= SeverityLevels::info);
boost::log::core::get()->add_sink(sink);
#ifdef DEBUGGING
boost::shared_ptr< boost::log::sinks::text_ostream_backend > backend =
boost::make_shared< boost::log::sinks::text_ostream_backend >();
backend->add_stream(
boost::shared_ptr< std::ostream >(&std::cout));
// Enable auto-flushing after each log record written
backend->auto_flush(true);
// Wrap it into the frontend and register in the core.
// The backend requires synchronization in the frontend.
// for testing and printing log in sysout
boost::shared_ptr< boost::log::sinks::synchronous_sink< boost::log::sinks::text_ostream_backend > > backend_sink(
new boost::log::sinks::synchronous_sink< boost::log::sinks::text_ostream_backend >(backend));
backend_sink->set_formatter(
boost::log::expressions::stream
// line id will be written in hex, 8-digits, zero-filled
<< boost::log::expressions::attr< boost::log::attributes::current_process_name::value_type >("Executable")
<< "(" << boost::log::expressions::attr< boost::log::attributes::current_process_name::value_type >("ExeUID")
<< ") CID(" << correlid << ") " << severity << " ["
<< boost::log::expressions::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S.%f")
<< "] [" << boost::log::expressions::attr< boost::log::attributes::current_thread_id::value_type >("ThreadID")
<< "] " << classname << " - " << boost::log::expressions::smessage);
boost::log::core::get()->add_sink(backend_sink); // for testing and printing log in sysout
#endif
}
I hope that now there is enough information :)
This line:
backend->add_stream(boost::shared_ptr< std::ostream >(&std::cout));
looks pretty disastrous me. Your program will attempt to delete std::cout when exiting. I'm not familiar with Boost Log, so I don't know how to properly set up a sink for std::cout.
As Arpegius pointed out you should use the null_deleter to avoid deletion. Something along the lines of this:
backend->add_stream(boost::shared_ptr< std::ostream>(&std::cout, boost::null_deleter()));