logger.cpp 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. //
  2. // Logger.cpp
  3. // DanmakuRPG
  4. //
  5. // Created by Sam Jaffe on 7/18/15.
  6. // Copyright (c) 2015 Sam Jaffe. All rights reserved.
  7. //
  8. #ifdef _WIN32
  9. #include <Windows.h>
  10. #endif
  11. #include <cassert>
  12. #include <cmath>
  13. #include <ctime>
  14. #include <map>
  15. #include <stdexcept>
  16. #include "logger.hpp"
  17. #include "properties.hpp"
  18. namespace logging {
  19. #define X(l) \
  20. case logging::L##l: \
  21. return #l;
  22. const char* level_header(log_level l) {
  23. assert(l != logging::LNONE);
  24. switch (l) {
  25. X(FATAL)
  26. X(CRITICAL)
  27. X(ERROR)
  28. X(WARNING)
  29. X(INFO)
  30. X(DEBUG)
  31. X(TRACE)
  32. X(NONE)
  33. }
  34. }
  35. #undef X
  36. std::string timestamp() {
  37. time_t round = std::time(NULL);
  38. struct tm time = *std::localtime(&round);
  39. char buf[32];
  40. snprintf(buf, sizeof(buf), "%0.4d-%0.2d-%0.2d %0.2d:%0.2d:%0.2d.%0.3d ",
  41. 1900 + time.tm_year, time.tm_mon + 1, time.tm_mday,
  42. time.tm_hour, time.tm_min, time.tm_sec,
  43. static_cast<int>(round % 1000));
  44. return buf;
  45. }
  46. }
  47. namespace logging {
  48. class multiple_bindings : public std::logic_error {
  49. using std::logic_error::logic_error;
  50. };
  51. // extern logger_impl& _logger_impl_shared_instance();
  52. extern _binding _default_logger_impl;
  53. static _binding _impl_binding = nullptr;
  54. bool bind_logger_impl(_binding impl) {
  55. assert(_impl_binding == nullptr);
  56. if (_impl_binding != nullptr) {
  57. throw multiple_bindings{"Only one logger implementation may be bound"};
  58. }
  59. _impl_binding = impl;
  60. return true;
  61. }
  62. logger_impl& _get_shared_instance() {
  63. if (_impl_binding == nullptr) {
  64. return _default_logger_impl();
  65. } else {
  66. return _impl_binding();
  67. }
  68. }
  69. }
  70. namespace logging {
  71. logger& logger::instance() {
  72. static logger instance;
  73. return instance;
  74. }
  75. logger& logger::instance(const char* name) {
  76. static std::map<const char*, std::unique_ptr<logger>> instances;
  77. std::map<const char*, std::unique_ptr<logger>>::iterator it;
  78. if ((it = instances.find(name)) != instances.end()) {
  79. return *(it->second);
  80. }
  81. return *(instances.emplace(std::make_pair(name, std::unique_ptr<logger>(new logger(name)))).first->second);
  82. }
  83. logger::logger(const char* name)
  84. : min_level_(LDEBUG)
  85. , logger_name_(name)
  86. , impl_(_get_shared_instance())
  87. {
  88. }
  89. logger::~logger() {
  90. flush();
  91. }
  92. std::string logger::get_header(log_level level) {
  93. std::string ts = timestamp();
  94. char data[64];
  95. snprintf(data, sizeof(data), "[%-5s] %s %s - ", level_header(level), logger_name_, ts.c_str());
  96. return data;
  97. }
  98. void logger::vlognf(log_level level, size_t num_bytes, char const* fmt, va_list args) {
  99. if (level < min_level_) return;
  100. const std::unique_ptr<char[]> data(new char[num_bytes]);
  101. int n = vsnprintf(data.get(), num_bytes, fmt, args);
  102. if (n >= 0) {
  103. data[num_bytes-1] = '\0';
  104. log(level, get_header(level) + data.get());
  105. }
  106. }
  107. void logger::log(log_level level, std::string const& msg) {
  108. impl_.write(level, msg);
  109. }
  110. void logger::flush() {
  111. impl_.flush();
  112. }
  113. }