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