LogMessage::~LogMessage() { stream_ << std::endl; std::string str_newline(stream_.str()); // Give any log message handler first dibs on the message. if (log_message_handler && log_message_handler(severity_, file_, line_, message_start_, str_newline)) { // The handler took care of it, no further processing. return; } if ((logging_destination & LOG_TO_SYSTEM_DEBUG_LOG) != 0) { OutputDebugStringA(str_newline.c_str()); fwrite(str_newline.data(), str_newline.size(), 1, stderr); fflush(stderr); } else if (severity_ >= kAlwaysPrintErrorLevel) { fwrite(str_newline.data(), str_newline.size(), 1, stderr); fflush(stderr); } if ((logging_destination & LOG_TO_FILE) != 0) { LoggingLock::Init(LOCK_LOG_FILE, NULL); LoggingLock logging_lock; if (InitializeLogFileHandle()) { SetFilePointer(log_file, 0, 0, SEEK_END); DWORD num_written; WriteFile(log_file, static_cast<const void*>(str_newline.c_str()), static_cast<DWORD>(str_newline.length()), &num_written, NULL); } } if (severity_ == LOG_FATAL) { // Ensure the first characters of the string are on the stack so they // are contained in minidumps for diagnostic purposes. char str_stack[1024]; str_newline.copy(str_stack, arraysize(str_stack)); // base::debug::Alias(str_stack); if (log_assert_handler) { log_assert_handler(std::string(stream_.str())); } else { // Don't use the string with the newline, get a fresh version to send to // the debug message process. We also don't display assertions to the // user in release mode. The enduser can't do anything with this // information, and displaying message boxes when the application is // hosed can cause additional problems. #ifndef NDEBUG // DisplayDebugMessageInDialog(stream_.str()); #endif // Crash the process to generate a dump. BreakDebugger(); } } }
LogMessage::~LogMessage() { if(severity_ < min_log_level) { return; } #ifndef NDEBUG if(severity_ == LOG_FATAL) { // fatal时输出堆栈. StackTrace trace; stream_ << std::endl; trace.OutputToStream(&stream_); } #endif stream_ << std::endl; std::string str_newline(stream_.str()); // 所有消息先交由log_message_handler处理 if(log_message_handler && log_message_handler(severity_, str_newline)) { return; } if(logging_destination==LOG_ONLY_TO_SYSTEM_DEBUG_LOG || logging_destination==LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) { OutputDebugStringA(str_newline.c_str()); fprintf(stderr, "%s", str_newline.c_str()); fflush(stderr); } else if(severity_ >= kAlwaysPrintErrorLevel) { // 在只输出日志到文件情况下, 对于kAlwaysPrintErrorLevel以及以上等级 // 的消息仍然显示到标准错误输出以便单元测试能更方便的检测和诊断问题. fprintf(stderr, "%s", str_newline.c_str()); fflush(stderr); } // 可能多线程或者多进程同时写操作, 所以必须加锁. // 如果客户端应用没有调用BaseInitLoggingImpl, 锁在此时才会创建, 假如同时有 // 2个线程运行此处, 会导致锁创建冲突, 这也是BaseInitLoggingImpl应该在main // 函数运行开始处调用的原因. LoggingLock::Init(LOCK_LOG_FILE, NULL); // 写日志文件 if(logging_destination!=LOG_NONE && logging_destination!=LOG_ONLY_TO_SYSTEM_DEBUG_LOG) { LoggingLock logging_lock; if(InitializeLogFileHandle()) { SetFilePointer(log_file, 0, 0, SEEK_END); DWORD num_written; WriteFile(log_file, static_cast<const void*>(str_newline.c_str()), static_cast<DWORD>(str_newline.length()), &num_written, NULL); } } if(severity_ == LOG_FATAL) { // fatal error: 显示错误消息或者显示在调试器中中断. if(DebugUtil::BeingDebugged()) { DebugUtil::BreakDebugger(); } else { if(log_assert_handler) { // make a copy of the string for the handler out of paranoia log_assert_handler(std::string(stream_.str())); } else { // 把错误消息发送到消息显示进程弹出. // 在release模式下不显示断言信息给用户, 因为这种信息对于最终用户 // 没什么价值而且显示消息框可能会给程序带来其他问题. #ifndef NDEBUG DisplayDebugMessageInDialog(stream_.str()); #endif // Crash the process to generate a dump. DebugUtil::BreakDebugger(); } } } else if(severity_ == LOG_ERROR_REPORT) { // 用户在release模式下通过参数--enable-dcheck启动程序 if(log_report_handler) { log_report_handler(std::string(stream_.str())); } else { DisplayDebugMessageInDialog(stream_.str()); } } }