llerror.cpp

Go to the documentation of this file.
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                                 // we need to set the string from a local copy of the string
00071                                 // since apparanetly openlog expects the const char* to remain
00072                                 // valid even after it returns (presumably until closelog)
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                         // mFile.flush();
00125                                 // *FIX: should we do this? 
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                 // GCC: type_info::name() returns a mangled class name, must demangle
00188 
00189                 static size_t abi_name_len = 100;
00190                 static char* abi_name_buf = (char*)malloc(abi_name_len);
00191                         // warning: above is voodoo inferred from the GCC manual,
00192                         // do NOT change
00193 
00194                 int status;
00195                         // We don't use status, and shouldn't have to pass apointer to it
00196                         // but gcc 3.3 libstc++'s implementation of demangling is broken
00197                         // and fails without.
00198                         
00199                 char* name = abi::__cxa_demangle(type.name(),
00200                                                                                 abi_name_buf, &abi_name_len, &status);
00201                         // this call can realloc the abi_name_buf pointer (!)
00202 
00203                 return name ? name : type.name();
00204 
00205 #elif LL_WINDOWS
00206                 // DevStudio: type_info::name() includes the text "class " at the start
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                 // DevStudio: the __FUNCTION__ macro string includes
00228                 // the type and/or namespace prefixes
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                         // NB: We have no abstraction in llcommon  for the "proper"
00262                         // delimiter but it turns out that "/" works on all three platforms
00263                         
00264                 std::string file = dirBase + "logcontrol-dev.xml";
00265                 
00266                 llstat stat_info;
00267                 if (LLFile::stat(file.c_str(), &stat_info)) {
00268                         // NB: stat returns non-zero if it can't read the file, for example
00269                         // if it doesn't exist.  LLFile has no better abstraction for 
00270                         // testing for file existence.
00271                         
00272                         file = dirBase + "logcontrol.xml";
00273                 }
00274                 return * new LogControlFile(file);
00275                         // NB: This instance is never freed
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                         // return the one instance of the globals
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                 /* This pattern, of returning a reference to a static function
00348                    variable, is to ensure that this global is constructed before
00349                    it is used, no matter what the global initializeation sequence
00350                    is.
00351                    See C++ FAQ Lite, sections 10.12 through 10.14
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                 // On Mac OS X, stderr from apps launched from the Finder goes to the
00474                 // console log.  It's generally considered bad form to spam too much
00475                 // there.
00476                 
00477                 // If stdin is a tty, assume the user launched from the command line and
00478                 // therefore wants to see stderr.  Otherwise, assume we've been launched
00479                 // from the finder and shouldn't spam stderr.
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         // virtual
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 Recorder formats:
00776 
00777 $type = "ERROR" | "WARNING" | "ALERT" | "INFO" | "DEBUG"
00778 $loc = "$file($line)"
00779 $msg = "$loc : " if FATAL or printing loc
00780                 "" otherwise
00781 $msg += "$type: "
00782 $msg += contents of stringstream
00783 
00784 $time = "%Y-%m-%dT%H:%M:%SZ" if UTC
00785          or "%Y-%m-%dT%H:%M:%S %Z" if local
00786 
00787 syslog: "$msg"
00788 file: "$time $msg\n"
00789 stderr: "$time $msg\n" except on windows, "$msg\n"
00790 fixedbuf: "$msg"
00791 winddebug: "$msg\n"
00792 
00793 Note: if FATAL, an additional line gets logged first, with $msg set to
00794         "$loc : error"
00795         
00796 You get:
00797         llfoo.cpp(42) : error
00798         llfoo.cpp(42) : ERROR: something
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                         //apr_thread_yield();
00849                                 // Just yielding won't necessarily work, I had problems with
00850                                 // this on Linux - doug 12/02/04
00851                 }
00852 
00853                 // We're hosed, we can't get the mutex.  Blah.
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                         // DevStudio: __FUNCTION__ already includes the full class name
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                 // Now, we go kaboom!
01058                 int* crash = NULL;
01059 
01060                 *crash = 0;
01061 
01062                 while(true)
01063                 {
01064                         // Loop forever, in case the crash didn't work?
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];        /* Flawfinder: ignore */
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 

Generated on Thu Jul 1 06:08:29 2010 for Second Life Viewer by  doxygen 1.4.7