blob: 8d6afbcd2be32ece32452c6d8bd42852676b1b75 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:261/*
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:2612#include <windows.h>
conceptgenesis3f705622016-01-30 22:40:4413#if _MSC_VER < 1900
henrike@webrtc.orgf0488722014-05-13 18:00:2614#define snprintf _snprintf
conceptgenesis3f705622016-01-30 22:40:4415#endif
henrike@webrtc.orgf0488722014-05-13 18:00:2616#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 10:03:0123
henrike@webrtc.orgf0488722014-05-13 18:00:2624// 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 10:03:0130#include <stdio.h>
31#include <string.h>
Yves Gerey665174f2018-06-19 13:03:0532#include <time.h>
andresp@webrtc.orgff689be2015-02-12 11:54:2633#include <algorithm>
Karl Wibergcefc4652018-05-23 21:20:3834#include <cstdarg>
henrike@webrtc.orgf0488722014-05-13 18:00:2635#include <vector>
36
Yves Gerey988cc082018-10-23 10:03:0137#include "rtc_base/checks.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3138#include "rtc_base/criticalsection.h"
39#include "rtc_base/logging.h"
Tommie51a0a82018-02-27 14:30:2940#include "rtc_base/platform_thread_types.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3141#include "rtc_base/stringencode.h"
Tommifef05002018-02-27 12:51:0842#include "rtc_base/strings/string_builder.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3143#include "rtc_base/stringutils.h"
Yves Gerey988cc082018-10-23 10:03:0144#include "rtc_base/thread_annotations.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3145#include "rtc_base/timeutils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:2646
47namespace rtc {
andrew88703d72015-09-07 07:34:5648namespace {
Jonas Olsson2b6f1352018-02-15 10:57:0349// 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 07:34:5657
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 10:57:0368// Global lock for log subsystem, only needed to serialize access to streams_.
69CriticalSection g_log_crit;
andrew88703d72015-09-07 07:34:5670} // namespace
henrike@webrtc.orgf0488722014-05-13 18:00:2671
Paulina Hensmanf1e3cb42018-06-20 12:07:0572// Inefficient default implementation, override is recommended.
73void LogSink::OnLogMessage(const std::string& msg,
74 LoggingSeverity severity,
75 const char* tag) {
Jiawei Ou3ea18782018-11-01 06:14:2476 OnLogMessage(tag + (": " + msg), severity);
77}
78
79void LogSink::OnLogMessage(const std::string& msg,
80 LoggingSeverity /* severity */) {
81 OnLogMessage(msg);
Paulina Hensmanf1e3cb42018-06-20 12:07:0582}
83
henrike@webrtc.orgf0488722014-05-13 18:00:2684/////////////////////////////////////////////////////////////////////////////
85// LogMessage
86/////////////////////////////////////////////////////////////////////////////
87
andrew88703d72015-09-07 07:34:5688bool LogMessage::log_to_stderr_ = true;
henrike@webrtc.orgf0488722014-05-13 18:00:2689
henrike@webrtc.orgf0488722014-05-13 18:00:2690// 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 22:06:4193// cleanup by setting to null, or let it leak (safe at program exit).
danilchap3c6abd22017-09-06 12:46:2994LogMessage::StreamList LogMessage::streams_ RTC_GUARDED_BY(g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:2695
96// Boolean options default to false (0)
97bool LogMessage::thread_, LogMessage::timestamp_;
98
Karl Wibergab4f1c12018-05-04 08:42:2899LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
100 : LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
101
Peter Boström225789d2015-10-23 13:20:56102LogMessage::LogMessage(const char* file,
103 int line,
104 LoggingSeverity sev,
105 LogErrorContext err_ctx,
Tommie51a0a82018-02-27 14:30:29106 int err)
Jonas Olssond8c50782018-09-07 09:21:28107 : severity_(sev) {
henrike@webrtc.orgf0488722014-05-13 18:00:26108 if (timestamp_) {
Taylor Brandstetter4f0dfbd2016-06-16 00:15:23109 // 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:26112 // Also ensure WallClockStartTime is initialized, so that it matches
113 // LogStartTime.
114 WallClockStartTime();
Jonas Olssond8c50782018-09-07 09:21:28115 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:26117 << "] ";
118 }
119
120 if (thread_) {
henrikaba35d052015-07-14 15:04:08121 PlatformThreadId id = CurrentThreadId();
Jonas Olssond8c50782018-09-07 09:21:28122 print_stream_ << "[" << id << "] ";
henrike@webrtc.orgf0488722014-05-13 18:00:26123 }
124
Paulina Hensmanf1e3cb42018-06-20 12:07:05125 if (file != nullptr) {
126#if defined(WEBRTC_ANDROID)
127 tag_ = FilenameFromPath(file);
128 print_stream_ << "(line " << line << "): ";
129#else
Yves Gerey665174f2018-06-19 13:03:05130 print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
Paulina Hensmanf1e3cb42018-06-20 12:07:05131#endif
132 }
andrew88703d72015-09-07 07:34:56133
henrike@webrtc.orgf0488722014-05-13 18:00:26134 if (err_ctx != ERRCTX_NONE) {
Karl Wiberg881f1682018-03-08 14:03:23135 char tmp_buf[1024];
136 SimpleStringBuilder tmp(tmp_buf);
Tommifef05002018-02-27 12:51:08137 tmp.AppendFormat("[0x%08X]", err);
henrike@webrtc.orgf0488722014-05-13 18:00:26138 switch (err_ctx) {
139 case ERRCTX_ERRNO:
140 tmp << " " << strerror(err);
141 break;
kwiberg77eab702016-09-29 00:42:01142#ifdef WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26143 case ERRCTX_HRESULT: {
144 char msgbuf[256];
Yves Gerey665174f2018-06-19 13:03:05145 DWORD flags =
146 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
henrike@webrtc.orgf0488722014-05-13 18:00:26147 if (DWORD len = FormatMessageA(
Tommie51a0a82018-02-27 14:30:29148 flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
deadbeef37f5ecf2017-02-27 22:06:41149 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26150 while ((len > 0) &&
Yves Gerey665174f2018-06-19 13:03:05151 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
henrike@webrtc.orgf0488722014-05-13 18:00:26152 msgbuf[--len] = 0;
153 }
154 tmp << " " << msgbuf;
155 }
156 break;
157 }
Tommi0eefb4d2015-05-23 07:54:07158#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26159#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
160 case ERRCTX_OSSTATUS: {
Tommi09ca02e2016-04-24 15:32:48161 std::string desc(DescriptionFromOSStatus(err));
162 tmp << " " << (desc.empty() ? "Unknown error" : desc.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26163 break;
164 }
165#endif // WEBRTC_MAC && !defined(WEBRTC_IOS)
166 default:
167 break;
168 }
169 extra_ = tmp.str();
170 }
171}
172
Tommie51a0a82018-02-27 14:30:29173#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 22:06:39174LogMessage::LogMessage(const char* file,
175 int line,
176 LoggingSeverity sev,
Tommie51a0a82018-02-27 14:30:29177 const char* tag)
Yves Gerey665174f2018-06-19 13:03:05178 : LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */) {
Jonas Olssond8c50782018-09-07 09:21:28179 tag_ = tag;
180 print_stream_ << tag << ": ";
jiayl66f0da22015-09-14 22:06:39181}
Tommie51a0a82018-02-27 14:30:29182#endif
183
184// DEPRECATED. Currently only used by downstream projects that use
185// implementation details of logging.h. Work is ongoing to remove those
186// dependencies.
Yves Gerey665174f2018-06-19 13:03:05187LogMessage::LogMessage(const char* file,
188 int line,
189 LoggingSeverity sev,
Tommie51a0a82018-02-27 14:30:29190 const std::string& tag)
191 : LogMessage(file, line, sev) {
Jonas Olssond8c50782018-09-07 09:21:28192 print_stream_ << tag << ": ";
Tommie51a0a82018-02-27 14:30:29193}
jiayl66f0da22015-09-14 22:06:39194
henrike@webrtc.orgf0488722014-05-13 18:00:26195LogMessage::~LogMessage() {
Tommifef05002018-02-27 12:51:08196 FinishPrintStream();
197
Jonas Olssond8c50782018-09-07 09:21:28198 const std::string str = print_stream_.Release();
Tommifef05002018-02-27 12:51:08199
Jonas Olsson2b6f1352018-02-15 10:57:03200 if (severity_ >= g_dbg_sev) {
Tommie51a0a82018-02-27 14:30:29201#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 22:06:39202 OutputToDebug(str, severity_, tag_);
Tommie51a0a82018-02-27 14:30:29203#else
204 OutputToDebug(str, severity_);
205#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26206 }
207
Peter Boström225789d2015-10-23 13:20:56208 CritScope cs(&g_log_crit);
209 for (auto& kv : streams_) {
210 if (severity_ >= kv.second) {
Paulina Hensmanf1e3cb42018-06-20 12:07:05211#if defined(WEBRTC_ANDROID)
212 kv.first->OnLogMessage(str, severity_, tag_);
213#else
Jiawei Ou3ea18782018-11-01 06:14:24214 kv.first->OnLogMessage(str, severity_);
Paulina Hensmanf1e3cb42018-06-20 12:07:05215#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26216 }
217 }
henrike@webrtc.orgf0488722014-05-13 18:00:26218}
219
Karl Wibergcefc4652018-05-23 21:20:38220void LogMessage::AddTag(const char* tag) {
221#ifdef WEBRTC_ANDROID
Jonas Olssond8c50782018-09-07 09:21:28222 tag_ = tag;
Karl Wibergcefc4652018-05-23 21:20:38223#endif
224}
225
Jonas Olssond8c50782018-09-07 09:21:28226rtc::StringBuilder& LogMessage::stream() {
227 return print_stream_;
Jonas Olsson2b6f1352018-02-15 10:57:03228}
229
230int LogMessage::GetMinLogSeverity() {
231 return g_min_sev;
232}
233
234LoggingSeverity LogMessage::GetLogToDebug() {
235 return g_dbg_sev;
236}
Honghai Zhang82d78622016-05-06 18:29:15237int64_t LogMessage::LogStartTime() {
Taylor Brandstetter4f0dfbd2016-06-16 00:15:23238 static const int64_t g_start = SystemTimeMillis();
henrike@webrtc.orgf0488722014-05-13 18:00:26239 return g_start;
240}
241
Peter Boström0c4e06b2015-10-07 10:23:21242uint32_t LogMessage::WallClockStartTime() {
deadbeef37f5ecf2017-02-27 22:06:41243 static const uint32_t g_start_wallclock = time(nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26244 return g_start_wallclock;
245}
246
henrike@webrtc.orgf0488722014-05-13 18:00:26247void LogMessage::LogThreads(bool on) {
248 thread_ = on;
249}
250
251void LogMessage::LogTimestamps(bool on) {
252 timestamp_ = on;
253}
254
Tommi0eefb4d2015-05-23 07:54:07255void LogMessage::LogToDebug(LoggingSeverity min_sev) {
Jonas Olsson2b6f1352018-02-15 10:57:03256 g_dbg_sev = min_sev;
Peter Boström225789d2015-10-23 13:20:56257 CritScope cs(&g_log_crit);
Tommi00aac5a2015-05-25 09:25:59258 UpdateMinLogSeverity();
henrike@webrtc.orgf0488722014-05-13 18:00:26259}
260
andrew88703d72015-09-07 07:34:56261void LogMessage::SetLogToStderr(bool log_to_stderr) {
262 log_to_stderr_ = log_to_stderr;
263}
264
Tommi0eefb4d2015-05-23 07:54:07265int LogMessage::GetLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 13:20:56266 CritScope cs(&g_log_crit);
Tommi0eefb4d2015-05-23 07:54:07267 LoggingSeverity sev = LS_NONE;
Peter Boström225789d2015-10-23 13:20:56268 for (auto& kv : streams_) {
269 if (!stream || stream == kv.first) {
270 sev = std::min(sev, kv.second);
henrike@webrtc.orgf0488722014-05-13 18:00:26271 }
272 }
273 return sev;
274}
275
Tommi0eefb4d2015-05-23 07:54:07276void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
Peter Boström225789d2015-10-23 13:20:56277 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26278 streams_.push_back(std::make_pair(stream, min_sev));
279 UpdateMinLogSeverity();
280}
281
Tommi0eefb4d2015-05-23 07:54:07282void LogMessage::RemoveLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 13:20:56283 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26284 for (StreamList::iterator it = streams_.begin(); it != streams_.end(); ++it) {
285 if (stream == it->first) {
286 streams_.erase(it);
287 break;
288 }
289 }
290 UpdateMinLogSeverity();
291}
292
Tommi0eefb4d2015-05-23 07:54:07293void LogMessage::ConfigureLogging(const char* params) {
294 LoggingSeverity current_level = LS_VERBOSE;
295 LoggingSeverity debug_level = GetLogToDebug();
henrike@webrtc.orgf0488722014-05-13 18:00:26296
297 std::vector<std::string> tokens;
298 tokenize(params, ' ', &tokens);
299
Tommi0eefb4d2015-05-23 07:54:07300 for (const std::string& token : tokens) {
301 if (token.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26302 continue;
303
304 // Logging features
Tommi0eefb4d2015-05-23 07:54:07305 if (token == "tstamp") {
henrike@webrtc.orgf0488722014-05-13 18:00:26306 LogTimestamps();
Tommi0eefb4d2015-05-23 07:54:07307 } else if (token == "thread") {
henrike@webrtc.orgf0488722014-05-13 18:00:26308 LogThreads();
309
Yves Gerey665174f2018-06-19 13:03:05310 // Logging levels
Tommi0eefb4d2015-05-23 07:54:07311 } else if (token == "sensitive") {
henrike@webrtc.orgf0488722014-05-13 18:00:26312 current_level = LS_SENSITIVE;
Tommi0eefb4d2015-05-23 07:54:07313 } else if (token == "verbose") {
henrike@webrtc.orgf0488722014-05-13 18:00:26314 current_level = LS_VERBOSE;
Tommi0eefb4d2015-05-23 07:54:07315 } else if (token == "info") {
henrike@webrtc.orgf0488722014-05-13 18:00:26316 current_level = LS_INFO;
Tommi0eefb4d2015-05-23 07:54:07317 } else if (token == "warning") {
henrike@webrtc.orgf0488722014-05-13 18:00:26318 current_level = LS_WARNING;
Tommi0eefb4d2015-05-23 07:54:07319 } else if (token == "error") {
henrike@webrtc.orgf0488722014-05-13 18:00:26320 current_level = LS_ERROR;
Tommi0eefb4d2015-05-23 07:54:07321 } else if (token == "none") {
322 current_level = LS_NONE;
henrike@webrtc.orgf0488722014-05-13 18:00:26323
Yves Gerey665174f2018-06-19 13:03:05324 // Logging targets
Tommi0eefb4d2015-05-23 07:54:07325 } else if (token == "debug") {
henrike@webrtc.orgf0488722014-05-13 18:00:26326 debug_level = current_level;
327 }
328 }
329
Robin Raymondce1b1402018-11-23 01:10:11330#if defined(WEBRTC_WIN) && !defined(WINUWP)
Tommi0eefb4d2015-05-23 07:54:07331 if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26332 // First, attempt to attach to our parent's console... so if you invoke
333 // from the command line, we'll see the output there. Otherwise, create
334 // our own console window.
335 // Note: These methods fail if a console already exists, which is fine.
Tommie51a0a82018-02-27 14:30:29336 if (!AttachConsole(ATTACH_PARENT_PROCESS))
henrike@webrtc.orgf0488722014-05-13 18:00:26337 ::AllocConsole();
henrike@webrtc.orgf0488722014-05-13 18:00:26338 }
Robin Raymondce1b1402018-11-23 01:10:11339#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
henrike@webrtc.orgf0488722014-05-13 18:00:26340
341 LogToDebug(debug_level);
henrike@webrtc.orgf0488722014-05-13 18:00:26342}
343
danilchap3c6abd22017-09-06 12:46:29344void LogMessage::UpdateMinLogSeverity()
345 RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_crit) {
Jonas Olsson2b6f1352018-02-15 10:57:03346 LoggingSeverity min_sev = g_dbg_sev;
Karl Wibergd294c852018-06-12 09:31:06347 for (const auto& kv : streams_) {
348 const LoggingSeverity sev = kv.second;
349 min_sev = std::min(min_sev, sev);
henrike@webrtc.orgf0488722014-05-13 18:00:26350 }
Jonas Olsson2b6f1352018-02-15 10:57:03351 g_min_sev = min_sev;
henrike@webrtc.orgf0488722014-05-13 18:00:26352}
353
Tommie51a0a82018-02-27 14:30:29354#if defined(WEBRTC_ANDROID)
henrike@webrtc.orgf0488722014-05-13 18:00:26355void LogMessage::OutputToDebug(const std::string& str,
jiayl66f0da22015-09-14 22:06:39356 LoggingSeverity severity,
Tommie51a0a82018-02-27 14:30:29357 const char* tag) {
358#else
359void LogMessage::OutputToDebug(const std::string& str,
360 LoggingSeverity severity) {
361#endif
andrew88703d72015-09-07 07:34:56362 bool log_to_stderr = log_to_stderr_;
tfarinaa41ab932015-10-30 23:08:48363#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26364 // On the Mac, all stderr output goes to the Console log and causes clutter.
365 // So in opt builds, don't log to stderr unless the user specifically sets
366 // a preference to do so.
Yves Gerey665174f2018-06-19 13:03:05367 CFStringRef key = CFStringCreateWithCString(
368 kCFAllocatorDefault, "logToStdErr", kCFStringEncodingUTF8);
henrike@webrtc.orgf0488722014-05-13 18:00:26369 CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
deadbeef37f5ecf2017-02-27 22:06:41370 if (key != nullptr && domain != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26371 Boolean exists_and_is_valid;
372 Boolean should_log =
373 CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
374 // If the key doesn't exist or is invalid or is false, we will not log to
375 // stderr.
376 log_to_stderr = exists_and_is_valid && should_log;
377 }
deadbeef37f5ecf2017-02-27 22:06:41378 if (key != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26379 CFRelease(key);
380 }
Tommie51a0a82018-02-27 14:30:29381#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
382
henrike@webrtc.orgf0488722014-05-13 18:00:26383#if defined(WEBRTC_WIN)
384 // Always log to the debugger.
385 // Perhaps stderr should be controlled by a preference, as on Mac?
386 OutputDebugStringA(str.c_str());
387 if (log_to_stderr) {
388 // This handles dynamically allocated consoles, too.
389 if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
390 log_to_stderr = false;
391 DWORD written = 0;
392 ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
393 &written, 0);
394 }
395 }
Tommi0eefb4d2015-05-23 07:54:07396#endif // WEBRTC_WIN
Tommie51a0a82018-02-27 14:30:29397
henrike@webrtc.orgf0488722014-05-13 18:00:26398#if defined(WEBRTC_ANDROID)
399 // Android's logging facility uses severity to log messages but we
400 // need to map libjingle's severity levels to Android ones first.
401 // Also write to stderr which maybe available to executable started
402 // from the shell.
403 int prio;
404 switch (severity) {
405 case LS_SENSITIVE:
Tommie51a0a82018-02-27 14:30:29406 __android_log_write(ANDROID_LOG_INFO, tag, "SENSITIVE");
henrike@webrtc.orgf0488722014-05-13 18:00:26407 if (log_to_stderr) {
408 fprintf(stderr, "SENSITIVE");
409 fflush(stderr);
410 }
411 return;
412 case LS_VERBOSE:
413 prio = ANDROID_LOG_VERBOSE;
414 break;
415 case LS_INFO:
416 prio = ANDROID_LOG_INFO;
417 break;
418 case LS_WARNING:
419 prio = ANDROID_LOG_WARN;
420 break;
421 case LS_ERROR:
422 prio = ANDROID_LOG_ERROR;
423 break;
424 default:
425 prio = ANDROID_LOG_UNKNOWN;
426 }
427
428 int size = str.size();
429 int line = 0;
430 int idx = 0;
431 const int max_lines = size / kMaxLogLineSize + 1;
432 if (max_lines == 1) {
Tommie51a0a82018-02-27 14:30:29433 __android_log_print(prio, tag, "%.*s", size, str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26434 } else {
435 while (size > 0) {
436 const int len = std::min(size, kMaxLogLineSize);
437 // Use the size of the string in the format (str may have \0 in the
438 // middle).
Tommie51a0a82018-02-27 14:30:29439 __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
440 str.c_str() + idx);
henrike@webrtc.orgf0488722014-05-13 18:00:26441 idx += len;
442 size -= len;
443 ++line;
444 }
445 }
446#endif // WEBRTC_ANDROID
447 if (log_to_stderr) {
448 fprintf(stderr, "%s", str.c_str());
449 fflush(stderr);
450 }
451}
452
Tommifef05002018-02-27 12:51:08453// static
454bool LogMessage::IsNoop(LoggingSeverity severity) {
Jonas Olssond8c50782018-09-07 09:21:28455 if (severity >= g_dbg_sev || severity >= g_min_sev)
Tommifef05002018-02-27 12:51:08456 return false;
457
458 // TODO(tommi): We're grabbing this lock for every LogMessage instance that
459 // is going to be logged. This introduces unnecessary synchronization for
460 // a feature that's mostly used for testing.
461 CritScope cs(&g_log_crit);
Jonas Olssond8c50782018-09-07 09:21:28462 if (streams_.size() > 0)
463 return false;
464
465 return true;
Tommifef05002018-02-27 12:51:08466}
467
468void LogMessage::FinishPrintStream() {
Tommifef05002018-02-27 12:51:08469 if (!extra_.empty())
470 print_stream_ << " : " << extra_;
Jonas Olssond8c50782018-09-07 09:21:28471 print_stream_ << "\n";
Tommifef05002018-02-27 12:51:08472}
473
Karl Wibergcefc4652018-05-23 21:20:38474namespace webrtc_logging_impl {
henrike@webrtc.orgf0488722014-05-13 18:00:26475
Karl Wibergcefc4652018-05-23 21:20:38476void Log(const LogArgType* fmt, ...) {
477 va_list args;
478 va_start(args, fmt);
479
480 LogMetadataErr meta;
481 const char* tag = nullptr;
482 switch (*fmt) {
483 case LogArgType::kLogMetadata: {
484 meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
485 break;
486 }
487 case LogArgType::kLogMetadataErr: {
488 meta = va_arg(args, LogMetadataErr);
489 break;
490 }
491#ifdef WEBRTC_ANDROID
492 case LogArgType::kLogMetadataTag: {
493 const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
494 meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
495 tag = tag_meta.tag;
496 break;
497 }
498#endif
499 default: {
500 RTC_NOTREACHED();
501 va_end(args);
502 return;
503 }
504 }
Jonas Olssond8c50782018-09-07 09:21:28505
506 if (LogMessage::IsNoop(meta.meta.Severity())) {
507 va_end(args);
508 return;
509 }
510
Karl Wibergcefc4652018-05-23 21:20:38511 LogMessage log_message(meta.meta.File(), meta.meta.Line(),
512 meta.meta.Severity(), meta.err_ctx, meta.err);
513 if (tag) {
514 log_message.AddTag(tag);
515 }
516
517 for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
518 switch (*fmt) {
519 case LogArgType::kInt:
520 log_message.stream() << va_arg(args, int);
521 break;
522 case LogArgType::kLong:
523 log_message.stream() << va_arg(args, long);
524 break;
525 case LogArgType::kLongLong:
526 log_message.stream() << va_arg(args, long long);
527 break;
528 case LogArgType::kUInt:
529 log_message.stream() << va_arg(args, unsigned);
530 break;
531 case LogArgType::kULong:
532 log_message.stream() << va_arg(args, unsigned long);
533 break;
534 case LogArgType::kULongLong:
535 log_message.stream() << va_arg(args, unsigned long long);
536 break;
537 case LogArgType::kDouble:
538 log_message.stream() << va_arg(args, double);
539 break;
540 case LogArgType::kLongDouble:
541 log_message.stream() << va_arg(args, long double);
542 break;
543 case LogArgType::kCharP:
544 log_message.stream() << va_arg(args, const char*);
545 break;
546 case LogArgType::kStdString:
547 log_message.stream() << *va_arg(args, const std::string*);
548 break;
Jonas Olssonf2ce37c2018-09-12 13:32:47549 case LogArgType::kStringView:
550 log_message.stream() << *va_arg(args, const absl::string_view*);
551 break;
Karl Wibergcefc4652018-05-23 21:20:38552 case LogArgType::kVoidP:
Jonas Olssond8c50782018-09-07 09:21:28553 log_message.stream() << rtc::ToHex(
554 reinterpret_cast<uintptr_t>(va_arg(args, const void*)));
Karl Wibergcefc4652018-05-23 21:20:38555 break;
556 default:
557 RTC_NOTREACHED();
558 va_end(args);
559 return;
560 }
561 }
562
563 va_end(args);
564}
565
566} // namespace webrtc_logging_impl
henrike@webrtc.orgf0488722014-05-13 18:00:26567} // namespace rtc