blob: 129a897439728713bc11c4be4e8c05ff2f724e7e [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
Oleh Prypin96a0f612018-10-05 13:13:38 +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>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000034#include <vector>
35
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020036#include "rtc_base/criticalsection.h"
37#include "rtc_base/logging.h"
Tommie51a0a82018-02-27 15:30:29 +010038#include "rtc_base/platform_thread_types.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020039#include "rtc_base/stringencode.h"
Tommifef05002018-02-27 13:51:08 +010040#include "rtc_base/strings/string_builder.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020041#include "rtc_base/stringutils.h"
42#include "rtc_base/timeutils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000043
44namespace rtc {
andrew88703d72015-09-07 00:34:56 -070045namespace {
Jonas Olsson2b6f1352018-02-15 11:57:03 +010046// By default, release builds don't log, debug builds at info level
47#if !defined(NDEBUG)
48static LoggingSeverity g_min_sev = LS_INFO;
49static LoggingSeverity g_dbg_sev = LS_INFO;
50#else
51static LoggingSeverity g_min_sev = LS_NONE;
52static LoggingSeverity g_dbg_sev = LS_NONE;
53#endif
andrew88703d72015-09-07 00:34:56 -070054
55// Return the filename portion of the string (that following the last slash).
56const char* FilenameFromPath(const char* file) {
57 const char* end1 = ::strrchr(file, '/');
58 const char* end2 = ::strrchr(file, '\\');
59 if (!end1 && !end2)
60 return file;
61 else
62 return (end1 > end2) ? end1 + 1 : end2 + 1;
63}
64
Jonas Olsson2b6f1352018-02-15 11:57:03 +010065// Global lock for log subsystem, only needed to serialize access to streams_.
66CriticalSection g_log_crit;
andrew88703d72015-09-07 00:34:56 -070067} // namespace
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000068
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +020069// Inefficient default implementation, override is recommended.
70void LogSink::OnLogMessage(const std::string& msg,
71 LoggingSeverity severity,
72 const char* tag) {
73 OnLogMessage(tag + (": " + msg));
74}
75
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000076/////////////////////////////////////////////////////////////////////////////
77// LogMessage
78/////////////////////////////////////////////////////////////////////////////
79
andrew88703d72015-09-07 00:34:56 -070080bool LogMessage::log_to_stderr_ = true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000081
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000082// The list of logging streams currently configured.
83// Note: we explicitly do not clean this up, because of the uncertain ordering
84// of destructors at program exit. Let the person who sets the stream trigger
deadbeef37f5ecf2017-02-27 14:06:41 -080085// cleanup by setting to null, or let it leak (safe at program exit).
danilchap3c6abd22017-09-06 05:46:29 -070086LogMessage::StreamList LogMessage::streams_ RTC_GUARDED_BY(g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000087
88// Boolean options default to false (0)
89bool LogMessage::thread_, LogMessage::timestamp_;
90
Karl Wibergab4f1c12018-05-04 10:42:28 +020091LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
92 : LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
93
Peter Boström225789d2015-10-23 15:20:56 +020094LogMessage::LogMessage(const char* file,
95 int line,
96 LoggingSeverity sev,
97 LogErrorContext err_ctx,
Tommie51a0a82018-02-27 15:30:29 +010098 int err)
Jonas Olssond8c50782018-09-07 11:21:28 +020099 : severity_(sev) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000100 if (timestamp_) {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700101 // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
102 // in log messages represents the real system time.
103 int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000104 // Also ensure WallClockStartTime is initialized, so that it matches
105 // LogStartTime.
106 WallClockStartTime();
Jonas Olssond8c50782018-09-07 11:21:28 +0200107 print_stream_ << "[" << rtc::LeftPad('0', 3, rtc::ToString(time / 1000))
108 << ":" << rtc::LeftPad('0', 3, rtc::ToString(time % 1000))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000109 << "] ";
110 }
111
112 if (thread_) {
henrikaba35d052015-07-14 17:04:08 +0200113 PlatformThreadId id = CurrentThreadId();
Jonas Olssond8c50782018-09-07 11:21:28 +0200114 print_stream_ << "[" << id << "] ";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000115 }
116
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200117 if (file != nullptr) {
118#if defined(WEBRTC_ANDROID)
119 tag_ = FilenameFromPath(file);
120 print_stream_ << "(line " << line << "): ";
121#else
Yves Gerey665174f2018-06-19 15:03:05 +0200122 print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200123#endif
124 }
andrew88703d72015-09-07 00:34:56 -0700125
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000126 if (err_ctx != ERRCTX_NONE) {
Karl Wiberg881f1682018-03-08 15:03:23 +0100127 char tmp_buf[1024];
128 SimpleStringBuilder tmp(tmp_buf);
Tommifef05002018-02-27 13:51:08 +0100129 tmp.AppendFormat("[0x%08X]", err);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000130 switch (err_ctx) {
131 case ERRCTX_ERRNO:
132 tmp << " " << strerror(err);
133 break;
kwiberg77eab702016-09-28 17:42:01 -0700134#ifdef WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000135 case ERRCTX_HRESULT: {
136 char msgbuf[256];
Yves Gerey665174f2018-06-19 15:03:05 +0200137 DWORD flags =
138 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000139 if (DWORD len = FormatMessageA(
Tommie51a0a82018-02-27 15:30:29 +0100140 flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
deadbeef37f5ecf2017-02-27 14:06:41 -0800141 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000142 while ((len > 0) &&
Yves Gerey665174f2018-06-19 15:03:05 +0200143 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000144 msgbuf[--len] = 0;
145 }
146 tmp << " " << msgbuf;
147 }
148 break;
149 }
Tommi0eefb4d2015-05-23 09:54:07 +0200150#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000151#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
152 case ERRCTX_OSSTATUS: {
Tommi09ca02e2016-04-24 17:32:48 +0200153 std::string desc(DescriptionFromOSStatus(err));
154 tmp << " " << (desc.empty() ? "Unknown error" : desc.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000155 break;
156 }
157#endif // WEBRTC_MAC && !defined(WEBRTC_IOS)
158 default:
159 break;
160 }
161 extra_ = tmp.str();
162 }
163}
164
Tommie51a0a82018-02-27 15:30:29 +0100165#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700166LogMessage::LogMessage(const char* file,
167 int line,
168 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100169 const char* tag)
Yves Gerey665174f2018-06-19 15:03:05 +0200170 : LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200171 tag_ = tag;
172 print_stream_ << tag << ": ";
jiayl66f0da22015-09-14 15:06:39 -0700173}
Tommie51a0a82018-02-27 15:30:29 +0100174#endif
175
176// DEPRECATED. Currently only used by downstream projects that use
177// implementation details of logging.h. Work is ongoing to remove those
178// dependencies.
Yves Gerey665174f2018-06-19 15:03:05 +0200179LogMessage::LogMessage(const char* file,
180 int line,
181 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100182 const std::string& tag)
183 : LogMessage(file, line, sev) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200184 print_stream_ << tag << ": ";
Tommie51a0a82018-02-27 15:30:29 +0100185}
jiayl66f0da22015-09-14 15:06:39 -0700186
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000187LogMessage::~LogMessage() {
Tommifef05002018-02-27 13:51:08 +0100188 FinishPrintStream();
189
Jonas Olssond8c50782018-09-07 11:21:28 +0200190 const std::string str = print_stream_.Release();
Tommifef05002018-02-27 13:51:08 +0100191
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100192 if (severity_ >= g_dbg_sev) {
Tommie51a0a82018-02-27 15:30:29 +0100193#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700194 OutputToDebug(str, severity_, tag_);
Tommie51a0a82018-02-27 15:30:29 +0100195#else
196 OutputToDebug(str, severity_);
197#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000198 }
199
Peter Boström225789d2015-10-23 15:20:56 +0200200 CritScope cs(&g_log_crit);
201 for (auto& kv : streams_) {
202 if (severity_ >= kv.second) {
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200203#if defined(WEBRTC_ANDROID)
204 kv.first->OnLogMessage(str, severity_, tag_);
205#else
Peter Boström225789d2015-10-23 15:20:56 +0200206 kv.first->OnLogMessage(str);
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200207#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000208 }
209 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000210}
211
Karl Wibergcefc4652018-05-23 23:20:38 +0200212void LogMessage::AddTag(const char* tag) {
213#ifdef WEBRTC_ANDROID
Jonas Olssond8c50782018-09-07 11:21:28 +0200214 tag_ = tag;
Karl Wibergcefc4652018-05-23 23:20:38 +0200215#endif
216}
217
Jonas Olssond8c50782018-09-07 11:21:28 +0200218rtc::StringBuilder& LogMessage::stream() {
219 return print_stream_;
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100220}
221
222int LogMessage::GetMinLogSeverity() {
223 return g_min_sev;
224}
225
226LoggingSeverity LogMessage::GetLogToDebug() {
227 return g_dbg_sev;
228}
Honghai Zhang82d78622016-05-06 11:29:15 -0700229int64_t LogMessage::LogStartTime() {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700230 static const int64_t g_start = SystemTimeMillis();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000231 return g_start;
232}
233
Peter Boström0c4e06b2015-10-07 12:23:21 +0200234uint32_t LogMessage::WallClockStartTime() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800235 static const uint32_t g_start_wallclock = time(nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000236 return g_start_wallclock;
237}
238
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000239void LogMessage::LogThreads(bool on) {
240 thread_ = on;
241}
242
243void LogMessage::LogTimestamps(bool on) {
244 timestamp_ = on;
245}
246
Tommi0eefb4d2015-05-23 09:54:07 +0200247void LogMessage::LogToDebug(LoggingSeverity min_sev) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100248 g_dbg_sev = min_sev;
Peter Boström225789d2015-10-23 15:20:56 +0200249 CritScope cs(&g_log_crit);
Tommi00aac5a2015-05-25 11:25:59 +0200250 UpdateMinLogSeverity();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000251}
252
andrew88703d72015-09-07 00:34:56 -0700253void LogMessage::SetLogToStderr(bool log_to_stderr) {
254 log_to_stderr_ = log_to_stderr;
255}
256
Tommi0eefb4d2015-05-23 09:54:07 +0200257int LogMessage::GetLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200258 CritScope cs(&g_log_crit);
Tommi0eefb4d2015-05-23 09:54:07 +0200259 LoggingSeverity sev = LS_NONE;
Peter Boström225789d2015-10-23 15:20:56 +0200260 for (auto& kv : streams_) {
261 if (!stream || stream == kv.first) {
262 sev = std::min(sev, kv.second);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000263 }
264 }
265 return sev;
266}
267
Tommi0eefb4d2015-05-23 09:54:07 +0200268void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
Peter Boström225789d2015-10-23 15:20:56 +0200269 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000270 streams_.push_back(std::make_pair(stream, min_sev));
271 UpdateMinLogSeverity();
272}
273
Tommi0eefb4d2015-05-23 09:54:07 +0200274void LogMessage::RemoveLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200275 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000276 for (StreamList::iterator it = streams_.begin(); it != streams_.end(); ++it) {
277 if (stream == it->first) {
278 streams_.erase(it);
279 break;
280 }
281 }
282 UpdateMinLogSeverity();
283}
284
Tommi0eefb4d2015-05-23 09:54:07 +0200285void LogMessage::ConfigureLogging(const char* params) {
286 LoggingSeverity current_level = LS_VERBOSE;
287 LoggingSeverity debug_level = GetLogToDebug();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000288
289 std::vector<std::string> tokens;
290 tokenize(params, ' ', &tokens);
291
Tommi0eefb4d2015-05-23 09:54:07 +0200292 for (const std::string& token : tokens) {
293 if (token.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000294 continue;
295
296 // Logging features
Tommi0eefb4d2015-05-23 09:54:07 +0200297 if (token == "tstamp") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000298 LogTimestamps();
Tommi0eefb4d2015-05-23 09:54:07 +0200299 } else if (token == "thread") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000300 LogThreads();
301
Yves Gerey665174f2018-06-19 15:03:05 +0200302 // Logging levels
Tommi0eefb4d2015-05-23 09:54:07 +0200303 } else if (token == "sensitive") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000304 current_level = LS_SENSITIVE;
Tommi0eefb4d2015-05-23 09:54:07 +0200305 } else if (token == "verbose") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000306 current_level = LS_VERBOSE;
Tommi0eefb4d2015-05-23 09:54:07 +0200307 } else if (token == "info") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000308 current_level = LS_INFO;
Tommi0eefb4d2015-05-23 09:54:07 +0200309 } else if (token == "warning") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000310 current_level = LS_WARNING;
Tommi0eefb4d2015-05-23 09:54:07 +0200311 } else if (token == "error") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000312 current_level = LS_ERROR;
Tommi0eefb4d2015-05-23 09:54:07 +0200313 } else if (token == "none") {
314 current_level = LS_NONE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000315
Yves Gerey665174f2018-06-19 15:03:05 +0200316 // Logging targets
Tommi0eefb4d2015-05-23 09:54:07 +0200317 } else if (token == "debug") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000318 debug_level = current_level;
319 }
320 }
321
322#if defined(WEBRTC_WIN)
Tommi0eefb4d2015-05-23 09:54:07 +0200323 if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000324 // First, attempt to attach to our parent's console... so if you invoke
325 // from the command line, we'll see the output there. Otherwise, create
326 // our own console window.
327 // Note: These methods fail if a console already exists, which is fine.
Tommie51a0a82018-02-27 15:30:29 +0100328 if (!AttachConsole(ATTACH_PARENT_PROCESS))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000329 ::AllocConsole();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000330 }
Tommi0eefb4d2015-05-23 09:54:07 +0200331#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000332
333 LogToDebug(debug_level);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000334}
335
danilchap3c6abd22017-09-06 05:46:29 -0700336void LogMessage::UpdateMinLogSeverity()
337 RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_crit) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100338 LoggingSeverity min_sev = g_dbg_sev;
Karl Wibergd294c852018-06-12 11:31:06 +0200339 for (const auto& kv : streams_) {
340 const LoggingSeverity sev = kv.second;
341 min_sev = std::min(min_sev, sev);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000342 }
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100343 g_min_sev = min_sev;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000344}
345
Tommie51a0a82018-02-27 15:30:29 +0100346#if defined(WEBRTC_ANDROID)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000347void LogMessage::OutputToDebug(const std::string& str,
jiayl66f0da22015-09-14 15:06:39 -0700348 LoggingSeverity severity,
Tommie51a0a82018-02-27 15:30:29 +0100349 const char* tag) {
350#else
351void LogMessage::OutputToDebug(const std::string& str,
352 LoggingSeverity severity) {
353#endif
andrew88703d72015-09-07 00:34:56 -0700354 bool log_to_stderr = log_to_stderr_;
tfarinaa41ab932015-10-30 16:08:48 -0700355#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000356 // On the Mac, all stderr output goes to the Console log and causes clutter.
357 // So in opt builds, don't log to stderr unless the user specifically sets
358 // a preference to do so.
Yves Gerey665174f2018-06-19 15:03:05 +0200359 CFStringRef key = CFStringCreateWithCString(
360 kCFAllocatorDefault, "logToStdErr", kCFStringEncodingUTF8);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000361 CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
deadbeef37f5ecf2017-02-27 14:06:41 -0800362 if (key != nullptr && domain != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000363 Boolean exists_and_is_valid;
364 Boolean should_log =
365 CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
366 // If the key doesn't exist or is invalid or is false, we will not log to
367 // stderr.
368 log_to_stderr = exists_and_is_valid && should_log;
369 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800370 if (key != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000371 CFRelease(key);
372 }
Tommie51a0a82018-02-27 15:30:29 +0100373#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
374
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000375#if defined(WEBRTC_WIN)
376 // Always log to the debugger.
377 // Perhaps stderr should be controlled by a preference, as on Mac?
378 OutputDebugStringA(str.c_str());
379 if (log_to_stderr) {
380 // This handles dynamically allocated consoles, too.
381 if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
382 log_to_stderr = false;
383 DWORD written = 0;
384 ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
385 &written, 0);
386 }
387 }
Tommi0eefb4d2015-05-23 09:54:07 +0200388#endif // WEBRTC_WIN
Tommie51a0a82018-02-27 15:30:29 +0100389
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000390#if defined(WEBRTC_ANDROID)
391 // Android's logging facility uses severity to log messages but we
392 // need to map libjingle's severity levels to Android ones first.
393 // Also write to stderr which maybe available to executable started
394 // from the shell.
395 int prio;
396 switch (severity) {
397 case LS_SENSITIVE:
Tommie51a0a82018-02-27 15:30:29 +0100398 __android_log_write(ANDROID_LOG_INFO, tag, "SENSITIVE");
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000399 if (log_to_stderr) {
400 fprintf(stderr, "SENSITIVE");
401 fflush(stderr);
402 }
403 return;
404 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
420 int size = str.size();
421 int line = 0;
422 int idx = 0;
423 const int max_lines = size / kMaxLogLineSize + 1;
424 if (max_lines == 1) {
Tommie51a0a82018-02-27 15:30:29 +0100425 __android_log_print(prio, tag, "%.*s", size, str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000426 } else {
427 while (size > 0) {
428 const int len = std::min(size, kMaxLogLineSize);
429 // Use the size of the string in the format (str may have \0 in the
430 // middle).
Tommie51a0a82018-02-27 15:30:29 +0100431 __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
432 str.c_str() + idx);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000433 idx += len;
434 size -= len;
435 ++line;
436 }
437 }
438#endif // WEBRTC_ANDROID
439 if (log_to_stderr) {
440 fprintf(stderr, "%s", str.c_str());
441 fflush(stderr);
442 }
443}
444
Tommifef05002018-02-27 13:51:08 +0100445// static
446bool LogMessage::IsNoop(LoggingSeverity severity) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200447 if (severity >= g_dbg_sev || severity >= g_min_sev)
Tommifef05002018-02-27 13:51:08 +0100448 return false;
449
450 // TODO(tommi): We're grabbing this lock for every LogMessage instance that
451 // is going to be logged. This introduces unnecessary synchronization for
452 // a feature that's mostly used for testing.
453 CritScope cs(&g_log_crit);
Jonas Olssond8c50782018-09-07 11:21:28 +0200454 if (streams_.size() > 0)
455 return false;
456
457 return true;
Tommifef05002018-02-27 13:51:08 +0100458}
459
460void LogMessage::FinishPrintStream() {
Tommifef05002018-02-27 13:51:08 +0100461 if (!extra_.empty())
462 print_stream_ << " : " << extra_;
Jonas Olssond8c50782018-09-07 11:21:28 +0200463 print_stream_ << "\n";
Tommifef05002018-02-27 13:51:08 +0100464}
465
Karl Wibergcefc4652018-05-23 23:20:38 +0200466namespace webrtc_logging_impl {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000467
Karl Wibergcefc4652018-05-23 23:20:38 +0200468void Log(const LogArgType* fmt, ...) {
469 va_list args;
470 va_start(args, fmt);
471
472 LogMetadataErr meta;
473 const char* tag = nullptr;
474 switch (*fmt) {
475 case LogArgType::kLogMetadata: {
476 meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
477 break;
478 }
479 case LogArgType::kLogMetadataErr: {
480 meta = va_arg(args, LogMetadataErr);
481 break;
482 }
483#ifdef WEBRTC_ANDROID
484 case LogArgType::kLogMetadataTag: {
485 const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
486 meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
487 tag = tag_meta.tag;
488 break;
489 }
490#endif
491 default: {
492 RTC_NOTREACHED();
493 va_end(args);
494 return;
495 }
496 }
Jonas Olssond8c50782018-09-07 11:21:28 +0200497
498 if (LogMessage::IsNoop(meta.meta.Severity())) {
499 va_end(args);
500 return;
501 }
502
Karl Wibergcefc4652018-05-23 23:20:38 +0200503 LogMessage log_message(meta.meta.File(), meta.meta.Line(),
504 meta.meta.Severity(), meta.err_ctx, meta.err);
505 if (tag) {
506 log_message.AddTag(tag);
507 }
508
509 for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
510 switch (*fmt) {
511 case LogArgType::kInt:
512 log_message.stream() << va_arg(args, int);
513 break;
514 case LogArgType::kLong:
515 log_message.stream() << va_arg(args, long);
516 break;
517 case LogArgType::kLongLong:
518 log_message.stream() << va_arg(args, long long);
519 break;
520 case LogArgType::kUInt:
521 log_message.stream() << va_arg(args, unsigned);
522 break;
523 case LogArgType::kULong:
524 log_message.stream() << va_arg(args, unsigned long);
525 break;
526 case LogArgType::kULongLong:
527 log_message.stream() << va_arg(args, unsigned long long);
528 break;
529 case LogArgType::kDouble:
530 log_message.stream() << va_arg(args, double);
531 break;
532 case LogArgType::kLongDouble:
533 log_message.stream() << va_arg(args, long double);
534 break;
535 case LogArgType::kCharP:
536 log_message.stream() << va_arg(args, const char*);
537 break;
538 case LogArgType::kStdString:
539 log_message.stream() << *va_arg(args, const std::string*);
540 break;
Jonas Olssonf2ce37c2018-09-12 15:32:47 +0200541 case LogArgType::kStringView:
542 log_message.stream() << *va_arg(args, const absl::string_view*);
543 break;
Karl Wibergcefc4652018-05-23 23:20:38 +0200544 case LogArgType::kVoidP:
Jonas Olssond8c50782018-09-07 11:21:28 +0200545 log_message.stream() << rtc::ToHex(
546 reinterpret_cast<uintptr_t>(va_arg(args, const void*)));
Karl Wibergcefc4652018-05-23 23:20:38 +0200547 break;
548 default:
549 RTC_NOTREACHED();
550 va_end(args);
551 return;
552 }
553 }
554
555 va_end(args);
556}
557
558} // namespace webrtc_logging_impl
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000559} // namespace rtc