blob: 4bc9183d97fa1be6de7e558675287ef665720708 [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"
Mirko Bonadei96191f82022-08-03 08:12:33 +000046#include "api/units/timestamp.h"
Yves Gerey988cc082018-10-23 12:03:01 +020047#include "rtc_base/checks.h"
Tommie51a0a82018-02-27 15:30:29 +010048#include "rtc_base/platform_thread_types.h"
Steve Anton10542f22019-01-11 09:11:00 -080049#include "rtc_base/string_encode.h"
50#include "rtc_base/string_utils.h"
Tommifef05002018-02-27 13:51:08 +010051#include "rtc_base/strings/string_builder.h"
Markus Handellde8a9352020-06-10 15:40:42 +020052#include "rtc_base/synchronization/mutex.h"
Yves Gerey988cc082018-10-23 12:03:01 +020053#include "rtc_base/thread_annotations.h"
Steve Anton10542f22019-01-11 09:11:00 -080054#include "rtc_base/time_utils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000055
56namespace rtc {
andrew88703d72015-09-07 00:34:56 -070057namespace {
Mirko Bonadei96191f82022-08-03 08:12:33 +000058
Jonas Olsson2b6f1352018-02-15 11:57:03 +010059// By default, release builds don't log, debug builds at info level
60#if !defined(NDEBUG)
Byoungchan Leebe87f0a2021-12-16 17:11:03 +090061constexpr LoggingSeverity kDefaultLoggingSeverity = LS_INFO;
Jonas Olsson2b6f1352018-02-15 11:57:03 +010062#else
Byoungchan Leebe87f0a2021-12-16 17:11:03 +090063constexpr LoggingSeverity kDefaultLoggingSeverity = LS_NONE;
Jonas Olsson2b6f1352018-02-15 11:57:03 +010064#endif
andrew88703d72015-09-07 00:34:56 -070065
Byoungchan Leebe87f0a2021-12-16 17:11:03 +090066// Note: `g_min_sev` and `g_dbg_sev` can be changed while running.
67LoggingSeverity g_min_sev = kDefaultLoggingSeverity;
68LoggingSeverity g_dbg_sev = kDefaultLoggingSeverity;
69
andrew88703d72015-09-07 00:34:56 -070070// Return the filename portion of the string (that following the last slash).
71const char* FilenameFromPath(const char* file) {
72 const char* end1 = ::strrchr(file, '/');
73 const char* end2 = ::strrchr(file, '\\');
74 if (!end1 && !end2)
75 return file;
76 else
77 return (end1 > end2) ? end1 + 1 : end2 + 1;
78}
79
Jonas Olsson2b6f1352018-02-15 11:57:03 +010080// Global lock for log subsystem, only needed to serialize access to streams_.
Byoungchan Lee524a4222021-11-19 19:03:49 +090081webrtc::Mutex& GetLoggingLock() {
82 static webrtc::Mutex& mutex = *new webrtc::Mutex();
83 return mutex;
84}
Markus Handell0d3c09a2021-04-19 09:12:15 +020085
andrew88703d72015-09-07 00:34:56 -070086} // namespace
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000087
Mirko Bonadei96191f82022-08-03 08:12:33 +000088std::string LogLineRef::DefaultLogLine() const {
89 rtc::StringBuilder log_output;
90 if (timestamp_ != webrtc::Timestamp::MinusInfinity()) {
91 // TODO(kwiberg): Switch to absl::StrFormat, if binary size is ok.
92 char timestamp[50]; // Maximum string length of an int64_t is 20.
93 int len =
94 snprintf(timestamp, sizeof(timestamp), "[%03" PRId64 ":%03" PRId64 "]",
95 timestamp_.ms() / 1000, timestamp_.ms() % 1000);
96 RTC_DCHECK_LT(len, sizeof(timestamp));
97 log_output << timestamp;
98 }
99 if (thread_id_.has_value()) {
100 log_output << "[" << *thread_id_ << "] ";
101 }
102 if (!filename_.empty()) {
103#if defined(WEBRTC_ANDROID)
104 log_output << "(line " << line_ << "): ";
105#else
106 log_output << "(" << filename_ << ":" << line_ << "): ";
107#endif
108 }
109 log_output << message_;
110 return log_output.Release();
111}
112
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000113/////////////////////////////////////////////////////////////////////////////
114// LogMessage
115/////////////////////////////////////////////////////////////////////////////
116
andrew88703d72015-09-07 00:34:56 -0700117bool LogMessage::log_to_stderr_ = true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000118
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000119// The list of logging streams currently configured.
120// Note: we explicitly do not clean this up, because of the uncertain ordering
121// of destructors at program exit. Let the person who sets the stream trigger
deadbeef37f5ecf2017-02-27 14:06:41 -0800122// cleanup by setting to null, or let it leak (safe at program exit).
Byoungchan Lee524a4222021-11-19 19:03:49 +0900123ABSL_CONST_INIT LogSink* LogMessage::streams_ RTC_GUARDED_BY(GetLoggingLock()) =
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200124 nullptr;
Markus Handellce1ff6f2020-07-08 08:52:48 +0200125ABSL_CONST_INIT std::atomic<bool> LogMessage::streams_empty_ = {true};
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000126
Mirko Bonadei96191f82022-08-03 08:12:33 +0000127// Boolean options default to false.
128ABSL_CONST_INIT bool LogMessage::log_thread_ = false;
129ABSL_CONST_INIT bool LogMessage::log_timestamp_ = false;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000130
Karl Wibergab4f1c12018-05-04 10:42:28 +0200131LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
132 : LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
133
Peter Boström225789d2015-10-23 15:20:56 +0200134LogMessage::LogMessage(const char* file,
135 int line,
136 LoggingSeverity sev,
137 LogErrorContext err_ctx,
Mirko Bonadei96191f82022-08-03 08:12:33 +0000138 int err) {
139 log_line_.set_severity(sev);
140 if (log_timestamp_) {
Mirko Bonadei57574ea2022-08-12 15:38:43 +0200141 int64_t log_start_time = LogStartTime();
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700142 // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
143 // in log messages represents the real system time.
Mirko Bonadei57574ea2022-08-12 15:38:43 +0200144 int64_t time = TimeDiff(SystemTimeMillis(), log_start_time);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000145 // Also ensure WallClockStartTime is initialized, so that it matches
146 // LogStartTime.
147 WallClockStartTime();
Mirko Bonadei96191f82022-08-03 08:12:33 +0000148 log_line_.set_timestamp(webrtc::Timestamp::Millis(time));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000149 }
150
Mirko Bonadei96191f82022-08-03 08:12:33 +0000151 if (log_thread_) {
152 log_line_.set_thread_id(CurrentThreadId());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000153 }
154
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200155 if (file != nullptr) {
Mirko Bonadei96191f82022-08-03 08:12:33 +0000156 log_line_.set_filename(FilenameFromPath(file));
157 log_line_.set_line(line);
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200158#if defined(WEBRTC_ANDROID)
Mirko Bonadei96191f82022-08-03 08:12:33 +0000159 log_line_.set_tag(log_line_.filename());
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200160#endif
161 }
andrew88703d72015-09-07 00:34:56 -0700162
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000163 if (err_ctx != ERRCTX_NONE) {
Karl Wiberg881f1682018-03-08 15:03:23 +0100164 char tmp_buf[1024];
165 SimpleStringBuilder tmp(tmp_buf);
Tommifef05002018-02-27 13:51:08 +0100166 tmp.AppendFormat("[0x%08X]", err);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000167 switch (err_ctx) {
168 case ERRCTX_ERRNO:
169 tmp << " " << strerror(err);
170 break;
kwiberg77eab702016-09-28 17:42:01 -0700171#ifdef WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000172 case ERRCTX_HRESULT: {
173 char msgbuf[256];
Yves Gerey665174f2018-06-19 15:03:05 +0200174 DWORD flags =
175 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000176 if (DWORD len = FormatMessageA(
Tommie51a0a82018-02-27 15:30:29 +0100177 flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
deadbeef37f5ecf2017-02-27 14:06:41 -0800178 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000179 while ((len > 0) &&
Yves Gerey665174f2018-06-19 15:03:05 +0200180 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000181 msgbuf[--len] = 0;
182 }
183 tmp << " " << msgbuf;
184 }
185 break;
186 }
Tommi0eefb4d2015-05-23 09:54:07 +0200187#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000188 default:
189 break;
190 }
191 extra_ = tmp.str();
192 }
193}
194
Tommie51a0a82018-02-27 15:30:29 +0100195#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700196LogMessage::LogMessage(const char* file,
197 int line,
198 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100199 const char* tag)
Mirko Bonadei96191f82022-08-03 08:12:33 +0000200 : LogMessage(file, line, sev, ERRCTX_NONE, /*err=*/0) {
201 log_line_.set_tag(tag);
Jonas Olssond8c50782018-09-07 11:21:28 +0200202 print_stream_ << tag << ": ";
jiayl66f0da22015-09-14 15:06:39 -0700203}
Tommie51a0a82018-02-27 15:30:29 +0100204#endif
205
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000206LogMessage::~LogMessage() {
Tommifef05002018-02-27 13:51:08 +0100207 FinishPrintStream();
208
Mirko Bonadei96191f82022-08-03 08:12:33 +0000209 log_line_.set_message(print_stream_.Release());
Tommifef05002018-02-27 13:51:08 +0100210
Mirko Bonadei96191f82022-08-03 08:12:33 +0000211 if (log_line_.severity() >= g_dbg_sev) {
212 OutputToDebug(log_line_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000213 }
214
Byoungchan Lee524a4222021-11-19 19:03:49 +0900215 webrtc::MutexLock lock(&GetLoggingLock());
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200216 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
Mirko Bonadei96191f82022-08-03 08:12:33 +0000217 if (log_line_.severity() >= entry->min_severity_) {
218 entry->OnLogMessage(log_line_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000219 }
220 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000221}
222
Karl Wibergcefc4652018-05-23 23:20:38 +0200223void LogMessage::AddTag(const char* tag) {
224#ifdef WEBRTC_ANDROID
Mirko Bonadei96191f82022-08-03 08:12:33 +0000225 log_line_.set_tag(tag);
Karl Wibergcefc4652018-05-23 23:20:38 +0200226#endif
227}
228
Jonas Olssond8c50782018-09-07 11:21:28 +0200229rtc::StringBuilder& LogMessage::stream() {
230 return print_stream_;
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100231}
232
233int LogMessage::GetMinLogSeverity() {
234 return g_min_sev;
235}
236
237LoggingSeverity LogMessage::GetLogToDebug() {
238 return g_dbg_sev;
239}
Honghai Zhang82d78622016-05-06 11:29:15 -0700240int64_t LogMessage::LogStartTime() {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700241 static const int64_t g_start = SystemTimeMillis();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000242 return g_start;
243}
244
Peter Boström0c4e06b2015-10-07 12:23:21 +0200245uint32_t LogMessage::WallClockStartTime() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800246 static const uint32_t g_start_wallclock = time(nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000247 return g_start_wallclock;
248}
249
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000250void LogMessage::LogThreads(bool on) {
Mirko Bonadei96191f82022-08-03 08:12:33 +0000251 log_thread_ = on;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000252}
253
254void LogMessage::LogTimestamps(bool on) {
Mirko Bonadei96191f82022-08-03 08:12:33 +0000255 log_timestamp_ = on;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000256}
257
Tommi0eefb4d2015-05-23 09:54:07 +0200258void LogMessage::LogToDebug(LoggingSeverity min_sev) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100259 g_dbg_sev = min_sev;
Byoungchan Lee524a4222021-11-19 19:03:49 +0900260 webrtc::MutexLock lock(&GetLoggingLock());
Tommi00aac5a2015-05-25 11:25:59 +0200261 UpdateMinLogSeverity();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000262}
263
andrew88703d72015-09-07 00:34:56 -0700264void LogMessage::SetLogToStderr(bool log_to_stderr) {
265 log_to_stderr_ = log_to_stderr;
266}
267
Tommi0eefb4d2015-05-23 09:54:07 +0200268int LogMessage::GetLogToStream(LogSink* stream) {
Byoungchan Lee524a4222021-11-19 19:03:49 +0900269 webrtc::MutexLock lock(&GetLoggingLock());
Tommi0eefb4d2015-05-23 09:54:07 +0200270 LoggingSeverity sev = LS_NONE;
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200271 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
272 if (stream == nullptr || stream == entry) {
273 sev = std::min(sev, entry->min_severity_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000274 }
275 }
276 return sev;
277}
278
Tommi0eefb4d2015-05-23 09:54:07 +0200279void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
Byoungchan Lee524a4222021-11-19 19:03:49 +0900280 webrtc::MutexLock lock(&GetLoggingLock());
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200281 stream->min_severity_ = min_sev;
282 stream->next_ = streams_;
283 streams_ = stream;
Markus Handellce1ff6f2020-07-08 08:52:48 +0200284 streams_empty_.store(false, std::memory_order_relaxed);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000285 UpdateMinLogSeverity();
286}
287
Tommi0eefb4d2015-05-23 09:54:07 +0200288void LogMessage::RemoveLogToStream(LogSink* stream) {
Byoungchan Lee524a4222021-11-19 19:03:49 +0900289 webrtc::MutexLock lock(&GetLoggingLock());
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200290 for (LogSink** entry = &streams_; *entry != nullptr;
291 entry = &(*entry)->next_) {
292 if (*entry == stream) {
293 *entry = (*entry)->next_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000294 break;
295 }
296 }
Markus Handellce1ff6f2020-07-08 08:52:48 +0200297 streams_empty_.store(streams_ == nullptr, std::memory_order_relaxed);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000298 UpdateMinLogSeverity();
299}
300
Ali Tofigh2ab914c2022-04-13 12:55:15 +0200301void LogMessage::ConfigureLogging(absl::string_view params) {
Tommi0eefb4d2015-05-23 09:54:07 +0200302 LoggingSeverity current_level = LS_VERBOSE;
303 LoggingSeverity debug_level = GetLogToDebug();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000304
305 std::vector<std::string> tokens;
306 tokenize(params, ' ', &tokens);
307
Tommi0eefb4d2015-05-23 09:54:07 +0200308 for (const std::string& token : tokens) {
309 if (token.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000310 continue;
311
312 // Logging features
Tommi0eefb4d2015-05-23 09:54:07 +0200313 if (token == "tstamp") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000314 LogTimestamps();
Tommi0eefb4d2015-05-23 09:54:07 +0200315 } else if (token == "thread") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000316 LogThreads();
317
Yves Gerey665174f2018-06-19 15:03:05 +0200318 // Logging levels
Tommi0eefb4d2015-05-23 09:54:07 +0200319 } else if (token == "verbose") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000320 current_level = LS_VERBOSE;
Tommi0eefb4d2015-05-23 09:54:07 +0200321 } else if (token == "info") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000322 current_level = LS_INFO;
Tommi0eefb4d2015-05-23 09:54:07 +0200323 } else if (token == "warning") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000324 current_level = LS_WARNING;
Tommi0eefb4d2015-05-23 09:54:07 +0200325 } else if (token == "error") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000326 current_level = LS_ERROR;
Tommi0eefb4d2015-05-23 09:54:07 +0200327 } else if (token == "none") {
328 current_level = LS_NONE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000329
Yves Gerey665174f2018-06-19 15:03:05 +0200330 // Logging targets
Tommi0eefb4d2015-05-23 09:54:07 +0200331 } else if (token == "debug") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000332 debug_level = current_level;
333 }
334 }
335
Robin Raymondce1b1402018-11-22 20:10:11 -0500336#if defined(WEBRTC_WIN) && !defined(WINUWP)
Tommi0eefb4d2015-05-23 09:54:07 +0200337 if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000338 // First, attempt to attach to our parent's console... so if you invoke
339 // from the command line, we'll see the output there. Otherwise, create
340 // our own console window.
341 // Note: These methods fail if a console already exists, which is fine.
Tommie51a0a82018-02-27 15:30:29 +0100342 if (!AttachConsole(ATTACH_PARENT_PROCESS))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000343 ::AllocConsole();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000344 }
Robin Raymondce1b1402018-11-22 20:10:11 -0500345#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000346
347 LogToDebug(debug_level);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000348}
349
danilchap3c6abd22017-09-06 05:46:29 -0700350void LogMessage::UpdateMinLogSeverity()
Byoungchan Lee524a4222021-11-19 19:03:49 +0900351 RTC_EXCLUSIVE_LOCKS_REQUIRED(GetLoggingLock()) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100352 LoggingSeverity min_sev = g_dbg_sev;
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200353 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
354 min_sev = std::min(min_sev, entry->min_severity_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000355 }
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100356 g_min_sev = min_sev;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000357}
358
Mirko Bonadei96191f82022-08-03 08:12:33 +0000359void LogMessage::OutputToDebug(const LogLineRef& log_line) {
360 std::string msg_str = log_line.DefaultLogLine();
andrew88703d72015-09-07 00:34:56 -0700361 bool log_to_stderr = log_to_stderr_;
tfarinaa41ab932015-10-30 16:08:48 -0700362#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000363 // On the Mac, all stderr output goes to the Console log and causes clutter.
364 // So in opt builds, don't log to stderr unless the user specifically sets
365 // a preference to do so.
Yves Gerey665174f2018-06-19 15:03:05 +0200366 CFStringRef key = CFStringCreateWithCString(
367 kCFAllocatorDefault, "logToStdErr", kCFStringEncodingUTF8);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000368 CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
deadbeef37f5ecf2017-02-27 14:06:41 -0800369 if (key != nullptr && domain != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000370 Boolean exists_and_is_valid;
371 Boolean should_log =
372 CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
373 // If the key doesn't exist or is invalid or is false, we will not log to
374 // stderr.
375 log_to_stderr = exists_and_is_valid && should_log;
376 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800377 if (key != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000378 CFRelease(key);
379 }
Tommie51a0a82018-02-27 15:30:29 +0100380#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
381
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000382#if defined(WEBRTC_WIN)
383 // Always log to the debugger.
384 // Perhaps stderr should be controlled by a preference, as on Mac?
Ali Tofigh98bfd992022-07-22 22:10:49 +0200385 OutputDebugStringA(msg_str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000386 if (log_to_stderr) {
387 // This handles dynamically allocated consoles, too.
388 if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
389 log_to_stderr = false;
390 DWORD written = 0;
Mirko Bonadei96191f82022-08-03 08:12:33 +0000391 ::WriteFile(error_handle, msg_str.c_str(),
392 static_cast<DWORD>(msg_str.size()), &written, 0);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000393 }
394 }
Tommi0eefb4d2015-05-23 09:54:07 +0200395#endif // WEBRTC_WIN
Tommie51a0a82018-02-27 15:30:29 +0100396
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000397#if defined(WEBRTC_ANDROID)
398 // Android's logging facility uses severity to log messages but we
399 // need to map libjingle's severity levels to Android ones first.
400 // Also write to stderr which maybe available to executable started
401 // from the shell.
402 int prio;
Mirko Bonadei96191f82022-08-03 08:12:33 +0000403 switch (log_line.severity()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000404 case LS_VERBOSE:
405 prio = ANDROID_LOG_VERBOSE;
406 break;
407 case LS_INFO:
408 prio = ANDROID_LOG_INFO;
409 break;
410 case LS_WARNING:
411 prio = ANDROID_LOG_WARN;
412 break;
413 case LS_ERROR:
414 prio = ANDROID_LOG_ERROR;
415 break;
416 default:
417 prio = ANDROID_LOG_UNKNOWN;
418 }
419
Mirko Bonadei96191f82022-08-03 08:12:33 +0000420 int size = msg_str.size();
421 int current_line = 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000422 int idx = 0;
423 const int max_lines = size / kMaxLogLineSize + 1;
424 if (max_lines == 1) {
Mirko Bonadei96191f82022-08-03 08:12:33 +0000425 __android_log_print(prio, log_line.tag().data(), "%.*s", size,
426 msg_str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000427 } else {
428 while (size > 0) {
429 const int len = std::min(size, kMaxLogLineSize);
Ali Tofigh98bfd992022-07-22 22:10:49 +0200430 // Use the size of the string in the format (msg may have \0 in the
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000431 // middle).
Mirko Bonadei96191f82022-08-03 08:12:33 +0000432 __android_log_print(prio, log_line.tag().data(), "[%d/%d] %.*s",
433 current_line + 1, max_lines, len,
Ali Tofigh98bfd992022-07-22 22:10:49 +0200434 msg_str.c_str() + idx);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000435 idx += len;
436 size -= len;
Mirko Bonadei96191f82022-08-03 08:12:33 +0000437 ++current_line;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000438 }
439 }
440#endif // WEBRTC_ANDROID
441 if (log_to_stderr) {
Ali Tofigh98bfd992022-07-22 22:10:49 +0200442 fprintf(stderr, "%s", msg_str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000443 fflush(stderr);
444 }
445}
446
Tommifef05002018-02-27 13:51:08 +0100447// static
448bool LogMessage::IsNoop(LoggingSeverity severity) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200449 if (severity >= g_dbg_sev || severity >= g_min_sev)
Tommifef05002018-02-27 13:51:08 +0100450 return false;
Markus Handellce1ff6f2020-07-08 08:52:48 +0200451 return streams_empty_.load(std::memory_order_relaxed);
Tommifef05002018-02-27 13:51:08 +0100452}
453
454void LogMessage::FinishPrintStream() {
Tommifef05002018-02-27 13:51:08 +0100455 if (!extra_.empty())
456 print_stream_ << " : " << extra_;
Jonas Olssond8c50782018-09-07 11:21:28 +0200457 print_stream_ << "\n";
Tommifef05002018-02-27 13:51:08 +0100458}
459
Karl Wibergcefc4652018-05-23 23:20:38 +0200460namespace webrtc_logging_impl {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000461
Karl Wibergcefc4652018-05-23 23:20:38 +0200462void Log(const LogArgType* fmt, ...) {
463 va_list args;
464 va_start(args, fmt);
465
466 LogMetadataErr meta;
467 const char* tag = nullptr;
468 switch (*fmt) {
469 case LogArgType::kLogMetadata: {
470 meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
471 break;
472 }
473 case LogArgType::kLogMetadataErr: {
474 meta = va_arg(args, LogMetadataErr);
475 break;
476 }
477#ifdef WEBRTC_ANDROID
478 case LogArgType::kLogMetadataTag: {
479 const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
480 meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
481 tag = tag_meta.tag;
482 break;
483 }
484#endif
485 default: {
Artem Titovd3251962021-11-15 16:57:07 +0100486 RTC_DCHECK_NOTREACHED();
Karl Wibergcefc4652018-05-23 23:20:38 +0200487 va_end(args);
488 return;
489 }
490 }
Jonas Olssond8c50782018-09-07 11:21:28 +0200491
Karl Wibergcefc4652018-05-23 23:20:38 +0200492 LogMessage log_message(meta.meta.File(), meta.meta.Line(),
493 meta.meta.Severity(), meta.err_ctx, meta.err);
494 if (tag) {
495 log_message.AddTag(tag);
496 }
497
498 for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
499 switch (*fmt) {
500 case LogArgType::kInt:
501 log_message.stream() << va_arg(args, int);
502 break;
503 case LogArgType::kLong:
504 log_message.stream() << va_arg(args, long);
505 break;
506 case LogArgType::kLongLong:
507 log_message.stream() << va_arg(args, long long);
508 break;
509 case LogArgType::kUInt:
510 log_message.stream() << va_arg(args, unsigned);
511 break;
512 case LogArgType::kULong:
513 log_message.stream() << va_arg(args, unsigned long);
514 break;
515 case LogArgType::kULongLong:
516 log_message.stream() << va_arg(args, unsigned long long);
517 break;
518 case LogArgType::kDouble:
519 log_message.stream() << va_arg(args, double);
520 break;
521 case LogArgType::kLongDouble:
522 log_message.stream() << va_arg(args, long double);
523 break;
Niels Möller65835be2019-02-04 19:23:58 +0100524 case LogArgType::kCharP: {
525 const char* s = va_arg(args, const char*);
526 log_message.stream() << (s ? s : "(null)");
Karl Wibergcefc4652018-05-23 23:20:38 +0200527 break;
Niels Möller65835be2019-02-04 19:23:58 +0100528 }
Karl Wibergcefc4652018-05-23 23:20:38 +0200529 case LogArgType::kStdString:
530 log_message.stream() << *va_arg(args, const std::string*);
531 break;
Jonas Olssonf2ce37c2018-09-12 15:32:47 +0200532 case LogArgType::kStringView:
533 log_message.stream() << *va_arg(args, const absl::string_view*);
534 break;
Karl Wibergcefc4652018-05-23 23:20:38 +0200535 case LogArgType::kVoidP:
Jonas Olssond8c50782018-09-07 11:21:28 +0200536 log_message.stream() << rtc::ToHex(
537 reinterpret_cast<uintptr_t>(va_arg(args, const void*)));
Karl Wibergcefc4652018-05-23 23:20:38 +0200538 break;
539 default:
Artem Titovd3251962021-11-15 16:57:07 +0100540 RTC_DCHECK_NOTREACHED();
Karl Wibergcefc4652018-05-23 23:20:38 +0200541 va_end(args);
542 return;
543 }
544 }
545
546 va_end(args);
547}
548
549} // namespace webrtc_logging_impl
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000550} // namespace rtc
Artem Titov6a4a1462019-11-26 16:24:46 +0100551#endif
552
553namespace rtc {
Mirko Bonadei96191f82022-08-03 08:12:33 +0000554// Default implementation, override is recomended.
555void LogSink::OnLogMessage(const LogLineRef& log_line) {
556#if defined(WEBRTC_ANDROID)
557 OnLogMessage(log_line.DefaultLogLine(), log_line.severity(),
558 log_line.tag().data());
559#else
560 OnLogMessage(log_line.DefaultLogLine(), log_line.severity());
561#endif
562}
563
Artem Titov6a4a1462019-11-26 16:24:46 +0100564// Inefficient default implementation, override is recommended.
565void LogSink::OnLogMessage(const std::string& msg,
566 LoggingSeverity severity,
567 const char* tag) {
568 OnLogMessage(tag + (": " + msg), severity);
569}
570
571void LogSink::OnLogMessage(const std::string& msg,
572 LoggingSeverity /* severity */) {
573 OnLogMessage(msg);
574}
Ali Tofigh6364d082022-03-14 13:32:04 +0100575
576// Inefficient default implementation, override is recommended.
577void LogSink::OnLogMessage(absl::string_view msg,
578 LoggingSeverity severity,
579 const char* tag) {
580 OnLogMessage(tag + (": " + std::string(msg)), severity);
581}
582
583void LogSink::OnLogMessage(absl::string_view msg,
584 LoggingSeverity /* severity */) {
585 OnLogMessage(msg);
586}
587
588void LogSink::OnLogMessage(absl::string_view msg) {
589 OnLogMessage(std::string(msg));
590}
Artem Titov6a4a1462019-11-26 16:24:46 +0100591} // namespace rtc