Bug 1233881 - Support dynamically setting log levels at runtime via prefs. r=froydnj

Adds support for changing log levels at runtime via 'logging.*' preferences.
This commit is contained in:
Eric Rahm 2015-12-22 15:09:41 -08:00
parent 5068114946
commit 9664d9a74d
6 changed files with 161 additions and 5 deletions

View File

@ -0,0 +1,90 @@
/* -*- 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 "LogModulePrefWatcher.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "nsString.h"
static const char kLoggingPrefPrefix[] = "logging.";
namespace mozilla {
NS_IMPL_ISUPPORTS(LogModulePrefWatcher, nsIObserver)
/**
* Loads the log level from the given pref and updates the corresponding
* LogModule.
*/
void
LoadPrefValue(const char* aName)
{
LogLevel logLevel = LogLevel::Disabled;
int32_t prefLevel = 0;
nsAutoCString prefStr;
if (Preferences::GetInt(aName, &prefLevel) == NS_OK) {
logLevel = ToLogLevel(prefLevel);
} else if (Preferences::GetCString(aName, &prefStr) == NS_OK) {
if (prefStr.LowerCaseEqualsLiteral("error")) {
logLevel = LogLevel::Error;
} else if (prefStr.LowerCaseEqualsLiteral("warning")) {
logLevel = LogLevel::Warning;
} else if (prefStr.LowerCaseEqualsLiteral("info")) {
logLevel = LogLevel::Info;
} else if (prefStr.LowerCaseEqualsLiteral("debug")) {
logLevel = LogLevel::Debug;
} else if (prefStr.LowerCaseEqualsLiteral("verbose")) {
logLevel = LogLevel::Verbose;
}
}
const char* moduleName = aName + strlen(kLoggingPrefPrefix);
LogModule::Get(moduleName)->SetLevel(logLevel);
}
void
LoadExistingPrefs()
{
uint32_t count;
char** names;
nsresult rv = Preferences::GetRootBranch()->
GetChildList(kLoggingPrefPrefix, &count, &names);
if (NS_SUCCEEDED(rv) && count) {
for (size_t i = 0; i < count; i++) {
LoadPrefValue(names[i]);
}
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, names);
}
}
LogModulePrefWatcher::LogModulePrefWatcher()
{
}
void
LogModulePrefWatcher::RegisterPrefWatcher()
{
RefPtr<LogModulePrefWatcher> prefWatcher = new LogModulePrefWatcher();
Preferences::AddStrongObserver(prefWatcher, kLoggingPrefPrefix);
LoadExistingPrefs();
}
NS_IMETHODIMP
LogModulePrefWatcher::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData)
{
if (strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic) == 0) {
NS_LossyConvertUTF16toASCII prefName(aData);
LoadPrefValue(prefName.get());
}
return NS_OK;
}
} // namespace mozilla

View File

@ -0,0 +1,42 @@
/* -*- 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/. */
#ifndef LogModulePrefWatcher_h
#define LogModulePrefWatcher_h
#include "nsIObserver.h"
namespace mozilla {
/**
* Watches for changes to "logging.*" prefs and then updates the appropriate
* LogModule's log level. Both the integer and string versions of the LogLevel
* enum are supported.
*
* For example setting the pref "logging.Foo" to "Verbose" will set the
* LogModule for "Foo" to the LogLevel::Verbose level. Setting "logging.Bar" to
* 4 would set the LogModule for "Bar" to the LogLevel::Debug level.
*/
class LogModulePrefWatcher : public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
/**
* Starts observing logging pref changes.
*/
static void RegisterPrefWatcher();
private:
LogModulePrefWatcher();
virtual ~LogModulePrefWatcher()
{
}
};
} // namespace mozilla
#endif // LogModulePrefWatcher_h

View File

@ -18,11 +18,9 @@
const uint32_t kInitialModuleCount = 256;
namespace mozilla {
/**
* Safely converts an integer into a valid LogLevel.
*/
LogLevel
Clamp(int32_t aLevel)
ToLogLevel(int32_t aLevel)
{
aLevel = std::min(aLevel, static_cast<int32_t>(LogLevel::Verbose));
aLevel = std::max(aLevel, static_cast<int32_t>(LogLevel::Disabled));
@ -57,7 +55,7 @@ public:
// 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);
LogLevel logLevel = ToLogLevel(prModule->level);
module = new LogModule(logLevel);
mModules.Put(aName, module);
}

View File

@ -45,6 +45,11 @@ enum class LogLevel {
Verbose,
};
/**
* Safely converts an integer into a valid LogLevel.
*/
LogLevel ToLogLevel(int32_t aLevel);
class LogModule
{
public:
@ -74,6 +79,11 @@ public:
*/
LogLevel Level() const { return mLevel; }
/**
* Sets the log module's level.
*/
void SetLevel(LogLevel level) { mLevel = level; }
private:
friend class LogModuleManager;

View File

@ -109,6 +109,7 @@ UNIFIED_SOURCES += [
'HoldDropJSObjects.cpp',
'JSObjectHolder.cpp',
'Logging.cpp',
'LogModulePrefWatcher.cpp',
'nsConsoleMessage.cpp',
'nsConsoleService.cpp',
'nsCycleCollector.cpp',

View File

@ -79,6 +79,7 @@
#include "mozilla/Omnijar.h"
#include "mozilla/Logging.h"
#include "LogModulePrefWatcher.h"
using namespace mozilla;
@ -448,6 +449,20 @@ nsComponentManagerImpl::Init()
nsCategoryManager::GetSingleton()->SuppressNotifications(false);
RegisterWeakMemoryReporter(this);
// NB: The logging preference watcher needs to be registered late enough in
// startup that it's okay to use the preference system, but also as soon as
// possible so that log modules enabled via preferences are turned on as
// early as possible.
//
// We can't initialize the preference watcher when the log module manager is
// initialized, as a number of things attempt to start logging before the
// preference system is initialized.
//
// The preference system is registered as a component so at this point during
// component manager initialization we know it is setup and we can register
// for notifications.
LogModulePrefWatcher::RegisterPrefWatcher();
#endif
// Unfortunately, we can't register the nsCategoryManager memory reporter