blob: 42f4fa941f2d7709a22e160eafe74009e3fa81c1 [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>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000023// Android has a 1024 limit on log inputs. We use 60 chars as an
24// approx for the header/tag portion.
25// See android/system/core/liblog/logd_write.c
26static const int kMaxLogLineSize = 1024 - 60;
27#endif // WEBRTC_MAC && !defined(WEBRTC_IOS) || WEBRTC_ANDROID
28
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000029#include <limits.h>
Yves Gerey665174f2018-06-19 15:03:05 +020030#include <time.h>
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000031
32#include <algorithm>
Karl Wibergcefc4652018-05-23 23:20:38 +020033#include <cstdarg>
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000034#include <iomanip>
35#include <ostream>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000036#include <vector>
37
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020038#include "rtc_base/criticalsection.h"
39#include "rtc_base/logging.h"
Tommie51a0a82018-02-27 15:30:29 +010040#include "rtc_base/platform_thread_types.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020041#include "rtc_base/stringencode.h"
Tommifef05002018-02-27 13:51:08 +010042#include "rtc_base/strings/string_builder.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020043#include "rtc_base/stringutils.h"
44#include "rtc_base/timeutils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000045
46namespace rtc {
andrew88703d72015-09-07 00:34:56 -070047namespace {
Jonas Olsson2b6f1352018-02-15 11:57:03 +010048// By default, release builds don't log, debug builds at info level
49#if !defined(NDEBUG)
50static LoggingSeverity g_min_sev = LS_INFO;
51static LoggingSeverity g_dbg_sev = LS_INFO;
52#else
53static LoggingSeverity g_min_sev = LS_NONE;
54static LoggingSeverity g_dbg_sev = LS_NONE;
55#endif
andrew88703d72015-09-07 00:34:56 -070056
57// Return the filename portion of the string (that following the last slash).
58const char* FilenameFromPath(const char* file) {
59 const char* end1 = ::strrchr(file, '/');
60 const char* end2 = ::strrchr(file, '\\');
61 if (!end1 && !end2)
62 return file;
63 else
64 return (end1 > end2) ? end1 + 1 : end2 + 1;
65}
66
Jonas Olsson2b6f1352018-02-15 11:57:03 +010067// Global lock for log subsystem, only needed to serialize access to streams_.
68CriticalSection g_log_crit;
andrew88703d72015-09-07 00:34:56 -070069} // namespace
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000070
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +020071// Inefficient default implementation, override is recommended.
72void LogSink::OnLogMessage(const std::string& msg,
73 LoggingSeverity severity,
74 const char* tag) {
75 OnLogMessage(tag + (": " + msg));
76}
77
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000078/////////////////////////////////////////////////////////////////////////////
79// LogMessage
80/////////////////////////////////////////////////////////////////////////////
81
andrew88703d72015-09-07 00:34:56 -070082bool LogMessage::log_to_stderr_ = true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000083
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000084// The list of logging streams currently configured.
85// Note: we explicitly do not clean this up, because of the uncertain ordering
86// of destructors at program exit. Let the person who sets the stream trigger
deadbeef37f5ecf2017-02-27 14:06:41 -080087// cleanup by setting to null, or let it leak (safe at program exit).
danilchap3c6abd22017-09-06 05:46:29 -070088LogMessage::StreamList LogMessage::streams_ RTC_GUARDED_BY(g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000089
90// Boolean options default to false (0)
91bool LogMessage::thread_, LogMessage::timestamp_;
92
Karl Wibergab4f1c12018-05-04 10:42:28 +020093LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
94 : LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
95
Peter Boström225789d2015-10-23 15:20:56 +020096LogMessage::LogMessage(const char* file,
97 int line,
98 LoggingSeverity sev,
99 LogErrorContext err_ctx,
Tommie51a0a82018-02-27 15:30:29 +0100100 int err)
Jonas Olssond8c50782018-09-07 11:21:28 +0200101 : severity_(sev) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000102 if (timestamp_) {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700103 // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
104 // in log messages represents the real system time.
105 int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000106 // Also ensure WallClockStartTime is initialized, so that it matches
107 // LogStartTime.
108 WallClockStartTime();
Jonas Olssond8c50782018-09-07 11:21:28 +0200109 print_stream_ << "[" << rtc::LeftPad('0', 3, rtc::ToString(time / 1000))
110 << ":" << rtc::LeftPad('0', 3, rtc::ToString(time % 1000))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000111 << "] ";
112 }
113
114 if (thread_) {
henrikaba35d052015-07-14 17:04:08 +0200115 PlatformThreadId id = CurrentThreadId();
Jonas Olssond8c50782018-09-07 11:21:28 +0200116 print_stream_ << "[" << id << "] ";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000117 }
118
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200119 if (file != nullptr) {
120#if defined(WEBRTC_ANDROID)
121 tag_ = FilenameFromPath(file);
122 print_stream_ << "(line " << line << "): ";
123#else
Yves Gerey665174f2018-06-19 15:03:05 +0200124 print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200125#endif
126 }
andrew88703d72015-09-07 00:34:56 -0700127
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000128 if (err_ctx != ERRCTX_NONE) {
Karl Wiberg881f1682018-03-08 15:03:23 +0100129 char tmp_buf[1024];
130 SimpleStringBuilder tmp(tmp_buf);
Tommifef05002018-02-27 13:51:08 +0100131 tmp.AppendFormat("[0x%08X]", err);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000132 switch (err_ctx) {
133 case ERRCTX_ERRNO:
134 tmp << " " << strerror(err);
135 break;
kwiberg77eab702016-09-28 17:42:01 -0700136#ifdef WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000137 case ERRCTX_HRESULT: {
138 char msgbuf[256];
Yves Gerey665174f2018-06-19 15:03:05 +0200139 DWORD flags =
140 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000141 if (DWORD len = FormatMessageA(
Tommie51a0a82018-02-27 15:30:29 +0100142 flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
deadbeef37f5ecf2017-02-27 14:06:41 -0800143 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000144 while ((len > 0) &&
Yves Gerey665174f2018-06-19 15:03:05 +0200145 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000146 msgbuf[--len] = 0;
147 }
148 tmp << " " << msgbuf;
149 }
150 break;
151 }
Tommi0eefb4d2015-05-23 09:54:07 +0200152#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000153#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
154 case ERRCTX_OSSTATUS: {
Tommi09ca02e2016-04-24 17:32:48 +0200155 std::string desc(DescriptionFromOSStatus(err));
156 tmp << " " << (desc.empty() ? "Unknown error" : desc.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000157 break;
158 }
159#endif // WEBRTC_MAC && !defined(WEBRTC_IOS)
160 default:
161 break;
162 }
163 extra_ = tmp.str();
164 }
165}
166
Tommie51a0a82018-02-27 15:30:29 +0100167#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700168LogMessage::LogMessage(const char* file,
169 int line,
170 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100171 const char* tag)
Yves Gerey665174f2018-06-19 15:03:05 +0200172 : LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200173 tag_ = tag;
174 print_stream_ << tag << ": ";
jiayl66f0da22015-09-14 15:06:39 -0700175}
Tommie51a0a82018-02-27 15:30:29 +0100176#endif
177
178// DEPRECATED. Currently only used by downstream projects that use
179// implementation details of logging.h. Work is ongoing to remove those
180// dependencies.
Yves Gerey665174f2018-06-19 15:03:05 +0200181LogMessage::LogMessage(const char* file,
182 int line,
183 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100184 const std::string& tag)
185 : LogMessage(file, line, sev) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200186 print_stream_ << tag << ": ";
Tommie51a0a82018-02-27 15:30:29 +0100187}
jiayl66f0da22015-09-14 15:06:39 -0700188
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000189LogMessage::~LogMessage() {
Tommifef05002018-02-27 13:51:08 +0100190 FinishPrintStream();
191
Jonas Olssond8c50782018-09-07 11:21:28 +0200192 const std::string str = print_stream_.Release();
Tommifef05002018-02-27 13:51:08 +0100193
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100194 if (severity_ >= g_dbg_sev) {
Tommie51a0a82018-02-27 15:30:29 +0100195#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700196 OutputToDebug(str, severity_, tag_);
Tommie51a0a82018-02-27 15:30:29 +0100197#else
198 OutputToDebug(str, severity_);
199#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000200 }
201
Peter Boström225789d2015-10-23 15:20:56 +0200202 CritScope cs(&g_log_crit);
203 for (auto& kv : streams_) {
204 if (severity_ >= kv.second) {
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200205#if defined(WEBRTC_ANDROID)
206 kv.first->OnLogMessage(str, severity_, tag_);
207#else
Peter Boström225789d2015-10-23 15:20:56 +0200208 kv.first->OnLogMessage(str);
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200209#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000210 }
211 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000212}
213
Karl Wibergcefc4652018-05-23 23:20:38 +0200214void LogMessage::AddTag(const char* tag) {
215#ifdef WEBRTC_ANDROID
Jonas Olssond8c50782018-09-07 11:21:28 +0200216 tag_ = tag;
Karl Wibergcefc4652018-05-23 23:20:38 +0200217#endif
218}
219
Jonas Olssond8c50782018-09-07 11:21:28 +0200220rtc::StringBuilder& LogMessage::stream() {
221 return print_stream_;
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100222}
223
224int LogMessage::GetMinLogSeverity() {
225 return g_min_sev;
226}
227
228LoggingSeverity LogMessage::GetLogToDebug() {
229 return g_dbg_sev;
230}
Honghai Zhang82d78622016-05-06 11:29:15 -0700231int64_t LogMessage::LogStartTime() {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700232 static const int64_t g_start = SystemTimeMillis();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000233 return g_start;
234}
235
Peter Boström0c4e06b2015-10-07 12:23:21 +0200236uint32_t LogMessage::WallClockStartTime() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800237 static const uint32_t g_start_wallclock = time(nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000238 return g_start_wallclock;
239}
240
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000241void LogMessage::LogThreads(bool on) {
242 thread_ = on;
243}
244
245void LogMessage::LogTimestamps(bool on) {
246 timestamp_ = on;
247}
248
Tommi0eefb4d2015-05-23 09:54:07 +0200249void LogMessage::LogToDebug(LoggingSeverity min_sev) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100250 g_dbg_sev = min_sev;
Peter Boström225789d2015-10-23 15:20:56 +0200251 CritScope cs(&g_log_crit);
Tommi00aac5a2015-05-25 11:25:59 +0200252 UpdateMinLogSeverity();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000253}
254
andrew88703d72015-09-07 00:34:56 -0700255void LogMessage::SetLogToStderr(bool log_to_stderr) {
256 log_to_stderr_ = log_to_stderr;
257}
258
Tommi0eefb4d2015-05-23 09:54:07 +0200259int LogMessage::GetLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200260 CritScope cs(&g_log_crit);
Tommi0eefb4d2015-05-23 09:54:07 +0200261 LoggingSeverity sev = LS_NONE;
Peter Boström225789d2015-10-23 15:20:56 +0200262 for (auto& kv : streams_) {
263 if (!stream || stream == kv.first) {
264 sev = std::min(sev, kv.second);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000265 }
266 }
267 return sev;
268}
269
Tommi0eefb4d2015-05-23 09:54:07 +0200270void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
Peter Boström225789d2015-10-23 15:20:56 +0200271 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000272 streams_.push_back(std::make_pair(stream, min_sev));
273 UpdateMinLogSeverity();
274}
275
Tommi0eefb4d2015-05-23 09:54:07 +0200276void LogMessage::RemoveLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200277 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000278 for (StreamList::iterator it = streams_.begin(); it != streams_.end(); ++it) {
279 if (stream == it->first) {
280 streams_.erase(it);
281 break;
282 }
283 }
284 UpdateMinLogSeverity();
285}
286
Tommi0eefb4d2015-05-23 09:54:07 +0200287void LogMessage::ConfigureLogging(const char* params) {
288 LoggingSeverity current_level = LS_VERBOSE;
289 LoggingSeverity debug_level = GetLogToDebug();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000290
291 std::vector<std::string> tokens;
292 tokenize(params, ' ', &tokens);
293
Tommi0eefb4d2015-05-23 09:54:07 +0200294 for (const std::string& token : tokens) {
295 if (token.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000296 continue;
297
298 // Logging features
Tommi0eefb4d2015-05-23 09:54:07 +0200299 if (token == "tstamp") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000300 LogTimestamps();
Tommi0eefb4d2015-05-23 09:54:07 +0200301 } else if (token == "thread") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000302 LogThreads();
303
Yves Gerey665174f2018-06-19 15:03:05 +0200304 // Logging levels
Tommi0eefb4d2015-05-23 09:54:07 +0200305 } else if (token == "sensitive") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000306 current_level = LS_SENSITIVE;
Tommi0eefb4d2015-05-23 09:54:07 +0200307 } else if (token == "verbose") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000308 current_level = LS_VERBOSE;
Tommi0eefb4d2015-05-23 09:54:07 +0200309 } else if (token == "info") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000310 current_level = LS_INFO;
Tommi0eefb4d2015-05-23 09:54:07 +0200311 } else if (token == "warning") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000312 current_level = LS_WARNING;
Tommi0eefb4d2015-05-23 09:54:07 +0200313 } else if (token == "error") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000314 current_level = LS_ERROR;
Tommi0eefb4d2015-05-23 09:54:07 +0200315 } else if (token == "none") {
316 current_level = LS_NONE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000317
Yves Gerey665174f2018-06-19 15:03:05 +0200318 // Logging targets
Tommi0eefb4d2015-05-23 09:54:07 +0200319 } else if (token == "debug") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000320 debug_level = current_level;
321 }
322 }
323
324#if defined(WEBRTC_WIN)
Tommi0eefb4d2015-05-23 09:54:07 +0200325 if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000326 // First, attempt to attach to our parent's console... so if you invoke
327 // from the command line, we'll see the output there. Otherwise, create
328 // our own console window.
329 // Note: These methods fail if a console already exists, which is fine.
Tommie51a0a82018-02-27 15:30:29 +0100330 if (!AttachConsole(ATTACH_PARENT_PROCESS))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000331 ::AllocConsole();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000332 }
Tommi0eefb4d2015-05-23 09:54:07 +0200333#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000334
335 LogToDebug(debug_level);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000336}
337
danilchap3c6abd22017-09-06 05:46:29 -0700338void LogMessage::UpdateMinLogSeverity()
339 RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_crit) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100340 LoggingSeverity min_sev = g_dbg_sev;
Karl Wibergd294c852018-06-12 11:31:06 +0200341 for (const auto& kv : streams_) {
342 const LoggingSeverity sev = kv.second;
343 min_sev = std::min(min_sev, sev);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000344 }
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100345 g_min_sev = min_sev;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000346}
347
Tommie51a0a82018-02-27 15:30:29 +0100348#if defined(WEBRTC_ANDROID)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000349void LogMessage::OutputToDebug(const std::string& str,
jiayl66f0da22015-09-14 15:06:39 -0700350 LoggingSeverity severity,
Tommie51a0a82018-02-27 15:30:29 +0100351 const char* tag) {
352#else
353void LogMessage::OutputToDebug(const std::string& str,
354 LoggingSeverity severity) {
355#endif
andrew88703d72015-09-07 00:34:56 -0700356 bool log_to_stderr = log_to_stderr_;
tfarinaa41ab932015-10-30 16:08:48 -0700357#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000358 // On the Mac, all stderr output goes to the Console log and causes clutter.
359 // So in opt builds, don't log to stderr unless the user specifically sets
360 // a preference to do so.
Yves Gerey665174f2018-06-19 15:03:05 +0200361 CFStringRef key = CFStringCreateWithCString(
362 kCFAllocatorDefault, "logToStdErr", kCFStringEncodingUTF8);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000363 CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
deadbeef37f5ecf2017-02-27 14:06:41 -0800364 if (key != nullptr && domain != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000365 Boolean exists_and_is_valid;
366 Boolean should_log =
367 CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
368 // If the key doesn't exist or is invalid or is false, we will not log to
369 // stderr.
370 log_to_stderr = exists_and_is_valid && should_log;
371 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800372 if (key != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000373 CFRelease(key);
374 }
Tommie51a0a82018-02-27 15:30:29 +0100375#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
376
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000377#if defined(WEBRTC_WIN)
378 // Always log to the debugger.
379 // Perhaps stderr should be controlled by a preference, as on Mac?
380 OutputDebugStringA(str.c_str());
381 if (log_to_stderr) {
382 // This handles dynamically allocated consoles, too.
383 if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
384 log_to_stderr = false;
385 DWORD written = 0;
386 ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
387 &written, 0);
388 }
389 }
Tommi0eefb4d2015-05-23 09:54:07 +0200390#endif // WEBRTC_WIN
Tommie51a0a82018-02-27 15:30:29 +0100391
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000392#if defined(WEBRTC_ANDROID)
393 // Android's logging facility uses severity to log messages but we
394 // need to map libjingle's severity levels to Android ones first.
395 // Also write to stderr which maybe available to executable started
396 // from the shell.
397 int prio;
398 switch (severity) {
399 case LS_SENSITIVE:
Tommie51a0a82018-02-27 15:30:29 +0100400 __android_log_write(ANDROID_LOG_INFO, tag, "SENSITIVE");
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000401 if (log_to_stderr) {
402 fprintf(stderr, "SENSITIVE");
403 fflush(stderr);
404 }
405 return;
406 case LS_VERBOSE:
407 prio = ANDROID_LOG_VERBOSE;
408 break;
409 case LS_INFO:
410 prio = ANDROID_LOG_INFO;
411 break;
412 case LS_WARNING:
413 prio = ANDROID_LOG_WARN;
414 break;
415 case LS_ERROR:
416 prio = ANDROID_LOG_ERROR;
417 break;
418 default:
419 prio = ANDROID_LOG_UNKNOWN;
420 }
421
422 int size = str.size();
423 int line = 0;
424 int idx = 0;
425 const int max_lines = size / kMaxLogLineSize + 1;
426 if (max_lines == 1) {
Tommie51a0a82018-02-27 15:30:29 +0100427 __android_log_print(prio, tag, "%.*s", size, str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000428 } else {
429 while (size > 0) {
430 const int len = std::min(size, kMaxLogLineSize);
431 // Use the size of the string in the format (str may have \0 in the
432 // middle).
Tommie51a0a82018-02-27 15:30:29 +0100433 __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
434 str.c_str() + idx);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000435 idx += len;
436 size -= len;
437 ++line;
438 }
439 }
440#endif // WEBRTC_ANDROID
441 if (log_to_stderr) {
442 fprintf(stderr, "%s", str.c_str());
443 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;
451
452 // TODO(tommi): We're grabbing this lock for every LogMessage instance that
453 // is going to be logged. This introduces unnecessary synchronization for
454 // a feature that's mostly used for testing.
455 CritScope cs(&g_log_crit);
Jonas Olssond8c50782018-09-07 11:21:28 +0200456 if (streams_.size() > 0)
457 return false;
458
459 return true;
Tommifef05002018-02-27 13:51:08 +0100460}
461
462void LogMessage::FinishPrintStream() {
Tommifef05002018-02-27 13:51:08 +0100463 if (!extra_.empty())
464 print_stream_ << " : " << extra_;
Jonas Olssond8c50782018-09-07 11:21:28 +0200465 print_stream_ << "\n";
Tommifef05002018-02-27 13:51:08 +0100466}
467
Karl Wibergcefc4652018-05-23 23:20:38 +0200468namespace webrtc_logging_impl {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000469
Karl Wibergcefc4652018-05-23 23:20:38 +0200470void Log(const LogArgType* fmt, ...) {
471 va_list args;
472 va_start(args, fmt);
473
474 LogMetadataErr meta;
475 const char* tag = nullptr;
476 switch (*fmt) {
477 case LogArgType::kLogMetadata: {
478 meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
479 break;
480 }
481 case LogArgType::kLogMetadataErr: {
482 meta = va_arg(args, LogMetadataErr);
483 break;
484 }
485#ifdef WEBRTC_ANDROID
486 case LogArgType::kLogMetadataTag: {
487 const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
488 meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
489 tag = tag_meta.tag;
490 break;
491 }
492#endif
493 default: {
494 RTC_NOTREACHED();
495 va_end(args);
496 return;
497 }
498 }
Jonas Olssond8c50782018-09-07 11:21:28 +0200499
500 if (LogMessage::IsNoop(meta.meta.Severity())) {
501 va_end(args);
502 return;
503 }
504
Karl Wibergcefc4652018-05-23 23:20:38 +0200505 LogMessage log_message(meta.meta.File(), meta.meta.Line(),
506 meta.meta.Severity(), meta.err_ctx, meta.err);
507 if (tag) {
508 log_message.AddTag(tag);
509 }
510
511 for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
512 switch (*fmt) {
513 case LogArgType::kInt:
514 log_message.stream() << va_arg(args, int);
515 break;
516 case LogArgType::kLong:
517 log_message.stream() << va_arg(args, long);
518 break;
519 case LogArgType::kLongLong:
520 log_message.stream() << va_arg(args, long long);
521 break;
522 case LogArgType::kUInt:
523 log_message.stream() << va_arg(args, unsigned);
524 break;
525 case LogArgType::kULong:
526 log_message.stream() << va_arg(args, unsigned long);
527 break;
528 case LogArgType::kULongLong:
529 log_message.stream() << va_arg(args, unsigned long long);
530 break;
531 case LogArgType::kDouble:
532 log_message.stream() << va_arg(args, double);
533 break;
534 case LogArgType::kLongDouble:
535 log_message.stream() << va_arg(args, long double);
536 break;
537 case LogArgType::kCharP:
538 log_message.stream() << va_arg(args, const char*);
539 break;
540 case LogArgType::kStdString:
541 log_message.stream() << *va_arg(args, const std::string*);
542 break;
543 case LogArgType::kVoidP:
Jonas Olssond8c50782018-09-07 11:21:28 +0200544 log_message.stream() << rtc::ToHex(
545 reinterpret_cast<uintptr_t>(va_arg(args, const void*)));
Karl Wibergcefc4652018-05-23 23:20:38 +0200546 break;
547 default:
548 RTC_NOTREACHED();
549 va_end(args);
550 return;
551 }
552 }
553
554 va_end(args);
555}
556
557} // namespace webrtc_logging_impl
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000558} // namespace rtc