blob: 8b3d9f1180b1ccb1ab4148fb1e8dd94e02cabb51 [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
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000084
85/////////////////////////////////////////////////////////////////////////////
86// LogMessage
87/////////////////////////////////////////////////////////////////////////////
88
andrew88703d72015-09-07 00:34:56 -070089bool LogMessage::log_to_stderr_ = true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000090
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000091// The list of logging streams currently configured.
92// Note: we explicitly do not clean this up, because of the uncertain ordering
93// of destructors at program exit. Let the person who sets the stream trigger
deadbeef37f5ecf2017-02-27 14:06:41 -080094// cleanup by setting to null, or let it leak (safe at program exit).
danilchap3c6abd22017-09-06 05:46:29 -070095LogMessage::StreamList LogMessage::streams_ RTC_GUARDED_BY(g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000096
97// Boolean options default to false (0)
98bool LogMessage::thread_, LogMessage::timestamp_;
99
Karl Wibergab4f1c12018-05-04 10:42:28 +0200100LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
101 : LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
102
Peter Boström225789d2015-10-23 15:20:56 +0200103LogMessage::LogMessage(const char* file,
104 int line,
105 LoggingSeverity sev,
106 LogErrorContext err_ctx,
Tommie51a0a82018-02-27 15:30:29 +0100107 int err)
108 : severity_(sev), is_noop_(IsNoop(sev)) {
Tommifef05002018-02-27 13:51:08 +0100109 // If there's no need to do any work, let's not :)
110 if (is_noop_)
111 return;
112
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000113 if (timestamp_) {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700114 // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
115 // in log messages represents the real system time.
116 int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000117 // Also ensure WallClockStartTime is initialized, so that it matches
118 // LogStartTime.
119 WallClockStartTime();
120 print_stream_ << "[" << std::setfill('0') << std::setw(3) << (time / 1000)
121 << ":" << std::setw(3) << (time % 1000) << std::setfill(' ')
122 << "] ";
123 }
124
125 if (thread_) {
henrikaba35d052015-07-14 17:04:08 +0200126 PlatformThreadId id = CurrentThreadId();
127 print_stream_ << "[" << std::dec << id << "] ";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000128 }
129
Alex Glaznev5abd78b2018-06-01 19:12:58 +0000130 if (file != nullptr)
Alex Glaznevebed24d2015-09-15 11:05:24 -0700131 print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
andrew88703d72015-09-07 00:34:56 -0700132
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000133 if (err_ctx != ERRCTX_NONE) {
Karl Wiberg881f1682018-03-08 15:03:23 +0100134 char tmp_buf[1024];
135 SimpleStringBuilder tmp(tmp_buf);
Tommifef05002018-02-27 13:51:08 +0100136 tmp.AppendFormat("[0x%08X]", err);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000137 switch (err_ctx) {
138 case ERRCTX_ERRNO:
139 tmp << " " << strerror(err);
140 break;
kwiberg77eab702016-09-28 17:42:01 -0700141#ifdef WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000142 case ERRCTX_HRESULT: {
143 char msgbuf[256];
Tommie51a0a82018-02-27 15:30:29 +0100144 DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM |
145 FORMAT_MESSAGE_IGNORE_INSERTS;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000146 if (DWORD len = FormatMessageA(
Tommie51a0a82018-02-27 15:30:29 +0100147 flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
deadbeef37f5ecf2017-02-27 14:06:41 -0800148 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000149 while ((len > 0) &&
150 isspace(static_cast<unsigned char>(msgbuf[len-1]))) {
151 msgbuf[--len] = 0;
152 }
153 tmp << " " << msgbuf;
154 }
155 break;
156 }
Tommi0eefb4d2015-05-23 09:54:07 +0200157#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000158#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
159 case ERRCTX_OSSTATUS: {
Tommi09ca02e2016-04-24 17:32:48 +0200160 std::string desc(DescriptionFromOSStatus(err));
161 tmp << " " << (desc.empty() ? "Unknown error" : desc.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000162 break;
163 }
164#endif // WEBRTC_MAC && !defined(WEBRTC_IOS)
165 default:
166 break;
167 }
168 extra_ = tmp.str();
169 }
170}
171
Tommie51a0a82018-02-27 15:30:29 +0100172#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700173LogMessage::LogMessage(const char* file,
174 int line,
175 LoggingSeverity sev,
Tommie51a0a82018-02-27 15:30:29 +0100176 const char* tag)
deadbeef37f5ecf2017-02-27 14:06:41 -0800177 : LogMessage(file,
178 line,
179 sev,
180 ERRCTX_NONE,
Tommie51a0a82018-02-27 15:30:29 +0100181 0 /* err */) {
Tommifef05002018-02-27 13:51:08 +0100182 if (!is_noop_) {
183 tag_ = tag;
Alex Glaznev5abd78b2018-06-01 19:12:58 +0000184 print_stream_ << tag << ": ";
Tommifef05002018-02-27 13:51:08 +0100185 }
jiayl66f0da22015-09-14 15:06:39 -0700186}
Tommie51a0a82018-02-27 15:30:29 +0100187#endif
188
189// DEPRECATED. Currently only used by downstream projects that use
190// implementation details of logging.h. Work is ongoing to remove those
191// dependencies.
192LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev,
193 const std::string& tag)
194 : LogMessage(file, line, sev) {
195 if (!is_noop_)
196 print_stream_ << tag << ": ";
197}
jiayl66f0da22015-09-14 15:06:39 -0700198
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000199LogMessage::~LogMessage() {
Tommifef05002018-02-27 13:51:08 +0100200 if (is_noop_)
201 return;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000202
Tommifef05002018-02-27 13:51:08 +0100203 FinishPrintStream();
204
205 // TODO(tommi): Unfortunately |ostringstream::str()| always returns a copy
206 // of the constructed string. This means that we always end up creating
207 // two copies here (one owned by the stream, one by the return value of
208 // |str()|). It would be nice to switch to something else.
209 const std::string str = print_stream_.str();
210
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100211 if (severity_ >= g_dbg_sev) {
Tommie51a0a82018-02-27 15:30:29 +0100212#if defined(WEBRTC_ANDROID)
jiayl66f0da22015-09-14 15:06:39 -0700213 OutputToDebug(str, severity_, tag_);
Tommie51a0a82018-02-27 15:30:29 +0100214#else
215 OutputToDebug(str, severity_);
216#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000217 }
218
Peter Boström225789d2015-10-23 15:20:56 +0200219 CritScope cs(&g_log_crit);
220 for (auto& kv : streams_) {
221 if (severity_ >= kv.second) {
222 kv.first->OnLogMessage(str);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000223 }
224 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000225}
226
Karl Wibergcefc4652018-05-23 23:20:38 +0200227void LogMessage::AddTag(const char* tag) {
228#ifdef WEBRTC_ANDROID
229 if (!is_noop_) {
230 tag_ = tag;
231 }
232#endif
233}
234
Tommifef05002018-02-27 13:51:08 +0100235std::ostream& LogMessage::stream() {
236 return is_noop_ ? GetNoopStream() : print_stream_;
237}
238
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100239bool LogMessage::Loggable(LoggingSeverity sev) {
240 return sev >= g_min_sev;
241}
242
243int LogMessage::GetMinLogSeverity() {
244 return g_min_sev;
245}
246
247LoggingSeverity LogMessage::GetLogToDebug() {
248 return g_dbg_sev;
249}
Honghai Zhang82d78622016-05-06 11:29:15 -0700250int64_t LogMessage::LogStartTime() {
Taylor Brandstetter4f0dfbd2016-06-15 17:15:23 -0700251 static const int64_t g_start = SystemTimeMillis();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000252 return g_start;
253}
254
Peter Boström0c4e06b2015-10-07 12:23:21 +0200255uint32_t LogMessage::WallClockStartTime() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800256 static const uint32_t g_start_wallclock = time(nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000257 return g_start_wallclock;
258}
259
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000260void LogMessage::LogThreads(bool on) {
261 thread_ = on;
262}
263
264void LogMessage::LogTimestamps(bool on) {
265 timestamp_ = on;
266}
267
Tommi0eefb4d2015-05-23 09:54:07 +0200268void LogMessage::LogToDebug(LoggingSeverity min_sev) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100269 g_dbg_sev = min_sev;
Peter Boström225789d2015-10-23 15:20:56 +0200270 CritScope cs(&g_log_crit);
Tommi00aac5a2015-05-25 11:25:59 +0200271 UpdateMinLogSeverity();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000272}
273
andrew88703d72015-09-07 00:34:56 -0700274void LogMessage::SetLogToStderr(bool log_to_stderr) {
275 log_to_stderr_ = log_to_stderr;
276}
277
Tommi0eefb4d2015-05-23 09:54:07 +0200278int LogMessage::GetLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200279 CritScope cs(&g_log_crit);
Tommi0eefb4d2015-05-23 09:54:07 +0200280 LoggingSeverity sev = LS_NONE;
Peter Boström225789d2015-10-23 15:20:56 +0200281 for (auto& kv : streams_) {
282 if (!stream || stream == kv.first) {
283 sev = std::min(sev, kv.second);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000284 }
285 }
286 return sev;
287}
288
Tommi0eefb4d2015-05-23 09:54:07 +0200289void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
Peter Boström225789d2015-10-23 15:20:56 +0200290 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000291 streams_.push_back(std::make_pair(stream, min_sev));
292 UpdateMinLogSeverity();
293}
294
Tommi0eefb4d2015-05-23 09:54:07 +0200295void LogMessage::RemoveLogToStream(LogSink* stream) {
Peter Boström225789d2015-10-23 15:20:56 +0200296 CritScope cs(&g_log_crit);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000297 for (StreamList::iterator it = streams_.begin(); it != streams_.end(); ++it) {
298 if (stream == it->first) {
299 streams_.erase(it);
300 break;
301 }
302 }
303 UpdateMinLogSeverity();
304}
305
Tommi0eefb4d2015-05-23 09:54:07 +0200306void LogMessage::ConfigureLogging(const char* params) {
307 LoggingSeverity current_level = LS_VERBOSE;
308 LoggingSeverity debug_level = GetLogToDebug();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000309
310 std::vector<std::string> tokens;
311 tokenize(params, ' ', &tokens);
312
Tommi0eefb4d2015-05-23 09:54:07 +0200313 for (const std::string& token : tokens) {
314 if (token.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000315 continue;
316
317 // Logging features
Tommi0eefb4d2015-05-23 09:54:07 +0200318 if (token == "tstamp") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000319 LogTimestamps();
Tommi0eefb4d2015-05-23 09:54:07 +0200320 } else if (token == "thread") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000321 LogThreads();
322
323 // Logging levels
Tommi0eefb4d2015-05-23 09:54:07 +0200324 } else if (token == "sensitive") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000325 current_level = LS_SENSITIVE;
Tommi0eefb4d2015-05-23 09:54:07 +0200326 } else if (token == "verbose") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000327 current_level = LS_VERBOSE;
Tommi0eefb4d2015-05-23 09:54:07 +0200328 } else if (token == "info") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000329 current_level = LS_INFO;
Tommi0eefb4d2015-05-23 09:54:07 +0200330 } else if (token == "warning") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000331 current_level = LS_WARNING;
Tommi0eefb4d2015-05-23 09:54:07 +0200332 } else if (token == "error") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000333 current_level = LS_ERROR;
Tommi0eefb4d2015-05-23 09:54:07 +0200334 } else if (token == "none") {
335 current_level = LS_NONE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000336
337 // Logging targets
Tommi0eefb4d2015-05-23 09:54:07 +0200338 } else if (token == "debug") {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000339 debug_level = current_level;
340 }
341 }
342
343#if defined(WEBRTC_WIN)
Tommi0eefb4d2015-05-23 09:54:07 +0200344 if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000345 // First, attempt to attach to our parent's console... so if you invoke
346 // from the command line, we'll see the output there. Otherwise, create
347 // our own console window.
348 // Note: These methods fail if a console already exists, which is fine.
Tommie51a0a82018-02-27 15:30:29 +0100349 if (!AttachConsole(ATTACH_PARENT_PROCESS))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000350 ::AllocConsole();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000351 }
Tommi0eefb4d2015-05-23 09:54:07 +0200352#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000353
354 LogToDebug(debug_level);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000355}
356
danilchap3c6abd22017-09-06 05:46:29 -0700357void LogMessage::UpdateMinLogSeverity()
358 RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_crit) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100359 LoggingSeverity min_sev = g_dbg_sev;
Peter Boström225789d2015-10-23 15:20:56 +0200360 for (auto& kv : streams_) {
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100361 min_sev = std::min(g_dbg_sev, kv.second);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000362 }
Jonas Olsson2b6f1352018-02-15 11:57:03 +0100363 g_min_sev = min_sev;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000364}
365
Tommie51a0a82018-02-27 15:30:29 +0100366#if defined(WEBRTC_ANDROID)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000367void LogMessage::OutputToDebug(const std::string& str,
jiayl66f0da22015-09-14 15:06:39 -0700368 LoggingSeverity severity,
Tommie51a0a82018-02-27 15:30:29 +0100369 const char* tag) {
370#else
371void LogMessage::OutputToDebug(const std::string& str,
372 LoggingSeverity severity) {
373#endif
andrew88703d72015-09-07 00:34:56 -0700374 bool log_to_stderr = log_to_stderr_;
tfarinaa41ab932015-10-30 16:08:48 -0700375#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000376 // On the Mac, all stderr output goes to the Console log and causes clutter.
377 // So in opt builds, don't log to stderr unless the user specifically sets
378 // a preference to do so.
379 CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault,
380 "logToStdErr",
381 kCFStringEncodingUTF8);
382 CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
deadbeef37f5ecf2017-02-27 14:06:41 -0800383 if (key != nullptr && domain != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000384 Boolean exists_and_is_valid;
385 Boolean should_log =
386 CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
387 // If the key doesn't exist or is invalid or is false, we will not log to
388 // stderr.
389 log_to_stderr = exists_and_is_valid && should_log;
390 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800391 if (key != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000392 CFRelease(key);
393 }
Tommie51a0a82018-02-27 15:30:29 +0100394#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
395
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000396#if defined(WEBRTC_WIN)
397 // Always log to the debugger.
398 // Perhaps stderr should be controlled by a preference, as on Mac?
399 OutputDebugStringA(str.c_str());
400 if (log_to_stderr) {
401 // This handles dynamically allocated consoles, too.
402 if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
403 log_to_stderr = false;
404 DWORD written = 0;
405 ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
406 &written, 0);
407 }
408 }
Tommi0eefb4d2015-05-23 09:54:07 +0200409#endif // WEBRTC_WIN
Tommie51a0a82018-02-27 15:30:29 +0100410
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000411#if defined(WEBRTC_ANDROID)
412 // Android's logging facility uses severity to log messages but we
413 // need to map libjingle's severity levels to Android ones first.
414 // Also write to stderr which maybe available to executable started
415 // from the shell.
416 int prio;
417 switch (severity) {
418 case LS_SENSITIVE:
Tommie51a0a82018-02-27 15:30:29 +0100419 __android_log_write(ANDROID_LOG_INFO, tag, "SENSITIVE");
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000420 if (log_to_stderr) {
421 fprintf(stderr, "SENSITIVE");
422 fflush(stderr);
423 }
424 return;
425 case LS_VERBOSE:
426 prio = ANDROID_LOG_VERBOSE;
427 break;
428 case LS_INFO:
429 prio = ANDROID_LOG_INFO;
430 break;
431 case LS_WARNING:
432 prio = ANDROID_LOG_WARN;
433 break;
434 case LS_ERROR:
435 prio = ANDROID_LOG_ERROR;
436 break;
437 default:
438 prio = ANDROID_LOG_UNKNOWN;
439 }
440
441 int size = str.size();
442 int line = 0;
443 int idx = 0;
444 const int max_lines = size / kMaxLogLineSize + 1;
445 if (max_lines == 1) {
Tommie51a0a82018-02-27 15:30:29 +0100446 __android_log_print(prio, tag, "%.*s", size, str.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000447 } else {
448 while (size > 0) {
449 const int len = std::min(size, kMaxLogLineSize);
450 // Use the size of the string in the format (str may have \0 in the
451 // middle).
Tommie51a0a82018-02-27 15:30:29 +0100452 __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
453 str.c_str() + idx);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000454 idx += len;
455 size -= len;
456 ++line;
457 }
458 }
459#endif // WEBRTC_ANDROID
460 if (log_to_stderr) {
461 fprintf(stderr, "%s", str.c_str());
462 fflush(stderr);
463 }
464}
465
Tommifef05002018-02-27 13:51:08 +0100466// static
467bool LogMessage::IsNoop(LoggingSeverity severity) {
468 if (severity >= g_dbg_sev)
469 return false;
470
471 // TODO(tommi): We're grabbing this lock for every LogMessage instance that
472 // is going to be logged. This introduces unnecessary synchronization for
473 // a feature that's mostly used for testing.
474 CritScope cs(&g_log_crit);
475 return streams_.size() == 0;
476}
477
478void LogMessage::FinishPrintStream() {
479 if (is_noop_)
480 return;
481 if (!extra_.empty())
482 print_stream_ << " : " << extra_;
483 print_stream_ << std::endl;
484}
485
Karl Wibergcefc4652018-05-23 23:20:38 +0200486namespace webrtc_logging_impl {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000487
Karl Wibergcefc4652018-05-23 23:20:38 +0200488void Log(const LogArgType* fmt, ...) {
489 va_list args;
490 va_start(args, fmt);
491
492 LogMetadataErr meta;
493 const char* tag = nullptr;
494 switch (*fmt) {
495 case LogArgType::kLogMetadata: {
496 meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
497 break;
498 }
499 case LogArgType::kLogMetadataErr: {
500 meta = va_arg(args, LogMetadataErr);
501 break;
502 }
503#ifdef WEBRTC_ANDROID
504 case LogArgType::kLogMetadataTag: {
505 const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
506 meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
507 tag = tag_meta.tag;
508 break;
509 }
510#endif
511 default: {
512 RTC_NOTREACHED();
513 va_end(args);
514 return;
515 }
516 }
517 LogMessage log_message(meta.meta.File(), meta.meta.Line(),
518 meta.meta.Severity(), meta.err_ctx, meta.err);
519 if (tag) {
520 log_message.AddTag(tag);
521 }
522
523 for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
524 switch (*fmt) {
525 case LogArgType::kInt:
526 log_message.stream() << va_arg(args, int);
527 break;
528 case LogArgType::kLong:
529 log_message.stream() << va_arg(args, long);
530 break;
531 case LogArgType::kLongLong:
532 log_message.stream() << va_arg(args, long long);
533 break;
534 case LogArgType::kUInt:
535 log_message.stream() << va_arg(args, unsigned);
536 break;
537 case LogArgType::kULong:
538 log_message.stream() << va_arg(args, unsigned long);
539 break;
540 case LogArgType::kULongLong:
541 log_message.stream() << va_arg(args, unsigned long long);
542 break;
543 case LogArgType::kDouble:
544 log_message.stream() << va_arg(args, double);
545 break;
546 case LogArgType::kLongDouble:
547 log_message.stream() << va_arg(args, long double);
548 break;
549 case LogArgType::kCharP:
550 log_message.stream() << va_arg(args, const char*);
551 break;
552 case LogArgType::kStdString:
553 log_message.stream() << *va_arg(args, const std::string*);
554 break;
555 case LogArgType::kVoidP:
556 log_message.stream() << va_arg(args, const void*);
557 break;
558 default:
559 RTC_NOTREACHED();
560 va_end(args);
561 return;
562 }
563 }
564
565 va_end(args);
566}
567
568} // namespace webrtc_logging_impl
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000569} // namespace rtc