14 #include <condition_variable>
19 #if (XTD_LOG_TARGET_CSV | XTD_LOG_TARGET_XML)
23 #if XTD_LOG_TARGET_SYSLOG
27 #if XTD_LOG_TARGET_COUT
39 #define FATAL(...) xtd::log::get().write(xtd::log::type::fatal, here(), __VA_ARGS__)
40 #define ERR(...) xtd::log::get().write(xtd::log::type::error, here(), __VA_ARGS__)
41 #define WARNING(...) xtd::log::get().write(xtd::log::type::warning, here(), __VA_ARGS__)
42 #define INFO(...) xtd::log::get().write(xtd::log::type::info, here(), __VA_ARGS__)
43 #define DBG(...) xtd::log::get().write(xtd::log::type::debug, here(), __VA_ARGS__)
59 static const char * type_string(type oType){
61 case xtd::log::type::fatal:
63 case xtd::log::type::error:
65 case xtd::log::type::warning:
67 case xtd::log::type::info:
69 case xtd::log::type::debug:
71 case xtd::log::type::enter:
73 case xtd::log::type::leave:
84 using pointer_type = std::shared_ptr<message>;
85 using deque_type = std::deque<pointer_type>;
86 using time_type = std::chrono::time_point<std::chrono::system_clock>;
89 : _tid(std::this_thread::get_id()), _type(msg_type), _location(location), _text(std::move(text)), _time(std::chrono::system_clock::now()){}
90 message(
const message& src)
91 :_tid(src._tid), _type(src._type), _location(src._location), _text(src._text), _time(src._time){}
92 message& operator=(
const message& src){
98 _location = src._location;
104 std::thread::id _tid;
113 virtual ~log_target() =
default;
114 using pointer_type = std::shared_ptr<log_target>;
115 using vector_type = std::vector<pointer_type>;
116 virtual void operator()(
const message::pointer_type&) = 0;
119 #if (XTD_LOG_TARGET_SYSLOG)
120 class syslog_target :
public log_target{
123 syslog_target(){ openlog(
nullptr, LOG_PID | LOG_NDELAY, 0); }
124 ~syslog_target()
override { closelog(); }
125 void operator()(
const message::pointer_type& oMessage)
override {
126 int iFacility = LOG_MAKEPRI(LOG_USER, LOG_DEBUG);
127 switch (oMessage->_type){
130 iFacility = LOG_MAKEPRI(LOG_USER, LOG_CRIT);
135 iFacility = LOG_MAKEPRI(LOG_USER, LOG_ERR);
140 iFacility = LOG_MAKEPRI(LOG_USER, LOG_WARNING);
145 iFacility = LOG_MAKEPRI(LOG_USER, LOG_INFO);
152 iFacility = LOG_MAKEPRI(LOG_USER, LOG_DEBUG);
156 syslog(iFacility,
"%s", oMessage->_text.c_str());
161 #if (XTD_LOG_TARGET_WINDBG)
162 class win_dbg_target :
public log_target{
164 ~win_dbg_target()
override =
default;
165 void operator()(
const message::pointer_type& oMessage)
override {
166 OutputDebugStringA(oMessage->_text.c_str());
172 #if (XTD_LOG_TARGET_COUT)
173 class std_cout_target :
public log_target{
175 ~std_cout_target()
override =
default;
176 void operator()(
const message::pointer_type& oMessage)
override{
177 std::cout << oMessage->_text << std::endl;
182 #if (XTD_LOG_TARGET_CSV)
183 class csv_target :
public log_target{
184 std::ofstream _LogFile;
185 std::mutex _FileLock;
190 void operator()(
const message::pointer_type& oMsg)
override{
191 static thread_local
size_t _StackDepth = 1;
192 if (type::leave == oMsg->_type) --_StackDepth;
193 std::string sMsgPrefix(_StackDepth,
',');
194 std::hash<std::thread::id> oHash;
195 auto sMsg =
xtd::string::format(oHash(oMsg->_tid),
",", oMsg->_time.time_since_epoch().count(),
",", type_string(oMsg->_type),
",", oMsg->_location.file(),
",", oMsg->_location.line(), sMsgPrefix, oMsg->_text);
196 if (type::enter == oMsg->_type) ++_StackDepth;
197 std::unique_lock<std::mutex> oLock(_FileLock);
198 _LogFile << sMsg << std::endl;
201 csv_target() : _LogFile(), _FileLock(){
202 auto oLogPath = xtd::filesystem::home_directory_path();
203 oLogPath /= xtd::executable::this_executable().path().filename();
205 oLogPath.append(
".csv");
206 _LogFile.open(oLogPath.string(), std::ios::out);
211 void callback_thread(){
212 _CallbackThreadStarted.set_value();
213 while ( !_CallbackThreadExit ){
214 callback_type oCallback;
216 std::unique_lock<std::mutex> oLock(_CallbackLock);
217 _CallbackCheck.wait(oLock, [
this]{
218 return _Callbacks.size();
220 oCallback = _Callbacks.front();
221 _Callbacks.pop_front();
223 _CallbackCheck.notify_one();
229 _CallbackThreadFinished.set_value();
232 log() : _Messages(), _Callbacks(), _CallbackThread(), _CallbackLock(), _CallbackCheck(), _LogTargets(){
234 #if (XTD_LOG_TARGET_SYSLOG)
235 _LogTargets.emplace_back(
new syslog_target);
238 #if (XTD_LOG_TARGET_WINDBG)
239 _LogTargets.emplace_back(
new win_dbg_target);
242 #if (XTD_LOG_TARGET_COUT)
243 _LogTargets.emplace_back(
new std_cout_target);
246 #if (XTD_LOG_TARGET_CSV)
247 _LogTargets.emplace_back(
new csv_target);
250 _CallbackThread = std::thread(&log::callback_thread,
this);
251 _CallbackThreadStarted.get_future().get();
256 std::lock_guard<std::mutex> oLock(_CallbackLock);
257 _Callbacks.push_back([
this](){
258 _CallbackThreadExit =
true;
260 _CallbackCheck.notify_one();
262 _CallbackThread.join();
263 _CallbackThreadFinished.get_future().get();
266 using callback_type = std::function<void()>;
267 using callback_deque = std::deque<callback_type>;
269 message::deque_type _Messages;
270 callback_deque _Callbacks;
271 std::thread _CallbackThread;
272 std::mutex _CallbackLock;
273 std::condition_variable _CallbackCheck;
274 log_target::vector_type _LogTargets;
275 std::promise<void> _CallbackThreadStarted;
276 std::promise<void> _CallbackThreadFinished;
277 bool _CallbackThreadExit =
false;
286 template <
typename ... _ArgTs>
287 inline void write(type mesageType,
const source_location& location, _ArgTs&&...oArgs){
289 if (
'\n' != sMessage.back()){
292 auto oMessage = std::make_shared<message>(mesageType, location, std::move(sMessage));
294 std::lock_guard<std::mutex> oLock(_CallbackLock);
295 _Callbacks.push_back([oMessage,
this](){
296 for (
auto oTarget : _LogTargets){
297 (*oTarget)(oMessage);
301 _CallbackCheck.notify_one();
represents an executable binary on disk or memory
constexpr processor_intrinsic< _Ty >::type intrinsic_cast(_Ty src)
casts a pointer to the processor intrinsic storage type
specializations of std::basic_string for advanced and common string handling
host, target and build configurations and settings Various components are purpose built for specific ...
maintains info about locations within source code
handle necessary filesystem and path functionality until C++17 is finalized
represents an in-memory process
static xstring format()
Type safe formatting Appends each item in the parameter list together performing type-safe verificati...
Contains information about the location of source code Used in error reporting and logging...