00001
00033 #include "linden_common.h"
00034
00035 #include "llerror.h"
00036 #include "llerrorcontrol.h"
00037
00038 #include <cctype>
00039 #ifdef __GNUC__
00040 # include <cxxabi.h>
00041 #endif // __GNUC__
00042 #include <sstream>
00043 #if !LL_WINDOWS
00044 # include <syslog.h>
00045 # include <unistd.h>
00046 #endif // !LL_WINDOWS
00047 #if LL_WINDOWS
00048 # include <windows.h>
00049 #endif // LL_WINDOWS
00050 #include <vector>
00051
00052 #include "llapp.h"
00053 #include "llapr.h"
00054 #include "llfile.h"
00055 #include "llfixedbuffer.h"
00056 #include "lllivefile.h"
00057 #include "llsd.h"
00058 #include "llsdserialize.h"
00059 #include "llstl.h"
00060
00061
00062 namespace {
00063 #if !LL_WINDOWS
00064 class RecordToSyslog : public LLError::Recorder
00065 {
00066 public:
00067 RecordToSyslog(const std::string& identity)
00068 : mIdentity(identity)
00069 {
00070 openlog(mIdentity.c_str(), LOG_CONS|LOG_PID, LOG_LOCAL0);
00071
00072
00073
00074 }
00075
00076 ~RecordToSyslog()
00077 {
00078 closelog();
00079 }
00080
00081 virtual void recordMessage(LLError::ELevel level,
00082 const std::string& message)
00083 {
00084 int syslogPriority = LOG_CRIT;
00085 switch (level) {
00086 case LLError::LEVEL_DEBUG: syslogPriority = LOG_DEBUG; break;
00087 case LLError::LEVEL_INFO: syslogPriority = LOG_INFO; break;
00088 case LLError::LEVEL_WARN: syslogPriority = LOG_WARNING; break;
00089 case LLError::LEVEL_ERROR: syslogPriority = LOG_CRIT; break;
00090 default: syslogPriority = LOG_CRIT;
00091 }
00092
00093 syslog(syslogPriority, "%s", message.c_str());
00094 }
00095 private:
00096 std::string mIdentity;
00097 };
00098 #endif
00099
00100 class RecordToFile : public LLError::Recorder
00101 {
00102 public:
00103 RecordToFile(const std::string& filename)
00104 {
00105 mFile.open(filename.c_str(), llofstream::out | llofstream::app);
00106 if (!mFile)
00107 {
00108 llinfos << "Error setting log file to " << filename << llendl;
00109 }
00110 }
00111
00112 ~RecordToFile()
00113 {
00114 mFile.close();
00115 }
00116
00117 bool okay() { return mFile; }
00118
00119 virtual bool wantsTime() { return true; }
00120
00121 virtual void recordMessage(LLError::ELevel level,
00122 const std::string& message)
00123 {
00124 mFile << message << std::endl;
00125
00126
00127 }
00128
00129 private:
00130 llofstream mFile;
00131 };
00132
00133
00134 class RecordToStderr : public LLError::Recorder
00135 {
00136 public:
00137 RecordToStderr(bool timestamp) : mTimestamp(timestamp), mUseANSI(ANSI_PROBE) { }
00138
00139 virtual bool wantsTime() { return mTimestamp; }
00140
00141 virtual void recordMessage(LLError::ELevel level,
00142 const std::string& message)
00143 {
00144 if (ANSI_PROBE == mUseANSI)
00145 mUseANSI = (checkANSI() ? ANSI_YES : ANSI_NO);
00146
00147 if (ANSI_YES == mUseANSI)
00148 {
00149
00150 colorANSI("1");
00151 switch (level) {
00152 case LLError::LEVEL_ERROR:
00153 colorANSI("31");
00154 break;
00155 case LLError::LEVEL_WARN:
00156 colorANSI("34");
00157 break;
00158 case LLError::LEVEL_DEBUG:
00159 colorANSI("35");
00160 break;
00161 default:
00162 break;
00163 }
00164 }
00165 fprintf(stderr, "%s\n", message.c_str());
00166 if (ANSI_YES == mUseANSI) colorANSI("0");
00167 }
00168
00169 private:
00170 bool mTimestamp;
00171 typedef enum ANSIState {ANSI_PROBE, ANSI_YES, ANSI_NO};
00172 ANSIState mUseANSI;
00173 void colorANSI(const std::string color)
00174 {
00175
00176 fprintf(stderr, "\033[%sm", color.c_str() );
00177 };
00178 bool checkANSI(void)
00179 {
00180 #if LL_LINUX || LL_DARWIN
00181
00182
00183
00184 return (0 != isatty(2)) &&
00185 (NULL == getenv("LL_NO_ANSI_COLOR"));
00186 #endif // LL_LINUX
00187 return false;
00188 };
00189 };
00190
00191 class RecordToFixedBuffer : public LLError::Recorder
00192 {
00193 public:
00194 RecordToFixedBuffer(LLFixedBuffer& buffer) : mBuffer(buffer) { }
00195
00196 virtual void recordMessage(LLError::ELevel level,
00197 const std::string& message)
00198 {
00199 mBuffer.addLine(message.c_str());
00200 }
00201
00202 private:
00203 LLFixedBuffer& mBuffer;
00204 };
00205
00206 #if LL_WINDOWS
00207 class RecordToWinDebug: public LLError::Recorder
00208 {
00209 public:
00210 virtual void recordMessage(LLError::ELevel level,
00211 const std::string& message)
00212 {
00213 llutf16string utf16str =
00214 wstring_to_utf16str(utf8str_to_wstring(message));
00215 utf16str += '\n';
00216 OutputDebugString(utf16str.c_str());
00217 }
00218 };
00219 #endif
00220 }
00221
00222
00223 namespace
00224 {
00225 std::string className(const std::type_info& type)
00226 {
00227 #ifdef __GNUC__
00228
00229
00230 static size_t abi_name_len = 100;
00231 static char* abi_name_buf = (char*)malloc(abi_name_len);
00232
00233
00234
00235 int status;
00236
00237
00238
00239
00240 char* name = abi::__cxa_demangle(type.name(),
00241 abi_name_buf, &abi_name_len, &status);
00242
00243
00244 return name ? name : type.name();
00245
00246 #elif LL_WINDOWS
00247
00248
00249 static const std::string class_prefix = "class ";
00250
00251 std::string name = type.name();
00252 std::string::size_type p = name.find(class_prefix);
00253 if (p == std::string::npos)
00254 {
00255 return name;
00256 }
00257
00258 return name.substr(p + class_prefix.size());
00259
00260 #else
00261 return type.name();
00262 #endif
00263 }
00264
00265 std::string functionName(const std::string& preprocessor_name)
00266 {
00267 #if LL_WINDOWS
00268
00269
00270
00271 std::string::size_type p = preprocessor_name.rfind(':');
00272 if (p == std::string::npos)
00273 {
00274 return preprocessor_name;
00275 }
00276 return preprocessor_name.substr(p + 1);
00277
00278 #else
00279 return preprocessor_name;
00280 #endif
00281 }
00282
00283
00284 class LogControlFile : public LLLiveFile
00285 {
00286 LOG_CLASS(LogControlFile);
00287
00288 public:
00289 static LogControlFile& fromDirectory(const std::string& dir);
00290
00291 virtual void loadFile();
00292
00293 private:
00294 LogControlFile(const std::string &filename)
00295 : LLLiveFile(filename)
00296 { }
00297 };
00298
00299 LogControlFile& LogControlFile::fromDirectory(const std::string& dir)
00300 {
00301 std::string dirBase = dir + "/";
00302
00303
00304
00305 std::string file = dirBase + "logcontrol-dev.xml";
00306
00307 llstat stat_info;
00308 if (LLFile::stat(file.c_str(), &stat_info)) {
00309
00310
00311
00312
00313 file = dirBase + "logcontrol.xml";
00314 }
00315 return * new LogControlFile(file);
00316
00317 }
00318
00319 void LogControlFile::loadFile()
00320 {
00321 LLSD configuration;
00322
00323 {
00324 llifstream file(filename().c_str());
00325 if (file.is_open())
00326 {
00327 LLSDSerialize::fromXML(configuration, file);
00328 }
00329
00330 if (configuration.isUndefined())
00331 {
00332 llwarns << filename() << " missing, ill-formed,"
00333 " or simply undefined; not changing configuration"
00334 << llendl;
00335 return;
00336 }
00337 }
00338
00339 LLError::configure(configuration);
00340 llinfos << "logging reconfigured from " << filename() << llendl;
00341 }
00342
00343
00344 typedef std::map<std::string, LLError::ELevel> LevelMap;
00345 typedef std::vector<LLError::Recorder*> Recorders;
00346 typedef std::vector<LLError::CallSite*> CallSiteVector;
00347
00348 class Globals
00349 {
00350 public:
00351 std::ostringstream messageStream;
00352 bool messageStreamInUse;
00353
00354 void addCallSite(LLError::CallSite&);
00355 void invalidateCallSites();
00356
00357 static Globals& get();
00358
00359
00360 private:
00361 CallSiteVector callSites;
00362
00363 Globals()
00364 : messageStreamInUse(false)
00365 { }
00366
00367 };
00368
00369 void Globals::addCallSite(LLError::CallSite& site)
00370 {
00371 callSites.push_back(&site);
00372 }
00373
00374 void Globals::invalidateCallSites()
00375 {
00376 for (CallSiteVector::const_iterator i = callSites.begin();
00377 i != callSites.end();
00378 ++i)
00379 {
00380 (*i)->invalidate();
00381 }
00382
00383 callSites.clear();
00384 }
00385
00386 Globals& Globals::get()
00387 {
00388
00389
00390
00391
00392
00393
00394 static Globals* globals = new Globals;
00395 return *globals;
00396 }
00397 }
00398
00399 namespace LLError
00400 {
00401 class Settings
00402 {
00403 public:
00404 bool printLocation;
00405
00406 LLError::ELevel defaultLevel;
00407
00408 LevelMap functionLevelMap;
00409 LevelMap classLevelMap;
00410 LevelMap fileLevelMap;
00411 LevelMap tagLevelMap;
00412 std::map<std::string, unsigned int> uniqueLogMessages;
00413
00414 LLError::FatalFunction crashFunction;
00415 LLError::TimeFunction timeFunction;
00416
00417 Recorders recorders;
00418 Recorder* fileRecorder;
00419 Recorder* fixedBufferRecorder;
00420 std::string fileRecorderFileName;
00421
00422 int shouldLogCallCounter;
00423
00424 static Settings& get();
00425
00426 static void reset();
00427 static Settings* saveAndReset();
00428 static void restore(Settings*);
00429
00430 private:
00431 Settings()
00432 : printLocation(false),
00433 defaultLevel(LLError::LEVEL_DEBUG),
00434 crashFunction(NULL),
00435 timeFunction(NULL),
00436 fileRecorder(NULL),
00437 fixedBufferRecorder(NULL),
00438 shouldLogCallCounter(0)
00439 { }
00440
00441 ~Settings()
00442 {
00443 for_each(recorders.begin(), recorders.end(),
00444 DeletePointer());
00445 }
00446
00447 static Settings*& getPtr();
00448 };
00449
00450 Settings& Settings::get()
00451 {
00452 Settings* p = getPtr();
00453 if (!p)
00454 {
00455 reset();
00456 p = getPtr();
00457 }
00458 return *p;
00459 }
00460
00461 void Settings::reset()
00462 {
00463 Globals::get().invalidateCallSites();
00464
00465 Settings*& p = getPtr();
00466 delete p;
00467 p = new Settings();
00468 }
00469
00470 Settings* Settings::saveAndReset()
00471 {
00472 Globals::get().invalidateCallSites();
00473
00474 Settings*& p = getPtr();
00475 Settings* originalSettings = p;
00476 p = new Settings();
00477 return originalSettings;
00478 }
00479
00480 void Settings::restore(Settings* originalSettings)
00481 {
00482 Globals::get().invalidateCallSites();
00483
00484 Settings*& p = getPtr();
00485 delete p;
00486 p = originalSettings;
00487 }
00488
00489 Settings*& Settings::getPtr()
00490 {
00491 static Settings* currentSettings = NULL;
00492 return currentSettings;
00493 }
00494 }
00495
00496 namespace LLError
00497 {
00498 CallSite::CallSite(ELevel level,
00499 const char* file,
00500 int line,
00501 const std::type_info& class_info,
00502 const char* function,
00503 const char* broadTag,
00504 const char* narrowTag,
00505 bool printOnce)
00506 : mLevel(level), mFile(file), mLine(line),
00507 mClassInfo(class_info), mFunction(function),
00508 mCached(false), mShouldLog(false),
00509 mBroadTag(broadTag), mNarrowTag(narrowTag), mPrintOnce(printOnce)
00510 { }
00511
00512
00513 void CallSite::invalidate()
00514 { mCached = false; }
00515 }
00516
00517 namespace
00518 {
00519 bool shouldLogToStderr()
00520 {
00521 #if LL_DARWIN
00522
00523
00524
00525
00526
00527
00528
00529 return isatty(0);
00530 #else
00531 return true;
00532 #endif
00533 }
00534
00535 bool stderrLogWantsTime()
00536 {
00537 #if LL_WINDOWS
00538 return false;
00539 #else
00540 return true;
00541 #endif
00542 }
00543
00544
00545 void commonInit(const std::string& dir)
00546 {
00547 LLError::Settings::reset();
00548
00549 LLError::setDefaultLevel(LLError::LEVEL_INFO);
00550 LLError::setFatalFunction(LLError::crashAndLoop);
00551 LLError::setTimeFunction(LLError::utcTime);
00552
00553 if (shouldLogToStderr())
00554 {
00555 LLError::addRecorder(new RecordToStderr(stderrLogWantsTime()));
00556 }
00557
00558 #if LL_WINDOWS
00559 LLError::addRecorder(new RecordToWinDebug);
00560 #endif
00561
00562 LogControlFile& e = LogControlFile::fromDirectory(dir);
00563
00564
00565
00566
00567
00568
00569
00570
00571 e.checkAndReload();
00572 e.addToEventTimer();
00573 }
00574 }
00575
00576 namespace LLError
00577 {
00578 void initForServer(const std::string& identity)
00579 {
00580 std::string dir = "/opt/linden/etc";
00581 if (LLApp::instance())
00582 {
00583 dir = LLApp::instance()->getOption("configdir").asString();
00584 }
00585 commonInit(dir);
00586 #if !LL_WINDOWS
00587 addRecorder(new RecordToSyslog(identity));
00588 #endif
00589 }
00590
00591 void initForApplication(const std::string& dir)
00592 {
00593 commonInit(dir);
00594 }
00595
00596 void setPrintLocation(bool print)
00597 {
00598 Settings& s = Settings::get();
00599 s.printLocation = print;
00600 }
00601
00602 void setFatalFunction(FatalFunction f)
00603 {
00604 Settings& s = Settings::get();
00605 s.crashFunction = f;
00606 }
00607
00608 void setTimeFunction(TimeFunction f)
00609 {
00610 Settings& s = Settings::get();
00611 s.timeFunction = f;
00612 }
00613
00614 void setDefaultLevel(ELevel level)
00615 {
00616 Globals& g = Globals::get();
00617 Settings& s = Settings::get();
00618 g.invalidateCallSites();
00619 s.defaultLevel = level;
00620 }
00621
00622 void setFunctionLevel(const std::string& function_name, ELevel level)
00623 {
00624 Globals& g = Globals::get();
00625 Settings& s = Settings::get();
00626 g.invalidateCallSites();
00627 s.functionLevelMap[function_name] = level;
00628 }
00629
00630 void setClassLevel(const std::string& class_name, ELevel level)
00631 {
00632 Globals& g = Globals::get();
00633 Settings& s = Settings::get();
00634 g.invalidateCallSites();
00635 s.classLevelMap[class_name] = level;
00636 }
00637
00638 void setFileLevel(const std::string& file_name, ELevel level)
00639 {
00640 Globals& g = Globals::get();
00641 Settings& s = Settings::get();
00642 g.invalidateCallSites();
00643 s.fileLevelMap[file_name] = level;
00644 }
00645
00646 void setTagLevel(const std::string& tag_name, ELevel level)
00647 {
00648 Globals& g = Globals::get();
00649 Settings& s = Settings::get();
00650 g.invalidateCallSites();
00651 s.tagLevelMap[tag_name] = level;
00652 }
00653 }
00654
00655 namespace {
00656 LLError::ELevel decodeLevel(std::string name)
00657 {
00658 static LevelMap level_names;
00659 if (level_names.empty())
00660 {
00661 level_names["ALL"] = LLError::LEVEL_ALL;
00662 level_names["DEBUG"] = LLError::LEVEL_DEBUG;
00663 level_names["INFO"] = LLError::LEVEL_INFO;
00664 level_names["WARN"] = LLError::LEVEL_WARN;
00665 level_names["ERROR"] = LLError::LEVEL_ERROR;
00666 level_names["NONE"] = LLError::LEVEL_NONE;
00667 }
00668
00669 std::transform(name.begin(), name.end(), name.begin(), toupper);
00670
00671 LevelMap::const_iterator i = level_names.find(name);
00672 if (i == level_names.end())
00673 {
00674 llwarns << "unrecognized logging level: '" << name << "'" << llendl;
00675 return LLError::LEVEL_INFO;
00676 }
00677
00678 return i->second;
00679 }
00680
00681 void setLevels(LevelMap& map, const LLSD& list, LLError::ELevel level)
00682 {
00683 LLSD::array_const_iterator i, end;
00684 for (i = list.beginArray(), end = list.endArray(); i != end; ++i)
00685 {
00686 map[*i] = level;
00687 }
00688 }
00689 }
00690
00691 namespace LLError
00692 {
00693 void configure(const LLSD& config)
00694 {
00695 Globals& g = Globals::get();
00696 Settings& s = Settings::get();
00697
00698 g.invalidateCallSites();
00699 s.functionLevelMap.clear();
00700 s.classLevelMap.clear();
00701 s.fileLevelMap.clear();
00702 s.tagLevelMap.clear();
00703 s.uniqueLogMessages.clear();
00704
00705 setPrintLocation(config["print-location"]);
00706 setDefaultLevel(decodeLevel(config["default-level"]));
00707
00708 LLSD sets = config["settings"];
00709 LLSD::array_const_iterator a, end;
00710 for (a = sets.beginArray(), end = sets.endArray(); a != end; ++a)
00711 {
00712 const LLSD& entry = *a;
00713
00714 ELevel level = decodeLevel(entry["level"]);
00715
00716 setLevels(s.functionLevelMap, entry["functions"], level);
00717 setLevels(s.classLevelMap, entry["classes"], level);
00718 setLevels(s.fileLevelMap, entry["files"], level);
00719 setLevels(s.tagLevelMap, entry["tags"], level);
00720 }
00721 }
00722 }
00723
00724
00725 namespace LLError
00726 {
00727 Recorder::~Recorder()
00728 { }
00729
00730
00731 bool Recorder::wantsTime()
00732 { return false; }
00733
00734
00735
00736 void addRecorder(Recorder* recorder)
00737 {
00738 if (recorder == NULL)
00739 {
00740 return;
00741 }
00742 Settings& s = Settings::get();
00743 s.recorders.push_back(recorder);
00744 }
00745
00746 void removeRecorder(Recorder* recorder)
00747 {
00748 if (recorder == NULL)
00749 {
00750 return;
00751 }
00752 Settings& s = Settings::get();
00753 s.recorders.erase(
00754 std::remove(s.recorders.begin(), s.recorders.end(), recorder),
00755 s.recorders.end());
00756 }
00757 }
00758
00759 namespace LLError
00760 {
00761 void logToFile(const std::string& file_name)
00762 {
00763 LLError::Settings& s = LLError::Settings::get();
00764
00765 removeRecorder(s.fileRecorder);
00766 delete s.fileRecorder;
00767 s.fileRecorder = NULL;
00768 s.fileRecorderFileName.clear();
00769
00770 if (file_name.empty())
00771 {
00772 return;
00773 }
00774
00775 RecordToFile* f = new RecordToFile(file_name);
00776 if (!f->okay())
00777 {
00778 delete f;
00779 return;
00780 }
00781
00782 s.fileRecorderFileName = file_name;
00783 s.fileRecorder = f;
00784 addRecorder(f);
00785 }
00786
00787 void logToFixedBuffer(LLFixedBuffer* fixedBuffer)
00788 {
00789 LLError::Settings& s = LLError::Settings::get();
00790
00791 removeRecorder(s.fixedBufferRecorder);
00792 delete s.fixedBufferRecorder;
00793 s.fixedBufferRecorder = NULL;
00794
00795 if (!fixedBuffer)
00796 {
00797 return;
00798 }
00799
00800 s.fixedBufferRecorder = new RecordToFixedBuffer(*fixedBuffer);
00801 addRecorder(s.fixedBufferRecorder);
00802 }
00803
00804 std::string logFileName()
00805 {
00806 LLError::Settings& s = LLError::Settings::get();
00807 return s.fileRecorderFileName;
00808 }
00809 }
00810
00811 namespace
00812 {
00813 void writeToRecorders(LLError::ELevel level, const std::string& message)
00814 {
00815 LLError::Settings& s = LLError::Settings::get();
00816
00817 std::string messageWithTime;
00818
00819 for (Recorders::const_iterator i = s.recorders.begin();
00820 i != s.recorders.end();
00821 ++i)
00822 {
00823 LLError::Recorder* r = *i;
00824
00825 if (r->wantsTime() && s.timeFunction != NULL)
00826 {
00827 if (messageWithTime.empty())
00828 {
00829 messageWithTime = s.timeFunction() + " " + message;
00830 }
00831
00832 r->recordMessage(level, messageWithTime);
00833 }
00834 else
00835 {
00836 r->recordMessage(level, message);
00837 }
00838 }
00839 }
00840 }
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871 namespace {
00872 bool checkLevelMap(const LevelMap& map, const std::string& key,
00873 LLError::ELevel& level)
00874 {
00875 LevelMap::const_iterator i = map.find(key);
00876 if (i == map.end())
00877 {
00878 return false;
00879 }
00880
00881 level = i->second;
00882 return true;
00883 }
00884
00885 class LogLock
00886 {
00887 public:
00888 LogLock();
00889 ~LogLock();
00890 bool ok() const { return mOK; }
00891 private:
00892 bool mLocked;
00893 bool mOK;
00894 };
00895
00896 LogLock::LogLock()
00897 : mLocked(false), mOK(false)
00898 {
00899 if (!gLogMutexp)
00900 {
00901 mOK = true;
00902 return;
00903 }
00904
00905 const int MAX_RETRIES = 5;
00906 for (int attempts = 0; attempts < MAX_RETRIES; ++attempts)
00907 {
00908 apr_status_t s = apr_thread_mutex_trylock(gLogMutexp);
00909 if (!APR_STATUS_IS_EBUSY(s))
00910 {
00911 mLocked = true;
00912 mOK = true;
00913 return;
00914 }
00915
00916 ms_sleep(1);
00917
00918
00919
00920 }
00921
00922
00923 std::cerr << "LogLock::LogLock: failed to get mutex for log"
00924 << std::endl;
00925 }
00926
00927 LogLock::~LogLock()
00928 {
00929 if (mLocked)
00930 {
00931 apr_thread_mutex_unlock(gLogMutexp);
00932 }
00933 }
00934 }
00935
00936 namespace LLError
00937 {
00938 bool Log::shouldLog(CallSite& site)
00939 {
00940 LogLock lock;
00941 if (!lock.ok())
00942 {
00943 return false;
00944 }
00945
00946 Globals& g = Globals::get();
00947 Settings& s = Settings::get();
00948
00949 s.shouldLogCallCounter += 1;
00950
00951 std::string class_name = className(site.mClassInfo);
00952 std::string function_name = functionName(site.mFunction);
00953 if (site.mClassInfo != typeid(NoClassInfo))
00954 {
00955 function_name = class_name + "::" + function_name;
00956 }
00957
00958 ELevel compareLevel = s.defaultLevel;
00959
00960
00961
00962
00963
00964 ((site.mNarrowTag != NULL) ? checkLevelMap(s.tagLevelMap, site.mNarrowTag, compareLevel) : false)
00965 || checkLevelMap(s.functionLevelMap, function_name, compareLevel)
00966 || checkLevelMap(s.classLevelMap, class_name, compareLevel)
00967 || checkLevelMap(s.fileLevelMap, abbreviateFile(site.mFile), compareLevel)
00968 || ((site.mBroadTag != NULL) ? checkLevelMap(s.tagLevelMap, site.mBroadTag, compareLevel) : false);
00969
00970 site.mCached = true;
00971 g.addCallSite(site);
00972 return site.mShouldLog = site.mLevel >= compareLevel;
00973 }
00974
00975
00976 std::ostringstream* Log::out()
00977 {
00978 LogLock lock;
00979 if (lock.ok())
00980 {
00981 Globals& g = Globals::get();
00982
00983 if (!g.messageStreamInUse)
00984 {
00985 g.messageStreamInUse = true;
00986 return &g.messageStream;
00987 }
00988 }
00989
00990 return new std::ostringstream;
00991 }
00992
00993 void Log::flush(std::ostringstream* out, const CallSite& site)
00994 {
00995 LogLock lock;
00996 if (!lock.ok())
00997 {
00998 return;
00999 }
01000
01001 Globals& g = Globals::get();
01002 Settings& s = Settings::get();
01003
01004 std::string message = out->str();
01005 if (out == &g.messageStream)
01006 {
01007 g.messageStream.clear();
01008 g.messageStream.str("");
01009 g.messageStreamInUse = false;
01010 }
01011 else
01012 {
01013 delete out;
01014 }
01015
01016 if (site.mLevel == LEVEL_ERROR)
01017 {
01018 std::ostringstream fatalMessage;
01019 fatalMessage << abbreviateFile(site.mFile)
01020 << "(" << site.mLine << ") : error";
01021
01022 writeToRecorders(site.mLevel, fatalMessage.str());
01023 }
01024
01025
01026 std::ostringstream prefix;
01027
01028 switch (site.mLevel)
01029 {
01030 case LEVEL_DEBUG: prefix << "DEBUG: "; break;
01031 case LEVEL_INFO: prefix << "INFO: "; break;
01032 case LEVEL_WARN: prefix << "WARNING: "; break;
01033 case LEVEL_ERROR: prefix << "ERROR: "; break;
01034 default: prefix << "XXX: "; break;
01035 };
01036
01037 if (s.printLocation)
01038 {
01039 prefix << abbreviateFile(site.mFile)
01040 << "(" << site.mLine << ") : ";
01041 }
01042
01043 if (message.find(functionName(site.mFunction)) == std::string::npos)
01044 {
01045 #if LL_WINDOWS
01046
01047 #else
01048 if (site.mClassInfo != typeid(NoClassInfo))
01049 {
01050 prefix << className(site.mClassInfo) << "::";
01051 }
01052 #endif
01053 prefix << site.mFunction << ": ";
01054 }
01055
01056 if (site.mPrintOnce)
01057 {
01058 std::map<std::string, unsigned int>::iterator messageIter = s.uniqueLogMessages.find(message);
01059 if (messageIter != s.uniqueLogMessages.end())
01060 {
01061 messageIter->second++;
01062 unsigned int num_messages = messageIter->second;
01063 if (num_messages == 10 || num_messages == 50 || (num_messages % 100) == 0)
01064 {
01065 prefix << "ONCE (" << num_messages << "th time seen): ";
01066 }
01067 else
01068 {
01069 return;
01070 }
01071 }
01072 else
01073 {
01074 prefix << "ONCE: ";
01075 s.uniqueLogMessages[message] = 1;
01076 }
01077 }
01078
01079 prefix << message;
01080 message = prefix.str();
01081
01082 writeToRecorders(site.mLevel, message);
01083
01084 if (site.mLevel == LEVEL_ERROR && s.crashFunction)
01085 {
01086 s.crashFunction(message);
01087 }
01088 }
01089 }
01090
01091
01092
01093
01094 namespace LLError
01095 {
01096 Settings* saveAndResetSettings()
01097 {
01098 return Settings::saveAndReset();
01099 }
01100
01101 void restoreSettings(Settings* s)
01102 {
01103 return Settings::restore(s);
01104 }
01105
01106 std::string removePrefix(std::string& s, const std::string& p)
01107 {
01108 std::string::size_type where = s.find(p);
01109 if (where == std::string::npos)
01110 {
01111 return s;
01112 }
01113
01114 return std::string(s, where + p.size());
01115 }
01116
01117 void replaceChar(std::string& s, char old, char replacement)
01118 {
01119 std::string::size_type i = 0;
01120 std::string::size_type len = s.length();
01121 for ( ; i < len; i++ )
01122 {
01123 if (s[i] == old)
01124 {
01125 s[i] = replacement;
01126 }
01127 }
01128 }
01129
01130 std::string abbreviateFile(const std::string& filePath)
01131 {
01132 std::string f = filePath;
01133 #if LL_WINDOWS
01134 replaceChar(f, '\\', '/');
01135 #endif
01136 static std::string indra_prefix = "indra/";
01137 f = removePrefix(f, indra_prefix);
01138
01139 #if LL_DARWIN
01140 static std::string newview_prefix = "newview/../";
01141 f = removePrefix(f, newview_prefix);
01142 #endif
01143
01144 return f;
01145 }
01146
01147 int shouldLogCallCount()
01148 {
01149 Settings& s = Settings::get();
01150 return s.shouldLogCallCounter;
01151 }
01152
01153 void crashAndLoop(const std::string& message)
01154 {
01155
01156 int* crash = NULL;
01157
01158 *crash = 0;
01159
01160 while(true)
01161 {
01162
01163 }
01164 }
01165
01166 std::string utcTime()
01167 {
01168 time_t now = time(NULL);
01169 const size_t BUF_SIZE = 64;
01170 char time_str[BUF_SIZE];
01171
01172 int chars = strftime(time_str, BUF_SIZE,
01173 "%Y-%m-%dT%H:%M:%SZ",
01174 gmtime(&now));
01175
01176 return chars ? time_str : "time error";
01177 }
01178 }
01179