blob: b143f57dfc8faf5ba46b2ec53a2046c1e865d332 [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"
Tommi12dc1842018-02-26 21:42:37 +010042#include "rtc_base/platform_thread_types.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020043#include "rtc_base/stringencode.h"
44#include "rtc_base/stringutils.h"
45#include "rtc_base/timeutils.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
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000072
73/////////////////////////////////////////////////////////////////////////////
74// LogMessage
75/////////////////////////////////////////////////////////////////////////////
76
andrew88703d72015-09-07 00:34:56 -070077bool LogMessage::log_to_stderr_ = true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000078
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000079// The list of logging streams currently configured.
80// Note: we explicitly do not clean this up, because of the uncertain ordering
81// of destructors at program exit. Let the person who sets the stream trigger
deadbeef37f5ecf2017-02-27 14:06:41 -080082// cleanup by setting to null, or let it leak (safe at program exit).
danilchap3c6abd22017-09-06 05:46:29 -070083LogMessage::StreamList LogMessage::streams_ RTC_GUARDED_BY(g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000084
85// Boolean options default to false (0)
86bool LogMessage::thread_, LogMessage::timestamp_;
87
Peter Boström225789d2015-10-23 15:20:56 +020088LogMessage::LogMessage(const char* file,
89 int line,
90 LoggingSeverity sev,
91 LogErrorContext err_ctx,
Tommi12dc1842018-02-26 21:42:37 +010092 int err)
93 : severity_(sev) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000094 if (timestamp_) {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -070095 // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
96 // in log messages represents the real system time.
97 int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000098 // Also ensure WallClockStartTime is initialized, so that it matches
99 // LogStartTime.
100 WallClockStartTime();
101 print_stream_ << "[" << std::setfill('0') << std::setw(3) << (time / 1000)
102 << ":" << std::setw(3) << (time % 1000) << std::setfill(' ')
103 << "] ";
104 }
105
106 if (thread_) {
henrikaba35d052015-07-14 17:04:08 +0200107 PlatformThreadId id = CurrentThreadId();
108 print_stream_ << "[" << std::dec << id << "] ";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000109 }
110
deadbeef37f5ecf2017-02-27 14:06:41 -0800111 if (file != nullptr)
Alex Glaznevebed24d2015-09-15 11:05:24 -0700112 print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
andrew88703d72015-09-07 00:34:56 -0700113
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000114 if (err_ctx != ERRCTX_NONE) {
115 std::ostringstream tmp;
116 tmp << "[0x" << std::setfill('0') << std::hex << std::setw(8) << err << "]";
117 switch (err_ctx) {
118 case ERRCTX_ERRNO:
119 tmp << " " << strerror(err);
120 break;
kwiberg77eab702016-09-28 17:42:01 -0700121#ifdef WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000122 case ERRCTX_HRESULT: {
123 char msgbuf[256];
Tommi12dc1842018-02-26 21:42:37 +0100124 DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM |
125 FORMAT_MESSAGE_IGNORE_INSERTS;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000126 if (DWORD len = FormatMessageA(
Tommi12dc1842018-02-26 21:42:37 +0100127 flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
deadbeef37f5ecf2017-02-27 14:06:41 -0800128 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000129 while ((len > 0) &&
130 isspace(static_cast<unsigned char>(msgbuf[len-1]))) {
131 msgbuf[--len] = 0;
132 }
133 tmp << " " << msgbuf;
134 }
135 break;
136 }
Tommi0eefb4d2015-05-23 09:54:07 +0200137#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000138#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
139 case ERRCTX_OSSTATUS: {
Tommi09ca02e2016-04-24 17:32:48 +0200140 std::string desc(DescriptionFromOSStatus(err));
141 tmp << " " << (desc.empty() ? "Unknown error" : desc.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000142 break;
143 }
144#endif // WEBRTC_MAC && !defined(WEBRTC_IOS)
145 default:
146 break;
147 }
148 extra_ = tmp.str();
149 }
150}
151
Tommi12dc1842018-02-26 21:42:37 +0100152#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700153LogMessage::LogMessage(const char* file,
154 int line,
155 LoggingSeverity sev,
Tommi12dc1842018-02-26 21:42:37 +0100156 const char* tag)
deadbeef37f5ecf2017-02-27 14:06:41 -0800157 : LogMessage(file,
158 line,
159 sev,
160 ERRCTX_NONE,
Tommi12dc1842018-02-26 21:42:37 +0100161 0 /* err */) {
jiayl66f0da22015-09-14 15:06:39 -0700162 tag_ = tag;
Jiayang Liue4ba6ce92015-09-21 15:49:24 -0700163 print_stream_ << tag << ": ";
jiayl66f0da22015-09-14 15:06:39 -0700164}
Tommi12dc1842018-02-26 21:42:37 +0100165#else
166// DEPRECATED.
167LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev,
168 const std::string& tag)
169 : LogMessage(file, line, sev) {}
170#endif
jiayl66f0da22015-09-14 15:06:39 -0700171
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000172LogMessage::~LogMessage() {
173 if (!extra_.empty())
174 print_stream_ << " : " << extra_;
175 print_stream_ << std::endl;
176
177 const std::string& str = print_stream_.str();
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100178 if (severity_ >= g_dbg_sev) {
Tommi12dc1842018-02-26 21:42:37 +0100179#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700180 OutputToDebug(str, severity_, tag_);
Tommi12dc1842018-02-26 21:42:37 +0100181#else
182 OutputToDebug(str, severity_);
183#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000184 }
185
Peter Boström225789d2015-10-23 15:20:56 +0200186 CritScope cs(&g_log_crit);
187 for (auto& kv : streams_) {
188 if (severity_ >= kv.second) {
189 kv.first->OnLogMessage(str);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000190 }
191 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000192}
193
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100194bool LogMessage::Loggable(LoggingSeverity sev) {
195 return sev >= g_min_sev;
196}
197
198int LogMessage::GetMinLogSeverity() {
199 return g_min_sev;
200}
201
202LoggingSeverity LogMessage::GetLogToDebug() {
203 return g_dbg_sev;
204}
Honghai Zhang82d78622016-05-06 11:29:15 -0700205int64_t LogMessage::LogStartTime() {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700206 static const int64_t g_start = SystemTimeMillis();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000207 return g_start;
208}
209
Peter Boström0c4e06b2015-10-07 12:23:21 +0200210uint32_t LogMessage::WallClockStartTime() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800211 static const uint32_t g_start_wallclock = time(nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000212 return g_start_wallclock;
213}
214
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000215void LogMessage::LogThreads(bool on) {
216 thread_ = on;
217}
218
219void LogMessage::LogTimestamps(bool on) {
220 timestamp_ = on;
221}
222
Tommi0eefb4d2015-05-23 09:54:07 +0200223void LogMessage::LogToDebug(LoggingSeverity min_sev) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100224 g_dbg_sev = min_sev;
Peter Boström225789d2015-10-23 15:20:56 +0200225 CritScope cs(&g_log_crit);
Tommi00aac5a2015-05-25 11:25:59 +0200226 UpdateMinLogSeverity();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000227}
228
andrew88703d72015-09-07 00:34:56 -0700229void LogMessage::SetLogToStderr(bool log_to_stderr) {
230 log_to_stderr_ = log_to_stderr;
231}
232
Tommi0eefb4d2015-05-23 09:54:07 +0200233int LogMessage::GetLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200234 CritScope cs(&g_log_crit);
Tommi0eefb4d2015-05-23 09:54:07 +0200235 LoggingSeverity sev = LS_NONE;
Peter Boström225789d2015-10-23 15:20:56 +0200236 for (auto& kv : streams_) {
237 if (!stream || stream == kv.first) {
238 sev = std::min(sev, kv.second);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000239 }
240 }
241 return sev;
242}
243
Tommi0eefb4d2015-05-23 09:54:07 +0200244void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
Peter Boström225789d2015-10-23 15:20:56 +0200245 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000246 streams_.push_back(std::make_pair(stream, min_sev));
247 UpdateMinLogSeverity();
248}
249
Tommi0eefb4d2015-05-23 09:54:07 +0200250void LogMessage::RemoveLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200251 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000252 for (StreamList::iterator it = streams_.begin(); it != streams_.end(); ++it) {
253 if (stream == it->first) {
254 streams_.erase(it);
255 break;
256 }
257 }
258 UpdateMinLogSeverity();
259}
260
Tommi0eefb4d2015-05-23 09:54:07 +0200261void LogMessage::ConfigureLogging(const char* params) {
262 LoggingSeverity current_level = LS_VERBOSE;
263 LoggingSeverity debug_level = GetLogToDebug();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000264
265 std::vector<std::string> tokens;
266 tokenize(params, ' ', &tokens);
267
Tommi0eefb4d2015-05-23 09:54:07 +0200268 for (const std::string& token : tokens) {
269 if (token.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000270 continue;
271
272 // Logging features
Tommi0eefb4d2015-05-23 09:54:07 +0200273 if (token == "tstamp") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000274 LogTimestamps();
Tommi0eefb4d2015-05-23 09:54:07 +0200275 } else if (token == "thread") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000276 LogThreads();
277
278 // Logging levels
Tommi0eefb4d2015-05-23 09:54:07 +0200279 } else if (token == "sensitive") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000280 current_level = LS_SENSITIVE;
Tommi0eefb4d2015-05-23 09:54:07 +0200281 } else if (token == "verbose") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000282 current_level = LS_VERBOSE;
Tommi0eefb4d2015-05-23 09:54:07 +0200283 } else if (token == "info") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000284 current_level = LS_INFO;
Tommi0eefb4d2015-05-23 09:54:07 +0200285 } else if (token == "warning") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000286 current_level = LS_WARNING;
Tommi0eefb4d2015-05-23 09:54:07 +0200287 } else if (token == "error") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000288 current_level = LS_ERROR;
Tommi0eefb4d2015-05-23 09:54:07 +0200289 } else if (token == "none") {
290 current_level = LS_NONE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000291
292 // Logging targets
Tommi0eefb4d2015-05-23 09:54:07 +0200293 } else if (token == "debug") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000294 debug_level = current_level;
295 }
296 }
297
298#if defined(WEBRTC_WIN)
Tommi0eefb4d2015-05-23 09:54:07 +0200299 if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000300 // First, attempt to attach to our parent's console... so if you invoke
301 // from the command line, we'll see the output there. Otherwise, create
302 // our own console window.
303 // Note: These methods fail if a console already exists, which is fine.
Tommi12dc1842018-02-26 21:42:37 +0100304 if (!AttachConsole(ATTACH_PARENT_PROCESS))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000305 ::AllocConsole();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000306 }
Tommi0eefb4d2015-05-23 09:54:07 +0200307#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000308
309 LogToDebug(debug_level);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000310}
311
danilchap3c6abd22017-09-06 05:46:29 -0700312void LogMessage::UpdateMinLogSeverity()
313 RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_crit) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100314 LoggingSeverity min_sev = g_dbg_sev;
Peter Boström225789d2015-10-23 15:20:56 +0200315 for (auto& kv : streams_) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100316 min_sev = std::min(g_dbg_sev, kv.second);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000317 }
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100318 g_min_sev = min_sev;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000319}
320
Tommi12dc1842018-02-26 21:42:37 +0100321#if defined(WEBRTC_ANDROID)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000322void LogMessage::OutputToDebug(const std::string& str,
jiayl66f0da22015-09-14 15:06:39 -0700323 LoggingSeverity severity,
Tommi12dc1842018-02-26 21:42:37 +0100324 const char* tag) {
325#else
326void LogMessage::OutputToDebug(const std::string& str,
327 LoggingSeverity severity) {
328#endif
andrew88703d72015-09-07 00:34:56 -0700329 bool log_to_stderr = log_to_stderr_;
tfarinaa41ab932015-10-30 16:08:48 -0700330#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000331 // On the Mac, all stderr output goes to the Console log and causes clutter.
332 // So in opt builds, don't log to stderr unless the user specifically sets
333 // a preference to do so.
334 CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault,
335 "logToStdErr",
336 kCFStringEncodingUTF8);
337 CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
deadbeef37f5ecf2017-02-27 14:06:41 -0800338 if (key != nullptr && domain != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000339 Boolean exists_and_is_valid;
340 Boolean should_log =
341 CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
342 // If the key doesn't exist or is invalid or is false, we will not log to
343 // stderr.
344 log_to_stderr = exists_and_is_valid && should_log;
345 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800346 if (key != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000347 CFRelease(key);
348 }
Tommi12dc1842018-02-26 21:42:37 +0100349#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
350
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000351#if defined(WEBRTC_WIN)
352 // Always log to the debugger.
353 // Perhaps stderr should be controlled by a preference, as on Mac?
354 OutputDebugStringA(str.c_str());
355 if (log_to_stderr) {
356 // This handles dynamically allocated consoles, too.
357 if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
358 log_to_stderr = false;
359 DWORD written = 0;
360 ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
361 &written, 0);
362 }
363 }
Tommi0eefb4d2015-05-23 09:54:07 +0200364#endif // WEBRTC_WIN
Tommi12dc1842018-02-26 21:42:37 +0100365
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000366#if defined(WEBRTC_ANDROID)
367 // Android's logging facility uses severity to log messages but we
368 // need to map libjingle's severity levels to Android ones first.
369 // Also write to stderr which maybe available to executable started
370 // from the shell.
371 int prio;
372 switch (severity) {
373 case LS_SENSITIVE:
Tommi12dc1842018-02-26 21:42:37 +0100374 __android_log_write(ANDROID_LOG_INFO, tag, "SENSITIVE");
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000375 if (log_to_stderr) {
376 fprintf(stderr, "SENSITIVE");
377 fflush(stderr);
378 }
379 return;
380 case LS_VERBOSE:
381 prio = ANDROID_LOG_VERBOSE;
382 break;
383 case LS_INFO:
384 prio = ANDROID_LOG_INFO;
385 break;
386 case LS_WARNING:
387 prio = ANDROID_LOG_WARN;
388 break;
389 case LS_ERROR:
390 prio = ANDROID_LOG_ERROR;
391 break;
392 default:
393 prio = ANDROID_LOG_UNKNOWN;
394 }
395
396 int size = str.size();
397 int line = 0;
398 int idx = 0;
399 const int max_lines = size / kMaxLogLineSize + 1;
400 if (max_lines == 1) {
Tommi12dc1842018-02-26 21:42:37 +0100401 __android_log_print(prio, tag, "%.*s", size, str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000402 } else {
403 while (size > 0) {
404 const int len = std::min(size, kMaxLogLineSize);
405 // Use the size of the string in the format (str may have \0 in the
406 // middle).
Tommi12dc1842018-02-26 21:42:37 +0100407 __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
408 str.c_str() + idx);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000409 idx += len;
410 size -= len;
411 ++line;
412 }
413 }
414#endif // WEBRTC_ANDROID
415 if (log_to_stderr) {
416 fprintf(stderr, "%s", str.c_str());
417 fflush(stderr);
418 }
419}
420
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000421//////////////////////////////////////////////////////////////////////
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000422
423} // namespace rtc