#include <boost/lambda/lambda.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
+#include <boost/property_tree/ptree.hpp>
#include <tbb/atomic.h>
template<typename Stream, typename Val>
void write(Stream& out, const Val& value)
{
- std::string to_string = boost::lexical_cast<std::string>(value);
+ std::wstring to_string = boost::lexical_cast<std::wstring>(value);
int length = static_cast<int>(to_string.size());
int read_width;
static column_writer severity_column(7);
namespace expr = boost::log::expressions;
- append_timestamp(strm);
+ std::wstringstream pre_message_stream;
+ append_timestamp(pre_message_stream);
+ thread_id_column.write(pre_message_stream, boost::log::extract<boost::log::attributes::current_thread_id::value_type>("ThreadID", rec).get().native_id());
+ severity_column.write(pre_message_stream, boost::log::extract<boost::log::trivial::severity_level>("Severity", rec));
- thread_id_column.write(strm, boost::log::extract<boost::log::attributes::current_thread_id::value_type>("ThreadID", rec).get().native_id());
- severity_column.write(strm, boost::log::extract<boost::log::trivial::severity_level>("Severity", rec));
+ auto pre_message = pre_message_stream.str();
+
+ strm << pre_message;
+
+ auto line_break_replacement = L"\n" + pre_message;
if (print_all_characters)
{
- strm << rec[expr::message];
+ strm << boost::replace_all_copy(rec[expr::message].get<std::wstring>(), "\n", line_break_replacement);
}
else
{
- strm << replace_nonprintable_copy(rec[expr::message].get<std::wstring>(), L'?');
+ strm << boost::replace_all_copy(replace_nonprintable_copy(rec[expr::message].get<std::wstring>(), L'?'), L"\n", line_break_replacement);
}
}
try
{
if (!boost::filesystem::is_directory(folder))
- BOOST_THROW_EXCEPTION(directory_not_found());
+ CASPAR_THROW_EXCEPTION(directory_not_found());
auto file_sink = boost::make_shared<file_sink_type>(
boost::log::keywords::file_name = (folder + L"caspar_%Y-%m-%d.log"),
}
}
+std::shared_ptr<void> add_preformatted_line_sink(std::function<void(std::string line)> formatted_line_sink)
+{
+ class sink_backend : public boost::log::sinks::basic_formatted_sink_backend<char>
+ {
+ std::function<void(std::string line)> formatted_line_sink_;
+ public:
+ sink_backend(std::function<void(std::string line)> formatted_line_sink)
+ : formatted_line_sink_(std::move(formatted_line_sink))
+ {
+ }
+
+ void consume(const boost::log::record_view& rec, const std::string& formatted_message)
+ {
+ try
+ {
+ formatted_line_sink_(formatted_message);
+ }
+ catch (...)
+ {
+ std::cerr << "[sink_backend] Error while consuming formatted message: " << formatted_message << std::endl << std::endl;
+ }
+ }
+ };
+
+ typedef boost::log::sinks::synchronous_sink<sink_backend> sink_type;
+
+ auto sink = boost::make_shared<sink_type>(std::move(formatted_line_sink));
+ bool print_all_characters = true;
+
+ sink->set_formatter(boost::bind(&my_formatter<boost::log::formatting_ostream>, print_all_characters, _1, _2));
+
+ boost::log::core::get()->add_sink(sink);
+
+ return std::shared_ptr<void>(nullptr, [=](void*)
+ {
+ boost::log::core::get()->remove_sink(sink);
+ });
+}
+
void set_log_level(const std::wstring& lvl)
{
if (boost::iequals(lvl, L"trace"))
boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::fatal);
}
+void print_child(
+ boost::log::trivial::severity_level level,
+ const std::wstring& indent,
+ const std::wstring& elem,
+ const boost::property_tree::wptree& tree)
+{
+ auto& data = tree.data();
+
+ if (!data.empty())
+ BOOST_LOG_STREAM_WITH_PARAMS(log::logger::get(), (boost::log::keywords::severity = level)) << indent << elem << L" " << replace_nonprintable_copy(data, L'?');
+ else if (tree.size() == 0)
+ BOOST_LOG_STREAM_WITH_PARAMS(log::logger::get(), (boost::log::keywords::severity = level)) << indent << elem;
+
+ for (auto& child : tree)
+ print_child(level, indent + (elem.empty() ? L"" : elem + L"."), child.first, child.second);
+}
+
}}