blob: fa84e17896b05811d54ad76fce3a43525bc01591 [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
Zhi Huangd81aac42018-02-27 01:59:01 +000032static const char kLibjingle[] = "libjingle";
33
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000034#include <time.h>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000035#include <limits.h>
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000036
37#include <algorithm>
38#include <iomanip>
39#include <ostream>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000040#include <vector>
41
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020042#include "rtc_base/criticalsection.h"
43#include "rtc_base/logging.h"
Zhi Huangd81aac42018-02-27 01:59:01 +000044#include "rtc_base/platform_thread.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020045#include "rtc_base/stringencode.h"
Tommifef05002018-02-27 13:51:08 +010046#include "rtc_base/strings/string_builder.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020047#include "rtc_base/stringutils.h"
48#include "rtc_base/timeutils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000049
50namespace rtc {
andrew88703d72015-09-07 00:34:56 -070051namespace {
Jonas Olsson2b6f1352018-02-15 11:57:03 +010052// By default, release builds don't log, debug builds at info level
53#if !defined(NDEBUG)
54static LoggingSeverity g_min_sev = LS_INFO;
55static LoggingSeverity g_dbg_sev = LS_INFO;
56#else
57static LoggingSeverity g_min_sev = LS_NONE;
58static LoggingSeverity g_dbg_sev = LS_NONE;
59#endif
andrew88703d72015-09-07 00:34:56 -070060
61// Return the filename portion of the string (that following the last slash).
62const char* FilenameFromPath(const char* file) {
63 const char* end1 = ::strrchr(file, '/');
64 const char* end2 = ::strrchr(file, '\\');
65 if (!end1 && !end2)
66 return file;
67 else
68 return (end1 > end2) ? end1 + 1 : end2 + 1;
69}
70
Tommifef05002018-02-27 13:51:08 +010071std::ostream& GetNoopStream() {
72 class NoopStreamBuf : public std::streambuf {
73 public:
74 int overflow(int c) override { return c; }
75 };
76 static NoopStreamBuf noop_buffer;
77 static std::ostream noop_stream(&noop_buffer);
78 return noop_stream;
79}
80
Jonas Olsson2b6f1352018-02-15 11:57:03 +010081// Global lock for log subsystem, only needed to serialize access to streams_.
82CriticalSection g_log_crit;
andrew88703d72015-09-07 00:34:56 -070083} // namespace
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000084
Zhi Huangd81aac42018-02-27 01:59:01 +000085/////////////////////////////////////////////////////////////////////////////
86// Constant Labels
87/////////////////////////////////////////////////////////////////////////////
88
89const char* FindLabel(int value, const ConstantLabel entries[]) {
90 for (int i = 0; entries[i].label; ++i) {
91 if (value == entries[i].value) {
92 return entries[i].label;
93 }
94 }
95 return 0;
96}
97
98std::string ErrorName(int err, const ConstantLabel* err_table) {
99 if (err == 0)
100 return "No error";
101
102 if (err_table != 0) {
103 if (const char* value = FindLabel(err, err_table))
104 return value;
105 }
106
107 char buffer[16];
108 snprintf(buffer, sizeof(buffer), "0x%08x", err);
109 return buffer;
110}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000111
112/////////////////////////////////////////////////////////////////////////////
113// LogMessage
114/////////////////////////////////////////////////////////////////////////////
115
andrew88703d72015-09-07 00:34:56 -0700116bool LogMessage::log_to_stderr_ = true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000117
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000118// The list of logging streams currently configured.
119// Note: we explicitly do not clean this up, because of the uncertain ordering
120// of destructors at program exit. Let the person who sets the stream trigger
deadbeef37f5ecf2017-02-27 14:06:41 -0800121// cleanup by setting to null, or let it leak (safe at program exit).
danilchap3c6abd22017-09-06 05:46:29 -0700122LogMessage::StreamList LogMessage::streams_ RTC_GUARDED_BY(g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000123
124// Boolean options default to false (0)
125bool LogMessage::thread_, LogMessage::timestamp_;
126
Peter Boström225789d2015-10-23 15:20:56 +0200127LogMessage::LogMessage(const char* file,
128 int line,
129 LoggingSeverity sev,
130 LogErrorContext err_ctx,
Zhi Huangd81aac42018-02-27 01:59:01 +0000131 int err,
132 const char* module)
Tommifef05002018-02-27 13:51:08 +0100133 : severity_(sev), tag_(kLibjingle), is_noop_(IsNoop(sev)) {
134 // If there's no need to do any work, let's not :)
135 if (is_noop_)
136 return;
137
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000138 if (timestamp_) {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700139 // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
140 // in log messages represents the real system time.
141 int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000142 // Also ensure WallClockStartTime is initialized, so that it matches
143 // LogStartTime.
144 WallClockStartTime();
145 print_stream_ << "[" << std::setfill('0') << std::setw(3) << (time / 1000)
146 << ":" << std::setw(3) << (time % 1000) << std::setfill(' ')
147 << "] ";
148 }
149
150 if (thread_) {
henrikaba35d052015-07-14 17:04:08 +0200151 PlatformThreadId id = CurrentThreadId();
152 print_stream_ << "[" << std::dec << id << "] ";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000153 }
154
deadbeef37f5ecf2017-02-27 14:06:41 -0800155 if (file != nullptr)
Alex Glaznevebed24d2015-09-15 11:05:24 -0700156 print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
andrew88703d72015-09-07 00:34:56 -0700157
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000158 if (err_ctx != ERRCTX_NONE) {
Tommifef05002018-02-27 13:51:08 +0100159 SimpleStringBuilder<1024> tmp;
160 tmp.AppendFormat("[0x%08X]", err);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000161 switch (err_ctx) {
162 case ERRCTX_ERRNO:
163 tmp << " " << strerror(err);
164 break;
kwiberg77eab702016-09-28 17:42:01 -0700165#ifdef WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000166 case ERRCTX_HRESULT: {
167 char msgbuf[256];
Zhi Huangd81aac42018-02-27 01:59:01 +0000168 DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM;
169 HMODULE hmod = GetModuleHandleA(module);
170 if (hmod)
171 flags |= FORMAT_MESSAGE_FROM_HMODULE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000172 if (DWORD len = FormatMessageA(
Zhi Huangd81aac42018-02-27 01:59:01 +0000173 flags, hmod, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
deadbeef37f5ecf2017-02-27 14:06:41 -0800174 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000175 while ((len > 0) &&
176 isspace(static_cast<unsigned char>(msgbuf[len-1]))) {
177 msgbuf[--len] = 0;
178 }
179 tmp << " " << msgbuf;
180 }
181 break;
182 }
Tommi0eefb4d2015-05-23 09:54:07 +0200183#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000184#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
185 case ERRCTX_OSSTATUS: {
Tommi09ca02e2016-04-24 17:32:48 +0200186 std::string desc(DescriptionFromOSStatus(err));
187 tmp << " " << (desc.empty() ? "Unknown error" : desc.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000188 break;
189 }
190#endif // WEBRTC_MAC && !defined(WEBRTC_IOS)
191 default:
192 break;
193 }
194 extra_ = tmp.str();
195 }
196}
197
jiayl66f0da22015-09-14 15:06:39 -0700198LogMessage::LogMessage(const char* file,
199 int line,
200 LoggingSeverity sev,
Zhi Huangd81aac42018-02-27 01:59:01 +0000201 const std::string& tag)
deadbeef37f5ecf2017-02-27 14:06:41 -0800202 : LogMessage(file,
203 line,
204 sev,
205 ERRCTX_NONE,
Zhi Huangd81aac42018-02-27 01:59:01 +0000206 0 /* err */,
207 nullptr /* module */) {
Tommifef05002018-02-27 13:51:08 +0100208 if (!is_noop_) {
209 tag_ = tag;
210 print_stream_ << tag << ": ";
211 }
jiayl66f0da22015-09-14 15:06:39 -0700212}
213
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000214LogMessage::~LogMessage() {
Tommifef05002018-02-27 13:51:08 +0100215 if (is_noop_)
216 return;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000217
Tommifef05002018-02-27 13:51:08 +0100218 FinishPrintStream();
219
220 // TODO(tommi): Unfortunately |ostringstream::str()| always returns a copy
221 // of the constructed string. This means that we always end up creating
222 // two copies here (one owned by the stream, one by the return value of
223 // |str()|). It would be nice to switch to something else.
224 const std::string str = print_stream_.str();
225
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100226 if (severity_ >= g_dbg_sev) {
jiayl66f0da22015-09-14 15:06:39 -0700227 OutputToDebug(str, severity_, tag_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000228 }
229
Peter Boström225789d2015-10-23 15:20:56 +0200230 CritScope cs(&g_log_crit);
231 for (auto& kv : streams_) {
232 if (severity_ >= kv.second) {
233 kv.first->OnLogMessage(str);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000234 }
235 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000236}
237
Tommifef05002018-02-27 13:51:08 +0100238std::ostream& LogMessage::stream() {
239 return is_noop_ ? GetNoopStream() : print_stream_;
240}
241
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100242bool LogMessage::Loggable(LoggingSeverity sev) {
243 return sev >= g_min_sev;
244}
245
246int LogMessage::GetMinLogSeverity() {
247 return g_min_sev;
248}
249
250LoggingSeverity LogMessage::GetLogToDebug() {
251 return g_dbg_sev;
252}
Honghai Zhang82d78622016-05-06 11:29:15 -0700253int64_t LogMessage::LogStartTime() {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700254 static const int64_t g_start = SystemTimeMillis();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000255 return g_start;
256}
257
Peter Boström0c4e06b2015-10-07 12:23:21 +0200258uint32_t LogMessage::WallClockStartTime() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800259 static const uint32_t g_start_wallclock = time(nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000260 return g_start_wallclock;
261}
262
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000263void LogMessage::LogThreads(bool on) {
264 thread_ = on;
265}
266
267void LogMessage::LogTimestamps(bool on) {
268 timestamp_ = on;
269}
270
Tommi0eefb4d2015-05-23 09:54:07 +0200271void LogMessage::LogToDebug(LoggingSeverity min_sev) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100272 g_dbg_sev = min_sev;
Peter Boström225789d2015-10-23 15:20:56 +0200273 CritScope cs(&g_log_crit);
Tommi00aac5a2015-05-25 11:25:59 +0200274 UpdateMinLogSeverity();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000275}
276
andrew88703d72015-09-07 00:34:56 -0700277void LogMessage::SetLogToStderr(bool log_to_stderr) {
278 log_to_stderr_ = log_to_stderr;
279}
280
Tommi0eefb4d2015-05-23 09:54:07 +0200281int LogMessage::GetLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200282 CritScope cs(&g_log_crit);
Tommi0eefb4d2015-05-23 09:54:07 +0200283 LoggingSeverity sev = LS_NONE;
Peter Boström225789d2015-10-23 15:20:56 +0200284 for (auto& kv : streams_) {
285 if (!stream || stream == kv.first) {
286 sev = std::min(sev, kv.second);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000287 }
288 }
289 return sev;
290}
291
Tommi0eefb4d2015-05-23 09:54:07 +0200292void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
Peter Boström225789d2015-10-23 15:20:56 +0200293 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000294 streams_.push_back(std::make_pair(stream, min_sev));
295 UpdateMinLogSeverity();
296}
297
Tommi0eefb4d2015-05-23 09:54:07 +0200298void LogMessage::RemoveLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200299 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000300 for (StreamList::iterator it = streams_.begin(); it != streams_.end(); ++it) {
301 if (stream == it->first) {
302 streams_.erase(it);
303 break;
304 }
305 }
306 UpdateMinLogSeverity();
307}
308
Tommi0eefb4d2015-05-23 09:54:07 +0200309void LogMessage::ConfigureLogging(const char* params) {
310 LoggingSeverity current_level = LS_VERBOSE;
311 LoggingSeverity debug_level = GetLogToDebug();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000312
313 std::vector<std::string> tokens;
314 tokenize(params, ' ', &tokens);
315
Tommi0eefb4d2015-05-23 09:54:07 +0200316 for (const std::string& token : tokens) {
317 if (token.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000318 continue;
319
320 // Logging features
Tommi0eefb4d2015-05-23 09:54:07 +0200321 if (token == "tstamp") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000322 LogTimestamps();
Tommi0eefb4d2015-05-23 09:54:07 +0200323 } else if (token == "thread") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000324 LogThreads();
325
326 // Logging levels
Tommi0eefb4d2015-05-23 09:54:07 +0200327 } else if (token == "sensitive") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000328 current_level = LS_SENSITIVE;
Tommi0eefb4d2015-05-23 09:54:07 +0200329 } else if (token == "verbose") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000330 current_level = LS_VERBOSE;
Tommi0eefb4d2015-05-23 09:54:07 +0200331 } else if (token == "info") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000332 current_level = LS_INFO;
Tommi0eefb4d2015-05-23 09:54:07 +0200333 } else if (token == "warning") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000334 current_level = LS_WARNING;
Tommi0eefb4d2015-05-23 09:54:07 +0200335 } else if (token == "error") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000336 current_level = LS_ERROR;
Tommi0eefb4d2015-05-23 09:54:07 +0200337 } else if (token == "none") {
338 current_level = LS_NONE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000339
340 // Logging targets
Tommi0eefb4d2015-05-23 09:54:07 +0200341 } else if (token == "debug") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000342 debug_level = current_level;
343 }
344 }
345
346#if defined(WEBRTC_WIN)
Tommi0eefb4d2015-05-23 09:54:07 +0200347 if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000348 // First, attempt to attach to our parent's console... so if you invoke
349 // from the command line, we'll see the output there. Otherwise, create
350 // our own console window.
351 // Note: These methods fail if a console already exists, which is fine.
Zhi Huangd81aac42018-02-27 01:59:01 +0000352 bool success = false;
353 typedef BOOL (WINAPI* PFN_AttachConsole)(DWORD);
354 if (HINSTANCE kernel32 = ::LoadLibrary(L"kernel32.dll")) {
355 // AttachConsole is defined on WinXP+.
356 if (PFN_AttachConsole attach_console = reinterpret_cast<PFN_AttachConsole>
357 (::GetProcAddress(kernel32, "AttachConsole"))) {
358 success = (FALSE != attach_console(ATTACH_PARENT_PROCESS));
359 }
360 ::FreeLibrary(kernel32);
361 }
362 if (!success) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000363 ::AllocConsole();
Zhi Huangd81aac42018-02-27 01:59:01 +0000364 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000365 }
Tommi0eefb4d2015-05-23 09:54:07 +0200366#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000367
368 LogToDebug(debug_level);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000369}
370
danilchap3c6abd22017-09-06 05:46:29 -0700371void LogMessage::UpdateMinLogSeverity()
372 RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_crit) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100373 LoggingSeverity min_sev = g_dbg_sev;
Peter Boström225789d2015-10-23 15:20:56 +0200374 for (auto& kv : streams_) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100375 min_sev = std::min(g_dbg_sev, kv.second);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000376 }
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100377 g_min_sev = min_sev;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000378}
379
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000380void LogMessage::OutputToDebug(const std::string& str,
jiayl66f0da22015-09-14 15:06:39 -0700381 LoggingSeverity severity,
Zhi Huangd81aac42018-02-27 01:59:01 +0000382 const std::string& tag) {
andrew88703d72015-09-07 00:34:56 -0700383 bool log_to_stderr = log_to_stderr_;
tfarinaa41ab932015-10-30 16:08:48 -0700384#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000385 // On the Mac, all stderr output goes to the Console log and causes clutter.
386 // So in opt builds, don't log to stderr unless the user specifically sets
387 // a preference to do so.
388 CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault,
389 "logToStdErr",
390 kCFStringEncodingUTF8);
391 CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
deadbeef37f5ecf2017-02-27 14:06:41 -0800392 if (key != nullptr && domain != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000393 Boolean exists_and_is_valid;
394 Boolean should_log =
395 CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
396 // If the key doesn't exist or is invalid or is false, we will not log to
397 // stderr.
398 log_to_stderr = exists_and_is_valid && should_log;
399 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800400 if (key != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000401 CFRelease(key);
402 }
Zhi Huangd81aac42018-02-27 01:59:01 +0000403#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000404#if defined(WEBRTC_WIN)
405 // Always log to the debugger.
406 // Perhaps stderr should be controlled by a preference, as on Mac?
407 OutputDebugStringA(str.c_str());
408 if (log_to_stderr) {
409 // This handles dynamically allocated consoles, too.
410 if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
411 log_to_stderr = false;
412 DWORD written = 0;
413 ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
414 &written, 0);
415 }
416 }
Tommi0eefb4d2015-05-23 09:54:07 +0200417#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000418#if defined(WEBRTC_ANDROID)
419 // Android's logging facility uses severity to log messages but we
420 // need to map libjingle's severity levels to Android ones first.
421 // Also write to stderr which maybe available to executable started
422 // from the shell.
423 int prio;
424 switch (severity) {
425 case LS_SENSITIVE:
Zhi Huangd81aac42018-02-27 01:59:01 +0000426 __android_log_write(ANDROID_LOG_INFO, tag.c_str(), "SENSITIVE");
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000427 if (log_to_stderr) {
428 fprintf(stderr, "SENSITIVE");
429 fflush(stderr);
430 }
431 return;
432 case LS_VERBOSE:
433 prio = ANDROID_LOG_VERBOSE;
434 break;
435 case LS_INFO:
436 prio = ANDROID_LOG_INFO;
437 break;
438 case LS_WARNING:
439 prio = ANDROID_LOG_WARN;
440 break;
441 case LS_ERROR:
442 prio = ANDROID_LOG_ERROR;
443 break;
444 default:
445 prio = ANDROID_LOG_UNKNOWN;
446 }
447
448 int size = str.size();
449 int line = 0;
450 int idx = 0;
451 const int max_lines = size / kMaxLogLineSize + 1;
452 if (max_lines == 1) {
Zhi Huangd81aac42018-02-27 01:59:01 +0000453 __android_log_print(prio, tag.c_str(), "%.*s", size, str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000454 } else {
455 while (size > 0) {
456 const int len = std::min(size, kMaxLogLineSize);
457 // Use the size of the string in the format (str may have \0 in the
458 // middle).
Zhi Huangd81aac42018-02-27 01:59:01 +0000459 __android_log_print(prio, tag.c_str(), "[%d/%d] %.*s",
460 line + 1, max_lines,
461 len, str.c_str() + idx);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000462 idx += len;
463 size -= len;
464 ++line;
465 }
466 }
467#endif // WEBRTC_ANDROID
468 if (log_to_stderr) {
469 fprintf(stderr, "%s", str.c_str());
470 fflush(stderr);
471 }
472}
473
Tommifef05002018-02-27 13:51:08 +0100474// static
475bool LogMessage::IsNoop(LoggingSeverity severity) {
476 if (severity >= g_dbg_sev)
477 return false;
478
479 // TODO(tommi): We're grabbing this lock for every LogMessage instance that
480 // is going to be logged. This introduces unnecessary synchronization for
481 // a feature that's mostly used for testing.
482 CritScope cs(&g_log_crit);
483 return streams_.size() == 0;
484}
485
486void LogMessage::FinishPrintStream() {
487 if (is_noop_)
488 return;
489 if (!extra_.empty())
490 print_stream_ << " : " << extra_;
491 print_stream_ << std::endl;
492}
493
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000494//////////////////////////////////////////////////////////////////////
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000495
496} // namespace rtc