blob: 2b5c80b33ce9980c1da78a101ff44e41141fa614 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:261/*
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 15:24:4611#include "rtc_base/logging.h"
12
13#include <string.h>
14
15#if RTC_LOG_ENABLED()
16
henrike@webrtc.orgf0488722014-05-13 18:00:2617#if defined(WEBRTC_WIN)
henrike@webrtc.orgf0488722014-05-13 18:00:2618#include <windows.h>
conceptgenesis3f705622016-01-30 22:40:4419#if _MSC_VER < 1900
henrike@webrtc.orgf0488722014-05-13 18:00:2620#define snprintf _snprintf
conceptgenesis3f705622016-01-30 22:40:4421#endif
henrike@webrtc.orgf0488722014-05-13 18:00:2622#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 10:03:0129
henrike@webrtc.orgf0488722014-05-13 18:00:2630// 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 10:40:0236#include <inttypes.h>
Yves Gerey988cc082018-10-23 10:03:0137#include <stdio.h>
Yves Gerey665174f2018-06-19 13:03:0538#include <time.h>
Jonas Olssona4d87372019-07-05 17:08:3339
andresp@webrtc.orgff689be2015-02-12 11:54:2640#include <algorithm>
Karl Wibergcefc4652018-05-23 21:20:3841#include <cstdarg>
henrike@webrtc.orgf0488722014-05-13 18:00:2642#include <vector>
43
Danil Chapovalovef98ae62019-10-11 15:18:2944#include "absl/base/attributes.h"
Yves Gerey988cc082018-10-23 10:03:0145#include "rtc_base/checks.h"
Tommie51a0a82018-02-27 14:30:2946#include "rtc_base/platform_thread_types.h"
Steve Anton10542f22019-01-11 17:11:0047#include "rtc_base/string_encode.h"
48#include "rtc_base/string_utils.h"
Tommifef05002018-02-27 12:51:0849#include "rtc_base/strings/string_builder.h"
Markus Handellde8a9352020-06-10 13:40:4250#include "rtc_base/synchronization/mutex.h"
Yves Gerey988cc082018-10-23 10:03:0151#include "rtc_base/thread_annotations.h"
Steve Anton10542f22019-01-11 17:11:0052#include "rtc_base/time_utils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:2653
54namespace rtc {
andrew88703d72015-09-07 07:34:5655namespace {
Jonas Olsson2b6f1352018-02-15 10:57:0356// By default, release builds don't log, debug builds at info level
57#if !defined(NDEBUG)
Byoungchan Leebe87f0a2021-12-16 08:11:0358constexpr LoggingSeverity kDefaultLoggingSeverity = LS_INFO;
Jonas Olsson2b6f1352018-02-15 10:57:0359#else
Byoungchan Leebe87f0a2021-12-16 08:11:0360constexpr LoggingSeverity kDefaultLoggingSeverity = LS_NONE;
Jonas Olsson2b6f1352018-02-15 10:57:0361#endif
andrew88703d72015-09-07 07:34:5662
Byoungchan Leebe87f0a2021-12-16 08:11:0363// Note: `g_min_sev` and `g_dbg_sev` can be changed while running.
64LoggingSeverity g_min_sev = kDefaultLoggingSeverity;
65LoggingSeverity g_dbg_sev = kDefaultLoggingSeverity;
66
andrew88703d72015-09-07 07:34:5667// Return the filename portion of the string (that following the last slash).
68const char* FilenameFromPath(const char* file) {
69 const char* end1 = ::strrchr(file, '/');
70 const char* end2 = ::strrchr(file, '\\');
71 if (!end1 && !end2)
72 return file;
73 else
74 return (end1 > end2) ? end1 + 1 : end2 + 1;
75}
76
Jonas Olsson2b6f1352018-02-15 10:57:0377// Global lock for log subsystem, only needed to serialize access to streams_.
Byoungchan Lee524a4222021-11-19 10:03:4978webrtc::Mutex& GetLoggingLock() {
79 static webrtc::Mutex& mutex = *new webrtc::Mutex();
80 return mutex;
81}
Markus Handell0d3c09a2021-04-19 07:12:1582
andrew88703d72015-09-07 07:34:5683} // namespace
henrike@webrtc.orgf0488722014-05-13 18:00:2684
henrike@webrtc.orgf0488722014-05-13 18:00:2685/////////////////////////////////////////////////////////////////////////////
86// LogMessage
87/////////////////////////////////////////////////////////////////////////////
88
andrew88703d72015-09-07 07:34:5689bool LogMessage::log_to_stderr_ = true;
henrike@webrtc.orgf0488722014-05-13 18:00:2690
henrike@webrtc.orgf0488722014-05-13 18:00:2691// The list of logging streams currently configured.
92// Note: we explicitly do not clean this up, because of the uncertain ordering
93// of destructors at program exit. Let the person who sets the stream trigger
deadbeef37f5ecf2017-02-27 22:06:4194// cleanup by setting to null, or let it leak (safe at program exit).
Byoungchan Lee524a4222021-11-19 10:03:4995ABSL_CONST_INIT LogSink* LogMessage::streams_ RTC_GUARDED_BY(GetLoggingLock()) =
Danil Chapovalovb9f69022019-10-21 07:19:1096 nullptr;
Markus Handellce1ff6f2020-07-08 06:52:4897ABSL_CONST_INIT std::atomic<bool> LogMessage::streams_empty_ = {true};
henrike@webrtc.orgf0488722014-05-13 18:00:2698
99// Boolean options default to false (0)
100bool LogMessage::thread_, LogMessage::timestamp_;
101
Karl Wibergab4f1c12018-05-04 08:42:28102LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
103 : LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
104
Peter Boström225789d2015-10-23 13:20:56105LogMessage::LogMessage(const char* file,
106 int line,
107 LoggingSeverity sev,
108 LogErrorContext err_ctx,
Tommie51a0a82018-02-27 14:30:29109 int err)
Jonas Olssond8c50782018-09-07 09:21:28110 : severity_(sev) {
henrike@webrtc.orgf0488722014-05-13 18:00:26111 if (timestamp_) {
Taylor Brandstetter4f0dfbd2016-06-16 00:15:23112 // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
113 // in log messages represents the real system time.
114 int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime());
henrike@webrtc.orgf0488722014-05-13 18:00:26115 // Also ensure WallClockStartTime is initialized, so that it matches
116 // LogStartTime.
117 WallClockStartTime();
Niels Möller646109f2020-09-17 10:40:02118 // TODO(kwiberg): Switch to absl::StrFormat, if binary size is ok.
119 char timestamp[50]; // Maximum string length of an int64_t is 20.
120 int len =
121 snprintf(timestamp, sizeof(timestamp), "[%03" PRId64 ":%03" PRId64 "]",
122 time / 1000, time % 1000);
123 RTC_DCHECK_LT(len, sizeof(timestamp));
124 print_stream_ << timestamp;
henrike@webrtc.orgf0488722014-05-13 18:00:26125 }
126
127 if (thread_) {
henrikaba35d052015-07-14 15:04:08128 PlatformThreadId id = CurrentThreadId();
Jonas Olssond8c50782018-09-07 09:21:28129 print_stream_ << "[" << id << "] ";
henrike@webrtc.orgf0488722014-05-13 18:00:26130 }
131
Paulina Hensmanf1e3cb42018-06-20 12:07:05132 if (file != nullptr) {
133#if defined(WEBRTC_ANDROID)
134 tag_ = FilenameFromPath(file);
135 print_stream_ << "(line " << line << "): ";
136#else
Yves Gerey665174f2018-06-19 13:03:05137 print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
Paulina Hensmanf1e3cb42018-06-20 12:07:05138#endif
139 }
andrew88703d72015-09-07 07:34:56140
henrike@webrtc.orgf0488722014-05-13 18:00:26141 if (err_ctx != ERRCTX_NONE) {
Karl Wiberg881f1682018-03-08 14:03:23142 char tmp_buf[1024];
143 SimpleStringBuilder tmp(tmp_buf);
Tommifef05002018-02-27 12:51:08144 tmp.AppendFormat("[0x%08X]", err);
henrike@webrtc.orgf0488722014-05-13 18:00:26145 switch (err_ctx) {
146 case ERRCTX_ERRNO:
147 tmp << " " << strerror(err);
148 break;
kwiberg77eab702016-09-29 00:42:01149#ifdef WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26150 case ERRCTX_HRESULT: {
151 char msgbuf[256];
Yves Gerey665174f2018-06-19 13:03:05152 DWORD flags =
153 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
henrike@webrtc.orgf0488722014-05-13 18:00:26154 if (DWORD len = FormatMessageA(
Tommie51a0a82018-02-27 14:30:29155 flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
deadbeef37f5ecf2017-02-27 22:06:41156 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26157 while ((len > 0) &&
Yves Gerey665174f2018-06-19 13:03:05158 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
henrike@webrtc.orgf0488722014-05-13 18:00:26159 msgbuf[--len] = 0;
160 }
161 tmp << " " << msgbuf;
162 }
163 break;
164 }
Tommi0eefb4d2015-05-23 07:54:07165#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26166 default:
167 break;
168 }
169 extra_ = tmp.str();
170 }
171}
172
Tommie51a0a82018-02-27 14:30:29173#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 22:06:39174LogMessage::LogMessage(const char* file,
175 int line,
176 LoggingSeverity sev,
Tommie51a0a82018-02-27 14:30:29177 const char* tag)
Yves Gerey665174f2018-06-19 13:03:05178 : LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */) {
Jonas Olssond8c50782018-09-07 09:21:28179 tag_ = tag;
180 print_stream_ << tag << ": ";
jiayl66f0da22015-09-14 22:06:39181}
Tommie51a0a82018-02-27 14:30:29182#endif
183
184// DEPRECATED. Currently only used by downstream projects that use
185// implementation details of logging.h. Work is ongoing to remove those
186// dependencies.
Yves Gerey665174f2018-06-19 13:03:05187LogMessage::LogMessage(const char* file,
188 int line,
189 LoggingSeverity sev,
Tommie51a0a82018-02-27 14:30:29190 const std::string& tag)
191 : LogMessage(file, line, sev) {
Jonas Olssond8c50782018-09-07 09:21:28192 print_stream_ << tag << ": ";
Tommie51a0a82018-02-27 14:30:29193}
jiayl66f0da22015-09-14 22:06:39194
henrike@webrtc.orgf0488722014-05-13 18:00:26195LogMessage::~LogMessage() {
Tommifef05002018-02-27 12:51:08196 FinishPrintStream();
197
Jonas Olssond8c50782018-09-07 09:21:28198 const std::string str = print_stream_.Release();
Tommifef05002018-02-27 12:51:08199
Jonas Olsson2b6f1352018-02-15 10:57:03200 if (severity_ >= g_dbg_sev) {
Tommie51a0a82018-02-27 14:30:29201#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 22:06:39202 OutputToDebug(str, severity_, tag_);
Tommie51a0a82018-02-27 14:30:29203#else
204 OutputToDebug(str, severity_);
205#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26206 }
207
Byoungchan Lee524a4222021-11-19 10:03:49208 webrtc::MutexLock lock(&GetLoggingLock());
Danil Chapovalovb9f69022019-10-21 07:19:10209 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
210 if (severity_ >= entry->min_severity_) {
Paulina Hensmanf1e3cb42018-06-20 12:07:05211#if defined(WEBRTC_ANDROID)
Danil Chapovalovb9f69022019-10-21 07:19:10212 entry->OnLogMessage(str, severity_, tag_);
Paulina Hensmanf1e3cb42018-06-20 12:07:05213#else
Danil Chapovalovb9f69022019-10-21 07:19:10214 entry->OnLogMessage(str, severity_);
Paulina Hensmanf1e3cb42018-06-20 12:07:05215#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26216 }
217 }
henrike@webrtc.orgf0488722014-05-13 18:00:26218}
219
Karl Wibergcefc4652018-05-23 21:20:38220void LogMessage::AddTag(const char* tag) {
221#ifdef WEBRTC_ANDROID
Jonas Olssond8c50782018-09-07 09:21:28222 tag_ = tag;
Karl Wibergcefc4652018-05-23 21:20:38223#endif
224}
225
Jonas Olssond8c50782018-09-07 09:21:28226rtc::StringBuilder& LogMessage::stream() {
227 return print_stream_;
Jonas Olsson2b6f1352018-02-15 10:57:03228}
229
230int LogMessage::GetMinLogSeverity() {
231 return g_min_sev;
232}
233
234LoggingSeverity LogMessage::GetLogToDebug() {
235 return g_dbg_sev;
236}
Honghai Zhang82d78622016-05-06 18:29:15237int64_t LogMessage::LogStartTime() {
Taylor Brandstetter4f0dfbd2016-06-16 00:15:23238 static const int64_t g_start = SystemTimeMillis();
henrike@webrtc.orgf0488722014-05-13 18:00:26239 return g_start;
240}
241
Peter Boström0c4e06b2015-10-07 10:23:21242uint32_t LogMessage::WallClockStartTime() {
deadbeef37f5ecf2017-02-27 22:06:41243 static const uint32_t g_start_wallclock = time(nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26244 return g_start_wallclock;
245}
246
henrike@webrtc.orgf0488722014-05-13 18:00:26247void LogMessage::LogThreads(bool on) {
248 thread_ = on;
249}
250
251void LogMessage::LogTimestamps(bool on) {
252 timestamp_ = on;
253}
254
Tommi0eefb4d2015-05-23 07:54:07255void LogMessage::LogToDebug(LoggingSeverity min_sev) {
Jonas Olsson2b6f1352018-02-15 10:57:03256 g_dbg_sev = min_sev;
Byoungchan Lee524a4222021-11-19 10:03:49257 webrtc::MutexLock lock(&GetLoggingLock());
Tommi00aac5a2015-05-25 09:25:59258 UpdateMinLogSeverity();
henrike@webrtc.orgf0488722014-05-13 18:00:26259}
260
andrew88703d72015-09-07 07:34:56261void LogMessage::SetLogToStderr(bool log_to_stderr) {
262 log_to_stderr_ = log_to_stderr;
263}
264
Tommi0eefb4d2015-05-23 07:54:07265int LogMessage::GetLogToStream(LogSink* stream) {
Byoungchan Lee524a4222021-11-19 10:03:49266 webrtc::MutexLock lock(&GetLoggingLock());
Tommi0eefb4d2015-05-23 07:54:07267 LoggingSeverity sev = LS_NONE;
Danil Chapovalovb9f69022019-10-21 07:19:10268 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
269 if (stream == nullptr || stream == entry) {
270 sev = std::min(sev, entry->min_severity_);
henrike@webrtc.orgf0488722014-05-13 18:00:26271 }
272 }
273 return sev;
274}
275
Tommi0eefb4d2015-05-23 07:54:07276void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
Byoungchan Lee524a4222021-11-19 10:03:49277 webrtc::MutexLock lock(&GetLoggingLock());
Danil Chapovalovb9f69022019-10-21 07:19:10278 stream->min_severity_ = min_sev;
279 stream->next_ = streams_;
280 streams_ = stream;
Markus Handellce1ff6f2020-07-08 06:52:48281 streams_empty_.store(false, std::memory_order_relaxed);
henrike@webrtc.orgf0488722014-05-13 18:00:26282 UpdateMinLogSeverity();
283}
284
Tommi0eefb4d2015-05-23 07:54:07285void LogMessage::RemoveLogToStream(LogSink* stream) {
Byoungchan Lee524a4222021-11-19 10:03:49286 webrtc::MutexLock lock(&GetLoggingLock());
Danil Chapovalovb9f69022019-10-21 07:19:10287 for (LogSink** entry = &streams_; *entry != nullptr;
288 entry = &(*entry)->next_) {
289 if (*entry == stream) {
290 *entry = (*entry)->next_;
henrike@webrtc.orgf0488722014-05-13 18:00:26291 break;
292 }
293 }
Markus Handellce1ff6f2020-07-08 06:52:48294 streams_empty_.store(streams_ == nullptr, std::memory_order_relaxed);
henrike@webrtc.orgf0488722014-05-13 18:00:26295 UpdateMinLogSeverity();
296}
297
Tommi0eefb4d2015-05-23 07:54:07298void LogMessage::ConfigureLogging(const char* params) {
299 LoggingSeverity current_level = LS_VERBOSE;
300 LoggingSeverity debug_level = GetLogToDebug();
henrike@webrtc.orgf0488722014-05-13 18:00:26301
302 std::vector<std::string> tokens;
303 tokenize(params, ' ', &tokens);
304
Tommi0eefb4d2015-05-23 07:54:07305 for (const std::string& token : tokens) {
306 if (token.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26307 continue;
308
309 // Logging features
Tommi0eefb4d2015-05-23 07:54:07310 if (token == "tstamp") {
henrike@webrtc.orgf0488722014-05-13 18:00:26311 LogTimestamps();
Tommi0eefb4d2015-05-23 07:54:07312 } else if (token == "thread") {
henrike@webrtc.orgf0488722014-05-13 18:00:26313 LogThreads();
314
Yves Gerey665174f2018-06-19 13:03:05315 // Logging levels
Tommi0eefb4d2015-05-23 07:54:07316 } else if (token == "verbose") {
henrike@webrtc.orgf0488722014-05-13 18:00:26317 current_level = LS_VERBOSE;
Tommi0eefb4d2015-05-23 07:54:07318 } else if (token == "info") {
henrike@webrtc.orgf0488722014-05-13 18:00:26319 current_level = LS_INFO;
Tommi0eefb4d2015-05-23 07:54:07320 } else if (token == "warning") {
henrike@webrtc.orgf0488722014-05-13 18:00:26321 current_level = LS_WARNING;
Tommi0eefb4d2015-05-23 07:54:07322 } else if (token == "error") {
henrike@webrtc.orgf0488722014-05-13 18:00:26323 current_level = LS_ERROR;
Tommi0eefb4d2015-05-23 07:54:07324 } else if (token == "none") {
325 current_level = LS_NONE;
henrike@webrtc.orgf0488722014-05-13 18:00:26326
Yves Gerey665174f2018-06-19 13:03:05327 // Logging targets
Tommi0eefb4d2015-05-23 07:54:07328 } else if (token == "debug") {
henrike@webrtc.orgf0488722014-05-13 18:00:26329 debug_level = current_level;
330 }
331 }
332
Robin Raymondce1b1402018-11-23 01:10:11333#if defined(WEBRTC_WIN) && !defined(WINUWP)
Tommi0eefb4d2015-05-23 07:54:07334 if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26335 // First, attempt to attach to our parent's console... so if you invoke
336 // from the command line, we'll see the output there. Otherwise, create
337 // our own console window.
338 // Note: These methods fail if a console already exists, which is fine.
Tommie51a0a82018-02-27 14:30:29339 if (!AttachConsole(ATTACH_PARENT_PROCESS))
henrike@webrtc.orgf0488722014-05-13 18:00:26340 ::AllocConsole();
henrike@webrtc.orgf0488722014-05-13 18:00:26341 }
Robin Raymondce1b1402018-11-23 01:10:11342#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
henrike@webrtc.orgf0488722014-05-13 18:00:26343
344 LogToDebug(debug_level);
henrike@webrtc.orgf0488722014-05-13 18:00:26345}
346
danilchap3c6abd22017-09-06 12:46:29347void LogMessage::UpdateMinLogSeverity()
Byoungchan Lee524a4222021-11-19 10:03:49348 RTC_EXCLUSIVE_LOCKS_REQUIRED(GetLoggingLock()) {
Jonas Olsson2b6f1352018-02-15 10:57:03349 LoggingSeverity min_sev = g_dbg_sev;
Danil Chapovalovb9f69022019-10-21 07:19:10350 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
351 min_sev = std::min(min_sev, entry->min_severity_);
henrike@webrtc.orgf0488722014-05-13 18:00:26352 }
Jonas Olsson2b6f1352018-02-15 10:57:03353 g_min_sev = min_sev;
henrike@webrtc.orgf0488722014-05-13 18:00:26354}
355
Tommie51a0a82018-02-27 14:30:29356#if defined(WEBRTC_ANDROID)
henrike@webrtc.orgf0488722014-05-13 18:00:26357void LogMessage::OutputToDebug(const std::string& str,
jiayl66f0da22015-09-14 22:06:39358 LoggingSeverity severity,
Tommie51a0a82018-02-27 14:30:29359 const char* tag) {
360#else
361void LogMessage::OutputToDebug(const std::string& str,
362 LoggingSeverity severity) {
363#endif
andrew88703d72015-09-07 07:34:56364 bool log_to_stderr = log_to_stderr_;
tfarinaa41ab932015-10-30 23:08:48365#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26366 // On the Mac, all stderr output goes to the Console log and causes clutter.
367 // So in opt builds, don't log to stderr unless the user specifically sets
368 // a preference to do so.
Yves Gerey665174f2018-06-19 13:03:05369 CFStringRef key = CFStringCreateWithCString(
370 kCFAllocatorDefault, "logToStdErr", kCFStringEncodingUTF8);
henrike@webrtc.orgf0488722014-05-13 18:00:26371 CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
deadbeef37f5ecf2017-02-27 22:06:41372 if (key != nullptr && domain != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26373 Boolean exists_and_is_valid;
374 Boolean should_log =
375 CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
376 // If the key doesn't exist or is invalid or is false, we will not log to
377 // stderr.
378 log_to_stderr = exists_and_is_valid && should_log;
379 }
deadbeef37f5ecf2017-02-27 22:06:41380 if (key != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26381 CFRelease(key);
382 }
Tommie51a0a82018-02-27 14:30:29383#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
384
henrike@webrtc.orgf0488722014-05-13 18:00:26385#if defined(WEBRTC_WIN)
386 // Always log to the debugger.
387 // Perhaps stderr should be controlled by a preference, as on Mac?
388 OutputDebugStringA(str.c_str());
389 if (log_to_stderr) {
390 // This handles dynamically allocated consoles, too.
391 if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
392 log_to_stderr = false;
393 DWORD written = 0;
394 ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
395 &written, 0);
396 }
397 }
Tommi0eefb4d2015-05-23 07:54:07398#endif // WEBRTC_WIN
Tommie51a0a82018-02-27 14:30:29399
henrike@webrtc.orgf0488722014-05-13 18:00:26400#if defined(WEBRTC_ANDROID)
401 // Android's logging facility uses severity to log messages but we
402 // need to map libjingle's severity levels to Android ones first.
403 // Also write to stderr which maybe available to executable started
404 // from the shell.
405 int prio;
406 switch (severity) {
henrike@webrtc.orgf0488722014-05-13 18:00:26407 case LS_VERBOSE:
408 prio = ANDROID_LOG_VERBOSE;
409 break;
410 case LS_INFO:
411 prio = ANDROID_LOG_INFO;
412 break;
413 case LS_WARNING:
414 prio = ANDROID_LOG_WARN;
415 break;
416 case LS_ERROR:
417 prio = ANDROID_LOG_ERROR;
418 break;
419 default:
420 prio = ANDROID_LOG_UNKNOWN;
421 }
422
423 int size = str.size();
424 int line = 0;
425 int idx = 0;
426 const int max_lines = size / kMaxLogLineSize + 1;
427 if (max_lines == 1) {
Tommie51a0a82018-02-27 14:30:29428 __android_log_print(prio, tag, "%.*s", size, str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26429 } else {
430 while (size > 0) {
431 const int len = std::min(size, kMaxLogLineSize);
432 // Use the size of the string in the format (str may have \0 in the
433 // middle).
Tommie51a0a82018-02-27 14:30:29434 __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
435 str.c_str() + idx);
henrike@webrtc.orgf0488722014-05-13 18:00:26436 idx += len;
437 size -= len;
438 ++line;
439 }
440 }
441#endif // WEBRTC_ANDROID
442 if (log_to_stderr) {
443 fprintf(stderr, "%s", str.c_str());
444 fflush(stderr);
445 }
446}
447
Tommifef05002018-02-27 12:51:08448// static
449bool LogMessage::IsNoop(LoggingSeverity severity) {
Jonas Olssond8c50782018-09-07 09:21:28450 if (severity >= g_dbg_sev || severity >= g_min_sev)
Tommifef05002018-02-27 12:51:08451 return false;
Markus Handellce1ff6f2020-07-08 06:52:48452 return streams_empty_.load(std::memory_order_relaxed);
Tommifef05002018-02-27 12:51:08453}
454
455void LogMessage::FinishPrintStream() {
Tommifef05002018-02-27 12:51:08456 if (!extra_.empty())
457 print_stream_ << " : " << extra_;
Jonas Olssond8c50782018-09-07 09:21:28458 print_stream_ << "\n";
Tommifef05002018-02-27 12:51:08459}
460
Karl Wibergcefc4652018-05-23 21:20:38461namespace webrtc_logging_impl {
henrike@webrtc.orgf0488722014-05-13 18:00:26462
Karl Wibergcefc4652018-05-23 21:20:38463void Log(const LogArgType* fmt, ...) {
464 va_list args;
465 va_start(args, fmt);
466
467 LogMetadataErr meta;
468 const char* tag = nullptr;
469 switch (*fmt) {
470 case LogArgType::kLogMetadata: {
471 meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
472 break;
473 }
474 case LogArgType::kLogMetadataErr: {
475 meta = va_arg(args, LogMetadataErr);
476 break;
477 }
478#ifdef WEBRTC_ANDROID
479 case LogArgType::kLogMetadataTag: {
480 const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
481 meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
482 tag = tag_meta.tag;
483 break;
484 }
485#endif
486 default: {
Artem Titovd3251962021-11-15 15:57:07487 RTC_DCHECK_NOTREACHED();
Karl Wibergcefc4652018-05-23 21:20:38488 va_end(args);
489 return;
490 }
491 }
Jonas Olssond8c50782018-09-07 09:21:28492
Karl Wibergcefc4652018-05-23 21:20:38493 LogMessage log_message(meta.meta.File(), meta.meta.Line(),
494 meta.meta.Severity(), meta.err_ctx, meta.err);
495 if (tag) {
496 log_message.AddTag(tag);
497 }
498
499 for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
500 switch (*fmt) {
501 case LogArgType::kInt:
502 log_message.stream() << va_arg(args, int);
503 break;
504 case LogArgType::kLong:
505 log_message.stream() << va_arg(args, long);
506 break;
507 case LogArgType::kLongLong:
508 log_message.stream() << va_arg(args, long long);
509 break;
510 case LogArgType::kUInt:
511 log_message.stream() << va_arg(args, unsigned);
512 break;
513 case LogArgType::kULong:
514 log_message.stream() << va_arg(args, unsigned long);
515 break;
516 case LogArgType::kULongLong:
517 log_message.stream() << va_arg(args, unsigned long long);
518 break;
519 case LogArgType::kDouble:
520 log_message.stream() << va_arg(args, double);
521 break;
522 case LogArgType::kLongDouble:
523 log_message.stream() << va_arg(args, long double);
524 break;
Niels Möller65835be2019-02-04 18:23:58525 case LogArgType::kCharP: {
526 const char* s = va_arg(args, const char*);
527 log_message.stream() << (s ? s : "(null)");
Karl Wibergcefc4652018-05-23 21:20:38528 break;
Niels Möller65835be2019-02-04 18:23:58529 }
Karl Wibergcefc4652018-05-23 21:20:38530 case LogArgType::kStdString:
531 log_message.stream() << *va_arg(args, const std::string*);
532 break;
Jonas Olssonf2ce37c2018-09-12 13:32:47533 case LogArgType::kStringView:
534 log_message.stream() << *va_arg(args, const absl::string_view*);
535 break;
Karl Wibergcefc4652018-05-23 21:20:38536 case LogArgType::kVoidP:
Jonas Olssond8c50782018-09-07 09:21:28537 log_message.stream() << rtc::ToHex(
538 reinterpret_cast<uintptr_t>(va_arg(args, const void*)));
Karl Wibergcefc4652018-05-23 21:20:38539 break;
540 default:
Artem Titovd3251962021-11-15 15:57:07541 RTC_DCHECK_NOTREACHED();
Karl Wibergcefc4652018-05-23 21:20:38542 va_end(args);
543 return;
544 }
545 }
546
547 va_end(args);
548}
549
550} // namespace webrtc_logging_impl
henrike@webrtc.orgf0488722014-05-13 18:00:26551} // namespace rtc
Artem Titov6a4a1462019-11-26 15:24:46552#endif
553
554namespace rtc {
555// Inefficient default implementation, override is recommended.
556void LogSink::OnLogMessage(const std::string& msg,
557 LoggingSeverity severity,
558 const char* tag) {
559 OnLogMessage(tag + (": " + msg), severity);
560}
561
562void LogSink::OnLogMessage(const std::string& msg,
563 LoggingSeverity /* severity */) {
564 OnLogMessage(msg);
565}
566} // namespace rtc