blob: 0681d8c872b821161fef23c6a94b7f0dff65286e [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>
Karl Wibergcefc4652018-05-23 23:20:38 +020036#include <cstdarg>
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000037#include <iomanip>
38#include <ostream>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000039#include <vector>
40
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020041#include "rtc_base/criticalsection.h"
42#include "rtc_base/logging.h"
Tommie51a0a82018-02-27 15:30:29 +010043#include "rtc_base/platform_thread_types.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020044#include "rtc_base/stringencode.h"
Tommifef05002018-02-27 13:51:08 +010045#include "rtc_base/strings/string_builder.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020046#include "rtc_base/stringutils.h"
47#include "rtc_base/timeutils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000048
49namespace rtc {
andrew88703d72015-09-07 00:34:56 -070050namespace {
Jonas Olsson2b6f1352018-02-15 11:57:03 +010051// By default, release builds don't log, debug builds at info level
52#if !defined(NDEBUG)
53static LoggingSeverity g_min_sev = LS_INFO;
54static LoggingSeverity g_dbg_sev = LS_INFO;
55#else
56static LoggingSeverity g_min_sev = LS_NONE;
57static LoggingSeverity g_dbg_sev = LS_NONE;
58#endif
andrew88703d72015-09-07 00:34:56 -070059
60// Return the filename portion of the string (that following the last slash).
61const char* FilenameFromPath(const char* file) {
62 const char* end1 = ::strrchr(file, '/');
63 const char* end2 = ::strrchr(file, '\\');
64 if (!end1 && !end2)
65 return file;
66 else
67 return (end1 > end2) ? end1 + 1 : end2 + 1;
68}
69
Tommifef05002018-02-27 13:51:08 +010070std::ostream& GetNoopStream() {
71 class NoopStreamBuf : public std::streambuf {
72 public:
73 int overflow(int c) override { return c; }
74 };
75 static NoopStreamBuf noop_buffer;
76 static std::ostream noop_stream(&noop_buffer);
77 return noop_stream;
78}
79
Jonas Olsson2b6f1352018-02-15 11:57:03 +010080// Global lock for log subsystem, only needed to serialize access to streams_.
81CriticalSection g_log_crit;
andrew88703d72015-09-07 00:34:56 -070082} // namespace
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000083
Paulina Hensman21219a0e2018-05-18 14:32:50 +020084void LogSink::OnLogMessage(const std::string& msg,
85 LoggingSeverity severity,
86 const char* tag) {
87 OnLogMessage(msg);
88}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000089
90/////////////////////////////////////////////////////////////////////////////
91// LogMessage
92/////////////////////////////////////////////////////////////////////////////
93
andrew88703d72015-09-07 00:34:56 -070094bool LogMessage::log_to_stderr_ = true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000095
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000096// The list of logging streams currently configured.
97// Note: we explicitly do not clean this up, because of the uncertain ordering
98// of destructors at program exit. Let the person who sets the stream trigger
deadbeef37f5ecf2017-02-27 14:06:41 -080099// cleanup by setting to null, or let it leak (safe at program exit).
danilchap3c6abd22017-09-06 05:46:29 -0700100LogMessage::StreamList LogMessage::streams_ RTC_GUARDED_BY(g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000101
102// Boolean options default to false (0)
103bool LogMessage::thread_, LogMessage::timestamp_;
104
Karl Wibergab4f1c12018-05-04 10:42:28 +0200105LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
106 : LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
107
Peter Boström225789d2015-10-23 15:20:56 +0200108LogMessage::LogMessage(const char* file,
109 int line,
110 LoggingSeverity sev,
111 LogErrorContext err_ctx,
Tommie51a0a82018-02-27 15:30:29 +0100112 int err)
113 : severity_(sev), is_noop_(IsNoop(sev)) {
Tommifef05002018-02-27 13:51:08 +0100114 // If there's no need to do any work, let's not :)
115 if (is_noop_)
116 return;
117
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000118 if (timestamp_) {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700119 // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
120 // in log messages represents the real system time.
121 int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000122 // Also ensure WallClockStartTime is initialized, so that it matches
123 // LogStartTime.
124 WallClockStartTime();
125 print_stream_ << "[" << std::setfill('0') << std::setw(3) << (time / 1000)
126 << ":" << std::setw(3) << (time % 1000) << std::setfill(' ')
127 << "] ";
128 }
129
130 if (thread_) {
henrikaba35d052015-07-14 17:04:08 +0200131 PlatformThreadId id = CurrentThreadId();
132 print_stream_ << "[" << std::dec << id << "] ";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000133 }
134
Paulina Hensman21219a0e2018-05-18 14:32:50 +0200135 if (file != nullptr) {
136#if defined(WEBRTC_ANDROID)
137 tag_ = FilenameFromPath(file);
138 print_stream_ << "(line " << line << "): ";
139#else
Alex Glaznevebed24d2015-09-15 11:05:24 -0700140 print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
Paulina Hensman21219a0e2018-05-18 14:32:50 +0200141#endif
142 }
andrew88703d72015-09-07 00:34:56 -0700143
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000144 if (err_ctx != ERRCTX_NONE) {
Karl Wiberg881f1682018-03-08 15:03:23 +0100145 char tmp_buf[1024];
146 SimpleStringBuilder tmp(tmp_buf);
Tommifef05002018-02-27 13:51:08 +0100147 tmp.AppendFormat("[0x%08X]", err);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000148 switch (err_ctx) {
149 case ERRCTX_ERRNO:
150 tmp << " " << strerror(err);
151 break;
kwiberg77eab702016-09-28 17:42:01 -0700152#ifdef WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000153 case ERRCTX_HRESULT: {
154 char msgbuf[256];
Tommie51a0a82018-02-27 15:30:29 +0100155 DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM |
156 FORMAT_MESSAGE_IGNORE_INSERTS;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000157 if (DWORD len = FormatMessageA(
Tommie51a0a82018-02-27 15:30:29 +0100158 flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
deadbeef37f5ecf2017-02-27 14:06:41 -0800159 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000160 while ((len > 0) &&
161 isspace(static_cast<unsigned char>(msgbuf[len-1]))) {
162 msgbuf[--len] = 0;
163 }
164 tmp << " " << msgbuf;
165 }
166 break;
167 }
Tommi0eefb4d2015-05-23 09:54:07 +0200168#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000169#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
170 case ERRCTX_OSSTATUS: {
Tommi09ca02e2016-04-24 17:32:48 +0200171 std::string desc(DescriptionFromOSStatus(err));
172 tmp << " " << (desc.empty() ? "Unknown error" : desc.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000173 break;
174 }
175#endif // WEBRTC_MAC && !defined(WEBRTC_IOS)
176 default:
177 break;
178 }
179 extra_ = tmp.str();
180 }
181}
182
Tommie51a0a82018-02-27 15:30:29 +0100183#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700184LogMessage::LogMessage(const char* file,
185 int line,
186 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100187 const char* tag)
deadbeef37f5ecf2017-02-27 14:06:41 -0800188 : LogMessage(file,
189 line,
190 sev,
191 ERRCTX_NONE,
Tommie51a0a82018-02-27 15:30:29 +0100192 0 /* err */) {
Tommifef05002018-02-27 13:51:08 +0100193 if (!is_noop_) {
194 tag_ = tag;
Tommifef05002018-02-27 13:51:08 +0100195 }
jiayl66f0da22015-09-14 15:06:39 -0700196}
Tommie51a0a82018-02-27 15:30:29 +0100197#endif
198
199// DEPRECATED. Currently only used by downstream projects that use
200// implementation details of logging.h. Work is ongoing to remove those
201// dependencies.
202LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev,
203 const std::string& tag)
204 : LogMessage(file, line, sev) {
205 if (!is_noop_)
206 print_stream_ << tag << ": ";
207}
jiayl66f0da22015-09-14 15:06:39 -0700208
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000209LogMessage::~LogMessage() {
Tommifef05002018-02-27 13:51:08 +0100210 if (is_noop_)
211 return;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000212
Tommifef05002018-02-27 13:51:08 +0100213 FinishPrintStream();
214
215 // TODO(tommi): Unfortunately |ostringstream::str()| always returns a copy
216 // of the constructed string. This means that we always end up creating
217 // two copies here (one owned by the stream, one by the return value of
218 // |str()|). It would be nice to switch to something else.
219 const std::string str = print_stream_.str();
220
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100221 if (severity_ >= g_dbg_sev) {
Tommie51a0a82018-02-27 15:30:29 +0100222#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700223 OutputToDebug(str, severity_, tag_);
Tommie51a0a82018-02-27 15:30:29 +0100224#else
225 OutputToDebug(str, severity_);
226#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000227 }
228
Peter Boström225789d2015-10-23 15:20:56 +0200229 CritScope cs(&g_log_crit);
230 for (auto& kv : streams_) {
231 if (severity_ >= kv.second) {
Paulina Hensman21219a0e2018-05-18 14:32:50 +0200232#if defined(WEBRTC_ANDROID)
233 kv.first->OnLogMessage(str, severity_, tag_);
234#else
Peter Boström225789d2015-10-23 15:20:56 +0200235 kv.first->OnLogMessage(str);
Paulina Hensman21219a0e2018-05-18 14:32:50 +0200236#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000237 }
238 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000239}
240
Karl Wibergcefc4652018-05-23 23:20:38 +0200241void LogMessage::AddTag(const char* tag) {
242#ifdef WEBRTC_ANDROID
243 if (!is_noop_) {
244 tag_ = tag;
245 }
246#endif
247}
248
Tommifef05002018-02-27 13:51:08 +0100249std::ostream& LogMessage::stream() {
250 return is_noop_ ? GetNoopStream() : print_stream_;
251}
252
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100253bool LogMessage::Loggable(LoggingSeverity sev) {
254 return sev >= g_min_sev;
255}
256
257int LogMessage::GetMinLogSeverity() {
258 return g_min_sev;
259}
260
261LoggingSeverity LogMessage::GetLogToDebug() {
262 return g_dbg_sev;
263}
Honghai Zhang82d78622016-05-06 11:29:15 -0700264int64_t LogMessage::LogStartTime() {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700265 static const int64_t g_start = SystemTimeMillis();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000266 return g_start;
267}
268
Peter Boström0c4e06b2015-10-07 12:23:21 +0200269uint32_t LogMessage::WallClockStartTime() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800270 static const uint32_t g_start_wallclock = time(nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000271 return g_start_wallclock;
272}
273
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000274void LogMessage::LogThreads(bool on) {
275 thread_ = on;
276}
277
278void LogMessage::LogTimestamps(bool on) {
279 timestamp_ = on;
280}
281
Tommi0eefb4d2015-05-23 09:54:07 +0200282void LogMessage::LogToDebug(LoggingSeverity min_sev) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100283 g_dbg_sev = min_sev;
Peter Boström225789d2015-10-23 15:20:56 +0200284 CritScope cs(&g_log_crit);
Tommi00aac5a2015-05-25 11:25:59 +0200285 UpdateMinLogSeverity();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000286}
287
andrew88703d72015-09-07 00:34:56 -0700288void LogMessage::SetLogToStderr(bool log_to_stderr) {
289 log_to_stderr_ = log_to_stderr;
290}
291
Tommi0eefb4d2015-05-23 09:54:07 +0200292int LogMessage::GetLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200293 CritScope cs(&g_log_crit);
Tommi0eefb4d2015-05-23 09:54:07 +0200294 LoggingSeverity sev = LS_NONE;
Peter Boström225789d2015-10-23 15:20:56 +0200295 for (auto& kv : streams_) {
296 if (!stream || stream == kv.first) {
297 sev = std::min(sev, kv.second);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000298 }
299 }
300 return sev;
301}
302
Tommi0eefb4d2015-05-23 09:54:07 +0200303void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
Peter Boström225789d2015-10-23 15:20:56 +0200304 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000305 streams_.push_back(std::make_pair(stream, min_sev));
306 UpdateMinLogSeverity();
307}
308
Tommi0eefb4d2015-05-23 09:54:07 +0200309void LogMessage::RemoveLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200310 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000311 for (StreamList::iterator it = streams_.begin(); it != streams_.end(); ++it) {
312 if (stream == it->first) {
313 streams_.erase(it);
314 break;
315 }
316 }
317 UpdateMinLogSeverity();
318}
319
Tommi0eefb4d2015-05-23 09:54:07 +0200320void LogMessage::ConfigureLogging(const char* params) {
321 LoggingSeverity current_level = LS_VERBOSE;
322 LoggingSeverity debug_level = GetLogToDebug();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000323
324 std::vector<std::string> tokens;
325 tokenize(params, ' ', &tokens);
326
Tommi0eefb4d2015-05-23 09:54:07 +0200327 for (const std::string& token : tokens) {
328 if (token.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000329 continue;
330
331 // Logging features
Tommi0eefb4d2015-05-23 09:54:07 +0200332 if (token == "tstamp") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000333 LogTimestamps();
Tommi0eefb4d2015-05-23 09:54:07 +0200334 } else if (token == "thread") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000335 LogThreads();
336
337 // Logging levels
Tommi0eefb4d2015-05-23 09:54:07 +0200338 } else if (token == "sensitive") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000339 current_level = LS_SENSITIVE;
Tommi0eefb4d2015-05-23 09:54:07 +0200340 } else if (token == "verbose") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000341 current_level = LS_VERBOSE;
Tommi0eefb4d2015-05-23 09:54:07 +0200342 } else if (token == "info") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000343 current_level = LS_INFO;
Tommi0eefb4d2015-05-23 09:54:07 +0200344 } else if (token == "warning") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000345 current_level = LS_WARNING;
Tommi0eefb4d2015-05-23 09:54:07 +0200346 } else if (token == "error") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000347 current_level = LS_ERROR;
Tommi0eefb4d2015-05-23 09:54:07 +0200348 } else if (token == "none") {
349 current_level = LS_NONE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000350
351 // Logging targets
Tommi0eefb4d2015-05-23 09:54:07 +0200352 } else if (token == "debug") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000353 debug_level = current_level;
354 }
355 }
356
357#if defined(WEBRTC_WIN)
Tommi0eefb4d2015-05-23 09:54:07 +0200358 if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000359 // First, attempt to attach to our parent's console... so if you invoke
360 // from the command line, we'll see the output there. Otherwise, create
361 // our own console window.
362 // Note: These methods fail if a console already exists, which is fine.
Tommie51a0a82018-02-27 15:30:29 +0100363 if (!AttachConsole(ATTACH_PARENT_PROCESS))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000364 ::AllocConsole();
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
Tommie51a0a82018-02-27 15:30:29 +0100380#if defined(WEBRTC_ANDROID)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000381void LogMessage::OutputToDebug(const std::string& str,
jiayl66f0da22015-09-14 15:06:39 -0700382 LoggingSeverity severity,
Tommie51a0a82018-02-27 15:30:29 +0100383 const char* tag) {
384#else
385void LogMessage::OutputToDebug(const std::string& str,
386 LoggingSeverity severity) {
387#endif
andrew88703d72015-09-07 00:34:56 -0700388 bool log_to_stderr = log_to_stderr_;
tfarinaa41ab932015-10-30 16:08:48 -0700389#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000390 // On the Mac, all stderr output goes to the Console log and causes clutter.
391 // So in opt builds, don't log to stderr unless the user specifically sets
392 // a preference to do so.
393 CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault,
394 "logToStdErr",
395 kCFStringEncodingUTF8);
396 CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
deadbeef37f5ecf2017-02-27 14:06:41 -0800397 if (key != nullptr && domain != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000398 Boolean exists_and_is_valid;
399 Boolean should_log =
400 CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
401 // If the key doesn't exist or is invalid or is false, we will not log to
402 // stderr.
403 log_to_stderr = exists_and_is_valid && should_log;
404 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800405 if (key != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000406 CFRelease(key);
407 }
Tommie51a0a82018-02-27 15:30:29 +0100408#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
409
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000410#if defined(WEBRTC_WIN)
411 // Always log to the debugger.
412 // Perhaps stderr should be controlled by a preference, as on Mac?
413 OutputDebugStringA(str.c_str());
414 if (log_to_stderr) {
415 // This handles dynamically allocated consoles, too.
416 if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
417 log_to_stderr = false;
418 DWORD written = 0;
419 ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
420 &written, 0);
421 }
422 }
Tommi0eefb4d2015-05-23 09:54:07 +0200423#endif // WEBRTC_WIN
Tommie51a0a82018-02-27 15:30:29 +0100424
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000425#if defined(WEBRTC_ANDROID)
426 // Android's logging facility uses severity to log messages but we
427 // need to map libjingle's severity levels to Android ones first.
428 // Also write to stderr which maybe available to executable started
429 // from the shell.
430 int prio;
431 switch (severity) {
432 case LS_SENSITIVE:
Tommie51a0a82018-02-27 15:30:29 +0100433 __android_log_write(ANDROID_LOG_INFO, tag, "SENSITIVE");
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000434 if (log_to_stderr) {
435 fprintf(stderr, "SENSITIVE");
436 fflush(stderr);
437 }
438 return;
439 case LS_VERBOSE:
440 prio = ANDROID_LOG_VERBOSE;
441 break;
442 case LS_INFO:
443 prio = ANDROID_LOG_INFO;
444 break;
445 case LS_WARNING:
446 prio = ANDROID_LOG_WARN;
447 break;
448 case LS_ERROR:
449 prio = ANDROID_LOG_ERROR;
450 break;
451 default:
452 prio = ANDROID_LOG_UNKNOWN;
453 }
454
455 int size = str.size();
456 int line = 0;
457 int idx = 0;
458 const int max_lines = size / kMaxLogLineSize + 1;
459 if (max_lines == 1) {
Tommie51a0a82018-02-27 15:30:29 +0100460 __android_log_print(prio, tag, "%.*s", size, str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000461 } else {
462 while (size > 0) {
463 const int len = std::min(size, kMaxLogLineSize);
464 // Use the size of the string in the format (str may have \0 in the
465 // middle).
Tommie51a0a82018-02-27 15:30:29 +0100466 __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
467 str.c_str() + idx);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000468 idx += len;
469 size -= len;
470 ++line;
471 }
472 }
473#endif // WEBRTC_ANDROID
474 if (log_to_stderr) {
475 fprintf(stderr, "%s", str.c_str());
476 fflush(stderr);
477 }
478}
479
Tommifef05002018-02-27 13:51:08 +0100480// static
481bool LogMessage::IsNoop(LoggingSeverity severity) {
482 if (severity >= g_dbg_sev)
483 return false;
484
485 // TODO(tommi): We're grabbing this lock for every LogMessage instance that
486 // is going to be logged. This introduces unnecessary synchronization for
487 // a feature that's mostly used for testing.
488 CritScope cs(&g_log_crit);
489 return streams_.size() == 0;
490}
491
492void LogMessage::FinishPrintStream() {
493 if (is_noop_)
494 return;
495 if (!extra_.empty())
496 print_stream_ << " : " << extra_;
497 print_stream_ << std::endl;
498}
499
Karl Wibergcefc4652018-05-23 23:20:38 +0200500namespace webrtc_logging_impl {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000501
Karl Wibergcefc4652018-05-23 23:20:38 +0200502void Log(const LogArgType* fmt, ...) {
503 va_list args;
504 va_start(args, fmt);
505
506 LogMetadataErr meta;
507 const char* tag = nullptr;
508 switch (*fmt) {
509 case LogArgType::kLogMetadata: {
510 meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
511 break;
512 }
513 case LogArgType::kLogMetadataErr: {
514 meta = va_arg(args, LogMetadataErr);
515 break;
516 }
517#ifdef WEBRTC_ANDROID
518 case LogArgType::kLogMetadataTag: {
519 const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
520 meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
521 tag = tag_meta.tag;
522 break;
523 }
524#endif
525 default: {
526 RTC_NOTREACHED();
527 va_end(args);
528 return;
529 }
530 }
531 LogMessage log_message(meta.meta.File(), meta.meta.Line(),
532 meta.meta.Severity(), meta.err_ctx, meta.err);
533 if (tag) {
534 log_message.AddTag(tag);
535 }
536
537 for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
538 switch (*fmt) {
539 case LogArgType::kInt:
540 log_message.stream() << va_arg(args, int);
541 break;
542 case LogArgType::kLong:
543 log_message.stream() << va_arg(args, long);
544 break;
545 case LogArgType::kLongLong:
546 log_message.stream() << va_arg(args, long long);
547 break;
548 case LogArgType::kUInt:
549 log_message.stream() << va_arg(args, unsigned);
550 break;
551 case LogArgType::kULong:
552 log_message.stream() << va_arg(args, unsigned long);
553 break;
554 case LogArgType::kULongLong:
555 log_message.stream() << va_arg(args, unsigned long long);
556 break;
557 case LogArgType::kDouble:
558 log_message.stream() << va_arg(args, double);
559 break;
560 case LogArgType::kLongDouble:
561 log_message.stream() << va_arg(args, long double);
562 break;
563 case LogArgType::kCharP:
564 log_message.stream() << va_arg(args, const char*);
565 break;
566 case LogArgType::kStdString:
567 log_message.stream() << *va_arg(args, const std::string*);
568 break;
569 case LogArgType::kVoidP:
570 log_message.stream() << va_arg(args, const void*);
571 break;
572 default:
573 RTC_NOTREACHED();
574 va_end(args);
575 return;
576 }
577 }
578
579 va_end(args);
580}
581
582} // namespace webrtc_logging_impl
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000583} // namespace rtc