author Eric Rahm <erahm@mozilla.com>
Mon, 19 Oct 2015 12:22:11 -0700
changeset 303814 342c95afb454a19b82bbfebdef8bd289cac157ea
child 316029 57af526c36540febcc4abd173e84468ed3050ed2
permissions -rw-r--r--
Bug 1174785 - Part 1: Add LogModule, LogModuleManager, and LazyLogModule. r=froydnj The logging interface is moved to xpcom/base, a LogModule wrapper for PR_Log is added, a thread-safe LogModuleManager is added, and a LazyLogModule class used to lazily load log modules in a thread-safe manner is added.

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/Logging.h"

#include <algorithm>

#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Mutex.h"
#include "mozilla/StaticPtr.h"
#include "nsClassHashtable.h"

// NB: Initial amount determined by auditing the codebase for the total amount
//     of unique module names and padding up to the next power of 2.
const uint32_t kInitialModuleCount = 256;

namespace mozilla {
 * Safely converts an integer into a valid LogLevel.
Clamp(int32_t aLevel)
  aLevel = std::min(aLevel, static_cast<int32_t>(LogLevel::Verbose));
  aLevel = std::max(aLevel, static_cast<int32_t>(LogLevel::Disabled));
  return static_cast<LogLevel>(aLevel);

class LogModuleManager
    : mModulesLock("logmodules")
    , mModules(kInitialModuleCount)

    // NB: mModules owns all of the log modules, they will get destroyed by
    //     its destructor.

  LogModule* CreateOrGetModule(const char* aName)
    OffTheBooksMutexAutoLock guard(mModulesLock);
    LogModule* module = nullptr;
    if (!mModules.Get(aName, &module)) {
      // Create the PRLogModule, this will read any env vars that set the log
      // level ahead of time. The module is held internally by NSPR, so it's
      // okay to drop the pointer when leaving this scope.
      PRLogModuleInfo* prModule = PR_NewLogModule(aName);

      // NSPR does not impose a restriction on the values that log levels can
      // be. LogModule uses the LogLevel enum class so we must clamp the value
      // to a max of Verbose.
      LogLevel logLevel = Clamp(prModule->level);
      module = new LogModule(logLevel);
      mModules.Put(aName, module);

    return module;

  OffTheBooksMutex mModulesLock;
  nsClassHashtable<nsCharPtrHashKey, LogModule> mModules;

StaticAutoPtr<LogModuleManager> sLogModuleManager;

LogModule::Get(const char* aName)
  // This is just a pass through to the LogModuleManager so
  // that the LogModuleManager implementation can be kept internal.
  MOZ_ASSERT(sLogModuleManager != nullptr);
  return sLogModuleManager->CreateOrGetModule(aName);

  // NB: This method is not threadsafe; it is expected to be called very early
  //     in startup prior to any other threads being run.
  if (sLogModuleManager) {
    // Already initialized.

  // NB: We intentionally do not register for ClearOnShutdown as that happens
  //     before all logging is complete. And, yes, that means we leak, but
  //     we're doing that intentionally.
  sLogModuleManager = new LogModuleManager();

} // namespace mozilla