Advertisement
Guest User

logger by thread

a guest
Dec 5th, 2017
188
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.06 KB | None | 0 0
  1.      1  #include <iostream>
  2.      2  #include <cstdint>
  3.      3  #include <thread>
  4.      4  #include <mutex>
  5.      5  #include <fstream>
  6.      6  #include <string>
  7.      7  #include <sstream>
  8.      8  #include <chrono>
  9.      9  #include <map>
  10.     10  #include <iomanip>
  11.     11  #include <ctime>
  12.     12  #include <functional>
  13.     13 
  14.     14  ///
  15.     15  /// \brief The logger struct
  16.     16  ///
  17.     17  struct logger {
  18.     18      enum level : int16_t { debug = 0, info = 1, warn = 2, error = 3, fatal = 4 };
  19.     19 
  20.     20      ~logger() {
  21.     21          write_all();
  22.     22      }
  23.     23 
  24.     24      logger & operator()(level p_level) {
  25.     25          add(true)
  26.     26                  << "[" << get_level(p_level) << "]"
  27.     27                  << "[" << std::time(NULL) << "]"
  28.     28                  << "[" << std::this_thread::get_id() << "] ";
  29.     29          return *this;
  30.     30      }
  31.     31 
  32.     32      template <typename T>
  33.     33      logger & operator << (const T & p_val) {
  34.     34          add() << p_val;
  35.     35          return *this;
  36.     36      }
  37.     37  private:
  38.     38 
  39.     39      struct at_thread_end {
  40.     40        at_thread_end (std::function<void (std::thread::id)> p_callback
  41.     41                       , std::thread::id p_id)
  42.     42            : m_callback(p_callback)
  43.     43            , m_id(p_id){}
  44.     44 
  45.     45        at_thread_end(at_thread_end && p_at_thread_end)
  46.     46            : m_callback(std::move(p_at_thread_end.m_callback))
  47.     47            , m_id(std::move(p_at_thread_end.m_id)) {}
  48.     48 
  49.     49        at_thread_end & operator=(at_thread_end && p_at_thread_end) {
  50.     50            m_callback = std::move(p_at_thread_end.m_callback);
  51.     51            m_id = std::move(p_at_thread_end.m_id);
  52.     52            return *this;
  53.     53        }
  54.     54 
  55.     55        ~at_thread_end() {
  56.     56            m_callback(m_id);
  57.     57        }
  58.     58 
  59.     59      private:
  60.     60        std::function<void (std::thread::id)> m_callback;
  61.     61        std::thread::id m_id;
  62.     62      };
  63.     63 
  64.     64      typedef std::map<std::thread::id, std::stringstream> streams;
  65.     65 
  66.     66      void on_thread_end(std::thread::id p_id) {
  67.     67          std::cout << "thread " << p_id << " ended" << std::endl;
  68.     68          streams::iterator _ite = m_streams.find(p_id);
  69.     69          if (_ite != m_streams.end()) {
  70.     70              write(_ite->second.str());
  71.     71              std::lock_guard<std::mutex> _lock(m_mutex_streams);
  72.     72              m_streams.erase(_ite);
  73.     73          }
  74.     74      }
  75.     75 
  76.     76      std::stringstream & add(bool p_clean = false) {
  77.     77          std::thread::id _id  = std::this_thread::get_id();
  78.     78          streams::iterator _ite = m_streams.find(_id);
  79.     79          if (_ite != m_streams.end()) {
  80.     80              if (p_clean) {
  81.     81                  write(_ite->second.str());
  82.     82                  _ite->second.str("");
  83.     83              }
  84.     84              return _ite->second;
  85.     85          }
  86.     86 
  87.     87 
  88.     88          using std::placeholders::_1;
  89.     89          thread_local at_thread_end
  90.     90                  _at_thread_end(std::bind(&logger::on_thread_end, this, _1)
  91.     91                                 ,_id);
  92.     92 
  93.     93          std::lock_guard<std::mutex> _lock(m_mutex_streams);
  94.     94          m_streams[_id] = std::stringstream();
  95.     95          return m_streams[_id];
  96.     96      }
  97.     97 
  98.     98      std::string get_level(level p_level) {
  99.     99          switch (p_level) {
  100.    100          case level::debug:
  101.    101              return "DEB";
  102.    102          case level::info:
  103.    103              return "INF";
  104.    104          case level::warn:
  105.    105              return "WAR";
  106.    106          case level::error:
  107.    107              return "ERR";
  108.    108          case level::fatal:
  109.    109              return "FAT";
  110.    110          }
  111.    111          return "LEVEL UNKNOW";
  112.    112      }
  113.    113 
  114.    114      void write(const std::string & p_str) {
  115.    115          std::lock_guard<std::mutex> _lock(m_mutex_write);
  116.    116          if (p_str.size()) {
  117.    117              std::cout << p_str << std::endl;
  118.    118          }
  119.    119      }
  120.    120 
  121.    121      void write_all() {
  122.    122          std::lock_guard<std::mutex> _lock(m_mutex_streams);
  123.    123          streams::iterator _end = m_streams.end();
  124.    124          for (streams::iterator _ite = m_streams.begin(); _ite != _end; ++_ite) {
  125.    125              write(_ite->second.str());
  126.    126          }
  127.    127      }
  128.    128 
  129.    129      streams m_streams;
  130.    130      std::mutex m_mutex_streams;
  131.    131      std::mutex m_mutex_write;
  132.    132 
  133.    133  };
  134.    134 
  135.    135 
  136.    136  ///
  137.    137  /// \brief The tester struct
  138.    138  ///
  139.    139  struct tester {
  140.    140 
  141.    141      tester(uint16_t p_id, uint16_t p_max
  142.    142              , std::chrono::milliseconds p_pause
  143.    143              , logger * p_logger)
  144.    144          : m_id(p_id)
  145.    145          , m_max(p_max)
  146.    146          , m_pause(p_pause)
  147.    147          , m_logger(p_logger) {}
  148.    148 
  149.    149      void operator()() {
  150.    150          for (uint16_t _i = 0;_i < m_max; ++_i) {
  151.    151              (*m_logger)(logger::level::debug) << "id = " << std::setfill('0')
  152.    152                                                << std::setw(2) << m_id
  153.    153                                                << ", i = " << std::setw(4) << _i << ", "
  154.    154                                                << "hello 0, " << "hello 1, "
  155.    155                                                << "a sentence, "
  156.    156                                                << "hello 2, " << "hello 3, "
  157.    157                                                << "a longer sentence, "
  158.    158                                                << "hello 4, " << "hello 5, "
  159.    159                                                << "a even longer sentence, "
  160.    160                                                << "hello 6, " << "hello 7, "
  161.    161                                                << "a quite very long sentence, "
  162.    162                                                << "hello 8, " << "hello 9";
  163.    163              std::this_thread::sleep_for(m_pause);
  164.    164          }
  165.    165      }
  166.    166 
  167.    167  private:
  168.    168      uint16_t m_id;
  169.    169      uint16_t m_max;
  170.    170      std::chrono::milliseconds m_pause;
  171.    171      logger * m_logger;
  172.    172  };
  173.    173 
  174.    174  int main() {
  175.    175 
  176.    176      logger _logger;
  177.    177      tester _p1(1, 15000, std::chrono::milliseconds(90), &_logger);
  178.    178      tester _p2(2, 16000, std::chrono::milliseconds(80), &_logger);
  179.    179      tester _p3(3, 17000, std::chrono::milliseconds(70), &_logger);
  180.    180      tester _p4(4, 18000, std::chrono::milliseconds(60), &_logger);
  181.    181      tester _p5(5, 19000, std::chrono::milliseconds(50), &_logger);
  182.    182 
  183.    183      std::thread _t1(std::ref(_p1));
  184.    184      std::thread _t2(std::ref(_p2));
  185.    185      std::thread _t3(std::ref(_p3));
  186.    186      std::thread _t4(std::ref(_p4));
  187.    187      std::thread _t5(std::ref(_p5));
  188.    188 
  189.    189      _t1.join();
  190.    190      _t2.join();
  191.    191      _t3.join();
  192.    192      _t4.join();
  193.    193      _t5.join();
  194.    194  }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement