LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/base - logging.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 2 214 0.9 %
Date: 2017-07-14 16:53:18 Functions: 0 19 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       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)
      12             : #if !defined(WIN32_LEAN_AND_MEAN)
      13             : #define WIN32_LEAN_AND_MEAN
      14             : #endif
      15             : #include <windows.h>
      16             : #if _MSC_VER < 1900
      17             : #define snprintf _snprintf
      18             : #endif
      19             : #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>
      26             : // 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
      29             : static const int kMaxLogLineSize = 1024 - 60;
      30             : #endif  // WEBRTC_MAC && !defined(WEBRTC_IOS) || WEBRTC_ANDROID
      31             : 
      32             : static const char kLibjingle[] = "libjingle";
      33             : 
      34             : #include <time.h>
      35             : #include <limits.h>
      36             : 
      37             : #include <algorithm>
      38             : #include <iomanip>
      39             : #include <ostream>
      40             : #include <vector>
      41             : 
      42             : #include "webrtc/base/criticalsection.h"
      43             : #include "webrtc/base/logging.h"
      44             : #include "webrtc/base/platform_thread.h"
      45             : #include "webrtc/base/stringencode.h"
      46             : #include "webrtc/base/stringutils.h"
      47             : #include "webrtc/base/timeutils.h"
      48             : 
      49             : namespace rtc {
      50             : namespace {
      51             : 
      52             : // Return the filename portion of the string (that following the last slash).
      53           0 : const char* FilenameFromPath(const char* file) {
      54           0 :   const char* end1 = ::strrchr(file, '/');
      55           0 :   const char* end2 = ::strrchr(file, '\\');
      56           0 :   if (!end1 && !end2)
      57           0 :     return file;
      58             :   else
      59           0 :     return (end1 > end2) ? end1 + 1 : end2 + 1;
      60             : }
      61             : 
      62             : }  // namespace
      63             : 
      64             : /////////////////////////////////////////////////////////////////////////////
      65             : // Constant Labels
      66             : /////////////////////////////////////////////////////////////////////////////
      67             : 
      68           0 : const char* FindLabel(int value, const ConstantLabel entries[]) {
      69           0 :   for (int i = 0; entries[i].label; ++i) {
      70           0 :     if (value == entries[i].value) {
      71           0 :       return entries[i].label;
      72             :     }
      73             :   }
      74           0 :   return 0;
      75             : }
      76             : 
      77           0 : std::string ErrorName(int err, const ConstantLabel* err_table) {
      78           0 :   if (err == 0)
      79           0 :     return "No error";
      80             : 
      81           0 :   if (err_table != 0) {
      82           0 :     if (const char* value = FindLabel(err, err_table))
      83           0 :       return value;
      84             :   }
      85             : 
      86             :   char buffer[16];
      87           0 :   snprintf(buffer, sizeof(buffer), "0x%08x", err);
      88           0 :   return buffer;
      89             : }
      90             : 
      91             : /////////////////////////////////////////////////////////////////////////////
      92             : // LogMessage
      93             : /////////////////////////////////////////////////////////////////////////////
      94             : 
      95             : // By default, release builds don't log, debug builds at info level
      96             : #if !defined(NDEBUG)
      97             : LoggingSeverity LogMessage::min_sev_ = LS_INFO;
      98             : LoggingSeverity LogMessage::dbg_sev_ = LS_INFO;
      99             : #else
     100             : LoggingSeverity LogMessage::min_sev_ = LS_NONE;
     101             : LoggingSeverity LogMessage::dbg_sev_ = LS_NONE;
     102             : #endif
     103             : bool LogMessage::log_to_stderr_ = true;
     104             : 
     105             : namespace {
     106             : // Global lock for log subsystem, only needed to serialize access to streams_.
     107           3 : CriticalSection g_log_crit;
     108             : }  // namespace
     109             : 
     110             : // The list of logging streams currently configured.
     111             : // Note: we explicitly do not clean this up, because of the uncertain ordering
     112             : // of destructors at program exit.  Let the person who sets the stream trigger
     113             : // cleanup by setting to NULL, or let it leak (safe at program exit).
     114           3 : LogMessage::StreamList LogMessage::streams_ GUARDED_BY(g_log_crit);
     115             : 
     116             : // Boolean options default to false (0)
     117             : bool LogMessage::thread_, LogMessage::timestamp_;
     118             : 
     119           0 : LogMessage::LogMessage(const char* file,
     120             :                        int line,
     121             :                        LoggingSeverity sev,
     122             :                        LogErrorContext err_ctx,
     123             :                        int err,
     124           0 :                        const char* module)
     125           0 :     : severity_(sev), tag_(kLibjingle) {
     126           0 :   if (timestamp_) {
     127             :     // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
     128             :     // in log messages represents the real system time.
     129           0 :     int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime());
     130             :     // Also ensure WallClockStartTime is initialized, so that it matches
     131             :     // LogStartTime.
     132           0 :     WallClockStartTime();
     133           0 :     print_stream_ << "[" << std::setfill('0') << std::setw(3) << (time / 1000)
     134           0 :                   << ":" << std::setw(3) << (time % 1000) << std::setfill(' ')
     135           0 :                   << "] ";
     136             :   }
     137             : 
     138           0 :   if (thread_) {
     139           0 :     PlatformThreadId id = CurrentThreadId();
     140           0 :     print_stream_ << "[" << std::dec << id << "] ";
     141             :   }
     142             : 
     143           0 :   if (file != NULL)
     144           0 :     print_stream_ << "(" << FilenameFromPath(file)  << ":" << line << "): ";
     145             : 
     146           0 :   if (err_ctx != ERRCTX_NONE) {
     147           0 :     std::ostringstream tmp;
     148           0 :     tmp << "[0x" << std::setfill('0') << std::hex << std::setw(8) << err << "]";
     149           0 :     switch (err_ctx) {
     150             :       case ERRCTX_ERRNO:
     151           0 :         tmp << " " << strerror(err);
     152           0 :         break;
     153             : #ifdef WEBRTC_WIN
     154             :       case ERRCTX_HRESULT: {
     155             :         char msgbuf[256];
     156             :         DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM;
     157             :         HMODULE hmod = GetModuleHandleA(module);
     158             :         if (hmod)
     159             :           flags |= FORMAT_MESSAGE_FROM_HMODULE;
     160             :         if (DWORD len = FormatMessageA(
     161             :             flags, hmod, err,
     162             :             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
     163             :             msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), NULL)) {
     164             :           while ((len > 0) &&
     165             :               isspace(static_cast<unsigned char>(msgbuf[len-1]))) {
     166             :             msgbuf[--len] = 0;
     167             :           }
     168             :           tmp << " " << msgbuf;
     169             :         }
     170             :         break;
     171             :       }
     172             : #endif  // WEBRTC_WIN
     173             : #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
     174             :       case ERRCTX_OSSTATUS: {
     175             :         std::string desc(DescriptionFromOSStatus(err));
     176             :         tmp << " " << (desc.empty() ? "Unknown error" : desc.c_str());
     177             :         break;
     178             :       }
     179             : #endif  // WEBRTC_MAC && !defined(WEBRTC_IOS)
     180             :       default:
     181           0 :         break;
     182             :     }
     183           0 :     extra_ = tmp.str();
     184             :   }
     185           0 : }
     186             : 
     187           0 : LogMessage::LogMessage(const char* file,
     188             :                        int line,
     189             :                        LoggingSeverity sev,
     190           0 :                        const std::string& tag)
     191           0 :     : LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */, NULL /* module */) {
     192           0 :   tag_ = tag;
     193           0 :   print_stream_ << tag << ": ";
     194           0 : }
     195             : 
     196           0 : LogMessage::~LogMessage() {
     197           0 :   if (!extra_.empty())
     198           0 :     print_stream_ << " : " << extra_;
     199           0 :   print_stream_ << std::endl;
     200             : 
     201           0 :   const std::string& str = print_stream_.str();
     202           0 :   if (severity_ >= dbg_sev_) {
     203           0 :     OutputToDebug(str, severity_, tag_);
     204             :   }
     205             : 
     206           0 :   CritScope cs(&g_log_crit);
     207           0 :   for (auto& kv : streams_) {
     208           0 :     if (severity_ >= kv.second) {
     209           0 :       kv.first->OnLogMessage(str);
     210             :     }
     211             :   }
     212           0 : }
     213             : 
     214           0 : int64_t LogMessage::LogStartTime() {
     215           0 :   static const int64_t g_start = SystemTimeMillis();
     216           0 :   return g_start;
     217             : }
     218             : 
     219           0 : uint32_t LogMessage::WallClockStartTime() {
     220           0 :   static const uint32_t g_start_wallclock = time(NULL);
     221           0 :   return g_start_wallclock;
     222             : }
     223             : 
     224           0 : void LogMessage::LogThreads(bool on) {
     225           0 :   thread_ = on;
     226           0 : }
     227             : 
     228           0 : void LogMessage::LogTimestamps(bool on) {
     229           0 :   timestamp_ = on;
     230           0 : }
     231             : 
     232           0 : void LogMessage::LogToDebug(LoggingSeverity min_sev) {
     233           0 :   dbg_sev_ = min_sev;
     234           0 :   CritScope cs(&g_log_crit);
     235           0 :   UpdateMinLogSeverity();
     236           0 : }
     237             : 
     238           0 : void LogMessage::SetLogToStderr(bool log_to_stderr) {
     239           0 :   log_to_stderr_ = log_to_stderr;
     240           0 : }
     241             : 
     242           0 : int LogMessage::GetLogToStream(LogSink* stream) {
     243           0 :   CritScope cs(&g_log_crit);
     244           0 :   LoggingSeverity sev = LS_NONE;
     245           0 :   for (auto& kv : streams_) {
     246           0 :     if (!stream || stream == kv.first) {
     247           0 :       sev = std::min(sev, kv.second);
     248             :     }
     249             :   }
     250           0 :   return sev;
     251             : }
     252             : 
     253           0 : void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
     254           0 :   CritScope cs(&g_log_crit);
     255           0 :   streams_.push_back(std::make_pair(stream, min_sev));
     256           0 :   UpdateMinLogSeverity();
     257           0 : }
     258             : 
     259           0 : void LogMessage::RemoveLogToStream(LogSink* stream) {
     260           0 :   CritScope cs(&g_log_crit);
     261           0 :   for (StreamList::iterator it = streams_.begin(); it != streams_.end(); ++it) {
     262           0 :     if (stream == it->first) {
     263           0 :       streams_.erase(it);
     264           0 :       break;
     265             :     }
     266             :   }
     267           0 :   UpdateMinLogSeverity();
     268           0 : }
     269             : 
     270           0 : void LogMessage::ConfigureLogging(const char* params) {
     271           0 :   LoggingSeverity current_level = LS_VERBOSE;
     272           0 :   LoggingSeverity debug_level = GetLogToDebug();
     273             : 
     274           0 :   std::vector<std::string> tokens;
     275           0 :   tokenize(params, ' ', &tokens);
     276             : 
     277           0 :   for (const std::string& token : tokens) {
     278           0 :     if (token.empty())
     279           0 :       continue;
     280             : 
     281             :     // Logging features
     282           0 :     if (token == "tstamp") {
     283           0 :       LogTimestamps();
     284           0 :     } else if (token == "thread") {
     285           0 :       LogThreads();
     286             : 
     287             :     // Logging levels
     288           0 :     } else if (token == "sensitive") {
     289           0 :       current_level = LS_SENSITIVE;
     290           0 :     } else if (token == "verbose") {
     291           0 :       current_level = LS_VERBOSE;
     292           0 :     } else if (token == "info") {
     293           0 :       current_level = LS_INFO;
     294           0 :     } else if (token == "warning") {
     295           0 :       current_level = LS_WARNING;
     296           0 :     } else if (token == "error") {
     297           0 :       current_level = LS_ERROR;
     298           0 :     } else if (token == "none") {
     299           0 :       current_level = LS_NONE;
     300             : 
     301             :     // Logging targets
     302           0 :     } else if (token == "debug") {
     303           0 :       debug_level = current_level;
     304             :     }
     305             :   }
     306             : 
     307             : #if defined(WEBRTC_WIN)
     308             :   if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
     309             :     // First, attempt to attach to our parent's console... so if you invoke
     310             :     // from the command line, we'll see the output there.  Otherwise, create
     311             :     // our own console window.
     312             :     // Note: These methods fail if a console already exists, which is fine.
     313             :     bool success = false;
     314             :     typedef BOOL (WINAPI* PFN_AttachConsole)(DWORD);
     315             :     if (HINSTANCE kernel32 = ::LoadLibrary(L"kernel32.dll")) {
     316             :       // AttachConsole is defined on WinXP+.
     317             :       if (PFN_AttachConsole attach_console = reinterpret_cast<PFN_AttachConsole>
     318             :             (::GetProcAddress(kernel32, "AttachConsole"))) {
     319             :         success = (FALSE != attach_console(ATTACH_PARENT_PROCESS));
     320             :       }
     321             :       ::FreeLibrary(kernel32);
     322             :     }
     323             :     if (!success) {
     324             :       ::AllocConsole();
     325             :     }
     326             :   }
     327             : #endif  // WEBRTC_WIN
     328             : 
     329           0 :   LogToDebug(debug_level);
     330           0 : }
     331             : 
     332           0 : void LogMessage::UpdateMinLogSeverity() EXCLUSIVE_LOCKS_REQUIRED(g_log_crit) {
     333           0 :   LoggingSeverity min_sev = dbg_sev_;
     334           0 :   for (auto& kv : streams_) {
     335           0 :     min_sev = std::min(dbg_sev_, kv.second);
     336             :   }
     337           0 :   min_sev_ = min_sev;
     338           0 : }
     339             : 
     340           0 : void LogMessage::OutputToDebug(const std::string& str,
     341             :                                LoggingSeverity severity,
     342             :                                const std::string& tag) {
     343           0 :   bool log_to_stderr = log_to_stderr_;
     344             : #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
     345             :   // On the Mac, all stderr output goes to the Console log and causes clutter.
     346             :   // So in opt builds, don't log to stderr unless the user specifically sets
     347             :   // a preference to do so.
     348             :   CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault,
     349             :                                               "logToStdErr",
     350             :                                               kCFStringEncodingUTF8);
     351             :   CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
     352             :   if (key != NULL && domain != NULL) {
     353             :     Boolean exists_and_is_valid;
     354             :     Boolean should_log =
     355             :         CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
     356             :     // If the key doesn't exist or is invalid or is false, we will not log to
     357             :     // stderr.
     358             :     log_to_stderr = exists_and_is_valid && should_log;
     359             :   }
     360             :   if (key != NULL) {
     361             :     CFRelease(key);
     362             :   }
     363             : #endif
     364             : #if defined(WEBRTC_WIN)
     365             :   // Always log to the debugger.
     366             :   // Perhaps stderr should be controlled by a preference, as on Mac?
     367             :   OutputDebugStringA(str.c_str());
     368             :   if (log_to_stderr) {
     369             :     // This handles dynamically allocated consoles, too.
     370             :     if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
     371             :       log_to_stderr = false;
     372             :       DWORD written = 0;
     373             :       ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
     374             :                   &written, 0);
     375             :     }
     376             :   }
     377             : #endif  // WEBRTC_WIN
     378             : #if defined(WEBRTC_ANDROID)
     379             :   // Android's logging facility uses severity to log messages but we
     380             :   // need to map libjingle's severity levels to Android ones first.
     381             :   // Also write to stderr which maybe available to executable started
     382             :   // from the shell.
     383             :   int prio;
     384             :   switch (severity) {
     385             :     case LS_SENSITIVE:
     386             :       __android_log_write(ANDROID_LOG_INFO, tag.c_str(), "SENSITIVE");
     387             :       if (log_to_stderr) {
     388             :         fprintf(stderr, "SENSITIVE");
     389             :         fflush(stderr);
     390             :       }
     391             :       return;
     392             :     case LS_VERBOSE:
     393             :       prio = ANDROID_LOG_VERBOSE;
     394             :       break;
     395             :     case LS_INFO:
     396             :       prio = ANDROID_LOG_INFO;
     397             :       break;
     398             :     case LS_WARNING:
     399             :       prio = ANDROID_LOG_WARN;
     400             :       break;
     401             :     case LS_ERROR:
     402             :       prio = ANDROID_LOG_ERROR;
     403             :       break;
     404             :     default:
     405             :       prio = ANDROID_LOG_UNKNOWN;
     406             :   }
     407             : 
     408             :   int size = str.size();
     409             :   int line = 0;
     410             :   int idx = 0;
     411             :   const int max_lines = size / kMaxLogLineSize + 1;
     412             :   if (max_lines == 1) {
     413             :     __android_log_print(prio, tag.c_str(), "%.*s", size, str.c_str());
     414             :   } else {
     415             :     while (size > 0) {
     416             :       const int len = std::min(size, kMaxLogLineSize);
     417             :       // Use the size of the string in the format (str may have \0 in the
     418             :       // middle).
     419             :       __android_log_print(prio, tag.c_str(), "[%d/%d] %.*s",
     420             :                           line + 1, max_lines,
     421             :                           len, str.c_str() + idx);
     422             :       idx += len;
     423             :       size -= len;
     424             :       ++line;
     425             :     }
     426             :   }
     427             : #endif  // WEBRTC_ANDROID
     428           0 :   if (log_to_stderr) {
     429           0 :     fprintf(stderr, "%s", str.c_str());
     430           0 :     fflush(stderr);
     431             :   }
     432           0 : }
     433             : 
     434             : //////////////////////////////////////////////////////////////////////
     435             : // Logging Helpers
     436             : //////////////////////////////////////////////////////////////////////
     437             : 
     438           0 : void LogMultiline(LoggingSeverity level, const char* label, bool input,
     439             :                   const void* data, size_t len, bool hex_mode,
     440             :                   LogMultilineState* state) {
     441           0 :   if (!LOG_CHECK_LEVEL_V(level))
     442           0 :     return;
     443             : 
     444           0 :   const char * direction = (input ? " << " : " >> ");
     445             : 
     446             :   // NULL data means to flush our count of unprintable characters.
     447           0 :   if (!data) {
     448           0 :     if (state && state->unprintable_count_[input]) {
     449           0 :       LOG_V(level) << label << direction << "## "
     450           0 :                    << state->unprintable_count_[input]
     451           0 :                    << " consecutive unprintable ##";
     452           0 :       state->unprintable_count_[input] = 0;
     453             :     }
     454           0 :     return;
     455             :   }
     456             : 
     457             :   // The ctype classification functions want unsigned chars.
     458           0 :   const unsigned char* udata = static_cast<const unsigned char*>(data);
     459             : 
     460           0 :   if (hex_mode) {
     461           0 :     const size_t LINE_SIZE = 24;
     462             :     char hex_line[LINE_SIZE * 9 / 4 + 2], asc_line[LINE_SIZE + 1];
     463           0 :     while (len > 0) {
     464           0 :       memset(asc_line, ' ', sizeof(asc_line));
     465           0 :       memset(hex_line, ' ', sizeof(hex_line));
     466           0 :       size_t line_len = std::min(len, LINE_SIZE);
     467           0 :       for (size_t i = 0; i < line_len; ++i) {
     468           0 :         unsigned char ch = udata[i];
     469           0 :         asc_line[i] = isprint(ch) ? ch : '.';
     470           0 :         hex_line[i*2 + i/4] = hex_encode(ch >> 4);
     471           0 :         hex_line[i*2 + i/4 + 1] = hex_encode(ch & 0xf);
     472             :       }
     473           0 :       asc_line[sizeof(asc_line)-1] = 0;
     474           0 :       hex_line[sizeof(hex_line)-1] = 0;
     475           0 :       LOG_V(level) << label << direction
     476           0 :                    << asc_line << " " << hex_line << " ";
     477           0 :       udata += line_len;
     478           0 :       len -= line_len;
     479             :     }
     480           0 :     return;
     481             :   }
     482             : 
     483           0 :   size_t consecutive_unprintable = state ? state->unprintable_count_[input] : 0;
     484             : 
     485           0 :   const unsigned char* end = udata + len;
     486           0 :   while (udata < end) {
     487           0 :     const unsigned char* line = udata;
     488           0 :     const unsigned char* end_of_line = strchrn<unsigned char>(udata,
     489           0 :                                                               end - udata,
     490           0 :                                                               '\n');
     491           0 :     if (!end_of_line) {
     492           0 :       udata = end_of_line = end;
     493             :     } else {
     494           0 :       udata = end_of_line + 1;
     495             :     }
     496             : 
     497           0 :     bool is_printable = true;
     498             : 
     499             :     // If we are in unprintable mode, we need to see a line of at least
     500             :     // kMinPrintableLine characters before we'll switch back.
     501           0 :     const ptrdiff_t kMinPrintableLine = 4;
     502           0 :     if (consecutive_unprintable && ((end_of_line - line) < kMinPrintableLine)) {
     503           0 :       is_printable = false;
     504             :     } else {
     505             :       // Determine if the line contains only whitespace and printable
     506             :       // characters.
     507           0 :       bool is_entirely_whitespace = true;
     508           0 :       for (const unsigned char* pos = line; pos < end_of_line; ++pos) {
     509           0 :         if (isspace(*pos))
     510           0 :           continue;
     511           0 :         is_entirely_whitespace = false;
     512           0 :         if (!isprint(*pos)) {
     513           0 :           is_printable = false;
     514           0 :           break;
     515             :         }
     516             :       }
     517             :       // Treat an empty line following unprintable data as unprintable.
     518           0 :       if (consecutive_unprintable && is_entirely_whitespace) {
     519           0 :         is_printable = false;
     520             :       }
     521             :     }
     522           0 :     if (!is_printable) {
     523           0 :       consecutive_unprintable += (udata - line);
     524           0 :       continue;
     525             :     }
     526             :     // Print out the current line, but prefix with a count of prior unprintable
     527             :     // characters.
     528           0 :     if (consecutive_unprintable) {
     529           0 :       LOG_V(level) << label << direction << "## " << consecutive_unprintable
     530           0 :                   << " consecutive unprintable ##";
     531           0 :       consecutive_unprintable = 0;
     532             :     }
     533             :     // Strip off trailing whitespace.
     534           0 :     while ((end_of_line > line) && isspace(*(end_of_line-1))) {
     535           0 :       --end_of_line;
     536             :     }
     537             :     // Filter out any private data
     538           0 :     std::string substr(reinterpret_cast<const char*>(line), end_of_line - line);
     539           0 :     std::string::size_type pos_private = substr.find("Email");
     540           0 :     if (pos_private == std::string::npos) {
     541           0 :       pos_private = substr.find("Passwd");
     542             :     }
     543           0 :     if (pos_private == std::string::npos) {
     544           0 :       LOG_V(level) << label << direction << substr;
     545             :     } else {
     546           0 :       LOG_V(level) << label << direction << "## omitted for privacy ##";
     547             :     }
     548             :   }
     549             : 
     550           0 :   if (state) {
     551           0 :     state->unprintable_count_[input] = consecutive_unprintable;
     552             :   }
     553             : }
     554             : 
     555             : //////////////////////////////////////////////////////////////////////
     556             : 
     557             : }  // namespace rtc

Generated by: LCOV version 1.13