LCOV - code coverage report
Current view: top level - xpcom/base - Logging.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 29 225 12.9 %
Date: 2018-08-07 16:35:00 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/Logging.h"
       8             : 
       9             : #include <algorithm>
      10             : 
      11             : #include "mozilla/ClearOnShutdown.h"
      12             : #include "mozilla/FileUtils.h"
      13             : #include "mozilla/Mutex.h"
      14             : #include "mozilla/StaticPtr.h"
      15             : #include "mozilla/Printf.h"
      16             : #include "mozilla/Atomics.h"
      17             : #include "mozilla/Sprintf.h"
      18             : #include "mozilla/UniquePtrExtensions.h"
      19             : #include "MainThreadUtils.h"
      20             : #include "nsClassHashtable.h"
      21             : #include "nsDebug.h"
      22             : #include "NSPRLogModulesParser.h"
      23             : #include "LogCommandLineHandler.h"
      24             : 
      25             : #include "prenv.h"
      26             : #ifdef XP_WIN
      27             : #include <process.h>
      28             : #else
      29             : #include <sys/types.h>
      30             : #include <unistd.h>
      31             : #endif
      32             : 
      33             : // NB: Initial amount determined by auditing the codebase for the total amount
      34             : //     of unique module names and padding up to the next power of 2.
      35             : const uint32_t kInitialModuleCount = 256;
      36             : // When rotate option is added to the modules list, this is the hardcoded
      37             : // number of files we create and rotate.  When there is rotate:40,
      38             : // we will keep four files per process, each limited to 10MB.  Sum is 40MB,
      39             : // the given limit.
      40             : //
      41             : // (Note: When this is changed to be >= 10, SandboxBroker::LaunchApp must add
      42             : // another rule to allow logfile.?? be written by content processes.)
      43             : const uint32_t kRotateFilesNumber = 4;
      44             : 
      45             : namespace mozilla {
      46             : 
      47           0 : LazyLogModule::operator LogModule*()
      48             : {
      49             :   // NB: The use of an atomic makes the reading and assignment of mLog
      50             :   //     thread-safe. There is a small chance that mLog will be set more
      51             :   //     than once, but that's okay as it will be set to the same LogModule
      52             :   //     instance each time. Also note LogModule::Get is thread-safe.
      53           0 :   LogModule* tmp = mLog;
      54           0 :   if (MOZ_UNLIKELY(!tmp)) {
      55           0 :     tmp = LogModule::Get(mLogName);
      56           0 :     mLog = tmp;
      57             :   }
      58             : 
      59           0 :   mCanary.Check();
      60             : 
      61      198609 :   return tmp;
      62             : }
      63             : 
      64             : namespace detail {
      65             : 
      66           0 : void log_print(const LogModule* aModule,
      67             :                LogLevel aLevel,
      68             :                const char* aFmt, ...)
      69             : {
      70             :   va_list ap;
      71           0 :   va_start(ap, aFmt);
      72           0 :   aModule->Printv(aLevel, aFmt, ap);
      73           0 :   va_end(ap);
      74           0 : }
      75             : 
      76             : } // detail
      77             : 
      78             : LogLevel
      79           0 : ToLogLevel(int32_t aLevel)
      80             : {
      81           0 :   aLevel = std::min(aLevel, static_cast<int32_t>(LogLevel::Verbose));
      82           0 :   aLevel = std::max(aLevel, static_cast<int32_t>(LogLevel::Disabled));
      83           0 :   return static_cast<LogLevel>(aLevel);
      84             : }
      85             : 
      86             : const char*
      87           0 : ToLogStr(LogLevel aLevel) {
      88           0 :   switch (aLevel) {
      89             :     case LogLevel::Error:
      90             :       return "E";
      91             :     case LogLevel::Warning:
      92           0 :       return "W";
      93             :     case LogLevel::Info:
      94           0 :       return "I";
      95             :     case LogLevel::Debug:
      96           0 :       return "D";
      97             :     case LogLevel::Verbose:
      98           0 :       return "V";
      99             :     case LogLevel::Disabled:
     100             :     default:
     101           0 :       MOZ_CRASH("Invalid log level.");
     102             :       return "";
     103             :   }
     104             : }
     105             : 
     106             : namespace detail {
     107             : 
     108             : /**
     109             :  * A helper class providing reference counting for FILE*.
     110             :  * It encapsulates the following:
     111             :  *  - the FILE handle
     112             :  *  - the order number it was created for when rotating (actual path)
     113             :  *  - number of active references
     114             :  */
     115             : class LogFile
     116             : {
     117             :   FILE* mFile;
     118             :   uint32_t mFileNum;
     119             : 
     120             : public:
     121             :   LogFile(FILE* aFile, uint32_t aFileNum)
     122           0 :     : mFile(aFile)
     123             :     , mFileNum(aFileNum)
     124           0 :     , mNextToRelease(nullptr)
     125             :   {
     126             :   }
     127             : 
     128           0 :   ~LogFile()
     129           0 :   {
     130           0 :     fclose(mFile);
     131           0 :     delete mNextToRelease;
     132           0 :   }
     133             : 
     134             :   FILE* File() const { return mFile; }
     135             :   uint32_t Num() const { return mFileNum; }
     136             : 
     137             :   LogFile* mNextToRelease;
     138             : };
     139             : 
     140             : const char*
     141           0 : ExpandPIDMarker(const char* aFilename, char (&buffer)[2048])
     142             : {
     143           0 :   MOZ_ASSERT(aFilename);
     144             :   static const char kPIDToken[] = "%PID";
     145           0 :   const char* pidTokenPtr = strstr(aFilename, kPIDToken);
     146           0 :   if (pidTokenPtr &&
     147           0 :     SprintfLiteral(buffer, "%.*s%s%d%s",
     148           0 :                    static_cast<int>(pidTokenPtr - aFilename), aFilename,
     149           0 :                    XRE_IsParentProcess() ? "-main." : "-child.",
     150             :                    base::GetCurrentProcId(),
     151             :                    pidTokenPtr + strlen(kPIDToken)) > 0)
     152             :   {
     153             :     return buffer;
     154             :   }
     155             : 
     156           0 :   return aFilename;
     157             : }
     158             : 
     159             : } // detail
     160             : 
     161             : namespace {
     162             :   // Helper method that initializes an empty va_list to be empty.
     163           0 :   void empty_va(va_list *va, ...)
     164             :   {
     165           0 :     va_start(*va, va);
     166           0 :     va_end(*va);
     167           0 :   }
     168             : }
     169             : 
     170             : class LogModuleManager
     171             : {
     172             : public:
     173           1 :   LogModuleManager()
     174           1 :     : mModulesLock("logmodules")
     175             :     , mModules(kInitialModuleCount)
     176             :     , mPrintEntryCount(0)
     177             :     , mOutFile(nullptr)
     178             :     , mToReleaseFile(nullptr)
     179             :     , mOutFileNum(0)
     180             :     , mOutFilePath(strdup(""))
     181           1 :     , mMainThread(PR_GetCurrentThread())
     182             :     , mSetFromEnv(false)
     183             :     , mAddTimestamp(false)
     184             :     , mIsRaw(false)
     185             :     , mIsSync(false)
     186             :     , mRotate(0)
     187           0 :     , mInitialized(false)
     188             :   {
     189           1 :   }
     190             : 
     191           0 :   ~LogModuleManager()
     192           0 :   {
     193           0 :     detail::LogFile* logFile = mOutFile.exchange(nullptr);
     194           0 :     delete logFile;
     195           0 :   }
     196             : 
     197             :   /**
     198             :    * Loads config from command line args or env vars if present, in
     199             :    * this specific order of priority.
     200             :    *
     201             :    * Notes:
     202             :    *
     203             :    * 1) This function is only intended to be called once per session.
     204             :    * 2) None of the functions used in Init should rely on logging.
     205             :    */
     206           0 :   void Init(int argc, char* argv[])
     207             :   {
     208           1 :     MOZ_DIAGNOSTIC_ASSERT(!mInitialized);
     209           0 :     mInitialized = true;
     210             : 
     211           2 :     LoggingHandleCommandLineArgs(argc, static_cast<char const* const*>(argv),
     212           0 :                                  [](nsACString const& env) {
     213             :       // We deliberately set/rewrite the environment variables
     214             :       // so that when child processes are spawned w/o passing
     215             :       // the arguments they still inherit the logging settings
     216             :       // as well as sandboxing can be correctly set.
     217             :       // Scripts can pass -MOZ_LOG=$MOZ_LOG,modules as an argument
     218             :       // to merge existing settings, if required.
     219             : 
     220             :       // PR_SetEnv takes ownership of the string.
     221           0 :       PR_SetEnv(ToNewCString(env));
     222           0 :     });
     223             : 
     224           0 :     bool shouldAppend = false;
     225           0 :     bool addTimestamp = false;
     226           0 :     bool isSync = false;
     227           0 :     bool isRaw = false;
     228           0 :     int32_t rotate = 0;
     229           0 :     const char* modules = PR_GetEnv("MOZ_LOG");
     230           0 :     if (!modules || !modules[0]) {
     231           1 :       modules = PR_GetEnv("MOZ_LOG_MODULES");
     232           1 :       if (modules) {
     233             :         NS_WARNING("MOZ_LOG_MODULES is deprecated."
     234           0 :             "\nPlease use MOZ_LOG instead.");
     235             :       }
     236             :     }
     237           0 :     if (!modules || !modules[0]) {
     238           1 :       modules = PR_GetEnv("NSPR_LOG_MODULES");
     239           1 :       if (modules) {
     240             :         NS_WARNING("NSPR_LOG_MODULES is deprecated."
     241           0 :             "\nPlease use MOZ_LOG instead.");
     242             :       }
     243             :     }
     244             : 
     245             :     // Need to capture `this` since `sLogModuleManager` is not set until after
     246             :     // initialization is complete.
     247           0 :     NSPRLogModulesParser(modules,
     248             :         [this, &shouldAppend, &addTimestamp, &isSync, &isRaw, &rotate]
     249           0 :             (const char* aName, LogLevel aLevel, int32_t aValue) mutable {
     250           0 :           if (strcmp(aName, "append") == 0) {
     251           0 :             shouldAppend = true;
     252           0 :           } else if (strcmp(aName, "timestamp") == 0) {
     253           0 :             addTimestamp = true;
     254           0 :           } else if (strcmp(aName, "sync") == 0) {
     255           0 :             isSync = true;
     256           0 :           } else if (strcmp(aName, "raw") == 0) {
     257           0 :             isRaw = true;
     258           0 :           } else if (strcmp(aName, "rotate") == 0) {
     259           0 :             rotate = (aValue << 20) / kRotateFilesNumber;
     260             :           } else {
     261           0 :             this->CreateOrGetModule(aName)->SetLevel(aLevel);
     262             :           }
     263           1 :     });
     264             : 
     265             :     // Rotate implies timestamp to make the files readable
     266           0 :     mAddTimestamp = addTimestamp || rotate > 0;
     267           0 :     mIsSync = isSync;
     268           2 :     mIsRaw = isRaw;
     269           0 :     mRotate = rotate;
     270             : 
     271           1 :     if (rotate > 0 && shouldAppend) {
     272           0 :       NS_WARNING("MOZ_LOG: when you rotate the log, you cannot use append!");
     273             :     }
     274             : 
     275           0 :     const char* logFile = PR_GetEnv("MOZ_LOG_FILE");
     276           1 :     if (!logFile || !logFile[0]) {
     277           1 :       logFile = PR_GetEnv("NSPR_LOG_FILE");
     278             :     }
     279             : 
     280           1 :     if (logFile && logFile[0]) {
     281             :       char buf[2048];
     282           0 :       logFile = detail::ExpandPIDMarker(logFile, buf);
     283           0 :       mOutFilePath.reset(strdup(logFile));
     284             : 
     285           0 :       if (mRotate > 0) {
     286             :         // Delete all the previously captured files, including non-rotated
     287             :         // log files, so that users don't complain our logs eat space even
     288             :         // after the rotate option has been added and don't happen to send
     289             :         // us old large logs along with the rotated files.
     290           0 :         remove(mOutFilePath.get());
     291           0 :         for (uint32_t i = 0; i < kRotateFilesNumber; ++i) {
     292           0 :           RemoveFile(i);
     293             :         }
     294             :       }
     295             : 
     296           0 :       mOutFile = OpenFile(shouldAppend, mOutFileNum);
     297           0 :       mSetFromEnv = true;
     298             :     }
     299           1 :   }
     300             : 
     301           0 :   void SetLogFile(const char* aFilename)
     302             :   {
     303             :     // For now we don't allow you to change the file at runtime.
     304           0 :     if (mSetFromEnv) {
     305             :       NS_WARNING("LogModuleManager::SetLogFile - Log file was set from the "
     306           0 :                  "MOZ_LOG_FILE environment variable.");
     307           0 :       return;
     308             :     }
     309             : 
     310           0 :     const char * filename = aFilename ? aFilename : "";
     311             :     char buf[2048];
     312           0 :     filename = detail::ExpandPIDMarker(filename, buf);
     313             : 
     314             :     // Can't use rotate at runtime yet.
     315           0 :     MOZ_ASSERT(mRotate == 0, "We don't allow rotate for runtime logfile changes");
     316           0 :     mOutFilePath.reset(strdup(filename));
     317             : 
     318             :     // Exchange mOutFile and set it to be released once all the writes are done.
     319           0 :     detail::LogFile* newFile = OpenFile(false, 0);
     320           0 :     detail::LogFile* oldFile = mOutFile.exchange(newFile);
     321             : 
     322             :     // Since we don't allow changing the logfile if MOZ_LOG_FILE is already set,
     323             :     // and we don't allow log rotation when setting it at runtime, mToReleaseFile
     324             :     // will be null, so we're not leaking.
     325           0 :     DebugOnly<detail::LogFile*> prevFile = mToReleaseFile.exchange(oldFile);
     326           0 :     MOZ_ASSERT(!prevFile, "Should be null because rotation is not allowed");
     327             : 
     328             :     // If we just need to release a file, we must force print, in order to
     329             :     // trigger the closing and release of mToReleaseFile.
     330           0 :     if (oldFile) {
     331             :       va_list va;
     332           0 :       empty_va(&va);
     333           0 :       Print("Logger", LogLevel::Info, "Flushing old log files\n", va);
     334             :     }
     335             :   }
     336             : 
     337           0 :   uint32_t GetLogFile(char *aBuffer, size_t aLength)
     338             :   {
     339           0 :     uint32_t len = strlen(mOutFilePath.get());
     340           0 :     if (len + 1 > aLength) {
     341             :       return 0;
     342             :     }
     343           0 :     snprintf(aBuffer, aLength, "%s", mOutFilePath.get());
     344           0 :     return len;
     345             :   }
     346             : 
     347             :   void SetIsSync(bool aIsSync)
     348             :   {
     349           0 :     mIsSync = aIsSync;
     350             :   }
     351             : 
     352             :   void SetAddTimestamp(bool aAddTimestamp)
     353             :   {
     354           0 :     mAddTimestamp = aAddTimestamp;
     355             :   }
     356             : 
     357           0 :   detail::LogFile* OpenFile(bool aShouldAppend, uint32_t aFileNum)
     358             :   {
     359             :     FILE* file;
     360             : 
     361           0 :     if (mRotate > 0) {
     362             :       char buf[2048];
     363           0 :       SprintfLiteral(buf, "%s.%d", mOutFilePath.get(), aFileNum);
     364             : 
     365             :       // rotate doesn't support append.
     366           0 :       file = fopen(buf, "w");
     367             :     } else {
     368           0 :       file = fopen(mOutFilePath.get(), aShouldAppend ? "a" : "w");
     369             :     }
     370             : 
     371           0 :     if (!file) {
     372             :       return nullptr;
     373             :     }
     374             : 
     375           0 :     return new detail::LogFile(file, aFileNum);
     376             :   }
     377             : 
     378           0 :   void RemoveFile(uint32_t aFileNum)
     379             :   {
     380             :     char buf[2048];
     381           0 :     SprintfLiteral(buf, "%s.%d", mOutFilePath.get(), aFileNum);
     382           0 :     remove(buf);
     383           0 :   }
     384             : 
     385           0 :   LogModule* CreateOrGetModule(const char* aName)
     386             :   {
     387           0 :     OffTheBooksMutexAutoLock guard(mModulesLock);
     388           0 :     LogModule* module = nullptr;
     389           0 :     if (!mModules.Get(aName, &module)) {
     390         198 :       module = new LogModule(aName, LogLevel::Disabled);
     391          99 :       mModules.Put(aName, module);
     392             :     }
     393             : 
     394         208 :     return module;
     395             :   }
     396             : 
     397           0 :   void Print(const char* aName, LogLevel aLevel, const char* aFmt, va_list aArgs)
     398             :     MOZ_FORMAT_PRINTF(4, 0)
     399             :   {
     400             :     // We don't do nuwa-style forking anymore, so our pid can't change.
     401           0 :     static long pid = static_cast<long>(base::GetCurrentProcId());
     402           0 :     const size_t kBuffSize = 1024;
     403             :     char buff[kBuffSize];
     404             : 
     405           0 :     char* buffToWrite = buff;
     406           0 :     SmprintfPointer allocatedBuff;
     407             : 
     408             :     va_list argsCopy;
     409           0 :     va_copy(argsCopy, aArgs);
     410           0 :     int charsWritten = VsprintfLiteral(buff, aFmt, argsCopy);
     411           0 :     va_end(argsCopy);
     412             : 
     413           0 :     if (charsWritten < 0) {
     414             :       // Print out at least something.  We must copy to the local buff,
     415             :       // can't just assign aFmt to buffToWrite, since when
     416             :       // buffToWrite != buff, we try to release it.
     417           0 :       MOZ_ASSERT(false, "Probably incorrect format string in LOG?");
     418             :       strncpy(buff, aFmt, kBuffSize - 1);
     419             :       buff[kBuffSize - 1] = '\0';
     420             :       charsWritten = strlen(buff);
     421           0 :     } else if (static_cast<size_t>(charsWritten) >= kBuffSize - 1) {
     422             :       // We may have maxed out, allocate a buffer instead.
     423           0 :       allocatedBuff = mozilla::Vsmprintf(aFmt, aArgs);
     424           0 :       buffToWrite = allocatedBuff.get();
     425           0 :       charsWritten = strlen(buffToWrite);
     426             :     }
     427             : 
     428             :     // Determine if a newline needs to be appended to the message.
     429           0 :     const char* newline = "";
     430           0 :     if (charsWritten == 0 || buffToWrite[charsWritten - 1] != '\n') {
     431           0 :       newline = "\n";
     432             :     }
     433             : 
     434           0 :     FILE* out = stderr;
     435             : 
     436             :     // In case we use rotate, this ensures the FILE is kept alive during
     437             :     // its use.  Increased before we load mOutFile.
     438           0 :     ++mPrintEntryCount;
     439             : 
     440           0 :     detail::LogFile* outFile = mOutFile;
     441           0 :     if (outFile) {
     442           0 :       out = outFile->File();
     443             :     }
     444             : 
     445             :     // This differs from the NSPR format in that we do not output the
     446             :     // opaque system specific thread pointer (ie pthread_t) cast
     447             :     // to a long. The address of the current PR_Thread continues to be
     448             :     // prefixed.
     449             :     //
     450             :     // Additionally we prefix the output with the abbreviated log level
     451             :     // and the module name.
     452           0 :     PRThread *currentThread = PR_GetCurrentThread();
     453           0 :     const char *currentThreadName = (mMainThread == currentThread)
     454           0 :       ? "Main Thread"
     455           0 :       : PR_GetThreadName(currentThread);
     456             : 
     457             :     char noNameThread[40];
     458           0 :     if (!currentThreadName) {
     459           0 :       SprintfLiteral(noNameThread, "Unnamed thread %p", currentThread);
     460           0 :       currentThreadName = noNameThread;
     461             :     }
     462             : 
     463           0 :     if (!mAddTimestamp) {
     464           0 :       if (!mIsRaw) {
     465           0 :         fprintf_stderr(out,
     466             :                       "[%ld:%s]: %s/%s %s%s",
     467             :                       pid, currentThreadName, ToLogStr(aLevel),
     468           0 :                       aName, buffToWrite, newline);
     469             :       } else {
     470           0 :         fprintf_stderr(out, "%s%s", buffToWrite, newline);
     471             :       }
     472             :     } else {
     473             :       PRExplodedTime now;
     474           0 :       PR_ExplodeTime(PR_Now(), PR_GMTParameters, &now);
     475           0 :       fprintf_stderr(
     476             :           out,
     477             :           "%04d-%02d-%02d %02d:%02d:%02d.%06d UTC - [%ld:%s]: %s/%s %s%s",
     478           0 :           now.tm_year, now.tm_month + 1, now.tm_mday,
     479             :           now.tm_hour, now.tm_min, now.tm_sec, now.tm_usec,
     480             :           pid, currentThreadName, ToLogStr(aLevel),
     481           0 :           aName, buffToWrite, newline);
     482             :     }
     483             : 
     484           0 :     if (mIsSync) {
     485           0 :       fflush(out);
     486             :     }
     487             : 
     488           0 :     if (mRotate > 0 && outFile) {
     489           0 :       int32_t fileSize = ftell(out);
     490           0 :       if (fileSize > mRotate) {
     491           0 :         uint32_t fileNum = outFile->Num();
     492             : 
     493           0 :         uint32_t nextFileNum = fileNum + 1;
     494           0 :         if (nextFileNum >= kRotateFilesNumber) {
     495           0 :           nextFileNum = 0;
     496             :         }
     497             : 
     498             :         // And here is the trick.  The current out-file remembers its order
     499             :         // number.  When no other thread shifted the global file number yet,
     500             :         // we are the thread to open the next file.
     501           0 :         if (mOutFileNum.compareExchange(fileNum, nextFileNum)) {
     502             :           // We can work with mToReleaseFile because we are sure the
     503             :           // mPrintEntryCount can't drop to zero now - the condition
     504             :           // to actually delete what's stored in that member.
     505             :           // And also, no other thread can enter this piece of code
     506             :           // because mOutFile is still holding the current file with
     507             :           // the non-shifted number.  The compareExchange() above is
     508             :           // a no-op for other threads.
     509           0 :           outFile->mNextToRelease = mToReleaseFile;
     510           0 :           mToReleaseFile = outFile;
     511             : 
     512           0 :           mOutFile = OpenFile(false, nextFileNum);
     513             :         }
     514             :       }
     515             :     }
     516             : 
     517           0 :     if (--mPrintEntryCount == 0 && mToReleaseFile) {
     518             :       // We were the last Print() entered, if there is a file to release
     519             :       // do it now.  exchange() is atomic and makes sure we release the file
     520             :       // only once on one thread.
     521           0 :       detail::LogFile* release = mToReleaseFile.exchange(nullptr);
     522           0 :       delete release;
     523             :     }
     524           0 :   }
     525             : 
     526             : private:
     527             :   OffTheBooksMutex mModulesLock;
     528             :   nsClassHashtable<nsCharPtrHashKey, LogModule> mModules;
     529             : 
     530             :   // Print() entry counter, actually reflects concurrent use of the current
     531             :   // output file.  ReleaseAcquire ensures that manipulation with mOutFile
     532             :   // and mToReleaseFile is synchronized by manipulation with this value.
     533             :   Atomic<uint32_t, ReleaseAcquire> mPrintEntryCount;
     534             :   // File to write to.  ReleaseAcquire because we need to sync mToReleaseFile
     535             :   // with this.
     536             :   Atomic<detail::LogFile*, ReleaseAcquire> mOutFile;
     537             :   // File to be released when reference counter drops to zero.  This member
     538             :   // is assigned mOutFile when the current file has reached the limit.
     539             :   // It can be Relaxed, since it's synchronized with mPrintEntryCount
     540             :   // manipulation and we do atomic exchange() on it.
     541             :   Atomic<detail::LogFile*, Relaxed> mToReleaseFile;
     542             :   // The next file number.  This is mostly only for synchronization sake.
     543             :   // Can have relaxed ordering, since we only do compareExchange on it which
     544             :   // is atomic regardless ordering.
     545             :   Atomic<uint32_t, Relaxed> mOutFileNum;
     546             :   // Just keeps the actual file path for further use.
     547             :   UniqueFreePtr<char[]> mOutFilePath;
     548             : 
     549             :   PRThread *mMainThread;
     550             :   bool mSetFromEnv;
     551             :   Atomic<bool, Relaxed> mAddTimestamp;
     552             :   Atomic<bool, Relaxed> mIsRaw;
     553             :   Atomic<bool, Relaxed> mIsSync;
     554             :   int32_t mRotate;
     555             :   bool mInitialized;
     556             : };
     557             : 
     558           1 : StaticAutoPtr<LogModuleManager> sLogModuleManager;
     559             : 
     560             : LogModule*
     561         104 : LogModule::Get(const char* aName)
     562             : {
     563             :   // This is just a pass through to the LogModuleManager so
     564             :   // that the LogModuleManager implementation can be kept internal.
     565         208 :   MOZ_ASSERT(sLogModuleManager != nullptr);
     566         104 :   return sLogModuleManager->CreateOrGetModule(aName);
     567             : }
     568             : 
     569             : void
     570           0 : LogModule::SetLogFile(const char* aFilename)
     571             : {
     572           0 :   MOZ_ASSERT(sLogModuleManager);
     573           0 :   sLogModuleManager->SetLogFile(aFilename);
     574           0 : }
     575             : 
     576             : uint32_t
     577           0 : LogModule::GetLogFile(char *aBuffer, size_t aLength)
     578             : {
     579           0 :   MOZ_ASSERT(sLogModuleManager);
     580           0 :   return sLogModuleManager->GetLogFile(aBuffer, aLength);
     581             : }
     582             : 
     583             : void
     584           0 : LogModule::SetAddTimestamp(bool aAddTimestamp)
     585             : {
     586           0 :   sLogModuleManager->SetAddTimestamp(aAddTimestamp);
     587           0 : }
     588             : 
     589             : void
     590           0 : LogModule::SetIsSync(bool aIsSync)
     591             : {
     592           0 :   sLogModuleManager->SetIsSync(aIsSync);
     593           0 : }
     594             : 
     595             : void
     596           3 : LogModule::Init(int argc, char* argv[])
     597             : {
     598             :   // NB: This method is not threadsafe; it is expected to be called very early
     599             :   //     in startup prior to any other threads being run.
     600           0 :   MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
     601             : 
     602           3 :   if (sLogModuleManager) {
     603             :     // Already initialized.
     604             :     return;
     605             :   }
     606             : 
     607             :   // NB: We intentionally do not register for ClearOnShutdown as that happens
     608             :   //     before all logging is complete. And, yes, that means we leak, but
     609             :   //     we're doing that intentionally.
     610             : 
     611             :   // Don't assign the pointer until after Init is called. This should help us
     612             :   // detect if any of the functions called by Init somehow rely on logging.
     613           1 :   auto mgr = new LogModuleManager();
     614           1 :   mgr->Init(argc, argv);
     615             :   sLogModuleManager = mgr;
     616             : }
     617             : 
     618             : void
     619           0 : LogModule::Printv(LogLevel aLevel, const char* aFmt, va_list aArgs) const
     620             : {
     621           0 :   MOZ_ASSERT(sLogModuleManager != nullptr);
     622             : 
     623             :   // Forward to LogModule manager w/ level and name
     624             :   sLogModuleManager->Print(Name(), aLevel, aFmt, aArgs);
     625             : }
     626             : 
     627             : } // namespace mozilla

Generated by: LCOV version 1.13-14-ga5dd952