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