├── .gitignore ├── README.md ├── chromium_winlog_demo.sln ├── chromium_winlog_demo ├── ReadMe.txt ├── chromium_winlog_demo.cpp ├── chromium_winlog_demo.vcxproj ├── chromium_winlog_demo.vcxproj.filters ├── stdafx.cpp ├── stdafx.h └── targetver.h └── src ├── chromium_logging_util.cpp ├── chromium_logging_util.h ├── lock.cc ├── lock.h ├── lock_impl.h ├── lock_impl_win.cc ├── logging.cc ├── logging.h ├── stack_trace.cc ├── stack_trace.h └── stack_trace_win.cc /.gitignore: -------------------------------------------------------------------------------- 1 | *.sdf 2 | *.suo 3 | *aps 4 | *.opensdf 5 | *.error -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # chromium_winlog 2 | a logging library for windows from chromium. 3 | 4 | 更多信息查看我的博客 http://blog.gclxry.com 5 | 6 | 这个log是从开源的chromium工程中抽取出来的。 7 | 支持的特性: 8 | * 支持输出log到文件,系统调试器 9 | * 支持输出不同等级log 10 | * 支持错误回调函数 11 | * 支持惰性输出,支持条件输出,支持仅在debug模式生效 12 | * 支持同时输出当前的GetLastError信息 13 | * 支持发生错误时的栈回溯 14 | * 支持线程安全 15 | 16 | ## 3分钟教程 17 | 18 | ### 初始化 19 | 20 | 使用log库之前需要调用logging::InitLogging函数初始化一次。 21 | 22 | 调用logging::SetLogItems设置输出每条log包含的的信息,比如进程id,线程id,时间戳,精确时间。 23 | 24 | ### log等级 25 | 26 | log分4个等级。INFO,WARNING,ERROR,FATAL。 27 | FATAL等级的log会触发一个断点。 28 | 29 | ### 输出log 30 | 31 | 输出log都是通过一些宏来输出,类似std::cout的用法。 32 | 33 | LOG(INFO) << "log INFO"; 34 | LOG(WARNING) << "log WARNING"; 35 | LOG(ERROR) << "log ERROR"; 36 | LOG(FATAL) << "log FATAL"; 37 | 38 | _IF后缀的是条件输出log 39 | 40 | LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; 41 | 42 | D前缀的是只在debug模式下生效 43 | 44 | DLOG(INFO) << "Found cookies"; 45 | DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; 46 | 47 | P前缀的是输出log之后会附加上GetLastError信息 48 | 49 | PLOG(ERROR) << "Couldn't do foo"; 50 | DPLOG(ERROR) << "Couldn't do foo"; 51 | DPLOG_IF(ERROR, cond) << "Couldn't do foo"; 52 | -------------------------------------------------------------------------------- /chromium_winlog_demo.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chromium_winlog_demo", "chromium_winlog_demo\chromium_winlog_demo.vcxproj", "{DFAE69A6-3519-47AD-BEBD-CCEC4FD0D252}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {DFAE69A6-3519-47AD-BEBD-CCEC4FD0D252}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {DFAE69A6-3519-47AD-BEBD-CCEC4FD0D252}.Debug|Win32.Build.0 = Debug|Win32 16 | {DFAE69A6-3519-47AD-BEBD-CCEC4FD0D252}.Release|Win32.ActiveCfg = Release|Win32 17 | {DFAE69A6-3519-47AD-BEBD-CCEC4FD0D252}.Release|Win32.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /chromium_winlog_demo/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | 控制台应用程序:chromium_winlog_demo 项目概述 3 | ======================================================================== 4 | 5 | 应用程序向导已为您创建了此 chromium_winlog_demo 应用程序。 6 | 7 | 本文件概要介绍组成 chromium_winlog_demo 应用程序的每个文件的内容。 8 | 9 | 10 | chromium_winlog_demo.vcxproj 11 | 这是使用应用程序向导生成的 VC++ 项目的主项目文件,其中包含生成该文件的 Visual C++ 的版本信息,以及有关使用应用程序向导选择的平台、配置和项目功能的信息。 12 | 13 | chromium_winlog_demo.vcxproj.filters 14 | 这是使用“应用程序向导”生成的 VC++ 项目筛选器文件。它包含有关项目文件与筛选器之间的关联信息。在 IDE 中,通过这种关联,在特定节点下以分组形式显示具有相似扩展名的文件。例如,“.cpp”文件与“源文件”筛选器关联。 15 | 16 | chromium_winlog_demo.cpp 17 | 这是主应用程序源文件。 18 | 19 | ///////////////////////////////////////////////////////////////////////////// 20 | 其他标准文件: 21 | 22 | StdAfx.h, StdAfx.cpp 23 | 这些文件用于生成名为 chromium_winlog_demo.pch 的预编译头 (PCH) 文件和名为 StdAfx.obj 的预编译类型文件。 24 | 25 | ///////////////////////////////////////////////////////////////////////////// 26 | 其他注释: 27 | 28 | 应用程序向导使用“TODO:”注释来指示应添加或自定义的源代码部分。 29 | 30 | ///////////////////////////////////////////////////////////////////////////// 31 | -------------------------------------------------------------------------------- /chromium_winlog_demo/chromium_winlog_demo.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gclxry/chromium_winlog/36586f4c3583eff16b5524d27f1a03e291dcb230/chromium_winlog_demo/chromium_winlog_demo.cpp -------------------------------------------------------------------------------- /chromium_winlog_demo/chromium_winlog_demo.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {DFAE69A6-3519-47AD-BEBD-CCEC4FD0D252} 15 | Win32Proj 16 | chromium_winlog_demo 17 | 18 | 19 | 20 | Application 21 | true 22 | v120 23 | Unicode 24 | 25 | 26 | Application 27 | false 28 | v120 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | Use 51 | Level3 52 | Disabled 53 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 54 | true 55 | 56 | 57 | Console 58 | true 59 | 60 | 61 | 62 | 63 | Level3 64 | Use 65 | MaxSpeed 66 | true 67 | true 68 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 69 | true 70 | 71 | 72 | Console 73 | true 74 | true 75 | true 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | Create 100 | Create 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /chromium_winlog_demo/chromium_winlog_demo.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 头文件 23 | 24 | 25 | 头文件 26 | 27 | 28 | 头文件 29 | 30 | 31 | 头文件 32 | 33 | 34 | 头文件 35 | 36 | 37 | 头文件 38 | 39 | 40 | 头文件 41 | 42 | 43 | 44 | 45 | 源文件 46 | 47 | 48 | 源文件 49 | 50 | 51 | 源文件 52 | 53 | 54 | 源文件 55 | 56 | 57 | 源文件 58 | 59 | 60 | 源文件 61 | 62 | 63 | 源文件 64 | 65 | 66 | 源文件 67 | 68 | 69 | -------------------------------------------------------------------------------- /chromium_winlog_demo/stdafx.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gclxry/chromium_winlog/36586f4c3583eff16b5524d27f1a03e291dcb230/chromium_winlog_demo/stdafx.cpp -------------------------------------------------------------------------------- /chromium_winlog_demo/stdafx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gclxry/chromium_winlog/36586f4c3583eff16b5524d27f1a03e291dcb230/chromium_winlog_demo/stdafx.h -------------------------------------------------------------------------------- /chromium_winlog_demo/targetver.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gclxry/chromium_winlog/36586f4c3583eff16b5524d27f1a03e291dcb230/chromium_winlog_demo/targetver.h -------------------------------------------------------------------------------- /src/chromium_logging_util.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include 3 | #include "chromium_logging_util.h" 4 | 5 | 6 | std::string remove_prefix(const std::string s, const std::string::size_type n) 7 | { 8 | std::string sRet = s.substr(n, s.size() - n); 9 | return sRet; 10 | } 11 | 12 | std::string remove_suffix(const std::string s, const std::string::size_type n) 13 | { 14 | return s.substr(0, s.size() - n); 15 | } 16 | 17 | 18 | std::string WideToUTF8(const std::wstring& wide) 19 | { 20 | std::string ret; 21 | return ret; 22 | } 23 | 24 | 25 | namespace base{ 26 | namespace debug{ 27 | void Alias(const void* var) { 28 | } 29 | 30 | void BreakDebugger() { 31 | __debugbreak(); 32 | #if defined(NDEBUG) 33 | _exit(1); 34 | #endif 35 | } 36 | 37 | } 38 | } 39 | 40 | namespace win_string_convert{ 41 | std::string WStringTOString(const std::wstring str, const DWORD dwType) 42 | { 43 | int nMultiByteLenght = WideCharToMultiByte(dwType, 0, str.c_str(), -1, NULL, 0, NULL, NULL); 44 | char* pMultiByteBuffer = new char[nMultiByteLenght]; 45 | nMultiByteLenght = WideCharToMultiByte(dwType, 0, str.c_str(), -1, pMultiByteBuffer, nMultiByteLenght, NULL, NULL); 46 | std::string sRet = pMultiByteBuffer; 47 | delete[] pMultiByteBuffer; 48 | return sRet; 49 | } 50 | std::wstring StringToWString(const std::string str, const DWORD dwType) 51 | { 52 | int nWideCharLenght = MultiByteToWideChar(dwType, 0, str.c_str(), -1, NULL, 0); 53 | wchar_t* pWideCharBuffer = new wchar_t[nWideCharLenght]; 54 | nWideCharLenght = MultiByteToWideChar(dwType, 0, str.c_str(), -1, pWideCharBuffer, nWideCharLenght); 55 | std::wstring sRet = pWideCharBuffer; 56 | delete[] pWideCharBuffer; 57 | return sRet; 58 | } 59 | 60 | std::string AnsiToUtf8(const std::string str) 61 | { 62 | std::wstring temp = StringToWString(str, CP_ACP); 63 | return WStringTOString(temp, CP_UTF8); 64 | } 65 | std::string Utf8ToAnsi(const std::string str) 66 | { 67 | std::wstring temp = StringToWString(str, CP_UTF8); 68 | return WStringTOString(temp, CP_ACP); 69 | } 70 | 71 | std::wstring UTF8ToWide(const std::string& s) 72 | { 73 | return StringToWString(Utf8ToAnsi(s)); 74 | } 75 | 76 | std::string WideToUTF8(const std::wstring& wide) 77 | { 78 | std::string temp = WStringTOString(wide); 79 | return AnsiToUtf8(temp); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/chromium_logging_util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include // For intptr_t. 5 | #include 6 | #include 7 | #include 8 | 9 | // 10 | 11 | 12 | // The arraysize(arr) macro returns the # of elements in an array arr. 13 | // The expression is a compile-time constant, and therefore can be 14 | // used in defining new arrays, for example. If you use arraysize on 15 | // a pointer by mistake, you will get a compile-time error. 16 | // 17 | // One caveat is that arraysize() doesn't accept any array of an 18 | // anonymous type or a type defined inside a function. In these rare 19 | // cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below. This is 20 | // due to a limitation in C++'s template system. The limitation might 21 | // eventually be removed, but it hasn't happened yet. 22 | 23 | // This template function declaration is used in defining arraysize. 24 | // Note that the function doesn't need an implementation, as we only 25 | // use its type. 26 | template 27 | char(&ArraySizeHelper(T(&array)[N]))[N]; 28 | 29 | // That gcc wants both of these prototypes seems mysterious. VC, for 30 | // its part, can't decide which to use (another mystery). Matching of 31 | // template overloads: the final frontier. 32 | #ifndef _MSC_VER 33 | template 34 | char(&ArraySizeHelper(const T(&array)[N]))[N]; 35 | #endif 36 | 37 | #define arraysize(array) (sizeof(ArraySizeHelper(array))) 38 | 39 | 40 | std::string remove_prefix(const std::string s, const std::string::size_type n); 41 | std::string remove_suffix(const std::string s, const std::string::size_type n); 42 | 43 | template 44 | inline void ignore_result(const T&) { 45 | } 46 | 47 | namespace base{ 48 | namespace debug{ 49 | void Alias(const void* var); 50 | 51 | // Break into the debugger, assumes a debugger is present. 52 | void BreakDebugger(); 53 | 54 | bool IsDebugUISuppressed(); 55 | } 56 | } 57 | 58 | #define HANDLE_EINTR(x) (x) 59 | #define IGNORE_EINTR(x) (x) 60 | 61 | namespace win_string_convert{ 62 | std::string WStringTOString(const std::wstring str, const DWORD dwType = CP_ACP); 63 | std::wstring StringToWString(const std::string str, const DWORD dwType = CP_ACP); 64 | std::string AnsiToUtf8(const std::string str); 65 | std::string Utf8ToAnsi(const std::string str); 66 | std::wstring UTF8ToWide(const std::string& s); 67 | std::string WideToUTF8(const std::wstring& wide); 68 | } -------------------------------------------------------------------------------- /src/lock.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | // This file is used for debugging assertion support. The Lock class 6 | // is functionally a wrapper around the LockImpl class, so the only 7 | // real intelligence in the class is in the debugging logic. 8 | #include "stdafx.h" 9 | #if !defined(NDEBUG) 10 | 11 | #include "lock.h" 12 | #include 13 | 14 | namespace base { 15 | 16 | Lock::Lock() : lock_() { 17 | } 18 | 19 | Lock::~Lock() { 20 | assert(owning_thread_ref_.is_null()); 21 | } 22 | 23 | void Lock::AssertAcquired() const { 24 | assert(owning_thread_ref_ == PlatformThreadRef(GetCurrentThreadId())); 25 | } 26 | 27 | void Lock::CheckHeldAndUnmark() { 28 | assert(owning_thread_ref_ == PlatformThreadRef(GetCurrentThreadId())); 29 | owning_thread_ref_ = PlatformThreadRef(); 30 | } 31 | 32 | void Lock::CheckUnheldAndMark() { 33 | assert(owning_thread_ref_.is_null()); 34 | owning_thread_ref_ = PlatformThreadRef(GetCurrentThreadId()); 35 | } 36 | 37 | } // namespace base 38 | 39 | #endif // NDEBUG 40 | -------------------------------------------------------------------------------- /src/lock.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef BASE_SYNCHRONIZATION_LOCK_H_ 6 | #define BASE_SYNCHRONIZATION_LOCK_H_ 7 | 8 | #include "lock_impl.h" 9 | 10 | namespace base { 11 | 12 | 13 | // Used for thread checking and debugging. 14 | // Meant to be as fast as possible. 15 | // These are produced by PlatformThread::CurrentRef(), and used to later 16 | // check if we are on the same thread or not by using ==. These are safe 17 | // to copy between threads, but can't be copied to another process as they 18 | // have no meaning there. Also, the internal identifier can be re-used 19 | // after a thread dies, so a PlatformThreadRef cannot be reliably used 20 | // to distinguish a new thread from an old, dead thread. 21 | class PlatformThreadRef { 22 | public: 23 | typedef DWORD RefType; 24 | PlatformThreadRef() 25 | : id_(0) { 26 | } 27 | 28 | explicit PlatformThreadRef(RefType id) 29 | : id_(id) { 30 | } 31 | 32 | bool operator==(PlatformThreadRef other) const { 33 | return id_ == other.id_; 34 | } 35 | 36 | bool is_null() const { 37 | return id_ == 0; 38 | } 39 | private: 40 | RefType id_; 41 | }; 42 | 43 | 44 | // A convenient wrapper for an OS specific critical section. The only real 45 | // intelligence in this class is in debug mode for the support for the 46 | // AssertAcquired() method. 47 | class Lock { 48 | public: 49 | #if defined(NDEBUG) // Optimized wrapper implementation 50 | Lock() : lock_() {} 51 | ~Lock() {} 52 | void Acquire() { lock_.Lock(); } 53 | void Release() { lock_.Unlock(); } 54 | 55 | // If the lock is not held, take it and return true. If the lock is already 56 | // held by another thread, immediately return false. This must not be called 57 | // by a thread already holding the lock (what happens is undefined and an 58 | // assertion may fail). 59 | bool Try() { return lock_.Try(); } 60 | 61 | // Null implementation if not debug. 62 | void AssertAcquired() const {} 63 | #else 64 | Lock(); 65 | ~Lock(); 66 | 67 | // NOTE: Although windows critical sections support recursive locks, we do not 68 | // allow this, and we will commonly fire a DCHECK() if a thread attempts to 69 | // acquire the lock a second time (while already holding it). 70 | void Acquire() { 71 | lock_.Lock(); 72 | CheckUnheldAndMark(); 73 | } 74 | void Release() { 75 | CheckHeldAndUnmark(); 76 | lock_.Unlock(); 77 | } 78 | 79 | bool Try() { 80 | bool rv = lock_.Try(); 81 | if (rv) { 82 | CheckUnheldAndMark(); 83 | } 84 | return rv; 85 | } 86 | 87 | void AssertAcquired() const; 88 | #endif // NDEBUG 89 | 90 | #if defined(OS_POSIX) 91 | // The posix implementation of ConditionVariable needs to be able 92 | // to see our lock and tweak our debugging counters, as it releases 93 | // and acquires locks inside of pthread_cond_{timed,}wait. 94 | friend class ConditionVariable; 95 | #elif defined(OS_WIN) 96 | // The Windows Vista implementation of ConditionVariable needs the 97 | // native handle of the critical section. 98 | friend class WinVistaCondVar; 99 | #endif 100 | 101 | private: 102 | #if !defined(NDEBUG) 103 | // Members and routines taking care of locks assertions. 104 | // Note that this checks for recursive locks and allows them 105 | // if the variable is set. This is allowed by the underlying implementation 106 | // on windows but not on Posix, so we're doing unneeded checks on Posix. 107 | // It's worth it to share the code. 108 | void CheckHeldAndUnmark(); 109 | void CheckUnheldAndMark(); 110 | 111 | // All private data is implicitly protected by lock_. 112 | // Be VERY careful to only access members under that lock. 113 | base::PlatformThreadRef owning_thread_ref_; 114 | #endif // NDEBUG 115 | 116 | // Platform specific underlying lock implementation. 117 | internal::LockImpl lock_; 118 | 119 | // DISALLOW_COPY_AND_ASSIGN 120 | Lock(const Lock&); 121 | void operator=(const Lock&); 122 | }; 123 | 124 | // A helper class that acquires the given Lock while the AutoLock is in scope. 125 | class AutoLock { 126 | public: 127 | struct AlreadyAcquired {}; 128 | 129 | explicit AutoLock(Lock& lock) : lock_(lock) { 130 | lock_.Acquire(); 131 | } 132 | 133 | AutoLock(Lock& lock, const AlreadyAcquired&) : lock_(lock) { 134 | lock_.AssertAcquired(); 135 | } 136 | 137 | ~AutoLock() { 138 | lock_.AssertAcquired(); 139 | lock_.Release(); 140 | } 141 | 142 | private: 143 | Lock& lock_; 144 | // DISALLOW_COPY_AND_ASSIGN 145 | AutoLock(const AutoLock&); 146 | void operator=(const AutoLock&); 147 | }; 148 | 149 | // AutoUnlock is a helper that will Release() the |lock| argument in the 150 | // constructor, and re-Acquire() it in the destructor. 151 | class AutoUnlock { 152 | public: 153 | explicit AutoUnlock(Lock& lock) : lock_(lock) { 154 | // We require our caller to have the lock. 155 | lock_.AssertAcquired(); 156 | lock_.Release(); 157 | } 158 | 159 | ~AutoUnlock() { 160 | lock_.Acquire(); 161 | } 162 | 163 | private: 164 | Lock& lock_; 165 | // DISALLOW_COPY_AND_ASSIGN 166 | AutoUnlock(const AutoUnlock&); 167 | void operator=(const AutoUnlock&); 168 | }; 169 | 170 | } // namespace base 171 | 172 | #endif // BASE_SYNCHRONIZATION_LOCK_H_ 173 | -------------------------------------------------------------------------------- /src/lock_impl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace base { 10 | namespace internal { 11 | 12 | // This class implements the underlying platform-specific spin-lock mechanism 13 | // used for the Lock class. Most users should not use LockImpl directly, but 14 | // should instead use Lock. 15 | class LockImpl { 16 | public: 17 | 18 | typedef CRITICAL_SECTION NativeHandle; 19 | 20 | LockImpl(); 21 | ~LockImpl(); 22 | 23 | // If the lock is not held, take it and return true. If the lock is already 24 | // held by something else, immediately return false. 25 | bool Try(); 26 | 27 | // Take the lock, blocking until it is available if necessary. 28 | void Lock(); 29 | 30 | // Release the lock. This must only be called by the lock's holder: after 31 | // a successful call to Try, or a call to Lock. 32 | void Unlock(); 33 | 34 | // Return the native underlying lock. 35 | // TODO(awalker): refactor lock and condition variables so that this is 36 | // unnecessary. 37 | NativeHandle* native_handle() { return &native_handle_; } 38 | 39 | private: 40 | NativeHandle native_handle_; 41 | 42 | // DISALLOW_COPY_AND_ASSIGN 43 | LockImpl(const LockImpl&); 44 | void operator=(const LockImpl&); 45 | }; 46 | 47 | } // namespace internal 48 | } // namespace base -------------------------------------------------------------------------------- /src/lock_impl_win.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | #include "stdafx.h" 5 | #include "lock_impl.h" 6 | 7 | namespace base { 8 | namespace internal { 9 | 10 | LockImpl::LockImpl() { 11 | // The second parameter is the spin count, for short-held locks it avoid the 12 | // contending thread from going to sleep which helps performance greatly. 13 | ::InitializeCriticalSectionAndSpinCount(&native_handle_, 2000); 14 | } 15 | 16 | LockImpl::~LockImpl() { 17 | ::DeleteCriticalSection(&native_handle_); 18 | } 19 | 20 | bool LockImpl::Try() { 21 | if (::TryEnterCriticalSection(&native_handle_) != FALSE) { 22 | return true; 23 | } 24 | return false; 25 | } 26 | 27 | void LockImpl::Lock() { 28 | ::EnterCriticalSection(&native_handle_); 29 | } 30 | 31 | void LockImpl::Unlock() { 32 | ::LeaveCriticalSection(&native_handle_); 33 | } 34 | 35 | } // namespace internal 36 | } // namespace base 37 | -------------------------------------------------------------------------------- /src/logging.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | #include "stdafx.h" 5 | #include "logging.h" 6 | 7 | #include 8 | #include 9 | typedef HANDLE FileHandle; 10 | typedef HANDLE MutexHandle; 11 | // Windows warns on using write(). It prefers _write(). 12 | #define write(fd, buf, count) _write(fd, buf, static_cast(count)) 13 | // Windows doesn't define STDERR_FILENO. Define it here. 14 | #define STDERR_FILENO 2 15 | 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "lock_impl.h" 25 | #include "stack_trace.h" 26 | #include "chromium_logging_util.h" 27 | 28 | namespace logging { 29 | 30 | namespace { 31 | 32 | const char* const log_severity_names[LOG_NUM_SEVERITIES] = { 33 | "INFO", "WARNING", "ERROR", "FATAL" }; 34 | 35 | const char* log_severity_name(int severity) 36 | { 37 | if (severity >= 0 && severity < LOG_NUM_SEVERITIES) 38 | return log_severity_names[severity]; 39 | return "UNKNOWN"; 40 | } 41 | 42 | int min_log_level = 0; 43 | 44 | LoggingDestination logging_destination = LOG_DEFAULT; 45 | 46 | // For LOG_ERROR and above, always print to stderr. 47 | const int kAlwaysPrintErrorLevel = LOG_ERROR; 48 | 49 | // Which log file to use? This is initialized by InitLogging or 50 | // will be lazily initialized to the default value when it is 51 | // first needed. 52 | typedef std::wstring PathString; 53 | 54 | PathString* log_file_name = NULL; 55 | 56 | // this file is lazily opened and the handle may be NULL 57 | FileHandle log_file = NULL; 58 | 59 | // what should be prepended to each message? 60 | bool log_process_id = false; 61 | bool log_thread_id = false; 62 | bool log_timestamp = true; 63 | bool log_tickcount = false; 64 | 65 | // Should we pop up fatal debug messages in a dialog? 66 | bool show_error_dialogs = false; 67 | 68 | // An assert handler override specified by the client to be called instead of 69 | // the debug message dialog and process termination. 70 | LogAssertHandlerFunction log_assert_handler = NULL; 71 | // A log message handler that gets notified of every log message we process. 72 | LogMessageHandlerFunction log_message_handler = NULL; 73 | 74 | // Helper functions to wrap platform differences. 75 | 76 | DWORD CurrentProcessId() { 77 | return GetCurrentProcessId(); 78 | } 79 | 80 | DWORD TickCount() { 81 | return GetTickCount(); 82 | } 83 | 84 | void DeleteFilePath(const PathString& log_name) { 85 | DeleteFile(log_name.c_str()); 86 | } 87 | 88 | PathString GetDefaultLogFile() { 89 | // On Windows we use the same path as the exe. 90 | wchar_t module_name[MAX_PATH]; 91 | GetModuleFileName(NULL, module_name, MAX_PATH); 92 | 93 | PathString log_file = module_name; 94 | PathString::size_type last_backslash = 95 | log_file.rfind('\\', log_file.size()); 96 | if (last_backslash != PathString::npos) 97 | log_file.erase(last_backslash + 1); 98 | log_file += L"debug.log"; 99 | return log_file; 100 | } 101 | 102 | // This class acts as a wrapper for locking the logging files. 103 | // LoggingLock::Init() should be called from the main thread before any logging 104 | // is done. Then whenever logging, be sure to have a local LoggingLock 105 | // instance on the stack. This will ensure that the lock is unlocked upon 106 | // exiting the frame. 107 | // LoggingLocks can not be nested. 108 | class LoggingLock { 109 | public: 110 | LoggingLock() { 111 | LockLogging(); 112 | } 113 | 114 | ~LoggingLock() { 115 | UnlockLogging(); 116 | } 117 | 118 | static void Init(LogLockingState lock_log, const PathChar* new_log_file) { 119 | if (initialized) 120 | return; 121 | lock_log_file = lock_log; 122 | if (lock_log_file == LOCK_LOG_FILE) { 123 | if (!log_mutex) { 124 | std::wstring safe_name; 125 | if (new_log_file) 126 | safe_name = new_log_file; 127 | else 128 | safe_name = GetDefaultLogFile(); 129 | // \ is not a legal character in mutex names so we replace \ with / 130 | std::replace(safe_name.begin(), safe_name.end(), '\\', '/'); 131 | std::wstring t(L"Global\\"); 132 | t.append(safe_name); 133 | log_mutex = ::CreateMutex(NULL, FALSE, t.c_str()); 134 | 135 | if (log_mutex == NULL) { 136 | #if DEBUG 137 | // Keep the error code for debugging 138 | int error = GetLastError(); // NOLINT 139 | base::debug::BreakDebugger(); 140 | #endif 141 | // Return nicely without putting initialized to true. 142 | return; 143 | } 144 | } 145 | } else { 146 | log_lock = new base::internal::LockImpl(); 147 | } 148 | initialized = true; 149 | } 150 | 151 | private: 152 | static void LockLogging() { 153 | if (lock_log_file == LOCK_LOG_FILE) { 154 | ::WaitForSingleObject(log_mutex, INFINITE); 155 | // WaitForSingleObject could have returned WAIT_ABANDONED. We don't 156 | // abort the process here. UI tests might be crashy sometimes, 157 | // and aborting the test binary only makes the problem worse. 158 | // We also don't use LOG macros because that might lead to an infinite 159 | // loop. For more info see http://crbug.com/18028. 160 | } else { 161 | // use the lock 162 | log_lock->Lock(); 163 | } 164 | } 165 | 166 | static void UnlockLogging() { 167 | if (lock_log_file == LOCK_LOG_FILE) { 168 | ReleaseMutex(log_mutex); 169 | } else { 170 | log_lock->Unlock(); 171 | } 172 | } 173 | 174 | // The lock is used if log file locking is false. It helps us avoid problems 175 | // with multiple threads writing to the log file at the same time. Use 176 | // LockImpl directly instead of using Lock, because Lock makes logging calls. 177 | static base::internal::LockImpl* log_lock; 178 | 179 | // When we don't use a lock, we are using a global mutex. We need to do this 180 | // because LockFileEx is not thread safe. 181 | static MutexHandle log_mutex; 182 | 183 | static bool initialized; 184 | static LogLockingState lock_log_file; 185 | }; 186 | 187 | // static 188 | bool LoggingLock::initialized = false; 189 | // static 190 | base::internal::LockImpl* LoggingLock::log_lock = NULL; 191 | // static 192 | LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE; 193 | 194 | // static 195 | MutexHandle LoggingLock::log_mutex = NULL; 196 | 197 | // Called by logging functions to ensure that debug_file is initialized 198 | // and can be used for writing. Returns false if the file could not be 199 | // initialized. debug_file will be NULL in this case. 200 | bool InitializeLogFileHandle() { 201 | if (log_file) 202 | return true; 203 | 204 | if (!log_file_name) { 205 | // Nobody has called InitLogging to specify a debug log file, so here we 206 | // initialize the log file name to a default. 207 | log_file_name = new PathString(GetDefaultLogFile()); 208 | } 209 | 210 | if ((logging_destination & LOG_TO_FILE) != 0) { 211 | log_file = CreateFile(log_file_name->c_str(), GENERIC_WRITE, 212 | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 213 | OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 214 | if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) { 215 | // try the current directory 216 | log_file = CreateFile(L".\\debug.log", GENERIC_WRITE, 217 | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 218 | OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 219 | if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) { 220 | log_file = NULL; 221 | return false; 222 | } 223 | } 224 | SetFilePointer(log_file, 0, 0, FILE_END); 225 | } 226 | 227 | return true; 228 | } 229 | 230 | void CloseFile(FileHandle log) { 231 | CloseHandle(log); 232 | } 233 | 234 | void CloseLogFileUnlocked() { 235 | if (!log_file) 236 | return; 237 | 238 | CloseFile(log_file); 239 | log_file = NULL; 240 | } 241 | 242 | } // namespace 243 | 244 | LoggingSettings::LoggingSettings() 245 | : logging_dest(LOG_DEFAULT), 246 | log_file(NULL), 247 | lock_log(LOCK_LOG_FILE), 248 | delete_old(APPEND_TO_OLD_LOG_FILE) {} 249 | 250 | bool BaseInitLoggingImpl(const LoggingSettings& settings) { 251 | 252 | logging_destination = settings.logging_dest; 253 | 254 | // ignore file options unless logging to file is set. 255 | if ((logging_destination & LOG_TO_FILE) == 0) 256 | return true; 257 | 258 | LoggingLock::Init(settings.lock_log, settings.log_file); 259 | LoggingLock logging_lock; 260 | 261 | // Calling InitLogging twice or after some log call has already opened the 262 | // default log file will re-initialize to the new options. 263 | CloseLogFileUnlocked(); 264 | 265 | if (!log_file_name) 266 | log_file_name = new PathString(); 267 | *log_file_name = settings.log_file; 268 | if (settings.delete_old == DELETE_OLD_LOG_FILE) 269 | DeleteFilePath(*log_file_name); 270 | 271 | return InitializeLogFileHandle(); 272 | } 273 | 274 | void SetMinLogLevel(int level) { 275 | min_log_level = (std::min)(LOG_FATAL, level); 276 | } 277 | 278 | int GetMinLogLevel() { 279 | return min_log_level; 280 | } 281 | 282 | 283 | void SetLogItems(bool enable_process_id, bool enable_thread_id, 284 | bool enable_timestamp, bool enable_tickcount) { 285 | log_process_id = enable_process_id; 286 | log_thread_id = enable_thread_id; 287 | log_timestamp = enable_timestamp; 288 | log_tickcount = enable_tickcount; 289 | } 290 | 291 | void SetShowErrorDialogs(bool enable_dialogs) { 292 | show_error_dialogs = enable_dialogs; 293 | } 294 | 295 | void SetLogAssertHandler(LogAssertHandlerFunction handler) { 296 | log_assert_handler = handler; 297 | } 298 | 299 | void SetLogMessageHandler(LogMessageHandlerFunction handler) { 300 | log_message_handler = handler; 301 | } 302 | 303 | LogMessageHandlerFunction GetLogMessageHandler() { 304 | return log_message_handler; 305 | } 306 | 307 | 308 | #if !defined(NDEBUG) 309 | // Displays a message box to the user with the error message in it. 310 | // Used for fatal messages, where we close the app simultaneously. 311 | // This is for developers only; we don't use this in circumstances 312 | // (like release builds) where users could see it, since users don't 313 | // understand these messages anyway. 314 | void DisplayDebugMessageInDialog(const std::string& str) { 315 | if (str.empty()) 316 | return; 317 | 318 | if (!show_error_dialogs) 319 | return; 320 | 321 | // For Windows programs, it's possible that the message loop is 322 | // messed up on a fatal error, and creating a MessageBox will cause 323 | // that message loop to be run. Instead, we try to spawn another 324 | // process that displays its command line. We look for "Debug 325 | // Message.exe" in the same directory as the application. If it 326 | // exists, we use it, otherwise, we use a regular message box. 327 | wchar_t prog_name[MAX_PATH]; 328 | GetModuleFileNameW(NULL, prog_name, MAX_PATH); 329 | wchar_t* backslash = wcsrchr(prog_name, '\\'); 330 | if (backslash) 331 | backslash[1] = 0; 332 | wcscat_s(prog_name, MAX_PATH, L"debug_message.exe"); 333 | 334 | std::wstring cmdline = win_string_convert::UTF8ToWide(str); 335 | if (cmdline.empty()) 336 | return; 337 | 338 | STARTUPINFO startup_info; 339 | memset(&startup_info, 0, sizeof(startup_info)); 340 | startup_info.cb = sizeof(startup_info); 341 | 342 | PROCESS_INFORMATION process_info; 343 | if (CreateProcessW(prog_name, &cmdline[0], NULL, NULL, false, 0, NULL, 344 | NULL, &startup_info, &process_info)) { 345 | WaitForSingleObject(process_info.hProcess, INFINITE); 346 | CloseHandle(process_info.hThread); 347 | CloseHandle(process_info.hProcess); 348 | } else { 349 | // debug process broken, let's just do a message box 350 | MessageBoxW(NULL, &cmdline[0], L"Fatal error", 351 | MB_OK | MB_ICONHAND | MB_TOPMOST); 352 | } 353 | } 354 | 355 | #endif // !defined(NDEBUG) 356 | 357 | LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) { 358 | } 359 | 360 | LogMessage::SaveLastError::~SaveLastError() { 361 | ::SetLastError(last_error_); 362 | } 363 | 364 | 365 | LogMessage::LogMessage(const char* file, int line, LogSeverity severity) 366 | : severity_(severity), file_(file), line_(line) { 367 | Init(file, line); 368 | } 369 | 370 | LogMessage::LogMessage(const char* file, int line, std::string* result) 371 | : severity_(LOG_FATAL), file_(file), line_(line) { 372 | Init(file, line); 373 | stream_ << "Check failed: " << *result; 374 | delete result; 375 | } 376 | 377 | LogMessage::LogMessage(const char* file, int line, LogSeverity severity, 378 | std::string* result) 379 | : severity_(severity), file_(file), line_(line) { 380 | Init(file, line); 381 | stream_ << "Check failed: " << *result; 382 | delete result; 383 | } 384 | 385 | LogMessage::~LogMessage() { 386 | #if !defined(NDEBUG) 387 | if (severity_ == LOG_FATAL) { 388 | // Include a stack trace on a fatal. 389 | base::debug::StackTrace trace; 390 | stream_ << std::endl; // Newline to separate from log message. 391 | trace.OutputToStream(&stream_); 392 | } 393 | #endif 394 | stream_ << std::endl; 395 | std::string str_newline(stream_.str()); 396 | 397 | // Give any log message handler first dibs on the message. 398 | if (log_message_handler && 399 | log_message_handler(severity_, file_, line_, 400 | message_start_, str_newline)) { 401 | // The handler took care of it, no further processing. 402 | return; 403 | } 404 | 405 | if ((logging_destination & LOG_TO_SYSTEM_DEBUG_LOG) != 0) { 406 | OutputDebugStringA(str_newline.c_str()); 407 | 408 | ignore_result(fwrite(str_newline.data(), str_newline.size(), 1, stderr)); 409 | fflush(stderr); 410 | } else if (severity_ >= kAlwaysPrintErrorLevel) { 411 | // When we're only outputting to a log file, above a certain log level, we 412 | // should still output to stderr so that we can better detect and diagnose 413 | // problems with unit tests, especially on the buildbots. 414 | ignore_result(fwrite(str_newline.data(), str_newline.size(), 1, stderr)); 415 | fflush(stderr); 416 | } 417 | 418 | // write to log file 419 | if ((logging_destination & LOG_TO_FILE) != 0) { 420 | // We can have multiple threads and/or processes, so try to prevent them 421 | // from clobbering each other's writes. 422 | // If the client app did not call InitLogging, and the lock has not 423 | // been created do it now. We do this on demand, but if two threads try 424 | // to do this at the same time, there will be a race condition to create 425 | // the lock. This is why InitLogging should be called from the main 426 | // thread at the beginning of execution. 427 | LoggingLock::Init(LOCK_LOG_FILE, NULL); 428 | LoggingLock logging_lock; 429 | if (InitializeLogFileHandle()) { 430 | SetFilePointer(log_file, 0, 0, SEEK_END); 431 | DWORD num_written; 432 | WriteFile(log_file, 433 | static_cast(str_newline.c_str()), 434 | static_cast(str_newline.length()), 435 | &num_written, 436 | NULL); 437 | } 438 | } 439 | 440 | if (severity_ == LOG_FATAL) { 441 | // Ensure the first characters of the string are on the stack so they 442 | // are contained in minidumps for diagnostic purposes. 443 | char str_stack[1024]; 444 | //str_newline.copy(str_stack, arraysize(str_stack)); 445 | base::debug::Alias(str_stack); 446 | 447 | if (log_assert_handler) { 448 | // Make a copy of the string for the handler out of paranoia. 449 | log_assert_handler(std::string(stream_.str())); 450 | } else { 451 | // Don't use the string with the newline, get a fresh version to send to 452 | // the debug message process. We also don't display assertions to the 453 | // user in release mode. The enduser can't do anything with this 454 | // information, and displaying message boxes when the application is 455 | // hosed can cause additional problems. 456 | #ifndef NDEBUG 457 | DisplayDebugMessageInDialog(stream_.str()); 458 | #endif 459 | // Crash the process to generate a dump. 460 | base::debug::BreakDebugger(); 461 | } 462 | } 463 | } 464 | 465 | // writes the common header info to the stream 466 | void LogMessage::Init(const char* file, int line) { 467 | std::string filename(file); 468 | size_t last_slash_pos = filename.find_last_of("\\/"); 469 | if (last_slash_pos != std::string::npos) 470 | filename = remove_prefix(filename, last_slash_pos + 1); 471 | 472 | // TODO(darin): It might be nice if the columns were fixed width. 473 | 474 | stream_ << '['; 475 | if (log_process_id) 476 | stream_ << CurrentProcessId() << ':'; 477 | if (log_thread_id) 478 | stream_ << GetCurrentThreadId() << ':'; 479 | if (log_timestamp) { 480 | time_t t = time(NULL); 481 | struct tm local_time = {0}; 482 | #if _MSC_VER >= 1400 483 | localtime_s(&local_time, &t); 484 | #else 485 | localtime_r(&t, &local_time); 486 | #endif 487 | struct tm* tm_time = &local_time; 488 | stream_ << std::setfill('0') 489 | << std::setw(2) << 1 + tm_time->tm_mon 490 | << std::setw(2) << tm_time->tm_mday 491 | << '/' 492 | << std::setw(2) << tm_time->tm_hour 493 | << std::setw(2) << tm_time->tm_min 494 | << std::setw(2) << tm_time->tm_sec 495 | << ':'; 496 | } 497 | if (log_tickcount) 498 | stream_ << TickCount() << ':'; 499 | if (severity_ >= 0) 500 | stream_ << log_severity_name(severity_); 501 | else 502 | stream_ << "VERBOSE" << -severity_; 503 | 504 | stream_ << ":" << filename << "(" << line << ")] "; 505 | 506 | message_start_ = stream_.tellp(); 507 | } 508 | 509 | // This has already been defined in the header, but defining it again as DWORD 510 | // ensures that the type used in the header is equivalent to DWORD. If not, 511 | // the redefinition is a compile error. 512 | typedef DWORD SystemErrorCode; 513 | 514 | SystemErrorCode GetLastSystemErrorCode() { 515 | return ::GetLastError(); 516 | } 517 | 518 | BASE_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code) { 519 | const int error_message_buffer_size = 256; 520 | char msgbuf[error_message_buffer_size]; 521 | DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; 522 | DWORD len = FormatMessageA(flags, NULL, error_code, 0, msgbuf, 523 | arraysize(msgbuf), NULL); 524 | if (len) { 525 | char temp_buf[error_message_buffer_size] = {0}; 526 | _snprintf_s(temp_buf, sizeof(temp_buf), "(0x%X|%u): %s\n", error_code, error_code,msgbuf); 527 | return remove_suffix(std::string(temp_buf), 3); 528 | } 529 | return std::string(); 530 | } 531 | 532 | Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file, 533 | int line, 534 | LogSeverity severity, 535 | SystemErrorCode err) 536 | : err_(err), 537 | log_message_(file, line, severity) { 538 | } 539 | 540 | Win32ErrorLogMessage::~Win32ErrorLogMessage() { 541 | stream() << ": " << SystemErrorCodeToString(err_); 542 | // We're about to crash (CHECK). Put |err_| on the stack (by placing it in a 543 | // field) and use Alias in hopes that it makes it into crash dumps. 544 | DWORD last_error = err_; 545 | base::debug::Alias(&last_error); 546 | } 547 | 548 | void CloseLogFile() { 549 | LoggingLock logging_lock; 550 | CloseLogFileUnlocked(); 551 | } 552 | 553 | void RawLog(int level, const char* message) { 554 | if (level >= min_log_level) { 555 | size_t bytes_written = 0; 556 | const size_t message_len = strlen(message); 557 | int rv; 558 | while (bytes_written < message_len) { 559 | rv = HANDLE_EINTR( 560 | write(STDERR_FILENO, message + bytes_written, 561 | message_len - bytes_written)); 562 | if (rv < 0) { 563 | // Give up, nothing we can do now. 564 | break; 565 | } 566 | bytes_written += rv; 567 | } 568 | 569 | if (message_len > 0 && message[message_len - 1] != '\n') { 570 | do { 571 | rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1)); 572 | if (rv < 0) { 573 | // Give up, nothing we can do now. 574 | break; 575 | } 576 | } while (rv != 1); 577 | } 578 | } 579 | 580 | if (level == LOG_FATAL) 581 | base::debug::BreakDebugger(); 582 | } 583 | 584 | // This was defined at the beginning of this file. 585 | #undef write 586 | 587 | std::wstring GetLogFileFullPath() { 588 | if (log_file_name) 589 | return *log_file_name; 590 | return std::wstring(); 591 | } 592 | 593 | } // namespace logging 594 | 595 | std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) { 596 | return out << win_string_convert::WideToUTF8(std::wstring(wstr)); 597 | } 598 | -------------------------------------------------------------------------------- /src/logging.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define BASE_EXPORT 13 | 14 | // 15 | // Optional message capabilities 16 | // ----------------------------- 17 | // Assertion failed messages and fatal errors are displayed in a dialog box 18 | // before the application exits. However, running this UI creates a message 19 | // loop, which causes application messages to be processed and potentially 20 | // dispatched to existing application windows. Since the application is in a 21 | // bad state when this assertion dialog is displayed, these messages may not 22 | // get processed and hang the dialog, or the application might go crazy. 23 | // 24 | // Therefore, it can be beneficial to display the error dialog in a separate 25 | // process from the main application. When the logging system needs to display 26 | // a fatal error dialog box, it will look for a program called 27 | // "DebugMessage.exe" in the same directory as the application executable. It 28 | // will run this application with the message as the command line, and will 29 | // not include the name of the application as is traditional for easier 30 | // parsing. 31 | // 32 | // The code for DebugMessage.exe is only one line. In WinMain, do: 33 | // MessageBox(NULL, GetCommandLineW(), L"Fatal Error", 0); 34 | // 35 | // If DebugMessage.exe is not found, the logging code will use a normal 36 | // MessageBox, potentially causing the problems discussed above. 37 | 38 | 39 | // Instructions 40 | // ------------ 41 | // 42 | // Make a bunch of macros for logging. The way to log things is to stream 43 | // things to LOG(). E.g., 44 | // 45 | // LOG(INFO) << "Found " << num_cookies << " cookies"; 46 | // 47 | // You can also do conditional logging: 48 | // 49 | // LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; 50 | // 51 | // The CHECK(condition) macro is active in both debug and release builds and 52 | // effectively performs a LOG(FATAL) which terminates the process and 53 | // generates a crashdump unless a debugger is attached. 54 | // 55 | // There are also "debug mode" logging macros like the ones above: 56 | // 57 | // DLOG(INFO) << "Found cookies"; 58 | // 59 | // DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; 60 | // 61 | // All "debug mode" logging is compiled away to nothing for non-debug mode 62 | // compiles. LOG_IF and development flags also work well together 63 | // because the code can be compiled away sometimes. 64 | // 65 | // We also have 66 | // 67 | // LOG_ASSERT(assertion); 68 | // DLOG_ASSERT(assertion); 69 | // 70 | // which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion; 71 | 72 | // 73 | // We also override the standard 'assert' to use 'DLOG_ASSERT'. 74 | // 75 | // Lastly, there is: 76 | // 77 | // PLOG(ERROR) << "Couldn't do foo"; 78 | // DPLOG(ERROR) << "Couldn't do foo"; 79 | // PLOG_IF(ERROR, cond) << "Couldn't do foo"; 80 | // DPLOG_IF(ERROR, cond) << "Couldn't do foo"; 81 | // PCHECK(condition) << "Couldn't do foo"; 82 | // DPCHECK(condition) << "Couldn't do foo"; 83 | // 84 | // which append the last system error to the message in string form (taken from 85 | // GetLastError() on Windows and errno on POSIX). 86 | // 87 | // The supported severity levels for macros that allow you to specify one 88 | // are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL. 89 | // 90 | // Very important: logging a message at the FATAL severity level causes 91 | // the program to terminate (after the message is logged). 92 | // 93 | // There is the special severity of DFATAL, which logs FATAL in debug mode, 94 | // ERROR in normal mode. 95 | 96 | namespace logging { 97 | // TODO(avi): do we want to do a unification of character types here? 98 | typedef wchar_t PathChar; 99 | 100 | // Where to record logging output? A flat file and/or system debug log 101 | // via OutputDebugString. 102 | enum LoggingDestination { 103 | LOG_NONE = 0, 104 | LOG_TO_FILE = 1 << 0, 105 | LOG_TO_SYSTEM_DEBUG_LOG = 1 << 1, 106 | 107 | LOG_TO_ALL = LOG_TO_FILE | LOG_TO_SYSTEM_DEBUG_LOG, 108 | 109 | // On Windows, use a file next to the exe; on POSIX platforms, where 110 | // it may not even be possible to locate the executable on disk, use 111 | // stderr. 112 | LOG_DEFAULT = LOG_TO_FILE, 113 | }; 114 | 115 | // Indicates that the log file should be locked when being written to. 116 | // Unless there is only one single-threaded process that is logging to 117 | // the log file, the file should be locked during writes to make each 118 | // log output atomic. Other writers will block. 119 | // 120 | // All processes writing to the log file must have their locking set for it to 121 | // work properly. Defaults to LOCK_LOG_FILE. 122 | enum LogLockingState { LOCK_LOG_FILE, DONT_LOCK_LOG_FILE }; 123 | 124 | // On startup, should we delete or append to an existing log file (if any)? 125 | // Defaults to APPEND_TO_OLD_LOG_FILE. 126 | enum OldFileDeletionState { DELETE_OLD_LOG_FILE, APPEND_TO_OLD_LOG_FILE }; 127 | 128 | struct BASE_EXPORT LoggingSettings { 129 | // The defaults values are: 130 | // 131 | // logging_dest: LOG_DEFAULT 132 | // log_file: NULL 133 | // lock_log: LOCK_LOG_FILE 134 | // delete_old: APPEND_TO_OLD_LOG_FILE 135 | LoggingSettings(); 136 | 137 | LoggingDestination logging_dest; 138 | 139 | // The three settings below have an effect only when LOG_TO_FILE is 140 | // set in |logging_dest|. 141 | const PathChar* log_file; 142 | LogLockingState lock_log; 143 | OldFileDeletionState delete_old; 144 | }; 145 | 146 | // Define different names for the BaseInitLoggingImpl() function depending on 147 | // whether NDEBUG is defined or not so that we'll fail to link if someone tries 148 | // to compile logging.cc with NDEBUG but includes logging.h without defining it, 149 | // or vice versa. 150 | #if NDEBUG 151 | #define BaseInitLoggingImpl BaseInitLoggingImpl_built_with_NDEBUG 152 | #else 153 | #define BaseInitLoggingImpl BaseInitLoggingImpl_built_without_NDEBUG 154 | #endif 155 | 156 | // Implementation of the InitLogging() method declared below. We use a 157 | // more-specific name so we can #define it above without affecting other code 158 | // that has named stuff "InitLogging". 159 | BASE_EXPORT bool BaseInitLoggingImpl(const LoggingSettings& settings); 160 | 161 | // Sets the log file name and other global logging state. Calling this function 162 | // is recommended, and is normally done at the beginning of application init. 163 | // If you don't call it, all the flags will be initialized to their default 164 | // values, and there is a race condition that may leak a critical section 165 | // object if two threads try to do the first log at the same time. 166 | // See the definition of the enums above for descriptions and default values. 167 | // 168 | // The default log file is initialized to "debug.log" in the application 169 | // directory. You probably don't want this, especially since the program 170 | // directory may not be writable on an enduser's system. 171 | // 172 | // This function may be called a second time to re-direct logging (e.g after 173 | // loging in to a user partition), however it should never be called more than 174 | // twice. 175 | inline bool InitLogging(const LoggingSettings& settings) { 176 | return BaseInitLoggingImpl(settings); 177 | } 178 | 179 | BASE_EXPORT void SetMinLogLevel(int level); 180 | 181 | // Gets the current log level. 182 | BASE_EXPORT int GetMinLogLevel(); 183 | 184 | // Sets the common items you want to be prepended to each log message. 185 | // process and thread IDs default to off, the timestamp defaults to on. 186 | // If this function is not called, logging defaults to writing the timestamp 187 | // only. 188 | BASE_EXPORT void SetLogItems(bool enable_process_id, bool enable_thread_id, 189 | bool enable_timestamp, bool enable_tickcount); 190 | 191 | // Sets whether or not you'd like to see fatal debug messages popped up in 192 | // a dialog box or not. 193 | // Dialogs are not shown by default. 194 | BASE_EXPORT void SetShowErrorDialogs(bool enable_dialogs); 195 | 196 | // Sets the Log Assert Handler that will be used to notify of check failures. 197 | // The default handler shows a dialog box and then terminate the process, 198 | // however clients can use this function to override with their own handling 199 | // (e.g. a silent one for Unit Tests) 200 | typedef void (*LogAssertHandlerFunction)(const std::string& str); 201 | BASE_EXPORT void SetLogAssertHandler(LogAssertHandlerFunction handler); 202 | 203 | // Sets the Log Message Handler that gets passed every log message before 204 | // it's sent to other log destinations (if any). 205 | // Returns true to signal that it handled the message and the message 206 | // should not be sent to other log destinations. 207 | typedef bool (*LogMessageHandlerFunction)(int severity, 208 | const char* file, int line, std::streamoff message_start, const std::string& str); 209 | BASE_EXPORT void SetLogMessageHandler(LogMessageHandlerFunction handler); 210 | BASE_EXPORT LogMessageHandlerFunction GetLogMessageHandler(); 211 | 212 | typedef int LogSeverity; 213 | const LogSeverity LOG_VERBOSE = -1; // This is level 1 verbosity 214 | // Note: the log severities are used to index into the array of names, 215 | // see log_severity_names. 216 | const LogSeverity LOG_INFO = 0; 217 | const LogSeverity LOG_WARNING = 1; 218 | const LogSeverity LOG_ERROR = 2; 219 | const LogSeverity LOG_FATAL = 3; 220 | const LogSeverity LOG_NUM_SEVERITIES = 4; 221 | 222 | // LOG_DFATAL is LOG_FATAL in debug mode, ERROR in normal mode 223 | #ifdef NDEBUG 224 | const LogSeverity LOG_DFATAL = LOG_ERROR; 225 | #else 226 | const LogSeverity LOG_DFATAL = LOG_FATAL; 227 | #endif 228 | 229 | // A few definitions of macros that don't generate much code. These are used 230 | // by LOG() and LOG_IF, etc. Since these are used all over our code, it's 231 | // better to have compact code for these operations. 232 | #define COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ...) \ 233 | logging::ClassName(__FILE__, __LINE__, logging::LOG_INFO , ##__VA_ARGS__) 234 | #define COMPACT_GOOGLE_LOG_EX_WARNING(ClassName, ...) \ 235 | logging::ClassName(__FILE__, __LINE__, logging::LOG_WARNING , ##__VA_ARGS__) 236 | #define COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ...) \ 237 | logging::ClassName(__FILE__, __LINE__, logging::LOG_ERROR , ##__VA_ARGS__) 238 | #define COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ...) \ 239 | logging::ClassName(__FILE__, __LINE__, logging::LOG_FATAL , ##__VA_ARGS__) 240 | #define COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName, ...) \ 241 | logging::ClassName(__FILE__, __LINE__, logging::LOG_DFATAL , ##__VA_ARGS__) 242 | 243 | #define COMPACT_GOOGLE_LOG_INFO \ 244 | COMPACT_GOOGLE_LOG_EX_INFO(LogMessage) 245 | #define COMPACT_GOOGLE_LOG_WARNING \ 246 | COMPACT_GOOGLE_LOG_EX_WARNING(LogMessage) 247 | #define COMPACT_GOOGLE_LOG_ERROR \ 248 | COMPACT_GOOGLE_LOG_EX_ERROR(LogMessage) 249 | #define COMPACT_GOOGLE_LOG_FATAL \ 250 | COMPACT_GOOGLE_LOG_EX_FATAL(LogMessage) 251 | #define COMPACT_GOOGLE_LOG_DFATAL \ 252 | COMPACT_GOOGLE_LOG_EX_DFATAL(LogMessage) 253 | 254 | // wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets 255 | // substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us 256 | // to keep using this syntax, we define this macro to do the same thing 257 | // as COMPACT_GOOGLE_LOG_ERROR, and also define ERROR the same way that 258 | // the Windows SDK does for consistency. 259 | #define ERROR 0 260 | #define COMPACT_GOOGLE_LOG_EX_0(ClassName, ...) \ 261 | COMPACT_GOOGLE_LOG_EX_ERROR(ClassName , ##__VA_ARGS__) 262 | #define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR 263 | // Needed for LOG_IS_ON(ERROR). 264 | const LogSeverity LOG_0 = LOG_ERROR; 265 | 266 | // As special cases, we can assume that LOG_IS_ON(FATAL) always holds. Also, 267 | // LOG_IS_ON(DFATAL) always holds in debug mode. In particular, CHECK()s will 268 | // always fire if they fail. 269 | #define LOG_IS_ON(severity) \ 270 | ((::logging::LOG_ ## severity) >= ::logging::GetMinLogLevel()) 271 | 272 | 273 | // Helper macro which avoids evaluating the arguments to a stream if 274 | // the condition doesn't hold. 275 | #define LAZY_STREAM(stream, condition) \ 276 | !(condition) ? (void) 0 : ::logging::LogMessageVoidify() & (stream) 277 | 278 | // We use the preprocessor's merging operator, "##", so that, e.g., 279 | // LOG(INFO) becomes the token COMPACT_GOOGLE_LOG_INFO. There's some funny 280 | // subtle difference between ostream member streaming functions (e.g., 281 | // ostream::operator<<(int) and ostream non-member streaming functions 282 | // (e.g., ::operator<<(ostream&, string&): it turns out that it's 283 | // impossible to stream something like a string directly to an unnamed 284 | // ostream. We employ a neat hack by calling the stream() member 285 | // function of LogMessage which seems to avoid the problem. 286 | #define LOG_STREAM(severity) COMPACT_GOOGLE_LOG_ ## severity.stream() 287 | 288 | #define LOG(severity) LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity)) 289 | #define LOG_IF(severity, condition) \ 290 | LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity) && (condition)) 291 | 292 | #define SYSLOG(severity) LOG(severity) 293 | #define SYSLOG_IF(severity, condition) LOG_IF(severity, condition) 294 | 295 | #define LOG_ASSERT(condition) \ 296 | LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". " 297 | #define SYSLOG_ASSERT(condition) \ 298 | SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". " 299 | 300 | #define PLOG_STREAM(severity) \ 301 | COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \ 302 | ::logging::GetLastSystemErrorCode()).stream() 303 | 304 | 305 | #define PLOG(severity) \ 306 | LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity)) 307 | 308 | #define PLOG_IF(severity, condition) \ 309 | LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity) && (condition)) 310 | 311 | // The actual stream used isn't important. 312 | #define EAT_STREAM_PARAMETERS \ 313 | true ? (void) 0 : ::logging::LogMessageVoidify() & LOG_STREAM(FATAL) 314 | 315 | // CHECK dies with a fatal error if condition is not true. It is *not* 316 | // controlled by NDEBUG, so the check will be executed regardless of 317 | // compilation mode. 318 | // 319 | // We make sure CHECK et al. always evaluates their arguments, as 320 | // doing CHECK(FunctionWithSideEffect()) is a common idiom. 321 | 322 | #if defined(NDEBUG) 323 | 324 | // Make all CHECK functions discard their log strings to reduce code 325 | // bloat for official release builds. 326 | 327 | // TODO(akalin): This would be more valuable if there were some way to 328 | // remove BreakDebugger() from the backtrace, perhaps by turning it 329 | // into a macro (like __debugbreak() on Windows). 330 | #define CHECK(condition) \ 331 | !(condition) ? ::base::debug::BreakDebugger() : EAT_STREAM_PARAMETERS 332 | 333 | #define PCHECK(condition) CHECK(condition) 334 | 335 | #define CHECK_OP(name, op, val1, val2) CHECK((val1) op (val2)) 336 | 337 | #else 338 | 339 | #define CHECK(condition) \ 340 | LAZY_STREAM(LOG_STREAM(FATAL), !(condition)) \ 341 | << "Check failed: " #condition ". " 342 | 343 | #define PCHECK(condition) \ 344 | LAZY_STREAM(PLOG_STREAM(FATAL), !(condition)) \ 345 | << "Check failed: " #condition ". " 346 | 347 | // Helper macro for binary operators. 348 | // Don't use this macro directly in your code, use CHECK_EQ et al below. 349 | // 350 | // TODO(akalin): Rewrite this so that constructs like if (...) 351 | // CHECK_EQ(...) else { ... } work properly. 352 | #define CHECK_OP(name, op, val1, val2) \ 353 | if (std::string* _result = \ 354 | logging::Check##name##Impl((val1), (val2), \ 355 | #val1 " " #op " " #val2)) \ 356 | logging::LogMessage(__FILE__, __LINE__, _result).stream() 357 | 358 | #endif 359 | 360 | // Build the error message string. This is separate from the "Impl" 361 | // function template because it is not performance critical and so can 362 | // be out of line, while the "Impl" code should be inline. Caller 363 | // takes ownership of the returned string. 364 | template 365 | std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) { 366 | std::ostringstream ss; 367 | ss << names << " (" << v1 << " vs. " << v2 << ")"; 368 | std::string* msg = new std::string(ss.str()); 369 | return msg; 370 | } 371 | 372 | // Helper functions for CHECK_OP macro. 373 | // The (int, int) specialization works around the issue that the compiler 374 | // will not instantiate the template version of the function on values of 375 | // unnamed enum type - see comment below. 376 | #define DEFINE_CHECK_OP_IMPL(name, op) \ 377 | template \ 378 | inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \ 379 | const char* names) { \ 380 | if (v1 op v2) return NULL; \ 381 | else return MakeCheckOpString(v1, v2, names); \ 382 | } \ 383 | inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \ 384 | if (v1 op v2) return NULL; \ 385 | else return MakeCheckOpString(v1, v2, names); \ 386 | } 387 | DEFINE_CHECK_OP_IMPL(EQ, ==) 388 | DEFINE_CHECK_OP_IMPL(NE, !=) 389 | DEFINE_CHECK_OP_IMPL(LE, <=) 390 | DEFINE_CHECK_OP_IMPL(LT, < ) 391 | DEFINE_CHECK_OP_IMPL(GE, >=) 392 | DEFINE_CHECK_OP_IMPL(GT, > ) 393 | #undef DEFINE_CHECK_OP_IMPL 394 | 395 | #define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2) 396 | #define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2) 397 | #define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2) 398 | #define CHECK_LT(val1, val2) CHECK_OP(LT, < , val1, val2) 399 | #define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2) 400 | #define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2) 401 | 402 | #if defined(NDEBUG) 403 | #define ENABLE_DLOG 0 404 | #else 405 | #define ENABLE_DLOG 1 406 | #endif 407 | 408 | #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) 409 | #define DCHECK_IS_ON 0 410 | #else 411 | #define DCHECK_IS_ON 1 412 | #endif 413 | 414 | // Definitions for DLOG et al. 415 | 416 | #if ENABLE_DLOG 417 | 418 | #define DLOG_IS_ON(severity) LOG_IS_ON(severity) 419 | #define DLOG_IF(severity, condition) LOG_IF(severity, condition) 420 | #define DLOG_ASSERT(condition) LOG_ASSERT(condition) 421 | #define DPLOG_IF(severity, condition) PLOG_IF(severity, condition) 422 | 423 | #else // ENABLE_DLOG 424 | 425 | // If ENABLE_DLOG is off, we want to avoid emitting any references to 426 | // |condition| (which may reference a variable defined only if NDEBUG 427 | // is not defined). Contrast this with DCHECK et al., which has 428 | // different behavior. 429 | 430 | #define DLOG_IS_ON(severity) false 431 | #define DLOG_IF(severity, condition) EAT_STREAM_PARAMETERS 432 | #define DLOG_ASSERT(condition) EAT_STREAM_PARAMETERS 433 | #define DPLOG_IF(severity, condition) EAT_STREAM_PARAMETERS 434 | 435 | #endif // ENABLE_DLOG 436 | 437 | // DEBUG_MODE is for uses like 438 | // if (DEBUG_MODE) foo.CheckThatFoo(); 439 | // instead of 440 | // #ifndef NDEBUG 441 | // foo.CheckThatFoo(); 442 | // #endif 443 | // 444 | // We tie its state to ENABLE_DLOG. 445 | enum { DEBUG_MODE = ENABLE_DLOG }; 446 | 447 | #undef ENABLE_DLOG 448 | 449 | #define DLOG(severity) \ 450 | LAZY_STREAM(LOG_STREAM(severity), DLOG_IS_ON(severity)) 451 | 452 | #define DPLOG(severity) \ 453 | LAZY_STREAM(PLOG_STREAM(severity), DLOG_IS_ON(severity)) 454 | 455 | // Definitions for DCHECK et al. 456 | 457 | #if DCHECK_IS_ON 458 | 459 | #define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \ 460 | COMPACT_GOOGLE_LOG_EX_FATAL(ClassName , ##__VA_ARGS__) 461 | #define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_FATAL 462 | const LogSeverity LOG_DCHECK = LOG_FATAL; 463 | 464 | #else // DCHECK_IS_ON 465 | 466 | // These are just dummy values. 467 | #define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \ 468 | COMPACT_GOOGLE_LOG_EX_INFO(ClassName , ##__VA_ARGS__) 469 | #define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_INFO 470 | const LogSeverity LOG_DCHECK = LOG_INFO; 471 | 472 | #endif // DCHECK_IS_ON 473 | 474 | // DCHECK et al. make sure to reference |condition| regardless of 475 | // whether DCHECKs are enabled; this is so that we don't get unused 476 | // variable warnings if the only use of a variable is in a DCHECK. 477 | // This behavior is different from DLOG_IF et al. 478 | 479 | #define DCHECK(condition) \ 480 | LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON && !(condition)) \ 481 | << "Check failed: " #condition ". " 482 | 483 | #define DPCHECK(condition) \ 484 | LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON && !(condition)) \ 485 | << "Check failed: " #condition ". " 486 | 487 | // Helper macro for binary operators. 488 | // Don't use this macro directly in your code, use DCHECK_EQ et al below. 489 | #define DCHECK_OP(name, op, val1, val2) \ 490 | if (DCHECK_IS_ON) \ 491 | if (std::string* _result = \ 492 | logging::Check##name##Impl((val1), (val2), \ 493 | #val1 " " #op " " #val2)) \ 494 | logging::LogMessage( \ 495 | __FILE__, __LINE__, ::logging::LOG_DCHECK, \ 496 | _result).stream() 497 | 498 | // Equality/Inequality checks - compare two values, and log a 499 | // LOG_DCHECK message including the two values when the result is not 500 | // as expected. The values must have operator<<(ostream, ...) 501 | // defined. 502 | // 503 | // You may append to the error message like so: 504 | // DCHECK_NE(1, 2) << ": The world must be ending!"; 505 | // 506 | // We are very careful to ensure that each argument is evaluated exactly 507 | // once, and that anything which is legal to pass as a function argument is 508 | // legal here. In particular, the arguments may be temporary expressions 509 | // which will end up being destroyed at the end of the apparent statement, 510 | // for example: 511 | // DCHECK_EQ(string("abc")[1], 'b'); 512 | // 513 | // WARNING: These may not compile correctly if one of the arguments is a pointer 514 | // and the other is NULL. To work around this, simply static_cast NULL to the 515 | // type of the desired pointer. 516 | 517 | #define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2) 518 | #define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2) 519 | #define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2) 520 | #define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2) 521 | #define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2) 522 | #define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2) 523 | 524 | // Redefine the standard assert to use our nice log files 525 | #undef assert 526 | #define assert(x) DLOG_ASSERT(x) 527 | 528 | // This class more or less represents a particular log message. You 529 | // create an instance of LogMessage and then stream stuff to it. 530 | // When you finish streaming to it, ~LogMessage is called and the 531 | // full message gets streamed to the appropriate destination. 532 | // 533 | // You shouldn't actually use LogMessage's constructor to log things, 534 | // though. You should use the LOG() macro (and variants thereof) 535 | // above. 536 | class BASE_EXPORT LogMessage { 537 | public: 538 | // Used for LOG(severity). 539 | LogMessage(const char* file, int line, LogSeverity severity); 540 | 541 | // Used for CHECK_EQ(), etc. Takes ownership of the given string. 542 | // Implied severity = LOG_FATAL. 543 | LogMessage(const char* file, int line, std::string* result); 544 | 545 | // Used for DCHECK_EQ(), etc. Takes ownership of the given string. 546 | LogMessage(const char* file, int line, LogSeverity severity, 547 | std::string* result); 548 | 549 | ~LogMessage(); 550 | 551 | std::ostream& stream() { return stream_; } 552 | 553 | private: 554 | void Init(const char* file, int line); 555 | 556 | LogSeverity severity_; 557 | std::ostringstream stream_; 558 | std::streamoff message_start_; // Offset of the start of the message (past prefix 559 | // info). 560 | // The file and line information passed in to the constructor. 561 | const char* file_; 562 | const int line_; 563 | 564 | 565 | // Stores the current value of GetLastError in the constructor and restores 566 | // it in the destructor by calling SetLastError. 567 | // This is useful since the LogMessage class uses a lot of Win32 calls 568 | // that will lose the value of GLE and the code that called the log function 569 | // will have lost the thread error value when the log call returns. 570 | class SaveLastError { 571 | public: 572 | SaveLastError(); 573 | ~SaveLastError(); 574 | 575 | unsigned long get_error() const { return last_error_; } 576 | 577 | protected: 578 | unsigned long last_error_; 579 | }; 580 | 581 | SaveLastError last_error_; 582 | 583 | // DISALLOW_COPY_AND_ASSIGN 584 | LogMessage(const LogMessage&); 585 | void operator=(const LogMessage&); 586 | }; 587 | 588 | // A non-macro interface to the log facility; (useful 589 | // when the logging level is not a compile-time constant). 590 | inline void LogAtLevel(int const log_level, std::string const &msg) { 591 | LogMessage(__FILE__, __LINE__, log_level).stream() << msg; 592 | } 593 | 594 | // This class is used to explicitly ignore values in the conditional 595 | // logging macros. This avoids compiler warnings like "value computed 596 | // is not used" and "statement has no effect". 597 | class LogMessageVoidify { 598 | public: 599 | LogMessageVoidify() { } 600 | // This has to be an operator with a precedence lower than << but 601 | // higher than ?: 602 | void operator&(std::ostream&) { } 603 | }; 604 | 605 | typedef unsigned long SystemErrorCode; 606 | 607 | 608 | // Alias for ::GetLastError() on Windows and errno on POSIX. Avoids having to 609 | // pull in windows.h just for GetLastError() and DWORD. 610 | BASE_EXPORT SystemErrorCode GetLastSystemErrorCode(); 611 | BASE_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code); 612 | 613 | // Appends a formatted system message of the GetLastError() type. 614 | class BASE_EXPORT Win32ErrorLogMessage { 615 | public: 616 | Win32ErrorLogMessage(const char* file, 617 | int line, 618 | LogSeverity severity, 619 | SystemErrorCode err); 620 | 621 | // Appends the error message before destructing the encapsulated class. 622 | ~Win32ErrorLogMessage(); 623 | 624 | std::ostream& stream() { return log_message_.stream(); } 625 | 626 | private: 627 | SystemErrorCode err_; 628 | LogMessage log_message_; 629 | 630 | // DISALLOW_COPY_AND_ASSIGN 631 | Win32ErrorLogMessage(const Win32ErrorLogMessage&); 632 | void operator=(const Win32ErrorLogMessage&); 633 | }; 634 | 635 | 636 | // Closes the log file explicitly if open. 637 | // NOTE: Since the log file is opened as necessary by the action of logging 638 | // statements, there's no guarantee that it will stay closed 639 | // after this call. 640 | BASE_EXPORT void CloseLogFile(); 641 | 642 | // Async signal safe logging mechanism. 643 | BASE_EXPORT void RawLog(int level, const char* message); 644 | 645 | #define RAW_LOG(level, message) logging::RawLog(logging::LOG_ ## level, message) 646 | 647 | #define RAW_CHECK(condition) \ 648 | do { \ 649 | if (!(condition)) \ 650 | logging::RawLog(logging::LOG_FATAL, "Check failed: " #condition "\n"); \ 651 | } while (0) 652 | 653 | // Returns the default log file path. 654 | BASE_EXPORT std::wstring GetLogFileFullPath(); 655 | 656 | 657 | } // namespace logging 658 | 659 | // These functions are provided as a convenience for logging, which is where we 660 | // use streams (it is against Google style to use streams in other places). It 661 | // is designed to allow you to emit non-ASCII Unicode strings to the log file, 662 | // which is normally ASCII. It is relatively slow, so try not to use it for 663 | // common cases. Non-ASCII characters will be converted to UTF-8 by these 664 | // operators. 665 | BASE_EXPORT std::ostream& operator<<(std::ostream& out, const wchar_t* wstr); 666 | inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) { 667 | return out << wstr.c_str(); 668 | } 669 | 670 | -------------------------------------------------------------------------------- /src/stack_trace.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | #include "stdafx.h" 5 | #include "stack_trace.h" 6 | 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include "chromium_logging_util.h" 13 | 14 | namespace base { 15 | namespace debug { 16 | 17 | StackTrace::StackTrace(const void* const* trace, size_t count) { 18 | count = (std::min)(count, arraysize(trace_)); 19 | if (count) 20 | memcpy(trace_, trace, count * sizeof(trace_[0])); 21 | count_ = count; 22 | } 23 | 24 | StackTrace::~StackTrace() { 25 | } 26 | 27 | const void *const *StackTrace::Addresses(size_t* count) const { 28 | *count = count_; 29 | if (count_) 30 | return trace_; 31 | return NULL; 32 | } 33 | 34 | std::string StackTrace::ToString() const { 35 | std::stringstream stream; 36 | #if !defined(__UCLIBC__) 37 | OutputToStream(&stream); 38 | #endif 39 | return stream.str(); 40 | } 41 | 42 | } // namespace debug 43 | } // namespace base 44 | -------------------------------------------------------------------------------- /src/stack_trace.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef BASE_DEBUG_STACK_TRACE_H_ 6 | #define BASE_DEBUG_STACK_TRACE_H_ 7 | 8 | #include 9 | #include 10 | 11 | struct _EXCEPTION_POINTERS; 12 | 13 | 14 | namespace base { 15 | namespace debug { 16 | 17 | // Enables stack dump to console output on exception and signals. 18 | // When enabled, the process will quit immediately. This is meant to be used in 19 | // unit_tests only! This is not thread-safe: only call from main thread. 20 | bool EnableInProcessStackDumping(); 21 | 22 | // A different version of EnableInProcessStackDumping that also works for 23 | // sandboxed processes. For more details take a look at the description 24 | // of EnableInProcessStackDumping. 25 | // Calling this function on Linux opens /proc/self/maps and caches its 26 | // contents. In DEBUG builds, this function also opens the object files that 27 | // are loaded in memory and caches their file descriptors (this cannot be 28 | // done in official builds because it has security implications). 29 | bool EnableInProcessStackDumpingForSandbox(); 30 | 31 | // A stacktrace can be helpful in debugging. For example, you can include a 32 | // stacktrace member in a object (probably around #ifndef NDEBUG) so that you 33 | // can later see where the given object was created from. 34 | class StackTrace { 35 | public: 36 | // Creates a stacktrace from the current location. 37 | StackTrace(); 38 | 39 | // Creates a stacktrace from an existing array of instruction 40 | // pointers (such as returned by Addresses()). |count| will be 41 | // trimmed to |kMaxTraces|. 42 | StackTrace(const void* const* trace, size_t count); 43 | 44 | 45 | // Creates a stacktrace for an exception. 46 | // Note: this function will throw an import not found (StackWalk64) exception 47 | // on system without dbghelp 5.1. 48 | StackTrace(const _EXCEPTION_POINTERS* exception_pointers); 49 | 50 | 51 | // Copying and assignment are allowed with the default functions. 52 | 53 | ~StackTrace(); 54 | 55 | // Gets an array of instruction pointer values. |*count| will be set to the 56 | // number of elements in the returned array. 57 | const void* const* Addresses(size_t* count) const; 58 | 59 | #if !defined(__UCLIBC__) 60 | // Prints the stack trace to stderr. 61 | void Print() const; 62 | 63 | // Resolves backtrace to symbols and write to stream. 64 | void OutputToStream(std::ostream* os) const; 65 | #endif 66 | 67 | // Resolves backtrace to symbols and returns as string. 68 | std::string ToString() const; 69 | 70 | private: 71 | // From http://msdn.microsoft.com/en-us/library/bb204633.aspx, 72 | // the sum of FramesToSkip and FramesToCapture must be less than 63, 73 | // so set it to 62. Even if on POSIX it could be a larger value, it usually 74 | // doesn't give much more information. 75 | static const int kMaxTraces = 62; 76 | 77 | void* trace_[kMaxTraces]; 78 | 79 | // The number of valid frames in |trace_|. 80 | size_t count_; 81 | }; 82 | 83 | 84 | } // namespace debug 85 | } // namespace base 86 | 87 | #endif // BASE_DEBUG_STACK_TRACE_H_ 88 | -------------------------------------------------------------------------------- /src/stack_trace_win.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | #include "stdafx.h" 5 | #include "stack_trace.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #pragma comment(lib, "dbghelp.lib") 15 | #include "lock.h" 16 | #include "chromium_logging_util.h" 17 | 18 | //#include "base/memory/singleton.h" 19 | //#include "base/path_service.h" 20 | //#include "base/process/launch.h" 21 | //#include "base/strings/string_util.h" 22 | 23 | //#include "base/win/windows_version.h" 24 | 25 | namespace base { 26 | namespace debug { 27 | 28 | namespace { 29 | 30 | // Previous unhandled filter. Will be called if not NULL when we intercept an 31 | // exception. Only used in unit tests. 32 | LPTOP_LEVEL_EXCEPTION_FILTER g_previous_filter = NULL; 33 | 34 | // Prints the exception call stack. 35 | // This is the unit tests exception filter. 36 | long WINAPI StackDumpExceptionFilter(EXCEPTION_POINTERS* info) { 37 | debug::StackTrace(info).Print(); 38 | if (g_previous_filter) 39 | return g_previous_filter(info); 40 | return EXCEPTION_CONTINUE_SEARCH; 41 | } 42 | 43 | 44 | void RouteStdioToConsole() { 45 | // Don't change anything if stdout or stderr already point to a 46 | // valid stream. 47 | // 48 | // If we are running under Buildbot or under Cygwin's default 49 | // terminal (mintty), stderr and stderr will be pipe handles. In 50 | // that case, we don't want to open CONOUT$, because its output 51 | // likely does not go anywhere. 52 | // 53 | // We don't use GetStdHandle() to check stdout/stderr here because 54 | // it can return dangling IDs of handles that were never inherited 55 | // by this process. These IDs could have been reused by the time 56 | // this function is called. The CRT checks the validity of 57 | // stdout/stderr on startup (before the handle IDs can be reused). 58 | // _fileno(stdout) will return -2 (_NO_CONSOLE_FILENO) if stdout was 59 | // invalid. 60 | if (_fileno(stdout) >= 0 || _fileno(stderr) >= 0) 61 | return; 62 | 63 | if (!AttachConsole(ATTACH_PARENT_PROCESS)) { 64 | unsigned int result = GetLastError(); 65 | // Was probably already attached. 66 | if (result == ERROR_ACCESS_DENIED) 67 | return; 68 | // Don't bother creating a new console for each child process if the 69 | // parent process is invalid (eg: crashed). 70 | if (result == ERROR_GEN_FAILURE) 71 | return; 72 | // Make a new console if attaching to parent fails with any other error. 73 | // It should be ERROR_INVALID_HANDLE at this point, which means the browser 74 | // was likely not started from a console. 75 | AllocConsole(); 76 | } 77 | 78 | // Arbitrary byte count to use when buffering output lines. More 79 | // means potential waste, less means more risk of interleaved 80 | // log-lines in output. 81 | enum { kOutputBufferSize = 64 * 1024 }; 82 | 83 | FILE* pCout; 84 | if (freopen_s(&pCout, "CONOUT$", "w", stdout)) { 85 | setvbuf(stdout, NULL, _IOLBF, kOutputBufferSize); 86 | // Overwrite FD 1 for the benefit of any code that uses this FD 87 | // directly. This is safe because the CRT allocates FDs 0, 1 and 88 | // 2 at startup even if they don't have valid underlying Windows 89 | // handles. This means we won't be overwriting an FD created by 90 | // _open() after startup. 91 | _dup2(_fileno(stdout), 1); 92 | } 93 | if (freopen_s(&pCout, "CONOUT$", "w", stderr)) { 94 | setvbuf(stderr, NULL, _IOLBF, kOutputBufferSize); 95 | _dup2(_fileno(stderr), 2); 96 | } 97 | 98 | // Fix all cout, wcout, cin, wcin, cerr, wcerr, clog and wclog. 99 | std::ios::sync_with_stdio(); 100 | } 101 | 102 | // SymbolContext is a threadsafe singleton that wraps the DbgHelp Sym* family 103 | // of functions. The Sym* family of functions may only be invoked by one 104 | // thread at a time. SymbolContext code may access a symbol server over the 105 | // network while holding the lock for this singleton. In the case of high 106 | // latency, this code will adversely affect performance. 107 | // 108 | // There is also a known issue where this backtrace code can interact 109 | // badly with breakpad if breakpad is invoked in a separate thread while 110 | // we are using the Sym* functions. This is because breakpad does now 111 | // share a lock with this function. See this related bug: 112 | // 113 | // http://code.google.com/p/google-breakpad/issues/detail?id=311 114 | // 115 | // This is a very unlikely edge case, and the current solution is to 116 | // just ignore it. 117 | 118 | class SymbolContext { 119 | public: 120 | static SymbolContext* GetInstance() { 121 | // We use a leaky singleton because code may call this during process 122 | // termination. 123 | // return Singleton >::get(); 124 | if (NULL == symbol_context_) 125 | { 126 | symbol_context_ = new SymbolContext; 127 | } 128 | return symbol_context_; 129 | } 130 | 131 | // Returns the error code of a failed initialization. 132 | DWORD init_error() const { 133 | return init_error_; 134 | } 135 | 136 | // For the given trace, attempts to resolve the symbols, and output a trace 137 | // to the ostream os. The format for each line of the backtrace is: 138 | // 139 | // SymbolName[0xAddress+Offset] (FileName:LineNo) 140 | // 141 | // This function should only be called if Init() has been called. We do not 142 | // LOG(FATAL) here because this code is called might be triggered by a 143 | // LOG(FATAL) itself. 144 | void OutputTraceToStream(const void* const* trace, 145 | size_t count, 146 | std::ostream* os) { 147 | base::AutoLock lock(lock_); 148 | 149 | for (size_t i = 0; (i < count) && os->good(); ++i) { 150 | const int kMaxNameLength = 256; 151 | DWORD_PTR frame = reinterpret_cast(trace[i]); 152 | 153 | // Code adapted from MSDN example: 154 | // http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx 155 | ULONG64 buffer[ 156 | (sizeof(SYMBOL_INFO) + 157 | kMaxNameLength * sizeof(wchar_t) + 158 | sizeof(ULONG64) - 1) / 159 | sizeof(ULONG64)]; 160 | memset(buffer, 0, sizeof(buffer)); 161 | 162 | // Initialize symbol information retrieval structures. 163 | DWORD64 sym_displacement = 0; 164 | PSYMBOL_INFO symbol = reinterpret_cast(&buffer[0]); 165 | symbol->SizeOfStruct = sizeof(SYMBOL_INFO); 166 | symbol->MaxNameLen = kMaxNameLength - 1; 167 | BOOL has_symbol = SymFromAddr(GetCurrentProcess(), frame, 168 | &sym_displacement, symbol); 169 | 170 | // Attempt to retrieve line number information. 171 | DWORD line_displacement = 0; 172 | IMAGEHLP_LINE64 line = {}; 173 | line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); 174 | BOOL has_line = SymGetLineFromAddr64(GetCurrentProcess(), frame, 175 | &line_displacement, &line); 176 | 177 | // Output the backtrace line. 178 | (*os) << "\t"; 179 | if (has_symbol) { 180 | (*os) << symbol->Name << " [0x" << trace[i] << "+" 181 | << sym_displacement << "]"; 182 | } else { 183 | // If there is no symbol information, add a spacer. 184 | (*os) << "(No symbol) [0x" << trace[i] << "]"; 185 | } 186 | if (has_line) { 187 | (*os) << " (" << line.FileName << ":" << line.LineNumber << ")"; 188 | } 189 | (*os) << "\n"; 190 | } 191 | } 192 | 193 | private: 194 | 195 | SymbolContext() : init_error_(ERROR_SUCCESS) { 196 | // Initializes the symbols for the process. 197 | // Defer symbol load until they're needed, use undecorated names, and 198 | // get line numbers. 199 | SymSetOptions(SYMOPT_DEFERRED_LOADS | 200 | SYMOPT_UNDNAME | 201 | SYMOPT_LOAD_LINES); 202 | if (!SymInitialize(GetCurrentProcess(), NULL, TRUE)) { 203 | init_error_ = GetLastError(); 204 | // TODO(awong): Handle error: SymInitialize can fail with 205 | // ERROR_INVALID_PARAMETER. 206 | // When it fails, we should not call debugbreak since it kills the current 207 | // process (prevents future tests from running or kills the browser 208 | // process). 209 | // DLOG(ERROR) << "SymInitialize failed: " << init_error_; 210 | assert(false); 211 | return; 212 | } 213 | } 214 | 215 | static SymbolContext* symbol_context_; 216 | DWORD init_error_; 217 | base::Lock lock_; 218 | // DISALLOW_COPY_AND_ASSIGN 219 | SymbolContext(const SymbolContext&); 220 | void operator=(const SymbolContext&); 221 | }; 222 | 223 | SymbolContext* SymbolContext::symbol_context_ = NULL; 224 | 225 | } // namespace 226 | 227 | bool EnableInProcessStackDumping() { 228 | // Add stack dumping support on exception on windows. Similar to OS_POSIX 229 | // signal() handling in process_util_posix.cc. 230 | g_previous_filter = SetUnhandledExceptionFilter(&StackDumpExceptionFilter); 231 | RouteStdioToConsole(); 232 | return true; 233 | } 234 | 235 | // Disable optimizations for the StackTrace::StackTrace function. It is 236 | // important to disable at least frame pointer optimization ("y"), since 237 | // that breaks CaptureStackBackTrace() and prevents StackTrace from working 238 | // in Release builds (it may still be janky if other frames are using FPO, 239 | // but at least it will make it further). 240 | #pragma optimize("", off) 241 | 242 | 243 | StackTrace::StackTrace() { 244 | // When walking our own stack, use CaptureStackBackTrace(). 245 | count_ = CaptureStackBackTrace(0, arraysize(trace_), trace_, NULL); 246 | } 247 | 248 | #pragma optimize("", on) 249 | 250 | StackTrace::StackTrace(const EXCEPTION_POINTERS* exception_pointers) { 251 | // When walking an exception stack, we need to use StackWalk64(). 252 | count_ = 0; 253 | // StackWalk64() may modify context record passed to it, so we will 254 | // use a copy. 255 | CONTEXT context_record = *exception_pointers->ContextRecord; 256 | // Initialize stack walking. 257 | STACKFRAME64 stack_frame; 258 | memset(&stack_frame, 0, sizeof(stack_frame)); 259 | #if defined(_WIN64) 260 | int machine_type = IMAGE_FILE_MACHINE_AMD64; 261 | stack_frame.AddrPC.Offset = context_record.Rip; 262 | stack_frame.AddrFrame.Offset = context_record.Rbp; 263 | stack_frame.AddrStack.Offset = context_record.Rsp; 264 | #else 265 | int machine_type = IMAGE_FILE_MACHINE_I386; 266 | stack_frame.AddrPC.Offset = context_record.Eip; 267 | stack_frame.AddrFrame.Offset = context_record.Ebp; 268 | stack_frame.AddrStack.Offset = context_record.Esp; 269 | #endif 270 | stack_frame.AddrPC.Mode = AddrModeFlat; 271 | stack_frame.AddrFrame.Mode = AddrModeFlat; 272 | stack_frame.AddrStack.Mode = AddrModeFlat; 273 | while (StackWalk64(machine_type, 274 | GetCurrentProcess(), 275 | GetCurrentThread(), 276 | &stack_frame, 277 | &context_record, 278 | NULL, 279 | &SymFunctionTableAccess64, 280 | &SymGetModuleBase64, 281 | NULL) && 282 | count_ < arraysize(trace_)) { 283 | trace_[count_++] = reinterpret_cast(stack_frame.AddrPC.Offset); 284 | } 285 | 286 | for (size_t i = count_; i < arraysize(trace_); ++i) 287 | trace_[i] = NULL; 288 | } 289 | 290 | void StackTrace::Print() const { 291 | OutputToStream(&std::cerr); 292 | } 293 | 294 | void StackTrace::OutputToStream(std::ostream* os) const { 295 | SymbolContext* context = SymbolContext::GetInstance(); 296 | DWORD error = context->init_error(); 297 | if (error != ERROR_SUCCESS) { 298 | (*os) << "Error initializing symbols (" << error 299 | << "). Dumping unresolved backtrace:\n"; 300 | for (size_t i = 0; (i < count_) && os->good(); ++i) { 301 | (*os) << "\t" << trace_[i] << "\n"; 302 | } 303 | } else { 304 | (*os) << "Backtrace:\n"; 305 | context->OutputTraceToStream(trace_, count_, os); 306 | } 307 | } 308 | 309 | } // namespace debug 310 | } // namespace base 311 | --------------------------------------------------------------------------------