├── .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 |
--------------------------------------------------------------------------------