Environment.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. /***************************************************************************
  2. *
  3. * Project _____ __ ____ _ _
  4. * ( _ ) /__\ (_ _)_| |_ _| |_
  5. * )(_)( /(__)\ )( (_ _)(_ _)
  6. * (_____)(__)(__)(__) |_| |_|
  7. *
  8. *
  9. * Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
  10. * Benedikt-Alexander Mokroß <oatpp@bamkrs.de>
  11. *
  12. * Licensed under the Apache License, Version 2.0 (the "License");
  13. * you may not use this file except in compliance with the License.
  14. * You may obtain a copy of the License at
  15. *
  16. * http://www.apache.org/licenses/LICENSE-2.0
  17. *
  18. * Unless required by applicable law or agreed to in writing, software
  19. * distributed under the License is distributed on an "AS IS" BASIS,
  20. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  21. * See the License for the specific language governing permissions and
  22. * limitations under the License.
  23. *
  24. ***************************************************************************/
  25. #include "Environment.hpp"
  26. #include <iomanip>
  27. #include <chrono>
  28. #include <iostream>
  29. #include <cstring>
  30. #include <ctime>
  31. #include <cstdarg>
  32. #if defined(WIN32) || defined(_WIN32)
  33. #include <winsock2.h>
  34. struct tm* localtime_r(time_t *_clock, struct tm *_result) {
  35. localtime_s(_result, _clock);
  36. return _result;
  37. }
  38. #endif
  39. namespace oatpp { namespace base {
  40. v_atomicCounter Environment::m_objectsCount(0);
  41. v_atomicCounter Environment::m_objectsCreated(0);
  42. #ifndef OATPP_COMPAT_BUILD_NO_THREAD_LOCAL
  43. thread_local v_counter Environment::m_threadLocalObjectsCount = 0;
  44. thread_local v_counter Environment::m_threadLocalObjectsCreated = 0;
  45. #endif
  46. std::mutex& Environment::getComponentsMutex() {
  47. static std::mutex componentsMutex;
  48. return componentsMutex;
  49. }
  50. std::unordered_map<std::string, std::unordered_map<std::string, void*>>& Environment::getComponents() {
  51. static std::unordered_map<std::string, std::unordered_map<std::string, void*>> components;
  52. return components;
  53. }
  54. std::shared_ptr<Logger> Environment::m_logger;
  55. DefaultLogger::DefaultLogger(const Config& config)
  56. : m_config(config)
  57. {}
  58. void DefaultLogger::log(v_uint32 priority, const std::string& tag, const std::string& message) {
  59. bool indent = false;
  60. auto time = std::chrono::system_clock::now().time_since_epoch();
  61. std::lock_guard<std::mutex> lock(m_lock);
  62. switch (priority) {
  63. case PRIORITY_V:
  64. std::cout << "\033[0m V \033[0m|";
  65. break;
  66. case PRIORITY_D:
  67. std::cout << "\033[34m D \033[0m|";
  68. break;
  69. case PRIORITY_I:
  70. std::cout << "\033[32m I \033[0m|";
  71. break;
  72. case PRIORITY_W:
  73. std::cout << "\033[45m W \033[0m|";
  74. break;
  75. case PRIORITY_E:
  76. std::cout << "\033[41m E \033[0m|";
  77. break;
  78. default:
  79. std::cout << " " << priority << " |";
  80. }
  81. if (m_config.timeFormat) {
  82. time_t seconds = std::chrono::duration_cast<std::chrono::seconds>(time).count();
  83. struct tm now;
  84. localtime_r(&seconds, &now);
  85. #ifdef OATPP_DISABLE_STD_PUT_TIME
  86. char timeBuffer[50];
  87. strftime(timeBuffer, sizeof(timeBuffer), m_config.timeFormat, &now);
  88. std::cout << timeBuffer;
  89. #else
  90. std::cout << std::put_time(&now, m_config.timeFormat);
  91. #endif
  92. indent = true;
  93. }
  94. if (m_config.printTicks) {
  95. auto ticks = std::chrono::duration_cast<std::chrono::microseconds>(time).count();
  96. if(indent) {
  97. std::cout << " ";
  98. }
  99. std::cout << ticks;
  100. indent = true;
  101. }
  102. if (indent) {
  103. std::cout << "|";
  104. }
  105. if (message.empty()) {
  106. std::cout << " " << tag << std::endl;
  107. } else {
  108. std::cout << " " << tag << ":" << message << std::endl;
  109. }
  110. }
  111. void DefaultLogger::enablePriority(v_uint32 priority) {
  112. if (priority > PRIORITY_E) {
  113. return;
  114. }
  115. m_config.logMask |= (1 << priority);
  116. }
  117. void DefaultLogger::disablePriority(v_uint32 priority) {
  118. if (priority > PRIORITY_E) {
  119. return;
  120. }
  121. m_config.logMask &= ~(1 << priority);
  122. }
  123. bool DefaultLogger::isLogPriorityEnabled(v_uint32 priority) {
  124. if (priority > PRIORITY_E) {
  125. return true;
  126. }
  127. return m_config.logMask & (1 << priority);
  128. }
  129. void LogCategory::enablePriority(v_uint32 priority) {
  130. if (priority > Logger::PRIORITY_E) {
  131. return;
  132. }
  133. enabledPriorities |= (1 << priority);
  134. }
  135. void LogCategory::disablePriority(v_uint32 priority) {
  136. if (priority > Logger::PRIORITY_E) {
  137. return;
  138. }
  139. enabledPriorities &= ~(1 << priority);
  140. }
  141. bool LogCategory::isLogPriorityEnabled(v_uint32 priority) {
  142. if (priority > Logger::PRIORITY_E) {
  143. return true;
  144. }
  145. return enabledPriorities & (1 << priority);
  146. }
  147. void Environment::init() {
  148. init(std::make_shared<DefaultLogger>());
  149. }
  150. void Environment::init(const std::shared_ptr<Logger>& logger) {
  151. m_logger = logger;
  152. #if defined(WIN32) || defined(_WIN32)
  153. // Initialize Winsock
  154. WSADATA wsaData;
  155. int iResult;
  156. iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
  157. if (iResult != 0) {
  158. throw std::runtime_error("[oatpp::base::Environment::init()]: Error. WSAStartup failed");
  159. }
  160. #endif
  161. checkTypes();
  162. m_objectsCount = 0;
  163. m_objectsCreated = 0;
  164. #ifndef OATPP_COMPAT_BUILD_NO_THREAD_LOCAL
  165. m_threadLocalObjectsCount = 0;
  166. m_threadLocalObjectsCreated = 0;
  167. #endif
  168. {
  169. std::lock_guard<std::mutex> lock(getComponentsMutex());
  170. if (getComponents().size() > 0) {
  171. throw std::runtime_error("[oatpp::base::Environment::init()]: Error. "
  172. "Invalid state. Components were created before call to Environment::init()");
  173. }
  174. }
  175. }
  176. void Environment::destroy(){
  177. if(getComponents().size() > 0) {
  178. std::lock_guard<std::mutex> lock(getComponentsMutex());
  179. throw std::runtime_error("[oatpp::base::Environment::destroy()]: Error. "
  180. "Invalid state. Leaking components");
  181. }
  182. m_logger.reset();
  183. #if defined(WIN32) || defined(_WIN32)
  184. WSACleanup();
  185. #endif
  186. }
  187. void Environment::checkTypes(){
  188. static_assert(sizeof(v_char8) == 1, "");
  189. static_assert(sizeof(v_int16) == 2, "");
  190. static_assert(sizeof(v_uint16) == 2, "");
  191. static_assert(sizeof(v_int32) == 4, "");
  192. static_assert(sizeof(v_int64) == 8, "");
  193. static_assert(sizeof(v_uint32) == 4, "");
  194. static_assert(sizeof(v_uint64) == 8, "");
  195. static_assert(sizeof(v_float64) == 8, "");
  196. v_int32 vInt32 = ~v_int32(1);
  197. v_int64 vInt64 = ~v_int64(1);
  198. v_uint32 vUInt32 = ~v_uint32(1);
  199. v_uint64 vUInt64 = ~v_uint64(1);
  200. OATPP_ASSERT(vInt32 < 0);
  201. OATPP_ASSERT(vInt64 < 0);
  202. OATPP_ASSERT(vUInt32 > 0);
  203. OATPP_ASSERT(vUInt64 > 0);
  204. }
  205. void Environment::incObjects(){
  206. m_objectsCount ++;
  207. m_objectsCreated ++;
  208. #ifndef OATPP_COMPAT_BUILD_NO_THREAD_LOCAL
  209. m_threadLocalObjectsCount ++;
  210. m_threadLocalObjectsCreated ++;
  211. #endif
  212. }
  213. void Environment::decObjects(){
  214. m_objectsCount --;
  215. #ifndef OATPP_COMPAT_BUILD_NO_THREAD_LOCAL
  216. m_threadLocalObjectsCount --;
  217. #endif
  218. }
  219. v_counter Environment::getObjectsCount(){
  220. return m_objectsCount;
  221. }
  222. v_counter Environment::getObjectsCreated(){
  223. return m_objectsCreated;
  224. }
  225. v_counter Environment::getThreadLocalObjectsCount(){
  226. #ifndef OATPP_COMPAT_BUILD_NO_THREAD_LOCAL
  227. return m_threadLocalObjectsCount;
  228. #else
  229. return 0;
  230. #endif
  231. }
  232. v_counter Environment::getThreadLocalObjectsCreated(){
  233. #ifndef OATPP_COMPAT_BUILD_NO_THREAD_LOCAL
  234. return m_threadLocalObjectsCreated;
  235. #else
  236. return 0;
  237. #endif
  238. }
  239. void Environment::setLogger(const std::shared_ptr<Logger>& logger){
  240. m_logger = logger;
  241. }
  242. std::shared_ptr<Logger> Environment::getLogger() {
  243. return m_logger;
  244. }
  245. void Environment::printCompilationConfig() {
  246. OATPP_LOGD("oatpp-version", OATPP_VERSION);
  247. #ifdef OATPP_DISABLE_ENV_OBJECT_COUNTERS
  248. OATPP_LOGD("oatpp/Config", "OATPP_DISABLE_ENV_OBJECT_COUNTERS");
  249. #endif
  250. #ifdef OATPP_COMPAT_BUILD_NO_THREAD_LOCAL
  251. OATPP_LOGD("oatpp/Config", "OATPP_COMPAT_BUILD_NO_THREAD_LOCAL");
  252. #endif
  253. #ifdef OATPP_THREAD_HARDWARE_CONCURRENCY
  254. OATPP_LOGD("oatpp/Config", "OATPP_THREAD_HARDWARE_CONCURRENCY=%d", OATPP_THREAD_HARDWARE_CONCURRENCY);
  255. #endif
  256. }
  257. void Environment::log(v_uint32 priority, const std::string& tag, const std::string& message) {
  258. if(m_logger != nullptr) {
  259. m_logger->log(priority, tag, message);
  260. }
  261. }
  262. void Environment::logFormatted(v_uint32 priority, const LogCategory& category, const char* message, ...) {
  263. if (category.categoryEnabled && (category.enabledPriorities & (1 << priority))) {
  264. va_list args;
  265. va_start(args, message);
  266. vlogFormatted(priority, category.tag, message, args);
  267. va_end(args);
  268. }
  269. }
  270. void Environment::logFormatted(v_uint32 priority, const std::string& tag, const char* message, ...) {
  271. va_list args;
  272. va_start(args, message);
  273. vlogFormatted(priority, tag, message, args);
  274. va_end(args);
  275. }
  276. void Environment::vlogFormatted(v_uint32 priority, const std::string& tag, const char* message, va_list args) {
  277. // do we have a logger and the priority is enabled?
  278. if (m_logger == nullptr || !m_logger->isLogPriorityEnabled(priority)) {
  279. return;
  280. }
  281. // if we dont need to format anything, just print the message
  282. if(message == nullptr) {
  283. log(priority, tag, std::string());
  284. return;
  285. }
  286. // check how big our buffer has to be
  287. va_list argscpy;
  288. va_copy(argscpy, args);
  289. v_buff_size allocsize = vsnprintf(nullptr, 0, message, argscpy) + 1;
  290. // alloc the buffer (or the max size)
  291. if (allocsize > m_logger->getMaxFormattingBufferSize()) {
  292. allocsize = m_logger->getMaxFormattingBufferSize();
  293. }
  294. auto buffer = std::unique_ptr<char[]>(new char[allocsize]);
  295. memset(buffer.get(), 0, allocsize);
  296. // actually format
  297. vsnprintf(buffer.get(), allocsize, message, args);
  298. // call (user) providen log function
  299. log(priority, tag, buffer.get());
  300. }
  301. void Environment::registerComponent(const std::string& typeName, const std::string& componentName, void* component) {
  302. std::lock_guard<std::mutex> lock(getComponentsMutex());
  303. auto& bucket = getComponents()[typeName];
  304. auto it = bucket.find(componentName);
  305. if(it != bucket.end()){
  306. throw std::runtime_error("[oatpp::base::Environment::registerComponent()]: Error. Component with given name already exists: name='" + componentName + "'");
  307. }
  308. bucket[componentName] = component;
  309. }
  310. void Environment::unregisterComponent(const std::string& typeName, const std::string& componentName) {
  311. std::lock_guard<std::mutex> lock(getComponentsMutex());
  312. auto& components = getComponents();
  313. auto bucketIt = getComponents().find(typeName);
  314. if(bucketIt == components.end() || bucketIt->second.size() == 0) {
  315. throw std::runtime_error("[oatpp::base::Environment::unregisterComponent()]: Error. Component of given type doesn't exist: type='" + typeName + "'");
  316. }
  317. auto& bucket = bucketIt->second;
  318. auto componentIt = bucket.find(componentName);
  319. if(componentIt == bucket.end()) {
  320. throw std::runtime_error("[oatpp::base::Environment::unregisterComponent()]: Error. Component with given name doesn't exist: name='" + componentName + "'");
  321. }
  322. bucket.erase(componentIt);
  323. if(bucket.size() == 0) {
  324. components.erase(bucketIt);
  325. }
  326. }
  327. void* Environment::getComponent(const std::string& typeName) {
  328. std::lock_guard<std::mutex> lock(getComponentsMutex());
  329. auto& components = getComponents();
  330. auto bucketIt = components.find(typeName);
  331. if(bucketIt == components.end() || bucketIt->second.size() == 0) {
  332. throw std::runtime_error("[oatpp::base::Environment::getComponent()]: Error. Component of given type doesn't exist: type='" + typeName + "'");
  333. }
  334. auto bucket = bucketIt->second;
  335. if(bucket.size() > 1){
  336. throw std::runtime_error("[oatpp::base::Environment::getComponent()]: Error. Ambiguous component reference. Multiple components exist for a given type: type='" + typeName + "'");
  337. }
  338. return bucket.begin()->second;
  339. }
  340. void* Environment::getComponent(const std::string& typeName, const std::string& componentName) {
  341. std::lock_guard<std::mutex> lock(getComponentsMutex());
  342. auto& components = getComponents();
  343. auto bucketIt = components.find(typeName);
  344. if(bucketIt == components.end() || bucketIt->second.size() == 0) {
  345. throw std::runtime_error("[oatpp::base::Environment::getComponent()]: Error. Component of given type doesn't exist: type='" + typeName + "'");
  346. }
  347. auto bucket = bucketIt->second;
  348. auto componentIt = bucket.find(componentName);
  349. if(componentIt == bucket.end()) {
  350. throw std::runtime_error("[oatpp::base::Environment::getComponent()]: Error. Component with given name doesn't exist: name='" + componentName + "'");
  351. }
  352. return componentIt->second;
  353. }
  354. v_int64 Environment::getMicroTickCount(){
  355. std::chrono::microseconds ms = std::chrono::duration_cast<std::chrono::microseconds>
  356. (std::chrono::system_clock::now().time_since_epoch());
  357. return ms.count();
  358. }
  359. }}