Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/base/LogModulePrefWatcher.cpp
Line
Count
Source (jump to first uncovered line)
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 "LogModulePrefWatcher.h"
8
9
#include "mozilla/Logging.h"
10
#include "mozilla/Preferences.h"
11
#include "nsMemory.h"
12
#include "nsString.h"
13
#include "nsXULAppAPI.h"
14
#include "base/process_util.h"
15
16
static const char kLoggingPrefPrefix[] = "logging.";
17
static const char kLoggingConfigPrefPrefix[] = "logging.config";
18
static const int  kLoggingConfigPrefixLen = sizeof(kLoggingConfigPrefPrefix) - 1;
19
static const char kLoggingPrefClearOnStartup[] = "logging.config.clear_on_startup";
20
static const char kLoggingPrefLogFile[] = "logging.config.LOG_FILE";
21
static const char kLoggingPrefAddTimestamp[] = "logging.config.add_timestamp";
22
static const char kLoggingPrefSync[] = "logging.config.sync";
23
24
namespace mozilla {
25
26
NS_IMPL_ISUPPORTS(LogModulePrefWatcher, nsIObserver)
27
28
/**
29
 * Resets all the preferences in the logging. branch
30
 * This is needed because we may crash while logging, and this would cause us
31
 * to log after restarting as well.
32
 *
33
 * If logging after restart is desired, set the logging.config.clear_on_startup
34
 * pref to false, or use the MOZ_LOG_FILE and MOZ_LOG_MODULES env vars.
35
 */
36
void ResetExistingPrefs()
37
0
{
38
0
  uint32_t count;
39
0
  char** names;
40
0
  nsresult rv = Preferences::GetRootBranch()->
41
0
      GetChildList(kLoggingPrefPrefix, &count, &names);
42
0
  if (NS_SUCCEEDED(rv) && count) {
43
0
    for (size_t i = 0; i < count; i++) {
44
0
      // Clearing the pref will cause it to reload, thus resetting the log level
45
0
      Preferences::ClearUser(names[i]);
46
0
    }
47
0
    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, names);
48
0
  }
49
0
}
50
51
/**
52
 * Loads the log level from the given pref and updates the corresponding
53
 * LogModule.
54
 */
55
static void
56
LoadPrefValue(const char* aName)
57
3
{
58
3
  LogLevel logLevel = LogLevel::Disabled;
59
3
60
3
  nsresult rv;
61
3
  int32_t prefLevel = 0;
62
3
  nsAutoCString prefValue;
63
3
64
3
  if (strncmp(aName, kLoggingConfigPrefPrefix, kLoggingConfigPrefixLen) == 0) {
65
3
    nsAutoCString prefName(aName);
66
3
67
3
    if (prefName.EqualsLiteral(kLoggingPrefLogFile)) {
68
0
      rv = Preferences::GetCString(aName, prefValue);
69
0
      // The pref was reset. Clear the user file.
70
0
      if (NS_FAILED(rv) || prefValue.IsEmpty()) {
71
0
        LogModule::SetLogFile(nullptr);
72
0
        return;
73
0
      }
74
0
75
0
      // If the pref value doesn't have a PID placeholder, append it to the end.
76
0
      if (!strstr(prefValue.get(), "%PID")) {
77
0
        prefValue.AppendLiteral("%PID");
78
0
      }
79
0
80
0
      LogModule::SetLogFile(prefValue.BeginReading());
81
3
    } else if (prefName.EqualsLiteral(kLoggingPrefAddTimestamp)) {
82
0
      bool addTimestamp = Preferences::GetBool(aName, false);
83
0
      LogModule::SetAddTimestamp(addTimestamp);
84
3
    } else if (prefName.EqualsLiteral(kLoggingPrefSync)) {
85
0
      bool sync = Preferences::GetBool(aName, false);
86
0
      LogModule::SetIsSync(sync);
87
0
    }
88
3
    return;
89
0
  }
90
0
91
0
  if (Preferences::GetInt(aName, &prefLevel) == NS_OK) {
92
0
    logLevel = ToLogLevel(prefLevel);
93
0
  } else if (Preferences::GetCString(aName, prefValue) == NS_OK) {
94
0
    if (prefValue.LowerCaseEqualsLiteral("error")) {
95
0
      logLevel = LogLevel::Error;
96
0
    } else if (prefValue.LowerCaseEqualsLiteral("warning")) {
97
0
      logLevel = LogLevel::Warning;
98
0
    } else if (prefValue.LowerCaseEqualsLiteral("info")) {
99
0
      logLevel = LogLevel::Info;
100
0
    } else if (prefValue.LowerCaseEqualsLiteral("debug")) {
101
0
      logLevel = LogLevel::Debug;
102
0
    } else if (prefValue.LowerCaseEqualsLiteral("verbose")) {
103
0
      logLevel = LogLevel::Verbose;
104
0
    }
105
0
  }
106
0
107
0
  const char* moduleName = aName + strlen(kLoggingPrefPrefix);
108
0
  LogModule::Get(moduleName)->SetLevel(logLevel);
109
0
}
110
111
void
112
LoadExistingPrefs()
113
3
{
114
3
  nsIPrefBranch* root = Preferences::GetRootBranch();
115
3
  if (!root) {
116
0
    return;
117
0
  }
118
3
119
3
  uint32_t count;
120
3
  char** names;
121
3
  nsresult rv = root->GetChildList(kLoggingPrefPrefix, &count, &names);
122
3
  if (NS_SUCCEEDED(rv) && count) {
123
6
    for (size_t i = 0; i < count; i++) {
124
3
      LoadPrefValue(names[i]);
125
3
    }
126
3
    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, names);
127
3
  }
128
3
}
129
130
LogModulePrefWatcher::LogModulePrefWatcher()
131
3
{
132
3
}
133
134
void
135
LogModulePrefWatcher::RegisterPrefWatcher()
136
3
{
137
3
  RefPtr<LogModulePrefWatcher> prefWatcher = new LogModulePrefWatcher();
138
3
  Preferences::AddStrongObserver(prefWatcher, kLoggingPrefPrefix);
139
3
140
3
  nsCOMPtr<nsIObserverService> observerService =
141
3
    mozilla::services::GetObserverService();
142
3
  if (observerService && XRE_IsParentProcess()) {
143
3
    observerService->AddObserver(prefWatcher, "browser-delayed-startup-finished", false);
144
3
  }
145
3
146
3
  LoadExistingPrefs();
147
3
}
148
149
NS_IMETHODIMP
150
LogModulePrefWatcher::Observe(nsISupports* aSubject, const char* aTopic,
151
                              const char16_t* aData)
152
0
{
153
0
  if (strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic) == 0) {
154
0
    NS_LossyConvertUTF16toASCII prefName(aData);
155
0
    LoadPrefValue(prefName.get());
156
0
  } else if (strcmp("browser-delayed-startup-finished", aTopic) == 0) {
157
0
    bool clear = Preferences::GetBool(kLoggingPrefClearOnStartup, true);
158
0
    if (clear) {
159
0
      ResetExistingPrefs();
160
0
    }
161
0
    nsCOMPtr<nsIObserverService> observerService =
162
0
      mozilla::services::GetObserverService();
163
0
    if (observerService) {
164
0
      observerService->RemoveObserver(this, "browser-delayed-startup-finished");
165
0
    }
166
0
  }
167
0
168
0
  return NS_OK;
169
0
}
170
171
} // namespace mozilla