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