blob: b842b38444f29f88dc219ec52488ec270978335e [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>
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000033#include <algorithm>
Karl Wibergcefc4652018-05-23 23:20:38 +020034#include <cstdarg>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000035#include <vector>
36
Yves Gerey988cc082018-10-23 12:03:01 +020037#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080038#include "rtc_base/critical_section.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020039#include "rtc_base/logging.h"
Tommie51a0a82018-02-27 15:30:29 +010040#include "rtc_base/platform_thread_types.h"
Steve Anton10542f22019-01-11 09:11:00 -080041#include "rtc_base/string_encode.h"
42#include "rtc_base/string_utils.h"
Tommifef05002018-02-27 13:51:08 +010043#include "rtc_base/strings/string_builder.h"
Yves Gerey988cc082018-10-23 12:03:01 +020044#include "rtc_base/thread_annotations.h"
Steve Anton10542f22019-01-11 09:11:00 -080045#include "rtc_base/time_utils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000046
47namespace rtc {
andrew88703d72015-09-07 00:34:56 -070048namespace {
Jonas Olsson2b6f1352018-02-15 11:57:03 +010049// By default, release builds don't log, debug builds at info level
50#if !defined(NDEBUG)
51static LoggingSeverity g_min_sev = LS_INFO;
52static LoggingSeverity g_dbg_sev = LS_INFO;
53#else
54static LoggingSeverity g_min_sev = LS_NONE;
55static LoggingSeverity g_dbg_sev = LS_NONE;
56#endif
andrew88703d72015-09-07 00:34:56 -070057
58// Return the filename portion of the string (that following the last slash).
59const char* FilenameFromPath(const char* file) {
60 const char* end1 = ::strrchr(file, '/');
61 const char* end2 = ::strrchr(file, '\\');
62 if (!end1 && !end2)
63 return file;
64 else
65 return (end1 > end2) ? end1 + 1 : end2 + 1;
66}
67
Jonas Olsson2b6f1352018-02-15 11:57:03 +010068// Global lock for log subsystem, only needed to serialize access to streams_.
69CriticalSection g_log_crit;
andrew88703d72015-09-07 00:34:56 -070070} // namespace
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000071
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +020072// Inefficient default implementation, override is recommended.
73void LogSink::OnLogMessage(const std::string& msg,
74 LoggingSeverity severity,
75 const char* tag) {
Jiawei Ou3ea18782018-10-31 23:14:24 -070076 OnLogMessage(tag + (": " + msg), severity);
77}
78
79void LogSink::OnLogMessage(const std::string& msg,
80 LoggingSeverity /* severity */) {
81 OnLogMessage(msg);
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +020082}
83
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000084/////////////////////////////////////////////////////////////////////////////
85// LogMessage
86/////////////////////////////////////////////////////////////////////////////
87
andrew88703d72015-09-07 00:34:56 -070088bool LogMessage::log_to_stderr_ = true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000089
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000090// The list of logging streams currently configured.
91// Note: we explicitly do not clean this up, because of the uncertain ordering
92// of destructors at program exit. Let the person who sets the stream trigger
deadbeef37f5ecf2017-02-27 14:06:41 -080093// cleanup by setting to null, or let it leak (safe at program exit).
danilchap3c6abd22017-09-06 05:46:29 -070094LogMessage::StreamList LogMessage::streams_ RTC_GUARDED_BY(g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000095
96// Boolean options default to false (0)
97bool LogMessage::thread_, LogMessage::timestamp_;
98
Karl Wibergab4f1c12018-05-04 10:42:28 +020099LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
100 : LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
101
Peter Boström225789d2015-10-23 15:20:56 +0200102LogMessage::LogMessage(const char* file,
103 int line,
104 LoggingSeverity sev,
105 LogErrorContext err_ctx,
Tommie51a0a82018-02-27 15:30:29 +0100106 int err)
Jonas Olssond8c50782018-09-07 11:21:28 +0200107 : severity_(sev) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000108 if (timestamp_) {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700109 // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
110 // in log messages represents the real system time.
111 int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000112 // Also ensure WallClockStartTime is initialized, so that it matches
113 // LogStartTime.
114 WallClockStartTime();
Jonas Olssond8c50782018-09-07 11:21:28 +0200115 print_stream_ << "[" << rtc::LeftPad('0', 3, rtc::ToString(time / 1000))
116 << ":" << rtc::LeftPad('0', 3, rtc::ToString(time % 1000))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000117 << "] ";
118 }
119
120 if (thread_) {
henrikaba35d052015-07-14 17:04:08 +0200121 PlatformThreadId id = CurrentThreadId();
Jonas Olssond8c50782018-09-07 11:21:28 +0200122 print_stream_ << "[" << id << "] ";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000123 }
124
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200125 if (file != nullptr) {
126#if defined(WEBRTC_ANDROID)
127 tag_ = FilenameFromPath(file);
128 print_stream_ << "(line " << line << "): ";
129#else
Yves Gerey665174f2018-06-19 15:03:05 +0200130 print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200131#endif
132 }
andrew88703d72015-09-07 00:34:56 -0700133
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000134 if (err_ctx != ERRCTX_NONE) {
Karl Wiberg881f1682018-03-08 15:03:23 +0100135 char tmp_buf[1024];
136 SimpleStringBuilder tmp(tmp_buf);
Tommifef05002018-02-27 13:51:08 +0100137 tmp.AppendFormat("[0x%08X]", err);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000138 switch (err_ctx) {
139 case ERRCTX_ERRNO:
140 tmp << " " << strerror(err);
141 break;
kwiberg77eab702016-09-28 17:42:01 -0700142#ifdef WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000143 case ERRCTX_HRESULT: {
144 char msgbuf[256];
Yves Gerey665174f2018-06-19 15:03:05 +0200145 DWORD flags =
146 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000147 if (DWORD len = FormatMessageA(
Tommie51a0a82018-02-27 15:30:29 +0100148 flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
deadbeef37f5ecf2017-02-27 14:06:41 -0800149 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000150 while ((len > 0) &&
Yves Gerey665174f2018-06-19 15:03:05 +0200151 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000152 msgbuf[--len] = 0;
153 }
154 tmp << " " << msgbuf;
155 }
156 break;
157 }
Tommi0eefb4d2015-05-23 09:54:07 +0200158#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000159 default:
160 break;
161 }
162 extra_ = tmp.str();
163 }
164}
165
Tommie51a0a82018-02-27 15:30:29 +0100166#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700167LogMessage::LogMessage(const char* file,
168 int line,
169 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100170 const char* tag)
Yves Gerey665174f2018-06-19 15:03:05 +0200171 : LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200172 tag_ = tag;
173 print_stream_ << tag << ": ";
jiayl66f0da22015-09-14 15:06:39 -0700174}
Tommie51a0a82018-02-27 15:30:29 +0100175#endif
176
177// DEPRECATED. Currently only used by downstream projects that use
178// implementation details of logging.h. Work is ongoing to remove those
179// dependencies.
Yves Gerey665174f2018-06-19 15:03:05 +0200180LogMessage::LogMessage(const char* file,
181 int line,
182 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100183 const std::string& tag)
184 : LogMessage(file, line, sev) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200185 print_stream_ << tag << ": ";
Tommie51a0a82018-02-27 15:30:29 +0100186}
jiayl66f0da22015-09-14 15:06:39 -0700187
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000188LogMessage::~LogMessage() {
Tommifef05002018-02-27 13:51:08 +0100189 FinishPrintStream();
190
Jonas Olssond8c50782018-09-07 11:21:28 +0200191 const std::string str = print_stream_.Release();
Tommifef05002018-02-27 13:51:08 +0100192
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100193 if (severity_ >= g_dbg_sev) {
Tommie51a0a82018-02-27 15:30:29 +0100194#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700195 OutputToDebug(str, severity_, tag_);
Tommie51a0a82018-02-27 15:30:29 +0100196#else
197 OutputToDebug(str, severity_);
198#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000199 }
200
Peter Boström225789d2015-10-23 15:20:56 +0200201 CritScope cs(&g_log_crit);
202 for (auto& kv : streams_) {
203 if (severity_ >= kv.second) {
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200204#if defined(WEBRTC_ANDROID)
205 kv.first->OnLogMessage(str, severity_, tag_);
206#else
Jiawei Ou3ea18782018-10-31 23:14:24 -0700207 kv.first->OnLogMessage(str, severity_);
Paulina Hensmanf1e3cb42018-06-20 14:07:05 +0200208#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000209 }
210 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000211}
212
Karl Wibergcefc4652018-05-23 23:20:38 +0200213void LogMessage::AddTag(const char* tag) {
214#ifdef WEBRTC_ANDROID
Jonas Olssond8c50782018-09-07 11:21:28 +0200215 tag_ = tag;
Karl Wibergcefc4652018-05-23 23:20:38 +0200216#endif
217}
218
Jonas Olssond8c50782018-09-07 11:21:28 +0200219rtc::StringBuilder& LogMessage::stream() {
220 return print_stream_;
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100221}
222
223int LogMessage::GetMinLogSeverity() {
224 return g_min_sev;
225}
226
227LoggingSeverity LogMessage::GetLogToDebug() {
228 return g_dbg_sev;
229}
Honghai Zhang82d78622016-05-06 11:29:15 -0700230int64_t LogMessage::LogStartTime() {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700231 static const int64_t g_start = SystemTimeMillis();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000232 return g_start;
233}
234
Peter Boström0c4e06b2015-10-07 12:23:21 +0200235uint32_t LogMessage::WallClockStartTime() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800236 static const uint32_t g_start_wallclock = time(nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000237 return g_start_wallclock;
238}
239
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000240void LogMessage::LogThreads(bool on) {
241 thread_ = on;
242}
243
244void LogMessage::LogTimestamps(bool on) {
245 timestamp_ = on;
246}
247
Tommi0eefb4d2015-05-23 09:54:07 +0200248void LogMessage::LogToDebug(LoggingSeverity min_sev) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100249 g_dbg_sev = min_sev;
Peter Boström225789d2015-10-23 15:20:56 +0200250 CritScope cs(&g_log_crit);
Tommi00aac5a2015-05-25 11:25:59 +0200251 UpdateMinLogSeverity();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000252}
253
andrew88703d72015-09-07 00:34:56 -0700254void LogMessage::SetLogToStderr(bool log_to_stderr) {
255 log_to_stderr_ = log_to_stderr;
256}
257
Tommi0eefb4d2015-05-23 09:54:07 +0200258int LogMessage::GetLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200259 CritScope cs(&g_log_crit);
Tommi0eefb4d2015-05-23 09:54:07 +0200260 LoggingSeverity sev = LS_NONE;
Peter Boström225789d2015-10-23 15:20:56 +0200261 for (auto& kv : streams_) {
262 if (!stream || stream == kv.first) {
263 sev = std::min(sev, kv.second);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000264 }
265 }
266 return sev;
267}
268
Tommi0eefb4d2015-05-23 09:54:07 +0200269void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
Peter Boström225789d2015-10-23 15:20:56 +0200270 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000271 streams_.push_back(std::make_pair(stream, min_sev));
272 UpdateMinLogSeverity();
273}
274
Tommi0eefb4d2015-05-23 09:54:07 +0200275void LogMessage::RemoveLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200276 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000277 for (StreamList::iterator it = streams_.begin(); it != streams_.end(); ++it) {
278 if (stream == it->first) {
279 streams_.erase(it);
280 break;
281 }
282 }
283 UpdateMinLogSeverity();
284}
285
Tommi0eefb4d2015-05-23 09:54:07 +0200286void LogMessage::ConfigureLogging(const char* params) {
287 LoggingSeverity current_level = LS_VERBOSE;
288 LoggingSeverity debug_level = GetLogToDebug();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000289
290 std::vector<std::string> tokens;
291 tokenize(params, ' ', &tokens);
292
Tommi0eefb4d2015-05-23 09:54:07 +0200293 for (const std::string& token : tokens) {
294 if (token.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000295 continue;
296
297 // Logging features
Tommi0eefb4d2015-05-23 09:54:07 +0200298 if (token == "tstamp") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000299 LogTimestamps();
Tommi0eefb4d2015-05-23 09:54:07 +0200300 } else if (token == "thread") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000301 LogThreads();
302
Yves Gerey665174f2018-06-19 15:03:05 +0200303 // Logging levels
Tommi0eefb4d2015-05-23 09:54:07 +0200304 } else if (token == "verbose") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000305 current_level = LS_VERBOSE;
Tommi0eefb4d2015-05-23 09:54:07 +0200306 } else if (token == "info") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000307 current_level = LS_INFO;
Tommi0eefb4d2015-05-23 09:54:07 +0200308 } else if (token == "warning") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000309 current_level = LS_WARNING;
Tommi0eefb4d2015-05-23 09:54:07 +0200310 } else if (token == "error") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000311 current_level = LS_ERROR;
Tommi0eefb4d2015-05-23 09:54:07 +0200312 } else if (token == "none") {
313 current_level = LS_NONE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000314
Yves Gerey665174f2018-06-19 15:03:05 +0200315 // Logging targets
Tommi0eefb4d2015-05-23 09:54:07 +0200316 } else if (token == "debug") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000317 debug_level = current_level;
318 }
319 }
320
Robin Raymondce1b1402018-11-22 20:10:11 -0500321#if defined(WEBRTC_WIN) && !defined(WINUWP)
Tommi0eefb4d2015-05-23 09:54:07 +0200322 if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000323 // First, attempt to attach to our parent's console... so if you invoke
324 // from the command line, we'll see the output there. Otherwise, create
325 // our own console window.
326 // Note: These methods fail if a console already exists, which is fine.
Tommie51a0a82018-02-27 15:30:29 +0100327 if (!AttachConsole(ATTACH_PARENT_PROCESS))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000328 ::AllocConsole();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000329 }
Robin Raymondce1b1402018-11-22 20:10:11 -0500330#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000331
332 LogToDebug(debug_level);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000333}
334
danilchap3c6abd22017-09-06 05:46:29 -0700335void LogMessage::UpdateMinLogSeverity()
336 RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_crit) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100337 LoggingSeverity min_sev = g_dbg_sev;
Karl Wibergd294c852018-06-12 11:31:06 +0200338 for (const auto& kv : streams_) {
339 const LoggingSeverity sev = kv.second;
340 min_sev = std::min(min_sev, sev);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000341 }
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100342 g_min_sev = min_sev;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000343}
344
Tommie51a0a82018-02-27 15:30:29 +0100345#if defined(WEBRTC_ANDROID)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000346void LogMessage::OutputToDebug(const std::string& str,
jiayl66f0da22015-09-14 15:06:39 -0700347 LoggingSeverity severity,
Tommie51a0a82018-02-27 15:30:29 +0100348 const char* tag) {
349#else
350void LogMessage::OutputToDebug(const std::string& str,
351 LoggingSeverity severity) {
352#endif
andrew88703d72015-09-07 00:34:56 -0700353 bool log_to_stderr = log_to_stderr_;
tfarinaa41ab932015-10-30 16:08:48 -0700354#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000355 // On the Mac, all stderr output goes to the Console log and causes clutter.
356 // So in opt builds, don't log to stderr unless the user specifically sets
357 // a preference to do so.
Yves Gerey665174f2018-06-19 15:03:05 +0200358 CFStringRef key = CFStringCreateWithCString(
359 kCFAllocatorDefault, "logToStdErr", kCFStringEncodingUTF8);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000360 CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
deadbeef37f5ecf2017-02-27 14:06:41 -0800361 if (key != nullptr && domain != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000362 Boolean exists_and_is_valid;
363 Boolean should_log =
364 CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
365 // If the key doesn't exist or is invalid or is false, we will not log to
366 // stderr.
367 log_to_stderr = exists_and_is_valid && should_log;
368 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800369 if (key != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000370 CFRelease(key);
371 }
Tommie51a0a82018-02-27 15:30:29 +0100372#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
373
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000374#if defined(WEBRTC_WIN)
375 // Always log to the debugger.
376 // Perhaps stderr should be controlled by a preference, as on Mac?
377 OutputDebugStringA(str.c_str());
378 if (log_to_stderr) {
379 // This handles dynamically allocated consoles, too.
380 if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
381 log_to_stderr = false;
382 DWORD written = 0;
383 ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
384 &written, 0);
385 }
386 }
Tommi0eefb4d2015-05-23 09:54:07 +0200387#endif // WEBRTC_WIN
Tommie51a0a82018-02-27 15:30:29 +0100388
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000389#if defined(WEBRTC_ANDROID)
390 // Android's logging facility uses severity to log messages but we
391 // need to map libjingle's severity levels to Android ones first.
392 // Also write to stderr which maybe available to executable started
393 // from the shell.
394 int prio;
395 switch (severity) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000396 case LS_VERBOSE:
397 prio = ANDROID_LOG_VERBOSE;
398 break;
399 case LS_INFO:
400 prio = ANDROID_LOG_INFO;
401 break;
402 case LS_WARNING:
403 prio = ANDROID_LOG_WARN;
404 break;
405 case LS_ERROR:
406 prio = ANDROID_LOG_ERROR;
407 break;
408 default:
409 prio = ANDROID_LOG_UNKNOWN;
410 }
411
412 int size = str.size();
413 int line = 0;
414 int idx = 0;
415 const int max_lines = size / kMaxLogLineSize + 1;
416 if (max_lines == 1) {
Tommie51a0a82018-02-27 15:30:29 +0100417 __android_log_print(prio, tag, "%.*s", size, str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000418 } else {
419 while (size > 0) {
420 const int len = std::min(size, kMaxLogLineSize);
421 // Use the size of the string in the format (str may have \0 in the
422 // middle).
Tommie51a0a82018-02-27 15:30:29 +0100423 __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
424 str.c_str() + idx);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000425 idx += len;
426 size -= len;
427 ++line;
428 }
429 }
430#endif // WEBRTC_ANDROID
431 if (log_to_stderr) {
432 fprintf(stderr, "%s", str.c_str());
433 fflush(stderr);
434 }
435}
436
Tommifef05002018-02-27 13:51:08 +0100437// static
438bool LogMessage::IsNoop(LoggingSeverity severity) {
Jonas Olssond8c50782018-09-07 11:21:28 +0200439 if (severity >= g_dbg_sev || severity >= g_min_sev)
Tommifef05002018-02-27 13:51:08 +0100440 return false;
441
442 // TODO(tommi): We're grabbing this lock for every LogMessage instance that
443 // is going to be logged. This introduces unnecessary synchronization for
444 // a feature that's mostly used for testing.
445 CritScope cs(&g_log_crit);
Jonas Olssond8c50782018-09-07 11:21:28 +0200446 if (streams_.size() > 0)
447 return false;
448
449 return true;
Tommifef05002018-02-27 13:51:08 +0100450}
451
452void LogMessage::FinishPrintStream() {
Tommifef05002018-02-27 13:51:08 +0100453 if (!extra_.empty())
454 print_stream_ << " : " << extra_;
Jonas Olssond8c50782018-09-07 11:21:28 +0200455 print_stream_ << "\n";
Tommifef05002018-02-27 13:51:08 +0100456}
457
Karl Wibergcefc4652018-05-23 23:20:38 +0200458namespace webrtc_logging_impl {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000459
Karl Wibergcefc4652018-05-23 23:20:38 +0200460void Log(const LogArgType* fmt, ...) {
461 va_list args;
462 va_start(args, fmt);
463
464 LogMetadataErr meta;
465 const char* tag = nullptr;
466 switch (*fmt) {
467 case LogArgType::kLogMetadata: {
468 meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
469 break;
470 }
471 case LogArgType::kLogMetadataErr: {
472 meta = va_arg(args, LogMetadataErr);
473 break;
474 }
475#ifdef WEBRTC_ANDROID
476 case LogArgType::kLogMetadataTag: {
477 const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
478 meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
479 tag = tag_meta.tag;
480 break;
481 }
482#endif
483 default: {
484 RTC_NOTREACHED();
485 va_end(args);
486 return;
487 }
488 }
Jonas Olssond8c50782018-09-07 11:21:28 +0200489
490 if (LogMessage::IsNoop(meta.meta.Severity())) {
491 va_end(args);
492 return;
493 }
494
Karl Wibergcefc4652018-05-23 23:20:38 +0200495 LogMessage log_message(meta.meta.File(), meta.meta.Line(),
496 meta.meta.Severity(), meta.err_ctx, meta.err);
497 if (tag) {
498 log_message.AddTag(tag);
499 }
500
501 for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
502 switch (*fmt) {
503 case LogArgType::kInt:
504 log_message.stream() << va_arg(args, int);
505 break;
506 case LogArgType::kLong:
507 log_message.stream() << va_arg(args, long);
508 break;
509 case LogArgType::kLongLong:
510 log_message.stream() << va_arg(args, long long);
511 break;
512 case LogArgType::kUInt:
513 log_message.stream() << va_arg(args, unsigned);
514 break;
515 case LogArgType::kULong:
516 log_message.stream() << va_arg(args, unsigned long);
517 break;
518 case LogArgType::kULongLong:
519 log_message.stream() << va_arg(args, unsigned long long);
520 break;
521 case LogArgType::kDouble:
522 log_message.stream() << va_arg(args, double);
523 break;
524 case LogArgType::kLongDouble:
525 log_message.stream() << va_arg(args, long double);
526 break;
Niels Möller65835be2019-02-04 19:23:58 +0100527 case LogArgType::kCharP: {
528 const char* s = va_arg(args, const char*);
529 log_message.stream() << (s ? s : "(null)");
Karl Wibergcefc4652018-05-23 23:20:38 +0200530 break;
Niels Möller65835be2019-02-04 19:23:58 +0100531 }
Karl Wibergcefc4652018-05-23 23:20:38 +0200532 case LogArgType::kStdString:
533 log_message.stream() << *va_arg(args, const std::string*);
534 break;
Jonas Olssonf2ce37c2018-09-12 15:32:47 +0200535 case LogArgType::kStringView:
536 log_message.stream() << *va_arg(args, const absl::string_view*);
537 break;
Karl Wibergcefc4652018-05-23 23:20:38 +0200538 case LogArgType::kVoidP:
Jonas Olssond8c50782018-09-07 11:21:28 +0200539 log_message.stream() << rtc::ToHex(
540 reinterpret_cast<uintptr_t>(va_arg(args, const void*)));
Karl Wibergcefc4652018-05-23 23:20:38 +0200541 break;
542 default:
543 RTC_NOTREACHED();
544 va_end(args);
545 return;
546 }
547 }
548
549 va_end(args);
550}
551
552} // namespace webrtc_logging_impl
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000553} // namespace rtc