blob: c87698add7f40bae6c1eaa2f40bb86d08c87479f [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#if defined(WEBRTC_WIN)
Tommi23edcff2015-05-25 10:45:43 +020012#if !defined(WIN32_LEAN_AND_MEAN)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000013#define WIN32_LEAN_AND_MEAN
Tommi23edcff2015-05-25 10:45:43 +020014#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000015#include <windows.h>
conceptgenesis3f705622016-01-30 14:40:44 -080016#if _MSC_VER < 1900
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000017#define snprintf _snprintf
conceptgenesis3f705622016-01-30 14:40:44 -080018#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000019#undef ERROR // wingdi.h
20#endif
21
22#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
23#include <CoreServices/CoreServices.h>
24#elif defined(WEBRTC_ANDROID)
25#include <android/log.h>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000026// Android has a 1024 limit on log inputs. We use 60 chars as an
27// approx for the header/tag portion.
28// See android/system/core/liblog/logd_write.c
29static const int kMaxLogLineSize = 1024 - 60;
30#endif // WEBRTC_MAC && !defined(WEBRTC_IOS) || WEBRTC_ANDROID
31
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000032#include <limits.h>
Yves Gerey665174f2018-06-19 15:03:05 +020033#include <time.h>
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000034
35#include <algorithm>
Karl Wibergcefc4652018-05-23 23:20:38 +020036#include <cstdarg>
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000037#include <iomanip>
38#include <ostream>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000039#include <vector>
40
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020041#include "rtc_base/criticalsection.h"
42#include "rtc_base/logging.h"
Tommie51a0a82018-02-27 15:30:29 +010043#include "rtc_base/platform_thread_types.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020044#include "rtc_base/stringencode.h"
Tommifef05002018-02-27 13:51:08 +010045#include "rtc_base/strings/string_builder.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020046#include "rtc_base/stringutils.h"
47#include "rtc_base/timeutils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000048
49namespace rtc {
andrew88703d72015-09-07 00:34:56 -070050namespace {
Jonas Olsson2b6f1352018-02-15 11:57:03 +010051// By default, release builds don't log, debug builds at info level
52#if !defined(NDEBUG)
53static LoggingSeverity g_min_sev = LS_INFO;
54static LoggingSeverity g_dbg_sev = LS_INFO;
55#else
56static LoggingSeverity g_min_sev = LS_NONE;
57static LoggingSeverity g_dbg_sev = LS_NONE;
58#endif
andrew88703d72015-09-07 00:34:56 -070059
60// Return the filename portion of the string (that following the last slash).
61const char* FilenameFromPath(const char* file) {
62 const char* end1 = ::strrchr(file, '/');
63 const char* end2 = ::strrchr(file, '\\');
64 if (!end1 && !end2)
65 return file;
66 else
67 return (end1 > end2) ? end1 + 1 : end2 + 1;
68}
69
Tommifef05002018-02-27 13:51:08 +010070std::ostream& GetNoopStream() {
71 class NoopStreamBuf : public std::streambuf {
72 public:
73 int overflow(int c) override { return c; }
74 };
75 static NoopStreamBuf noop_buffer;
76 static std::ostream noop_stream(&noop_buffer);
77 return noop_stream;
78}
79
Jonas Olsson2b6f1352018-02-15 11:57:03 +010080// Global lock for log subsystem, only needed to serialize access to streams_.
81CriticalSection g_log_crit;
andrew88703d72015-09-07 00:34:56 -070082} // namespace
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000083
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +020084// Inefficient default implementation, override is recommended.
85void LogSink::OnLogMessage(const std::string& msg,
86 LoggingSeverity severity,
87 const char* tag) {
88 OnLogMessage(tag + (": " + msg));
89}
90
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000091/////////////////////////////////////////////////////////////////////////////
92// LogMessage
93/////////////////////////////////////////////////////////////////////////////
94
andrew88703d72015-09-07 00:34:56 -070095bool LogMessage::log_to_stderr_ = true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000096
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000097// The list of logging streams currently configured.
98// Note: we explicitly do not clean this up, because of the uncertain ordering
99// of destructors at program exit. Let the person who sets the stream trigger
deadbeef37f5ecf2017-02-27 14:06:41 -0800100// cleanup by setting to null, or let it leak (safe at program exit).
danilchap3c6abd22017-09-06 05:46:29 -0700101LogMessage::StreamList LogMessage::streams_ RTC_GUARDED_BY(g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000102
103// Boolean options default to false (0)
104bool LogMessage::thread_, LogMessage::timestamp_;
105
Karl Wibergab4f1c12018-05-04 10:42:28 +0200106LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
107 : LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
108
Peter Boström225789d2015-10-23 15:20:56 +0200109LogMessage::LogMessage(const char* file,
110 int line,
111 LoggingSeverity sev,
112 LogErrorContext err_ctx,
Tommie51a0a82018-02-27 15:30:29 +0100113 int err)
114 : severity_(sev), is_noop_(IsNoop(sev)) {
Tommifef05002018-02-27 13:51:08 +0100115 // If there's no need to do any work, let's not :)
116 if (is_noop_)
117 return;
118
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000119 if (timestamp_) {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700120 // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
121 // in log messages represents the real system time.
122 int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000123 // Also ensure WallClockStartTime is initialized, so that it matches
124 // LogStartTime.
125 WallClockStartTime();
126 print_stream_ << "[" << std::setfill('0') << std::setw(3) << (time / 1000)
127 << ":" << std::setw(3) << (time % 1000) << std::setfill(' ')
128 << "] ";
129 }
130
131 if (thread_) {
henrikaba35d052015-07-14 17:04:08 +0200132 PlatformThreadId id = CurrentThreadId();
133 print_stream_ << "[" << std::dec << id << "] ";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000134 }
135
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200136 if (file != nullptr) {
137#if defined(WEBRTC_ANDROID)
138 tag_ = FilenameFromPath(file);
139 print_stream_ << "(line " << line << "): ";
140#else
Yves Gerey665174f2018-06-19 15:03:05 +0200141 print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200142#endif
143 }
andrew88703d72015-09-07 00:34:56 -0700144
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000145 if (err_ctx != ERRCTX_NONE) {
Karl Wiberg881f1682018-03-08 15:03:23 +0100146 char tmp_buf[1024];
147 SimpleStringBuilder tmp(tmp_buf);
Tommifef05002018-02-27 13:51:08 +0100148 tmp.AppendFormat("[0x%08X]", err);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000149 switch (err_ctx) {
150 case ERRCTX_ERRNO:
151 tmp << " " << strerror(err);
152 break;
kwiberg77eab702016-09-28 17:42:01 -0700153#ifdef WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000154 case ERRCTX_HRESULT: {
155 char msgbuf[256];
Yves Gerey665174f2018-06-19 15:03:05 +0200156 DWORD flags =
157 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000158 if (DWORD len = FormatMessageA(
Tommie51a0a82018-02-27 15:30:29 +0100159 flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
deadbeef37f5ecf2017-02-27 14:06:41 -0800160 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000161 while ((len > 0) &&
Yves Gerey665174f2018-06-19 15:03:05 +0200162 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000163 msgbuf[--len] = 0;
164 }
165 tmp << " " << msgbuf;
166 }
167 break;
168 }
Tommi0eefb4d2015-05-23 09:54:07 +0200169#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000170#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
171 case ERRCTX_OSSTATUS: {
Tommi09ca02e2016-04-24 17:32:48 +0200172 std::string desc(DescriptionFromOSStatus(err));
173 tmp << " " << (desc.empty() ? "Unknown error" : desc.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000174 break;
175 }
176#endif // WEBRTC_MAC && !defined(WEBRTC_IOS)
177 default:
178 break;
179 }
180 extra_ = tmp.str();
181 }
182}
183
Tommie51a0a82018-02-27 15:30:29 +0100184#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700185LogMessage::LogMessage(const char* file,
186 int line,
187 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100188 const char* tag)
Yves Gerey665174f2018-06-19 15:03:05 +0200189 : LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */) {
Tommifef05002018-02-27 13:51:08 +0100190 if (!is_noop_) {
191 tag_ = tag;
Alex Glaznev5abd78b2018-06-01 19:12:58 +0000192 print_stream_ << tag << ": ";
Tommifef05002018-02-27 13:51:08 +0100193 }
jiayl66f0da22015-09-14 15:06:39 -0700194}
Tommie51a0a82018-02-27 15:30:29 +0100195#endif
196
197// DEPRECATED. Currently only used by downstream projects that use
198// implementation details of logging.h. Work is ongoing to remove those
199// dependencies.
Yves Gerey665174f2018-06-19 15:03:05 +0200200LogMessage::LogMessage(const char* file,
201 int line,
202 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100203 const std::string& tag)
204 : LogMessage(file, line, sev) {
205 if (!is_noop_)
206 print_stream_ << tag << ": ";
207}
jiayl66f0da22015-09-14 15:06:39 -0700208
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000209LogMessage::~LogMessage() {
Tommifef05002018-02-27 13:51:08 +0100210 if (is_noop_)
211 return;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000212
Tommifef05002018-02-27 13:51:08 +0100213 FinishPrintStream();
214
215 // TODO(tommi): Unfortunately |ostringstream::str()| always returns a copy
216 // of the constructed string. This means that we always end up creating
217 // two copies here (one owned by the stream, one by the return value of
218 // |str()|). It would be nice to switch to something else.
219 const std::string str = print_stream_.str();
220
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100221 if (severity_ >= g_dbg_sev) {
Tommie51a0a82018-02-27 15:30:29 +0100222#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700223 OutputToDebug(str, severity_, tag_);
Tommie51a0a82018-02-27 15:30:29 +0100224#else
225 OutputToDebug(str, severity_);
226#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000227 }
228
Peter Boström225789d2015-10-23 15:20:56 +0200229 CritScope cs(&g_log_crit);
230 for (auto& kv : streams_) {
231 if (severity_ >= kv.second) {
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200232#if defined(WEBRTC_ANDROID)
233 kv.first->OnLogMessage(str, severity_, tag_);
234#else
Peter Boström225789d2015-10-23 15:20:56 +0200235 kv.first->OnLogMessage(str);
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200236#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000237 }
238 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000239}
240
Karl Wibergcefc4652018-05-23 23:20:38 +0200241void LogMessage::AddTag(const char* tag) {
242#ifdef WEBRTC_ANDROID
243 if (!is_noop_) {
244 tag_ = tag;
245 }
246#endif
247}
248
Tommifef05002018-02-27 13:51:08 +0100249std::ostream& LogMessage::stream() {
250 return is_noop_ ? GetNoopStream() : print_stream_;
251}
252
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100253bool LogMessage::Loggable(LoggingSeverity sev) {
254 return sev >= g_min_sev;
255}
256
257int LogMessage::GetMinLogSeverity() {
258 return g_min_sev;
259}
260
261LoggingSeverity LogMessage::GetLogToDebug() {
262 return g_dbg_sev;
263}
Honghai Zhang82d78622016-05-06 11:29:15 -0700264int64_t LogMessage::LogStartTime() {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700265 static const int64_t g_start = SystemTimeMillis();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000266 return g_start;
267}
268
Peter Boström0c4e06b2015-10-07 12:23:21 +0200269uint32_t LogMessage::WallClockStartTime() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800270 static const uint32_t g_start_wallclock = time(nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000271 return g_start_wallclock;
272}
273
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000274void LogMessage::LogThreads(bool on) {
275 thread_ = on;
276}
277
278void LogMessage::LogTimestamps(bool on) {
279 timestamp_ = on;
280}
281
Tommi0eefb4d2015-05-23 09:54:07 +0200282void LogMessage::LogToDebug(LoggingSeverity min_sev) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100283 g_dbg_sev = min_sev;
Peter Boström225789d2015-10-23 15:20:56 +0200284 CritScope cs(&g_log_crit);
Tommi00aac5a2015-05-25 11:25:59 +0200285 UpdateMinLogSeverity();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000286}
287
andrew88703d72015-09-07 00:34:56 -0700288void LogMessage::SetLogToStderr(bool log_to_stderr) {
289 log_to_stderr_ = log_to_stderr;
290}
291
Tommi0eefb4d2015-05-23 09:54:07 +0200292int LogMessage::GetLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200293 CritScope cs(&g_log_crit);
Tommi0eefb4d2015-05-23 09:54:07 +0200294 LoggingSeverity sev = LS_NONE;
Peter Boström225789d2015-10-23 15:20:56 +0200295 for (auto& kv : streams_) {
296 if (!stream || stream == kv.first) {
297 sev = std::min(sev, kv.second);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000298 }
299 }
300 return sev;
301}
302
Tommi0eefb4d2015-05-23 09:54:07 +0200303void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
Peter Boström225789d2015-10-23 15:20:56 +0200304 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000305 streams_.push_back(std::make_pair(stream, min_sev));
306 UpdateMinLogSeverity();
307}
308
Tommi0eefb4d2015-05-23 09:54:07 +0200309void LogMessage::RemoveLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200310 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000311 for (StreamList::iterator it = streams_.begin(); it != streams_.end(); ++it) {
312 if (stream == it->first) {
313 streams_.erase(it);
314 break;
315 }
316 }
317 UpdateMinLogSeverity();
318}
319
Tommi0eefb4d2015-05-23 09:54:07 +0200320void LogMessage::ConfigureLogging(const char* params) {
321 LoggingSeverity current_level = LS_VERBOSE;
322 LoggingSeverity debug_level = GetLogToDebug();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000323
324 std::vector<std::string> tokens;
325 tokenize(params, ' ', &tokens);
326
Tommi0eefb4d2015-05-23 09:54:07 +0200327 for (const std::string& token : tokens) {
328 if (token.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000329 continue;
330
331 // Logging features
Tommi0eefb4d2015-05-23 09:54:07 +0200332 if (token == "tstamp") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000333 LogTimestamps();
Tommi0eefb4d2015-05-23 09:54:07 +0200334 } else if (token == "thread") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000335 LogThreads();
336
Yves Gerey665174f2018-06-19 15:03:05 +0200337 // Logging levels
Tommi0eefb4d2015-05-23 09:54:07 +0200338 } else if (token == "sensitive") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000339 current_level = LS_SENSITIVE;
Tommi0eefb4d2015-05-23 09:54:07 +0200340 } else if (token == "verbose") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000341 current_level = LS_VERBOSE;
Tommi0eefb4d2015-05-23 09:54:07 +0200342 } else if (token == "info") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000343 current_level = LS_INFO;
Tommi0eefb4d2015-05-23 09:54:07 +0200344 } else if (token == "warning") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000345 current_level = LS_WARNING;
Tommi0eefb4d2015-05-23 09:54:07 +0200346 } else if (token == "error") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000347 current_level = LS_ERROR;
Tommi0eefb4d2015-05-23 09:54:07 +0200348 } else if (token == "none") {
349 current_level = LS_NONE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000350
Yves Gerey665174f2018-06-19 15:03:05 +0200351 // Logging targets
Tommi0eefb4d2015-05-23 09:54:07 +0200352 } else if (token == "debug") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000353 debug_level = current_level;
354 }
355 }
356
357#if defined(WEBRTC_WIN)
Tommi0eefb4d2015-05-23 09:54:07 +0200358 if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000359 // First, attempt to attach to our parent's console... so if you invoke
360 // from the command line, we'll see the output there. Otherwise, create
361 // our own console window.
362 // Note: These methods fail if a console already exists, which is fine.
Tommie51a0a82018-02-27 15:30:29 +0100363 if (!AttachConsole(ATTACH_PARENT_PROCESS))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000364 ::AllocConsole();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000365 }
Tommi0eefb4d2015-05-23 09:54:07 +0200366#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000367
368 LogToDebug(debug_level);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000369}
370
danilchap3c6abd22017-09-06 05:46:29 -0700371void LogMessage::UpdateMinLogSeverity()
372 RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_crit) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100373 LoggingSeverity min_sev = g_dbg_sev;
Karl Wibergd294c852018-06-12 11:31:06 +0200374 for (const auto& kv : streams_) {
375 const LoggingSeverity sev = kv.second;
376 min_sev = std::min(min_sev, sev);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000377 }
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100378 g_min_sev = min_sev;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000379}
380
Tommie51a0a82018-02-27 15:30:29 +0100381#if defined(WEBRTC_ANDROID)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000382void LogMessage::OutputToDebug(const std::string& str,
jiayl66f0da22015-09-14 15:06:39 -0700383 LoggingSeverity severity,
Tommie51a0a82018-02-27 15:30:29 +0100384 const char* tag) {
385#else
386void LogMessage::OutputToDebug(const std::string& str,
387 LoggingSeverity severity) {
388#endif
andrew88703d72015-09-07 00:34:56 -0700389 bool log_to_stderr = log_to_stderr_;
tfarinaa41ab932015-10-30 16:08:48 -0700390#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000391 // On the Mac, all stderr output goes to the Console log and causes clutter.
392 // So in opt builds, don't log to stderr unless the user specifically sets
393 // a preference to do so.
Yves Gerey665174f2018-06-19 15:03:05 +0200394 CFStringRef key = CFStringCreateWithCString(
395 kCFAllocatorDefault, "logToStdErr", kCFStringEncodingUTF8);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000396 CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
deadbeef37f5ecf2017-02-27 14:06:41 -0800397 if (key != nullptr && domain != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000398 Boolean exists_and_is_valid;
399 Boolean should_log =
400 CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
401 // If the key doesn't exist or is invalid or is false, we will not log to
402 // stderr.
403 log_to_stderr = exists_and_is_valid && should_log;
404 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800405 if (key != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000406 CFRelease(key);
407 }
Tommie51a0a82018-02-27 15:30:29 +0100408#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
409
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000410#if defined(WEBRTC_WIN)
411 // Always log to the debugger.
412 // Perhaps stderr should be controlled by a preference, as on Mac?
413 OutputDebugStringA(str.c_str());
414 if (log_to_stderr) {
415 // This handles dynamically allocated consoles, too.
416 if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
417 log_to_stderr = false;
418 DWORD written = 0;
419 ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
420 &written, 0);
421 }
422 }
Tommi0eefb4d2015-05-23 09:54:07 +0200423#endif // WEBRTC_WIN
Tommie51a0a82018-02-27 15:30:29 +0100424
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000425#if defined(WEBRTC_ANDROID)
426 // Android's logging facility uses severity to log messages but we
427 // need to map libjingle's severity levels to Android ones first.
428 // Also write to stderr which maybe available to executable started
429 // from the shell.
430 int prio;
431 switch (severity) {
432 case LS_SENSITIVE:
Tommie51a0a82018-02-27 15:30:29 +0100433 __android_log_write(ANDROID_LOG_INFO, tag, "SENSITIVE");
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000434 if (log_to_stderr) {
435 fprintf(stderr, "SENSITIVE");
436 fflush(stderr);
437 }
438 return;
439 case LS_VERBOSE:
440 prio = ANDROID_LOG_VERBOSE;
441 break;
442 case LS_INFO:
443 prio = ANDROID_LOG_INFO;
444 break;
445 case LS_WARNING:
446 prio = ANDROID_LOG_WARN;
447 break;
448 case LS_ERROR:
449 prio = ANDROID_LOG_ERROR;
450 break;
451 default:
452 prio = ANDROID_LOG_UNKNOWN;
453 }
454
455 int size = str.size();
456 int line = 0;
457 int idx = 0;
458 const int max_lines = size / kMaxLogLineSize + 1;
459 if (max_lines == 1) {
Tommie51a0a82018-02-27 15:30:29 +0100460 __android_log_print(prio, tag, "%.*s", size, str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000461 } else {
462 while (size > 0) {
463 const int len = std::min(size, kMaxLogLineSize);
464 // Use the size of the string in the format (str may have \0 in the
465 // middle).
Tommie51a0a82018-02-27 15:30:29 +0100466 __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
467 str.c_str() + idx);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000468 idx += len;
469 size -= len;
470 ++line;
471 }
472 }
473#endif // WEBRTC_ANDROID
474 if (log_to_stderr) {
475 fprintf(stderr, "%s", str.c_str());
476 fflush(stderr);
477 }
478}
479
Tommifef05002018-02-27 13:51:08 +0100480// static
481bool LogMessage::IsNoop(LoggingSeverity severity) {
482 if (severity >= g_dbg_sev)
483 return false;
484
485 // TODO(tommi): We're grabbing this lock for every LogMessage instance that
486 // is going to be logged. This introduces unnecessary synchronization for
487 // a feature that's mostly used for testing.
488 CritScope cs(&g_log_crit);
489 return streams_.size() == 0;
490}
491
492void LogMessage::FinishPrintStream() {
493 if (is_noop_)
494 return;
495 if (!extra_.empty())
496 print_stream_ << " : " << extra_;
497 print_stream_ << std::endl;
498}
499
Karl Wibergcefc4652018-05-23 23:20:38 +0200500namespace webrtc_logging_impl {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000501
Karl Wibergcefc4652018-05-23 23:20:38 +0200502void Log(const LogArgType* fmt, ...) {
503 va_list args;
504 va_start(args, fmt);
505
506 LogMetadataErr meta;
507 const char* tag = nullptr;
508 switch (*fmt) {
509 case LogArgType::kLogMetadata: {
510 meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
511 break;
512 }
513 case LogArgType::kLogMetadataErr: {
514 meta = va_arg(args, LogMetadataErr);
515 break;
516 }
517#ifdef WEBRTC_ANDROID
518 case LogArgType::kLogMetadataTag: {
519 const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
520 meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
521 tag = tag_meta.tag;
522 break;
523 }
524#endif
525 default: {
526 RTC_NOTREACHED();
527 va_end(args);
528 return;
529 }
530 }
531 LogMessage log_message(meta.meta.File(), meta.meta.Line(),
532 meta.meta.Severity(), meta.err_ctx, meta.err);
533 if (tag) {
534 log_message.AddTag(tag);
535 }
536
537 for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
538 switch (*fmt) {
539 case LogArgType::kInt:
540 log_message.stream() << va_arg(args, int);
541 break;
542 case LogArgType::kLong:
543 log_message.stream() << va_arg(args, long);
544 break;
545 case LogArgType::kLongLong:
546 log_message.stream() << va_arg(args, long long);
547 break;
548 case LogArgType::kUInt:
549 log_message.stream() << va_arg(args, unsigned);
550 break;
551 case LogArgType::kULong:
552 log_message.stream() << va_arg(args, unsigned long);
553 break;
554 case LogArgType::kULongLong:
555 log_message.stream() << va_arg(args, unsigned long long);
556 break;
557 case LogArgType::kDouble:
558 log_message.stream() << va_arg(args, double);
559 break;
560 case LogArgType::kLongDouble:
561 log_message.stream() << va_arg(args, long double);
562 break;
563 case LogArgType::kCharP:
564 log_message.stream() << va_arg(args, const char*);
565 break;
566 case LogArgType::kStdString:
567 log_message.stream() << *va_arg(args, const std::string*);
568 break;
569 case LogArgType::kVoidP:
570 log_message.stream() << va_arg(args, const void*);
571 break;
572 default:
573 RTC_NOTREACHED();
574 va_end(args);
575 return;
576 }
577 }
578
579 va_end(args);
580}
581
582} // namespace webrtc_logging_impl
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000583} // namespace rtc