blob: 94ddcba6d22b5ac54eab219580121cb8025a05cb [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
Artem Titov6a4a1462019-11-26 16:24:46 +010011#include "rtc_base/logging.h"
12
13#include <string.h>
14
15#if RTC_LOG_ENABLED()
16
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000017#if defined(WEBRTC_WIN)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000018#include <windows.h>
conceptgenesis3f705622016-01-30 14:40:44 -080019#if _MSC_VER < 1900
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000020#define snprintf _snprintf
conceptgenesis3f705622016-01-30 14:40:44 -080021#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000022#undef ERROR // wingdi.h
23#endif
24
25#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
26#include <CoreServices/CoreServices.h>
27#elif defined(WEBRTC_ANDROID)
28#include <android/log.h>
Yves Gerey988cc082018-10-23 12:03:01 +020029
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000030// Android has a 1024 limit on log inputs. We use 60 chars as an
31// approx for the header/tag portion.
32// See android/system/core/liblog/logd_write.c
33static const int kMaxLogLineSize = 1024 - 60;
34#endif // WEBRTC_MAC && !defined(WEBRTC_IOS) || WEBRTC_ANDROID
35
Yves Gerey988cc082018-10-23 12:03:01 +020036#include <stdio.h>
Yves Gerey665174f2018-06-19 15:03:05 +020037#include <time.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020038
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000039#include <algorithm>
Karl Wibergcefc4652018-05-23 23:20:38 +020040#include <cstdarg>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000041#include <vector>
42
Danil Chapovalovef98ae62019-10-11 17:18:29 +020043#include "absl/base/attributes.h"
Yves Gerey988cc082018-10-23 12:03:01 +020044#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080045#include "rtc_base/critical_section.h"
Tommie51a0a82018-02-27 15:30:29 +010046#include "rtc_base/platform_thread_types.h"
Steve Anton10542f22019-01-11 09:11:00 -080047#include "rtc_base/string_encode.h"
48#include "rtc_base/string_utils.h"
Tommifef05002018-02-27 13:51:08 +010049#include "rtc_base/strings/string_builder.h"
Markus Handellde8a9352020-06-10 15:40:42 +020050#include "rtc_base/synchronization/mutex.h"
Yves Gerey988cc082018-10-23 12:03:01 +020051#include "rtc_base/thread_annotations.h"
Steve Anton10542f22019-01-11 09:11:00 -080052#include "rtc_base/time_utils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000053
54namespace rtc {
andrew88703d72015-09-07 00:34:56 -070055namespace {
Jonas Olsson2b6f1352018-02-15 11:57:03 +010056// By default, release builds don't log, debug builds at info level
57#if !defined(NDEBUG)
58static LoggingSeverity g_min_sev = LS_INFO;
59static LoggingSeverity g_dbg_sev = LS_INFO;
60#else
61static LoggingSeverity g_min_sev = LS_NONE;
62static LoggingSeverity g_dbg_sev = LS_NONE;
63#endif
andrew88703d72015-09-07 00:34:56 -070064
65// Return the filename portion of the string (that following the last slash).
66const char* FilenameFromPath(const char* file) {
67 const char* end1 = ::strrchr(file, '/');
68 const char* end2 = ::strrchr(file, '\\');
69 if (!end1 && !end2)
70 return file;
71 else
72 return (end1 > end2) ? end1 + 1 : end2 + 1;
73}
74
Jonas Olsson2b6f1352018-02-15 11:57:03 +010075// Global lock for log subsystem, only needed to serialize access to streams_.
Markus Handellde8a9352020-06-10 15:40:42 +020076// TODO(bugs.webrtc.org/11665): this is not currently constant initialized and
77// trivially destructible.
78webrtc::Mutex g_log_mutex_;
andrew88703d72015-09-07 00:34:56 -070079} // namespace
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000080
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000081/////////////////////////////////////////////////////////////////////////////
82// LogMessage
83/////////////////////////////////////////////////////////////////////////////
84
andrew88703d72015-09-07 00:34:56 -070085bool LogMessage::log_to_stderr_ = true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000086
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000087// The list of logging streams currently configured.
88// Note: we explicitly do not clean this up, because of the uncertain ordering
89// of destructors at program exit. Let the person who sets the stream trigger
deadbeef37f5ecf2017-02-27 14:06:41 -080090// cleanup by setting to null, or let it leak (safe at program exit).
Markus Handellde8a9352020-06-10 15:40:42 +020091ABSL_CONST_INIT LogSink* LogMessage::streams_ RTC_GUARDED_BY(g_log_mutex_) =
Danil Chapovalovb9f69022019-10-21 09:19:10 +020092 nullptr;
Markus Handellce1ff6f2020-07-08 08:52:48 +020093ABSL_CONST_INIT std::atomic<bool> LogMessage::streams_empty_ = {true};
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000094
95// Boolean options default to false (0)
96bool LogMessage::thread_, LogMessage::timestamp_;
97
Karl Wibergab4f1c12018-05-04 10:42:28 +020098LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
99 : LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
100
Peter Boström225789d2015-10-23 15:20:56 +0200101LogMessage::LogMessage(const char* file,
102 int line,
103 LoggingSeverity sev,
104 LogErrorContext err_ctx,
Tommie51a0a82018-02-27 15:30:29 +0100105 int err)
Jonas Olssond8c50782018-09-07 11:21:28 +0200106 : severity_(sev) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000107 if (timestamp_) {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700108 // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
109 // in log messages represents the real system time.
110 int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000111 // Also ensure WallClockStartTime is initialized, so that it matches
112 // LogStartTime.
113 WallClockStartTime();
Jonas Olssond8c50782018-09-07 11:21:28 +0200114 print_stream_ << "[" << rtc::LeftPad('0', 3, rtc::ToString(time / 1000))
115 << ":" << rtc::LeftPad('0', 3, rtc::ToString(time % 1000))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000116 << "] ";
117 }
118
119 if (thread_) {
henrikaba35d052015-07-14 17:04:08 +0200120 PlatformThreadId id = CurrentThreadId();
Jonas Olssond8c50782018-09-07 11:21:28 +0200121 print_stream_ << "[" << id << "] ";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000122 }
123
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200124 if (file != nullptr) {
125#if defined(WEBRTC_ANDROID)
126 tag_ = FilenameFromPath(file);
127 print_stream_ << "(line " << line << "): ";
128#else
Yves Gerey665174f2018-06-19 15:03:05 +0200129 print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200130#endif
131 }
andrew88703d72015-09-07 00:34:56 -0700132
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000133 if (err_ctx != ERRCTX_NONE) {
Karl Wiberg881f1682018-03-08 15:03:23 +0100134 char tmp_buf[1024];
135 SimpleStringBuilder tmp(tmp_buf);
Tommifef05002018-02-27 13:51:08 +0100136 tmp.AppendFormat("[0x%08X]", err);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000137 switch (err_ctx) {
138 case ERRCTX_ERRNO:
139 tmp << " " << strerror(err);
140 break;
kwiberg77eab702016-09-28 17:42:01 -0700141#ifdef WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000142 case ERRCTX_HRESULT: {
143 char msgbuf[256];
Yves Gerey665174f2018-06-19 15:03:05 +0200144 DWORD flags =
145 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000146 if (DWORD len = FormatMessageA(
Tommie51a0a82018-02-27 15:30:29 +0100147 flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
deadbeef37f5ecf2017-02-27 14:06:41 -0800148 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000149 while ((len > 0) &&
Yves Gerey665174f2018-06-19 15:03:05 +0200150 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000151 msgbuf[--len] = 0;
152 }
153 tmp << " " << msgbuf;
154 }
155 break;
156 }
Tommi0eefb4d2015-05-23 09:54:07 +0200157#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000158 default:
159 break;
160 }
161 extra_ = tmp.str();
162 }
163}
164
Tommie51a0a82018-02-27 15:30:29 +0100165#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700166LogMessage::LogMessage(const char* file,
167 int line,
168 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100169 const char* tag)
Yves Gerey665174f2018-06-19 15:03:05 +0200170 : LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200171 tag_ = tag;
172 print_stream_ << tag << ": ";
jiayl66f0da22015-09-14 15:06:39 -0700173}
Tommie51a0a82018-02-27 15:30:29 +0100174#endif
175
176// DEPRECATED. Currently only used by downstream projects that use
177// implementation details of logging.h. Work is ongoing to remove those
178// dependencies.
Yves Gerey665174f2018-06-19 15:03:05 +0200179LogMessage::LogMessage(const char* file,
180 int line,
181 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100182 const std::string& tag)
183 : LogMessage(file, line, sev) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200184 print_stream_ << tag << ": ";
Tommie51a0a82018-02-27 15:30:29 +0100185}
jiayl66f0da22015-09-14 15:06:39 -0700186
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000187LogMessage::~LogMessage() {
Tommifef05002018-02-27 13:51:08 +0100188 FinishPrintStream();
189
Jonas Olssond8c50782018-09-07 11:21:28 +0200190 const std::string str = print_stream_.Release();
Tommifef05002018-02-27 13:51:08 +0100191
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100192 if (severity_ >= g_dbg_sev) {
Tommie51a0a82018-02-27 15:30:29 +0100193#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700194 OutputToDebug(str, severity_, tag_);
Tommie51a0a82018-02-27 15:30:29 +0100195#else
196 OutputToDebug(str, severity_);
197#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000198 }
199
Markus Handellde8a9352020-06-10 15:40:42 +0200200 webrtc::MutexLock lock(&g_log_mutex_);
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200201 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
202 if (severity_ >= entry->min_severity_) {
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200203#if defined(WEBRTC_ANDROID)
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200204 entry->OnLogMessage(str, severity_, tag_);
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200205#else
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200206 entry->OnLogMessage(str, severity_);
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200207#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000208 }
209 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000210}
211
Karl Wibergcefc4652018-05-23 23:20:38 +0200212void LogMessage::AddTag(const char* tag) {
213#ifdef WEBRTC_ANDROID
Jonas Olssond8c50782018-09-07 11:21:28 +0200214 tag_ = tag;
Karl Wibergcefc4652018-05-23 23:20:38 +0200215#endif
216}
217
Jonas Olssond8c50782018-09-07 11:21:28 +0200218rtc::StringBuilder& LogMessage::stream() {
219 return print_stream_;
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100220}
221
222int LogMessage::GetMinLogSeverity() {
223 return g_min_sev;
224}
225
226LoggingSeverity LogMessage::GetLogToDebug() {
227 return g_dbg_sev;
228}
Honghai Zhang82d78622016-05-06 11:29:15 -0700229int64_t LogMessage::LogStartTime() {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700230 static const int64_t g_start = SystemTimeMillis();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000231 return g_start;
232}
233
Peter Boström0c4e06b2015-10-07 12:23:21 +0200234uint32_t LogMessage::WallClockStartTime() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800235 static const uint32_t g_start_wallclock = time(nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000236 return g_start_wallclock;
237}
238
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000239void LogMessage::LogThreads(bool on) {
240 thread_ = on;
241}
242
243void LogMessage::LogTimestamps(bool on) {
244 timestamp_ = on;
245}
246
Tommi0eefb4d2015-05-23 09:54:07 +0200247void LogMessage::LogToDebug(LoggingSeverity min_sev) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100248 g_dbg_sev = min_sev;
Markus Handellde8a9352020-06-10 15:40:42 +0200249 webrtc::MutexLock lock(&g_log_mutex_);
Tommi00aac5a2015-05-25 11:25:59 +0200250 UpdateMinLogSeverity();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000251}
252
andrew88703d72015-09-07 00:34:56 -0700253void LogMessage::SetLogToStderr(bool log_to_stderr) {
254 log_to_stderr_ = log_to_stderr;
255}
256
Tommi0eefb4d2015-05-23 09:54:07 +0200257int LogMessage::GetLogToStream(LogSink* stream) {
Markus Handellde8a9352020-06-10 15:40:42 +0200258 webrtc::MutexLock lock(&g_log_mutex_);
Tommi0eefb4d2015-05-23 09:54:07 +0200259 LoggingSeverity sev = LS_NONE;
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200260 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
261 if (stream == nullptr || stream == entry) {
262 sev = std::min(sev, entry->min_severity_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000263 }
264 }
265 return sev;
266}
267
Tommi0eefb4d2015-05-23 09:54:07 +0200268void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
Markus Handellde8a9352020-06-10 15:40:42 +0200269 webrtc::MutexLock lock(&g_log_mutex_);
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200270 stream->min_severity_ = min_sev;
271 stream->next_ = streams_;
272 streams_ = stream;
Markus Handellce1ff6f2020-07-08 08:52:48 +0200273 streams_empty_.store(false, std::memory_order_relaxed);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000274 UpdateMinLogSeverity();
275}
276
Tommi0eefb4d2015-05-23 09:54:07 +0200277void LogMessage::RemoveLogToStream(LogSink* stream) {
Markus Handellde8a9352020-06-10 15:40:42 +0200278 webrtc::MutexLock lock(&g_log_mutex_);
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200279 for (LogSink** entry = &streams_; *entry != nullptr;
280 entry = &(*entry)->next_) {
281 if (*entry == stream) {
282 *entry = (*entry)->next_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000283 break;
284 }
285 }
Markus Handellce1ff6f2020-07-08 08:52:48 +0200286 streams_empty_.store(streams_ == nullptr, std::memory_order_relaxed);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000287 UpdateMinLogSeverity();
288}
289
Tommi0eefb4d2015-05-23 09:54:07 +0200290void LogMessage::ConfigureLogging(const char* params) {
291 LoggingSeverity current_level = LS_VERBOSE;
292 LoggingSeverity debug_level = GetLogToDebug();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000293
294 std::vector<std::string> tokens;
295 tokenize(params, ' ', &tokens);
296
Tommi0eefb4d2015-05-23 09:54:07 +0200297 for (const std::string& token : tokens) {
298 if (token.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000299 continue;
300
301 // Logging features
Tommi0eefb4d2015-05-23 09:54:07 +0200302 if (token == "tstamp") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000303 LogTimestamps();
Tommi0eefb4d2015-05-23 09:54:07 +0200304 } else if (token == "thread") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000305 LogThreads();
306
Yves Gerey665174f2018-06-19 15:03:05 +0200307 // Logging levels
Tommi0eefb4d2015-05-23 09:54:07 +0200308 } else if (token == "verbose") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000309 current_level = LS_VERBOSE;
Tommi0eefb4d2015-05-23 09:54:07 +0200310 } else if (token == "info") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000311 current_level = LS_INFO;
Tommi0eefb4d2015-05-23 09:54:07 +0200312 } else if (token == "warning") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000313 current_level = LS_WARNING;
Tommi0eefb4d2015-05-23 09:54:07 +0200314 } else if (token == "error") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000315 current_level = LS_ERROR;
Tommi0eefb4d2015-05-23 09:54:07 +0200316 } else if (token == "none") {
317 current_level = LS_NONE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000318
Yves Gerey665174f2018-06-19 15:03:05 +0200319 // Logging targets
Tommi0eefb4d2015-05-23 09:54:07 +0200320 } else if (token == "debug") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000321 debug_level = current_level;
322 }
323 }
324
Robin Raymondce1b1402018-11-22 20:10:11 -0500325#if defined(WEBRTC_WIN) && !defined(WINUWP)
Tommi0eefb4d2015-05-23 09:54:07 +0200326 if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000327 // First, attempt to attach to our parent's console... so if you invoke
328 // from the command line, we'll see the output there. Otherwise, create
329 // our own console window.
330 // Note: These methods fail if a console already exists, which is fine.
Tommie51a0a82018-02-27 15:30:29 +0100331 if (!AttachConsole(ATTACH_PARENT_PROCESS))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000332 ::AllocConsole();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000333 }
Robin Raymondce1b1402018-11-22 20:10:11 -0500334#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000335
336 LogToDebug(debug_level);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000337}
338
danilchap3c6abd22017-09-06 05:46:29 -0700339void LogMessage::UpdateMinLogSeverity()
Markus Handellde8a9352020-06-10 15:40:42 +0200340 RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_mutex_) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100341 LoggingSeverity min_sev = g_dbg_sev;
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200342 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
343 min_sev = std::min(min_sev, entry->min_severity_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000344 }
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100345 g_min_sev = min_sev;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000346}
347
Tommie51a0a82018-02-27 15:30:29 +0100348#if defined(WEBRTC_ANDROID)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000349void LogMessage::OutputToDebug(const std::string& str,
jiayl66f0da22015-09-14 15:06:39 -0700350 LoggingSeverity severity,
Tommie51a0a82018-02-27 15:30:29 +0100351 const char* tag) {
352#else
353void LogMessage::OutputToDebug(const std::string& str,
354 LoggingSeverity severity) {
355#endif
andrew88703d72015-09-07 00:34:56 -0700356 bool log_to_stderr = log_to_stderr_;
tfarinaa41ab932015-10-30 16:08:48 -0700357#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000358 // On the Mac, all stderr output goes to the Console log and causes clutter.
359 // So in opt builds, don't log to stderr unless the user specifically sets
360 // a preference to do so.
Yves Gerey665174f2018-06-19 15:03:05 +0200361 CFStringRef key = CFStringCreateWithCString(
362 kCFAllocatorDefault, "logToStdErr", kCFStringEncodingUTF8);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000363 CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
deadbeef37f5ecf2017-02-27 14:06:41 -0800364 if (key != nullptr && domain != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000365 Boolean exists_and_is_valid;
366 Boolean should_log =
367 CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
368 // If the key doesn't exist or is invalid or is false, we will not log to
369 // stderr.
370 log_to_stderr = exists_and_is_valid && should_log;
371 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800372 if (key != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000373 CFRelease(key);
374 }
Tommie51a0a82018-02-27 15:30:29 +0100375#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
376
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000377#if defined(WEBRTC_WIN)
378 // Always log to the debugger.
379 // Perhaps stderr should be controlled by a preference, as on Mac?
380 OutputDebugStringA(str.c_str());
381 if (log_to_stderr) {
382 // This handles dynamically allocated consoles, too.
383 if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
384 log_to_stderr = false;
385 DWORD written = 0;
386 ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
387 &written, 0);
388 }
389 }
Tommi0eefb4d2015-05-23 09:54:07 +0200390#endif // WEBRTC_WIN
Tommie51a0a82018-02-27 15:30:29 +0100391
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000392#if defined(WEBRTC_ANDROID)
393 // Android's logging facility uses severity to log messages but we
394 // need to map libjingle's severity levels to Android ones first.
395 // Also write to stderr which maybe available to executable started
396 // from the shell.
397 int prio;
398 switch (severity) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000399 case LS_VERBOSE:
400 prio = ANDROID_LOG_VERBOSE;
401 break;
402 case LS_INFO:
403 prio = ANDROID_LOG_INFO;
404 break;
405 case LS_WARNING:
406 prio = ANDROID_LOG_WARN;
407 break;
408 case LS_ERROR:
409 prio = ANDROID_LOG_ERROR;
410 break;
411 default:
412 prio = ANDROID_LOG_UNKNOWN;
413 }
414
415 int size = str.size();
416 int line = 0;
417 int idx = 0;
418 const int max_lines = size / kMaxLogLineSize + 1;
419 if (max_lines == 1) {
Tommie51a0a82018-02-27 15:30:29 +0100420 __android_log_print(prio, tag, "%.*s", size, str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000421 } else {
422 while (size > 0) {
423 const int len = std::min(size, kMaxLogLineSize);
424 // Use the size of the string in the format (str may have \0 in the
425 // middle).
Tommie51a0a82018-02-27 15:30:29 +0100426 __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
427 str.c_str() + idx);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000428 idx += len;
429 size -= len;
430 ++line;
431 }
432 }
433#endif // WEBRTC_ANDROID
434 if (log_to_stderr) {
435 fprintf(stderr, "%s", str.c_str());
436 fflush(stderr);
437 }
438}
439
Tommifef05002018-02-27 13:51:08 +0100440// static
441bool LogMessage::IsNoop(LoggingSeverity severity) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200442 if (severity >= g_dbg_sev || severity >= g_min_sev)
Tommifef05002018-02-27 13:51:08 +0100443 return false;
Markus Handellce1ff6f2020-07-08 08:52:48 +0200444 return streams_empty_.load(std::memory_order_relaxed);
Tommifef05002018-02-27 13:51:08 +0100445}
446
447void LogMessage::FinishPrintStream() {
Tommifef05002018-02-27 13:51:08 +0100448 if (!extra_.empty())
449 print_stream_ << " : " << extra_;
Jonas Olssond8c50782018-09-07 11:21:28 +0200450 print_stream_ << "\n";
Tommifef05002018-02-27 13:51:08 +0100451}
452
Karl Wibergcefc4652018-05-23 23:20:38 +0200453namespace webrtc_logging_impl {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000454
Karl Wibergcefc4652018-05-23 23:20:38 +0200455void Log(const LogArgType* fmt, ...) {
456 va_list args;
457 va_start(args, fmt);
458
459 LogMetadataErr meta;
460 const char* tag = nullptr;
461 switch (*fmt) {
462 case LogArgType::kLogMetadata: {
463 meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
464 break;
465 }
466 case LogArgType::kLogMetadataErr: {
467 meta = va_arg(args, LogMetadataErr);
468 break;
469 }
470#ifdef WEBRTC_ANDROID
471 case LogArgType::kLogMetadataTag: {
472 const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
473 meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
474 tag = tag_meta.tag;
475 break;
476 }
477#endif
478 default: {
479 RTC_NOTREACHED();
480 va_end(args);
481 return;
482 }
483 }
Jonas Olssond8c50782018-09-07 11:21:28 +0200484
485 if (LogMessage::IsNoop(meta.meta.Severity())) {
486 va_end(args);
487 return;
488 }
489
Karl Wibergcefc4652018-05-23 23:20:38 +0200490 LogMessage log_message(meta.meta.File(), meta.meta.Line(),
491 meta.meta.Severity(), meta.err_ctx, meta.err);
492 if (tag) {
493 log_message.AddTag(tag);
494 }
495
496 for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
497 switch (*fmt) {
498 case LogArgType::kInt:
499 log_message.stream() << va_arg(args, int);
500 break;
501 case LogArgType::kLong:
502 log_message.stream() << va_arg(args, long);
503 break;
504 case LogArgType::kLongLong:
505 log_message.stream() << va_arg(args, long long);
506 break;
507 case LogArgType::kUInt:
508 log_message.stream() << va_arg(args, unsigned);
509 break;
510 case LogArgType::kULong:
511 log_message.stream() << va_arg(args, unsigned long);
512 break;
513 case LogArgType::kULongLong:
514 log_message.stream() << va_arg(args, unsigned long long);
515 break;
516 case LogArgType::kDouble:
517 log_message.stream() << va_arg(args, double);
518 break;
519 case LogArgType::kLongDouble:
520 log_message.stream() << va_arg(args, long double);
521 break;
Niels Möller65835be2019-02-04 19:23:58 +0100522 case LogArgType::kCharP: {
523 const char* s = va_arg(args, const char*);
524 log_message.stream() << (s ? s : "(null)");
Karl Wibergcefc4652018-05-23 23:20:38 +0200525 break;
Niels Möller65835be2019-02-04 19:23:58 +0100526 }
Karl Wibergcefc4652018-05-23 23:20:38 +0200527 case LogArgType::kStdString:
528 log_message.stream() << *va_arg(args, const std::string*);
529 break;
Jonas Olssonf2ce37c2018-09-12 15:32:47 +0200530 case LogArgType::kStringView:
531 log_message.stream() << *va_arg(args, const absl::string_view*);
532 break;
Karl Wibergcefc4652018-05-23 23:20:38 +0200533 case LogArgType::kVoidP:
Jonas Olssond8c50782018-09-07 11:21:28 +0200534 log_message.stream() << rtc::ToHex(
535 reinterpret_cast<uintptr_t>(va_arg(args, const void*)));
Karl Wibergcefc4652018-05-23 23:20:38 +0200536 break;
537 default:
538 RTC_NOTREACHED();
539 va_end(args);
540 return;
541 }
542 }
543
544 va_end(args);
545}
546
547} // namespace webrtc_logging_impl
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000548} // namespace rtc
Artem Titov6a4a1462019-11-26 16:24:46 +0100549#endif
550
551namespace rtc {
552// Inefficient default implementation, override is recommended.
553void LogSink::OnLogMessage(const std::string& msg,
554 LoggingSeverity severity,
555 const char* tag) {
556 OnLogMessage(tag + (": " + msg), severity);
557}
558
559void LogSink::OnLogMessage(const std::string& msg,
560 LoggingSeverity /* severity */) {
561 OnLogMessage(msg);
562}
563} // namespace rtc