blob: 102c1d1c70e1e4c6298d922c013a27220f389bba [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"
Ali Tofigh6364d082022-03-14 13:32:04 +010045#include "absl/strings/string_view.h"
Yves Gerey988cc082018-10-23 12:03:01 +020046#include "rtc_base/checks.h"
Tommie51a0a82018-02-27 15:30:29 +010047#include "rtc_base/platform_thread_types.h"
Steve Anton10542f22019-01-11 09:11:00 -080048#include "rtc_base/string_encode.h"
49#include "rtc_base/string_utils.h"
Tommifef05002018-02-27 13:51:08 +010050#include "rtc_base/strings/string_builder.h"
Markus Handellde8a9352020-06-10 15:40:42 +020051#include "rtc_base/synchronization/mutex.h"
Yves Gerey988cc082018-10-23 12:03:01 +020052#include "rtc_base/thread_annotations.h"
Steve Anton10542f22019-01-11 09:11:00 -080053#include "rtc_base/time_utils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000054
55namespace rtc {
andrew88703d72015-09-07 00:34:56 -070056namespace {
Jonas Olsson2b6f1352018-02-15 11:57:03 +010057// By default, release builds don't log, debug builds at info level
58#if !defined(NDEBUG)
Byoungchan Leebe87f0a2021-12-16 17:11:03 +090059constexpr LoggingSeverity kDefaultLoggingSeverity = LS_INFO;
Jonas Olsson2b6f1352018-02-15 11:57:03 +010060#else
Byoungchan Leebe87f0a2021-12-16 17:11:03 +090061constexpr LoggingSeverity kDefaultLoggingSeverity = LS_NONE;
Jonas Olsson2b6f1352018-02-15 11:57:03 +010062#endif
andrew88703d72015-09-07 00:34:56 -070063
Byoungchan Leebe87f0a2021-12-16 17:11:03 +090064// Note: `g_min_sev` and `g_dbg_sev` can be changed while running.
65LoggingSeverity g_min_sev = kDefaultLoggingSeverity;
66LoggingSeverity g_dbg_sev = kDefaultLoggingSeverity;
67
andrew88703d72015-09-07 00:34:56 -070068// Return the filename portion of the string (that following the last slash).
69const char* FilenameFromPath(const char* file) {
70 const char* end1 = ::strrchr(file, '/');
71 const char* end2 = ::strrchr(file, '\\');
72 if (!end1 && !end2)
73 return file;
74 else
75 return (end1 > end2) ? end1 + 1 : end2 + 1;
76}
77
Jonas Olsson2b6f1352018-02-15 11:57:03 +010078// Global lock for log subsystem, only needed to serialize access to streams_.
Byoungchan Lee524a4222021-11-19 19:03:49 +090079webrtc::Mutex& GetLoggingLock() {
80 static webrtc::Mutex& mutex = *new webrtc::Mutex();
81 return mutex;
82}
Markus Handell0d3c09a2021-04-19 09:12:15 +020083
andrew88703d72015-09-07 00:34:56 -070084} // namespace
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000085
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000086/////////////////////////////////////////////////////////////////////////////
87// LogMessage
88/////////////////////////////////////////////////////////////////////////////
89
andrew88703d72015-09-07 00:34:56 -070090bool LogMessage::log_to_stderr_ = true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000091
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000092// The list of logging streams currently configured.
93// Note: we explicitly do not clean this up, because of the uncertain ordering
94// of destructors at program exit. Let the person who sets the stream trigger
deadbeef37f5ecf2017-02-27 14:06:41 -080095// cleanup by setting to null, or let it leak (safe at program exit).
Byoungchan Lee524a4222021-11-19 19:03:49 +090096ABSL_CONST_INIT LogSink* LogMessage::streams_ RTC_GUARDED_BY(GetLoggingLock()) =
Danil Chapovalovb9f69022019-10-21 09:19:10 +020097 nullptr;
Markus Handellce1ff6f2020-07-08 08:52:48 +020098ABSL_CONST_INIT std::atomic<bool> LogMessage::streams_empty_ = {true};
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)
Jonas Olssond8c50782018-09-07 11:21:28 +0200111 : severity_(sev) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000112 if (timestamp_) {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700113 // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
114 // in log messages represents the real system time.
115 int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000116 // Also ensure WallClockStartTime is initialized, so that it matches
117 // LogStartTime.
118 WallClockStartTime();
Niels Möller646109f2020-09-17 12:40:02 +0200119 // TODO(kwiberg): Switch to absl::StrFormat, if binary size is ok.
120 char timestamp[50]; // Maximum string length of an int64_t is 20.
121 int len =
122 snprintf(timestamp, sizeof(timestamp), "[%03" PRId64 ":%03" PRId64 "]",
123 time / 1000, time % 1000);
124 RTC_DCHECK_LT(len, sizeof(timestamp));
125 print_stream_ << timestamp;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000126 }
127
128 if (thread_) {
henrikaba35d052015-07-14 17:04:08 +0200129 PlatformThreadId id = CurrentThreadId();
Jonas Olssond8c50782018-09-07 11:21:28 +0200130 print_stream_ << "[" << 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 default:
168 break;
169 }
170 extra_ = tmp.str();
171 }
172}
173
Tommie51a0a82018-02-27 15:30:29 +0100174#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700175LogMessage::LogMessage(const char* file,
176 int line,
177 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100178 const char* tag)
Yves Gerey665174f2018-06-19 15:03:05 +0200179 : LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200180 tag_ = tag;
181 print_stream_ << tag << ": ";
jiayl66f0da22015-09-14 15:06:39 -0700182}
Tommie51a0a82018-02-27 15:30:29 +0100183#endif
184
185// DEPRECATED. Currently only used by downstream projects that use
186// implementation details of logging.h. Work is ongoing to remove those
187// dependencies.
Yves Gerey665174f2018-06-19 15:03:05 +0200188LogMessage::LogMessage(const char* file,
189 int line,
190 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100191 const std::string& tag)
192 : LogMessage(file, line, sev) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200193 print_stream_ << tag << ": ";
Tommie51a0a82018-02-27 15:30:29 +0100194}
jiayl66f0da22015-09-14 15:06:39 -0700195
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000196LogMessage::~LogMessage() {
Tommifef05002018-02-27 13:51:08 +0100197 FinishPrintStream();
198
Jonas Olssond8c50782018-09-07 11:21:28 +0200199 const std::string str = print_stream_.Release();
Tommifef05002018-02-27 13:51:08 +0100200
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100201 if (severity_ >= g_dbg_sev) {
Tommie51a0a82018-02-27 15:30:29 +0100202#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700203 OutputToDebug(str, severity_, tag_);
Tommie51a0a82018-02-27 15:30:29 +0100204#else
205 OutputToDebug(str, severity_);
206#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000207 }
208
Byoungchan Lee524a4222021-11-19 19:03:49 +0900209 webrtc::MutexLock lock(&GetLoggingLock());
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200210 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
211 if (severity_ >= entry->min_severity_) {
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200212#if defined(WEBRTC_ANDROID)
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200213 entry->OnLogMessage(str, severity_, tag_);
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200214#else
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200215 entry->OnLogMessage(str, severity_);
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200216#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000217 }
218 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000219}
220
Karl Wibergcefc4652018-05-23 23:20:38 +0200221void LogMessage::AddTag(const char* tag) {
222#ifdef WEBRTC_ANDROID
Jonas Olssond8c50782018-09-07 11:21:28 +0200223 tag_ = tag;
Karl Wibergcefc4652018-05-23 23:20:38 +0200224#endif
225}
226
Jonas Olssond8c50782018-09-07 11:21:28 +0200227rtc::StringBuilder& LogMessage::stream() {
228 return print_stream_;
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100229}
230
231int LogMessage::GetMinLogSeverity() {
232 return g_min_sev;
233}
234
235LoggingSeverity LogMessage::GetLogToDebug() {
236 return g_dbg_sev;
237}
Honghai Zhang82d78622016-05-06 11:29:15 -0700238int64_t LogMessage::LogStartTime() {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700239 static const int64_t g_start = SystemTimeMillis();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000240 return g_start;
241}
242
Peter Boström0c4e06b2015-10-07 12:23:21 +0200243uint32_t LogMessage::WallClockStartTime() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800244 static const uint32_t g_start_wallclock = time(nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000245 return g_start_wallclock;
246}
247
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000248void LogMessage::LogThreads(bool on) {
249 thread_ = on;
250}
251
252void LogMessage::LogTimestamps(bool on) {
253 timestamp_ = on;
254}
255
Tommi0eefb4d2015-05-23 09:54:07 +0200256void LogMessage::LogToDebug(LoggingSeverity min_sev) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100257 g_dbg_sev = min_sev;
Byoungchan Lee524a4222021-11-19 19:03:49 +0900258 webrtc::MutexLock lock(&GetLoggingLock());
Tommi00aac5a2015-05-25 11:25:59 +0200259 UpdateMinLogSeverity();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000260}
261
andrew88703d72015-09-07 00:34:56 -0700262void LogMessage::SetLogToStderr(bool log_to_stderr) {
263 log_to_stderr_ = log_to_stderr;
264}
265
Tommi0eefb4d2015-05-23 09:54:07 +0200266int LogMessage::GetLogToStream(LogSink* stream) {
Byoungchan Lee524a4222021-11-19 19:03:49 +0900267 webrtc::MutexLock lock(&GetLoggingLock());
Tommi0eefb4d2015-05-23 09:54:07 +0200268 LoggingSeverity sev = LS_NONE;
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200269 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
270 if (stream == nullptr || stream == entry) {
271 sev = std::min(sev, entry->min_severity_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000272 }
273 }
274 return sev;
275}
276
Tommi0eefb4d2015-05-23 09:54:07 +0200277void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
Byoungchan Lee524a4222021-11-19 19:03:49 +0900278 webrtc::MutexLock lock(&GetLoggingLock());
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200279 stream->min_severity_ = min_sev;
280 stream->next_ = streams_;
281 streams_ = stream;
Markus Handellce1ff6f2020-07-08 08:52:48 +0200282 streams_empty_.store(false, std::memory_order_relaxed);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000283 UpdateMinLogSeverity();
284}
285
Tommi0eefb4d2015-05-23 09:54:07 +0200286void LogMessage::RemoveLogToStream(LogSink* stream) {
Byoungchan Lee524a4222021-11-19 19:03:49 +0900287 webrtc::MutexLock lock(&GetLoggingLock());
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200288 for (LogSink** entry = &streams_; *entry != nullptr;
289 entry = &(*entry)->next_) {
290 if (*entry == stream) {
291 *entry = (*entry)->next_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000292 break;
293 }
294 }
Markus Handellce1ff6f2020-07-08 08:52:48 +0200295 streams_empty_.store(streams_ == nullptr, std::memory_order_relaxed);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000296 UpdateMinLogSeverity();
297}
298
Tommi0eefb4d2015-05-23 09:54:07 +0200299void LogMessage::ConfigureLogging(const char* params) {
300 LoggingSeverity current_level = LS_VERBOSE;
301 LoggingSeverity debug_level = GetLogToDebug();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000302
303 std::vector<std::string> tokens;
304 tokenize(params, ' ', &tokens);
305
Tommi0eefb4d2015-05-23 09:54:07 +0200306 for (const std::string& token : tokens) {
307 if (token.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000308 continue;
309
310 // Logging features
Tommi0eefb4d2015-05-23 09:54:07 +0200311 if (token == "tstamp") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000312 LogTimestamps();
Tommi0eefb4d2015-05-23 09:54:07 +0200313 } else if (token == "thread") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000314 LogThreads();
315
Yves Gerey665174f2018-06-19 15:03:05 +0200316 // Logging levels
Tommi0eefb4d2015-05-23 09:54:07 +0200317 } else if (token == "verbose") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000318 current_level = LS_VERBOSE;
Tommi0eefb4d2015-05-23 09:54:07 +0200319 } else if (token == "info") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000320 current_level = LS_INFO;
Tommi0eefb4d2015-05-23 09:54:07 +0200321 } else if (token == "warning") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000322 current_level = LS_WARNING;
Tommi0eefb4d2015-05-23 09:54:07 +0200323 } else if (token == "error") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000324 current_level = LS_ERROR;
Tommi0eefb4d2015-05-23 09:54:07 +0200325 } else if (token == "none") {
326 current_level = LS_NONE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000327
Yves Gerey665174f2018-06-19 15:03:05 +0200328 // Logging targets
Tommi0eefb4d2015-05-23 09:54:07 +0200329 } else if (token == "debug") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000330 debug_level = current_level;
331 }
332 }
333
Robin Raymondce1b1402018-11-22 20:10:11 -0500334#if defined(WEBRTC_WIN) && !defined(WINUWP)
Tommi0eefb4d2015-05-23 09:54:07 +0200335 if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000336 // First, attempt to attach to our parent's console... so if you invoke
337 // from the command line, we'll see the output there. Otherwise, create
338 // our own console window.
339 // Note: These methods fail if a console already exists, which is fine.
Tommie51a0a82018-02-27 15:30:29 +0100340 if (!AttachConsole(ATTACH_PARENT_PROCESS))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000341 ::AllocConsole();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000342 }
Robin Raymondce1b1402018-11-22 20:10:11 -0500343#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000344
345 LogToDebug(debug_level);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000346}
347
danilchap3c6abd22017-09-06 05:46:29 -0700348void LogMessage::UpdateMinLogSeverity()
Byoungchan Lee524a4222021-11-19 19:03:49 +0900349 RTC_EXCLUSIVE_LOCKS_REQUIRED(GetLoggingLock()) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100350 LoggingSeverity min_sev = g_dbg_sev;
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200351 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
352 min_sev = std::min(min_sev, entry->min_severity_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000353 }
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100354 g_min_sev = min_sev;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000355}
356
Tommie51a0a82018-02-27 15:30:29 +0100357#if defined(WEBRTC_ANDROID)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000358void LogMessage::OutputToDebug(const std::string& str,
jiayl66f0da22015-09-14 15:06:39 -0700359 LoggingSeverity severity,
Tommie51a0a82018-02-27 15:30:29 +0100360 const char* tag) {
361#else
362void LogMessage::OutputToDebug(const std::string& str,
363 LoggingSeverity severity) {
364#endif
andrew88703d72015-09-07 00:34:56 -0700365 bool log_to_stderr = log_to_stderr_;
tfarinaa41ab932015-10-30 16:08:48 -0700366#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000367 // On the Mac, all stderr output goes to the Console log and causes clutter.
368 // So in opt builds, don't log to stderr unless the user specifically sets
369 // a preference to do so.
Yves Gerey665174f2018-06-19 15:03:05 +0200370 CFStringRef key = CFStringCreateWithCString(
371 kCFAllocatorDefault, "logToStdErr", kCFStringEncodingUTF8);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000372 CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
deadbeef37f5ecf2017-02-27 14:06:41 -0800373 if (key != nullptr && domain != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000374 Boolean exists_and_is_valid;
375 Boolean should_log =
376 CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
377 // If the key doesn't exist or is invalid or is false, we will not log to
378 // stderr.
379 log_to_stderr = exists_and_is_valid && should_log;
380 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800381 if (key != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000382 CFRelease(key);
383 }
Tommie51a0a82018-02-27 15:30:29 +0100384#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
385
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000386#if defined(WEBRTC_WIN)
387 // Always log to the debugger.
388 // Perhaps stderr should be controlled by a preference, as on Mac?
389 OutputDebugStringA(str.c_str());
390 if (log_to_stderr) {
391 // This handles dynamically allocated consoles, too.
392 if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
393 log_to_stderr = false;
394 DWORD written = 0;
395 ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
396 &written, 0);
397 }
398 }
Tommi0eefb4d2015-05-23 09:54:07 +0200399#endif // WEBRTC_WIN
Tommie51a0a82018-02-27 15:30:29 +0100400
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000401#if defined(WEBRTC_ANDROID)
402 // Android's logging facility uses severity to log messages but we
403 // need to map libjingle's severity levels to Android ones first.
404 // Also write to stderr which maybe available to executable started
405 // from the shell.
406 int prio;
407 switch (severity) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000408 case LS_VERBOSE:
409 prio = ANDROID_LOG_VERBOSE;
410 break;
411 case LS_INFO:
412 prio = ANDROID_LOG_INFO;
413 break;
414 case LS_WARNING:
415 prio = ANDROID_LOG_WARN;
416 break;
417 case LS_ERROR:
418 prio = ANDROID_LOG_ERROR;
419 break;
420 default:
421 prio = ANDROID_LOG_UNKNOWN;
422 }
423
424 int size = str.size();
425 int line = 0;
426 int idx = 0;
427 const int max_lines = size / kMaxLogLineSize + 1;
428 if (max_lines == 1) {
Tommie51a0a82018-02-27 15:30:29 +0100429 __android_log_print(prio, tag, "%.*s", size, str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000430 } else {
431 while (size > 0) {
432 const int len = std::min(size, kMaxLogLineSize);
433 // Use the size of the string in the format (str may have \0 in the
434 // middle).
Tommie51a0a82018-02-27 15:30:29 +0100435 __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
436 str.c_str() + idx);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000437 idx += len;
438 size -= len;
439 ++line;
440 }
441 }
442#endif // WEBRTC_ANDROID
443 if (log_to_stderr) {
444 fprintf(stderr, "%s", str.c_str());
445 fflush(stderr);
446 }
447}
448
Tommifef05002018-02-27 13:51:08 +0100449// static
450bool LogMessage::IsNoop(LoggingSeverity severity) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200451 if (severity >= g_dbg_sev || severity >= g_min_sev)
Tommifef05002018-02-27 13:51:08 +0100452 return false;
Markus Handellce1ff6f2020-07-08 08:52:48 +0200453 return streams_empty_.load(std::memory_order_relaxed);
Tommifef05002018-02-27 13:51:08 +0100454}
455
456void LogMessage::FinishPrintStream() {
Tommifef05002018-02-27 13:51:08 +0100457 if (!extra_.empty())
458 print_stream_ << " : " << extra_;
Jonas Olssond8c50782018-09-07 11:21:28 +0200459 print_stream_ << "\n";
Tommifef05002018-02-27 13:51:08 +0100460}
461
Karl Wibergcefc4652018-05-23 23:20:38 +0200462namespace webrtc_logging_impl {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000463
Karl Wibergcefc4652018-05-23 23:20:38 +0200464void Log(const LogArgType* fmt, ...) {
465 va_list args;
466 va_start(args, fmt);
467
468 LogMetadataErr meta;
469 const char* tag = nullptr;
470 switch (*fmt) {
471 case LogArgType::kLogMetadata: {
472 meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
473 break;
474 }
475 case LogArgType::kLogMetadataErr: {
476 meta = va_arg(args, LogMetadataErr);
477 break;
478 }
479#ifdef WEBRTC_ANDROID
480 case LogArgType::kLogMetadataTag: {
481 const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
482 meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
483 tag = tag_meta.tag;
484 break;
485 }
486#endif
487 default: {
Artem Titovd3251962021-11-15 16:57:07 +0100488 RTC_DCHECK_NOTREACHED();
Karl Wibergcefc4652018-05-23 23:20:38 +0200489 va_end(args);
490 return;
491 }
492 }
Jonas Olssond8c50782018-09-07 11:21:28 +0200493
Karl Wibergcefc4652018-05-23 23:20:38 +0200494 LogMessage log_message(meta.meta.File(), meta.meta.Line(),
495 meta.meta.Severity(), meta.err_ctx, meta.err);
496 if (tag) {
497 log_message.AddTag(tag);
498 }
499
500 for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
501 switch (*fmt) {
502 case LogArgType::kInt:
503 log_message.stream() << va_arg(args, int);
504 break;
505 case LogArgType::kLong:
506 log_message.stream() << va_arg(args, long);
507 break;
508 case LogArgType::kLongLong:
509 log_message.stream() << va_arg(args, long long);
510 break;
511 case LogArgType::kUInt:
512 log_message.stream() << va_arg(args, unsigned);
513 break;
514 case LogArgType::kULong:
515 log_message.stream() << va_arg(args, unsigned long);
516 break;
517 case LogArgType::kULongLong:
518 log_message.stream() << va_arg(args, unsigned long long);
519 break;
520 case LogArgType::kDouble:
521 log_message.stream() << va_arg(args, double);
522 break;
523 case LogArgType::kLongDouble:
524 log_message.stream() << va_arg(args, long double);
525 break;
Niels Möller65835be2019-02-04 19:23:58 +0100526 case LogArgType::kCharP: {
527 const char* s = va_arg(args, const char*);
528 log_message.stream() << (s ? s : "(null)");
Karl Wibergcefc4652018-05-23 23:20:38 +0200529 break;
Niels Möller65835be2019-02-04 19:23:58 +0100530 }
Karl Wibergcefc4652018-05-23 23:20:38 +0200531 case LogArgType::kStdString:
532 log_message.stream() << *va_arg(args, const std::string*);
533 break;
Jonas Olssonf2ce37c2018-09-12 15:32:47 +0200534 case LogArgType::kStringView:
535 log_message.stream() << *va_arg(args, const absl::string_view*);
536 break;
Karl Wibergcefc4652018-05-23 23:20:38 +0200537 case LogArgType::kVoidP:
Jonas Olssond8c50782018-09-07 11:21:28 +0200538 log_message.stream() << rtc::ToHex(
539 reinterpret_cast<uintptr_t>(va_arg(args, const void*)));
Karl Wibergcefc4652018-05-23 23:20:38 +0200540 break;
541 default:
Artem Titovd3251962021-11-15 16:57:07 +0100542 RTC_DCHECK_NOTREACHED();
Karl Wibergcefc4652018-05-23 23:20:38 +0200543 va_end(args);
544 return;
545 }
546 }
547
548 va_end(args);
549}
550
551} // namespace webrtc_logging_impl
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000552} // namespace rtc
Artem Titov6a4a1462019-11-26 16:24:46 +0100553#endif
554
555namespace rtc {
556// Inefficient default implementation, override is recommended.
557void LogSink::OnLogMessage(const std::string& msg,
558 LoggingSeverity severity,
559 const char* tag) {
560 OnLogMessage(tag + (": " + msg), severity);
561}
562
563void LogSink::OnLogMessage(const std::string& msg,
564 LoggingSeverity /* severity */) {
565 OnLogMessage(msg);
566}
Ali Tofigh6364d082022-03-14 13:32:04 +0100567
568// Inefficient default implementation, override is recommended.
569void LogSink::OnLogMessage(absl::string_view msg,
570 LoggingSeverity severity,
571 const char* tag) {
572 OnLogMessage(tag + (": " + std::string(msg)), severity);
573}
574
575void LogSink::OnLogMessage(absl::string_view msg,
576 LoggingSeverity /* severity */) {
577 OnLogMessage(msg);
578}
579
580void LogSink::OnLogMessage(absl::string_view msg) {
581 OnLogMessage(std::string(msg));
582}
Artem Titov6a4a1462019-11-26 16:24:46 +0100583} // namespace rtc