#include "except.h"
#include "utf.h"
-#include "compiler/vs/stack_walker.h"
#include <ios>
#include <iomanip>
#include <boost/filesystem/convenience.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/algorithm/string.hpp>
-#include <boost/foreach.hpp>
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
+#include <boost/property_tree/ptree.hpp>
#include <tbb/atomic.h>
-#include <tbb/enumerable_thread_specific.h>
namespace caspar { namespace log {
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);
}
}
boost::log::core::get()->add_sink(stream_sink);
}
-std::wstring get_call_stack()
-{
- class log_call_stack_walker : public stack_walker
- {
- std::string str_;
- public:
- log_call_stack_walker() : stack_walker() {}
-
- std::string flush()
- {
- return std::move(str_);
- }
- protected:
- virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)
- {
- }
- virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion)
- {
- }
- virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)
- {
- }
- virtual void OnOutput(LPCSTR szText)
- {
- std::string str = szText;
-
- if(str.find("internal::get_call_stack") == std::string::npos && str.find("stack_walker::ShowCallstack") == std::string::npos)
- str_ += std::move(str);
- }
- };
-
- static tbb::enumerable_thread_specific<log_call_stack_walker> walkers;
- try
- {
- auto& walker = walkers.local();
- walker.ShowCallstack();
- return u16(walker.flush());
- }
- catch(...)
- {
- return L"!!!";
- }
-}
-
}
void add_file_sink(const std::wstring& folder)
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);
}
-}}
\ No newline at end of file
+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);
+}
+
+}}