1 /* 2 * Copyright 2012 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 #include "third_party/webrtc/overrides/webrtc/base/logging.h" 12 13 #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) 14 #include <CoreServices/CoreServices.h> 15 #endif // OS_MACOSX 16 17 #include <iomanip> 18 19 #include "base/atomicops.h" 20 #include "base/strings/string_util.h" 21 #include "base/threading/platform_thread.h" 22 #include "third_party/webrtc/base/ipaddress.h" 23 #include "third_party/webrtc/base/stream.h" 24 #include "third_party/webrtc/base/stringencode.h" 25 #include "third_party/webrtc/base/stringutils.h" 26 #include "third_party/webrtc/base/timeutils.h" 27 28 // From this file we can't use VLOG since it expands into usage of the __FILE__ 29 // macro (for correct filtering). The actual logging call from DIAGNOSTIC_LOG in 30 // ~DiagnosticLogMessage. Note that the second parameter to the LAZY_STREAM 31 // macro is true since the filter check has already been done for 32 // DIAGNOSTIC_LOG. 33 #define LOG_LAZY_STREAM_DIRECT(file_name, line_number, sev) \ 34 LAZY_STREAM(logging::LogMessage(file_name, line_number, \ 35 -sev).stream(), true) 36 37 namespace rtc { 38 39 void (*g_logging_delegate_function)(const std::string&) = NULL; 40 void (*g_extra_logging_init_function)( 41 void (*logging_delegate_function)(const std::string&)) = NULL; 42 #ifndef NDEBUG 43 COMPILE_ASSERT(sizeof(base::subtle::Atomic32) == sizeof(base::PlatformThreadId), 44 atomic32_not_same_size_as_platformthreadid); 45 base::subtle::Atomic32 g_init_logging_delegate_thread_id = 0; 46 #endif 47 48 ///////////////////////////////////////////////////////////////////////////// 49 // Constant Labels 50 ///////////////////////////////////////////////////////////////////////////// 51 52 const char* FindLabel(int value, const ConstantLabel entries[]) { 53 for (int i = 0; entries[i].label; ++i) { 54 if (value == entries[i].value) return entries[i].label; 55 } 56 return 0; 57 } 58 59 std::string ErrorName(int err, const ConstantLabel* err_table) { 60 if (err == 0) 61 return "No error"; 62 63 if (err_table != 0) { 64 if (const char * value = FindLabel(err, err_table)) 65 return value; 66 } 67 68 char buffer[16]; 69 base::snprintf(buffer, sizeof(buffer), "0x%08x", err); 70 return buffer; 71 } 72 73 ///////////////////////////////////////////////////////////////////////////// 74 // Log helper functions 75 ///////////////////////////////////////////////////////////////////////////// 76 77 // Generates extra information for LOG_E. 78 static std::string GenerateExtra(LogErrorContext err_ctx, 79 int err, 80 const char* module) { 81 if (err_ctx != ERRCTX_NONE) { 82 std::ostringstream tmp; 83 tmp << ": "; 84 tmp << "[0x" << std::setfill('0') << std::hex << std::setw(8) << err << "]"; 85 switch (err_ctx) { 86 case ERRCTX_ERRNO: 87 tmp << " " << strerror(err); 88 break; 89 #if defined(WEBRTC_WIN) 90 case ERRCTX_HRESULT: { 91 char msgbuf[256]; 92 DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM; 93 HMODULE hmod = GetModuleHandleA(module); 94 if (hmod) 95 flags |= FORMAT_MESSAGE_FROM_HMODULE; 96 if (DWORD len = FormatMessageA( 97 flags, hmod, err, 98 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 99 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), NULL)) { 100 while ((len > 0) && 101 isspace(static_cast<unsigned char>(msgbuf[len-1]))) { 102 msgbuf[--len] = 0; 103 } 104 tmp << " " << msgbuf; 105 } 106 break; 107 } 108 #endif // OS_WIN 109 #if defined(WEBRTC_IOS) 110 case ERRCTX_OSSTATUS: 111 tmp << " " << "Unknown LibJingle error: " << err; 112 break; 113 #elif defined(WEBRTC_MAC) 114 case ERRCTX_OSSTATUS: { 115 tmp << " " << nonnull(GetMacOSStatusErrorString(err), "Unknown error"); 116 if (const char* desc = GetMacOSStatusCommentString(err)) { 117 tmp << ": " << desc; 118 } 119 break; 120 } 121 #endif // OS_MACOSX 122 default: 123 break; 124 } 125 return tmp.str(); 126 } 127 return ""; 128 } 129 130 DiagnosticLogMessage::DiagnosticLogMessage(const char* file, 131 int line, 132 LoggingSeverity severity, 133 bool log_to_chrome, 134 LogErrorContext err_ctx, 135 int err) 136 : file_name_(file), 137 line_(line), 138 severity_(severity), 139 log_to_chrome_(log_to_chrome) { 140 extra_ = GenerateExtra(err_ctx, err, NULL); 141 } 142 143 DiagnosticLogMessage::DiagnosticLogMessage(const char* file, 144 int line, 145 LoggingSeverity severity, 146 bool log_to_chrome, 147 LogErrorContext err_ctx, 148 int err, 149 const char* module) 150 : file_name_(file), 151 line_(line), 152 severity_(severity), 153 log_to_chrome_(log_to_chrome) { 154 extra_ = GenerateExtra(err_ctx, err, module); 155 } 156 157 DiagnosticLogMessage::~DiagnosticLogMessage() { 158 print_stream_ << extra_; 159 const std::string& str = print_stream_.str(); 160 if (log_to_chrome_) 161 LOG_LAZY_STREAM_DIRECT(file_name_, line_, severity_) << str; 162 if (g_logging_delegate_function && severity_ <= LS_INFO) { 163 g_logging_delegate_function(str); 164 } 165 } 166 167 // static 168 void LogMessage::LogToDebug(int min_sev) { 169 logging::SetMinLogLevel(min_sev); 170 } 171 172 // Note: this function is a copy from the overriden libjingle implementation. 173 void LogMultiline(LoggingSeverity level, const char* label, bool input, 174 const void* data, size_t len, bool hex_mode, 175 LogMultilineState* state) { 176 if (!LOG_CHECK_LEVEL_V(level)) 177 return; 178 179 const char * direction = (input ? " << " : " >> "); 180 181 // NULL data means to flush our count of unprintable characters. 182 if (!data) { 183 if (state && state->unprintable_count_[input]) { 184 LOG_V(level) << label << direction << "## " 185 << state->unprintable_count_[input] 186 << " consecutive unprintable ##"; 187 state->unprintable_count_[input] = 0; 188 } 189 return; 190 } 191 192 // The ctype classification functions want unsigned chars. 193 const unsigned char* udata = static_cast<const unsigned char*>(data); 194 195 if (hex_mode) { 196 const size_t LINE_SIZE = 24; 197 char hex_line[LINE_SIZE * 9 / 4 + 2], asc_line[LINE_SIZE + 1]; 198 while (len > 0) { 199 memset(asc_line, ' ', sizeof(asc_line)); 200 memset(hex_line, ' ', sizeof(hex_line)); 201 size_t line_len = _min(len, LINE_SIZE); 202 for (size_t i = 0; i < line_len; ++i) { 203 unsigned char ch = udata[i]; 204 asc_line[i] = isprint(ch) ? ch : '.'; 205 hex_line[i*2 + i/4] = hex_encode(ch >> 4); 206 hex_line[i*2 + i/4 + 1] = hex_encode(ch & 0xf); 207 } 208 asc_line[sizeof(asc_line)-1] = 0; 209 hex_line[sizeof(hex_line)-1] = 0; 210 LOG_V(level) << label << direction 211 << asc_line << " " << hex_line << " "; 212 udata += line_len; 213 len -= line_len; 214 } 215 return; 216 } 217 218 size_t consecutive_unprintable = state ? state->unprintable_count_[input] : 0; 219 220 const unsigned char* end = udata + len; 221 while (udata < end) { 222 const unsigned char* line = udata; 223 const unsigned char* end_of_line = strchrn<unsigned char>(udata, 224 end - udata, 225 '\n'); 226 if (!end_of_line) { 227 udata = end_of_line = end; 228 } else { 229 udata = end_of_line + 1; 230 } 231 232 bool is_printable = true; 233 234 // If we are in unprintable mode, we need to see a line of at least 235 // kMinPrintableLine characters before we'll switch back. 236 const ptrdiff_t kMinPrintableLine = 4; 237 if (consecutive_unprintable && ((end_of_line - line) < kMinPrintableLine)) { 238 is_printable = false; 239 } else { 240 // Determine if the line contains only whitespace and printable 241 // characters. 242 bool is_entirely_whitespace = true; 243 for (const unsigned char* pos = line; pos < end_of_line; ++pos) { 244 if (isspace(*pos)) 245 continue; 246 is_entirely_whitespace = false; 247 if (!isprint(*pos)) { 248 is_printable = false; 249 break; 250 } 251 } 252 // Treat an empty line following unprintable data as unprintable. 253 if (consecutive_unprintable && is_entirely_whitespace) { 254 is_printable = false; 255 } 256 } 257 if (!is_printable) { 258 consecutive_unprintable += (udata - line); 259 continue; 260 } 261 // Print out the current line, but prefix with a count of prior unprintable 262 // characters. 263 if (consecutive_unprintable) { 264 LOG_V(level) << label << direction << "## " << consecutive_unprintable 265 << " consecutive unprintable ##"; 266 consecutive_unprintable = 0; 267 } 268 // Strip off trailing whitespace. 269 while ((end_of_line > line) && isspace(*(end_of_line-1))) { 270 --end_of_line; 271 } 272 // Filter out any private data 273 std::string substr(reinterpret_cast<const char*>(line), end_of_line - line); 274 std::string::size_type pos_private = substr.find("Email"); 275 if (pos_private == std::string::npos) { 276 pos_private = substr.find("Passwd"); 277 } 278 if (pos_private == std::string::npos) { 279 LOG_V(level) << label << direction << substr; 280 } else { 281 LOG_V(level) << label << direction << "## omitted for privacy ##"; 282 } 283 } 284 285 if (state) { 286 state->unprintable_count_[input] = consecutive_unprintable; 287 } 288 } 289 290 void InitDiagnosticLoggingDelegateFunction( 291 void (*delegate)(const std::string&)) { 292 #ifndef NDEBUG 293 // Ensure that this function is always called from the same thread. 294 base::subtle::NoBarrier_CompareAndSwap(&g_init_logging_delegate_thread_id, 0, 295 static_cast<base::subtle::Atomic32>(base::PlatformThread::CurrentId())); 296 DCHECK_EQ( 297 g_init_logging_delegate_thread_id, 298 static_cast<base::subtle::Atomic32>(base::PlatformThread::CurrentId())); 299 #endif 300 CHECK(delegate); 301 // This function may be called with the same argument several times if the 302 // page is reloaded or there are several PeerConnections on one page with 303 // logging enabled. This is OK, we simply don't have to do anything. 304 if (delegate == g_logging_delegate_function) 305 return; 306 CHECK(!g_logging_delegate_function); 307 #ifdef NDEBUG 308 IPAddress::set_strip_sensitive(true); 309 #endif 310 g_logging_delegate_function = delegate; 311 312 if (g_extra_logging_init_function) 313 g_extra_logging_init_function(delegate); 314 } 315 316 void SetExtraLoggingInit( 317 void (*function)(void (*delegate)(const std::string&))) { 318 CHECK(function); 319 CHECK(!g_extra_logging_init_function); 320 g_extra_logging_init_function = function; 321 } 322 323 } // namespace rtc 324