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...