blob: a333d839708a4a4d13fec39289f9f2da66cf61d7 [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
Niels Möller646109f2020-09-17 12:40:02 +020036#include <inttypes.h>
Yves Gerey988cc082018-10-23 12:03:01 +020037#include <stdio.h>
Yves Gerey665174f2018-06-19 15:03:05 +020038#include <time.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020039
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000040#include <algorithm>
Karl Wibergcefc4652018-05-23 23:20:38 +020041#include <cstdarg>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000042#include <vector>
43
Danil Chapovalovef98ae62019-10-11 17:18:29 +020044#include "absl/base/attributes.h"
Yves Gerey988cc082018-10-23 12:03:01 +020045#include "rtc_base/checks.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
Markus Handell0d3c09a2021-04-19 09:12:15 +020054#if defined(WEBRTC_RACE_CHECK_MUTEX)
55#if defined(WEBRTC_ABSL_MUTEX)
56#error Please only define one of WEBRTC_RACE_CHECK_MUTEX and WEBRTC_ABSL_MUTEX.
57#endif
58#include "absl/base/const_init.h"
59#include "absl/synchronization/mutex.h" // nogncheck
60using LoggingMutexLock = ::absl::MutexLock;
61#else
62using LoggingMutexLock = ::webrtc::MutexLock;
63#endif // if defined(WEBRTC_RACE_CHECK_MUTEX)
64
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000065namespace rtc {
andrew88703d72015-09-07 00:34:56 -070066namespace {
Jonas Olsson2b6f1352018-02-15 11:57:03 +010067// By default, release builds don't log, debug builds at info level
68#if !defined(NDEBUG)
69static LoggingSeverity g_min_sev = LS_INFO;
70static LoggingSeverity g_dbg_sev = LS_INFO;
71#else
72static LoggingSeverity g_min_sev = LS_NONE;
73static LoggingSeverity g_dbg_sev = LS_NONE;
74#endif
andrew88703d72015-09-07 00:34:56 -070075
76// Return the filename portion of the string (that following the last slash).
77const char* FilenameFromPath(const char* file) {
78 const char* end1 = ::strrchr(file, '/');
79 const char* end2 = ::strrchr(file, '\\');
80 if (!end1 && !end2)
81 return file;
82 else
83 return (end1 > end2) ? end1 + 1 : end2 + 1;
84}
85
Jonas Olsson2b6f1352018-02-15 11:57:03 +010086// Global lock for log subsystem, only needed to serialize access to streams_.
Markus Handellde8a9352020-06-10 15:40:42 +020087// TODO(bugs.webrtc.org/11665): this is not currently constant initialized and
88// trivially destructible.
Markus Handell0d3c09a2021-04-19 09:12:15 +020089#if defined(WEBRTC_RACE_CHECK_MUTEX)
90// When WEBRTC_RACE_CHECK_MUTEX is defined, even though WebRTC objects are
91// invoked serially, the logging is static, invoked concurrently and hence needs
92// protection.
93absl::Mutex g_log_mutex_(absl::kConstInit);
94#else
Markus Handellde8a9352020-06-10 15:40:42 +020095webrtc::Mutex g_log_mutex_;
Markus Handell0d3c09a2021-04-19 09:12:15 +020096#endif
97
andrew88703d72015-09-07 00:34:56 -070098} // namespace
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000099
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000100/////////////////////////////////////////////////////////////////////////////
101// LogMessage
102/////////////////////////////////////////////////////////////////////////////
103
andrew88703d72015-09-07 00:34:56 -0700104bool LogMessage::log_to_stderr_ = true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000105
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000106// The list of logging streams currently configured.
107// Note: we explicitly do not clean this up, because of the uncertain ordering
108// of destructors at program exit. Let the person who sets the stream trigger
deadbeef37f5ecf2017-02-27 14:06:41 -0800109// cleanup by setting to null, or let it leak (safe at program exit).
Markus Handellde8a9352020-06-10 15:40:42 +0200110ABSL_CONST_INIT LogSink* LogMessage::streams_ RTC_GUARDED_BY(g_log_mutex_) =
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200111 nullptr;
Markus Handellce1ff6f2020-07-08 08:52:48 +0200112ABSL_CONST_INIT std::atomic<bool> LogMessage::streams_empty_ = {true};
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000113
114// Boolean options default to false (0)
115bool LogMessage::thread_, LogMessage::timestamp_;
116
Karl Wibergab4f1c12018-05-04 10:42:28 +0200117LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
118 : LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
119
Peter Boström225789d2015-10-23 15:20:56 +0200120LogMessage::LogMessage(const char* file,
121 int line,
122 LoggingSeverity sev,
123 LogErrorContext err_ctx,
Tommie51a0a82018-02-27 15:30:29 +0100124 int err)
Jonas Olssond8c50782018-09-07 11:21:28 +0200125 : severity_(sev) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000126 if (timestamp_) {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700127 // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
128 // in log messages represents the real system time.
129 int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000130 // Also ensure WallClockStartTime is initialized, so that it matches
131 // LogStartTime.
132 WallClockStartTime();
Niels Möller646109f2020-09-17 12:40:02 +0200133 // TODO(kwiberg): Switch to absl::StrFormat, if binary size is ok.
134 char timestamp[50]; // Maximum string length of an int64_t is 20.
135 int len =
136 snprintf(timestamp, sizeof(timestamp), "[%03" PRId64 ":%03" PRId64 "]",
137 time / 1000, time % 1000);
138 RTC_DCHECK_LT(len, sizeof(timestamp));
139 print_stream_ << timestamp;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000140 }
141
142 if (thread_) {
henrikaba35d052015-07-14 17:04:08 +0200143 PlatformThreadId id = CurrentThreadId();
Jonas Olssond8c50782018-09-07 11:21:28 +0200144 print_stream_ << "[" << id << "] ";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000145 }
146
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200147 if (file != nullptr) {
148#if defined(WEBRTC_ANDROID)
149 tag_ = FilenameFromPath(file);
150 print_stream_ << "(line " << line << "): ";
151#else
Yves Gerey665174f2018-06-19 15:03:05 +0200152 print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200153#endif
154 }
andrew88703d72015-09-07 00:34:56 -0700155
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000156 if (err_ctx != ERRCTX_NONE) {
Karl Wiberg881f1682018-03-08 15:03:23 +0100157 char tmp_buf[1024];
158 SimpleStringBuilder tmp(tmp_buf);
Tommifef05002018-02-27 13:51:08 +0100159 tmp.AppendFormat("[0x%08X]", err);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000160 switch (err_ctx) {
161 case ERRCTX_ERRNO:
162 tmp << " " << strerror(err);
163 break;
kwiberg77eab702016-09-28 17:42:01 -0700164#ifdef WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000165 case ERRCTX_HRESULT: {
166 char msgbuf[256];
Yves Gerey665174f2018-06-19 15:03:05 +0200167 DWORD flags =
168 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000169 if (DWORD len = FormatMessageA(
Tommie51a0a82018-02-27 15:30:29 +0100170 flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
deadbeef37f5ecf2017-02-27 14:06:41 -0800171 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000172 while ((len > 0) &&
Yves Gerey665174f2018-06-19 15:03:05 +0200173 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000174 msgbuf[--len] = 0;
175 }
176 tmp << " " << msgbuf;
177 }
178 break;
179 }
Tommi0eefb4d2015-05-23 09:54:07 +0200180#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000181 default:
182 break;
183 }
184 extra_ = tmp.str();
185 }
186}
187
Tommie51a0a82018-02-27 15:30:29 +0100188#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700189LogMessage::LogMessage(const char* file,
190 int line,
191 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100192 const char* tag)
Yves Gerey665174f2018-06-19 15:03:05 +0200193 : LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200194 tag_ = tag;
195 print_stream_ << tag << ": ";
jiayl66f0da22015-09-14 15:06:39 -0700196}
Tommie51a0a82018-02-27 15:30:29 +0100197#endif
198
199// DEPRECATED. Currently only used by downstream projects that use
200// implementation details of logging.h. Work is ongoing to remove those
201// dependencies.
Yves Gerey665174f2018-06-19 15:03:05 +0200202LogMessage::LogMessage(const char* file,
203 int line,
204 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100205 const std::string& tag)
206 : LogMessage(file, line, sev) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200207 print_stream_ << tag << ": ";
Tommie51a0a82018-02-27 15:30:29 +0100208}
jiayl66f0da22015-09-14 15:06:39 -0700209
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000210LogMessage::~LogMessage() {
Tommifef05002018-02-27 13:51:08 +0100211 FinishPrintStream();
212
Jonas Olssond8c50782018-09-07 11:21:28 +0200213 const std::string str = print_stream_.Release();
Tommifef05002018-02-27 13:51:08 +0100214
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100215 if (severity_ >= g_dbg_sev) {
Tommie51a0a82018-02-27 15:30:29 +0100216#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700217 OutputToDebug(str, severity_, tag_);
Tommie51a0a82018-02-27 15:30:29 +0100218#else
219 OutputToDebug(str, severity_);
220#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000221 }
222
Markus Handell0d3c09a2021-04-19 09:12:15 +0200223 LoggingMutexLock lock(&g_log_mutex_);
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200224 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
225 if (severity_ >= entry->min_severity_) {
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200226#if defined(WEBRTC_ANDROID)
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200227 entry->OnLogMessage(str, severity_, tag_);
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200228#else
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200229 entry->OnLogMessage(str, severity_);
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200230#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000231 }
232 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000233}
234
Karl Wibergcefc4652018-05-23 23:20:38 +0200235void LogMessage::AddTag(const char* tag) {
236#ifdef WEBRTC_ANDROID
Jonas Olssond8c50782018-09-07 11:21:28 +0200237 tag_ = tag;
Karl Wibergcefc4652018-05-23 23:20:38 +0200238#endif
239}
240
Jonas Olssond8c50782018-09-07 11:21:28 +0200241rtc::StringBuilder& LogMessage::stream() {
242 return print_stream_;
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100243}
244
245int LogMessage::GetMinLogSeverity() {
246 return g_min_sev;
247}
248
249LoggingSeverity LogMessage::GetLogToDebug() {
250 return g_dbg_sev;
251}
Honghai Zhang82d78622016-05-06 11:29:15 -0700252int64_t LogMessage::LogStartTime() {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700253 static const int64_t g_start = SystemTimeMillis();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000254 return g_start;
255}
256
Peter Boström0c4e06b2015-10-07 12:23:21 +0200257uint32_t LogMessage::WallClockStartTime() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800258 static const uint32_t g_start_wallclock = time(nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000259 return g_start_wallclock;
260}
261
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000262void LogMessage::LogThreads(bool on) {
263 thread_ = on;
264}
265
266void LogMessage::LogTimestamps(bool on) {
267 timestamp_ = on;
268}
269
Tommi0eefb4d2015-05-23 09:54:07 +0200270void LogMessage::LogToDebug(LoggingSeverity min_sev) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100271 g_dbg_sev = min_sev;
Markus Handell0d3c09a2021-04-19 09:12:15 +0200272 LoggingMutexLock lock(&g_log_mutex_);
Tommi00aac5a2015-05-25 11:25:59 +0200273 UpdateMinLogSeverity();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000274}
275
andrew88703d72015-09-07 00:34:56 -0700276void LogMessage::SetLogToStderr(bool log_to_stderr) {
277 log_to_stderr_ = log_to_stderr;
278}
279
Tommi0eefb4d2015-05-23 09:54:07 +0200280int LogMessage::GetLogToStream(LogSink* stream) {
Markus Handell0d3c09a2021-04-19 09:12:15 +0200281 LoggingMutexLock lock(&g_log_mutex_);
Tommi0eefb4d2015-05-23 09:54:07 +0200282 LoggingSeverity sev = LS_NONE;
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200283 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
284 if (stream == nullptr || stream == entry) {
285 sev = std::min(sev, entry->min_severity_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000286 }
287 }
288 return sev;
289}
290
Tommi0eefb4d2015-05-23 09:54:07 +0200291void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
Markus Handell0d3c09a2021-04-19 09:12:15 +0200292 LoggingMutexLock lock(&g_log_mutex_);
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200293 stream->min_severity_ = min_sev;
294 stream->next_ = streams_;
295 streams_ = stream;
Markus Handellce1ff6f2020-07-08 08:52:48 +0200296 streams_empty_.store(false, std::memory_order_relaxed);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000297 UpdateMinLogSeverity();
298}
299
Tommi0eefb4d2015-05-23 09:54:07 +0200300void LogMessage::RemoveLogToStream(LogSink* stream) {
Markus Handell0d3c09a2021-04-19 09:12:15 +0200301 LoggingMutexLock lock(&g_log_mutex_);
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200302 for (LogSink** entry = &streams_; *entry != nullptr;
303 entry = &(*entry)->next_) {
304 if (*entry == stream) {
305 *entry = (*entry)->next_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000306 break;
307 }
308 }
Markus Handellce1ff6f2020-07-08 08:52:48 +0200309 streams_empty_.store(streams_ == nullptr, std::memory_order_relaxed);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000310 UpdateMinLogSeverity();
311}
312
Tommi0eefb4d2015-05-23 09:54:07 +0200313void LogMessage::ConfigureLogging(const char* params) {
314 LoggingSeverity current_level = LS_VERBOSE;
315 LoggingSeverity debug_level = GetLogToDebug();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000316
317 std::vector<std::string> tokens;
318 tokenize(params, ' ', &tokens);
319
Tommi0eefb4d2015-05-23 09:54:07 +0200320 for (const std::string& token : tokens) {
321 if (token.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000322 continue;
323
324 // Logging features
Tommi0eefb4d2015-05-23 09:54:07 +0200325 if (token == "tstamp") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000326 LogTimestamps();
Tommi0eefb4d2015-05-23 09:54:07 +0200327 } else if (token == "thread") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000328 LogThreads();
329
Yves Gerey665174f2018-06-19 15:03:05 +0200330 // Logging levels
Tommi0eefb4d2015-05-23 09:54:07 +0200331 } else if (token == "verbose") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000332 current_level = LS_VERBOSE;
Tommi0eefb4d2015-05-23 09:54:07 +0200333 } else if (token == "info") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000334 current_level = LS_INFO;
Tommi0eefb4d2015-05-23 09:54:07 +0200335 } else if (token == "warning") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000336 current_level = LS_WARNING;
Tommi0eefb4d2015-05-23 09:54:07 +0200337 } else if (token == "error") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000338 current_level = LS_ERROR;
Tommi0eefb4d2015-05-23 09:54:07 +0200339 } else if (token == "none") {
340 current_level = LS_NONE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000341
Yves Gerey665174f2018-06-19 15:03:05 +0200342 // Logging targets
Tommi0eefb4d2015-05-23 09:54:07 +0200343 } else if (token == "debug") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000344 debug_level = current_level;
345 }
346 }
347
Robin Raymondce1b1402018-11-22 20:10:11 -0500348#if defined(WEBRTC_WIN) && !defined(WINUWP)
Tommi0eefb4d2015-05-23 09:54:07 +0200349 if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000350 // First, attempt to attach to our parent's console... so if you invoke
351 // from the command line, we'll see the output there. Otherwise, create
352 // our own console window.
353 // Note: These methods fail if a console already exists, which is fine.
Tommie51a0a82018-02-27 15:30:29 +0100354 if (!AttachConsole(ATTACH_PARENT_PROCESS))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000355 ::AllocConsole();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000356 }
Robin Raymondce1b1402018-11-22 20:10:11 -0500357#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000358
359 LogToDebug(debug_level);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000360}
361
danilchap3c6abd22017-09-06 05:46:29 -0700362void LogMessage::UpdateMinLogSeverity()
Markus Handellde8a9352020-06-10 15:40:42 +0200363 RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_mutex_) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100364 LoggingSeverity min_sev = g_dbg_sev;
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200365 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
366 min_sev = std::min(min_sev, entry->min_severity_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000367 }
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100368 g_min_sev = min_sev;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000369}
370
Tommie51a0a82018-02-27 15:30:29 +0100371#if defined(WEBRTC_ANDROID)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000372void LogMessage::OutputToDebug(const std::string& str,
jiayl66f0da22015-09-14 15:06:39 -0700373 LoggingSeverity severity,
Tommie51a0a82018-02-27 15:30:29 +0100374 const char* tag) {
375#else
376void LogMessage::OutputToDebug(const std::string& str,
377 LoggingSeverity severity) {
378#endif
andrew88703d72015-09-07 00:34:56 -0700379 bool log_to_stderr = log_to_stderr_;
tfarinaa41ab932015-10-30 16:08:48 -0700380#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000381 // On the Mac, all stderr output goes to the Console log and causes clutter.
382 // So in opt builds, don't log to stderr unless the user specifically sets
383 // a preference to do so.
Yves Gerey665174f2018-06-19 15:03:05 +0200384 CFStringRef key = CFStringCreateWithCString(
385 kCFAllocatorDefault, "logToStdErr", kCFStringEncodingUTF8);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000386 CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
deadbeef37f5ecf2017-02-27 14:06:41 -0800387 if (key != nullptr && domain != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000388 Boolean exists_and_is_valid;
389 Boolean should_log =
390 CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
391 // If the key doesn't exist or is invalid or is false, we will not log to
392 // stderr.
393 log_to_stderr = exists_and_is_valid && should_log;
394 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800395 if (key != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000396 CFRelease(key);
397 }
Tommie51a0a82018-02-27 15:30:29 +0100398#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
399
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000400#if defined(WEBRTC_WIN)
401 // Always log to the debugger.
402 // Perhaps stderr should be controlled by a preference, as on Mac?
403 OutputDebugStringA(str.c_str());
404 if (log_to_stderr) {
405 // This handles dynamically allocated consoles, too.
406 if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
407 log_to_stderr = false;
408 DWORD written = 0;
409 ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
410 &written, 0);
411 }
412 }
Tommi0eefb4d2015-05-23 09:54:07 +0200413#endif // WEBRTC_WIN
Tommie51a0a82018-02-27 15:30:29 +0100414
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000415#if defined(WEBRTC_ANDROID)
416 // Android's logging facility uses severity to log messages but we
417 // need to map libjingle's severity levels to Android ones first.
418 // Also write to stderr which maybe available to executable started
419 // from the shell.
420 int prio;
421 switch (severity) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000422 case LS_VERBOSE:
423 prio = ANDROID_LOG_VERBOSE;
424 break;
425 case LS_INFO:
426 prio = ANDROID_LOG_INFO;
427 break;
428 case LS_WARNING:
429 prio = ANDROID_LOG_WARN;
430 break;
431 case LS_ERROR:
432 prio = ANDROID_LOG_ERROR;
433 break;
434 default:
435 prio = ANDROID_LOG_UNKNOWN;
436 }
437
438 int size = str.size();
439 int line = 0;
440 int idx = 0;
441 const int max_lines = size / kMaxLogLineSize + 1;
442 if (max_lines == 1) {
Tommie51a0a82018-02-27 15:30:29 +0100443 __android_log_print(prio, tag, "%.*s", size, str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000444 } else {
445 while (size > 0) {
446 const int len = std::min(size, kMaxLogLineSize);
447 // Use the size of the string in the format (str may have \0 in the
448 // middle).
Tommie51a0a82018-02-27 15:30:29 +0100449 __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
450 str.c_str() + idx);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000451 idx += len;
452 size -= len;
453 ++line;
454 }
455 }
456#endif // WEBRTC_ANDROID
457 if (log_to_stderr) {
458 fprintf(stderr, "%s", str.c_str());
459 fflush(stderr);
460 }
461}
462
Tommifef05002018-02-27 13:51:08 +0100463// static
464bool LogMessage::IsNoop(LoggingSeverity severity) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200465 if (severity >= g_dbg_sev || severity >= g_min_sev)
Tommifef05002018-02-27 13:51:08 +0100466 return false;
Markus Handellce1ff6f2020-07-08 08:52:48 +0200467 return streams_empty_.load(std::memory_order_relaxed);
Tommifef05002018-02-27 13:51:08 +0100468}
469
470void LogMessage::FinishPrintStream() {
Tommifef05002018-02-27 13:51:08 +0100471 if (!extra_.empty())
472 print_stream_ << " : " << extra_;
Jonas Olssond8c50782018-09-07 11:21:28 +0200473 print_stream_ << "\n";
Tommifef05002018-02-27 13:51:08 +0100474}
475
Karl Wibergcefc4652018-05-23 23:20:38 +0200476namespace webrtc_logging_impl {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000477
Karl Wibergcefc4652018-05-23 23:20:38 +0200478void Log(const LogArgType* fmt, ...) {
479 va_list args;
480 va_start(args, fmt);
481
482 LogMetadataErr meta;
483 const char* tag = nullptr;
484 switch (*fmt) {
485 case LogArgType::kLogMetadata: {
486 meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
487 break;
488 }
489 case LogArgType::kLogMetadataErr: {
490 meta = va_arg(args, LogMetadataErr);
491 break;
492 }
493#ifdef WEBRTC_ANDROID
494 case LogArgType::kLogMetadataTag: {
495 const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
496 meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
497 tag = tag_meta.tag;
498 break;
499 }
500#endif
501 default: {
502 RTC_NOTREACHED();
503 va_end(args);
504 return;
505 }
506 }
Jonas Olssond8c50782018-09-07 11:21:28 +0200507
Karl Wibergcefc4652018-05-23 23:20:38 +0200508 LogMessage log_message(meta.meta.File(), meta.meta.Line(),
509 meta.meta.Severity(), meta.err_ctx, meta.err);
510 if (tag) {
511 log_message.AddTag(tag);
512 }
513
514 for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
515 switch (*fmt) {
516 case LogArgType::kInt:
517 log_message.stream() << va_arg(args, int);
518 break;
519 case LogArgType::kLong:
520 log_message.stream() << va_arg(args, long);
521 break;
522 case LogArgType::kLongLong:
523 log_message.stream() << va_arg(args, long long);
524 break;
525 case LogArgType::kUInt:
526 log_message.stream() << va_arg(args, unsigned);
527 break;
528 case LogArgType::kULong:
529 log_message.stream() << va_arg(args, unsigned long);
530 break;
531 case LogArgType::kULongLong:
532 log_message.stream() << va_arg(args, unsigned long long);
533 break;
534 case LogArgType::kDouble:
535 log_message.stream() << va_arg(args, double);
536 break;
537 case LogArgType::kLongDouble:
538 log_message.stream() << va_arg(args, long double);
539 break;
Niels Möller65835be2019-02-04 19:23:58 +0100540 case LogArgType::kCharP: {
541 const char* s = va_arg(args, const char*);
542 log_message.stream() << (s ? s : "(null)");
Karl Wibergcefc4652018-05-23 23:20:38 +0200543 break;
Niels Möller65835be2019-02-04 19:23:58 +0100544 }
Karl Wibergcefc4652018-05-23 23:20:38 +0200545 case LogArgType::kStdString:
546 log_message.stream() << *va_arg(args, const std::string*);
547 break;
Jonas Olssonf2ce37c2018-09-12 15:32:47 +0200548 case LogArgType::kStringView:
549 log_message.stream() << *va_arg(args, const absl::string_view*);
550 break;
Karl Wibergcefc4652018-05-23 23:20:38 +0200551 case LogArgType::kVoidP:
Jonas Olssond8c50782018-09-07 11:21:28 +0200552 log_message.stream() << rtc::ToHex(
553 reinterpret_cast<uintptr_t>(va_arg(args, const void*)));
Karl Wibergcefc4652018-05-23 23:20:38 +0200554 break;
555 default:
556 RTC_NOTREACHED();
557 va_end(args);
558 return;
559 }
560 }
561
562 va_end(args);
563}
564
565} // namespace webrtc_logging_impl
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000566} // namespace rtc
Artem Titov6a4a1462019-11-26 16:24:46 +0100567#endif
568
569namespace rtc {
570// Inefficient default implementation, override is recommended.
571void LogSink::OnLogMessage(const std::string& msg,
572 LoggingSeverity severity,
573 const char* tag) {
574 OnLogMessage(tag + (": " + msg), severity);
575}
576
577void LogSink::OnLogMessage(const std::string& msg,
578 LoggingSeverity /* severity */) {
579 OnLogMessage(msg);
580}
581} // namespace rtc