Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: src/plugin/PluginDebug.cpp

Issue 5187613258416128: Issue #1234 - Rewrite internals of debug facility (Closed)
Patch Set: rebase only Created Nov. 26, 2015, 1:02 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/plugin/PluginDebug.h ('k') | src/plugin/PluginSettings.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2015 Eyeo GmbH 3 * Copyright (C) 2006-2015 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 #include "PluginStdAfx.h" 18 #include "PluginStdAfx.h"
19 #include "PluginDebug.h" 19 #include "PluginDebug.h"
20 #include "PluginClientBase.h" 20 #include "PluginClientBase.h"
21 #include "PluginMutex.h" 21 #include "PluginMutex.h"
22 #include "PluginSettings.h" 22 #include "PluginClientBase.h"
23 23 #include "../shared/Utils.h"
24 class CPluginDebugLock : public CPluginMutex 24 #include <iomanip>
25 { 25 #include <memory>
26 26
27 private: 27 namespace
28 28 {
29 static CComAutoCriticalSection s_criticalSectionDebugLock; 29 class CPluginDebugLock
30 30 : public CPluginMutex
31 public: 31 {
32 32 private:
33 CPluginDebugLock() : CPluginMutex(L"DebugFile", PLUGIN_ERROR_MUTEX_DEBUG_FILE) 33 static CComAutoCriticalSection s_criticalSectionDebugLock;
34 { 34
35 s_criticalSectionDebugLock.Lock(); 35 public:
36 CPluginDebugLock()
37 : CPluginMutex(L"DebugFile", PLUGIN_ERROR_MUTEX_DEBUG_FILE)
38 {
39 s_criticalSectionDebugLock.Lock();
40 }
41
42 ~CPluginDebugLock()
43 {
44 s_criticalSectionDebugLock.Unlock();
45 }
46 };
47
48 CComAutoCriticalSection CPluginDebugLock::s_criticalSectionDebugLock;
49
50 class LogText
51 {
52 public:
53 virtual std::string Text() const = 0;
54 virtual ~LogText() {};
55 };
56
57 class LogTextFixed
sergei 2015/12/02 13:53:00 What about naming of classes differently? Let's a
Eric 2015/12/02 15:01:24 No. Naming the subclasses of 'class LogText' with
58 : public LogText
59 {
60 protected:
61 const std::string fixedText;
62
63 public:
64 explicit LogTextFixed(const std::string& text)
65 : fixedText(text)
66 {}
67
68 explicit LogTextFixed(const std::exception& ex)
69 : fixedText(std::string("!!! Exception: ") + ex.what())
70 {}
71
72 virtual std::string Text() const override
sergei 2015/11/30 14:15:03 I would propose to omit `virtual` when we use `ove
Eric 2015/11/30 17:39:01 It's good to have both in place. Makes the intent
sergei 2015/11/30 18:14:29 Actually, I would like to note that it's not relat
Eric 2015/12/01 20:43:58 OK.
73 {
74 return fixedText;
75 }
76 };
77
78 class LogTextErrorCode
79 : public LogTextFixed
80 {
81 protected:
82 const DWORD errorCode;
83
84 public:
85 LogTextErrorCode(DWORD errorCode, const std::string& text)
86 : LogTextFixed(text), errorCode(errorCode)
87 {}
88
89 virtual std::string Text() const override
90 {
91 std::ostringstream ss;
92 ss << fixedText << ". error = " << errorCode << " (0x";
93 ss << std::setfill('0') << std::setw(2 * sizeof(DWORD)) << std::hex << err orCode;
94 ss << ")";
95 return ss.str();
96 }
97 };
98
99 /**
100 * Wrapper around SYSTEMTIME allows initialization of 'const' instances.
101 */
102 struct SystemTime
103 : public SYSTEMTIME
104 {
105 SystemTime()
106 {
107 ::GetSystemTime(static_cast<SYSTEMTIME*>(this));
108 }
109 };
110
111 class LogEntry
112 {
113 const std::unique_ptr<LogText> text;
sergei 2015/12/02 13:53:00 Just in case, what is the reason of extensively pu
Eric 2015/12/02 15:01:24 'const' members mean "initialized only at construc
114
115 std::string InitialPrefix() const
116 {
117 std::stringstream ss;
118 ss << std::setfill('0') << std::setw(2) << st.wHour;
119 ss << ":";
120 ss << std::setfill('0') << std::setw(2) << st.wMinute;
121 ss << ":";
122 ss << std::setfill('0') << std::setw(2) << st.wSecond;
123 ss << ".";
124 ss << std::setfill('0') << std::setw(3) << st.wMilliseconds;
125 ss << " [";
126 ss << std::setfill(' ') << std::setw(5) << threadId;
127 ss << "] - ";
128 return ss.str();
129 }
130
131 std::string SubsequentPrefix() const
132 {
133 return " + ";
134 }
135
136 public:
137 /**
138 * The time at which the log-generating statement executes.
139 */
140 const SystemTime st;
141
142 /**
143 * The process within which the log-generating statement executes.
144 */
145 const DWORD processId;
146
147 /**
148 * The thread within which the log-generating statement executes.
149 */
150 const DWORD threadId;
151
152 explicit LogEntry(LogText* text)
153 : processId(::GetCurrentProcessId()), threadId(::GetCurrentThreadId()), te xt(text)
154 {}
155
156 LogEntry(LogText* text, DWORD processId, DWORD threadId)
157 : processId(processId), threadId(threadId), text(text)
158 {}
159
160 void Write(std::ostream& out) const
161 {
162 CPluginDebugLock lock;
163 if (lock.IsLocked())
164 {
165 auto lines = text->Text();
166 size_t linePosition = 0;
167 while (true)
168 {
169 auto eolPosition = lines.find('\n', linePosition);
170 auto prefix = linePosition == 0 ? InitialPrefix() : SubsequentPrefix() ;
171 out << prefix;
172 if (eolPosition == std::string::npos)
173 {
174 out << lines.substr(linePosition) << "\n";
175 break;
176 }
177 else
178 {
179 out << lines.substr(linePosition, eolPosition - linePosition) << "\n ";
180 linePosition = eolPosition + 1;
181 }
182 }
183 out.flush();
184 }
185 }
186
187 void WriteFile(const std::wstring& logFileName) const
188 {
189 std::ofstream out;
190 out.open(logFileName, std::ios::app);
sergei 2015/12/02 13:53:00 I wonder whether we need a synchronization here. E
Eric 2015/12/02 15:01:24 Easy answer: This locking behavior is the same as
191 Write(out);
192 }
193 };
194
195 std::wstring GetDataPath(const std::wstring& filename)
196 {
197 return GetAppDataPath() + L"\\" + filename;
36 } 198 }
37 199
38 ~CPluginDebugLock() 200 void LogWriteDefault(const LogEntry& le)
39 { 201 {
40 s_criticalSectionDebugLock.Unlock(); 202 std::wstring debugFileName = GetDataPath(L"debug_" + std::to_wstring(le.proc essId) + L".txt");
203 le.WriteFile(debugFileName);
41 } 204 }
42 }; 205
43 206 void LogWriteResult(const LogEntry& le)
44 CComAutoCriticalSection CPluginDebugLock::s_criticalSectionDebugLock; 207 {
208 std::wstring debugFileName = GetDataPath(L"debug_result.txt");
209 le.WriteFile(debugFileName);
210 }
211 }
212
213 #ifdef ENABLE_DEBUG_INFO
214
215 void CPluginDebug::Debug(const std::string& text)
216 {
217 LogWriteDefault(LogEntry(new LogTextFixed(text)));
218 }
219
220 void CPluginDebug::Debug(const std::wstring& text)
221 {
222 Debug(ToUtf8String(text));
223 }
224
225 #endif
45 226
46 void CPluginDebug::DebugSystemException(const std::system_error& ex, int errorId , int errorSubid, const std::string& description) 227 void CPluginDebug::DebugSystemException(const std::system_error& ex, int errorId , int errorSubid, const std::string& description)
47 { 228 {
48 std::string message = description + ", " + ex.code().message() + ", " + ex.wha t(); 229 std::string message = description + ", " + ex.code().message() + ", " + ex.wha t();
49 DEBUG_ERROR_LOG(ex.code().value(), errorId, errorSubid, message); 230 DEBUG_ERROR_LOG(ex.code().value(), errorId, errorSubid, message);
50 } 231 }
51 232
52 #ifdef ENABLE_DEBUG_INFO
53
54 void DebugLegacy(const CString& text, DWORD dwProcessId, DWORD dwThreadId)
55 {
56 #ifdef USE_CONSOLE
57 CONSOLE("%s", CT2A(text.GetString(), CP_UTF8));
58 #endif
59
60 if (CPluginSettings::HasInstance())
61 {
62 #ifdef ENABLE_DEBUG_SPLIT_FILE
63 CPluginSettings* settings = CPluginSettings::GetInstance();
64
65 bool isWorkingThread = settings->IsWorkingThread(dwThreadId);
66
67 std::wstring processor;
68 wchar_t tmp[10];
69 _itow_s(::GetCurrentProcessId(), tmp, 10);
70 if (isWorkingThread)
71 processor = L"tab" + std::wstring(tmp) + L"_thread";
72 else
73 processor = L"tab" + std::wstring(tmp) + L"_ui";
74 #else
75 if (dwProcessId == 0)
76 {
77 dwProcessId = ::GetCurrentProcessId();
78 }
79 if (dwThreadId == 0)
80 {
81 dwThreadId = ::GetCurrentThreadId();
82 }
83
84 CStringA processInfo;
85 processInfo.Format("%4.4u.%4.4u - ", dwProcessId, dwThreadId);
86 #endif
87 SYSTEMTIME st;
88 ::GetSystemTime(&st);
89
90 CStringA sysTime;
91 sysTime.Format("%2.2d:%2.2d:%2.2d.%3.3d - ", st.wHour, st.wMinute, st.wSecon d, st.wMilliseconds);
92
93 CPluginDebugLock lock;
94 if (lock.IsLocked())
95 {
96 std::ofstream debugFile;
97
98 #ifdef ENABLE_DEBUG_SPLIT_FILE
99 debugFile.open(GetDataPath(L"debug_" + processor + L".txt"), std::ios::app );
100 #else
101 debugFile.open(GetDataPath(L"debug.txt"), std::ios::app);
102 #endif
103 int pos = 0;
104 CStringA line = text.Tokenize(L"\n\r", pos);
105
106 while (pos >= 0)
107 {
108 debugFile.write(sysTime.GetBuffer(), sysTime.GetLength());
109 #ifndef ENABLE_DEBUG_SPLIT_FILE
110 debugFile.write(processInfo.GetBuffer(), processInfo.GetLength());
111 #endif
112 debugFile.write(line.GetBuffer(), line.GetLength());
113 debugFile.write("\n", 1);
114
115 line = text.Tokenize(L"\n\r", pos);
116 }
117
118 debugFile.flush();
119 }
120 }
121 }
122
123 void CPluginDebug::Debug(const std::string& text, DWORD processId, DWORD threadI d)
124 {
125 DebugLegacy(CString(text.c_str()), processId, threadId);
126 }
127
128 void CPluginDebug::Debug(const std::wstring& text, DWORD processId, DWORD thread Id)
129 {
130 DebugLegacy(ToCString(text), processId, threadId);
131 }
132
133 #endif
134
135 #if (defined ENABLE_DEBUG_INFO) 233 #if (defined ENABLE_DEBUG_INFO)
136 234
137 void CPluginDebug::DebugException(const std::exception& ex) 235 void CPluginDebug::DebugException(const std::exception& ex)
138 { 236 {
139 auto error = std::string("!!! Exception:") + ex.what(); 237 auto lt = new LogTextFixed(ex);
238 LogEntry le(lt);
140 #ifdef ENABLE_DEBUG_ERROR 239 #ifdef ENABLE_DEBUG_ERROR
141 Debug(error); 240 LogWriteDefault(le);
142 #endif 241 #endif
143 242 DEBUG_SELFTEST(
144 DEBUG_SELFTEST("************************************************************** ******************\n" + error + "\n********************************************* ***********************************") 243 "*************************************************************************** *****\n"
145 } 244 + lt->text() + "\n"
146 245 "*************************************************************************** *****")
147 void DebugErrorCodeLegacy(DWORD errorCode, const CString& error, DWORD dwProcess Id, DWORD dwThreadId) 246 }
148 { 247
149 CString errorCodeText; 248 void CPluginDebug::DebugErrorCode(DWORD errorCode, const std::string& error, DWO RD processId, DWORD threadId)
150 errorCodeText.Format(L"%u (0x%8.8x)", errorCode, errorCode); 249 {
151 250 auto lt = new LogTextErrorCode(errorCode, error);
152 CString finalError = error + L". error=" + errorCodeText; 251 LogEntry le(lt, processId, threadId);
153
154 #ifdef ENABLE_DEBUG_ERROR 252 #ifdef ENABLE_DEBUG_ERROR
155 DebugLegacy(finalError, dwProcessId, dwThreadId); 253 LogWriteDefault(le);
156 #endif 254 #endif
157 255 DEBUG_SELFTEST(
158 DEBUG_SELFTEST(L"************************************************************* *******************\n" + finalError + "\n*************************************** *****************************************") 256 "*************************************************************************** *****\n"
159 } 257 + lt->text() + "\n"
160 258 "*************************************************************************** *****")
161 void CPluginDebug::DebugErrorCode(DWORD errorCode, const std::string& error, DWO RD processId, DWORD threadId) 259 }
162 { 260
163 DebugErrorCodeLegacy(errorCode, CString(error.c_str()), processId, threadId); 261 #endif
164 }
165
166 #endif
167 262
168 // ============================================================================ 263 // ============================================================================
169 // Debug result 264 // Debug result
170 // ============================================================================ 265 // ============================================================================
171 266
172 #ifdef ENABLE_DEBUG_RESULT 267 #ifdef ENABLE_DEBUG_RESULT
173 268
174 void DebugResultLegacy(const CString& text)
175 {
176 SYSTEMTIME st;
177 ::GetSystemTime(&st);
178
179 CStringA sysTime;
180 sysTime.Format("%2.2d:%2.2d:%2.2d.%3.3d - ", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
181
182 CStringA textA = text;
183
184 CPluginDebugLock lock;
185 if (lock.IsLocked())
186 {
187 std::ofstream debugFile;
188
189 debugFile.open(GetDataPath(L"debug_result.txt"), std::ios::app);
190 debugFile.write(sysTime.GetBuffer(), sysTime.GetLength());
191 debugFile.write(LPCSTR(textA), textA.GetLength());
192 debugFile.write("\n", 1);
193 debugFile.flush();
194 }
195 }
196
197 void CPluginDebug::DebugResult(const std::wstring& text) 269 void CPluginDebug::DebugResult(const std::wstring& text)
198 { 270 {
199 DebugResultLegacy(ToCString(text)); 271 LogWriteResult(LogEntry(new LogTextFixed(ToUtf8String(text))));
200 } 272 }
201 273
202 void CPluginDebug::DebugResultDomain(const std::wstring& domain) 274 void CPluginDebug::DebugResultDomain(const std::wstring& domain)
203 { 275 {
204 DebugResult(L"================================================================ ================================================================================ ==========================================="); 276 DebugResult(
205 DebugResult(domain); 277 L"========================================================================== ===============\n"
206 DebugResult(L"================================================================ ================================================================================ ==========================================="); 278 + domain + L"\n"
279 L"========================================================================== ===============");
207 } 280 }
208 281
282 namespace
283 {
284 void DebugResultFormat(const std::wstring& action, const std::wstring& type, c onst std::wstring& param1, const std::wstring& param2)
285 {
286 std::wostringstream ss;
287 ss << std::setw(7) << std::setiosflags(std::ios::left) << action;
288 ss << L" ";
289 ss << std::setw(12) << std::setiosflags(std::ios::left) << type;
290 ss << L" " << param1 << L" " << param2;
291 CPluginDebug::DebugResult(ss.str());
292 }
293
294 std::wstring Shorten(const std::wstring& s)
295 {
296 auto n = s.length();
297 if (n <= 100) return s;
298 auto r = s.substr(0, 67);
299 r += L"...";
300 r += s.substr(n - 30, 30);
301 return r;
302 }
303 }
209 304
210 void CPluginDebug::DebugResultBlocking(const std::wstring& type, const std::wstr ing& src, const std::wstring& domain) 305 void CPluginDebug::DebugResultBlocking(const std::wstring& type, const std::wstr ing& src, const std::wstring& domain)
211 { 306 {
212 CString srcTrunc = ToCString(src); 307 DebugResultFormat(L"Blocked", type, domain.empty() ? L"-" : domain, Shorten(sr c));
213 if (src.length() > 100)
214 {
215 srcTrunc = srcTrunc.Left(67) + L"..." + srcTrunc.Right(30);
216 }
217
218 CString blocking;
219 blocking.Format(L"Blocked %-12s %-20s %s", ToCString(type), domain.empty()? L"-" : ToCString(domain), srcTrunc);
220
221 DebugResultLegacy(blocking);
222 } 308 }
223 309
224 310
225 void CPluginDebug::DebugResultHiding(const std::wstring& tag, const std::wstring & id, const std::wstring& filter) 311 void CPluginDebug::DebugResultHiding(const std::wstring& tag, const std::wstring & id, const std::wstring& filter)
226 { 312 {
227 CString srcTrunc = ToCString(id); 313 DebugResultFormat(L"Hidden", tag, L"- " + Shorten(id), filter);
228 if (srcTrunc.GetLength() > 100)
229 {
230 srcTrunc = srcTrunc.Left(67) + L"..." + srcTrunc.Right(30);
231 }
232
233 CString blocking;
234 blocking.Format(L"Hidden %-12s - %s %s", ToCString(tag), srcTrunc, ToCStri ng(filter));
235
236 DebugResultLegacy(blocking);
237 } 314 }
238 315
239 #endif // ENABLE_DEBUG_RESULT 316 #endif // ENABLE_DEBUG_RESULT
240 317
241 318
242 #ifdef ENABLE_DEBUG_RESULT_IGNORED 319 #ifdef ENABLE_DEBUG_RESULT_IGNORED
243 320
244 void CPluginDebug::DebugResultIgnoring(const std::wstring& type, const std::wstr ing& src, const std::wstring& domain) 321 void CPluginDebug::DebugResultIgnoring(const std::wstring& type, const std::wstr ing& src, const std::wstring& domain)
245 { 322 {
246 CString srcTrunc = ToCString(src); 323 DebugResultFormat(L"Ignored", type, domain.empty() ? L"-" : domain, Shorten(sr c));
247 if (src.length() > 100)
248 {
249 srcTrunc = srcTrunc.Left(67) + L"..." + srcTrunc.Right(30);
250 }
251
252 CString blocking;
253 blocking.Format(L"Ignored %-12s %s %s", ToCString(type), domain.empty()? L" -" : ToCString(domain), srcTrunc);
254
255 DebugResultLegacy(blocking);
256 } 324 }
257 325
258 #endif // ENABLE_DEBUG_RESULT_IGNORED 326 #endif // ENABLE_DEBUG_RESULT_IGNORED
OLDNEW
« no previous file with comments | « src/plugin/PluginDebug.h ('k') | src/plugin/PluginSettings.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld