blob: 158be33b4d9af66dbf20f1bd8660bb2d5e8418f3 [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
11#if defined(WEBRTC_WIN)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000012#include <windows.h>
conceptgenesis3f705622016-01-30 14:40:44 -080013#if _MSC_VER < 1900
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000014#define snprintf _snprintf
conceptgenesis3f705622016-01-30 14:40:44 -080015#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000016#undef ERROR // wingdi.h
17#endif
18
19#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
20#include <CoreServices/CoreServices.h>
21#elif defined(WEBRTC_ANDROID)
22#include <android/log.h>
Yves Gerey988cc082018-10-23 12:03:01 +020023
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000024// Android has a 1024 limit on log inputs. We use 60 chars as an
25// approx for the header/tag portion.
26// See android/system/core/liblog/logd_write.c
27static const int kMaxLogLineSize = 1024 - 60;
28#endif // WEBRTC_MAC && !defined(WEBRTC_IOS) || WEBRTC_ANDROID
29
Yves Gerey988cc082018-10-23 12:03:01 +020030#include <stdio.h>
31#include <string.h>
Yves Gerey665174f2018-06-19 15:03:05 +020032#include <time.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020033
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000034#include <algorithm>
Karl Wibergcefc4652018-05-23 23:20:38 +020035#include <cstdarg>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000036#include <vector>
37
Danil Chapovalovef98ae62019-10-11 17:18:29 +020038#include "absl/base/attributes.h"
Yves Gerey988cc082018-10-23 12:03:01 +020039#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080040#include "rtc_base/critical_section.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020041#include "rtc_base/logging.h"
Tommie51a0a82018-02-27 15:30:29 +010042#include "rtc_base/platform_thread_types.h"
Steve Anton10542f22019-01-11 09:11:00 -080043#include "rtc_base/string_encode.h"
44#include "rtc_base/string_utils.h"
Tommifef05002018-02-27 13:51:08 +010045#include "rtc_base/strings/string_builder.h"
Yves Gerey988cc082018-10-23 12:03:01 +020046#include "rtc_base/thread_annotations.h"
Steve Anton10542f22019-01-11 09:11:00 -080047#include "rtc_base/time_utils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000048
49namespace rtc {
andrew88703d72015-09-07 00:34:56 -070050namespace {
Jonas Olsson2b6f1352018-02-15 11:57:03 +010051// By default, release builds don't log, debug builds at info level
52#if !defined(NDEBUG)
53static LoggingSeverity g_min_sev = LS_INFO;
54static LoggingSeverity g_dbg_sev = LS_INFO;
55#else
56static LoggingSeverity g_min_sev = LS_NONE;
57static LoggingSeverity g_dbg_sev = LS_NONE;
58#endif
andrew88703d72015-09-07 00:34:56 -070059
60// Return the filename portion of the string (that following the last slash).
61const char* FilenameFromPath(const char* file) {
62 const char* end1 = ::strrchr(file, '/');
63 const char* end2 = ::strrchr(file, '\\');
64 if (!end1 && !end2)
65 return file;
66 else
67 return (end1 > end2) ? end1 + 1 : end2 + 1;
68}
69
Jonas Olsson2b6f1352018-02-15 11:57:03 +010070// Global lock for log subsystem, only needed to serialize access to streams_.
Danil Chapovalovef98ae62019-10-11 17:18:29 +020071ABSL_CONST_INIT GlobalLock g_log_crit;
andrew88703d72015-09-07 00:34:56 -070072} // namespace
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000073
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +020074// Inefficient default implementation, override is recommended.
75void LogSink::OnLogMessage(const std::string& msg,
76 LoggingSeverity severity,
77 const char* tag) {
Jiawei Ou3ea18782018-10-31 23:14:24 -070078 OnLogMessage(tag + (": " + msg), severity);
79}
80
81void LogSink::OnLogMessage(const std::string& msg,
82 LoggingSeverity /* severity */) {
83 OnLogMessage(msg);
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +020084}
85
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).
Danil Chapovalovb9f69022019-10-21 09:19:10 +020096ABSL_CONST_INIT LogSink* LogMessage::streams_ RTC_GUARDED_BY(g_log_crit) =
97 nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000098
99// Boolean options default to false (0)
100bool LogMessage::thread_, LogMessage::timestamp_;
101
Karl Wibergab4f1c12018-05-04 10:42:28 +0200102LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
103 : LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
104
Peter Boström225789d2015-10-23 15:20:56 +0200105LogMessage::LogMessage(const char* file,
106 int line,
107 LoggingSeverity sev,
108 LogErrorContext err_ctx,
Tommie51a0a82018-02-27 15:30:29 +0100109 int err)
Jonas Olssond8c50782018-09-07 11:21:28 +0200110 : severity_(sev) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000111 if (timestamp_) {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700112 // 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:26 +0000115 // Also ensure WallClockStartTime is initialized, so that it matches
116 // LogStartTime.
117 WallClockStartTime();
Jonas Olssond8c50782018-09-07 11:21:28 +0200118 print_stream_ << "[" << rtc::LeftPad('0', 3, rtc::ToString(time / 1000))
119 << ":" << rtc::LeftPad('0', 3, rtc::ToString(time % 1000))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000120 << "] ";
121 }
122
123 if (thread_) {
henrikaba35d052015-07-14 17:04:08 +0200124 PlatformThreadId id = CurrentThreadId();
Jonas Olssond8c50782018-09-07 11:21:28 +0200125 print_stream_ << "[" << id << "] ";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000126 }
127
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200128 if (file != nullptr) {
129#if defined(WEBRTC_ANDROID)
130 tag_ = FilenameFromPath(file);
131 print_stream_ << "(line " << line << "): ";
132#else
Yves Gerey665174f2018-06-19 15:03:05 +0200133 print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200134#endif
135 }
andrew88703d72015-09-07 00:34:56 -0700136
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000137 if (err_ctx != ERRCTX_NONE) {
Karl Wiberg881f1682018-03-08 15:03:23 +0100138 char tmp_buf[1024];
139 SimpleStringBuilder tmp(tmp_buf);
Tommifef05002018-02-27 13:51:08 +0100140 tmp.AppendFormat("[0x%08X]", err);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000141 switch (err_ctx) {
142 case ERRCTX_ERRNO:
143 tmp << " " << strerror(err);
144 break;
kwiberg77eab702016-09-28 17:42:01 -0700145#ifdef WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000146 case ERRCTX_HRESULT: {
147 char msgbuf[256];
Yves Gerey665174f2018-06-19 15:03:05 +0200148 DWORD flags =
149 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000150 if (DWORD len = FormatMessageA(
Tommie51a0a82018-02-27 15:30:29 +0100151 flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
deadbeef37f5ecf2017-02-27 14:06:41 -0800152 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000153 while ((len > 0) &&
Yves Gerey665174f2018-06-19 15:03:05 +0200154 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000155 msgbuf[--len] = 0;
156 }
157 tmp << " " << msgbuf;
158 }
159 break;
160 }
Tommi0eefb4d2015-05-23 09:54:07 +0200161#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000162 default:
163 break;
164 }
165 extra_ = tmp.str();
166 }
167}
168
Tommie51a0a82018-02-27 15:30:29 +0100169#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700170LogMessage::LogMessage(const char* file,
171 int line,
172 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100173 const char* tag)
Yves Gerey665174f2018-06-19 15:03:05 +0200174 : LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200175 tag_ = tag;
176 print_stream_ << tag << ": ";
jiayl66f0da22015-09-14 15:06:39 -0700177}
Tommie51a0a82018-02-27 15:30:29 +0100178#endif
179
180// DEPRECATED. Currently only used by downstream projects that use
181// implementation details of logging.h. Work is ongoing to remove those
182// dependencies.
Yves Gerey665174f2018-06-19 15:03:05 +0200183LogMessage::LogMessage(const char* file,
184 int line,
185 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100186 const std::string& tag)
187 : LogMessage(file, line, sev) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200188 print_stream_ << tag << ": ";
Tommie51a0a82018-02-27 15:30:29 +0100189}
jiayl66f0da22015-09-14 15:06:39 -0700190
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000191LogMessage::~LogMessage() {
Tommifef05002018-02-27 13:51:08 +0100192 FinishPrintStream();
193
Jonas Olssond8c50782018-09-07 11:21:28 +0200194 const std::string str = print_stream_.Release();
Tommifef05002018-02-27 13:51:08 +0100195
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100196 if (severity_ >= g_dbg_sev) {
Tommie51a0a82018-02-27 15:30:29 +0100197#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700198 OutputToDebug(str, severity_, tag_);
Tommie51a0a82018-02-27 15:30:29 +0100199#else
200 OutputToDebug(str, severity_);
201#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000202 }
203
Danil Chapovalovef98ae62019-10-11 17:18:29 +0200204 GlobalLockScope cs(&g_log_crit);
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200205 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
206 if (severity_ >= entry->min_severity_) {
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200207#if defined(WEBRTC_ANDROID)
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200208 entry->OnLogMessage(str, severity_, tag_);
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200209#else
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200210 entry->OnLogMessage(str, severity_);
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200211#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000212 }
213 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000214}
215
Karl Wibergcefc4652018-05-23 23:20:38 +0200216void LogMessage::AddTag(const char* tag) {
217#ifdef WEBRTC_ANDROID
Jonas Olssond8c50782018-09-07 11:21:28 +0200218 tag_ = tag;
Karl Wibergcefc4652018-05-23 23:20:38 +0200219#endif
220}
221
Jonas Olssond8c50782018-09-07 11:21:28 +0200222rtc::StringBuilder& LogMessage::stream() {
223 return print_stream_;
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100224}
225
226int LogMessage::GetMinLogSeverity() {
227 return g_min_sev;
228}
229
230LoggingSeverity LogMessage::GetLogToDebug() {
231 return g_dbg_sev;
232}
Honghai Zhang82d78622016-05-06 11:29:15 -0700233int64_t LogMessage::LogStartTime() {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700234 static const int64_t g_start = SystemTimeMillis();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000235 return g_start;
236}
237
Peter Boström0c4e06b2015-10-07 12:23:21 +0200238uint32_t LogMessage::WallClockStartTime() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800239 static const uint32_t g_start_wallclock = time(nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000240 return g_start_wallclock;
241}
242
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000243void LogMessage::LogThreads(bool on) {
244 thread_ = on;
245}
246
247void LogMessage::LogTimestamps(bool on) {
248 timestamp_ = on;
249}
250
Tommi0eefb4d2015-05-23 09:54:07 +0200251void LogMessage::LogToDebug(LoggingSeverity min_sev) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100252 g_dbg_sev = min_sev;
Danil Chapovalovef98ae62019-10-11 17:18:29 +0200253 GlobalLockScope cs(&g_log_crit);
Tommi00aac5a2015-05-25 11:25:59 +0200254 UpdateMinLogSeverity();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000255}
256
andrew88703d72015-09-07 00:34:56 -0700257void LogMessage::SetLogToStderr(bool log_to_stderr) {
258 log_to_stderr_ = log_to_stderr;
259}
260
Tommi0eefb4d2015-05-23 09:54:07 +0200261int LogMessage::GetLogToStream(LogSink* stream) {
Danil Chapovalovef98ae62019-10-11 17:18:29 +0200262 GlobalLockScope cs(&g_log_crit);
Tommi0eefb4d2015-05-23 09:54:07 +0200263 LoggingSeverity sev = LS_NONE;
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200264 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
265 if (stream == nullptr || stream == entry) {
266 sev = std::min(sev, entry->min_severity_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000267 }
268 }
269 return sev;
270}
271
Tommi0eefb4d2015-05-23 09:54:07 +0200272void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
Danil Chapovalovef98ae62019-10-11 17:18:29 +0200273 GlobalLockScope cs(&g_log_crit);
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200274 stream->min_severity_ = min_sev;
275 stream->next_ = streams_;
276 streams_ = stream;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000277 UpdateMinLogSeverity();
278}
279
Tommi0eefb4d2015-05-23 09:54:07 +0200280void LogMessage::RemoveLogToStream(LogSink* stream) {
Danil Chapovalovef98ae62019-10-11 17:18:29 +0200281 GlobalLockScope cs(&g_log_crit);
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200282 for (LogSink** entry = &streams_; *entry != nullptr;
283 entry = &(*entry)->next_) {
284 if (*entry == stream) {
285 *entry = (*entry)->next_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000286 break;
287 }
288 }
289 UpdateMinLogSeverity();
290}
291
Tommi0eefb4d2015-05-23 09:54:07 +0200292void LogMessage::ConfigureLogging(const char* params) {
293 LoggingSeverity current_level = LS_VERBOSE;
294 LoggingSeverity debug_level = GetLogToDebug();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000295
296 std::vector<std::string> tokens;
297 tokenize(params, ' ', &tokens);
298
Tommi0eefb4d2015-05-23 09:54:07 +0200299 for (const std::string& token : tokens) {
300 if (token.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000301 continue;
302
303 // Logging features
Tommi0eefb4d2015-05-23 09:54:07 +0200304 if (token == "tstamp") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000305 LogTimestamps();
Tommi0eefb4d2015-05-23 09:54:07 +0200306 } else if (token == "thread") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000307 LogThreads();
308
Yves Gerey665174f2018-06-19 15:03:05 +0200309 // Logging levels
Tommi0eefb4d2015-05-23 09:54:07 +0200310 } else if (token == "verbose") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000311 current_level = LS_VERBOSE;
Tommi0eefb4d2015-05-23 09:54:07 +0200312 } else if (token == "info") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000313 current_level = LS_INFO;
Tommi0eefb4d2015-05-23 09:54:07 +0200314 } else if (token == "warning") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000315 current_level = LS_WARNING;
Tommi0eefb4d2015-05-23 09:54:07 +0200316 } else if (token == "error") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000317 current_level = LS_ERROR;
Tommi0eefb4d2015-05-23 09:54:07 +0200318 } else if (token == "none") {
319 current_level = LS_NONE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000320
Yves Gerey665174f2018-06-19 15:03:05 +0200321 // Logging targets
Tommi0eefb4d2015-05-23 09:54:07 +0200322 } else if (token == "debug") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000323 debug_level = current_level;
324 }
325 }
326
Robin Raymondce1b1402018-11-22 20:10:11 -0500327#if defined(WEBRTC_WIN) && !defined(WINUWP)
Tommi0eefb4d2015-05-23 09:54:07 +0200328 if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000329 // First, attempt to attach to our parent's console... so if you invoke
330 // from the command line, we'll see the output there. Otherwise, create
331 // our own console window.
332 // Note: These methods fail if a console already exists, which is fine.
Tommie51a0a82018-02-27 15:30:29 +0100333 if (!AttachConsole(ATTACH_PARENT_PROCESS))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000334 ::AllocConsole();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000335 }
Robin Raymondce1b1402018-11-22 20:10:11 -0500336#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000337
338 LogToDebug(debug_level);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000339}
340
danilchap3c6abd22017-09-06 05:46:29 -0700341void LogMessage::UpdateMinLogSeverity()
342 RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_crit) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100343 LoggingSeverity min_sev = g_dbg_sev;
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200344 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
345 min_sev = std::min(min_sev, entry->min_severity_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000346 }
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100347 g_min_sev = min_sev;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000348}
349
Tommie51a0a82018-02-27 15:30:29 +0100350#if defined(WEBRTC_ANDROID)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000351void LogMessage::OutputToDebug(const std::string& str,
jiayl66f0da22015-09-14 15:06:39 -0700352 LoggingSeverity severity,
Tommie51a0a82018-02-27 15:30:29 +0100353 const char* tag) {
354#else
355void LogMessage::OutputToDebug(const std::string& str,
356 LoggingSeverity severity) {
357#endif
andrew88703d72015-09-07 00:34:56 -0700358 bool log_to_stderr = log_to_stderr_;
tfarinaa41ab932015-10-30 16:08:48 -0700359#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000360 // On the Mac, all stderr output goes to the Console log and causes clutter.
361 // So in opt builds, don't log to stderr unless the user specifically sets
362 // a preference to do so.
Yves Gerey665174f2018-06-19 15:03:05 +0200363 CFStringRef key = CFStringCreateWithCString(
364 kCFAllocatorDefault, "logToStdErr", kCFStringEncodingUTF8);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000365 CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
deadbeef37f5ecf2017-02-27 14:06:41 -0800366 if (key != nullptr && domain != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000367 Boolean exists_and_is_valid;
368 Boolean should_log =
369 CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
370 // If the key doesn't exist or is invalid or is false, we will not log to
371 // stderr.
372 log_to_stderr = exists_and_is_valid && should_log;
373 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800374 if (key != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000375 CFRelease(key);
376 }
Tommie51a0a82018-02-27 15:30:29 +0100377#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
378
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000379#if defined(WEBRTC_WIN)
380 // Always log to the debugger.
381 // Perhaps stderr should be controlled by a preference, as on Mac?
382 OutputDebugStringA(str.c_str());
383 if (log_to_stderr) {
384 // This handles dynamically allocated consoles, too.
385 if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
386 log_to_stderr = false;
387 DWORD written = 0;
388 ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
389 &written, 0);
390 }
391 }
Tommi0eefb4d2015-05-23 09:54:07 +0200392#endif // WEBRTC_WIN
Tommie51a0a82018-02-27 15:30:29 +0100393
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000394#if defined(WEBRTC_ANDROID)
395 // Android's logging facility uses severity to log messages but we
396 // need to map libjingle's severity levels to Android ones first.
397 // Also write to stderr which maybe available to executable started
398 // from the shell.
399 int prio;
400 switch (severity) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000401 case LS_VERBOSE:
402 prio = ANDROID_LOG_VERBOSE;
403 break;
404 case LS_INFO:
405 prio = ANDROID_LOG_INFO;
406 break;
407 case LS_WARNING:
408 prio = ANDROID_LOG_WARN;
409 break;
410 case LS_ERROR:
411 prio = ANDROID_LOG_ERROR;
412 break;
413 default:
414 prio = ANDROID_LOG_UNKNOWN;
415 }
416
417 int size = str.size();
418 int line = 0;
419 int idx = 0;
420 const int max_lines = size / kMaxLogLineSize + 1;
421 if (max_lines == 1) {
Tommie51a0a82018-02-27 15:30:29 +0100422 __android_log_print(prio, tag, "%.*s", size, str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000423 } else {
424 while (size > 0) {
425 const int len = std::min(size, kMaxLogLineSize);
426 // Use the size of the string in the format (str may have \0 in the
427 // middle).
Tommie51a0a82018-02-27 15:30:29 +0100428 __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
429 str.c_str() + idx);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000430 idx += len;
431 size -= len;
432 ++line;
433 }
434 }
435#endif // WEBRTC_ANDROID
436 if (log_to_stderr) {
437 fprintf(stderr, "%s", str.c_str());
438 fflush(stderr);
439 }
440}
441
Tommifef05002018-02-27 13:51:08 +0100442// static
443bool LogMessage::IsNoop(LoggingSeverity severity) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200444 if (severity >= g_dbg_sev || severity >= g_min_sev)
Tommifef05002018-02-27 13:51:08 +0100445 return false;
446
447 // TODO(tommi): We're grabbing this lock for every LogMessage instance that
448 // is going to be logged. This introduces unnecessary synchronization for
449 // a feature that's mostly used for testing.
Danil Chapovalovef98ae62019-10-11 17:18:29 +0200450 GlobalLockScope cs(&g_log_crit);
Danil Chapovalovb9f69022019-10-21 09:19:10 +0200451 return streams_ == nullptr;
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: {
486 RTC_NOTREACHED();
487 va_end(args);
488 return;
489 }
490 }
Jonas Olssond8c50782018-09-07 11:21:28 +0200491
492 if (LogMessage::IsNoop(meta.meta.Severity())) {
493 va_end(args);
494 return;
495 }
496
Karl Wibergcefc4652018-05-23 23:20:38 +0200497 LogMessage log_message(meta.meta.File(), meta.meta.Line(),
498 meta.meta.Severity(), meta.err_ctx, meta.err);
499 if (tag) {
500 log_message.AddTag(tag);
501 }
502
503 for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
504 switch (*fmt) {
505 case LogArgType::kInt:
506 log_message.stream() << va_arg(args, int);
507 break;
508 case LogArgType::kLong:
509 log_message.stream() << va_arg(args, long);
510 break;
511 case LogArgType::kLongLong:
512 log_message.stream() << va_arg(args, long long);
513 break;
514 case LogArgType::kUInt:
515 log_message.stream() << va_arg(args, unsigned);
516 break;
517 case LogArgType::kULong:
518 log_message.stream() << va_arg(args, unsigned long);
519 break;
520 case LogArgType::kULongLong:
521 log_message.stream() << va_arg(args, unsigned long long);
522 break;
523 case LogArgType::kDouble:
524 log_message.stream() << va_arg(args, double);
525 break;
526 case LogArgType::kLongDouble:
527 log_message.stream() << va_arg(args, long double);
528 break;
Niels Möller65835be2019-02-04 19:23:58 +0100529 case LogArgType::kCharP: {
530 const char* s = va_arg(args, const char*);
531 log_message.stream() << (s ? s : "(null)");
Karl Wibergcefc4652018-05-23 23:20:38 +0200532 break;
Niels Möller65835be2019-02-04 19:23:58 +0100533 }
Karl Wibergcefc4652018-05-23 23:20:38 +0200534 case LogArgType::kStdString:
535 log_message.stream() << *va_arg(args, const std::string*);
536 break;
Jonas Olssonf2ce37c2018-09-12 15:32:47 +0200537 case LogArgType::kStringView:
538 log_message.stream() << *va_arg(args, const absl::string_view*);
539 break;
Karl Wibergcefc4652018-05-23 23:20:38 +0200540 case LogArgType::kVoidP:
Jonas Olssond8c50782018-09-07 11:21:28 +0200541 log_message.stream() << rtc::ToHex(
542 reinterpret_cast<uintptr_t>(va_arg(args, const void*)));
Karl Wibergcefc4652018-05-23 23:20:38 +0200543 break;
544 default:
545 RTC_NOTREACHED();
546 va_end(args);
547 return;
548 }
549 }
550
551 va_end(args);
552}
553
554} // namespace webrtc_logging_impl
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000555} // namespace rtc