blob: 8411c21158c43553ca523ca020cab1b3e3a382b2 [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)
Tommi23edcff2015-05-25 10:45:43 +020012#if !defined(WIN32_LEAN_AND_MEAN)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000013#define WIN32_LEAN_AND_MEAN
Tommi23edcff2015-05-25 10:45:43 +020014#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000015#include <windows.h>
conceptgenesis3f705622016-01-30 14:40:44 -080016#if _MSC_VER < 1900
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000017#define snprintf _snprintf
conceptgenesis3f705622016-01-30 14:40:44 -080018#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000019#undef ERROR // wingdi.h
20#endif
21
22#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
23#include <CoreServices/CoreServices.h>
24#elif defined(WEBRTC_ANDROID)
25#include <android/log.h>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000026// Android has a 1024 limit on log inputs. We use 60 chars as an
27// approx for the header/tag portion.
28// See android/system/core/liblog/logd_write.c
29static const int kMaxLogLineSize = 1024 - 60;
30#endif // WEBRTC_MAC && !defined(WEBRTC_IOS) || WEBRTC_ANDROID
31
32#include <time.h>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000033#include <limits.h>
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000034
35#include <algorithm>
36#include <iomanip>
37#include <ostream>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000038#include <vector>
39
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020040#include "rtc_base/criticalsection.h"
41#include "rtc_base/logging.h"
Tommie51a0a82018-02-27 15:30:29 +010042#include "rtc_base/platform_thread_types.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020043#include "rtc_base/stringencode.h"
Tommifef05002018-02-27 13:51:08 +010044#include "rtc_base/strings/string_builder.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020045#include "rtc_base/stringutils.h"
46#include "rtc_base/timeutils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000047
48namespace rtc {
andrew88703d72015-09-07 00:34:56 -070049namespace {
Jonas Olsson2b6f1352018-02-15 11:57:03 +010050// By default, release builds don't log, debug builds at info level
51#if !defined(NDEBUG)
52static LoggingSeverity g_min_sev = LS_INFO;
53static LoggingSeverity g_dbg_sev = LS_INFO;
54#else
55static LoggingSeverity g_min_sev = LS_NONE;
56static LoggingSeverity g_dbg_sev = LS_NONE;
57#endif
andrew88703d72015-09-07 00:34:56 -070058
59// Return the filename portion of the string (that following the last slash).
60const char* FilenameFromPath(const char* file) {
61 const char* end1 = ::strrchr(file, '/');
62 const char* end2 = ::strrchr(file, '\\');
63 if (!end1 && !end2)
64 return file;
65 else
66 return (end1 > end2) ? end1 + 1 : end2 + 1;
67}
68
Tommifef05002018-02-27 13:51:08 +010069std::ostream& GetNoopStream() {
70 class NoopStreamBuf : public std::streambuf {
71 public:
72 int overflow(int c) override { return c; }
73 };
74 static NoopStreamBuf noop_buffer;
75 static std::ostream noop_stream(&noop_buffer);
76 return noop_stream;
77}
78
Jonas Olsson2b6f1352018-02-15 11:57:03 +010079// Global lock for log subsystem, only needed to serialize access to streams_.
80CriticalSection g_log_crit;
andrew88703d72015-09-07 00:34:56 -070081} // namespace
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000082
Paulina Hensman21219a0e2018-05-18 14:32:50 +020083void LogSink::OnLogMessage(const std::string& msg,
84 LoggingSeverity severity,
85 const char* tag) {
86 OnLogMessage(msg);
87}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000088
89/////////////////////////////////////////////////////////////////////////////
90// LogMessage
91/////////////////////////////////////////////////////////////////////////////
92
andrew88703d72015-09-07 00:34:56 -070093bool LogMessage::log_to_stderr_ = true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000094
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000095// The list of logging streams currently configured.
96// Note: we explicitly do not clean this up, because of the uncertain ordering
97// of destructors at program exit. Let the person who sets the stream trigger
deadbeef37f5ecf2017-02-27 14:06:41 -080098// cleanup by setting to null, or let it leak (safe at program exit).
danilchap3c6abd22017-09-06 05:46:29 -070099LogMessage::StreamList LogMessage::streams_ RTC_GUARDED_BY(g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000100
101// Boolean options default to false (0)
102bool LogMessage::thread_, LogMessage::timestamp_;
103
Karl Wibergab4f1c12018-05-04 10:42:28 +0200104LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
105 : LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
106
Peter Boström225789d2015-10-23 15:20:56 +0200107LogMessage::LogMessage(const char* file,
108 int line,
109 LoggingSeverity sev,
110 LogErrorContext err_ctx,
Tommie51a0a82018-02-27 15:30:29 +0100111 int err)
112 : severity_(sev), is_noop_(IsNoop(sev)) {
Tommifef05002018-02-27 13:51:08 +0100113 // If there's no need to do any work, let's not :)
114 if (is_noop_)
115 return;
116
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000117 if (timestamp_) {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700118 // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
119 // in log messages represents the real system time.
120 int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000121 // Also ensure WallClockStartTime is initialized, so that it matches
122 // LogStartTime.
123 WallClockStartTime();
124 print_stream_ << "[" << std::setfill('0') << std::setw(3) << (time / 1000)
125 << ":" << std::setw(3) << (time % 1000) << std::setfill(' ')
126 << "] ";
127 }
128
129 if (thread_) {
henrikaba35d052015-07-14 17:04:08 +0200130 PlatformThreadId id = CurrentThreadId();
131 print_stream_ << "[" << std::dec << id << "] ";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000132 }
133
Paulina Hensman21219a0e2018-05-18 14:32:50 +0200134 if (file != nullptr) {
135#if defined(WEBRTC_ANDROID)
136 tag_ = FilenameFromPath(file);
137 print_stream_ << "(line " << line << "): ";
138#else
Alex Glaznevebed24d2015-09-15 11:05:24 -0700139 print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
Paulina Hensman21219a0e2018-05-18 14:32:50 +0200140#endif
141 }
andrew88703d72015-09-07 00:34:56 -0700142
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000143 if (err_ctx != ERRCTX_NONE) {
Karl Wiberg881f1682018-03-08 15:03:23 +0100144 char tmp_buf[1024];
145 SimpleStringBuilder tmp(tmp_buf);
Tommifef05002018-02-27 13:51:08 +0100146 tmp.AppendFormat("[0x%08X]", err);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000147 switch (err_ctx) {
148 case ERRCTX_ERRNO:
149 tmp << " " << strerror(err);
150 break;
kwiberg77eab702016-09-28 17:42:01 -0700151#ifdef WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000152 case ERRCTX_HRESULT: {
153 char msgbuf[256];
Tommie51a0a82018-02-27 15:30:29 +0100154 DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM |
155 FORMAT_MESSAGE_IGNORE_INSERTS;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000156 if (DWORD len = FormatMessageA(
Tommie51a0a82018-02-27 15:30:29 +0100157 flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
deadbeef37f5ecf2017-02-27 14:06:41 -0800158 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000159 while ((len > 0) &&
160 isspace(static_cast<unsigned char>(msgbuf[len-1]))) {
161 msgbuf[--len] = 0;
162 }
163 tmp << " " << msgbuf;
164 }
165 break;
166 }
Tommi0eefb4d2015-05-23 09:54:07 +0200167#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000168#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
169 case ERRCTX_OSSTATUS: {
Tommi09ca02e2016-04-24 17:32:48 +0200170 std::string desc(DescriptionFromOSStatus(err));
171 tmp << " " << (desc.empty() ? "Unknown error" : desc.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000172 break;
173 }
174#endif // WEBRTC_MAC && !defined(WEBRTC_IOS)
175 default:
176 break;
177 }
178 extra_ = tmp.str();
179 }
180}
181
Tommie51a0a82018-02-27 15:30:29 +0100182#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700183LogMessage::LogMessage(const char* file,
184 int line,
185 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100186 const char* tag)
deadbeef37f5ecf2017-02-27 14:06:41 -0800187 : LogMessage(file,
188 line,
189 sev,
190 ERRCTX_NONE,
Tommie51a0a82018-02-27 15:30:29 +0100191 0 /* err */) {
Tommifef05002018-02-27 13:51:08 +0100192 if (!is_noop_) {
193 tag_ = tag;
Tommifef05002018-02-27 13:51:08 +0100194 }
jiayl66f0da22015-09-14 15:06:39 -0700195}
Tommie51a0a82018-02-27 15:30:29 +0100196#endif
197
198// DEPRECATED. Currently only used by downstream projects that use
199// implementation details of logging.h. Work is ongoing to remove those
200// dependencies.
201LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev,
202 const std::string& tag)
203 : LogMessage(file, line, sev) {
204 if (!is_noop_)
205 print_stream_ << tag << ": ";
206}
jiayl66f0da22015-09-14 15:06:39 -0700207
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000208LogMessage::~LogMessage() {
Tommifef05002018-02-27 13:51:08 +0100209 if (is_noop_)
210 return;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000211
Tommifef05002018-02-27 13:51:08 +0100212 FinishPrintStream();
213
214 // TODO(tommi): Unfortunately |ostringstream::str()| always returns a copy
215 // of the constructed string. This means that we always end up creating
216 // two copies here (one owned by the stream, one by the return value of
217 // |str()|). It would be nice to switch to something else.
218 const std::string str = print_stream_.str();
219
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100220 if (severity_ >= g_dbg_sev) {
Tommie51a0a82018-02-27 15:30:29 +0100221#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700222 OutputToDebug(str, severity_, tag_);
Tommie51a0a82018-02-27 15:30:29 +0100223#else
224 OutputToDebug(str, severity_);
225#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000226 }
227
Peter Boström225789d2015-10-23 15:20:56 +0200228 CritScope cs(&g_log_crit);
229 for (auto& kv : streams_) {
230 if (severity_ >= kv.second) {
Paulina Hensman21219a0e2018-05-18 14:32:50 +0200231#if defined(WEBRTC_ANDROID)
232 kv.first->OnLogMessage(str, severity_, tag_);
233#else
Peter Boström225789d2015-10-23 15:20:56 +0200234 kv.first->OnLogMessage(str);
Paulina Hensman21219a0e2018-05-18 14:32:50 +0200235#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000236 }
237 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000238}
239
Tommifef05002018-02-27 13:51:08 +0100240std::ostream& LogMessage::stream() {
241 return is_noop_ ? GetNoopStream() : print_stream_;
242}
243
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100244bool LogMessage::Loggable(LoggingSeverity sev) {
245 return sev >= g_min_sev;
246}
247
248int LogMessage::GetMinLogSeverity() {
249 return g_min_sev;
250}
251
252LoggingSeverity LogMessage::GetLogToDebug() {
253 return g_dbg_sev;
254}
Honghai Zhang82d78622016-05-06 11:29:15 -0700255int64_t LogMessage::LogStartTime() {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700256 static const int64_t g_start = SystemTimeMillis();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000257 return g_start;
258}
259
Peter Boström0c4e06b2015-10-07 12:23:21 +0200260uint32_t LogMessage::WallClockStartTime() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800261 static const uint32_t g_start_wallclock = time(nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000262 return g_start_wallclock;
263}
264
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000265void LogMessage::LogThreads(bool on) {
266 thread_ = on;
267}
268
269void LogMessage::LogTimestamps(bool on) {
270 timestamp_ = on;
271}
272
Tommi0eefb4d2015-05-23 09:54:07 +0200273void LogMessage::LogToDebug(LoggingSeverity min_sev) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100274 g_dbg_sev = min_sev;
Peter Boström225789d2015-10-23 15:20:56 +0200275 CritScope cs(&g_log_crit);
Tommi00aac5a2015-05-25 11:25:59 +0200276 UpdateMinLogSeverity();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000277}
278
andrew88703d72015-09-07 00:34:56 -0700279void LogMessage::SetLogToStderr(bool log_to_stderr) {
280 log_to_stderr_ = log_to_stderr;
281}
282
Tommi0eefb4d2015-05-23 09:54:07 +0200283int LogMessage::GetLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200284 CritScope cs(&g_log_crit);
Tommi0eefb4d2015-05-23 09:54:07 +0200285 LoggingSeverity sev = LS_NONE;
Peter Boström225789d2015-10-23 15:20:56 +0200286 for (auto& kv : streams_) {
287 if (!stream || stream == kv.first) {
288 sev = std::min(sev, kv.second);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000289 }
290 }
291 return sev;
292}
293
Tommi0eefb4d2015-05-23 09:54:07 +0200294void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
Peter Boström225789d2015-10-23 15:20:56 +0200295 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000296 streams_.push_back(std::make_pair(stream, min_sev));
297 UpdateMinLogSeverity();
298}
299
Tommi0eefb4d2015-05-23 09:54:07 +0200300void LogMessage::RemoveLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200301 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000302 for (StreamList::iterator it = streams_.begin(); it != streams_.end(); ++it) {
303 if (stream == it->first) {
304 streams_.erase(it);
305 break;
306 }
307 }
308 UpdateMinLogSeverity();
309}
310
Tommi0eefb4d2015-05-23 09:54:07 +0200311void LogMessage::ConfigureLogging(const char* params) {
312 LoggingSeverity current_level = LS_VERBOSE;
313 LoggingSeverity debug_level = GetLogToDebug();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000314
315 std::vector<std::string> tokens;
316 tokenize(params, ' ', &tokens);
317
Tommi0eefb4d2015-05-23 09:54:07 +0200318 for (const std::string& token : tokens) {
319 if (token.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000320 continue;
321
322 // Logging features
Tommi0eefb4d2015-05-23 09:54:07 +0200323 if (token == "tstamp") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000324 LogTimestamps();
Tommi0eefb4d2015-05-23 09:54:07 +0200325 } else if (token == "thread") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000326 LogThreads();
327
328 // Logging levels
Tommi0eefb4d2015-05-23 09:54:07 +0200329 } else if (token == "sensitive") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000330 current_level = LS_SENSITIVE;
Tommi0eefb4d2015-05-23 09:54:07 +0200331 } else if (token == "verbose") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000332 current_level = LS_VERBOSE;
Tommi0eefb4d2015-05-23 09:54:07 +0200333 } else if (token == "info") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000334 current_level = LS_INFO;
Tommi0eefb4d2015-05-23 09:54:07 +0200335 } else if (token == "warning") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000336 current_level = LS_WARNING;
Tommi0eefb4d2015-05-23 09:54:07 +0200337 } else if (token == "error") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000338 current_level = LS_ERROR;
Tommi0eefb4d2015-05-23 09:54:07 +0200339 } else if (token == "none") {
340 current_level = LS_NONE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000341
342 // Logging targets
Tommi0eefb4d2015-05-23 09:54:07 +0200343 } else if (token == "debug") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000344 debug_level = current_level;
345 }
346 }
347
348#if defined(WEBRTC_WIN)
Tommi0eefb4d2015-05-23 09:54:07 +0200349 if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000350 // First, attempt to attach to our parent's console... so if you invoke
351 // from the command line, we'll see the output there. Otherwise, create
352 // our own console window.
353 // Note: These methods fail if a console already exists, which is fine.
Tommie51a0a82018-02-27 15:30:29 +0100354 if (!AttachConsole(ATTACH_PARENT_PROCESS))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000355 ::AllocConsole();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000356 }
Tommi0eefb4d2015-05-23 09:54:07 +0200357#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000358
359 LogToDebug(debug_level);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000360}
361
danilchap3c6abd22017-09-06 05:46:29 -0700362void LogMessage::UpdateMinLogSeverity()
363 RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_crit) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100364 LoggingSeverity min_sev = g_dbg_sev;
Peter Boström225789d2015-10-23 15:20:56 +0200365 for (auto& kv : streams_) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100366 min_sev = std::min(g_dbg_sev, kv.second);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000367 }
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100368 g_min_sev = min_sev;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000369}
370
Tommie51a0a82018-02-27 15:30:29 +0100371#if defined(WEBRTC_ANDROID)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000372void LogMessage::OutputToDebug(const std::string& str,
jiayl66f0da22015-09-14 15:06:39 -0700373 LoggingSeverity severity,
Tommie51a0a82018-02-27 15:30:29 +0100374 const char* tag) {
375#else
376void LogMessage::OutputToDebug(const std::string& str,
377 LoggingSeverity severity) {
378#endif
andrew88703d72015-09-07 00:34:56 -0700379 bool log_to_stderr = log_to_stderr_;
tfarinaa41ab932015-10-30 16:08:48 -0700380#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000381 // On the Mac, all stderr output goes to the Console log and causes clutter.
382 // So in opt builds, don't log to stderr unless the user specifically sets
383 // a preference to do so.
384 CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault,
385 "logToStdErr",
386 kCFStringEncodingUTF8);
387 CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
deadbeef37f5ecf2017-02-27 14:06:41 -0800388 if (key != nullptr && domain != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000389 Boolean exists_and_is_valid;
390 Boolean should_log =
391 CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
392 // If the key doesn't exist or is invalid or is false, we will not log to
393 // stderr.
394 log_to_stderr = exists_and_is_valid && should_log;
395 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800396 if (key != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000397 CFRelease(key);
398 }
Tommie51a0a82018-02-27 15:30:29 +0100399#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
400
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000401#if defined(WEBRTC_WIN)
402 // Always log to the debugger.
403 // Perhaps stderr should be controlled by a preference, as on Mac?
404 OutputDebugStringA(str.c_str());
405 if (log_to_stderr) {
406 // This handles dynamically allocated consoles, too.
407 if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
408 log_to_stderr = false;
409 DWORD written = 0;
410 ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
411 &written, 0);
412 }
413 }
Tommi0eefb4d2015-05-23 09:54:07 +0200414#endif // WEBRTC_WIN
Tommie51a0a82018-02-27 15:30:29 +0100415
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000416#if defined(WEBRTC_ANDROID)
417 // Android's logging facility uses severity to log messages but we
418 // need to map libjingle's severity levels to Android ones first.
419 // Also write to stderr which maybe available to executable started
420 // from the shell.
421 int prio;
422 switch (severity) {
423 case LS_SENSITIVE:
Tommie51a0a82018-02-27 15:30:29 +0100424 __android_log_write(ANDROID_LOG_INFO, tag, "SENSITIVE");
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000425 if (log_to_stderr) {
426 fprintf(stderr, "SENSITIVE");
427 fflush(stderr);
428 }
429 return;
430 case LS_VERBOSE:
431 prio = ANDROID_LOG_VERBOSE;
432 break;
433 case LS_INFO:
434 prio = ANDROID_LOG_INFO;
435 break;
436 case LS_WARNING:
437 prio = ANDROID_LOG_WARN;
438 break;
439 case LS_ERROR:
440 prio = ANDROID_LOG_ERROR;
441 break;
442 default:
443 prio = ANDROID_LOG_UNKNOWN;
444 }
445
446 int size = str.size();
447 int line = 0;
448 int idx = 0;
449 const int max_lines = size / kMaxLogLineSize + 1;
450 if (max_lines == 1) {
Tommie51a0a82018-02-27 15:30:29 +0100451 __android_log_print(prio, tag, "%.*s", size, str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000452 } else {
453 while (size > 0) {
454 const int len = std::min(size, kMaxLogLineSize);
455 // Use the size of the string in the format (str may have \0 in the
456 // middle).
Tommie51a0a82018-02-27 15:30:29 +0100457 __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
458 str.c_str() + idx);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000459 idx += len;
460 size -= len;
461 ++line;
462 }
463 }
464#endif // WEBRTC_ANDROID
465 if (log_to_stderr) {
466 fprintf(stderr, "%s", str.c_str());
467 fflush(stderr);
468 }
469}
470
Tommifef05002018-02-27 13:51:08 +0100471// static
472bool LogMessage::IsNoop(LoggingSeverity severity) {
473 if (severity >= g_dbg_sev)
474 return false;
475
476 // TODO(tommi): We're grabbing this lock for every LogMessage instance that
477 // is going to be logged. This introduces unnecessary synchronization for
478 // a feature that's mostly used for testing.
479 CritScope cs(&g_log_crit);
480 return streams_.size() == 0;
481}
482
483void LogMessage::FinishPrintStream() {
484 if (is_noop_)
485 return;
486 if (!extra_.empty())
487 print_stream_ << " : " << extra_;
488 print_stream_ << std::endl;
489}
490
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000491//////////////////////////////////////////////////////////////////////
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000492
493} // namespace rtc