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

log_adapter.cc 15 kB

5 years ago
6 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. /**
  2. * Copyright 2019 Huawei Technologies Co., Ltd
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "utils/log_adapter.h"
  17. #include <unistd.h>
  18. #include <map>
  19. #include "debug/trace.h"
  20. // namespace to support utils module definition
  21. namespace mindspore {
  22. #ifdef USE_GLOG
  23. static std::string GetTime() {
  24. #define BUFLEN 80
  25. static char buf[BUFLEN];
  26. #if defined(_WIN32) || defined(_WIN64)
  27. time_t time_seconds = time(0);
  28. struct tm now_time;
  29. localtime_s(&now_time, &time_seconds);
  30. sprintf_s(buf, BUFLEN, "%d-%d-%d %d:%d:%d", now_time.tm_year + 1900, now_time.tm_mon + 1, now_time.tm_mday,
  31. now_time.tm_hour, now_time.tm_min, now_time.tm_sec);
  32. #else
  33. struct timeval cur_time;
  34. (void)gettimeofday(&cur_time, nullptr);
  35. struct tm now;
  36. (void)localtime_r(&cur_time.tv_sec, &now);
  37. (void)strftime(buf, BUFLEN, "%Y-%m-%d-%H:%M:%S", &now); // format date and time
  38. // set micro-second
  39. buf[27] = '\0';
  40. int idx = 26;
  41. auto num = cur_time.tv_usec;
  42. for (int i = 5; i >= 0; i--) {
  43. buf[idx--] = static_cast<char>(num % 10 + '0');
  44. num /= 10;
  45. if (i % 3 == 0) {
  46. buf[idx--] = '.';
  47. }
  48. }
  49. #endif
  50. return std::string(buf);
  51. }
  52. static std::string GetProcName() {
  53. #if defined(__APPLE__) || defined(__FreeBSD__)
  54. const char *appname = getprogname();
  55. #elif defined(_GNU_SOURCE)
  56. const char *appname = program_invocation_name;
  57. #else
  58. const char *appname = "?";
  59. #endif
  60. // some times, the appname is an absolute path, its too long
  61. std::string app_name(appname);
  62. std::size_t pos = app_name.rfind("/");
  63. if (pos == std::string::npos) {
  64. return app_name;
  65. }
  66. if (pos + 1 >= app_name.size()) {
  67. return app_name;
  68. }
  69. return app_name.substr(pos + 1);
  70. }
  71. static std::string GetLogLevel(MsLogLevel level) {
  72. #define _TO_STRING(x) #x
  73. static const char *const level_names[] = {
  74. _TO_STRING(DEBUG),
  75. _TO_STRING(INFO),
  76. _TO_STRING(WARNING),
  77. _TO_STRING(ERROR),
  78. };
  79. #undef _TO_STRING
  80. if (level > ERROR) {
  81. level = ERROR;
  82. }
  83. return std::string(level_names[level]);
  84. }
  85. // convert MsLogLevel to corresponding glog level
  86. static int GetGlogLevel(MsLogLevel level) {
  87. switch (level) {
  88. case DEBUG:
  89. case INFO:
  90. return google::GLOG_INFO;
  91. case WARNING:
  92. return google::GLOG_WARNING;
  93. case ERROR:
  94. default:
  95. return google::GLOG_ERROR;
  96. }
  97. }
  98. #else
  99. #undef Dlog
  100. #define Dlog(module_id, level, format, ...) \
  101. do { \
  102. DlogInner((module_id), (level), (format), ##__VA_ARGS__); \
  103. } while (0)
  104. // convert MsLogLevel to corresponding slog level
  105. static int GetSlogLevel(MsLogLevel level) {
  106. switch (level) {
  107. case DEBUG:
  108. return DLOG_DEBUG;
  109. case INFO:
  110. return DLOG_INFO;
  111. case WARNING:
  112. return DLOG_WARN;
  113. case ERROR:
  114. default:
  115. return DLOG_ERROR;
  116. }
  117. }
  118. #endif
  119. static std::string ExceptionTypeToString(ExceptionType type) {
  120. #define _TO_STRING(x) #x
  121. // clang-format off
  122. static const char *const type_names[] = {
  123. _TO_STRING(NoExceptionType),
  124. _TO_STRING(UnknownError),
  125. _TO_STRING(ArgumentError),
  126. _TO_STRING(NotSupportError),
  127. _TO_STRING(NotExistsError),
  128. _TO_STRING(AlreadyExistsError),
  129. _TO_STRING(UnavailableError),
  130. _TO_STRING(DeviceProcessError),
  131. _TO_STRING(AbortedError),
  132. _TO_STRING(TimeOutError),
  133. _TO_STRING(ResourceUnavailable),
  134. _TO_STRING(NoPermissionError),
  135. _TO_STRING(IndexError),
  136. _TO_STRING(ValueError),
  137. _TO_STRING(TypeError),
  138. };
  139. // clang-format on
  140. #undef _TO_STRING
  141. if (type < UnknownError || type > TypeError) {
  142. type = UnknownError;
  143. }
  144. return std::string(type_names[type]);
  145. }
  146. static const char *GetSubModuleName(SubModuleId module_id) {
  147. static const char *sub_module_names[NUM_SUBMODUES] = {
  148. "UNKNOWN", // SM_UNKNOWN
  149. "ANALYZER", // SM_ANALYZER
  150. "COMMON", // SM_COMMON
  151. "DEBUG", // SM_DEBUG
  152. "DEVICE", // SM_DEVICE
  153. "GE_ADPT", // SM_GE_ADPT
  154. "IR", // SM_IR
  155. "KERNEL", // SM_KERNEL
  156. "MD", // SM_MD
  157. "ME", // SM_ME
  158. "ONNX", // SM_ONNX
  159. "OPTIMIZER", // SM_OPTIMIZER
  160. "PARALLEL", // SM_PARALLEL
  161. "PARSER", // SM_PARSER
  162. "PIPELINE", // SM_PIPELINE
  163. "PRE_ACT", // SM_PRE_ACT
  164. "PYNATIVE", // SM_PYNATIVE
  165. "SESSION", // SM_SESSION
  166. "UTILS", // SM_UTILS
  167. "VM" // SM_VM
  168. };
  169. return sub_module_names[module_id % NUM_SUBMODUES];
  170. }
  171. void LogWriter::OutputLog(const std::ostringstream &msg) const {
  172. #ifdef USE_GLOG
  173. auto submodule_name = GetSubModuleName(submodule_);
  174. google::LogMessage("", 0, GetGlogLevel(log_level_)).stream()
  175. << "[" << GetLogLevel(log_level_) << "] " << submodule_name << "(" << getpid() << "," << GetProcName()
  176. << "):" << GetTime() << " "
  177. << "[" << location_.file_ << ":" << location_.line_ << "] " << location_.func_ << "] " << msg.str() << std::endl;
  178. #else
  179. auto str_msg = msg.str();
  180. auto slog_module_id = (submodule_ == SM_MD ? MD : ME);
  181. Dlog(static_cast<int>(slog_module_id), GetSlogLevel(log_level_), "[%s:%d] %s] %s", location_.file_, location_.line_,
  182. location_.func_, str_msg.c_str());
  183. #endif
  184. }
  185. void LogWriter::operator<(const LogStream &stream) const noexcept {
  186. std::ostringstream msg;
  187. msg << stream.sstream_->rdbuf();
  188. OutputLog(msg);
  189. }
  190. void LogWriter::operator^(const LogStream &stream) const {
  191. std::ostringstream msg;
  192. msg << stream.sstream_->rdbuf();
  193. OutputLog(msg);
  194. std::ostringstream oss;
  195. oss << location_.file_ << ":" << location_.line_ << " " << location_.func_ << "] ";
  196. if (exception_type_ != NoExceptionType && exception_type_ != IndexError && exception_type_ != TypeError &&
  197. exception_type_ != ValueError) {
  198. oss << ExceptionTypeToString(exception_type_) << " ";
  199. }
  200. oss << msg.str();
  201. trace::TraceGraphEval();
  202. trace::GetEvalStackInfo(oss);
  203. if (exception_handler_ != nullptr) {
  204. exception_handler_(exception_type_, oss.str());
  205. }
  206. throw std::runtime_error(oss.str());
  207. }
  208. static std::string GetEnv(const std::string &envvar) {
  209. const char *value = ::getenv(envvar.c_str());
  210. if (value == nullptr) {
  211. return std::string();
  212. }
  213. return std::string(value);
  214. }
  215. enum LogConfigToken {
  216. INVALID, // indicate invalid token
  217. LEFT_BRACE, // '{'
  218. RIGHT_BRACE, // '}'
  219. VARIABLE, // '[A-Za-z][A-Za-z0-9_]*'
  220. NUMBER, // [0-9]+
  221. COMMA, // ','
  222. COLON, // ':'
  223. EOS, // End Of String, '\0'
  224. NUM_LOG_CFG_TOKENS
  225. };
  226. static const char *g_tok_names[NUM_LOG_CFG_TOKENS] = {
  227. "invalid", // indicate invalid token
  228. "{", // '{'
  229. "}", // '}'
  230. "variable", // '[A-Za-z][A-Za-z0-9_]*'
  231. "number", // [0-9]+
  232. ",", // ','
  233. ":", // ':'
  234. "end-of-string", // End Of String, '\0'
  235. };
  236. static inline bool IsAlpha(char ch) { return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); }
  237. static inline bool IsDigit(char ch) { return ch >= '0' && ch <= '9'; }
  238. class LogConfigLexer {
  239. public:
  240. explicit LogConfigLexer(const std::string &text) : buffer_(text) {
  241. cur_idx_ = 0;
  242. cur_token_ = LogConfigToken::INVALID;
  243. }
  244. ~LogConfigLexer() = default;
  245. // skip white space, and return the first char after white space
  246. char SkipWhiteSpace() {
  247. while (cur_idx_ < buffer_.size()) {
  248. char ch = buffer_[cur_idx_];
  249. if (ch == ' ' || ch == '\t') {
  250. ++cur_idx_;
  251. continue;
  252. }
  253. return ch;
  254. }
  255. return '\0';
  256. }
  257. LogConfigToken GetNext(std::string *const ptr) {
  258. #ifdef DEBUG
  259. std::string text;
  260. auto tok = GetNextInner(&text);
  261. MS_LOG(DEBUG) << "Got token " << tok << " with value [" << text << "]";
  262. if (ptr != nullptr) {
  263. *ptr = text;
  264. }
  265. return tok;
  266. }
  267. LogConfigToken GetNextInner(std::string *ptr) {
  268. #endif
  269. char ch = SkipWhiteSpace();
  270. // clang-format off
  271. static const std::map<char, LogConfigToken> single_char_map = {
  272. {'{', LogConfigToken::LEFT_BRACE},
  273. {'}', LogConfigToken::RIGHT_BRACE},
  274. {',', LogConfigToken::COMMA},
  275. {':', LogConfigToken::COLON},
  276. {'\0', LogConfigToken::EOS},
  277. };
  278. // clang-format on
  279. auto iter = single_char_map.find(ch);
  280. if (iter != single_char_map.end()) {
  281. if (ptr != nullptr) {
  282. *ptr = std::string() + ch;
  283. }
  284. ++cur_idx_;
  285. return iter->second;
  286. } else if (IsAlpha(ch)) {
  287. std::ostringstream oss;
  288. do {
  289. oss << ch;
  290. ch = buffer_[++cur_idx_];
  291. } while (cur_idx_ < buffer_.size() && (IsAlpha(ch) || IsDigit(ch) || ch == '_'));
  292. if (ptr != nullptr) {
  293. *ptr = std::string(oss.str());
  294. }
  295. return LogConfigToken::VARIABLE;
  296. } else if (IsDigit(ch)) {
  297. std::ostringstream oss;
  298. do {
  299. oss << ch;
  300. ch = buffer_[++cur_idx_];
  301. } while (cur_idx_ < buffer_.size() && IsDigit(ch));
  302. if (ptr != nullptr) {
  303. *ptr = std::string(oss.str());
  304. }
  305. return LogConfigToken::NUMBER;
  306. }
  307. return LogConfigToken::INVALID;
  308. }
  309. private:
  310. std::string buffer_;
  311. size_t cur_idx_;
  312. LogConfigToken cur_token_;
  313. std::string cur_text_;
  314. };
  315. class LogConfigParser {
  316. public:
  317. explicit LogConfigParser(const std::string &cfg) : lexer(cfg) {}
  318. ~LogConfigParser() = default;
  319. bool Expect(LogConfigToken expected, LogConfigToken tok) {
  320. if (expected != tok) {
  321. MS_LOG(WARNING) << "Parse submodule log configuration text error, expect `" << g_tok_names[expected]
  322. << "`, but got `" << g_tok_names[tok] << "`. The whole configuration will be ignored.";
  323. return false;
  324. }
  325. return true;
  326. }
  327. // The text of config MS_SUBMODULE_LOG_v is in the form {submodule1:log_level1,submodule2:log_level2,...}.
  328. // Valid values of log levels are: 0 - debug, 1 - info, 2 - warning, 3 - error
  329. // e.g. MS_SUBMODULE_LOG_v={PARSER:0, ANALYZER:2, PIPELINE:1}
  330. std::map<std::string, std::string> Parse() {
  331. std::map<std::string, std::string> log_levels;
  332. bool flag_error = false;
  333. std::string text;
  334. auto tok = lexer.GetNext(&text);
  335. // empty string
  336. if (tok == LogConfigToken::EOS) {
  337. return log_levels;
  338. }
  339. if (!Expect(LogConfigToken::LEFT_BRACE, tok)) {
  340. return log_levels;
  341. }
  342. do {
  343. std::string key, val;
  344. tok = lexer.GetNext(&key);
  345. if (!Expect(LogConfigToken::VARIABLE, tok)) {
  346. flag_error = true;
  347. break;
  348. }
  349. tok = lexer.GetNext(&text);
  350. if (!Expect(LogConfigToken::COLON, tok)) {
  351. flag_error = true;
  352. break;
  353. }
  354. tok = lexer.GetNext(&val);
  355. if (!Expect(LogConfigToken::NUMBER, tok)) {
  356. flag_error = true;
  357. break;
  358. }
  359. log_levels[key] = val;
  360. tok = lexer.GetNext(&text);
  361. } while (tok == LogConfigToken::COMMA);
  362. if (!flag_error && !Expect(LogConfigToken::RIGHT_BRACE, tok)) {
  363. flag_error = true;
  364. }
  365. if (flag_error) {
  366. log_levels.clear();
  367. }
  368. return log_levels;
  369. }
  370. private:
  371. LogConfigLexer lexer;
  372. };
  373. bool ParseLogLevel(const std::string &str_level, MsLogLevel *ptr_level) {
  374. if (str_level.size() == 1) {
  375. int ch = str_level.c_str()[0];
  376. ch = ch - '0'; // substract ASCII code of '0', which is 48
  377. if (ch >= DEBUG && ch <= ERROR) {
  378. if (ptr_level != nullptr) {
  379. *ptr_level = static_cast<MsLogLevel>(ch);
  380. }
  381. return true;
  382. }
  383. }
  384. return false;
  385. }
  386. static MsLogLevel GetGlobalLogLevel() {
  387. #ifdef USE_GLOG
  388. return static_cast<MsLogLevel>(FLAGS_v);
  389. #else
  390. int log_level = WARNING; // set default log level to WARNING
  391. auto str_level = GetEnv("GLOG_v");
  392. if (str_level.size() == 1) {
  393. int ch = str_level.c_str()[0];
  394. ch = ch - '0'; // substract ASCII code of '0', which is 48
  395. if (ch >= DEBUG && ch <= ERROR) {
  396. log_level = ch;
  397. }
  398. }
  399. return static_cast<MsLogLevel>(log_level);
  400. #endif
  401. }
  402. void InitSubModulesLogLevel() {
  403. // initialize submodule's log level using global
  404. auto global_log_level = GetGlobalLogLevel();
  405. for (int i = 0; i < NUM_SUBMODUES; ++i) {
  406. g_ms_submodule_log_levels[i] = global_log_level;
  407. }
  408. // set submodule's log level
  409. auto submodule = GetEnv("MS_SUBMODULE_LOG_v");
  410. MS_LOG(DEBUG) << "MS_SUBMODULE_LOG_v=`" << submodule << "`";
  411. LogConfigParser parser(submodule);
  412. auto configs = parser.Parse();
  413. for (const auto &cfg : configs) {
  414. int mod_idx = -1;
  415. for (int i = 0; i < NUM_SUBMODUES; ++i) {
  416. if (cfg.first == GetSubModuleName(static_cast<SubModuleId>(i))) {
  417. mod_idx = i;
  418. break;
  419. }
  420. }
  421. if (mod_idx < 0) {
  422. MS_LOG(WARNING) << "Undefined module name " << cfg.first << ", ignore it";
  423. continue;
  424. }
  425. MsLogLevel submodule_log_level;
  426. if (!ParseLogLevel(cfg.second, &submodule_log_level)) {
  427. MS_LOG(WARNING) << "Illegal log level value " << cfg.second << " for " << cfg.first << ", ignore it.";
  428. continue;
  429. }
  430. g_ms_submodule_log_levels[mod_idx] = submodule_log_level;
  431. }
  432. }
  433. } // namespace mindspore
  434. extern "C" {
  435. #if defined(_WIN32) || defined(_WIN64)
  436. __attribute__((constructor)) void common_log_init(void) {
  437. #else
  438. void common_log_init(void) {
  439. #endif
  440. #ifdef USE_GLOG
  441. // do not use glog predefined log prefix
  442. FLAGS_log_prefix = false;
  443. // set default log level to WARNING
  444. if (mindspore::GetEnv("GLOG_v").empty()) {
  445. FLAGS_v = mindspore::WARNING;
  446. }
  447. // set default log file mode to 0640
  448. if (mindspore::GetEnv("GLOG_logfile_mode").empty()) {
  449. FLAGS_logfile_mode = 0640;
  450. }
  451. std::string logtostderr = mindspore::GetEnv("GLOG_logtostderr");
  452. // default print log to screen
  453. if (logtostderr.empty()) {
  454. FLAGS_logtostderr = true;
  455. } else if (logtostderr == "0" && mindspore::GetEnv("GLOG_log_dir").empty()) {
  456. FLAGS_logtostderr = true;
  457. MS_LOG(WARNING) << "`GLOG_log_dir` is not set, output log to screen.";
  458. }
  459. #endif
  460. mindspore::InitSubModulesLogLevel();
  461. }
  462. // shared lib init hook
  463. #if defined(_WIN32) || defined(_WIN64)
  464. __attribute__((constructor)) void mindspore_log_init(void) {
  465. #else
  466. void mindspore_log_init(void) {
  467. #endif
  468. #ifdef USE_GLOG
  469. static bool is_glog_initialzed = false;
  470. if (!is_glog_initialzed) {
  471. #if !defined(_WIN32) && !defined(_WIN64)
  472. google::InitGoogleLogging("mindspore");
  473. #endif
  474. is_glog_initialzed = true;
  475. }
  476. #endif
  477. common_log_init();
  478. }
  479. }