587 lines
17 KiB
C++
587 lines
17 KiB
C++
|
/*
|
||
|
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
|
||
|
*
|
||
|
* Use of this source code is governed by a BSD-style license
|
||
|
* that can be found in the LICENSE file in the root of the source
|
||
|
* tree. An additional intellectual property rights grant can be found
|
||
|
* in the file PATENTS. All contributing project authors may
|
||
|
* be found in the AUTHORS file in the root of the source tree.
|
||
|
*/
|
||
|
|
||
|
#include "rtc_base/logging.h"
|
||
|
|
||
|
#include <string.h>
|
||
|
|
||
|
#if RTC_LOG_ENABLED()
|
||
|
|
||
|
#if defined(WEBRTC_WIN)
|
||
|
#include <windows.h>
|
||
|
#if _MSC_VER < 1900
|
||
|
#define snprintf _snprintf
|
||
|
#endif
|
||
|
#undef ERROR // wingdi.h
|
||
|
#endif
|
||
|
|
||
|
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
|
||
|
#include <CoreServices/CoreServices.h>
|
||
|
#elif defined(WEBRTC_ANDROID)
|
||
|
#include <android/log.h>
|
||
|
|
||
|
// Android has a 1024 limit on log inputs. We use 60 chars as an
|
||
|
// approx for the header/tag portion.
|
||
|
// See android/system/core/liblog/logd_write.c
|
||
|
static const int kMaxLogLineSize = 1024 - 60;
|
||
|
#endif // WEBRTC_MAC && !defined(WEBRTC_IOS) || WEBRTC_ANDROID
|
||
|
|
||
|
#include <inttypes.h>
|
||
|
#include <stdio.h>
|
||
|
#include <time.h>
|
||
|
|
||
|
#include <algorithm>
|
||
|
#include <cstdarg>
|
||
|
#include <vector>
|
||
|
|
||
|
#include "absl/base/attributes.h"
|
||
|
#include "absl/strings/string_view.h"
|
||
|
#include "api/units/timestamp.h"
|
||
|
#include "rtc_base/checks.h"
|
||
|
#include "rtc_base/platform_thread_types.h"
|
||
|
#include "rtc_base/string_encode.h"
|
||
|
#include "rtc_base/string_utils.h"
|
||
|
#include "rtc_base/strings/string_builder.h"
|
||
|
#include "rtc_base/synchronization/mutex.h"
|
||
|
#include "rtc_base/thread_annotations.h"
|
||
|
#include "rtc_base/time_utils.h"
|
||
|
|
||
|
namespace rtc {
|
||
|
namespace {
|
||
|
|
||
|
// By default, release builds don't log, debug builds at info level
|
||
|
#if !defined(NDEBUG)
|
||
|
constexpr LoggingSeverity kDefaultLoggingSeverity = LS_INFO;
|
||
|
#else
|
||
|
constexpr LoggingSeverity kDefaultLoggingSeverity = LS_NONE;
|
||
|
#endif
|
||
|
|
||
|
// Note: `g_min_sev` and `g_dbg_sev` can be changed while running.
|
||
|
LoggingSeverity g_min_sev = kDefaultLoggingSeverity;
|
||
|
LoggingSeverity g_dbg_sev = kDefaultLoggingSeverity;
|
||
|
|
||
|
// Return the filename portion of the string (that following the last slash).
|
||
|
const char* FilenameFromPath(const char* file) {
|
||
|
const char* end1 = ::strrchr(file, '/');
|
||
|
const char* end2 = ::strrchr(file, '\\');
|
||
|
if (!end1 && !end2)
|
||
|
return file;
|
||
|
else
|
||
|
return (end1 > end2) ? end1 + 1 : end2 + 1;
|
||
|
}
|
||
|
|
||
|
// Global lock for log subsystem, only needed to serialize access to streams_.
|
||
|
webrtc::Mutex& GetLoggingLock() {
|
||
|
static webrtc::Mutex& mutex = *new webrtc::Mutex();
|
||
|
return mutex;
|
||
|
}
|
||
|
|
||
|
} // namespace
|
||
|
|
||
|
std::string LogLineRef::DefaultLogLine() const {
|
||
|
rtc::StringBuilder log_output;
|
||
|
if (timestamp_ != webrtc::Timestamp::MinusInfinity()) {
|
||
|
// TODO(kwiberg): Switch to absl::StrFormat, if binary size is ok.
|
||
|
char timestamp[50]; // Maximum string length of an int64_t is 20.
|
||
|
int len =
|
||
|
snprintf(timestamp, sizeof(timestamp), "[%03" PRId64 ":%03" PRId64 "]",
|
||
|
timestamp_.ms() / 1000, timestamp_.ms() % 1000);
|
||
|
RTC_DCHECK_LT(len, sizeof(timestamp));
|
||
|
log_output << timestamp;
|
||
|
}
|
||
|
if (thread_id_.has_value()) {
|
||
|
log_output << "[" << *thread_id_ << "] ";
|
||
|
}
|
||
|
if (!filename_.empty()) {
|
||
|
#if defined(WEBRTC_ANDROID)
|
||
|
log_output << "(line " << line_ << "): ";
|
||
|
#else
|
||
|
log_output << "(" << filename_ << ":" << line_ << "): ";
|
||
|
#endif
|
||
|
}
|
||
|
log_output << message_;
|
||
|
return log_output.Release();
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// LogMessage
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
bool LogMessage::log_to_stderr_ = true;
|
||
|
|
||
|
// The list of logging streams currently configured.
|
||
|
// Note: we explicitly do not clean this up, because of the uncertain ordering
|
||
|
// of destructors at program exit. Let the person who sets the stream trigger
|
||
|
// cleanup by setting to null, or let it leak (safe at program exit).
|
||
|
ABSL_CONST_INIT LogSink* LogMessage::streams_ RTC_GUARDED_BY(GetLoggingLock()) =
|
||
|
nullptr;
|
||
|
ABSL_CONST_INIT std::atomic<bool> LogMessage::streams_empty_ = {true};
|
||
|
|
||
|
// Boolean options default to false.
|
||
|
ABSL_CONST_INIT bool LogMessage::log_thread_ = false;
|
||
|
ABSL_CONST_INIT bool LogMessage::log_timestamp_ = false;
|
||
|
|
||
|
LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
|
||
|
: LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
|
||
|
|
||
|
LogMessage::LogMessage(const char* file,
|
||
|
int line,
|
||
|
LoggingSeverity sev,
|
||
|
LogErrorContext err_ctx,
|
||
|
int err) {
|
||
|
log_line_.set_severity(sev);
|
||
|
if (log_timestamp_) {
|
||
|
int64_t log_start_time = LogStartTime();
|
||
|
// Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
|
||
|
// in log messages represents the real system time.
|
||
|
int64_t time = TimeDiff(SystemTimeMillis(), log_start_time);
|
||
|
// Also ensure WallClockStartTime is initialized, so that it matches
|
||
|
// LogStartTime.
|
||
|
WallClockStartTime();
|
||
|
log_line_.set_timestamp(webrtc::Timestamp::Millis(time));
|
||
|
}
|
||
|
|
||
|
if (log_thread_) {
|
||
|
log_line_.set_thread_id(CurrentThreadId());
|
||
|
}
|
||
|
|
||
|
if (file != nullptr) {
|
||
|
log_line_.set_filename(FilenameFromPath(file));
|
||
|
log_line_.set_line(line);
|
||
|
#if defined(WEBRTC_ANDROID)
|
||
|
log_line_.set_tag(log_line_.filename());
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
if (err_ctx != ERRCTX_NONE) {
|
||
|
char tmp_buf[1024];
|
||
|
SimpleStringBuilder tmp(tmp_buf);
|
||
|
tmp.AppendFormat("[0x%08X]", err);
|
||
|
switch (err_ctx) {
|
||
|
case ERRCTX_ERRNO:
|
||
|
tmp << " " << strerror(err);
|
||
|
break;
|
||
|
#ifdef WEBRTC_WIN
|
||
|
case ERRCTX_HRESULT: {
|
||
|
char msgbuf[256];
|
||
|
DWORD flags =
|
||
|
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
|
||
|
if (DWORD len = FormatMessageA(
|
||
|
flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||
|
msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
|
||
|
while ((len > 0) &&
|
||
|
isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
|
||
|
msgbuf[--len] = 0;
|
||
|
}
|
||
|
tmp << " " << msgbuf;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
#endif // WEBRTC_WIN
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
extra_ = tmp.str();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if defined(WEBRTC_ANDROID)
|
||
|
LogMessage::LogMessage(const char* file,
|
||
|
int line,
|
||
|
LoggingSeverity sev,
|
||
|
const char* tag)
|
||
|
: LogMessage(file, line, sev, ERRCTX_NONE, /*err=*/0) {
|
||
|
log_line_.set_tag(tag);
|
||
|
print_stream_ << tag << ": ";
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
LogMessage::~LogMessage() {
|
||
|
FinishPrintStream();
|
||
|
|
||
|
log_line_.set_message(print_stream_.Release());
|
||
|
|
||
|
if (log_line_.severity() >= g_dbg_sev) {
|
||
|
OutputToDebug(log_line_);
|
||
|
}
|
||
|
|
||
|
webrtc::MutexLock lock(&GetLoggingLock());
|
||
|
for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
|
||
|
if (log_line_.severity() >= entry->min_severity_) {
|
||
|
entry->OnLogMessage(log_line_);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void LogMessage::AddTag(const char* tag) {
|
||
|
#ifdef WEBRTC_ANDROID
|
||
|
log_line_.set_tag(tag);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
rtc::StringBuilder& LogMessage::stream() {
|
||
|
return print_stream_;
|
||
|
}
|
||
|
|
||
|
int LogMessage::GetMinLogSeverity() {
|
||
|
return g_min_sev;
|
||
|
}
|
||
|
|
||
|
LoggingSeverity LogMessage::GetLogToDebug() {
|
||
|
return g_dbg_sev;
|
||
|
}
|
||
|
int64_t LogMessage::LogStartTime() {
|
||
|
static const int64_t g_start = SystemTimeMillis();
|
||
|
return g_start;
|
||
|
}
|
||
|
|
||
|
uint32_t LogMessage::WallClockStartTime() {
|
||
|
static const uint32_t g_start_wallclock = time(nullptr);
|
||
|
return g_start_wallclock;
|
||
|
}
|
||
|
|
||
|
void LogMessage::LogThreads(bool on) {
|
||
|
log_thread_ = on;
|
||
|
}
|
||
|
|
||
|
void LogMessage::LogTimestamps(bool on) {
|
||
|
log_timestamp_ = on;
|
||
|
}
|
||
|
|
||
|
void LogMessage::LogToDebug(LoggingSeverity min_sev) {
|
||
|
g_dbg_sev = min_sev;
|
||
|
webrtc::MutexLock lock(&GetLoggingLock());
|
||
|
UpdateMinLogSeverity();
|
||
|
}
|
||
|
|
||
|
void LogMessage::SetLogToStderr(bool log_to_stderr) {
|
||
|
log_to_stderr_ = log_to_stderr;
|
||
|
}
|
||
|
|
||
|
int LogMessage::GetLogToStream(LogSink* stream) {
|
||
|
webrtc::MutexLock lock(&GetLoggingLock());
|
||
|
LoggingSeverity sev = LS_NONE;
|
||
|
for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
|
||
|
if (stream == nullptr || stream == entry) {
|
||
|
sev = std::min(sev, entry->min_severity_);
|
||
|
}
|
||
|
}
|
||
|
return sev;
|
||
|
}
|
||
|
|
||
|
void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
|
||
|
webrtc::MutexLock lock(&GetLoggingLock());
|
||
|
stream->min_severity_ = min_sev;
|
||
|
stream->next_ = streams_;
|
||
|
streams_ = stream;
|
||
|
streams_empty_.store(false, std::memory_order_relaxed);
|
||
|
UpdateMinLogSeverity();
|
||
|
}
|
||
|
|
||
|
void LogMessage::RemoveLogToStream(LogSink* stream) {
|
||
|
webrtc::MutexLock lock(&GetLoggingLock());
|
||
|
for (LogSink** entry = &streams_; *entry != nullptr;
|
||
|
entry = &(*entry)->next_) {
|
||
|
if (*entry == stream) {
|
||
|
*entry = (*entry)->next_;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
streams_empty_.store(streams_ == nullptr, std::memory_order_relaxed);
|
||
|
UpdateMinLogSeverity();
|
||
|
}
|
||
|
|
||
|
void LogMessage::ConfigureLogging(absl::string_view params) {
|
||
|
LoggingSeverity current_level = LS_VERBOSE;
|
||
|
LoggingSeverity debug_level = GetLogToDebug();
|
||
|
|
||
|
std::vector<std::string> tokens;
|
||
|
tokenize(params, ' ', &tokens);
|
||
|
|
||
|
for (const std::string& token : tokens) {
|
||
|
if (token.empty())
|
||
|
continue;
|
||
|
|
||
|
// Logging features
|
||
|
if (token == "tstamp") {
|
||
|
LogTimestamps();
|
||
|
} else if (token == "thread") {
|
||
|
LogThreads();
|
||
|
|
||
|
// Logging levels
|
||
|
} else if (token == "verbose") {
|
||
|
current_level = LS_VERBOSE;
|
||
|
} else if (token == "info") {
|
||
|
current_level = LS_INFO;
|
||
|
} else if (token == "warning") {
|
||
|
current_level = LS_WARNING;
|
||
|
} else if (token == "error") {
|
||
|
current_level = LS_ERROR;
|
||
|
} else if (token == "none") {
|
||
|
current_level = LS_NONE;
|
||
|
|
||
|
// Logging targets
|
||
|
} else if (token == "debug") {
|
||
|
debug_level = current_level;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if defined(WEBRTC_WIN) && !defined(WINUWP)
|
||
|
if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
|
||
|
// First, attempt to attach to our parent's console... so if you invoke
|
||
|
// from the command line, we'll see the output there. Otherwise, create
|
||
|
// our own console window.
|
||
|
// Note: These methods fail if a console already exists, which is fine.
|
||
|
if (!AttachConsole(ATTACH_PARENT_PROCESS))
|
||
|
::AllocConsole();
|
||
|
}
|
||
|
#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
|
||
|
|
||
|
LogToDebug(debug_level);
|
||
|
}
|
||
|
|
||
|
void LogMessage::UpdateMinLogSeverity()
|
||
|
RTC_EXCLUSIVE_LOCKS_REQUIRED(GetLoggingLock()) {
|
||
|
LoggingSeverity min_sev = g_dbg_sev;
|
||
|
for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
|
||
|
min_sev = std::min(min_sev, entry->min_severity_);
|
||
|
}
|
||
|
g_min_sev = min_sev;
|
||
|
}
|
||
|
|
||
|
void LogMessage::OutputToDebug(const LogLineRef& log_line) {
|
||
|
std::string msg_str = log_line.DefaultLogLine();
|
||
|
bool log_to_stderr = log_to_stderr_;
|
||
|
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
|
||
|
// On the Mac, all stderr output goes to the Console log and causes clutter.
|
||
|
// So in opt builds, don't log to stderr unless the user specifically sets
|
||
|
// a preference to do so.
|
||
|
CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
|
||
|
if (domain != nullptr) {
|
||
|
Boolean exists_and_is_valid;
|
||
|
Boolean should_log = CFPreferencesGetAppBooleanValue(
|
||
|
CFSTR("logToStdErr"), domain, &exists_and_is_valid);
|
||
|
// If the key doesn't exist or is invalid or is false, we will not log to
|
||
|
// stderr.
|
||
|
log_to_stderr = exists_and_is_valid && should_log;
|
||
|
}
|
||
|
#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
|
||
|
|
||
|
#if defined(WEBRTC_WIN)
|
||
|
// Always log to the debugger.
|
||
|
// Perhaps stderr should be controlled by a preference, as on Mac?
|
||
|
OutputDebugStringA(msg_str.c_str());
|
||
|
if (log_to_stderr) {
|
||
|
// This handles dynamically allocated consoles, too.
|
||
|
if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
|
||
|
log_to_stderr = false;
|
||
|
DWORD written = 0;
|
||
|
::WriteFile(error_handle, msg_str.c_str(),
|
||
|
static_cast<DWORD>(msg_str.size()), &written, 0);
|
||
|
}
|
||
|
}
|
||
|
#endif // WEBRTC_WIN
|
||
|
|
||
|
#if defined(WEBRTC_ANDROID)
|
||
|
// Android's logging facility uses severity to log messages but we
|
||
|
// need to map libjingle's severity levels to Android ones first.
|
||
|
// Also write to stderr which maybe available to executable started
|
||
|
// from the shell.
|
||
|
int prio;
|
||
|
switch (log_line.severity()) {
|
||
|
case LS_VERBOSE:
|
||
|
prio = ANDROID_LOG_VERBOSE;
|
||
|
break;
|
||
|
case LS_INFO:
|
||
|
prio = ANDROID_LOG_INFO;
|
||
|
break;
|
||
|
case LS_WARNING:
|
||
|
prio = ANDROID_LOG_WARN;
|
||
|
break;
|
||
|
case LS_ERROR:
|
||
|
prio = ANDROID_LOG_ERROR;
|
||
|
break;
|
||
|
default:
|
||
|
prio = ANDROID_LOG_UNKNOWN;
|
||
|
}
|
||
|
|
||
|
int size = msg_str.size();
|
||
|
int current_line = 0;
|
||
|
int idx = 0;
|
||
|
const int max_lines = size / kMaxLogLineSize + 1;
|
||
|
if (max_lines == 1) {
|
||
|
__android_log_print(prio, log_line.tag().data(), "%.*s", size,
|
||
|
msg_str.c_str());
|
||
|
} else {
|
||
|
while (size > 0) {
|
||
|
const int len = std::min(size, kMaxLogLineSize);
|
||
|
// Use the size of the string in the format (msg may have \0 in the
|
||
|
// middle).
|
||
|
__android_log_print(prio, log_line.tag().data(), "[%d/%d] %.*s",
|
||
|
current_line + 1, max_lines, len,
|
||
|
msg_str.c_str() + idx);
|
||
|
idx += len;
|
||
|
size -= len;
|
||
|
++current_line;
|
||
|
}
|
||
|
}
|
||
|
#endif // WEBRTC_ANDROID
|
||
|
if (log_to_stderr) {
|
||
|
fprintf(stderr, "%s", msg_str.c_str());
|
||
|
fflush(stderr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// static
|
||
|
bool LogMessage::IsNoop(LoggingSeverity severity) {
|
||
|
if (severity >= g_dbg_sev || severity >= g_min_sev)
|
||
|
return false;
|
||
|
return streams_empty_.load(std::memory_order_relaxed);
|
||
|
}
|
||
|
|
||
|
void LogMessage::FinishPrintStream() {
|
||
|
if (!extra_.empty())
|
||
|
print_stream_ << " : " << extra_;
|
||
|
print_stream_ << "\n";
|
||
|
}
|
||
|
|
||
|
namespace webrtc_logging_impl {
|
||
|
|
||
|
void Log(const LogArgType* fmt, ...) {
|
||
|
va_list args;
|
||
|
va_start(args, fmt);
|
||
|
|
||
|
LogMetadataErr meta;
|
||
|
const char* tag = nullptr;
|
||
|
switch (*fmt) {
|
||
|
case LogArgType::kLogMetadata: {
|
||
|
meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
|
||
|
break;
|
||
|
}
|
||
|
case LogArgType::kLogMetadataErr: {
|
||
|
meta = va_arg(args, LogMetadataErr);
|
||
|
break;
|
||
|
}
|
||
|
#ifdef WEBRTC_ANDROID
|
||
|
case LogArgType::kLogMetadataTag: {
|
||
|
const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
|
||
|
meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
|
||
|
tag = tag_meta.tag;
|
||
|
break;
|
||
|
}
|
||
|
#endif
|
||
|
default: {
|
||
|
RTC_DCHECK_NOTREACHED();
|
||
|
va_end(args);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LogMessage log_message(meta.meta.File(), meta.meta.Line(),
|
||
|
meta.meta.Severity(), meta.err_ctx, meta.err);
|
||
|
if (tag) {
|
||
|
log_message.AddTag(tag);
|
||
|
}
|
||
|
|
||
|
for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
|
||
|
switch (*fmt) {
|
||
|
case LogArgType::kInt:
|
||
|
log_message.stream() << va_arg(args, int);
|
||
|
break;
|
||
|
case LogArgType::kLong:
|
||
|
log_message.stream() << va_arg(args, long);
|
||
|
break;
|
||
|
case LogArgType::kLongLong:
|
||
|
log_message.stream() << va_arg(args, long long);
|
||
|
break;
|
||
|
case LogArgType::kUInt:
|
||
|
log_message.stream() << va_arg(args, unsigned);
|
||
|
break;
|
||
|
case LogArgType::kULong:
|
||
|
log_message.stream() << va_arg(args, unsigned long);
|
||
|
break;
|
||
|
case LogArgType::kULongLong:
|
||
|
log_message.stream() << va_arg(args, unsigned long long);
|
||
|
break;
|
||
|
case LogArgType::kDouble:
|
||
|
log_message.stream() << va_arg(args, double);
|
||
|
break;
|
||
|
case LogArgType::kLongDouble:
|
||
|
log_message.stream() << va_arg(args, long double);
|
||
|
break;
|
||
|
case LogArgType::kCharP: {
|
||
|
const char* s = va_arg(args, const char*);
|
||
|
log_message.stream() << (s ? s : "(null)");
|
||
|
break;
|
||
|
}
|
||
|
case LogArgType::kStdString:
|
||
|
log_message.stream() << *va_arg(args, const std::string*);
|
||
|
break;
|
||
|
case LogArgType::kStringView:
|
||
|
log_message.stream() << *va_arg(args, const absl::string_view*);
|
||
|
break;
|
||
|
case LogArgType::kVoidP:
|
||
|
log_message.stream() << rtc::ToHex(
|
||
|
reinterpret_cast<uintptr_t>(va_arg(args, const void*)));
|
||
|
break;
|
||
|
default:
|
||
|
RTC_DCHECK_NOTREACHED();
|
||
|
va_end(args);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
va_end(args);
|
||
|
}
|
||
|
|
||
|
} // namespace webrtc_logging_impl
|
||
|
} // namespace rtc
|
||
|
#endif
|
||
|
|
||
|
namespace rtc {
|
||
|
// Default implementation, override is recomended.
|
||
|
void LogSink::OnLogMessage(const LogLineRef& log_line) {
|
||
|
#if defined(WEBRTC_ANDROID)
|
||
|
OnLogMessage(log_line.DefaultLogLine(), log_line.severity(),
|
||
|
log_line.tag().data());
|
||
|
#else
|
||
|
OnLogMessage(log_line.DefaultLogLine(), log_line.severity());
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// Inefficient default implementation, override is recommended.
|
||
|
void LogSink::OnLogMessage(const std::string& msg,
|
||
|
LoggingSeverity severity,
|
||
|
const char* tag) {
|
||
|
OnLogMessage(tag + (": " + msg), severity);
|
||
|
}
|
||
|
|
||
|
void LogSink::OnLogMessage(const std::string& msg,
|
||
|
LoggingSeverity /* severity */) {
|
||
|
OnLogMessage(msg);
|
||
|
}
|
||
|
|
||
|
// Inefficient default implementation, override is recommended.
|
||
|
void LogSink::OnLogMessage(absl::string_view msg,
|
||
|
LoggingSeverity severity,
|
||
|
const char* tag) {
|
||
|
OnLogMessage(tag + (": " + std::string(msg)), severity);
|
||
|
}
|
||
|
|
||
|
void LogSink::OnLogMessage(absl::string_view msg,
|
||
|
LoggingSeverity /* severity */) {
|
||
|
OnLogMessage(msg);
|
||
|
}
|
||
|
|
||
|
void LogSink::OnLogMessage(absl::string_view msg) {
|
||
|
OnLogMessage(std::string(msg));
|
||
|
}
|
||
|
} // namespace rtc
|