2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
4 * This file is part of CasparCG (www.casparcg.com).
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
19 * Author: Robert Nagy, ronag89@gmail.com
25 #pragma warning (disable : 4100) // 'identifier' : unreferenced formal parameter
26 #pragma warning (disable : 4512) // 'class' : assignment operator could not be generated
33 #include "compiler/vs/stack_walker.h"
39 #include <boost/bind.hpp>
40 #include <boost/shared_ptr.hpp>
41 #include <boost/make_shared.hpp>
42 #include <boost/filesystem/convenience.hpp>
43 #include <boost/date_time/posix_time/posix_time.hpp>
44 #include <boost/algorithm/string.hpp>
46 #include <boost/log/core/core.hpp>
48 #include <boost/log/formatters/stream.hpp>
49 #include <boost/log/formatters/attr.hpp>
50 #include <boost/log/formatters/date_time.hpp>
51 #include <boost/log/formatters/message.hpp>
53 #include <boost/log/filters/attr.hpp>
55 #include <boost/log/sinks/text_file_backend.hpp>
57 #include <boost/log/detail/universal_path.hpp>
59 #include <boost/log/sinks/text_file_backend.hpp>
60 #include <boost/log/sinks/text_ostream_backend.hpp>
61 #include <boost/log/sinks/sync_frontend.hpp>
62 #include <boost/log/sinks/async_frontend.hpp>
63 #include <boost/log/core/record.hpp>
64 #include <boost/log/utility/attribute_value_extractor.hpp>
66 #include <boost/log/utility/init/common_attributes.hpp>
67 #include <boost/log/utility/empty_deleter.hpp>
68 #include <boost/lambda/lambda.hpp>
70 #include <tbb/enumerable_thread_specific.h>
72 namespace caspar { namespace log {
74 using namespace boost;
76 void my_formatter(bool print_all_characters, std::wostream& strm, boost::log::basic_record<wchar_t> const& rec)
78 namespace lambda = boost::lambda;
80 #pragma warning(disable : 4996)
84 timeinfo = localtime ( &rawtime );
86 strftime (buffer,80, "%c", timeinfo);
87 strm << L"[" << buffer << L"] ";
89 boost::log::attributes::current_thread_id::held_type thread_id;
90 if(boost::log::extract<boost::log::attributes::current_thread_id::held_type>(L"ThreadID", rec.attribute_values(), lambda::var(thread_id) = lambda::_1))
91 strm << L"[" << thread_id << L"] ";
93 severity_level severity;
94 if(boost::log::extract<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get(), rec.attribute_values(), lambda::var(severity) = lambda::_1))
98 strm << L"[" << severity << L"] ";
99 for(int n = 0; n < 7-static_cast<int>(ss.str().size()); ++n)
103 if (print_all_characters)
105 strm << rec.message();
109 strm << replace_nonprintable_copy(rec.message(), L'?');
117 boost::log::add_common_attributes<wchar_t>();
118 typedef boost::log::aux::add_common_attributes_constants<wchar_t> traits_t;
120 typedef boost::log::sinks::synchronous_sink<boost::log::sinks::wtext_file_backend> file_sink_type;
122 typedef boost::log::sinks::asynchronous_sink<boost::log::sinks::wtext_ostream_backend> stream_sink_type;
124 auto stream_backend = boost::make_shared<boost::log::sinks::wtext_ostream_backend>();
125 stream_backend->add_stream(boost::shared_ptr<std::wostream>(&std::wcout, boost::log::empty_deleter()));
126 stream_backend->auto_flush(true);
128 auto stream_sink = boost::make_shared<stream_sink_type>(stream_backend);
131 // stream_sink->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= debug);
133 // stream_sink->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= debug);
136 stream_sink->locked_backend()->set_formatter(boost::bind(my_formatter, false, _1, _2));
138 boost::log::wcore::get()->add_sink(stream_sink);
141 std::wstring get_call_stack()
143 class log_call_stack_walker : public stack_walker
147 log_call_stack_walker() : stack_walker() {}
151 return std::move(str_);
154 virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)
157 virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion)
160 virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)
163 virtual void OnOutput(LPCSTR szText)
165 std::string str = szText;
167 if(str.find("internal::get_call_stack") == std::string::npos && str.find("stack_walker::ShowCallstack") == std::string::npos)
168 str_ += std::move(str);
172 static tbb::enumerable_thread_specific<log_call_stack_walker> walkers;
175 auto& walker = walkers.local();
176 walker.ShowCallstack();
177 return u16(walker.flush());
187 void add_file_sink(const std::wstring& folder)
189 boost::log::add_common_attributes<wchar_t>();
190 typedef boost::log::aux::add_common_attributes_constants<wchar_t> traits_t;
192 typedef boost::log::sinks::synchronous_sink<boost::log::sinks::wtext_file_backend> file_sink_type;
196 if(!boost::filesystem::is_directory(folder))
197 CASPAR_THROW_EXCEPTION(directory_not_found());
199 auto file_sink = boost::make_shared<file_sink_type>(
200 boost::log::keywords::file_name = (folder + L"caspar_%Y-%m-%d.log"),
201 boost::log::keywords::time_based_rotation = boost::log::sinks::file::rotation_at_time_point(0, 0, 0),
202 boost::log::keywords::auto_flush = true,
203 boost::log::keywords::open_mode = std::ios::app
206 file_sink->locked_backend()->set_formatter(boost::bind(my_formatter, true, _1, _2));
209 // file_sink->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= debug);
211 // file_sink->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= debug);
213 boost::log::wcore::get()->add_sink(file_sink);
217 std::wcerr << L"Failed to Setup File Logging Sink" << std::endl << std::endl;
221 void set_log_level(const std::wstring& lvl)
223 if(boost::iequals(lvl, L"trace"))
224 boost::log::wcore::get()->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= trace);
225 else if(boost::iequals(lvl, L"debug"))
226 boost::log::wcore::get()->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= debug);
227 else if(boost::iequals(lvl, L"info"))
228 boost::log::wcore::get()->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= info);
229 else if(boost::iequals(lvl, L"warning"))
230 boost::log::wcore::get()->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= warning);
231 else if(boost::iequals(lvl, L"error"))
232 boost::log::wcore::get()->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= error);
233 else if(boost::iequals(lvl, L"fatal"))
234 boost::log::wcore::get()->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= fatal);