Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this
3 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #include "WebRtcLog.h"
6 :
7 : #include "mozilla/Logging.h"
8 : #include "mozilla/StaticPtr.h"
9 : #include "prenv.h"
10 : #include "webrtc/system_wrappers/include/trace.h"
11 : #include "webrtc/common_types.h"
12 : #include "webrtc/base/logging.h"
13 :
14 : #include "nscore.h"
15 : #include "nsString.h"
16 : #include "nsXULAppAPI.h"
17 : #include "mozilla/Preferences.h"
18 :
19 : #include "nsIFile.h"
20 : #include "nsDirectoryServiceUtils.h"
21 : #include "nsDirectoryServiceDefs.h"
22 :
23 : using mozilla::LogLevel;
24 :
25 : static int gWebRtcTraceLoggingOn = 0;
26 :
27 : #if defined(ANDROID)
28 : static const char *default_tmp_dir = "/dev/null";
29 : static const char *default_log_name = "nspr";
30 : #else // Assume a POSIX environment
31 3 : NS_NAMED_LITERAL_CSTRING(default_log_name, "WebRTC.log");
32 : #endif
33 :
34 : static mozilla::LazyLogModule sWebRtcLog("webrtc_trace");
35 : static mozilla::LazyLogModule sLogAEC("AEC");
36 :
37 3 : class WebRtcTraceCallback: public webrtc::TraceCallback
38 : {
39 : public:
40 0 : void Print(webrtc::TraceLevel level, const char* message, int length)
41 : {
42 0 : MOZ_LOG(sWebRtcLog, LogLevel::Debug, ("%s", message));
43 0 : }
44 : };
45 :
46 0 : class LogSinkImpl : public rtc::LogSink
47 : {
48 : public:
49 0 : LogSinkImpl() {}
50 :
51 : private:
52 0 : void OnLogMessage(const std::string& message) override {
53 0 : MOZ_LOG(sWebRtcLog, LogLevel::Debug, ("%s", message.data()));
54 0 : }
55 : };
56 :
57 : // For WEBRTC_TRACE()
58 3 : static WebRtcTraceCallback gWebRtcCallback;
59 : // For LOG()
60 3 : static mozilla::StaticAutoPtr<LogSinkImpl> sSink;
61 :
62 0 : void GetWebRtcLogPrefs(uint32_t *aTraceMask, nsACString* aLogFile, nsACString *aAECLogDir, bool *aMultiLog)
63 : {
64 0 : *aMultiLog = mozilla::Preferences::GetBool("media.webrtc.debug.multi_log");
65 0 : *aTraceMask = mozilla::Preferences::GetUint("media.webrtc.debug.trace_mask");
66 0 : mozilla::Preferences::GetCString("media.webrtc.debug.log_file", aLogFile);
67 0 : mozilla::Preferences::GetCString("media.webrtc.debug.aec_log_dir", aAECLogDir);
68 0 : webrtc::Trace::set_aec_debug_size(mozilla::Preferences::GetUint("media.webrtc.debug.aec_dump_max_size"));
69 0 : }
70 :
71 : mozilla::LogLevel
72 0 : CheckOverrides(uint32_t *aTraceMask, nsACString *aLogFile, bool *aMultiLog)
73 : {
74 0 : mozilla::LogModule *log_info = sWebRtcLog;
75 0 : mozilla::LogLevel log_level = log_info->Level();
76 :
77 0 : if (!aTraceMask || !aLogFile || !aMultiLog) {
78 0 : return log_level;
79 : }
80 :
81 : // Override or fill in attributes from the environment if possible.
82 0 : switch (log_level) {
83 : case mozilla::LogLevel::Verbose:
84 0 : *aTraceMask = webrtc::TraceLevel::kTraceAll;
85 0 : break;
86 : case mozilla::LogLevel::Debug:
87 0 : *aTraceMask = 0x1fff; // kTraceInfo and below
88 0 : break;
89 : case mozilla::LogLevel::Info:
90 0 : *aTraceMask = 0x07ff; // kTraceStream and below;
91 0 : break;
92 : case mozilla::LogLevel::Warning:
93 0 : *aTraceMask = webrtc::TraceLevel::kTraceDefault; // ktraceModule and below
94 0 : break;
95 : case mozilla::LogLevel::Error:
96 0 : *aTraceMask = webrtc::TraceLevel::kTraceWarning |
97 : webrtc::TraceLevel::kTraceError |
98 : webrtc::TraceLevel::kTraceStateInfo;
99 0 : break;
100 : case mozilla::LogLevel::Disabled:
101 : default:
102 0 : *aTraceMask = 0;
103 : }
104 :
105 : // Allow it to be overridden
106 0 : char *trace_level = getenv("WEBRTC_TRACE_LEVEL");
107 0 : if (trace_level && *trace_level) {
108 0 : *aTraceMask = atoi(trace_level);
109 : }
110 :
111 0 : log_info = sLogAEC;
112 0 : if (sLogAEC && (log_info->Level() != mozilla::LogLevel::Disabled)) {
113 0 : webrtc::Trace::set_aec_debug(true);
114 : }
115 :
116 0 : const char *file_name = PR_GetEnv("WEBRTC_TRACE_FILE");
117 0 : if (file_name) {
118 0 : aLogFile->Assign(file_name);
119 : }
120 0 : return log_level;
121 : }
122 :
123 0 : void ConfigWebRtcLog(mozilla::LogLevel level, uint32_t trace_mask,
124 : nsCString &aLogFile, nsCString &aAECLogDir, bool multi_log)
125 : {
126 0 : if (gWebRtcTraceLoggingOn) {
127 0 : return;
128 : }
129 :
130 : #if defined(ANDROID)
131 : // Special case: use callback to pipe to NSPR logging.
132 : aLogFile.Assign(default_log_name);
133 : #else
134 :
135 : rtc::LoggingSeverity log_level;
136 0 : switch (level) {
137 : case mozilla::LogLevel::Verbose:
138 0 : log_level = rtc::LoggingSeverity::LS_VERBOSE;
139 0 : break;
140 : case mozilla::LogLevel::Debug:
141 : case mozilla::LogLevel::Info:
142 0 : log_level = rtc::LoggingSeverity::LS_INFO;
143 0 : break;
144 : case mozilla::LogLevel::Warning:
145 0 : log_level = rtc::LoggingSeverity::LS_WARNING;
146 0 : break;
147 : case mozilla::LogLevel::Error:
148 0 : log_level = rtc::LoggingSeverity::LS_ERROR;
149 0 : break;
150 : case mozilla::LogLevel::Disabled:
151 0 : log_level = rtc::LoggingSeverity::LS_NONE;
152 0 : break;
153 : default:
154 0 : MOZ_ASSERT(false);
155 : break;
156 : }
157 0 : rtc::LogMessage::LogToDebug(log_level);
158 0 : if (level != mozilla::LogLevel::Disabled) {
159 : // always capture LOG(...) << ... logging in webrtc.org code to nspr logs
160 0 : if (!sSink) {
161 0 : sSink = new LogSinkImpl();
162 0 : rtc::LogMessage::AddLogToStream(sSink, log_level);
163 : // it's ok if this leaks to program end
164 : }
165 0 : } else if (sSink) {
166 0 : rtc::LogMessage::RemoveLogToStream(sSink);
167 0 : sSink = nullptr;
168 : }
169 :
170 0 : webrtc::Trace::set_level_filter(trace_mask);
171 0 : if (trace_mask != 0) {
172 : // default WEBRTC_TRACE logs to a rotating file, but allow redirecting to nspr
173 : // XXX always redirect in e10s if the sandbox blocks file access, or somehow proxy
174 0 : if (aLogFile.EqualsLiteral("nspr") || aLogFile.EqualsLiteral("moz_log")) {
175 0 : rtc::LogMessage::SetLogToStderr(false);
176 0 : webrtc::Trace::SetTraceCallback(&gWebRtcCallback);
177 : } else {
178 0 : rtc::LogMessage::SetLogToStderr(true);
179 0 : webrtc::Trace::SetTraceFile(aLogFile.get(), multi_log);
180 : }
181 : } else {
182 0 : rtc::LogMessage::SetLogToStderr(false);
183 : }
184 :
185 0 : if (aLogFile.IsEmpty()) {
186 0 : nsCOMPtr<nsIFile> tempDir;
187 0 : nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tempDir));
188 0 : if (NS_SUCCEEDED(rv)) {
189 0 : tempDir->AppendNative(default_log_name);
190 0 : tempDir->GetNativePath(aLogFile);
191 : }
192 : }
193 : #endif
194 :
195 0 : if (XRE_IsParentProcess()) {
196 : // Capture the final choice for the trace setting.
197 0 : mozilla::Preferences::SetCString("media.webrtc.debug.log_file", aLogFile);
198 : }
199 0 : return;
200 : }
201 :
202 0 : void StartWebRtcLog(uint32_t log_level)
203 : {
204 0 : if (gWebRtcTraceLoggingOn && log_level != 0) {
205 0 : return;
206 : }
207 :
208 0 : if (log_level == 0) {
209 0 : if (gWebRtcTraceLoggingOn) {
210 0 : gWebRtcTraceLoggingOn = false;
211 0 : webrtc::Trace::set_level_filter(webrtc::kTraceNone);
212 : }
213 0 : return;
214 : }
215 :
216 0 : uint32_t trace_mask = 0;
217 0 : bool multi_log = false;
218 0 : nsAutoCString log_file;
219 0 : nsAutoCString aec_log_dir;
220 :
221 0 : GetWebRtcLogPrefs(&trace_mask, &log_file, &aec_log_dir, &multi_log);
222 0 : mozilla::LogLevel level = CheckOverrides(&trace_mask, &log_file, &multi_log);
223 :
224 0 : if (trace_mask == 0) {
225 0 : trace_mask = log_level;
226 : }
227 :
228 0 : ConfigWebRtcLog(level, trace_mask, log_file, aec_log_dir, multi_log);
229 0 : return;
230 :
231 : }
232 :
233 0 : void EnableWebRtcLog()
234 : {
235 0 : if (gWebRtcTraceLoggingOn) {
236 0 : return;
237 : }
238 :
239 0 : uint32_t trace_mask = 0;
240 0 : bool multi_log = false;
241 0 : nsAutoCString log_file;
242 0 : nsAutoCString aec_log_dir;
243 :
244 0 : GetWebRtcLogPrefs(&trace_mask, &log_file, &aec_log_dir, &multi_log);
245 0 : mozilla::LogLevel level = CheckOverrides(&trace_mask, &log_file, &multi_log);
246 0 : ConfigWebRtcLog(level, trace_mask, log_file, aec_log_dir, multi_log);
247 0 : return;
248 : }
249 :
250 : // Called when we destroy the singletons from PeerConnectionCtx or if the
251 : // user changes logging in about:webrtc
252 0 : void StopWebRtcLog()
253 : {
254 : // TODO(NG) strip/fix gWebRtcTraceLoggingOn which is never set to true
255 0 : webrtc::Trace::set_level_filter(webrtc::kTraceNone);
256 0 : webrtc::Trace::SetTraceCallback(nullptr);
257 0 : webrtc::Trace::SetTraceFile(nullptr);
258 0 : if (sSink) {
259 0 : rtc::LogMessage::RemoveLogToStream(sSink);
260 0 : sSink = nullptr;
261 : }
262 0 : }
263 :
264 0 : void ConfigAecLog(nsCString &aAECLogDir) {
265 0 : if (webrtc::Trace::aec_debug()) {
266 0 : return;
267 : }
268 : #if defined(ANDROID)
269 : // For AEC, do not use a default value: force the user to specify a directory.
270 : if (aAECLogDir.IsEmpty()) {
271 : aAECLogDir.Assign(default_tmp_dir);
272 : }
273 : #else
274 0 : if (aAECLogDir.IsEmpty()) {
275 0 : nsCOMPtr<nsIFile> tempDir;
276 0 : nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tempDir));
277 0 : if (NS_SUCCEEDED(rv)) {
278 0 : if (aAECLogDir.IsEmpty()) {
279 0 : tempDir->GetNativePath(aAECLogDir);
280 : }
281 : }
282 : }
283 : #endif
284 0 : webrtc::Trace::set_aec_debug_filename(aAECLogDir.get());
285 0 : if (XRE_IsParentProcess()) {
286 : // Capture the final choice for the aec_log_dir setting.
287 0 : mozilla::Preferences::SetCString("media.webrtc.debug.aec_log_dir", aAECLogDir);
288 : }
289 : }
290 :
291 0 : void StartAecLog()
292 : {
293 0 : if (webrtc::Trace::aec_debug()) {
294 0 : return;
295 : }
296 0 : uint32_t trace_mask = 0;
297 0 : bool multi_log = false;
298 0 : nsAutoCString log_file;
299 0 : nsAutoCString aec_log_dir;
300 :
301 0 : GetWebRtcLogPrefs(&trace_mask, &log_file, &aec_log_dir, &multi_log);
302 0 : CheckOverrides(&trace_mask, &log_file, &multi_log);
303 0 : ConfigAecLog(aec_log_dir);
304 :
305 0 : webrtc::Trace::set_aec_debug(true);
306 : }
307 :
308 0 : void StopAecLog()
309 : {
310 0 : webrtc::Trace::set_aec_debug(false);
311 0 : }
|