blob: ff7369dd5c40dd5b6d84041c8a67636d06eb8932 [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
Artem Titov6a4a1462019-11-26 15:24:4611#include "rtc_base/logging.h"
12
13#include <string.h>
14
15#if RTC_LOG_ENABLED()
16
henrike@webrtc.orgf0488722014-05-13 18:00:2617#if defined(WEBRTC_WIN)
henrike@webrtc.orgf0488722014-05-13 18:00:2618#include <windows.h>
conceptgenesis3f705622016-01-30 22:40:4419#if _MSC_VER < 1900
henrike@webrtc.orgf0488722014-05-13 18:00:2620#define snprintf _snprintf
conceptgenesis3f705622016-01-30 22:40:4421#endif
henrike@webrtc.orgf0488722014-05-13 18:00:2622#undef ERROR // wingdi.h
23#endif
24
25#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
26#include <CoreServices/CoreServices.h>
27#elif defined(WEBRTC_ANDROID)
28#include <android/log.h>
Yves Gerey988cc082018-10-23 10:03:0129
henrike@webrtc.orgf0488722014-05-13 18:00:2630// Android has a 1024 limit on log inputs. We use 60 chars as an
31// approx for the header/tag portion.
32// See android/system/core/liblog/logd_write.c
33static const int kMaxLogLineSize = 1024 - 60;
34#endif // WEBRTC_MAC && !defined(WEBRTC_IOS) || WEBRTC_ANDROID
35
Yves Gerey988cc082018-10-23 10:03:0136#include <stdio.h>
Yves Gerey665174f2018-06-19 13:03:0537#include <time.h>
Jonas Olssona4d87372019-07-05 17:08:3338
andresp@webrtc.orgff689be2015-02-12 11:54:2639#include <algorithm>
Karl Wibergcefc4652018-05-23 21:20:3840#include <cstdarg>
henrike@webrtc.orgf0488722014-05-13 18:00:2641#include <vector>
42
Danil Chapovalovef98ae62019-10-11 15:18:2943#include "absl/base/attributes.h"
Yves Gerey988cc082018-10-23 10:03:0144#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 17:11:0045#include "rtc_base/critical_section.h"
Tommie51a0a82018-02-27 14:30:2946#include "rtc_base/platform_thread_types.h"
Steve Anton10542f22019-01-11 17:11:0047#include "rtc_base/string_encode.h"
48#include "rtc_base/string_utils.h"
Tommifef05002018-02-27 12:51:0849#include "rtc_base/strings/string_builder.h"
Yves Gerey988cc082018-10-23 10:03:0150#include "rtc_base/thread_annotations.h"
Steve Anton10542f22019-01-11 17:11:0051#include "rtc_base/time_utils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:2652
53namespace rtc {
andrew88703d72015-09-07 07:34:5654namespace {
Jonas Olsson2b6f1352018-02-15 10:57:0355// By default, release builds don't log, debug builds at info level
56#if !defined(NDEBUG)
57static LoggingSeverity g_min_sev = LS_INFO;
58static LoggingSeverity g_dbg_sev = LS_INFO;
59#else
60static LoggingSeverity g_min_sev = LS_NONE;
61static LoggingSeverity g_dbg_sev = LS_NONE;
62#endif
andrew88703d72015-09-07 07:34:5663
64// Return the filename portion of the string (that following the last slash).
65const char* FilenameFromPath(const char* file) {
66 const char* end1 = ::strrchr(file, '/');
67 const char* end2 = ::strrchr(file, '\\');
68 if (!end1 && !end2)
69 return file;
70 else
71 return (end1 > end2) ? end1 + 1 : end2 + 1;
72}
73
Jonas Olsson2b6f1352018-02-15 10:57:0374// Global lock for log subsystem, only needed to serialize access to streams_.
Danil Chapovalovec221832019-11-21 09:07:5775CriticalSection g_log_crit;
andrew88703d72015-09-07 07:34:5676} // namespace
henrike@webrtc.orgf0488722014-05-13 18:00:2677
henrike@webrtc.orgf0488722014-05-13 18:00:2678/////////////////////////////////////////////////////////////////////////////
79// LogMessage
80/////////////////////////////////////////////////////////////////////////////
81
andrew88703d72015-09-07 07:34:5682bool LogMessage::log_to_stderr_ = true;
henrike@webrtc.orgf0488722014-05-13 18:00:2683
henrike@webrtc.orgf0488722014-05-13 18:00:2684// The list of logging streams currently configured.
85// Note: we explicitly do not clean this up, because of the uncertain ordering
86// of destructors at program exit. Let the person who sets the stream trigger
deadbeef37f5ecf2017-02-27 22:06:4187// cleanup by setting to null, or let it leak (safe at program exit).
Danil Chapovalovb9f69022019-10-21 07:19:1088ABSL_CONST_INIT LogSink* LogMessage::streams_ RTC_GUARDED_BY(g_log_crit) =
89 nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:2690
91// Boolean options default to false (0)
92bool LogMessage::thread_, LogMessage::timestamp_;
93
Karl Wibergab4f1c12018-05-04 08:42:2894LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
95 : LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
96
Peter Boström225789d2015-10-23 13:20:5697LogMessage::LogMessage(const char* file,
98 int line,
99 LoggingSeverity sev,
100 LogErrorContext err_ctx,
Tommie51a0a82018-02-27 14:30:29101 int err)
Jonas Olssond8c50782018-09-07 09:21:28102 : severity_(sev) {
henrike@webrtc.orgf0488722014-05-13 18:00:26103 if (timestamp_) {
Taylor Brandstetter4f0dfbd2016-06-16 00:15:23104 // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
105 // in log messages represents the real system time.
106 int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime());
henrike@webrtc.orgf0488722014-05-13 18:00:26107 // Also ensure WallClockStartTime is initialized, so that it matches
108 // LogStartTime.
109 WallClockStartTime();
Jonas Olssond8c50782018-09-07 09:21:28110 print_stream_ << "[" << rtc::LeftPad('0', 3, rtc::ToString(time / 1000))
111 << ":" << rtc::LeftPad('0', 3, rtc::ToString(time % 1000))
henrike@webrtc.orgf0488722014-05-13 18:00:26112 << "] ";
113 }
114
115 if (thread_) {
henrikaba35d052015-07-14 15:04:08116 PlatformThreadId id = CurrentThreadId();
Jonas Olssond8c50782018-09-07 09:21:28117 print_stream_ << "[" << id << "] ";
henrike@webrtc.orgf0488722014-05-13 18:00:26118 }
119
Paulina Hensmanf1e3cb42018-06-20 12:07:05120 if (file != nullptr) {
121#if defined(WEBRTC_ANDROID)
122 tag_ = FilenameFromPath(file);
123 print_stream_ << "(line " << line << "): ";
124#else
Yves Gerey665174f2018-06-19 13:03:05125 print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
Paulina Hensmanf1e3cb42018-06-20 12:07:05126#endif
127 }
andrew88703d72015-09-07 07:34:56128
henrike@webrtc.orgf0488722014-05-13 18:00:26129 if (err_ctx != ERRCTX_NONE) {
Karl Wiberg881f1682018-03-08 14:03:23130 char tmp_buf[1024];
131 SimpleStringBuilder tmp(tmp_buf);
Tommifef05002018-02-27 12:51:08132 tmp.AppendFormat("[0x%08X]", err);
henrike@webrtc.orgf0488722014-05-13 18:00:26133 switch (err_ctx) {
134 case ERRCTX_ERRNO:
135 tmp << " " << strerror(err);
136 break;
kwiberg77eab702016-09-29 00:42:01137#ifdef WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26138 case ERRCTX_HRESULT: {
139 char msgbuf[256];
Yves Gerey665174f2018-06-19 13:03:05140 DWORD flags =
141 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
henrike@webrtc.orgf0488722014-05-13 18:00:26142 if (DWORD len = FormatMessageA(
Tommie51a0a82018-02-27 14:30:29143 flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
deadbeef37f5ecf2017-02-27 22:06:41144 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26145 while ((len > 0) &&
Yves Gerey665174f2018-06-19 13:03:05146 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
henrike@webrtc.orgf0488722014-05-13 18:00:26147 msgbuf[--len] = 0;
148 }
149 tmp << " " << msgbuf;
150 }
151 break;
152 }
Tommi0eefb4d2015-05-23 07:54:07153#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26154 default:
155 break;
156 }
157 extra_ = tmp.str();
158 }
159}
160
Tommie51a0a82018-02-27 14:30:29161#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 22:06:39162LogMessage::LogMessage(const char* file,
163 int line,
164 LoggingSeverity sev,
Tommie51a0a82018-02-27 14:30:29165 const char* tag)
Yves Gerey665174f2018-06-19 13:03:05166 : LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */) {
Jonas Olssond8c50782018-09-07 09:21:28167 tag_ = tag;
168 print_stream_ << tag << ": ";
jiayl66f0da22015-09-14 22:06:39169}
Tommie51a0a82018-02-27 14:30:29170#endif
171
172// DEPRECATED. Currently only used by downstream projects that use
173// implementation details of logging.h. Work is ongoing to remove those
174// dependencies.
Yves Gerey665174f2018-06-19 13:03:05175LogMessage::LogMessage(const char* file,
176 int line,
177 LoggingSeverity sev,
Tommie51a0a82018-02-27 14:30:29178 const std::string& tag)
179 : LogMessage(file, line, sev) {
Jonas Olssond8c50782018-09-07 09:21:28180 print_stream_ << tag << ": ";
Tommie51a0a82018-02-27 14:30:29181}
jiayl66f0da22015-09-14 22:06:39182
henrike@webrtc.orgf0488722014-05-13 18:00:26183LogMessage::~LogMessage() {
Tommifef05002018-02-27 12:51:08184 FinishPrintStream();
185
Jonas Olssond8c50782018-09-07 09:21:28186 const std::string str = print_stream_.Release();
Tommifef05002018-02-27 12:51:08187
Jonas Olsson2b6f1352018-02-15 10:57:03188 if (severity_ >= g_dbg_sev) {
Tommie51a0a82018-02-27 14:30:29189#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 22:06:39190 OutputToDebug(str, severity_, tag_);
Tommie51a0a82018-02-27 14:30:29191#else
192 OutputToDebug(str, severity_);
193#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26194 }
195
Danil Chapovalovec221832019-11-21 09:07:57196 CritScope cs(&g_log_crit);
Danil Chapovalovb9f69022019-10-21 07:19:10197 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
198 if (severity_ >= entry->min_severity_) {
Paulina Hensmanf1e3cb42018-06-20 12:07:05199#if defined(WEBRTC_ANDROID)
Danil Chapovalovb9f69022019-10-21 07:19:10200 entry->OnLogMessage(str, severity_, tag_);
Paulina Hensmanf1e3cb42018-06-20 12:07:05201#else
Danil Chapovalovb9f69022019-10-21 07:19:10202 entry->OnLogMessage(str, severity_);
Paulina Hensmanf1e3cb42018-06-20 12:07:05203#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26204 }
205 }
henrike@webrtc.orgf0488722014-05-13 18:00:26206}
207
Karl Wibergcefc4652018-05-23 21:20:38208void LogMessage::AddTag(const char* tag) {
209#ifdef WEBRTC_ANDROID
Jonas Olssond8c50782018-09-07 09:21:28210 tag_ = tag;
Karl Wibergcefc4652018-05-23 21:20:38211#endif
212}
213
Jonas Olssond8c50782018-09-07 09:21:28214rtc::StringBuilder& LogMessage::stream() {
215 return print_stream_;
Jonas Olsson2b6f1352018-02-15 10:57:03216}
217
218int LogMessage::GetMinLogSeverity() {
219 return g_min_sev;
220}
221
222LoggingSeverity LogMessage::GetLogToDebug() {
223 return g_dbg_sev;
224}
Honghai Zhang82d78622016-05-06 18:29:15225int64_t LogMessage::LogStartTime() {
Taylor Brandstetter4f0dfbd2016-06-16 00:15:23226 static const int64_t g_start = SystemTimeMillis();
henrike@webrtc.orgf0488722014-05-13 18:00:26227 return g_start;
228}
229
Peter Boström0c4e06b2015-10-07 10:23:21230uint32_t LogMessage::WallClockStartTime() {
deadbeef37f5ecf2017-02-27 22:06:41231 static const uint32_t g_start_wallclock = time(nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26232 return g_start_wallclock;
233}
234
henrike@webrtc.orgf0488722014-05-13 18:00:26235void LogMessage::LogThreads(bool on) {
236 thread_ = on;
237}
238
239void LogMessage::LogTimestamps(bool on) {
240 timestamp_ = on;
241}
242
Tommi0eefb4d2015-05-23 07:54:07243void LogMessage::LogToDebug(LoggingSeverity min_sev) {
Jonas Olsson2b6f1352018-02-15 10:57:03244 g_dbg_sev = min_sev;
Danil Chapovalovec221832019-11-21 09:07:57245 CritScope cs(&g_log_crit);
Tommi00aac5a2015-05-25 09:25:59246 UpdateMinLogSeverity();
henrike@webrtc.orgf0488722014-05-13 18:00:26247}
248
andrew88703d72015-09-07 07:34:56249void LogMessage::SetLogToStderr(bool log_to_stderr) {
250 log_to_stderr_ = log_to_stderr;
251}
252
Tommi0eefb4d2015-05-23 07:54:07253int LogMessage::GetLogToStream(LogSink* stream) {
Danil Chapovalovec221832019-11-21 09:07:57254 CritScope cs(&g_log_crit);
Tommi0eefb4d2015-05-23 07:54:07255 LoggingSeverity sev = LS_NONE;
Danil Chapovalovb9f69022019-10-21 07:19:10256 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
257 if (stream == nullptr || stream == entry) {
258 sev = std::min(sev, entry->min_severity_);
henrike@webrtc.orgf0488722014-05-13 18:00:26259 }
260 }
261 return sev;
262}
263
Tommi0eefb4d2015-05-23 07:54:07264void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
Danil Chapovalovec221832019-11-21 09:07:57265 CritScope cs(&g_log_crit);
Danil Chapovalovb9f69022019-10-21 07:19:10266 stream->min_severity_ = min_sev;
267 stream->next_ = streams_;
268 streams_ = stream;
henrike@webrtc.orgf0488722014-05-13 18:00:26269 UpdateMinLogSeverity();
270}
271
Tommi0eefb4d2015-05-23 07:54:07272void LogMessage::RemoveLogToStream(LogSink* stream) {
Danil Chapovalovec221832019-11-21 09:07:57273 CritScope cs(&g_log_crit);
Danil Chapovalovb9f69022019-10-21 07:19:10274 for (LogSink** entry = &streams_; *entry != nullptr;
275 entry = &(*entry)->next_) {
276 if (*entry == stream) {
277 *entry = (*entry)->next_;
henrike@webrtc.orgf0488722014-05-13 18:00:26278 break;
279 }
280 }
281 UpdateMinLogSeverity();
282}
283
Tommi0eefb4d2015-05-23 07:54:07284void LogMessage::ConfigureLogging(const char* params) {
285 LoggingSeverity current_level = LS_VERBOSE;
286 LoggingSeverity debug_level = GetLogToDebug();
henrike@webrtc.orgf0488722014-05-13 18:00:26287
288 std::vector<std::string> tokens;
289 tokenize(params, ' ', &tokens);
290
Tommi0eefb4d2015-05-23 07:54:07291 for (const std::string& token : tokens) {
292 if (token.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26293 continue;
294
295 // Logging features
Tommi0eefb4d2015-05-23 07:54:07296 if (token == "tstamp") {
henrike@webrtc.orgf0488722014-05-13 18:00:26297 LogTimestamps();
Tommi0eefb4d2015-05-23 07:54:07298 } else if (token == "thread") {
henrike@webrtc.orgf0488722014-05-13 18:00:26299 LogThreads();
300
Yves Gerey665174f2018-06-19 13:03:05301 // Logging levels
Tommi0eefb4d2015-05-23 07:54:07302 } else if (token == "verbose") {
henrike@webrtc.orgf0488722014-05-13 18:00:26303 current_level = LS_VERBOSE;
Tommi0eefb4d2015-05-23 07:54:07304 } else if (token == "info") {
henrike@webrtc.orgf0488722014-05-13 18:00:26305 current_level = LS_INFO;
Tommi0eefb4d2015-05-23 07:54:07306 } else if (token == "warning") {
henrike@webrtc.orgf0488722014-05-13 18:00:26307 current_level = LS_WARNING;
Tommi0eefb4d2015-05-23 07:54:07308 } else if (token == "error") {
henrike@webrtc.orgf0488722014-05-13 18:00:26309 current_level = LS_ERROR;
Tommi0eefb4d2015-05-23 07:54:07310 } else if (token == "none") {
311 current_level = LS_NONE;
henrike@webrtc.orgf0488722014-05-13 18:00:26312
Yves Gerey665174f2018-06-19 13:03:05313 // Logging targets
Tommi0eefb4d2015-05-23 07:54:07314 } else if (token == "debug") {
henrike@webrtc.orgf0488722014-05-13 18:00:26315 debug_level = current_level;
316 }
317 }
318
Robin Raymondce1b1402018-11-23 01:10:11319#if defined(WEBRTC_WIN) && !defined(WINUWP)
Tommi0eefb4d2015-05-23 07:54:07320 if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26321 // First, attempt to attach to our parent's console... so if you invoke
322 // from the command line, we'll see the output there. Otherwise, create
323 // our own console window.
324 // Note: These methods fail if a console already exists, which is fine.
Tommie51a0a82018-02-27 14:30:29325 if (!AttachConsole(ATTACH_PARENT_PROCESS))
henrike@webrtc.orgf0488722014-05-13 18:00:26326 ::AllocConsole();
henrike@webrtc.orgf0488722014-05-13 18:00:26327 }
Robin Raymondce1b1402018-11-23 01:10:11328#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
henrike@webrtc.orgf0488722014-05-13 18:00:26329
330 LogToDebug(debug_level);
henrike@webrtc.orgf0488722014-05-13 18:00:26331}
332
danilchap3c6abd22017-09-06 12:46:29333void LogMessage::UpdateMinLogSeverity()
334 RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_crit) {
Jonas Olsson2b6f1352018-02-15 10:57:03335 LoggingSeverity min_sev = g_dbg_sev;
Danil Chapovalovb9f69022019-10-21 07:19:10336 for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
337 min_sev = std::min(min_sev, entry->min_severity_);
henrike@webrtc.orgf0488722014-05-13 18:00:26338 }
Jonas Olsson2b6f1352018-02-15 10:57:03339 g_min_sev = min_sev;
henrike@webrtc.orgf0488722014-05-13 18:00:26340}
341
Tommie51a0a82018-02-27 14:30:29342#if defined(WEBRTC_ANDROID)
henrike@webrtc.orgf0488722014-05-13 18:00:26343void LogMessage::OutputToDebug(const std::string& str,
jiayl66f0da22015-09-14 22:06:39344 LoggingSeverity severity,
Tommie51a0a82018-02-27 14:30:29345 const char* tag) {
346#else
347void LogMessage::OutputToDebug(const std::string& str,
348 LoggingSeverity severity) {
349#endif
andrew88703d72015-09-07 07:34:56350 bool log_to_stderr = log_to_stderr_;
tfarinaa41ab932015-10-30 23:08:48351#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26352 // On the Mac, all stderr output goes to the Console log and causes clutter.
353 // So in opt builds, don't log to stderr unless the user specifically sets
354 // a preference to do so.
Yves Gerey665174f2018-06-19 13:03:05355 CFStringRef key = CFStringCreateWithCString(
356 kCFAllocatorDefault, "logToStdErr", kCFStringEncodingUTF8);
henrike@webrtc.orgf0488722014-05-13 18:00:26357 CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
deadbeef37f5ecf2017-02-27 22:06:41358 if (key != nullptr && domain != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26359 Boolean exists_and_is_valid;
360 Boolean should_log =
361 CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
362 // If the key doesn't exist or is invalid or is false, we will not log to
363 // stderr.
364 log_to_stderr = exists_and_is_valid && should_log;
365 }
deadbeef37f5ecf2017-02-27 22:06:41366 if (key != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26367 CFRelease(key);
368 }
Tommie51a0a82018-02-27 14:30:29369#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
370
henrike@webrtc.orgf0488722014-05-13 18:00:26371#if defined(WEBRTC_WIN)
372 // Always log to the debugger.
373 // Perhaps stderr should be controlled by a preference, as on Mac?
374 OutputDebugStringA(str.c_str());
375 if (log_to_stderr) {
376 // This handles dynamically allocated consoles, too.
377 if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
378 log_to_stderr = false;
379 DWORD written = 0;
380 ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
381 &written, 0);
382 }
383 }
Tommi0eefb4d2015-05-23 07:54:07384#endif // WEBRTC_WIN
Tommie51a0a82018-02-27 14:30:29385
henrike@webrtc.orgf0488722014-05-13 18:00:26386#if defined(WEBRTC_ANDROID)
387 // Android's logging facility uses severity to log messages but we
388 // need to map libjingle's severity levels to Android ones first.
389 // Also write to stderr which maybe available to executable started
390 // from the shell.
391 int prio;
392 switch (severity) {
henrike@webrtc.orgf0488722014-05-13 18:00:26393 case LS_VERBOSE:
394 prio = ANDROID_LOG_VERBOSE;
395 break;
396 case LS_INFO:
397 prio = ANDROID_LOG_INFO;
398 break;
399 case LS_WARNING:
400 prio = ANDROID_LOG_WARN;
401 break;
402 case LS_ERROR:
403 prio = ANDROID_LOG_ERROR;
404 break;
405 default:
406 prio = ANDROID_LOG_UNKNOWN;
407 }
408
409 int size = str.size();
410 int line = 0;
411 int idx = 0;
412 const int max_lines = size / kMaxLogLineSize + 1;
413 if (max_lines == 1) {
Tommie51a0a82018-02-27 14:30:29414 __android_log_print(prio, tag, "%.*s", size, str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26415 } else {
416 while (size > 0) {
417 const int len = std::min(size, kMaxLogLineSize);
418 // Use the size of the string in the format (str may have \0 in the
419 // middle).
Tommie51a0a82018-02-27 14:30:29420 __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
421 str.c_str() + idx);
henrike@webrtc.orgf0488722014-05-13 18:00:26422 idx += len;
423 size -= len;
424 ++line;
425 }
426 }
427#endif // WEBRTC_ANDROID
428 if (log_to_stderr) {
429 fprintf(stderr, "%s", str.c_str());
430 fflush(stderr);
431 }
432}
433
Tommifef05002018-02-27 12:51:08434// static
435bool LogMessage::IsNoop(LoggingSeverity severity) {
Jonas Olssond8c50782018-09-07 09:21:28436 if (severity >= g_dbg_sev || severity >= g_min_sev)
Tommifef05002018-02-27 12:51:08437 return false;
438
439 // TODO(tommi): We're grabbing this lock for every LogMessage instance that
440 // is going to be logged. This introduces unnecessary synchronization for
441 // a feature that's mostly used for testing.
Danil Chapovalovec221832019-11-21 09:07:57442 CritScope cs(&g_log_crit);
Danil Chapovalovb9f69022019-10-21 07:19:10443 return streams_ == nullptr;
Tommifef05002018-02-27 12:51:08444}
445
446void LogMessage::FinishPrintStream() {
Tommifef05002018-02-27 12:51:08447 if (!extra_.empty())
448 print_stream_ << " : " << extra_;
Jonas Olssond8c50782018-09-07 09:21:28449 print_stream_ << "\n";
Tommifef05002018-02-27 12:51:08450}
451
Karl Wibergcefc4652018-05-23 21:20:38452namespace webrtc_logging_impl {
henrike@webrtc.orgf0488722014-05-13 18:00:26453
Karl Wibergcefc4652018-05-23 21:20:38454void Log(const LogArgType* fmt, ...) {
455 va_list args;
456 va_start(args, fmt);
457
458 LogMetadataErr meta;
459 const char* tag = nullptr;
460 switch (*fmt) {
461 case LogArgType::kLogMetadata: {
462 meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
463 break;
464 }
465 case LogArgType::kLogMetadataErr: {
466 meta = va_arg(args, LogMetadataErr);
467 break;
468 }
469#ifdef WEBRTC_ANDROID
470 case LogArgType::kLogMetadataTag: {
471 const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
472 meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
473 tag = tag_meta.tag;
474 break;
475 }
476#endif
477 default: {
478 RTC_NOTREACHED();
479 va_end(args);
480 return;
481 }
482 }
Jonas Olssond8c50782018-09-07 09:21:28483
484 if (LogMessage::IsNoop(meta.meta.Severity())) {
485 va_end(args);
486 return;
487 }
488
Karl Wibergcefc4652018-05-23 21:20:38489 LogMessage log_message(meta.meta.File(), meta.meta.Line(),
490 meta.meta.Severity(), meta.err_ctx, meta.err);
491 if (tag) {
492 log_message.AddTag(tag);
493 }
494
495 for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
496 switch (*fmt) {
497 case LogArgType::kInt:
498 log_message.stream() << va_arg(args, int);
499 break;
500 case LogArgType::kLong:
501 log_message.stream() << va_arg(args, long);
502 break;
503 case LogArgType::kLongLong:
504 log_message.stream() << va_arg(args, long long);
505 break;
506 case LogArgType::kUInt:
507 log_message.stream() << va_arg(args, unsigned);
508 break;
509 case LogArgType::kULong:
510 log_message.stream() << va_arg(args, unsigned long);
511 break;
512 case LogArgType::kULongLong:
513 log_message.stream() << va_arg(args, unsigned long long);
514 break;
515 case LogArgType::kDouble:
516 log_message.stream() << va_arg(args, double);
517 break;
518 case LogArgType::kLongDouble:
519 log_message.stream() << va_arg(args, long double);
520 break;
Niels Möller65835be2019-02-04 18:23:58521 case LogArgType::kCharP: {
522 const char* s = va_arg(args, const char*);
523 log_message.stream() << (s ? s : "(null)");
Karl Wibergcefc4652018-05-23 21:20:38524 break;
Niels Möller65835be2019-02-04 18:23:58525 }
Karl Wibergcefc4652018-05-23 21:20:38526 case LogArgType::kStdString:
527 log_message.stream() << *va_arg(args, const std::string*);
528 break;
Jonas Olssonf2ce37c2018-09-12 13:32:47529 case LogArgType::kStringView:
530 log_message.stream() << *va_arg(args, const absl::string_view*);
531 break;
Karl Wibergcefc4652018-05-23 21:20:38532 case LogArgType::kVoidP:
Jonas Olssond8c50782018-09-07 09:21:28533 log_message.stream() << rtc::ToHex(
534 reinterpret_cast<uintptr_t>(va_arg(args, const void*)));
Karl Wibergcefc4652018-05-23 21:20:38535 break;
536 default:
537 RTC_NOTREACHED();
538 va_end(args);
539 return;
540 }
541 }
542
543 va_end(args);
544}
545
546} // namespace webrtc_logging_impl
henrike@webrtc.orgf0488722014-05-13 18:00:26547} // namespace rtc
Artem Titov6a4a1462019-11-26 15:24:46548#endif
549
550namespace rtc {
551// Inefficient default implementation, override is recommended.
552void LogSink::OnLogMessage(const std::string& msg,
553 LoggingSeverity severity,
554 const char* tag) {
555 OnLogMessage(tag + (": " + msg), severity);
556}
557
558void LogSink::OnLogMessage(const std::string& msg,
559 LoggingSeverity /* severity */) {
560 OnLogMessage(msg);
561}
562} // namespace rtc