You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

703 lines
21 KiB

4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
  1. //
  2. // Created by zhaohe on 19-5-31.
  3. //
  4. #include "logger_factory.hpp"
  5. #include <sys/stat.h>
  6. #include <sys/types.h>
  7. #include <fstream>
  8. #include <iostream>
  9. #include <mutex>
  10. #include <thread>
  11. #include "default_logger_config.hpp"
  12. #include "nlohmann/json.hpp"
  13. #include "spdlog/sinks/basic_file_sink.h"
  14. #include "spdlog/sinks/daily_file_sink.h"
  15. #include "spdlog/sinks/rotating_file_sink.h"
  16. #include "spdlog/sinks/stdout_sinks.h"
  17. // #include "zwtimecpp/core/utils/compliler.h"
  18. using namespace std;
  19. using namespace iflytop;
  20. using namespace core;
  21. using namespace nlohmann;
  22. using namespace spdlog;
  23. const static char* kRootLogerName = "root";
  24. // const static char* kSpdDefaultConfigPaths[] = {"spd_logger_cfg.json"};
  25. const static char* kDefaultPattern = "[%C-%m-%d %H:%M:%S.%e] [%-30n] [%^%L%$] %v";
  26. // const static string kDefaultPattern = "";
  27. // const string WEAK spdLoggerConfig() { return ""; }
  28. // const static string kDefaultLoggerBeforeConfig = "DefaultLoggerBeforeConfig";
  29. // {
  30. // "name": "LoggerName",
  31. // "level": 2,
  32. // "type":"daily_logger_mt",
  33. // "filename":"fileName",
  34. // "hour":0,
  35. // "minute":0,
  36. // "truncate":false
  37. // }
  38. // {
  39. // "name": "LoggerName",
  40. // "level": 2,
  41. // "type":"rotating_logger_mt",
  42. // "filename":"fileName",
  43. // "max_file_size":1000,
  44. // "max_files":100,
  45. // "rotate_on_open":true
  46. // }
  47. // Rotate files:
  48. // log.txt -> log.1.txt
  49. // log.1.txt -> log.2.txt
  50. // log.2.txt -> log.3.txt
  51. // log.3.txt -> delete
  52. // 1. 没设置type,统统被当做logger处理
  53. // 2. 所有的logger,sink loggerAndSink,name都不能重复
  54. // 3.
  55. /**
  56. * @brief
  57. *loggerSupportList:
  58. *
  59. *-->: daily_logger_mt
  60. *-->: basic_logger_mt
  61. *-->: logger
  62. *-->: daily_file_sink_mt
  63. *-->: stderr_color_sink_mt
  64. *-->: stdout_color_sink_mt
  65. *
  66. * rotating_logger_mt
  67. * rotating_file_sink_mt
  68. *
  69. */
  70. #define ASSININ_VALUE(value) \
  71. if (config_item.key() == #value) item.at(#value).get_to(config.value);
  72. #if 0
  73. static bool c_daily_logger_mt(json j) {
  74. try {
  75. string type = j.at("type").get<string>();
  76. if (type == "daily_logger_mt") {
  77. GET(string, name);
  78. GET(string, filename);
  79. mkdirIfNotExist(filename);
  80. TRY_GET(int, hour, 0);
  81. TRY_GET(int, minute, 0);
  82. TRY_GET(bool, truncate, false);
  83. auto var_logger =
  84. spdlog::daily_logger_mt(name, filename, hour, minute, truncate);
  85. logger_common_config(var_logger, j);
  86. insertLogger(var_logger);
  87. return true;
  88. } else {
  89. return false;
  90. }
  91. } catch (const std::exception& e) {
  92. spdlog::critical("c_daily_logger_mt fail {} reason {}", j.dump(1),
  93. e.what());
  94. exit(-1);
  95. }
  96. };
  97. #endif
  98. #if 0
  99. static bool c_daily_file_sink_mt(json j) {
  100. try {
  101. string type = j.at("type").get<string>();
  102. if (type == "daily_file_sink_mt") {
  103. GET(string, name);
  104. GET(string, filename);
  105. mkdirIfNotExist(filename);
  106. TRY_GET(int, hour, 0);
  107. TRY_GET(int, minute, 0);
  108. TRY_GET(bool, truncate, false);
  109. auto sink = make_shared<sinks::daily_file_sink_mt>(filename, hour, minute,
  110. truncate);
  111. sink_common_config(sink, j);
  112. insertSink(name, sink);
  113. return true;
  114. } else {
  115. return false;
  116. }
  117. } catch (const std::exception& e) {
  118. spdlog::critical("c_daily_file_sink_mt fail {} reason {}", j.dump(1),
  119. e.what());
  120. exit(-1);
  121. }
  122. };
  123. #endif
  124. // 10485760 == 10M
  125. static string default_config = R"(
  126. [
  127. {
  128. "name": "info-sink",
  129. "type": "rotating_file_sink_mt",
  130. "filename": "logs/infolog.log",
  131. "max_file_size":10485760,
  132. "max_files": 3,
  133. "rotate_on_open": false,
  134. "level" : 2
  135. },
  136. {
  137. "name": "debug-sink",
  138. "type": "rotating_file_sink_mt",
  139. "filename": "logs/debuglog.log",
  140. "max_file_size":10485760,
  141. "max_files": 3,
  142. "rotate_on_open": false,
  143. "level": 0
  144. },
  145. {
  146. "name": "terminal-sink",
  147. "type": "stdout_color_sink_mt"
  148. },
  149. {
  150. "name": "root",
  151. "type": "logger",
  152. "level": 2,
  153. "sinks": [
  154. "terminal-sink",
  155. "debug-sink",
  156. "info-sink"
  157. ]
  158. }
  159. ]
  160. )";
  161. #define LOGGER_ENABLE_BEGIN(_name) \
  162. static bool c_##_name(json j) { \
  163. logger_t var_logger; \
  164. try { \
  165. string type = j.at("type").get<string>(); \
  166. if (type == #_name) { \
  167. GET(string, name);
  168. #define LOGGER_ENABLE_END(name) \
  169. logger_common_config(var_logger, j); \
  170. insertLogger(var_logger); \
  171. return true; \
  172. } \
  173. else { \
  174. return false; \
  175. } \
  176. } \
  177. catch (const std::exception& e) { \
  178. spdlog::critical("c_{} fail {} reason {}", #name, j.dump(1), e.what()); \
  179. exit(-1); \
  180. } \
  181. } \
  182. ;
  183. #define SINK_DEFINE_BEGIN(var_name) \
  184. static bool c_##var_name(json j) { \
  185. sink_ptr sink; \
  186. try { \
  187. string type = j.at("type").get<string>(); \
  188. if (type == #var_name) { \
  189. GET(string, name);
  190. #define SINK_DEFINE_END(var_name) \
  191. sink_common_config(sink, j); \
  192. insertSink(name, sink); \
  193. return true; \
  194. } \
  195. else { \
  196. return false; \
  197. } \
  198. } \
  199. catch (const std::exception& e) { \
  200. spdlog::critical("c_" #var_name " fail {} reason {}", j.dump(1), e.what()); \
  201. exit(-1); \
  202. } \
  203. } \
  204. ;
  205. template <class type>
  206. type tryGet(json j, string value_name, type defaultValue) {
  207. try {
  208. if (j.find(value_name) == j.end()) {
  209. return defaultValue;
  210. }
  211. type value = j.at(value_name).get<type>();
  212. return value;
  213. } catch (const std::exception& e) {
  214. return defaultValue;
  215. }
  216. }
  217. static bool exist(const string& path) {
  218. struct stat statInfo;
  219. if (stat(path.c_str(), &statInfo) == 0) {
  220. return true;
  221. }
  222. return false;
  223. }
  224. static bool mkdirIfNotExist(const string& path) {
  225. string::size_type sepPos = path.find_last_of("/");
  226. if (sepPos == string::npos) {
  227. return false;
  228. }
  229. string dirPath = path.substr(0, sepPos);
  230. if (exist(dirPath)) {
  231. return true;
  232. }
  233. int ret = mkdir(dirPath.c_str(), S_IRWXU | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
  234. return 0 == ret ? true : false;
  235. }
  236. class LoggerAndSinks {
  237. public:
  238. string loggerName;
  239. set<string> sinkNames;
  240. };
  241. /****************************************************************************************************/
  242. static map<string, sink_ptr> s_sinks = {};
  243. static map<string, shared_ptr<logger>> s_loggers = {};
  244. static set<shared_ptr<LoggerAndSinks>> s_loggerAndSinks = {};
  245. static void insertLogger(shared_ptr<logger> var_logger) {
  246. if (s_loggers.find(var_logger->name()) == s_loggers.end()) {
  247. s_loggers[var_logger->name()] = var_logger;
  248. } else {
  249. spdlog::critical("Add the logger {} fail", var_logger->name());
  250. exit(-1);
  251. }
  252. };
  253. static void insertSink(string name, sink_ptr sink) {
  254. if (s_sinks.find(name) == s_sinks.end()) {
  255. s_sinks[name] = sink;
  256. } else {
  257. spdlog::critical("Add the sink {} fail", name);
  258. exit(-1);
  259. }
  260. };
  261. static level::level_enum to_level(int value) {
  262. switch (value) {
  263. case SPDLOG_LEVEL_TRACE:
  264. return level::trace;
  265. case SPDLOG_LEVEL_DEBUG:
  266. return level::debug;
  267. case SPDLOG_LEVEL_INFO:
  268. return level::info;
  269. case SPDLOG_LEVEL_WARN:
  270. return level::warn;
  271. case SPDLOG_LEVEL_ERROR:
  272. return level::err;
  273. case SPDLOG_LEVEL_CRITICAL:
  274. return level::critical;
  275. default:
  276. spdlog::critical("level is out of range {} level must in [{},{}]", value, SPDLOG_LEVEL_TRACE, SPDLOG_LEVEL_CRITICAL);
  277. exit(-1);
  278. break;
  279. }
  280. return level::info;
  281. }
  282. // #define GET(type,value,error_msg,...)
  283. #define TRY_GET(type, value_name, default_value) type value_name = tryGet<type>(j, #value_name, default_value)
  284. #define GET(T, value_name) T value_name = j.at(#value_name).get<T>();
  285. static void logger_common_config(logger_t var_logger, json j) {
  286. TRY_GET(int, level, 2);
  287. TRY_GET(string, pattern, kDefaultPattern);
  288. TRY_GET(set<string>, sinks, {});
  289. var_logger->set_level(to_level(level));
  290. if (!sinks.empty()) {
  291. shared_ptr<LoggerAndSinks> las(new LoggerAndSinks());
  292. las->loggerName = var_logger->name();
  293. las->sinkNames = sinks;
  294. s_loggerAndSinks.insert(las);
  295. }
  296. }
  297. static void sink_common_config(sink_ptr sink, json j) {
  298. TRY_GET(int, level, 0);
  299. TRY_GET(string, pattern, kDefaultPattern);
  300. TRY_GET(set<string>, sinks, {});
  301. sink->set_level(to_level(level));
  302. if (!pattern.empty()) sink->set_pattern(pattern);
  303. }
  304. /**
  305. * logger-----------------------------------------------------------------------------------------------------
  306. */
  307. LOGGER_ENABLE_BEGIN(daily_logger_mt) {
  308. GET(string, filename);
  309. mkdirIfNotExist(filename);
  310. TRY_GET(int, hour, 0);
  311. TRY_GET(int, minute, 0);
  312. TRY_GET(bool, truncate, false);
  313. TRY_GET(int, max_files, 100);
  314. var_logger = spdlog::daily_logger_mt(name, filename, hour, minute, truncate, max_files);
  315. }
  316. LOGGER_ENABLE_END(daily_logger_mt)
  317. LOGGER_ENABLE_BEGIN(rotating_logger_mt) {
  318. GET(string, filename);
  319. mkdirIfNotExist(filename);
  320. TRY_GET(int, max_file_size, 10 * 1024 * 1024);
  321. TRY_GET(int, max_files, 3);
  322. TRY_GET(bool, rotate_on_open, true);
  323. var_logger = spdlog::rotating_logger_mt(name, filename, max_file_size, max_files, rotate_on_open);
  324. }
  325. LOGGER_ENABLE_END(rotating_logger_mt)
  326. LOGGER_ENABLE_BEGIN(basic_logger_mt) {
  327. GET(string, filename);
  328. mkdirIfNotExist(filename);
  329. var_logger = spdlog::basic_logger_mt(name, filename);
  330. }
  331. LOGGER_ENABLE_END(basic_logger_mt)
  332. static bool c_logger(json j) {
  333. try {
  334. string type = j.at("type").get<string>();
  335. if (type == "logger") {
  336. GET(string, name);
  337. GET(set<string>, sinks);
  338. auto var_logger = make_shared<logger>(name, sinks_init_list{});
  339. if (sinks.empty()) {
  340. spdlog::critical("c_logger fail {} reason {}", j.dump(1), "Not set sink");
  341. exit(-1);
  342. }
  343. logger_common_config(var_logger, j);
  344. insertLogger(var_logger);
  345. return true;
  346. } else {
  347. return false;
  348. }
  349. } catch (const std::exception& e) {
  350. spdlog::critical("c_logger fail {} reason {}", j.dump(1), e.what());
  351. exit(-1);
  352. }
  353. };
  354. /**
  355. * sinks-----------------------------------------------------------------------------------------------------
  356. */
  357. SINK_DEFINE_BEGIN(daily_file_sink_mt) {
  358. GET(string, filename);
  359. mkdirIfNotExist(filename);
  360. TRY_GET(int, hour, 0);
  361. TRY_GET(int, minute, 0);
  362. TRY_GET(bool, truncate, false);
  363. TRY_GET(int, max_files, 100);
  364. // printf("filename:%s,max_files %d\n", filename.c_str(), max_files);
  365. sink = make_shared<sinks::daily_file_sink_mt>(filename, hour, minute, truncate, max_files);
  366. }
  367. SINK_DEFINE_END(daily_file_sink_mt)
  368. SINK_DEFINE_BEGIN(rotating_file_sink_mt) {
  369. GET(string, filename);
  370. mkdirIfNotExist(filename);
  371. TRY_GET(int, max_file_size, 10 * 1024 * 1024);
  372. TRY_GET(int, max_files, 5);
  373. TRY_GET(bool, rotate_on_open, true);
  374. sink = make_shared<sinks::rotating_file_sink_mt>(filename, max_file_size, max_files, rotate_on_open);
  375. }
  376. SINK_DEFINE_END(rotating_file_sink_mt)
  377. SINK_DEFINE_BEGIN(stdout_color_sink_mt) { sink = make_shared<sinks::stdout_color_sink_mt>(); }
  378. SINK_DEFINE_END(stdout_color_sink_mt)
  379. SINK_DEFINE_BEGIN(stderr_color_sink_mt) { sink = make_shared<sinks::stderr_color_sink_mt>(); }
  380. SINK_DEFINE_END(stderr_color_sink_mt)
  381. /**
  382. * default_root_logger-----------------------------------------------------------------------------------------------------
  383. */
  384. static logger_t createRootLogger() {
  385. if (!get(kRootLogerName)) {
  386. auto rootLogger = spdlog::stdout_color_mt(kRootLogerName);
  387. if (!string(kDefaultPattern).empty()) {
  388. rootLogger->set_pattern(kDefaultPattern);
  389. }
  390. return rootLogger;
  391. }
  392. // auto stdoutsink = make_shared<sinks::stderr_color_sink_mt>();
  393. // stdoutsink->set_level(level::debug);
  394. // if (!kDefaultPattern.empty()) {
  395. // stdoutsink->set_pattern(kDefaultPattern);
  396. // }
  397. // auto rootLogger =
  398. // make_shared<logger>(kRootLogerName, sinks_init_list{stdoutsink});
  399. // rootLogger->set_level(level::info);
  400. // rootLogger->set_pattern(kDefaultPattern);
  401. return get(kRootLogerName);
  402. }
  403. /**
  404. * @brief
  405. */
  406. /**
  407. * @brief 使 daily_logger_mt时候会自动注册logger, 使make_shared<logger>
  408. * logger
  409. * @param var_logger
  410. */
  411. static void myRegLogger(logger_t var_logger) {
  412. if (var_logger->name() == kRootLogerName) {
  413. spdlog::set_default_logger(var_logger);
  414. }
  415. if (!get(var_logger->name())) {
  416. register_logger(var_logger);
  417. }
  418. if (!get(var_logger->name())) {
  419. spdlog::critical("reg root logger fail {}");
  420. exit(-1);
  421. }
  422. }
  423. static void __parseSphLogConfig(json var) {
  424. if (c_daily_logger_mt(var)) {
  425. } else if (c_rotating_logger_mt(var)) {
  426. } else if (c_basic_logger_mt(var)) {
  427. } else if (c_daily_file_sink_mt(var)) {
  428. } else if (c_logger(var)) {
  429. } else if (c_stderr_color_sink_mt(var)) {
  430. } else if (c_stdout_color_sink_mt(var)) {
  431. } else if (c_rotating_file_sink_mt(var)) {
  432. } else {
  433. spdlog::critical("no such type {}", var.dump());
  434. exit(-1);
  435. }
  436. }
  437. static logger_t createLoggerWithoutType(json j) {
  438. TRY_GET(int, level, 2);
  439. GET(string, name);
  440. TRY_GET(string, pattern, kDefaultPattern);
  441. auto rootLogger = get(kRootLogerName);
  442. if (!rootLogger) {
  443. spdlog::critical("func: createLoggerWithoutType,can't find rootLogger");
  444. exit(-1);
  445. }
  446. auto newLogger = rootLogger->clone(name);
  447. newLogger->set_level(to_level(level));
  448. if (!pattern.empty()) newLogger->set_pattern(pattern);
  449. return newLogger;
  450. }
  451. /**
  452. * @brief
  453. *
  454. * logger思路
  455. * 1. type了的logger和sink
  456. * 2. logger和对应的sink
  457. * 3. rootLogger,rootLogger
  458. * 4. type的logger,rootLogger,level
  459. * @param path
  460. */
  461. void core::SpdLoggerFactory::parseSphLogConfig(string path) {
  462. try {
  463. // 这里必须清空,因为这个方法可能在main函数之前启动,所以数量可能未初始化
  464. s_sinks.clear();
  465. s_loggers.clear();
  466. s_loggerAndSinks.clear();
  467. fstream infile(path, ios::binary | ios::in);
  468. stringstream sstream;
  469. sstream << infile.rdbuf();
  470. infile.close();
  471. string jsonStr(sstream.str());
  472. sstream.clear();
  473. json configjson = json::parse(jsonStr);
  474. for (auto& j : configjson) {
  475. TRY_GET(string, type, "");
  476. if (!type.empty()) {
  477. __parseSphLogConfig(j);
  478. }
  479. }
  480. // 组装logger and sink
  481. for (auto& las : s_loggerAndSinks) {
  482. logger_t logger = s_loggers[las->loggerName];
  483. if (logger == nullptr) {
  484. spdlog::critical("can't find logger", las->loggerName);
  485. exit(-1);
  486. }
  487. set<sink_ptr> sinks;
  488. for (auto& sinkname : las->sinkNames) {
  489. auto result = s_sinks.find(sinkname);
  490. if (result == s_sinks.end()) {
  491. spdlog::critical("can't find sink {} ??", sinkname);
  492. exit(-1);
  493. }
  494. sinks.insert(result->second);
  495. }
  496. for (auto& sink : sinks) logger->sinks().push_back(sink);
  497. }
  498. for (auto& var : s_loggers) myRegLogger(var.second);
  499. // 如果没有rootLogger,构造rootLogger
  500. if (!get(kRootLogerName)) {
  501. for (auto& j : configjson) {
  502. GET(string, name);
  503. TRY_GET(string, type, "");
  504. if (name == kRootLogerName) {
  505. if (type.empty()) {
  506. TRY_GET(int, level, 2);
  507. TRY_GET(string, pattern, kDefaultPattern);
  508. auto rootLogger = createRootLogger();
  509. rootLogger->set_level(to_level(level));
  510. if (!pattern.empty()) rootLogger->set_pattern(pattern);
  511. myRegLogger(rootLogger);
  512. } else {
  513. spdlog::critical("shouldn't go here");
  514. exit(-1);
  515. }
  516. break;
  517. }
  518. }
  519. }
  520. // 如果依然没有构造rootLogger则构造默认logger
  521. if (!get(kRootLogerName)) myRegLogger(createRootLogger());
  522. // 构造没有type的logger
  523. for (auto& j : configjson) {
  524. TRY_GET(string, type, "");
  525. GET(string, name);
  526. if (type.empty() && name != kRootLogerName) {
  527. auto newlogger = createLoggerWithoutType(j);
  528. myRegLogger(newlogger);
  529. }
  530. }
  531. // spdlog::info("Logger initialize ok");
  532. } catch (const exception& e) {
  533. spdlog::critical("parse logger config fail {}", e.what());
  534. exit(-1);
  535. }
  536. }
  537. static string getConfigFilePath() {
  538. if (spdLoggerConfig) {
  539. if (exist(spdLoggerConfig())) {
  540. return spdLoggerConfig();
  541. } else {
  542. spdlog::warn("can't find spdLoggerConfig file {},use deafult config", spdLoggerConfig());
  543. }
  544. }
  545. return "spd_logger_cfg.json";
  546. }
  547. class MonitoringSpdLoggerConfigTask {
  548. unique_ptr<thread> wthread;
  549. public:
  550. MonitoringSpdLoggerConfigTask() {
  551. wthread.reset(new thread([]() {
  552. }));
  553. }
  554. ~MonitoringSpdLoggerConfigTask() { wthread->join(); }
  555. };
  556. void SpdLoggerFactory::initialize() {
  557. if (!initializeLogger) {
  558. string configFilePath = getConfigFilePath();
  559. if (!configFilePath.empty() && exist(configFilePath)) {
  560. parseSphLogConfig(configFilePath);
  561. } else {
  562. spdlog::warn("can't find logger config file use default config {}", configFilePath);
  563. // 写字符串default_config到文件中configFilePath
  564. ofstream outfile(configFilePath);
  565. outfile << default_config;
  566. outfile.close();
  567. parseSphLogConfig(configFilePath);
  568. }
  569. initializeLogger = true;
  570. }
  571. }
  572. shared_ptr<logger> SpdLoggerFactory::createLogger(string loggerName) {
  573. lock_guard<mutex> lock_gu(createLogger_lock);
  574. if (!loggerName.empty()) {
  575. if (s_loggerNames.size() == 0) {
  576. s_loggerNames.insert(loggerName);
  577. } else {
  578. if (s_loggerNames.find(loggerName) == s_loggerNames.end()) {
  579. s_loggerNames.insert(loggerName);
  580. }
  581. }
  582. }
  583. // TODO:当使用gtest进行单元测试的时候,logger似乎会被清空,原因未知
  584. if (!get(kRootLogerName)) {
  585. initializeLogger = false;
  586. if (!string(kDefaultPattern).empty()) {
  587. spdlog::set_pattern(kDefaultPattern);
  588. }
  589. }
  590. if (!initializeLogger) {
  591. string configFilePath = getConfigFilePath();
  592. if (!configFilePath.empty() && exist(configFilePath)) {
  593. parseSphLogConfig(configFilePath);
  594. } else {
  595. spdlog::warn("can't find logger config file use default config {}", configFilePath);
  596. // 写字符串default_config到文件中configFilePath
  597. ofstream outfile(configFilePath);
  598. outfile << default_config;
  599. outfile.close();
  600. parseSphLogConfig(configFilePath);
  601. }
  602. initializeLogger = true;
  603. }
  604. logger_t ret_logger = get(loggerName);
  605. if (ret_logger) {
  606. return ret_logger;
  607. } else {
  608. logger_t rootLogger = get(kRootLogerName);
  609. if (!rootLogger) {
  610. spdlog::critical("can't find root logger ?????");
  611. exit(-1);
  612. }
  613. logger_t newLogger = rootLogger->clone(loggerName);
  614. myRegLogger(newLogger);
  615. newLogger->flush_on(spdlog::level::debug);
  616. return newLogger;
  617. }
  618. return nullptr;
  619. }
  620. set<string> SpdLoggerFactory::loggerNames() { return s_loggerNames; }
  621. sink_ptr SpdLoggerFactory::getSink(string name) {
  622. auto result = s_sinks.find(name);
  623. if (result == s_sinks.end()) {
  624. return nullptr;
  625. }
  626. return result->second;
  627. }
  628. shared_ptr<logger> SpdLoggerFactory::createRotatingFileLogger(const std::string& logger_name, size_t max_file_size, size_t max_files, bool bindTerminal,
  629. bool bindDebug, bool bindInfo) {
  630. auto newlogger = spdlog::rotating_logger_mt(logger_name, fmt::format("logs/{}.log", logger_name), 5 * 1024 * 1024 /*5M*/, 3 /*times*/);
  631. newlogger->set_level(spdlog::level::info);
  632. if (bindTerminal && GET_SINK("terminal-sink")) newlogger->sinks().push_back(GET_SINK("terminal-sink"));
  633. if (bindDebug && GET_SINK("debug-sink")) newlogger->sinks().push_back(GET_SINK("debug-sink"));
  634. if (bindInfo && GET_SINK("info-sink")) newlogger->sinks().push_back(GET_SINK("info-sink"));
  635. myRegLogger(newlogger);
  636. return newlogger;
  637. }