llerror.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218
  1. /**
  2. * @file llerror.cpp
  3. * @brief Error message system implementation
  4. *
  5. * $LicenseInfo:firstyear=2006&license=viewergpl$
  6. *
  7. * Copyright (c) 2006-2009, Linden Research, Inc.
  8. * Copyright (c) 2009-2023, Henri Beauchamp.
  9. *
  10. * Second Life Viewer Source Code
  11. * The source code in this file ("Source Code") is provided by Linden Lab
  12. * to you under the terms of the GNU General Public License, version 2.0
  13. * ("GPL"), unless you have obtained a separate licensing agreement
  14. * ("Other License"), formally executed by you and Linden Lab. Terms of
  15. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  16. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  17. *
  18. * There are special exceptions to the terms and conditions of the GPL as
  19. * it is applied to this Source Code. View the full text of the exception
  20. * in the file doc/FLOSS-exception.txt in this software distribution, or
  21. * online at
  22. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  23. *
  24. * By copying, modifying or distributing this software, you acknowledge
  25. * that you have read and understood your obligations described above,
  26. * and agree to abide by those obligations.
  27. *
  28. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  29. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  30. * COMPLETENESS OR PERFORMANCE.
  31. * $/LicenseInfo$
  32. */
  33. #include "linden_common.h"
  34. #include "llerrorcontrol.h"
  35. #include <cctype>
  36. #include <chrono>
  37. #include <sstream>
  38. #if LL_WINDOWS
  39. # include <windows.h>
  40. # include <io.h>
  41. #else // LL_WINDOWS
  42. # include <cxxabi.h>
  43. # include <stdlib.h> // getenv()
  44. # include <syslog.h>
  45. # include <unistd.h>
  46. #endif // !LL_WINDOWS
  47. #if LL_DARWIN
  48. # include <sys/stat.h>
  49. #endif
  50. #include "llapp.h"
  51. #include "hbfastmap.h"
  52. #include "lllivefile.h"
  53. #include "llmutex.h"
  54. #include "llsd.h"
  55. #include "llsdserialize.h"
  56. #include "llsingleton.h"
  57. #include "llstl.h"
  58. #include "llstring.h"
  59. #include "lltimer.h"
  60. #include "hbxxh.h"
  61. bool LLError::Log::sDebugMessages = true;
  62. bool LLError::Log::sPreciseTimeStamp = false;
  63. bool LLError::Log::sIsBeingDebugged = false;
  64. namespace
  65. {
  66. #if LL_WINDOWS
  67. // Be careful when calling OutputDebugString as it throws
  68. // DBG_PRINTEXCEPTION_C which works just fine under the windows debugger,
  69. // but can cause users who have enabled SEHOP exception chain validation to
  70. // crash due to interactions between the Win 32-bit exception handling and
  71. // boost coroutine fiber stacks. BUG-2707
  72. LL_INLINE void LLOutputDebugUTF8(const std::string& s)
  73. {
  74. // Need UTF16 for Unicode OutputDebugString
  75. if (IsDebuggerPresent() && s.size())
  76. {
  77. OutputDebugString(ll_convert_string_to_wide(s).c_str());
  78. OutputDebugString(TEXT("\n"));
  79. }
  80. }
  81. class RecordToWinDebug final : public LLError::Recorder
  82. {
  83. public:
  84. void recordMessage(LLError::ELevel, const std::string& msg) override
  85. {
  86. LLOutputDebugUTF8(msg);
  87. }
  88. };
  89. #else
  90. class RecordToSyslog final : public LLError::Recorder
  91. {
  92. public:
  93. RecordToSyslog(const std::string& identity)
  94. : mIdentity(identity)
  95. {
  96. openlog(mIdentity.c_str(), LOG_CONS|LOG_PID, LOG_LOCAL0);
  97. // we need to set the string from a local copy of the string
  98. // since apparanetly openlog expects the const char* to remain
  99. // valid even after it returns (presumably until closelog)
  100. }
  101. ~RecordToSyslog()
  102. {
  103. closelog();
  104. }
  105. void recordMessage(LLError::ELevel lv, const std::string& msg) override
  106. {
  107. int prio = LOG_CRIT;
  108. switch (lv)
  109. {
  110. case LLError::LEVEL_DEBUG: prio = LOG_DEBUG; break;
  111. case LLError::LEVEL_INFO: prio = LOG_INFO; break;
  112. case LLError::LEVEL_WARN: prio = LOG_WARNING; break;
  113. case LLError::LEVEL_ERROR: prio = LOG_CRIT; break;
  114. default: prio = LOG_CRIT;
  115. }
  116. syslog(prio, "%s", msg.c_str());
  117. }
  118. private:
  119. std::string mIdentity;
  120. };
  121. #endif
  122. class RecordToFile final : public LLError::Recorder
  123. {
  124. public:
  125. RecordToFile(const std::string& filename)
  126. : mName(filename),
  127. #if LL_LINUX || LL_DARWIN
  128. mSavedStderr(-1),
  129. #endif
  130. mLogFile(LLFile::open(filename, "a"))
  131. {
  132. if (!mLogFile)
  133. {
  134. llwarns << "Error setting log file to " << filename << llendl;
  135. }
  136. #if LL_LINUX || LL_DARWIN
  137. else if (getenv("LL_REDIRECT_STDERR_TO_LOG"))
  138. {
  139. // We use a number of classic-C libraries, some of which write
  140. // log output to stderr. The trouble with that is that unless
  141. // you launch the viewer from a console, stderr output is lost.
  142. // Redirect STDERR_FILENO to write into this log file. But
  143. // first, save the original stream in case we want it later.
  144. mSavedStderr = dup(STDERR_FILENO);
  145. dup2(fileno(mLogFile), STDERR_FILENO);
  146. }
  147. #endif
  148. }
  149. ~RecordToFile() override
  150. {
  151. #if LL_LINUX || LL_DARWIN
  152. if (mSavedStderr >= 0)
  153. {
  154. // Restore stderr to its original fileno so any subsequent
  155. // output to stderr goes to original stream.
  156. dup2(mSavedStderr, STDERR_FILENO);
  157. }
  158. #endif
  159. mLogFile.flush(); // Paranoia
  160. }
  161. LL_INLINE bool okay() { return bool(mLogFile); }
  162. LL_INLINE bool wantsTime() override { return true; }
  163. LL_INLINE void recordMessage(LLError::ELevel,
  164. const std::string& msg) override
  165. {
  166. fwrite(msg.c_str(), sizeof(char), msg.length(), mLogFile);
  167. putc('\n', mLogFile);
  168. flushIfNeeded();
  169. }
  170. // This method flushes to the disk only when needed, so to keep the
  171. // number of writes low enough (especially important with SSDs and
  172. // their limited write endurance). HB
  173. LL_NO_INLINE void flushIfNeeded()
  174. {
  175. static LLTimer flush_timer;
  176. // In the Cool VL Viewer, sDebugMessages is true on startup and,
  177. // once logged in, when any LL_DEBUGS tag is active; we want to
  178. // see log messages in real time in the latter case, so let's
  179. // always flush them.
  180. bool do_flush = LLError::Log::sDebugMessages ||
  181. #if LL_LINUX || LL_DARWIN
  182. // We also need to always flush whenever the stderr stream is
  183. // redirected to our log stream, else race conditions will happen
  184. // between viewer log messages and third parties libraries/binaries
  185. // log messages, causing mangled log lines.
  186. mSavedStderr >= 0 ||
  187. #endif
  188. // Flush at least once every 10 seconds otherwise.
  189. flush_timer.getElapsedTimeF64() >= 10.0;
  190. if (do_flush)
  191. {
  192. mLogFile.flush();
  193. flush_timer.reset();
  194. }
  195. }
  196. LL_INLINE const std::string& getFilename() const
  197. {
  198. return mName;
  199. }
  200. private:
  201. LLFile mLogFile;
  202. std::string mName;
  203. #if LL_LINUX || LL_DARWIN
  204. int mSavedStderr;
  205. #endif
  206. };
  207. class RecordToStderr final : public LLError::Recorder
  208. {
  209. public:
  210. RecordToStderr()
  211. : mUseANSI(ANSI_PROBE)
  212. {
  213. }
  214. #if LL_WINDOWS
  215. LL_INLINE bool wantsTime() override { return false; }
  216. #else
  217. LL_INLINE bool wantsTime() override { return true; }
  218. #endif
  219. void recordMessage(LLError::ELevel lv, const std::string& msg) override
  220. {
  221. // Default all message levels to bold so we can distinguish our
  222. // own messages from those dumped by subprocesses and libraries.
  223. static std::string s_ansi_bold = createANSI("1"); // Bold
  224. static std::string s_ansi_error = s_ansi_bold +
  225. createANSI("31"); // Red
  226. static std::string s_ansi_warn = s_ansi_bold +
  227. createANSI("34"); // Blue
  228. static std::string s_ansi_debug = s_ansi_bold +
  229. createANSI("35"); // Magenta
  230. if (ANSI_PROBE == mUseANSI)
  231. {
  232. mUseANSI = checkANSI() ? ANSI_YES : ANSI_NO;
  233. }
  234. if (ANSI_YES != mUseANSI)
  235. {
  236. fprintf(stderr, "%s\n", msg.c_str());
  237. return;
  238. }
  239. switch (lv)
  240. {
  241. case LLError::LEVEL_ERROR:
  242. writeANSI(s_ansi_error, msg);
  243. return;
  244. case LLError::LEVEL_WARN:
  245. writeANSI(s_ansi_warn, msg);
  246. return;
  247. case LLError::LEVEL_DEBUG:
  248. writeANSI(s_ansi_debug, msg);
  249. return;
  250. default:
  251. writeANSI(s_ansi_bold, msg);
  252. }
  253. }
  254. private:
  255. LL_INLINE std::string createANSI(const std::string& code)
  256. {
  257. return "\033[" + code + "m";
  258. }
  259. LL_INLINE void writeANSI(const std::string& ansi_code,
  260. const std::string& message)
  261. {
  262. static std::string s_ansi_reset = createANSI("0");
  263. fprintf(stderr, "%s%s%s\n", ansi_code.c_str(), message.c_str(),
  264. s_ansi_reset.c_str());
  265. }
  266. LL_INLINE bool checkANSI()
  267. {
  268. // Check whether it is okay to use ANSI; if stderr is a TTY then we
  269. // assume yes. Can be turned off with the LL_NO_ANSI_COLOR env var.
  270. return isatty(2) != 0 && getenv("LL_NO_ANSI_COLOR") == NULL;
  271. }
  272. private:
  273. enum ANSIState { ANSI_PROBE, ANSI_YES, ANSI_NO };
  274. ANSIState mUseANSI;
  275. };
  276. class RecordToFixedBuffer final : public LLError::Recorder
  277. {
  278. public:
  279. RecordToFixedBuffer(LLLineBuffer* buffer)
  280. : mBuffer(buffer)
  281. {
  282. }
  283. void recordMessage(LLError::ELevel, const std::string& msg) override
  284. {
  285. mBuffer->addLine(msg);
  286. }
  287. private:
  288. LLLineBuffer* mBuffer;
  289. };
  290. class LogControlFile final : public LLLiveFile
  291. {
  292. protected:
  293. LOG_CLASS(LogControlFile);
  294. public:
  295. static LogControlFile& fromDirectory(const std::string& dir);
  296. bool loadFile() override;
  297. private:
  298. LogControlFile(const std::string& filename)
  299. : LLLiveFile(filename)
  300. {
  301. }
  302. };
  303. LogControlFile& LogControlFile::fromDirectory(const std::string& dir)
  304. {
  305. #if LL_WINDOWS
  306. std::string file = dir + "\\logcontrol.xml";
  307. #else
  308. std::string file = dir + "/logcontrol.xml";
  309. #endif
  310. return *new LogControlFile(file); // NB: this instance is never freed
  311. }
  312. bool LogControlFile::loadFile()
  313. {
  314. LLSD configuration;
  315. llifstream file(filename().c_str());
  316. if (file.is_open())
  317. {
  318. LLSDSerialize::fromXML(configuration, file);
  319. }
  320. if (configuration.isUndefined())
  321. {
  322. llwarns << filename()
  323. << " missing, ill-formed or simply undefined; not changing configuration."
  324. << llendl;
  325. return false;
  326. }
  327. LLError::configure(configuration);
  328. llinfos << "logging reconfigured from " << filename() << llendl;
  329. return true;
  330. }
  331. typedef flat_hmap<std::string, LLError::ELevel> level_map_t;
  332. typedef std::vector<LLError::Recorder*> rec_list_t;
  333. typedef std::vector<LLError::CallSite*> callsite_vect_t;
  334. typedef flat_hmap<std::string, U32> uniq_msg_map_t;
  335. class Globals : public LLSingleton<Globals>
  336. {
  337. friend class LLSingleton<Globals>;
  338. public:
  339. Globals() = default;
  340. void addCallSite(LLError::CallSite& site)
  341. {
  342. mCallSites.push_back(&site);
  343. }
  344. void invalidateCallSites()
  345. {
  346. for (callsite_vect_t::const_iterator it = mCallSites.begin(),
  347. end = mCallSites.end();
  348. it != end; ++it)
  349. {
  350. (*it)->invalidate();
  351. }
  352. mCallSites.clear();
  353. }
  354. private:
  355. callsite_vect_t mCallSites;
  356. };
  357. }
  358. namespace LLError
  359. {
  360. class Settings
  361. {
  362. private:
  363. Settings()
  364. : mPrintLocation(false),
  365. mDefaultLevel(LLError::LEVEL_DEBUG),
  366. mCrashFunction(NULL),
  367. mTimeFunction(NULL),
  368. mFileRecorder(NULL),
  369. mFixedBufferRecorder(NULL)
  370. {
  371. }
  372. ~Settings()
  373. {
  374. for_each(mRecorders.begin(), mRecorders.end(), DeletePointer());
  375. mRecorders.clear();
  376. }
  377. public:
  378. static Settings*& getPtr();
  379. static Settings& get();
  380. static void reset();
  381. static Settings* saveAndReset();
  382. static void restore(Settings*);
  383. public:
  384. LLError::ELevel mDefaultLevel;
  385. level_map_t mFunctionLevelMap;
  386. level_map_t mClassLevelMap;
  387. level_map_t mFileLevelMap;
  388. level_map_t mTagLevelMap;
  389. LLError::fatal_func_t mCrashFunction;
  390. LLError::time_func_t mTimeFunction;
  391. rec_list_t mRecorders;
  392. Recorder* mFileRecorder;
  393. Recorder* mFixedBufferRecorder;
  394. std::string mFileRecorderFileName;
  395. bool mPrintLocation;
  396. };
  397. LL_INLINE Settings& Settings::get()
  398. {
  399. Settings* p = getPtr();
  400. if (!p)
  401. {
  402. reset();
  403. p = getPtr();
  404. }
  405. return *p;
  406. }
  407. void Settings::reset()
  408. {
  409. Globals::getInstance()->invalidateCallSites();
  410. Settings*& p = getPtr();
  411. delete p;
  412. p = new Settings();
  413. }
  414. Settings* Settings::saveAndReset()
  415. {
  416. Globals::getInstance()->invalidateCallSites();
  417. Settings*& p = getPtr();
  418. Settings* originalSettings = p;
  419. p = new Settings();
  420. return originalSettings;
  421. }
  422. void Settings::restore(Settings* originalSettings)
  423. {
  424. Globals::getInstance()->invalidateCallSites();
  425. Settings*& p = getPtr();
  426. delete p;
  427. p = originalSettings;
  428. }
  429. LL_INLINE Settings*& Settings::getPtr()
  430. {
  431. static Settings* currentSettings = NULL;
  432. return currentSettings;
  433. }
  434. bool isAvailable()
  435. {
  436. return Settings::getPtr() != NULL && Globals::instanceExists();
  437. }
  438. LL_INLINE void removePrefix(char* s, const char* p)
  439. {
  440. char* where = strstr(s, p);
  441. if (where)
  442. {
  443. s = where + strlen(p);
  444. }
  445. }
  446. LL_NO_INLINE CallSite::CallSite(ELevel level, const char* file, S32 line,
  447. const std::type_info& class_info,
  448. const char* function, const char* tag)
  449. : mLevel(level),
  450. mLine(line),
  451. mClassInfo(class_info),
  452. mFunction(function),
  453. mCached(false),
  454. mShouldLog(false),
  455. mTag(tag)
  456. {
  457. // This indeed points to a C-string constant, but we change the start
  458. // of the string to remove useless verbosity; done here once and for
  459. // all to avoid calling removePrefix() in time critical sections. HB
  460. mFile = (char*)file;
  461. #if LL_WINDOWS
  462. removePrefix(mFile, "indra\\");
  463. #else
  464. removePrefix(mFile, "indra/");
  465. #endif
  466. #if LL_DARWIN
  467. removePrefix(mFile, "newview/../");
  468. #endif
  469. }
  470. LL_NO_INLINE CallSiteOnce::CallSiteOnce(ELevel level, const char* file, S32 line,
  471. const std::type_info& class_info,
  472. const char* function, const char* tag,
  473. bool sparse)
  474. : CallSite(level, file, line, class_info, function, tag),
  475. mSparse(sparse)
  476. {
  477. }
  478. //virtual
  479. LL_NO_INLINE bool CallSiteOnce::getPrefix(std::ostringstream& out,
  480. const std::string& msg) const
  481. {
  482. // Using a (fast !) hash as a key for the map (instead of the 'msg'
  483. // string, originally) saves memory and makes searches in the map much
  484. // faster. HB
  485. U64 hash = HBXXH64::digest(msg);
  486. msg_hash_map_t::iterator it = mOccurrences.find(hash);
  487. if (it == mOccurrences.end())
  488. {
  489. mOccurrences[hash] = 1;
  490. out << (mSparse ? "SPARSE: " : "ONCE: ");
  491. return true;
  492. }
  493. if (mSparse)
  494. {
  495. U32 num_messages = ++it->second;
  496. if (num_messages == 10 || num_messages == 100 ||
  497. num_messages == 1000 || num_messages % 10000 == 0)
  498. {
  499. out << "SPARSE (" << num_messages << "th time seen): ";
  500. return true;
  501. }
  502. }
  503. return false;
  504. }
  505. #if LL_DARWIN
  506. bool shouldLogToStderr()
  507. {
  508. if (getenv("LL_REDIRECT_STDERR_TO_LOG"))
  509. {
  510. // Do not log to stderr when we redirect the latter to the log file
  511. // (else we get duplicates for every viewer log messages).
  512. return false;
  513. }
  514. // On Mac OS X, stderr from apps launched from the Finder goes to the
  515. // console log. It is generally considered bad form to spam too much
  516. // there. That scenario can be detected by noticing that stderr is a
  517. // character device (S_IFCHR). If stderr is a TTY or a pipe, assume the
  518. // user launched from the command line or debugger and therefore wants
  519. // to see stderr.
  520. if (isatty(STDERR_FILENO))
  521. {
  522. return true;
  523. }
  524. struct stat st;
  525. if (fstat(STDERR_FILENO, &st) >= 0)
  526. {
  527. // fstat() worked: allow to log only if stderr is a pipe
  528. return (st.st_mode & S_IFMT) == S_IFIFO;
  529. }
  530. // Got called during log-system setup: cannot fstat() just yet, so just
  531. // report the issue and give-up logging...
  532. int errno_save = errno;
  533. std::cerr << "shouldLogToStderr: fstat(" << STDERR_FILENO
  534. << ") failed with errno: " << errno_save << std::endl;
  535. return false;
  536. }
  537. #elif LL_LINUX
  538. bool shouldLogToStderr()
  539. {
  540. // Do not log to stderr when we redirect the latter to the log file
  541. // (else we get duplicates for every viewer log messages).
  542. return !getenv("LL_REDIRECT_STDERR_TO_LOG");
  543. }
  544. #endif
  545. void commonInit(const std::string& dir)
  546. {
  547. Settings::reset();
  548. setDefaultLevel(LEVEL_INFO);
  549. setTimeFunction(utcTime);
  550. #if LL_WINDOWS
  551. addRecorder(new RecordToStderr);
  552. addRecorder(new RecordToWinDebug);
  553. #else
  554. if (shouldLogToStderr())
  555. {
  556. addRecorder(new RecordToStderr);
  557. }
  558. #endif
  559. LogControlFile& e = LogControlFile::fromDirectory(dir);
  560. // NOTE: We want to explicitly load the file before we add it to the
  561. // event timer that checks for changes to the file. Else, we are not
  562. // actually loading the file yet and most of the initialization happens
  563. // without any attention being paid to the log control file. Not to
  564. // mention that when it finally gets checked later, all log statements
  565. // that have been evaluated already become dirty and need to be
  566. // evaluated for printing again. So, make sure to call checkAndReload()
  567. // before addToEventTimer().
  568. e.checkAndReload();
  569. e.addToEventTimer();
  570. }
  571. void initForApplication(const std::string& dir)
  572. {
  573. commonInit(dir);
  574. }
  575. void setPrintLocation(bool print)
  576. {
  577. Settings& s = Settings::get();
  578. s.mPrintLocation = print;
  579. }
  580. void setFatalFunction(fatal_func_t f)
  581. {
  582. Settings& s = Settings::get();
  583. s.mCrashFunction = f;
  584. }
  585. void setTimeFunction(time_func_t f)
  586. {
  587. Settings& s = Settings::get();
  588. s.mTimeFunction = f;
  589. }
  590. void setDefaultLevel(ELevel level)
  591. {
  592. Globals::getInstance()->invalidateCallSites();
  593. Settings& s = Settings::get();
  594. s.mDefaultLevel = level;
  595. }
  596. void setFunctionLevel(const std::string& function_name, ELevel level)
  597. {
  598. Globals::getInstance()->invalidateCallSites();
  599. Settings& s = Settings::get();
  600. s.mFunctionLevelMap.emplace(function_name, level);
  601. }
  602. void setClassLevel(const std::string& class_name, ELevel level)
  603. {
  604. Globals::getInstance()->invalidateCallSites();
  605. Settings& s = Settings::get();
  606. s.mClassLevelMap.emplace(class_name, level);
  607. }
  608. void setFileLevel(const std::string& file_name, ELevel level)
  609. {
  610. Globals::getInstance()->invalidateCallSites();
  611. Settings& s = Settings::get();
  612. s.mFileLevelMap.emplace(file_name, level);
  613. }
  614. void setTagLevel(const std::string& tag_name, ELevel level)
  615. {
  616. Globals::getInstance()->invalidateCallSites();
  617. Settings& s = Settings::get();
  618. // Do not use emplace() here, since setTagLevel() may be called with a
  619. // different level to change it after the initialization of the call
  620. // site and while the viewer is running. HB
  621. s.mTagLevelMap[tag_name] = level;
  622. }
  623. ELevel getTagLevel(const std::string& tag_name)
  624. {
  625. Settings& s = Settings::get();
  626. return s.mTagLevelMap[tag_name];
  627. }
  628. std::set<std::string> getTagsForLevel(ELevel level)
  629. {
  630. std::set<std::string> tags;
  631. Globals::getInstance()->invalidateCallSites();
  632. Settings& s = Settings::get();
  633. for (level_map_t::const_iterator it = s.mTagLevelMap.begin(),
  634. end = s.mTagLevelMap.end();
  635. it != end; ++it)
  636. {
  637. if (it->second == level)
  638. {
  639. tags.emplace(it->first);
  640. }
  641. }
  642. return tags;
  643. }
  644. ELevel decodeLevel(std::string name)
  645. {
  646. static level_map_t level_names;
  647. if (level_names.empty())
  648. {
  649. level_names["ALL"] = LEVEL_DEBUG;
  650. level_names["DEBUG"] = LEVEL_DEBUG;
  651. level_names["INFO"] = LEVEL_INFO;
  652. level_names["WARN"] = LEVEL_WARN;
  653. level_names["ERROR"] = LEVEL_ERROR;
  654. level_names["NONE"] = LEVEL_NONE;
  655. }
  656. LLStringUtil::toUpper(name);
  657. level_map_t::const_iterator it = level_names.find(name);
  658. if (it == level_names.end())
  659. {
  660. llwarns << "Unrecognized logging level: '" << name << "'"
  661. << llendl;
  662. return LEVEL_INFO;
  663. }
  664. return it->second;
  665. }
  666. void setLevels(level_map_t& map, const LLSD& list, ELevel level)
  667. {
  668. for (LLSD::array_const_iterator it = list.beginArray(),
  669. end = list.endArray();
  670. it != end; ++it)
  671. {
  672. map[it->asString()] = level;
  673. }
  674. }
  675. void configure(const LLSD& config)
  676. {
  677. Globals::getInstance()->invalidateCallSites();
  678. Settings& s = Settings::get();
  679. s.mFunctionLevelMap.clear();
  680. s.mClassLevelMap.clear();
  681. s.mFileLevelMap.clear();
  682. s.mTagLevelMap.clear();
  683. setPrintLocation(config["print-location"]);
  684. setDefaultLevel(decodeLevel(config["default-level"]));
  685. LLSD sets = config["settings"];
  686. for (LLSD::array_const_iterator it = sets.beginArray(),
  687. end = sets.endArray();
  688. it != end; ++it)
  689. {
  690. const LLSD& entry = *it;
  691. ELevel level = decodeLevel(entry["level"]);
  692. setLevels(s.mFunctionLevelMap, entry["functions"], level);
  693. setLevels(s.mClassLevelMap, entry["classes"], level);
  694. setLevels(s.mFileLevelMap, entry["files"], level);
  695. setLevels(s.mTagLevelMap, entry["tags"], level);
  696. }
  697. }
  698. LL_INLINE Recorder::~Recorder() = default;
  699. LL_INLINE bool Recorder::wantsTime() { return false; }
  700. void addRecorder(Recorder* recorder)
  701. {
  702. if (recorder)
  703. {
  704. Settings& s = Settings::get();
  705. s.mRecorders.push_back(recorder);
  706. }
  707. }
  708. void removeRecorder(Recorder* recorder)
  709. {
  710. if (!recorder)
  711. {
  712. return;
  713. }
  714. Settings& s = Settings::get();
  715. rec_list_t::iterator end = s.mRecorders.end();
  716. s.mRecorders.erase(std::remove(s.mRecorders.begin(), end, recorder),
  717. end);
  718. }
  719. void logToFile(const std::string& file_name)
  720. {
  721. Settings& s = Settings::get();
  722. removeRecorder(s.mFileRecorder);
  723. delete s.mFileRecorder;
  724. s.mFileRecorder = NULL;
  725. s.mFileRecorderFileName.clear();
  726. if (file_name.empty())
  727. {
  728. return;
  729. }
  730. RecordToFile* f = new RecordToFile(file_name);
  731. if (!f->okay())
  732. {
  733. delete f;
  734. return;
  735. }
  736. s.mFileRecorderFileName = file_name;
  737. s.mFileRecorder = f;
  738. addRecorder(f);
  739. }
  740. void logToFixedBuffer(LLLineBuffer* fixed_bufp)
  741. {
  742. Settings& s = Settings::get();
  743. removeRecorder(s.mFixedBufferRecorder);
  744. delete s.mFixedBufferRecorder;
  745. s.mFixedBufferRecorder = NULL;
  746. if (!fixed_bufp)
  747. {
  748. return;
  749. }
  750. s.mFixedBufferRecorder = new RecordToFixedBuffer(fixed_bufp);
  751. addRecorder(s.mFixedBufferRecorder);
  752. }
  753. std::string logFileName()
  754. {
  755. Settings& s = Settings::get();
  756. return s.mFileRecorderFileName;
  757. }
  758. void setLogFileName(std::string filename)
  759. {
  760. Settings& s = Settings::get();
  761. s.mFileRecorderFileName = filename;
  762. }
  763. // Recorder formats:
  764. //
  765. // $type = "ERROR" | "WARNING" | "INFO" | "DEBUG"
  766. // $loc = "$file($line)"
  767. // $msg = "$loc : " if FATAL or printing loc, "" otherwise
  768. // $msg += "$type: "
  769. // $msg += contents of stringstream
  770. // $time = "%Y-%m-%d %H:%M:%SZ" (UTC)
  771. //
  772. // syslog: "$msg"
  773. // file: "$time $msg\n"
  774. // stderr: "$time $msg\n" except on windows, "$msg\n"
  775. // fixedbuf: "$msg"
  776. // winddebug: "$msg\n"
  777. //
  778. // Note: if FATAL, an additional line gets logged first, with $msg set to
  779. // "$loc : error"
  780. //
  781. // You get:
  782. // llfoo.cpp(42) : error
  783. // llfoo.cpp(42) : ERROR: something
  784. // This ensures the static mutex gets constructed on first use, which is
  785. // otherwise not the case with boost mutexes, resulting in a hang at
  786. // startup... HB
  787. LLMutex& getLogMutex()
  788. {
  789. static LLMutex mutex;
  790. return mutex;
  791. }
  792. LL_NO_INLINE std::string className(const std::type_info& type)
  793. {
  794. std::string name = type.name();
  795. #if LL_DARWIN
  796. // libc++'s type_info::name() returns a mangled class name, must
  797. // demangle
  798. // Newest macOS versions got a crash bug in abi::__cxa_demangle()
  799. // when it is passed a static buffer pointer, so just let that
  800. // method allocate the memory by itself (slower than a static buffer,
  801. // of course)...
  802. int status; // Not used by us but needed by __cxa_demangle()...
  803. char* c_str = abi::__cxa_demangle(name.c_str(), NULL, 0, &status);
  804. if (c_str)
  805. {
  806. name.assign(c_str);
  807. free((void*)c_str);
  808. }
  809. #elif LL_LINUX
  810. // libstdc++'s type_info::name() returns a mangled class name, must
  811. // demangle
  812. static size_t abi_name_len = 1024; // Large enough to avoid realloc...
  813. static char* abi_name_buf = (char*)malloc(abi_name_len);
  814. int status; // Not used by us but needed by __cxa_demangle()...
  815. char* c_str = abi::__cxa_demangle(name.c_str(), abi_name_buf,
  816. &abi_name_len, &status);
  817. if (c_str)
  818. {
  819. name.assign(c_str);
  820. }
  821. #elif LL_WINDOWS
  822. // MSVC runtimes' type_info::name() includes the text "class " at the
  823. // start
  824. static const std::string class_prefix = "class ";
  825. if (name.compare(0, 6, class_prefix) == 0)
  826. {
  827. return name.substr(6);
  828. }
  829. # if 0 // ... or "struct "... But we do not use logging macros in structures,
  830. // in the Cool VL Viewer, so we do not care ! HB
  831. static const std::string struct_prefix = "struct ";
  832. if (name.compare(0, 7, struct_prefix) == 0)
  833. {
  834. return name.substr(7);
  835. }
  836. # endif
  837. #endif
  838. return name;
  839. }
  840. LL_INLINE bool checkLevelMap(const level_map_t& map,
  841. const std::string& key, ELevel& level)
  842. {
  843. level_map_t::const_iterator it = map.find(key);
  844. if (it == map.end())
  845. {
  846. return false;
  847. }
  848. level = it->second;
  849. return true;
  850. }
  851. LL_NO_INLINE bool Log::shouldLog(CallSite& site)
  852. {
  853. LLMutexLock lock(getLogMutex());
  854. Settings& s = Settings::get();
  855. ELevel level = s.mDefaultLevel;
  856. std::string class_name = className(site.mClassInfo);
  857. std::string function_name = site.mFunction;
  858. if (!s.mFunctionLevelMap.empty())
  859. {
  860. #if LL_MSVC
  861. // DevStudio: the __FUNCTION__ macro string includes the type
  862. // and/or namespace prefixes... Remove them.
  863. size_t p = function_name.rfind(':');
  864. if (p != std::string::npos)
  865. {
  866. function_name = function_name.substr(p + 1);
  867. }
  868. #endif
  869. static const std::string no_class_info = "LLError::NoClassInfo";
  870. if (class_name != no_class_info)
  871. {
  872. function_name = class_name + "::" + function_name;
  873. }
  874. }
  875. // The most specific match found will be used as the log level, since
  876. // the computation short circuits. So, in increasing order of
  877. // importance:
  878. // Default < Tag < File < Class < Function
  879. checkLevelMap(s.mFunctionLevelMap, function_name, level)
  880. || checkLevelMap(s.mClassLevelMap, class_name, level)
  881. || checkLevelMap(s.mFileLevelMap, site.mFile, level)
  882. || (site.mTag && checkLevelMap(s.mTagLevelMap, site.mTag, level));
  883. site.mCached = true;
  884. Globals::getInstance()->addCallSite(site);
  885. return site.mShouldLog = site.mLevel >= level;
  886. }
  887. LL_NO_INLINE void writeToRecorders(ELevel level,
  888. const std::string& message)
  889. {
  890. static std::string last_message;
  891. static U32 repeats = 0;
  892. if (message == last_message)
  893. {
  894. ++repeats;
  895. return;
  896. }
  897. if (repeats > 1)
  898. {
  899. last_message += llformat(" (repeated %d times)", repeats);
  900. }
  901. Settings& s = Settings::get();
  902. if (s.mTimeFunction)
  903. {
  904. std::string message_with_time =
  905. s.mTimeFunction(Log::sPreciseTimeStamp) + " ";
  906. std::string last_with_time;
  907. if (repeats > 0)
  908. {
  909. last_with_time = message_with_time + last_message;
  910. }
  911. message_with_time += message;
  912. for (rec_list_t::const_iterator it = s.mRecorders.begin(),
  913. end = s.mRecorders.end();
  914. it != end; ++it)
  915. {
  916. Recorder* r = *it;
  917. if (r->wantsTime())
  918. {
  919. if (repeats > 0)
  920. {
  921. r->recordMessage(level, last_with_time);
  922. }
  923. r->recordMessage(level, message_with_time);
  924. }
  925. else
  926. {
  927. if (repeats > 0)
  928. {
  929. r->recordMessage(level, last_message);
  930. }
  931. r->recordMessage(level, message);
  932. }
  933. }
  934. }
  935. else
  936. {
  937. for (rec_list_t::const_iterator it = s.mRecorders.begin(),
  938. end = s.mRecorders.end();
  939. it != end; ++it)
  940. {
  941. Recorder* r = *it;
  942. if (repeats > 0)
  943. {
  944. r->recordMessage(level, last_message);
  945. }
  946. r->recordMessage(level, message);
  947. }
  948. }
  949. repeats = 0;
  950. last_message = message;
  951. }
  952. LL_NO_INLINE void Log::flush(const std::ostringstream& out,
  953. const CallSite& site)
  954. {
  955. LLMutexLock lock(getLogMutex());
  956. std::string message = out.str();
  957. if (site.mLevel == LEVEL_ERROR)
  958. {
  959. std::ostringstream fatal_msg;
  960. fatal_msg << site.mFile << "(" << site.mLine << ") : error";
  961. writeToRecorders(site.mLevel, fatal_msg.str());
  962. }
  963. std::ostringstream prefix;
  964. switch (site.mLevel)
  965. {
  966. case LEVEL_DEBUG: prefix << "DEBUG: "; break;
  967. case LEVEL_INFO: prefix << "INFO: "; break;
  968. case LEVEL_WARN: prefix << "WARNING: "; break;
  969. case LEVEL_ERROR: prefix << "ERROR: "; break;
  970. default: prefix << "XXX: ";
  971. }
  972. Settings& s = Settings::get();
  973. if (s.mPrintLocation)
  974. {
  975. prefix << site.mFile << "(" << site.mLine << ") : ";
  976. }
  977. #if !LL_MSVC // DevStudio: __FUNCTION__ already includes the full class name
  978. std::string class_name = className(site.mClassInfo);
  979. static const std::string no_class_info = "LLError::NoClassInfo";
  980. if (class_name != no_class_info)
  981. {
  982. static const std::string anonymous = "(anonymous namespace)::";
  983. if (class_name.compare(0, 23, anonymous) == 0)
  984. {
  985. class_name = class_name.substr(23);
  986. }
  987. prefix << class_name << "::";
  988. }
  989. #endif
  990. prefix << site.mFunction << ": ";
  991. // Possible ONCE and SPARSE message prefixes. When 'false' is returned,
  992. // the log line must be discarded. HB
  993. if (!site.getPrefix(prefix, message))
  994. {
  995. return;
  996. }
  997. prefix << message;
  998. message = prefix.str();
  999. writeToRecorders(site.mLevel, message);
  1000. if (site.mLevel == LEVEL_ERROR)
  1001. {
  1002. // Do not call the crash function while being debugged, to avoid
  1003. // polluting the stack trace with that function call. HB
  1004. if (s.mCrashFunction && !sIsBeingDebugged)
  1005. {
  1006. s.mCrashFunction(message);
  1007. }
  1008. else
  1009. {
  1010. LL_ERROR_CRASH;
  1011. }
  1012. }
  1013. }
  1014. Settings* saveAndResetSettings()
  1015. {
  1016. return Settings::saveAndReset();
  1017. }
  1018. void restoreSettings(Settings* s)
  1019. {
  1020. return Settings::restore(s);
  1021. }
  1022. void replaceChar(std::string& s, char old, char replacement)
  1023. {
  1024. for (size_t i = 0, len = s.length(); i < len; ++i)
  1025. {
  1026. if (s[i] == old)
  1027. {
  1028. s[i] = replacement;
  1029. }
  1030. }
  1031. }
  1032. LL_NO_INLINE std::string utcTime(bool print_ms)
  1033. {
  1034. // We cache the last timestamp string and return it when this function
  1035. // is called again soon enough for that string to stay unchanged. HB
  1036. static bool last_print_ms = false;
  1037. static time_t last_time = 0;
  1038. static S32 last_ms = 0;
  1039. static char time_str[64];
  1040. if (print_ms)
  1041. {
  1042. auto sysclock = std::chrono::system_clock::now();
  1043. time_t now = std::chrono::system_clock::to_time_t(sysclock);
  1044. static const auto chrono_ms = std::chrono::milliseconds(1);
  1045. S32 ms = (sysclock.time_since_epoch() / chrono_ms) % 1000;
  1046. if (ms != last_ms || now != last_time || last_print_ms != print_ms)
  1047. {
  1048. last_print_ms = print_ms;
  1049. last_time = now;
  1050. last_ms = ms;
  1051. strftime(time_str, 64, "%Y-%m-%d %H:%M:%S", gmtime(&now));
  1052. strcat(time_str, llformat(".%03dZ", ms).c_str());
  1053. }
  1054. }
  1055. else
  1056. {
  1057. time_t now = time(NULL);
  1058. if (now != last_time || last_print_ms != print_ms)
  1059. {
  1060. last_print_ms = print_ms;
  1061. last_time = now;
  1062. time_str[0] = '\0';
  1063. strftime(time_str, 64, "%Y-%m-%d %H:%M:%SZ", gmtime(&now));
  1064. }
  1065. }
  1066. return time_str;
  1067. }
  1068. }