llerror.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:29k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llerror.cpp
  3.  * @date   December 2006
  4.  * @brief error message system
  5.  *
  6.  * $LicenseInfo:firstyear=2006&license=viewergpl$
  7.  * 
  8.  * Copyright (c) 2006-2010, Linden Research, Inc.
  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 "llerror.h"
  35. #include "llerrorcontrol.h"
  36. #include <cctype>
  37. #ifdef __GNUC__
  38. # include <cxxabi.h>
  39. #endif // __GNUC__
  40. #include <sstream>
  41. #if !LL_WINDOWS
  42. # include <syslog.h>
  43. # include <unistd.h>
  44. #endif // !LL_WINDOWS
  45. #include <vector>
  46. #include "llapp.h"
  47. #include "llapr.h"
  48. #include "llfile.h"
  49. #include "lllivefile.h"
  50. #include "llsd.h"
  51. #include "llsdserialize.h"
  52. #include "llstl.h"
  53. #include "lltimer.h"
  54. namespace {
  55. #if !LL_WINDOWS
  56. class RecordToSyslog : public LLError::Recorder
  57. {
  58. public:
  59. RecordToSyslog(const std::string& identity)
  60. : mIdentity(identity)
  61. {
  62. openlog(mIdentity.c_str(), LOG_CONS|LOG_PID, LOG_LOCAL0);
  63. // we need to set the string from a local copy of the string
  64. // since apparanetly openlog expects the const char* to remain
  65. // valid even after it returns (presumably until closelog)
  66. }
  67. ~RecordToSyslog()
  68. {
  69. closelog();
  70. }
  71. virtual void recordMessage(LLError::ELevel level,
  72. const std::string& message)
  73. {
  74. int syslogPriority = LOG_CRIT;
  75. switch (level) {
  76. case LLError::LEVEL_DEBUG: syslogPriority = LOG_DEBUG; break;
  77. case LLError::LEVEL_INFO: syslogPriority = LOG_INFO; break;
  78. case LLError::LEVEL_WARN: syslogPriority = LOG_WARNING; break;
  79. case LLError::LEVEL_ERROR: syslogPriority = LOG_CRIT; break;
  80. default: syslogPriority = LOG_CRIT;
  81. }
  82. syslog(syslogPriority, "%s", message.c_str());
  83. }
  84. private:
  85. std::string mIdentity;
  86. };
  87. #endif
  88. class RecordToFile : public LLError::Recorder
  89. {
  90. public:
  91. RecordToFile(const std::string& filename)
  92. {
  93. mFile.open(filename, llofstream::out | llofstream::app);
  94. if (!mFile)
  95. {
  96. llinfos << "Error setting log file to " << filename << llendl;
  97. }
  98. }
  99. ~RecordToFile()
  100. {
  101. mFile.close();
  102. }
  103. bool okay() { return mFile; }
  104. virtual bool wantsTime() { return true; }
  105. virtual void recordMessage(LLError::ELevel level,
  106. const std::string& message)
  107. {
  108. mFile << message << std::endl;
  109. // mFile.flush();
  110. // *FIX: should we do this? 
  111. }
  112. private:
  113. llofstream mFile;
  114. };
  115. class RecordToStderr : public LLError::Recorder
  116. {
  117. public:
  118. RecordToStderr(bool timestamp) : mTimestamp(timestamp), mUseANSI(ANSI_PROBE) { }
  119. virtual bool wantsTime() { return mTimestamp; }
  120. virtual void recordMessage(LLError::ELevel level,
  121.    const std::string& message)
  122. {
  123. if (ANSI_PROBE == mUseANSI)
  124. mUseANSI = (checkANSI() ? ANSI_YES : ANSI_NO);
  125. if (ANSI_YES == mUseANSI)
  126. {
  127. // Default all message levels to bold so we can distinguish our own messages from those dumped by subprocesses and libraries.
  128. colorANSI("1"); // bold
  129. switch (level) {
  130. case LLError::LEVEL_ERROR:
  131. colorANSI("31"); // red
  132. break;
  133. case LLError::LEVEL_WARN:
  134. colorANSI("34"); // blue
  135. break;
  136. case LLError::LEVEL_DEBUG:
  137. colorANSI("35"); // magenta
  138. break;
  139. default:
  140. break;
  141. }
  142. }
  143. fprintf(stderr, "%sn", message.c_str());
  144. if (ANSI_YES == mUseANSI) colorANSI("0"); // reset
  145. }
  146. private:
  147. bool mTimestamp;
  148. enum ANSIState {ANSI_PROBE, ANSI_YES, ANSI_NO};
  149. ANSIState mUseANSI;
  150. void colorANSI(const std::string color)
  151. {
  152. // ANSI color code escape sequence
  153. fprintf(stderr, "33[%sm", color.c_str() );
  154. };
  155. bool checkANSI(void)
  156. {
  157. #if LL_LINUX || LL_DARWIN
  158. // Check whether it's okay to use ANSI; if stderr is
  159. // a tty then we assume yes.  Can be turned off with
  160. // the LL_NO_ANSI_COLOR env var.
  161. return (0 != isatty(2)) &&
  162. (NULL == getenv("LL_NO_ANSI_COLOR"));
  163. #endif // LL_LINUX
  164. return false;
  165. };
  166. };
  167. class RecordToFixedBuffer : public LLError::Recorder
  168. {
  169. public:
  170. RecordToFixedBuffer(LLLineBuffer* buffer) : mBuffer(buffer) { }
  171. virtual void recordMessage(LLError::ELevel level,
  172.    const std::string& message)
  173. {
  174. mBuffer->addLine(message);
  175. }
  176. private:
  177. LLLineBuffer* mBuffer;
  178. };
  179. #if LL_WINDOWS
  180. class RecordToWinDebug: public LLError::Recorder
  181. {
  182. public:
  183. virtual void recordMessage(LLError::ELevel level,
  184.    const std::string& message)
  185. {
  186. llutf16string utf16str =
  187. wstring_to_utf16str(utf8str_to_wstring(message));
  188. utf16str += 'n';
  189. OutputDebugString(utf16str.c_str());
  190. }
  191. };
  192. #endif
  193. }
  194. namespace
  195. {
  196. std::string className(const std::type_info& type)
  197. {
  198. #ifdef __GNUC__
  199. // GCC: type_info::name() returns a mangled class name, must demangle
  200. static size_t abi_name_len = 100;
  201. static char* abi_name_buf = (char*)malloc(abi_name_len);
  202. // warning: above is voodoo inferred from the GCC manual,
  203. // do NOT change
  204. int status;
  205. // We don't use status, and shouldn't have to pass apointer to it
  206. // but gcc 3.3 libstc++'s implementation of demangling is broken
  207. // and fails without.
  208. char* name = abi::__cxa_demangle(type.name(),
  209. abi_name_buf, &abi_name_len, &status);
  210. // this call can realloc the abi_name_buf pointer (!)
  211. return name ? name : type.name();
  212. #elif LL_WINDOWS
  213. // DevStudio: type_info::name() includes the text "class " at the start
  214. static const std::string class_prefix = "class ";
  215. std::string name = type.name();
  216. std::string::size_type p = name.find(class_prefix);
  217. if (p == std::string::npos)
  218. {
  219. return name;
  220. }
  221. return name.substr(p + class_prefix.size());
  222. #else
  223. return type.name();
  224. #endif
  225. }
  226. std::string functionName(const std::string& preprocessor_name)
  227. {
  228. #if LL_WINDOWS
  229. // DevStudio: the __FUNCTION__ macro string includes
  230. // the type and/or namespace prefixes
  231. std::string::size_type p = preprocessor_name.rfind(':');
  232. if (p == std::string::npos)
  233. {
  234. return preprocessor_name;
  235. }
  236. return preprocessor_name.substr(p + 1);
  237. #else
  238. return preprocessor_name;
  239. #endif
  240. }
  241. class LogControlFile : public LLLiveFile
  242. {
  243. LOG_CLASS(LogControlFile);
  244. public:
  245. static LogControlFile& fromDirectory(const std::string& dir);
  246. virtual bool loadFile();
  247. private:
  248. LogControlFile(const std::string &filename)
  249. : LLLiveFile(filename)
  250. { }
  251. };
  252. LogControlFile& LogControlFile::fromDirectory(const std::string& dir)
  253. {
  254. std::string dirBase = dir + "/";
  255. // NB: We have no abstraction in llcommon  for the "proper"
  256. // delimiter but it turns out that "/" works on all three platforms
  257. std::string file = dirBase + "logcontrol-dev.xml";
  258. llstat stat_info;
  259. if (LLFile::stat(file, &stat_info)) {
  260. // NB: stat returns non-zero if it can't read the file, for example
  261. // if it doesn't exist.  LLFile has no better abstraction for 
  262. // testing for file existence.
  263. file = dirBase + "logcontrol.xml";
  264. }
  265. return * new LogControlFile(file);
  266. // NB: This instance is never freed
  267. }
  268. bool LogControlFile::loadFile()
  269. {
  270. LLSD configuration;
  271. {
  272. llifstream file(filename());
  273. if (file.is_open())
  274. {
  275. LLSDSerialize::fromXML(configuration, file);
  276. }
  277. if (configuration.isUndefined())
  278. {
  279. llwarns << filename() << " missing, ill-formed,"
  280. " or simply undefined; not changing configuration"
  281. << llendl;
  282. return false;
  283. }
  284. }
  285. LLError::configure(configuration);
  286. llinfos << "logging reconfigured from " << filename() << llendl;
  287. return true;
  288. }
  289. typedef std::map<std::string, LLError::ELevel> LevelMap;
  290. typedef std::vector<LLError::Recorder*> Recorders;
  291. typedef std::vector<LLError::CallSite*> CallSiteVector;
  292. class Globals
  293. {
  294. public:
  295. std::ostringstream messageStream;
  296. bool messageStreamInUse;
  297. void addCallSite(LLError::CallSite&);
  298. void invalidateCallSites();
  299. static Globals& get();
  300. // return the one instance of the globals
  301. private:
  302. CallSiteVector callSites;
  303. Globals()
  304. : messageStreamInUse(false)
  305. { }
  306. };
  307. void Globals::addCallSite(LLError::CallSite& site)
  308. {
  309. callSites.push_back(&site);
  310. }
  311. void Globals::invalidateCallSites()
  312. {
  313. for (CallSiteVector::const_iterator i = callSites.begin();
  314.  i != callSites.end();
  315.  ++i)
  316. {
  317. (*i)->invalidate();
  318. }
  319. callSites.clear();
  320. }
  321. Globals& Globals::get()
  322. {
  323. /* This pattern, of returning a reference to a static function
  324.    variable, is to ensure that this global is constructed before
  325.    it is used, no matter what the global initializeation sequence
  326.    is.
  327.    See C++ FAQ Lite, sections 10.12 through 10.14
  328. */
  329. static Globals* globals = new Globals;
  330. return *globals;
  331. }
  332. }
  333. namespace LLError
  334. {
  335. class Settings
  336. {
  337. public:
  338. bool printLocation;
  339. LLError::ELevel defaultLevel;
  340. LevelMap functionLevelMap;
  341. LevelMap classLevelMap;
  342. LevelMap fileLevelMap;
  343. LevelMap tagLevelMap;
  344. std::map<std::string, unsigned int> uniqueLogMessages;
  345. LLError::FatalFunction crashFunction;
  346. LLError::TimeFunction timeFunction;
  347. Recorders recorders;
  348. Recorder* fileRecorder;
  349. Recorder* fixedBufferRecorder;
  350. std::string fileRecorderFileName;
  351. int shouldLogCallCounter;
  352. static Settings& get();
  353. static void reset();
  354. static Settings* saveAndReset();
  355. static void restore(Settings*);
  356. private:
  357. Settings()
  358. : printLocation(false),
  359. defaultLevel(LLError::LEVEL_DEBUG),
  360. crashFunction(),
  361. timeFunction(NULL),
  362. fileRecorder(NULL),
  363. fixedBufferRecorder(NULL),
  364. shouldLogCallCounter(0)
  365. { }
  366. ~Settings()
  367. {
  368. for_each(recorders.begin(), recorders.end(),
  369.  DeletePointer());
  370. }
  371. static Settings*& getPtr();
  372. };
  373. Settings& Settings::get()
  374. {
  375. Settings* p = getPtr();
  376. if (!p)
  377. {
  378. reset();
  379. p = getPtr();
  380. }
  381. return *p;
  382. }
  383. void Settings::reset()
  384. {
  385. Globals::get().invalidateCallSites();
  386. Settings*& p = getPtr();
  387. delete p;
  388. p = new Settings();
  389. }
  390. Settings* Settings::saveAndReset()
  391. {
  392. Globals::get().invalidateCallSites();
  393. Settings*& p = getPtr();
  394. Settings* originalSettings = p;
  395. p = new Settings();
  396. return originalSettings;
  397. }
  398. void Settings::restore(Settings* originalSettings)
  399. {
  400. Globals::get().invalidateCallSites();
  401. Settings*& p = getPtr();
  402. delete p;
  403. p = originalSettings;
  404. }
  405. Settings*& Settings::getPtr()
  406. {
  407. static Settings* currentSettings = NULL;
  408. return currentSettings;
  409. }
  410. }
  411. namespace LLError
  412. {
  413. CallSite::CallSite(ELevel level,
  414. const char* file,
  415. int line,
  416. const std::type_info& class_info, 
  417. const char* function, 
  418. const char* broadTag, 
  419. const char* narrowTag,
  420. bool printOnce)
  421. : mLevel(level), mFile(file), mLine(line),
  422.   mClassInfo(class_info), mFunction(function),
  423.   mCached(false), mShouldLog(false), 
  424.   mBroadTag(broadTag), mNarrowTag(narrowTag), mPrintOnce(printOnce)
  425. { }
  426. void CallSite::invalidate()
  427. { mCached = false; }
  428. }
  429. namespace
  430. {
  431. bool shouldLogToStderr()
  432. {
  433. #if LL_DARWIN
  434. // On Mac OS X, stderr from apps launched from the Finder goes to the
  435. // console log.  It's generally considered bad form to spam too much
  436. // there.
  437. // If stdin is a tty, assume the user launched from the command line and
  438. // therefore wants to see stderr.  Otherwise, assume we've been launched
  439. // from the finder and shouldn't spam stderr.
  440. return isatty(0);
  441. #else
  442. return true;
  443. #endif
  444. }
  445. bool stderrLogWantsTime()
  446. {
  447. #if LL_WINDOWS
  448. return false;
  449. #else
  450. return true;
  451. #endif
  452. }
  453. void commonInit(const std::string& dir)
  454. {
  455. LLError::Settings::reset();
  456. LLError::setDefaultLevel(LLError::LEVEL_INFO);
  457. LLError::setFatalFunction(LLError::crashAndLoop);
  458. LLError::setTimeFunction(LLError::utcTime);
  459. if (shouldLogToStderr())
  460. {
  461. LLError::addRecorder(new RecordToStderr(stderrLogWantsTime()));
  462. }
  463. #if LL_WINDOWS
  464. LLError::addRecorder(new RecordToWinDebug);
  465. #endif
  466. LogControlFile& e = LogControlFile::fromDirectory(dir);
  467. // NOTE: We want to explicitly load the file before we add it to the event timer
  468. // that checks for changes to the file.  Else, we're not actually loading the file yet,
  469. // and most of the initialization happens without any attention being paid to the
  470. // log control file.  Not to mention that when it finally gets checked later,
  471. // all log statements that have been evaluated already become dirty and need to be
  472. // evaluated for printing again.  So, make sure to call checkAndReload()
  473. // before addToEventTimer().
  474. e.checkAndReload();
  475. e.addToEventTimer();
  476. }
  477. }
  478. namespace LLError
  479. {
  480. void initForServer(const std::string& identity)
  481. {
  482. std::string dir = "/opt/linden/etc";
  483. if (LLApp::instance())
  484. {
  485. dir = LLApp::instance()->getOption("configdir").asString();
  486. }
  487. commonInit(dir);
  488. #if !LL_WINDOWS
  489. addRecorder(new RecordToSyslog(identity));
  490. #endif
  491. }
  492. void initForApplication(const std::string& dir)
  493. {
  494. commonInit(dir);
  495. }
  496. void setPrintLocation(bool print)
  497. {
  498. Settings& s = Settings::get();
  499. s.printLocation = print;
  500. }
  501. void setFatalFunction(const FatalFunction& f)
  502. {
  503. Settings& s = Settings::get();
  504. s.crashFunction = f;
  505. }
  506.     FatalFunction getFatalFunction()
  507.     {
  508.         Settings& s = Settings::get();
  509.         return s.crashFunction;
  510.     }
  511. void setTimeFunction(TimeFunction f)
  512. {
  513. Settings& s = Settings::get();
  514. s.timeFunction = f;
  515. }
  516. void setDefaultLevel(ELevel level)
  517. {
  518. Globals& g = Globals::get();
  519. Settings& s = Settings::get();
  520. g.invalidateCallSites();
  521. s.defaultLevel = level;
  522. }
  523. void setFunctionLevel(const std::string& function_name, ELevel level)
  524. {
  525. Globals& g = Globals::get();
  526. Settings& s = Settings::get();
  527. g.invalidateCallSites();
  528. s.functionLevelMap[function_name] = level;
  529. }
  530. void setClassLevel(const std::string& class_name, ELevel level)
  531. {
  532. Globals& g = Globals::get();
  533. Settings& s = Settings::get();
  534. g.invalidateCallSites();
  535. s.classLevelMap[class_name] = level;
  536. }
  537. void setFileLevel(const std::string& file_name, ELevel level)
  538. {
  539. Globals& g = Globals::get();
  540. Settings& s = Settings::get();
  541. g.invalidateCallSites();
  542. s.fileLevelMap[file_name] = level;
  543. }
  544. void setTagLevel(const std::string& tag_name, ELevel level)
  545. {
  546. Globals& g = Globals::get();
  547. Settings& s = Settings::get();
  548. g.invalidateCallSites();
  549. s.tagLevelMap[tag_name] = level;
  550. }
  551. }
  552. namespace {
  553. LLError::ELevel decodeLevel(std::string name)
  554. {
  555. static LevelMap level_names;
  556. if (level_names.empty())
  557. {
  558. level_names["ALL"] = LLError::LEVEL_ALL;
  559. level_names["DEBUG"] = LLError::LEVEL_DEBUG;
  560. level_names["INFO"] = LLError::LEVEL_INFO;
  561. level_names["WARN"] = LLError::LEVEL_WARN;
  562. level_names["ERROR"] = LLError::LEVEL_ERROR;
  563. level_names["NONE"] = LLError::LEVEL_NONE;
  564. }
  565. std::transform(name.begin(), name.end(), name.begin(), toupper);
  566. LevelMap::const_iterator i = level_names.find(name);
  567. if (i == level_names.end())
  568. {
  569. llwarns << "unrecognized logging level: '" << name << "'" << llendl;
  570. return LLError::LEVEL_INFO;
  571. }
  572. return i->second;
  573. }
  574. void setLevels(LevelMap& map, const LLSD& list, LLError::ELevel level)
  575. {
  576. LLSD::array_const_iterator i, end;
  577. for (i = list.beginArray(), end = list.endArray(); i != end; ++i)
  578. {
  579. map[*i] = level;
  580. }
  581. }
  582. }
  583. namespace LLError
  584. {
  585. void configure(const LLSD& config)
  586. {
  587. Globals& g = Globals::get();
  588. Settings& s = Settings::get();
  589. g.invalidateCallSites();
  590. s.functionLevelMap.clear();
  591. s.classLevelMap.clear();
  592. s.fileLevelMap.clear();
  593. s.tagLevelMap.clear();
  594. s.uniqueLogMessages.clear();
  595. setPrintLocation(config["print-location"]);
  596. setDefaultLevel(decodeLevel(config["default-level"]));
  597. LLSD sets = config["settings"];
  598. LLSD::array_const_iterator a, end;
  599. for (a = sets.beginArray(), end = sets.endArray(); a != end; ++a)
  600. {
  601. const LLSD& entry = *a;
  602. ELevel level = decodeLevel(entry["level"]);
  603. setLevels(s.functionLevelMap, entry["functions"], level);
  604. setLevels(s.classLevelMap, entry["classes"], level);
  605. setLevels(s.fileLevelMap, entry["files"], level);
  606. setLevels(s.tagLevelMap, entry["tags"], level);
  607. }
  608. }
  609. }
  610. namespace LLError
  611. {
  612. Recorder::~Recorder()
  613. { }
  614. // virtual
  615. bool Recorder::wantsTime()
  616. { return false; }
  617. void addRecorder(Recorder* recorder)
  618. {
  619. if (recorder == NULL)
  620. {
  621. return;
  622. }
  623. Settings& s = Settings::get();
  624. s.recorders.push_back(recorder);
  625. }
  626. void removeRecorder(Recorder* recorder)
  627. {
  628. if (recorder == NULL)
  629. {
  630. return;
  631. }
  632. Settings& s = Settings::get();
  633. s.recorders.erase(
  634. std::remove(s.recorders.begin(), s.recorders.end(), recorder),
  635. s.recorders.end());
  636. }
  637. }
  638. namespace LLError
  639. {
  640. void logToFile(const std::string& file_name)
  641. {
  642. LLError::Settings& s = LLError::Settings::get();
  643. removeRecorder(s.fileRecorder);
  644. delete s.fileRecorder;
  645. s.fileRecorder = NULL;
  646. s.fileRecorderFileName.clear();
  647. if (file_name.empty())
  648. {
  649. return;
  650. }
  651. RecordToFile* f = new RecordToFile(file_name);
  652. if (!f->okay())
  653. {
  654. delete f;
  655. return;
  656. }
  657. s.fileRecorderFileName = file_name;
  658. s.fileRecorder = f;
  659. addRecorder(f);
  660. }
  661. void logToFixedBuffer(LLLineBuffer* fixedBuffer)
  662. {
  663. LLError::Settings& s = LLError::Settings::get();
  664. removeRecorder(s.fixedBufferRecorder);
  665. delete s.fixedBufferRecorder;
  666. s.fixedBufferRecorder = NULL;
  667. if (!fixedBuffer)
  668. {
  669. return;
  670. }
  671. s.fixedBufferRecorder = new RecordToFixedBuffer(fixedBuffer);
  672. addRecorder(s.fixedBufferRecorder);
  673. }
  674. std::string logFileName()
  675. {
  676. LLError::Settings& s = LLError::Settings::get();
  677. return s.fileRecorderFileName;
  678. }
  679. }
  680. namespace
  681. {
  682. void writeToRecorders(LLError::ELevel level, const std::string& message)
  683. {
  684. LLError::Settings& s = LLError::Settings::get();
  685. std::string messageWithTime;
  686. for (Recorders::const_iterator i = s.recorders.begin();
  687. i != s.recorders.end();
  688. ++i)
  689. {
  690. LLError::Recorder* r = *i;
  691. if (r->wantsTime()  &&  s.timeFunction != NULL)
  692. {
  693. if (messageWithTime.empty())
  694. {
  695. messageWithTime = s.timeFunction() + " " + message;
  696. }
  697. r->recordMessage(level, messageWithTime);
  698. }
  699. else
  700. {
  701. r->recordMessage(level, message);
  702. }
  703. }
  704. }
  705. }
  706. /*
  707. Recorder formats:
  708. $type = "ERROR" | "WARNING" | "ALERT" | "INFO" | "DEBUG"
  709. $loc = "$file($line)"
  710. $msg = "$loc : " if FATAL or printing loc
  711. "" otherwise
  712. $msg += "$type: "
  713. $msg += contents of stringstream
  714. $time = "%Y-%m-%dT%H:%M:%SZ" if UTC
  715.  or "%Y-%m-%dT%H:%M:%S %Z" if local
  716. syslog: "$msg"
  717. file: "$time $msgn"
  718. stderr: "$time $msgn" except on windows, "$msgn"
  719. fixedbuf: "$msg"
  720. winddebug: "$msgn"
  721. Note: if FATAL, an additional line gets logged first, with $msg set to
  722. "$loc : error"
  723. You get:
  724. llfoo.cpp(42) : error
  725. llfoo.cpp(42) : ERROR: something
  726. */
  727. namespace {
  728. bool checkLevelMap(const LevelMap& map, const std::string& key,
  729. LLError::ELevel& level)
  730. {
  731. LevelMap::const_iterator i = map.find(key);
  732. if (i == map.end())
  733. {
  734. return false;
  735. }
  736. level = i->second;
  737. return true;
  738. }
  739. class LogLock
  740. {
  741. public:
  742. LogLock();
  743. ~LogLock();
  744. bool ok() const { return mOK; }
  745. private:
  746. bool mLocked;
  747. bool mOK;
  748. };
  749. LogLock::LogLock()
  750. : mLocked(false), mOK(false)
  751. {
  752. if (!gLogMutexp)
  753. {
  754. mOK = true;
  755. return;
  756. }
  757. const int MAX_RETRIES = 5;
  758. for (int attempts = 0; attempts < MAX_RETRIES; ++attempts)
  759. {
  760. apr_status_t s = apr_thread_mutex_trylock(gLogMutexp);
  761. if (!APR_STATUS_IS_EBUSY(s))
  762. {
  763. mLocked = true;
  764. mOK = true;
  765. return;
  766. }
  767. ms_sleep(1);
  768. //apr_thread_yield();
  769. // Just yielding won't necessarily work, I had problems with
  770. // this on Linux - doug 12/02/04
  771. }
  772. // We're hosed, we can't get the mutex.  Blah.
  773. std::cerr << "LogLock::LogLock: failed to get mutex for log"
  774. << std::endl;
  775. }
  776. LogLock::~LogLock()
  777. {
  778. if (mLocked)
  779. {
  780. apr_thread_mutex_unlock(gLogMutexp);
  781. }
  782. }
  783. }
  784. namespace LLError
  785. {
  786. bool Log::shouldLog(CallSite& site)
  787. {
  788. LogLock lock;
  789. if (!lock.ok())
  790. {
  791. return false;
  792. }
  793. Globals& g = Globals::get();
  794. Settings& s = Settings::get();
  795. s.shouldLogCallCounter += 1;
  796. std::string class_name = className(site.mClassInfo);
  797. std::string function_name = functionName(site.mFunction);
  798. if (site.mClassInfo != typeid(NoClassInfo))
  799. {
  800. function_name = class_name + "::" + function_name;
  801. }
  802. ELevel compareLevel = s.defaultLevel;
  803. // The most specific match found will be used as the log level,
  804. // since the computation short circuits.
  805. // So, in increasing order of importance:
  806. // Default < Broad Tag < File < Class < Function < Narrow Tag
  807. ((site.mNarrowTag != NULL) ? checkLevelMap(s.tagLevelMap, site.mNarrowTag, compareLevel) : false)
  808. || checkLevelMap(s.functionLevelMap, function_name, compareLevel)
  809. || checkLevelMap(s.classLevelMap, class_name, compareLevel)
  810. || checkLevelMap(s.fileLevelMap, abbreviateFile(site.mFile), compareLevel)
  811. || ((site.mBroadTag != NULL) ? checkLevelMap(s.tagLevelMap, site.mBroadTag, compareLevel) : false);
  812. site.mCached = true;
  813. g.addCallSite(site);
  814. return site.mShouldLog = site.mLevel >= compareLevel;
  815. }
  816. std::ostringstream* Log::out()
  817. {
  818. LogLock lock;
  819. if (lock.ok())
  820. {
  821. Globals& g = Globals::get();
  822. if (!g.messageStreamInUse)
  823. {
  824. g.messageStreamInUse = true;
  825. return &g.messageStream;
  826. }
  827. }
  828. return new std::ostringstream;
  829. }
  830. void Log::flush(std::ostringstream* out, char* message)
  831.     {
  832.        LogLock lock;
  833.        if (!lock.ok())
  834.        {
  835.            return;
  836.        }
  837.        
  838.    if(strlen(out->str().c_str()) < 128)
  839.    {
  840.    strcpy(message, out->str().c_str());
  841.    }
  842.    else
  843.    {
  844.    strncpy(message, out->str().c_str(), 127);
  845.    message[127] = '' ;
  846.    }
  847.    
  848.    Globals& g = Globals::get();
  849.        if (out == &g.messageStream)
  850.        {
  851.            g.messageStream.clear();
  852.            g.messageStream.str("");
  853.            g.messageStreamInUse = false;
  854.        }
  855.        else
  856.        {
  857.            delete out;
  858.        }
  859.    return ;
  860.     }
  861. void Log::flush(std::ostringstream* out, const CallSite& site)
  862. {
  863. LogLock lock;
  864. if (!lock.ok())
  865. {
  866. return;
  867. }
  868. Globals& g = Globals::get();
  869. Settings& s = Settings::get();
  870. std::string message = out->str();
  871. if (out == &g.messageStream)
  872. {
  873. g.messageStream.clear();
  874. g.messageStream.str("");
  875. g.messageStreamInUse = false;
  876. }
  877. else
  878. {
  879. delete out;
  880. }
  881. if (site.mLevel == LEVEL_ERROR)
  882. {
  883. std::ostringstream fatalMessage;
  884. fatalMessage << abbreviateFile(site.mFile)
  885. << "(" << site.mLine << ") : error";
  886. writeToRecorders(site.mLevel, fatalMessage.str());
  887. }
  888. std::ostringstream prefix;
  889. switch (site.mLevel)
  890. {
  891. case LEVEL_DEBUG: prefix << "DEBUG: "; break;
  892. case LEVEL_INFO: prefix << "INFO: "; break;
  893. case LEVEL_WARN: prefix << "WARNING: "; break;
  894. case LEVEL_ERROR: prefix << "ERROR: "; break;
  895. default: prefix << "XXX: "; break;
  896. };
  897. if (s.printLocation)
  898. {
  899. prefix << abbreviateFile(site.mFile)
  900. << "(" << site.mLine << ") : ";
  901. }
  902. #if LL_WINDOWS
  903. // DevStudio: __FUNCTION__ already includes the full class name
  904. #else
  905. if (site.mClassInfo != typeid(NoClassInfo))
  906. {
  907. prefix << className(site.mClassInfo) << "::";
  908. }
  909. #endif
  910. prefix << site.mFunction << ": ";
  911. if (site.mPrintOnce)
  912. {
  913. std::map<std::string, unsigned int>::iterator messageIter = s.uniqueLogMessages.find(message);
  914. if (messageIter != s.uniqueLogMessages.end())
  915. {
  916. messageIter->second++;
  917. unsigned int num_messages = messageIter->second;
  918. if (num_messages == 10 || num_messages == 50 || (num_messages % 100) == 0)
  919. {
  920. prefix << "ONCE (" << num_messages << "th time seen): ";
  921. else
  922. {
  923. return;
  924. }
  925. }
  926. else 
  927. {
  928. prefix << "ONCE: ";
  929. s.uniqueLogMessages[message] = 1;
  930. }
  931. }
  932. prefix << message;
  933. message = prefix.str();
  934. writeToRecorders(site.mLevel, message);
  935. if (site.mLevel == LEVEL_ERROR  &&  s.crashFunction)
  936. {
  937. s.crashFunction(message);
  938. }
  939. }
  940. }
  941. namespace LLError
  942. {
  943. Settings* saveAndResetSettings()
  944. {
  945. return Settings::saveAndReset();
  946. }
  947. void restoreSettings(Settings* s)
  948. {
  949. return Settings::restore(s);
  950. }
  951. std::string removePrefix(std::string& s, const std::string& p)
  952. {
  953. std::string::size_type where = s.find(p);
  954. if (where == std::string::npos)
  955. {
  956. return s;
  957. }
  958. return std::string(s, where + p.size());
  959. }
  960. void replaceChar(std::string& s, char old, char replacement)
  961. {
  962. std::string::size_type i = 0;
  963. std::string::size_type len = s.length();
  964. for ( ; i < len; i++ )
  965. {
  966. if (s[i] == old)
  967. {
  968. s[i] = replacement;
  969. }
  970. }
  971. }
  972. std::string abbreviateFile(const std::string& filePath)
  973. {
  974. std::string f = filePath;
  975. #if LL_WINDOWS
  976. replaceChar(f, '\', '/');
  977. #endif
  978. static std::string indra_prefix = "indra/";
  979. f = removePrefix(f, indra_prefix);
  980. #if LL_DARWIN
  981. static std::string newview_prefix = "newview/../";
  982. f = removePrefix(f, newview_prefix);
  983. #endif
  984. return f;
  985. }
  986. int shouldLogCallCount()
  987. {
  988. Settings& s = Settings::get();
  989. return s.shouldLogCallCounter;
  990. }
  991. #if LL_WINDOWS
  992. // VC80 was optimizing the error away.
  993. #pragma optimize("", off)
  994. #endif
  995. void crashAndLoop(const std::string& message)
  996. {
  997. // Now, we go kaboom!
  998. int* make_me_crash = NULL;
  999. *make_me_crash = 0;
  1000. while(true)
  1001. {
  1002. // Loop forever, in case the crash didn't work?
  1003. }
  1004. // this is an attempt to let Coverity and other semantic scanners know that this function won't be returning ever.
  1005. exit(EXIT_FAILURE);
  1006. }
  1007. #if LL_WINDOWS
  1008. #pragma optimize("", on)
  1009. #endif
  1010. std::string utcTime()
  1011. {
  1012. time_t now = time(NULL);
  1013. const size_t BUF_SIZE = 64;
  1014. char time_str[BUF_SIZE]; /* Flawfinder: ignore */
  1015. int chars = strftime(time_str, BUF_SIZE, 
  1016.   "%Y-%m-%dT%H:%M:%SZ",
  1017.   gmtime(&now));
  1018. return chars ? time_str : "time error";
  1019. }
  1020. }
  1021. namespace LLError
  1022. {     
  1023. char** LLCallStacks::sBuffer = NULL ;
  1024. S32    LLCallStacks::sIndex  = 0 ;
  1025. class CallStacksLogLock
  1026. {
  1027. public:
  1028. CallStacksLogLock();
  1029. ~CallStacksLogLock();
  1030. bool ok() const { return mOK; }
  1031. private:
  1032. bool mLocked;
  1033. bool mOK;
  1034. };
  1035. CallStacksLogLock::CallStacksLogLock()
  1036. : mLocked(false), mOK(false)
  1037. {
  1038. if (!gCallStacksLogMutexp)
  1039. {
  1040. mOK = true;
  1041. return;
  1042. }
  1043. const int MAX_RETRIES = 5;
  1044. for (int attempts = 0; attempts < MAX_RETRIES; ++attempts)
  1045. {
  1046. apr_status_t s = apr_thread_mutex_trylock(gCallStacksLogMutexp);
  1047. if (!APR_STATUS_IS_EBUSY(s))
  1048. {
  1049. mLocked = true;
  1050. mOK = true;
  1051. return;
  1052. }
  1053. ms_sleep(1);
  1054. }
  1055. // We're hosed, we can't get the mutex.  Blah.
  1056. std::cerr << "CallStacksLogLock::CallStacksLogLock: failed to get mutex for log"
  1057. << std::endl;
  1058. }
  1059. CallStacksLogLock::~CallStacksLogLock()
  1060. {
  1061. if (mLocked)
  1062. {
  1063. apr_thread_mutex_unlock(gCallStacksLogMutexp);
  1064. }
  1065. }
  1066. //static
  1067.    void LLCallStacks::push(const char* function, const int line)
  1068.    {
  1069.    CallStacksLogLock lock;
  1070.        if (!lock.ok())
  1071.        {
  1072.            return;
  1073.        }
  1074.    if(!sBuffer)
  1075.    {
  1076.    sBuffer = new char*[512] ;
  1077.    sBuffer[0] = new char[512 * 128] ;
  1078.    for(S32 i = 1 ; i < 512 ; i++)
  1079.    {
  1080.    sBuffer[i] = sBuffer[i-1] + 128 ;
  1081.    }
  1082.    sIndex = 0 ;
  1083.    }
  1084.    if(sIndex > 511)
  1085.    {
  1086.    clear() ;
  1087.    }
  1088.    strcpy(sBuffer[sIndex], function) ;
  1089.    sprintf(sBuffer[sIndex] + strlen(function), " line: %d ", line) ;
  1090.    sIndex++ ;
  1091.    return ;
  1092.    }
  1093. //static
  1094.    std::ostringstream* LLCallStacks::insert(const char* function, const int line)
  1095.    {
  1096.        std::ostringstream* _out = LLError::Log::out();
  1097.    *_out << function << " line " << line << " " ;
  1098.              
  1099.    return _out ;
  1100.    }
  1101.    //static
  1102.    void LLCallStacks::end(std::ostringstream* _out)
  1103.    {
  1104.    CallStacksLogLock lock;
  1105.        if (!lock.ok())
  1106.        {
  1107.            return;
  1108.        }
  1109.    if(!sBuffer)
  1110.    {
  1111.    sBuffer = new char*[512] ;
  1112.    sBuffer[0] = new char[512 * 128] ;
  1113.    for(S32 i = 1 ; i < 512 ; i++)
  1114.    {
  1115.    sBuffer[i] = sBuffer[i-1] + 128 ;
  1116.    }
  1117.    sIndex = 0 ;
  1118.    }
  1119.    if(sIndex > 511)
  1120.    {
  1121.    clear() ;
  1122.    }
  1123.    LLError::Log::flush(_out, sBuffer[sIndex++]) ;    
  1124.    }
  1125.    //static
  1126.    void LLCallStacks::print()
  1127.    {
  1128.    CallStacksLogLock lock;
  1129.        if (!lock.ok())
  1130.        {
  1131.            return;
  1132.        }
  1133.        if(sIndex > 0)
  1134.        {
  1135.            llinfos << " ************* PRINT OUT LL CALL STACKS ************* " << llendl ;
  1136.            while(sIndex > 0)
  1137.            {                  
  1138.    sIndex-- ;
  1139.                llinfos << sBuffer[sIndex] << llendl ;
  1140.            }
  1141.            llinfos << " *************** END OF LL CALL STACKS *************** " << llendl ;
  1142.        }
  1143.    if(sBuffer)
  1144.    {
  1145.    delete[] sBuffer[0] ;
  1146.    delete[] sBuffer ;
  1147.    sBuffer = NULL ;
  1148.    }
  1149.    }
  1150.    //static
  1151.    void LLCallStacks::clear()
  1152.    {
  1153.        sIndex = 0 ;
  1154.    }
  1155. }