1f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch/* 2f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * libjingle 3dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen * Copyright 2011, Google Inc. 4f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 5f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Redistribution and use in source and binary forms, with or without 6f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * modification, are permitted provided that the following conditions are met: 7f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 8f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 1. Redistributions of source code must retain the above copyright notice, 9f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * this list of conditions and the following disclaimer. 10f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 2. Redistributions in binary form must reproduce the above copyright notice, 11f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * this list of conditions and the following disclaimer in the documentation 12f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * and/or other materials provided with the distribution. 13f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 3. The name of the author may not be used to endorse or promote products 14f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * derived from this software without specific prior written permission. 15f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 16f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch */ 27f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 28f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifdef WIN32 29f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#define WIN32_LEAN_AND_MEAN 30f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <windows.h> 31f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#define snprintf _snprintf 32f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#undef ERROR // wingdi.h 33f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif 34f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 35f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifdef OSX 36f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <CoreServices/CoreServices.h> 37f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#elif defined(ANDROID) 38f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <android/log.h> 39f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstatic const char kLibjingle[] = "libjingle"; 40dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Android has a 1024 limit on log inputs. We use 60 chars as an 41dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// approx for the header/tag portion. 42dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// See android/system/core/liblog/logd_write.c 43dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenstatic const int kMaxLogLineSize = 1024 - 60; 44f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif // OSX || ANDROID 45f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 46f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <iostream> 47f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <iomanip> 48f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <vector> 49f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 50f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/logging.h" 51f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/stream.h" 52f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/stringencode.h" 53f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/stringutils.h" 54f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/time.h" 55f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 56f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochnamespace talk_base { 57f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 58f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch///////////////////////////////////////////////////////////////////////////// 59f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Constant Labels 60f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch///////////////////////////////////////////////////////////////////////////// 61f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 62f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst char * FindLabel(int value, const ConstantLabel entries[]) { 63f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (int i = 0; entries[i].label; ++i) { 64f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (value == entries[i].value) { 65f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return entries[i].label; 66f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 67f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 68f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return 0; 69f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 70f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 71f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstd::string ErrorName(int err, const ConstantLabel * err_table) { 72f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (err == 0) 73f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return "No error"; 74f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 75f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (err_table != 0) { 76f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (const char * value = FindLabel(err, err_table)) 77f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return value; 78f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 79f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 80f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch char buffer[16]; 81f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch snprintf(buffer, sizeof(buffer), "0x%08x", err); 82f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return buffer; 83f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 84f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 85f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch///////////////////////////////////////////////////////////////////////////// 86f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// LogMessage 87f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch///////////////////////////////////////////////////////////////////////////// 88f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 89f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst int LogMessage::NO_LOGGING = LS_ERROR + 1; 90f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 91f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#if _DEBUG 92f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstatic const int LOG_DEFAULT = LS_INFO; 93f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#else // !_DEBUG 94f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstatic const int LOG_DEFAULT = LogMessage::NO_LOGGING; 95f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif // !_DEBUG 96f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 97f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Global lock for log subsystem, only needed to serialize access to streams_. 98f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochCriticalSection LogMessage::crit_; 99f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 100f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// By default, release builds don't log, debug builds at info level 101f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint LogMessage::min_sev_ = LOG_DEFAULT; 102f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint LogMessage::dbg_sev_ = LOG_DEFAULT; 103f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 104f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Don't bother printing context for the ubiquitous INFO log messages 105f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint LogMessage::ctx_sev_ = LS_WARNING; 106f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 107f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// The list of logging streams currently configured. 108f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Note: we explicitly do not clean this up, because of the uncertain ordering 109f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// of destructors at program exit. Let the person who sets the stream trigger 110f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// cleanup by setting to NULL, or let it leak (safe at program exit). 111f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochLogMessage::StreamList LogMessage::streams_; 112f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 113f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Boolean options default to false (0) 114f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool LogMessage::thread_, LogMessage::timestamp_; 115f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 116f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Program start time 117f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochuint32 LogMessage::start_ = StartTime(); 118f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 119f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// If we're in diagnostic mode, we'll be explicitly set that way; default=false. 120f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool LogMessage::is_diagnostic_mode_ = false; 121f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 122f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochLogMessage::LogMessage(const char* file, int line, LoggingSeverity sev, 123f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LogErrorContext err_ctx, int err, const char* module) 124f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch : severity_(sev) { 125f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Android's logging facility keeps track of timestamp and thread. 126f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifndef ANDROID 127f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (timestamp_) { 128f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch uint32 time = TimeSince(start_); 129f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch print_stream_ << "[" << std::setfill('0') << std::setw(3) << (time / 1000) 130f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << ":" << std::setw(3) << (time % 1000) << std::setfill(' ') 131f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << "] "; 132f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 133f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 134f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (thread_) { 135f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifdef WIN32 136f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch DWORD id = GetCurrentThreadId(); 137f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch print_stream_ << "[" << std::hex << id << std::dec << "] "; 138f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif // WIN32 139f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 140f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif // !ANDROID 141f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 142f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (severity_ >= ctx_sev_) { 143f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch print_stream_ << Describe(sev) << "(" << DescribeFile(file) 144f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << ":" << line << "): "; 145f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 146f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 147f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (err_ctx != ERRCTX_NONE) { 148f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::ostringstream tmp; 149f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch tmp << "[0x" << std::setfill('0') << std::hex << std::setw(8) << err << "]"; 150f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch switch (err_ctx) { 151f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case ERRCTX_ERRNO: 152f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch tmp << " " << strerror(err); 153f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 154f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#if WIN32 155f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case ERRCTX_HRESULT: { 156f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch char msgbuf[256]; 157f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM; 158f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HMODULE hmod = GetModuleHandleA(module); 159f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (hmod) 160f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch flags |= FORMAT_MESSAGE_FROM_HMODULE; 161f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (DWORD len = FormatMessageA( 162f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch flags, hmod, err, 163f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 164f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), NULL)) { 165f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch while ((len > 0) && 166f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch isspace(static_cast<unsigned char>(msgbuf[len-1]))) { 167f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch msgbuf[--len] = 0; 168f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 169f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch tmp << " " << msgbuf; 170f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 171f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 172f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 173f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif // WIN32 174f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#if OSX 175f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case ERRCTX_OSSTATUS: { 176f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch tmp << " " << nonnull(GetMacOSStatusErrorString(err), "Unknown error"); 177f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (const char* desc = GetMacOSStatusCommentString(err)) { 178f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch tmp << ": " << desc; 179f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 180f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 181f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 182f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif // OSX 183f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch default: 184f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 185f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 186f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch extra_ = tmp.str(); 187f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 188f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 189f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 190f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochLogMessage::~LogMessage() { 191f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!extra_.empty()) 192f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch print_stream_ << " : " << extra_; 193f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch print_stream_ << std::endl; 194f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 195f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const std::string& str = print_stream_.str(); 196f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (severity_ >= dbg_sev_) { 197f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch OutputToDebug(str, severity_); 198f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 199f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 200f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Must lock streams_ before accessing 201f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CritScope cs(&crit_); 202f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (StreamList::iterator it = streams_.begin(); it != streams_.end(); ++it) { 203f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (severity_ >= it->second) { 204f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch OutputToStream(it->first, str); 205f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 206f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 207f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 208f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 209f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid LogMessage::LogContext(int min_sev) { 210f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ctx_sev_ = min_sev; 211f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 212f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 213f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid LogMessage::LogThreads(bool on) { 214f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch thread_ = on; 215f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 216f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 217f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid LogMessage::LogTimestamps(bool on) { 218f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch timestamp_ = on; 219f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 220f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 221f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid LogMessage::ResetTimestamps() { 222f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch start_ = Time(); 223f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 224f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 225f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid LogMessage::LogToDebug(int min_sev) { 226f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch dbg_sev_ = min_sev; 227f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch UpdateMinLogSeverity(); 228f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 229f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 230f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid LogMessage::LogToStream(StreamInterface* stream, int min_sev) { 231f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CritScope cs(&crit_); 232f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Discard and delete all previously installed streams 233f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (StreamList::iterator it = streams_.begin(); it != streams_.end(); ++it) { 234f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch delete it->first; 235f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 236f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch streams_.clear(); 237f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Install the new stream, if specified 238f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (stream) { 239f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch AddLogToStream(stream, min_sev); 240f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 241f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 242f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 243f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint LogMessage::GetLogToStream(StreamInterface* stream) { 244f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CritScope cs(&crit_); 245f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int sev = NO_LOGGING; 246f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (StreamList::iterator it = streams_.begin(); it != streams_.end(); ++it) { 247f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!stream || stream == it->first) { 248f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch sev = _min(sev, it->second); 249f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 250f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 251f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return sev; 252f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 253f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 254f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid LogMessage::AddLogToStream(StreamInterface* stream, int min_sev) { 255f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CritScope cs(&crit_); 256f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch streams_.push_back(std::make_pair(stream, min_sev)); 257f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch UpdateMinLogSeverity(); 258f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 259f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 260f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid LogMessage::RemoveLogToStream(StreamInterface* stream) { 261f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CritScope cs(&crit_); 262f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (StreamList::iterator it = streams_.begin(); it != streams_.end(); ++it) { 263f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (stream == it->first) { 264f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch streams_.erase(it); 265f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 266f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 267f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 268f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch UpdateMinLogSeverity(); 269f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 270f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 271f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid LogMessage::ConfigureLogging(const char* params, const char* filename) { 272f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int current_level = LS_VERBOSE; 273f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int debug_level = GetLogToDebug(); 274f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int file_level = GetLogToStream(); 275f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 276f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::vector<std::string> tokens; 277dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen tokenize(params, ' ', &tokens); 278f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 279f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (size_t i = 0; i < tokens.size(); ++i) { 280f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (tokens[i].empty()) 281f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch continue; 282f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 283f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Logging features 284f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (tokens[i] == "tstamp") { 285f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LogTimestamps(); 286f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (tokens[i] == "thread") { 287f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LogThreads(); 288f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 289f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Logging levels 290f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (tokens[i] == "sensitive") { 291f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch current_level = LS_SENSITIVE; 292f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (tokens[i] == "verbose") { 293f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch current_level = LS_VERBOSE; 294f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (tokens[i] == "info") { 295f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch current_level = LS_INFO; 296f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (tokens[i] == "warning") { 297f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch current_level = LS_WARNING; 298f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (tokens[i] == "error") { 299f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch current_level = LS_ERROR; 300f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (tokens[i] == "none") { 301f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch current_level = NO_LOGGING; 302f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 303f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Logging targets 304f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (tokens[i] == "file") { 305f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch file_level = current_level; 306f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (tokens[i] == "debug") { 307f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch debug_level = current_level; 308f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 309f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 310f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 311f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifdef WIN32 312f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if ((NO_LOGGING != debug_level) && !::IsDebuggerPresent()) { 313f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // First, attempt to attach to our parent's console... so if you invoke 314f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // from the command line, we'll see the output there. Otherwise, create 315f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // our own console window. 316f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Note: These methods fail if a console already exists, which is fine. 317f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool success = false; 318f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch typedef BOOL (WINAPI* PFN_AttachConsole)(DWORD); 319f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (HINSTANCE kernel32 = ::LoadLibrary(L"kernel32.dll")) { 320f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // AttachConsole is defined on WinXP+. 321f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (PFN_AttachConsole attach_console = reinterpret_cast<PFN_AttachConsole> 322f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch (::GetProcAddress(kernel32, "AttachConsole"))) { 323f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch success = (FALSE != attach_console(ATTACH_PARENT_PROCESS)); 324f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 325f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ::FreeLibrary(kernel32); 326f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 327f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!success) { 328f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ::AllocConsole(); 329f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 330f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 331f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif // WIN32 332f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 333f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch scoped_ptr<FileStream> stream; 334f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (NO_LOGGING != file_level) { 335f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch stream.reset(new FileStream); 336f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!stream->Open(filename, "wb") || !stream->DisableBuffering()) { 337f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch stream.reset(); 338f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 339f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 340f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 341f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LogToDebug(debug_level); 342f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LogToStream(stream.release(), file_level); 343f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 344f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 345f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint LogMessage::ParseLogSeverity(const std::string& value) { 346f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int level = NO_LOGGING; 347f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (value == "LS_SENSITIVE") { 348f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch level = LS_SENSITIVE; 349f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (value == "LS_VERBOSE") { 350f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch level = LS_VERBOSE; 351f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (value == "LS_INFO") { 352f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch level = LS_INFO; 353f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (value == "LS_WARNING") { 354f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch level = LS_WARNING; 355f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (value == "LS_ERROR") { 356f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch level = LS_ERROR; 357f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (isdigit(value[0])) { 358f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch level = atoi(value.c_str()); // NOLINT 359f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 360f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return level; 361f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 362f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 363f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid LogMessage::UpdateMinLogSeverity() { 364f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int min_sev = dbg_sev_; 365f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (StreamList::iterator it = streams_.begin(); it != streams_.end(); ++it) { 366f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch min_sev = _min(dbg_sev_, it->second); 367f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 368f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch min_sev_ = min_sev; 369f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 370f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 371f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst char* LogMessage::Describe(LoggingSeverity sev) { 372f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch switch (sev) { 373f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case LS_SENSITIVE: return "Sensitive"; 374f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case LS_VERBOSE: return "Verbose"; 375f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case LS_INFO: return "Info"; 376f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case LS_WARNING: return "Warning"; 377f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case LS_ERROR: return "Error"; 378f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch default: return "<unknown>"; 379f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 380f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 381f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 382f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst char* LogMessage::DescribeFile(const char* file) { 383f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const char* end1 = ::strrchr(file, '/'); 384f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const char* end2 = ::strrchr(file, '\\'); 385f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!end1 && !end2) 386f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return file; 387f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch else 388f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return (end1 > end2) ? end1 + 1 : end2 + 1; 389f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 390f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 391f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid LogMessage::OutputToDebug(const std::string& str, 392f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LoggingSeverity severity) { 393f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool log_to_stderr = true; 394f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#if defined(OSX) && (!defined(DEBUG) || defined(NDEBUG)) 395f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // On the Mac, all stderr output goes to the Console log and causes clutter. 396f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // So in opt builds, don't log to stderr unless the user specifically sets 397f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // a preference to do so. 398f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault, 399f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch "logToStdErr", 400f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch kCFStringEncodingUTF8); 401f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle()); 402f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (key != NULL && domain != NULL) { 403f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Boolean exists_and_is_valid; 404f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Boolean should_log = 405f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid); 406f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // If the key doesn't exist or is invalid or is false, we will not log to 407f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // stderr. 408f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch log_to_stderr = exists_and_is_valid && should_log; 409f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 410f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (key != NULL) { 411f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CFRelease(key); 412f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 413f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif 414f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifdef WIN32 415f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Always log to the debugger. 416f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Perhaps stderr should be controlled by a preference, as on Mac? 417f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch OutputDebugStringA(str.c_str()); 418f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (log_to_stderr) { 419f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // This handles dynamically allocated consoles, too. 420f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) { 421f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch log_to_stderr = false; 422f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch unsigned long written; // NOLINT 423f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ::WriteFile(error_handle, str.data(), str.size(), &written, 0); 424f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 425f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 426f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif // WIN32 427f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifdef ANDROID 428f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Android's logging facility uses severity to log messages but we 429f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // need to map libjingle's severity levels to Android ones first. 430f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Also write to stderr which maybe available to executable started 431f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // from the shell. 432f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int prio; 433f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch switch (severity) { 434f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case LS_SENSITIVE: 435f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch __android_log_write(ANDROID_LOG_INFO, kLibjingle, "SENSITIVE"); 436dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (log_to_stderr) { 437dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen std::cerr << "SENSITIVE"; 438dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen std::cerr.flush(); 439dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 440f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 441f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case LS_VERBOSE: 442f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch prio = ANDROID_LOG_VERBOSE; 443f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 444f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case LS_INFO: 445f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch prio = ANDROID_LOG_INFO; 446f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 447f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case LS_WARNING: 448f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch prio = ANDROID_LOG_WARN; 449f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 450f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case LS_ERROR: 451f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch prio = ANDROID_LOG_ERROR; 452f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 453f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch default: 454f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch prio = ANDROID_LOG_UNKNOWN; 455f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 456dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 457dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int size = str.size(); 458dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int line = 0; 459dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int idx = 0; 460dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const int max_lines = size / kMaxLogLineSize + 1; 461dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (max_lines == 1) { 462dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen __android_log_print(prio, kLibjingle, "%.*s", size, str.c_str()); 463dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } else { 464dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen while (size > 0) { 465dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const int len = std::min(size, kMaxLogLineSize); 466dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Use the size of the string in the format (str may have \0 in the 467dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // middle). 468dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen __android_log_print(prio, kLibjingle, "[%d/%d] %.*s", 469dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen line + 1, max_lines, 470dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen len, str.c_str() + idx); 471dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen idx += len; 472dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen size -= len; 473dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ++line; 474dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 475dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 476f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif // ANDROID 477f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (log_to_stderr) { 478f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::cerr << str; 479f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::cerr.flush(); 480f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 481f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 482f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 483f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid LogMessage::OutputToStream(StreamInterface* stream, 484f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const std::string& str) { 485f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // If write isn't fully successful, what are we going to do, log it? :) 486f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch stream->WriteAll(str.data(), str.size(), NULL, NULL); 487f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 488f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 489f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch////////////////////////////////////////////////////////////////////// 490f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Logging Helpers 491f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch////////////////////////////////////////////////////////////////////// 492f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 493f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid LogMultiline(LoggingSeverity level, const char* label, bool input, 494f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const void* data, size_t len, bool hex_mode, 495f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LogMultilineState* state) { 496f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!LOG_CHECK_LEVEL_V(level)) 497f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 498f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 499f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const char * direction = (input ? " << " : " >> "); 500f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 501f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // NULL data means to flush our count of unprintable characters. 502f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!data) { 503f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (state && state->unprintable_count_[input]) { 504f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_V(level) << label << direction << "## " 505f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << state->unprintable_count_[input] 506f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << " consecutive unprintable ##"; 507f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch state->unprintable_count_[input] = 0; 508f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 509f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 510f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 511f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 512f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // The ctype classification functions want unsigned chars. 513f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const unsigned char* udata = static_cast<const unsigned char*>(data); 514f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 515f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (hex_mode) { 516f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const size_t LINE_SIZE = 24; 517f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch char hex_line[LINE_SIZE * 9 / 4 + 2], asc_line[LINE_SIZE + 1]; 518f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch while (len > 0) { 519f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch memset(asc_line, ' ', sizeof(asc_line)); 520f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch memset(hex_line, ' ', sizeof(hex_line)); 521f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t line_len = _min(len, LINE_SIZE); 522f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (size_t i = 0; i < line_len; ++i) { 523f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch unsigned char ch = udata[i]; 524f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch asc_line[i] = isprint(ch) ? ch : '.'; 525f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch hex_line[i*2 + i/4] = hex_encode(ch >> 4); 526f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch hex_line[i*2 + i/4 + 1] = hex_encode(ch & 0xf); 527f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 528f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch asc_line[sizeof(asc_line)-1] = 0; 529f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch hex_line[sizeof(hex_line)-1] = 0; 530f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_V(level) << label << direction 531f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << asc_line << " " << hex_line << " "; 532f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch udata += line_len; 533f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch len -= line_len; 534f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 535f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 536f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 537f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 538f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t consecutive_unprintable = state ? state->unprintable_count_[input] : 0; 539f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 540f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const unsigned char* end = udata + len; 541f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch while (udata < end) { 542f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const unsigned char* line = udata; 543f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const unsigned char* end_of_line = strchrn<unsigned char>(udata, 544f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch end - udata, 545f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch '\n'); 546f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!end_of_line) { 547f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch udata = end_of_line = end; 548f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 549f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch udata = end_of_line + 1; 550f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 551f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 552f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool is_printable = true; 553f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 554f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // If we are in unprintable mode, we need to see a line of at least 555f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // kMinPrintableLine characters before we'll switch back. 556f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const ptrdiff_t kMinPrintableLine = 4; 557f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (consecutive_unprintable && ((end_of_line - line) < kMinPrintableLine)) { 558f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch is_printable = false; 559f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 560f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Determine if the line contains only whitespace and printable 561f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // characters. 562f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool is_entirely_whitespace = true; 563f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (const unsigned char* pos = line; pos < end_of_line; ++pos) { 564f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (isspace(*pos)) 565f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch continue; 566f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch is_entirely_whitespace = false; 567f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!isprint(*pos)) { 568f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch is_printable = false; 569f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 570f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 571f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 572f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Treat an empty line following unprintable data as unprintable. 573f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (consecutive_unprintable && is_entirely_whitespace) { 574f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch is_printable = false; 575f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 576f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 577f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!is_printable) { 578f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch consecutive_unprintable += (udata - line); 579f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch continue; 580f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 581f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Print out the current line, but prefix with a count of prior unprintable 582f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // characters. 583f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (consecutive_unprintable) { 584f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_V(level) << label << direction << "## " << consecutive_unprintable 585f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << " consecutive unprintable ##"; 586f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch consecutive_unprintable = 0; 587f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 588f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Strip off trailing whitespace. 589f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch while ((end_of_line > line) && isspace(*(end_of_line-1))) { 590f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch --end_of_line; 591f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 592f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Filter out any private data 593f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string substr(reinterpret_cast<const char*>(line), end_of_line - line); 594f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string::size_type pos_private = substr.find("Email"); 595f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (pos_private == std::string::npos) { 596f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch pos_private = substr.find("Passwd"); 597f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 598f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (pos_private == std::string::npos) { 599f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_V(level) << label << direction << substr; 600f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 601f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_V(level) << label << direction << "## omitted for privacy ##"; 602f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 603f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 604f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 605f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (state) { 606f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch state->unprintable_count_[input] = consecutive_unprintable; 607f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 608f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 609f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 610f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch////////////////////////////////////////////////////////////////////// 611f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 612f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} // namespace talk_base 613