blob: c386600abbae200f200348f0047195fb5794bc99 [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)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000012#include <windows.h>
conceptgenesis3f705622016-01-30 14:40:44 -080013#if _MSC_VER < 1900
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000014#define snprintf _snprintf
conceptgenesis3f705622016-01-30 14:40:44 -080015#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000016#undef ERROR // wingdi.h
17#endif
18
19#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
20#include <CoreServices/CoreServices.h>
21#elif defined(WEBRTC_ANDROID)
22#include <android/log.h>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000023// Android has a 1024 limit on log inputs. We use 60 chars as an
24// approx for the header/tag portion.
25// See android/system/core/liblog/logd_write.c
26static const int kMaxLogLineSize = 1024 - 60;
27#endif // WEBRTC_MAC && !defined(WEBRTC_IOS) || WEBRTC_ANDROID
28
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000029#include <limits.h>
Yves Gerey665174f2018-06-19 15:03:05 +020030#include <time.h>
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000031
32#include <algorithm>
Karl Wibergcefc4652018-05-23 23:20:38 +020033#include <cstdarg>
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000034#include <iomanip>
35#include <ostream>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000036#include <vector>
37
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020038#include "rtc_base/criticalsection.h"
39#include "rtc_base/logging.h"
Tommie51a0a82018-02-27 15:30:29 +010040#include "rtc_base/platform_thread_types.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020041#include "rtc_base/stringencode.h"
Tommifef05002018-02-27 13:51:08 +010042#include "rtc_base/strings/string_builder.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020043#include "rtc_base/stringutils.h"
44#include "rtc_base/timeutils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000045
46namespace rtc {
andrew88703d72015-09-07 00:34:56 -070047namespace {
Jonas Olsson2b6f1352018-02-15 11:57:03 +010048// By default, release builds don't log, debug builds at info level
49#if !defined(NDEBUG)
50static LoggingSeverity g_min_sev = LS_INFO;
51static LoggingSeverity g_dbg_sev = LS_INFO;
52#else
53static LoggingSeverity g_min_sev = LS_NONE;
54static LoggingSeverity g_dbg_sev = LS_NONE;
55#endif
andrew88703d72015-09-07 00:34:56 -070056
57// Return the filename portion of the string (that following the last slash).
58const char* FilenameFromPath(const char* file) {
59 const char* end1 = ::strrchr(file, '/');
60 const char* end2 = ::strrchr(file, '\\');
61 if (!end1 && !end2)
62 return file;
63 else
64 return (end1 > end2) ? end1 + 1 : end2 + 1;
65}
66
Tommifef05002018-02-27 13:51:08 +010067std::ostream& GetNoopStream() {
68 class NoopStreamBuf : public std::streambuf {
69 public:
70 int overflow(int c) override { return c; }
71 };
72 static NoopStreamBuf noop_buffer;
73 static std::ostream noop_stream(&noop_buffer);
74 return noop_stream;
75}
76
Jonas Olsson2b6f1352018-02-15 11:57:03 +010077// Global lock for log subsystem, only needed to serialize access to streams_.
78CriticalSection g_log_crit;
andrew88703d72015-09-07 00:34:56 -070079} // namespace
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000080
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +020081// Inefficient default implementation, override is recommended.
82void LogSink::OnLogMessage(const std::string& msg,
83 LoggingSeverity severity,
84 const char* tag) {
85 OnLogMessage(tag + (": " + msg));
86}
87
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000088/////////////////////////////////////////////////////////////////////////////
89// LogMessage
90/////////////////////////////////////////////////////////////////////////////
91
andrew88703d72015-09-07 00:34:56 -070092bool LogMessage::log_to_stderr_ = true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000093
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000094// The list of logging streams currently configured.
95// Note: we explicitly do not clean this up, because of the uncertain ordering
96// of destructors at program exit. Let the person who sets the stream trigger
deadbeef37f5ecf2017-02-27 14:06:41 -080097// cleanup by setting to null, or let it leak (safe at program exit).
danilchap3c6abd22017-09-06 05:46:29 -070098LogMessage::StreamList LogMessage::streams_ RTC_GUARDED_BY(g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000099
100// Boolean options default to false (0)
101bool LogMessage::thread_, LogMessage::timestamp_;
102
Karl Wibergab4f1c12018-05-04 10:42:28 +0200103LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
104 : LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
105
Peter Boström225789d2015-10-23 15:20:56 +0200106LogMessage::LogMessage(const char* file,
107 int line,
108 LoggingSeverity sev,
109 LogErrorContext err_ctx,
Tommie51a0a82018-02-27 15:30:29 +0100110 int err)
111 : severity_(sev), is_noop_(IsNoop(sev)) {
Tommifef05002018-02-27 13:51:08 +0100112 // If there's no need to do any work, let's not :)
113 if (is_noop_)
114 return;
115
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000116 if (timestamp_) {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700117 // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
118 // in log messages represents the real system time.
119 int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000120 // Also ensure WallClockStartTime is initialized, so that it matches
121 // LogStartTime.
122 WallClockStartTime();
123 print_stream_ << "[" << std::setfill('0') << std::setw(3) << (time / 1000)
124 << ":" << std::setw(3) << (time % 1000) << std::setfill(' ')
125 << "] ";
126 }
127
128 if (thread_) {
henrikaba35d052015-07-14 17:04:08 +0200129 PlatformThreadId id = CurrentThreadId();
130 print_stream_ << "[" << std::dec << id << "] ";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000131 }
132
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200133 if (file != nullptr) {
134#if defined(WEBRTC_ANDROID)
135 tag_ = FilenameFromPath(file);
136 print_stream_ << "(line " << line << "): ";
137#else
Yves Gerey665174f2018-06-19 15:03:05 +0200138 print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200139#endif
140 }
andrew88703d72015-09-07 00:34:56 -0700141
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000142 if (err_ctx != ERRCTX_NONE) {
Karl Wiberg881f1682018-03-08 15:03:23 +0100143 char tmp_buf[1024];
144 SimpleStringBuilder tmp(tmp_buf);
Tommifef05002018-02-27 13:51:08 +0100145 tmp.AppendFormat("[0x%08X]", err);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000146 switch (err_ctx) {
147 case ERRCTX_ERRNO:
148 tmp << " " << strerror(err);
149 break;
kwiberg77eab702016-09-28 17:42:01 -0700150#ifdef WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000151 case ERRCTX_HRESULT: {
152 char msgbuf[256];
Yves Gerey665174f2018-06-19 15:03:05 +0200153 DWORD flags =
154 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000155 if (DWORD len = FormatMessageA(
Tommie51a0a82018-02-27 15:30:29 +0100156 flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
deadbeef37f5ecf2017-02-27 14:06:41 -0800157 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000158 while ((len > 0) &&
Yves Gerey665174f2018-06-19 15:03:05 +0200159 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000160 msgbuf[--len] = 0;
161 }
162 tmp << " " << msgbuf;
163 }
164 break;
165 }
Tommi0eefb4d2015-05-23 09:54:07 +0200166#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000167#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
168 case ERRCTX_OSSTATUS: {
Tommi09ca02e2016-04-24 17:32:48 +0200169 std::string desc(DescriptionFromOSStatus(err));
170 tmp << " " << (desc.empty() ? "Unknown error" : desc.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000171 break;
172 }
173#endif // WEBRTC_MAC && !defined(WEBRTC_IOS)
174 default:
175 break;
176 }
177 extra_ = tmp.str();
178 }
179}
180
Tommie51a0a82018-02-27 15:30:29 +0100181#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700182LogMessage::LogMessage(const char* file,
183 int line,
184 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100185 const char* tag)
Yves Gerey665174f2018-06-19 15:03:05 +0200186 : LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */) {
Tommifef05002018-02-27 13:51:08 +0100187 if (!is_noop_) {
188 tag_ = tag;
Alex Glaznev5abd78b2018-06-01 19:12:58 +0000189 print_stream_ << tag << ": ";
Tommifef05002018-02-27 13:51:08 +0100190 }
jiayl66f0da22015-09-14 15:06:39 -0700191}
Tommie51a0a82018-02-27 15:30:29 +0100192#endif
193
194// DEPRECATED. Currently only used by downstream projects that use
195// implementation details of logging.h. Work is ongoing to remove those
196// dependencies.
Yves Gerey665174f2018-06-19 15:03:05 +0200197LogMessage::LogMessage(const char* file,
198 int line,
199 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100200 const std::string& tag)
201 : LogMessage(file, line, sev) {
202 if (!is_noop_)
203 print_stream_ << tag << ": ";
204}
jiayl66f0da22015-09-14 15:06:39 -0700205
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000206LogMessage::~LogMessage() {
Tommifef05002018-02-27 13:51:08 +0100207 if (is_noop_)
208 return;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000209
Tommifef05002018-02-27 13:51:08 +0100210 FinishPrintStream();
211
212 // TODO(tommi): Unfortunately |ostringstream::str()| always returns a copy
213 // of the constructed string. This means that we always end up creating
214 // two copies here (one owned by the stream, one by the return value of
215 // |str()|). It would be nice to switch to something else.
216 const std::string str = print_stream_.str();
217
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100218 if (severity_ >= g_dbg_sev) {
Tommie51a0a82018-02-27 15:30:29 +0100219#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700220 OutputToDebug(str, severity_, tag_);
Tommie51a0a82018-02-27 15:30:29 +0100221#else
222 OutputToDebug(str, severity_);
223#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000224 }
225
Peter Boström225789d2015-10-23 15:20:56 +0200226 CritScope cs(&g_log_crit);
227 for (auto& kv : streams_) {
228 if (severity_ >= kv.second) {
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200229#if defined(WEBRTC_ANDROID)
230 kv.first->OnLogMessage(str, severity_, tag_);
231#else
Peter Boström225789d2015-10-23 15:20:56 +0200232 kv.first->OnLogMessage(str);
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200233#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000234 }
235 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000236}
237
Karl Wibergcefc4652018-05-23 23:20:38 +0200238void LogMessage::AddTag(const char* tag) {
239#ifdef WEBRTC_ANDROID
240 if (!is_noop_) {
241 tag_ = tag;
242 }
243#endif
244}
245
Tommifef05002018-02-27 13:51:08 +0100246std::ostream& LogMessage::stream() {
247 return is_noop_ ? GetNoopStream() : print_stream_;
248}
249
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100250bool LogMessage::Loggable(LoggingSeverity sev) {
251 return sev >= g_min_sev;
252}
253
254int LogMessage::GetMinLogSeverity() {
255 return g_min_sev;
256}
257
258LoggingSeverity LogMessage::GetLogToDebug() {
259 return g_dbg_sev;
260}
Honghai Zhang82d78622016-05-06 11:29:15 -0700261int64_t LogMessage::LogStartTime() {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700262 static const int64_t g_start = SystemTimeMillis();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000263 return g_start;
264}
265
Peter Boström0c4e06b2015-10-07 12:23:21 +0200266uint32_t LogMessage::WallClockStartTime() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800267 static const uint32_t g_start_wallclock = time(nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000268 return g_start_wallclock;
269}
270
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000271void LogMessage::LogThreads(bool on) {
272 thread_ = on;
273}
274
275void LogMessage::LogTimestamps(bool on) {
276 timestamp_ = on;
277}
278
Tommi0eefb4d2015-05-23 09:54:07 +0200279void LogMessage::LogToDebug(LoggingSeverity min_sev) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100280 g_dbg_sev = min_sev;
Peter Boström225789d2015-10-23 15:20:56 +0200281 CritScope cs(&g_log_crit);
Tommi00aac5a2015-05-25 11:25:59 +0200282 UpdateMinLogSeverity();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000283}
284
andrew88703d72015-09-07 00:34:56 -0700285void LogMessage::SetLogToStderr(bool log_to_stderr) {
286 log_to_stderr_ = log_to_stderr;
287}
288
Tommi0eefb4d2015-05-23 09:54:07 +0200289int LogMessage::GetLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200290 CritScope cs(&g_log_crit);
Tommi0eefb4d2015-05-23 09:54:07 +0200291 LoggingSeverity sev = LS_NONE;
Peter Boström225789d2015-10-23 15:20:56 +0200292 for (auto& kv : streams_) {
293 if (!stream || stream == kv.first) {
294 sev = std::min(sev, kv.second);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000295 }
296 }
297 return sev;
298}
299
Tommi0eefb4d2015-05-23 09:54:07 +0200300void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
Peter Boström225789d2015-10-23 15:20:56 +0200301 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000302 streams_.push_back(std::make_pair(stream, min_sev));
303 UpdateMinLogSeverity();
304}
305
Tommi0eefb4d2015-05-23 09:54:07 +0200306void LogMessage::RemoveLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200307 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000308 for (StreamList::iterator it = streams_.begin(); it != streams_.end(); ++it) {
309 if (stream == it->first) {
310 streams_.erase(it);
311 break;
312 }
313 }
314 UpdateMinLogSeverity();
315}
316
Tommi0eefb4d2015-05-23 09:54:07 +0200317void LogMessage::ConfigureLogging(const char* params) {
318 LoggingSeverity current_level = LS_VERBOSE;
319 LoggingSeverity debug_level = GetLogToDebug();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000320
321 std::vector<std::string> tokens;
322 tokenize(params, ' ', &tokens);
323
Tommi0eefb4d2015-05-23 09:54:07 +0200324 for (const std::string& token : tokens) {
325 if (token.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000326 continue;
327
328 // Logging features
Tommi0eefb4d2015-05-23 09:54:07 +0200329 if (token == "tstamp") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000330 LogTimestamps();
Tommi0eefb4d2015-05-23 09:54:07 +0200331 } else if (token == "thread") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000332 LogThreads();
333
Yves Gerey665174f2018-06-19 15:03:05 +0200334 // Logging levels
Tommi0eefb4d2015-05-23 09:54:07 +0200335 } else if (token == "sensitive") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000336 current_level = LS_SENSITIVE;
Tommi0eefb4d2015-05-23 09:54:07 +0200337 } else if (token == "verbose") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000338 current_level = LS_VERBOSE;
Tommi0eefb4d2015-05-23 09:54:07 +0200339 } else if (token == "info") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000340 current_level = LS_INFO;
Tommi0eefb4d2015-05-23 09:54:07 +0200341 } else if (token == "warning") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000342 current_level = LS_WARNING;
Tommi0eefb4d2015-05-23 09:54:07 +0200343 } else if (token == "error") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000344 current_level = LS_ERROR;
Tommi0eefb4d2015-05-23 09:54:07 +0200345 } else if (token == "none") {
346 current_level = LS_NONE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000347
Yves Gerey665174f2018-06-19 15:03:05 +0200348 // Logging targets
Tommi0eefb4d2015-05-23 09:54:07 +0200349 } else if (token == "debug") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000350 debug_level = current_level;
351 }
352 }
353
354#if defined(WEBRTC_WIN)
Tommi0eefb4d2015-05-23 09:54:07 +0200355 if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000356 // First, attempt to attach to our parent's console... so if you invoke
357 // from the command line, we'll see the output there. Otherwise, create
358 // our own console window.
359 // Note: These methods fail if a console already exists, which is fine.
Tommie51a0a82018-02-27 15:30:29 +0100360 if (!AttachConsole(ATTACH_PARENT_PROCESS))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000361 ::AllocConsole();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000362 }
Tommi0eefb4d2015-05-23 09:54:07 +0200363#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000364
365 LogToDebug(debug_level);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000366}
367
danilchap3c6abd22017-09-06 05:46:29 -0700368void LogMessage::UpdateMinLogSeverity()
369 RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_crit) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100370 LoggingSeverity min_sev = g_dbg_sev;
Karl Wibergd294c852018-06-12 11:31:06 +0200371 for (const auto& kv : streams_) {
372 const LoggingSeverity sev = kv.second;
373 min_sev = std::min(min_sev, sev);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000374 }
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100375 g_min_sev = min_sev;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000376}
377
Tommie51a0a82018-02-27 15:30:29 +0100378#if defined(WEBRTC_ANDROID)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000379void LogMessage::OutputToDebug(const std::string& str,
jiayl66f0da22015-09-14 15:06:39 -0700380 LoggingSeverity severity,
Tommie51a0a82018-02-27 15:30:29 +0100381 const char* tag) {
382#else
383void LogMessage::OutputToDebug(const std::string& str,
384 LoggingSeverity severity) {
385#endif
andrew88703d72015-09-07 00:34:56 -0700386 bool log_to_stderr = log_to_stderr_;
tfarinaa41ab932015-10-30 16:08:48 -0700387#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000388 // On the Mac, all stderr output goes to the Console log and causes clutter.
389 // So in opt builds, don't log to stderr unless the user specifically sets
390 // a preference to do so.
Yves Gerey665174f2018-06-19 15:03:05 +0200391 CFStringRef key = CFStringCreateWithCString(
392 kCFAllocatorDefault, "logToStdErr", kCFStringEncodingUTF8);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000393 CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
deadbeef37f5ecf2017-02-27 14:06:41 -0800394 if (key != nullptr && domain != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000395 Boolean exists_and_is_valid;
396 Boolean should_log =
397 CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
398 // If the key doesn't exist or is invalid or is false, we will not log to
399 // stderr.
400 log_to_stderr = exists_and_is_valid && should_log;
401 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800402 if (key != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000403 CFRelease(key);
404 }
Tommie51a0a82018-02-27 15:30:29 +0100405#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
406
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000407#if defined(WEBRTC_WIN)
408 // Always log to the debugger.
409 // Perhaps stderr should be controlled by a preference, as on Mac?
410 OutputDebugStringA(str.c_str());
411 if (log_to_stderr) {
412 // This handles dynamically allocated consoles, too.
413 if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
414 log_to_stderr = false;
415 DWORD written = 0;
416 ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
417 &written, 0);
418 }
419 }
Tommi0eefb4d2015-05-23 09:54:07 +0200420#endif // WEBRTC_WIN
Tommie51a0a82018-02-27 15:30:29 +0100421
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000422#if defined(WEBRTC_ANDROID)
423 // Android's logging facility uses severity to log messages but we
424 // need to map libjingle's severity levels to Android ones first.
425 // Also write to stderr which maybe available to executable started
426 // from the shell.
427 int prio;
428 switch (severity) {
429 case LS_SENSITIVE:
Tommie51a0a82018-02-27 15:30:29 +0100430 __android_log_write(ANDROID_LOG_INFO, tag, "SENSITIVE");
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000431 if (log_to_stderr) {
432 fprintf(stderr, "SENSITIVE");
433 fflush(stderr);
434 }
435 return;
436 case LS_VERBOSE:
437 prio = ANDROID_LOG_VERBOSE;
438 break;
439 case LS_INFO:
440 prio = ANDROID_LOG_INFO;
441 break;
442 case LS_WARNING:
443 prio = ANDROID_LOG_WARN;
444 break;
445 case LS_ERROR:
446 prio = ANDROID_LOG_ERROR;
447 break;
448 default:
449 prio = ANDROID_LOG_UNKNOWN;
450 }
451
452 int size = str.size();
453 int line = 0;
454 int idx = 0;
455 const int max_lines = size / kMaxLogLineSize + 1;
456 if (max_lines == 1) {
Tommie51a0a82018-02-27 15:30:29 +0100457 __android_log_print(prio, tag, "%.*s", size, str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000458 } else {
459 while (size > 0) {
460 const int len = std::min(size, kMaxLogLineSize);
461 // Use the size of the string in the format (str may have \0 in the
462 // middle).
Tommie51a0a82018-02-27 15:30:29 +0100463 __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
464 str.c_str() + idx);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000465 idx += len;
466 size -= len;
467 ++line;
468 }
469 }
470#endif // WEBRTC_ANDROID
471 if (log_to_stderr) {
472 fprintf(stderr, "%s", str.c_str());
473 fflush(stderr);
474 }
475}
476
Tommifef05002018-02-27 13:51:08 +0100477// static
478bool LogMessage::IsNoop(LoggingSeverity severity) {
479 if (severity >= g_dbg_sev)
480 return false;
481
482 // TODO(tommi): We're grabbing this lock for every LogMessage instance that
483 // is going to be logged. This introduces unnecessary synchronization for
484 // a feature that's mostly used for testing.
485 CritScope cs(&g_log_crit);
486 return streams_.size() == 0;
487}
488
489void LogMessage::FinishPrintStream() {
490 if (is_noop_)
491 return;
492 if (!extra_.empty())
493 print_stream_ << " : " << extra_;
494 print_stream_ << std::endl;
495}
496
Karl Wibergcefc4652018-05-23 23:20:38 +0200497namespace webrtc_logging_impl {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000498
Karl Wibergcefc4652018-05-23 23:20:38 +0200499void Log(const LogArgType* fmt, ...) {
500 va_list args;
501 va_start(args, fmt);
502
503 LogMetadataErr meta;
504 const char* tag = nullptr;
505 switch (*fmt) {
506 case LogArgType::kLogMetadata: {
507 meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
508 break;
509 }
510 case LogArgType::kLogMetadataErr: {
511 meta = va_arg(args, LogMetadataErr);
512 break;
513 }
514#ifdef WEBRTC_ANDROID
515 case LogArgType::kLogMetadataTag: {
516 const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
517 meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
518 tag = tag_meta.tag;
519 break;
520 }
521#endif
522 default: {
523 RTC_NOTREACHED();
524 va_end(args);
525 return;
526 }
527 }
528 LogMessage log_message(meta.meta.File(), meta.meta.Line(),
529 meta.meta.Severity(), meta.err_ctx, meta.err);
530 if (tag) {
531 log_message.AddTag(tag);
532 }
533
534 for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
535 switch (*fmt) {
536 case LogArgType::kInt:
537 log_message.stream() << va_arg(args, int);
538 break;
539 case LogArgType::kLong:
540 log_message.stream() << va_arg(args, long);
541 break;
542 case LogArgType::kLongLong:
543 log_message.stream() << va_arg(args, long long);
544 break;
545 case LogArgType::kUInt:
546 log_message.stream() << va_arg(args, unsigned);
547 break;
548 case LogArgType::kULong:
549 log_message.stream() << va_arg(args, unsigned long);
550 break;
551 case LogArgType::kULongLong:
552 log_message.stream() << va_arg(args, unsigned long long);
553 break;
554 case LogArgType::kDouble:
555 log_message.stream() << va_arg(args, double);
556 break;
557 case LogArgType::kLongDouble:
558 log_message.stream() << va_arg(args, long double);
559 break;
560 case LogArgType::kCharP:
561 log_message.stream() << va_arg(args, const char*);
562 break;
563 case LogArgType::kStdString:
564 log_message.stream() << *va_arg(args, const std::string*);
565 break;
566 case LogArgType::kVoidP:
567 log_message.stream() << va_arg(args, const void*);
568 break;
569 default:
570 RTC_NOTREACHED();
571 va_end(args);
572 return;
573 }
574 }
575
576 va_end(args);
577}
578
579} // namespace webrtc_logging_impl
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000580} // namespace rtc