Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(284)

Side by Side Diff: base/logging.cc

Issue 1352713002: Get logging to chrome_debug.log working again on Windows Vista+. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Review comments second round Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/logging.h ('k') | chrome/app/chrome_main_delegate.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/logging.h" 5 #include "base/logging.h"
6 6
7 #if defined(OS_WIN) 7 #if defined(OS_WIN)
8 #include <io.h> 8 #include <io.h>
9 #include <windows.h> 9 #include <windows.h>
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
10 typedef HANDLE FileHandle; 12 typedef HANDLE FileHandle;
11 typedef HANDLE MutexHandle; 13 typedef HANDLE MutexHandle;
12 // Windows warns on using write(). It prefers _write(). 14 // Windows warns on using write(). It prefers _write().
13 #define write(fd, buf, count) _write(fd, buf, static_cast<unsigned int>(count)) 15 #define write(fd, buf, count) _write(fd, buf, static_cast<unsigned int>(count))
14 // Windows doesn't define STDERR_FILENO. Define it here. 16 // Windows doesn't define STDERR_FILENO. Define it here.
15 #define STDERR_FILENO 2 17 #define STDERR_FILENO 2
16 #elif defined(OS_MACOSX) 18 #elif defined(OS_MACOSX)
17 #include <mach/mach.h> 19 #include <mach/mach.h>
18 #include <mach/mach_time.h> 20 #include <mach/mach_time.h>
19 #include <mach-o/dyld.h> 21 #include <mach-o/dyld.h>
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 if (last_backslash != PathString::npos) 171 if (last_backslash != PathString::npos)
170 log_name.erase(last_backslash + 1); 172 log_name.erase(last_backslash + 1);
171 log_name += L"debug.log"; 173 log_name += L"debug.log";
172 return log_name; 174 return log_name;
173 #elif defined(OS_POSIX) 175 #elif defined(OS_POSIX)
174 // On other platforms we just use the current directory. 176 // On other platforms we just use the current directory.
175 return PathString("debug.log"); 177 return PathString("debug.log");
176 #endif 178 #endif
177 } 179 }
178 180
181 // We don't need locks on Windows for atomically appending to files. The OS
182 // provides this functionality.
183 #if !defined(OS_WIN)
179 // This class acts as a wrapper for locking the logging files. 184 // This class acts as a wrapper for locking the logging files.
180 // LoggingLock::Init() should be called from the main thread before any logging 185 // LoggingLock::Init() should be called from the main thread before any logging
181 // is done. Then whenever logging, be sure to have a local LoggingLock 186 // is done. Then whenever logging, be sure to have a local LoggingLock
182 // instance on the stack. This will ensure that the lock is unlocked upon 187 // instance on the stack. This will ensure that the lock is unlocked upon
183 // exiting the frame. 188 // exiting the frame.
184 // LoggingLocks can not be nested. 189 // LoggingLocks can not be nested.
185 class LoggingLock { 190 class LoggingLock {
186 public: 191 public:
187 LoggingLock() { 192 LoggingLock() {
188 LockLogging(); 193 LockLogging();
189 } 194 }
190 195
191 ~LoggingLock() { 196 ~LoggingLock() {
192 UnlockLogging(); 197 UnlockLogging();
193 } 198 }
194 199
195 static void Init(LogLockingState lock_log, const PathChar* new_log_file) { 200 static void Init(LogLockingState lock_log, const PathChar* new_log_file) {
196 if (initialized) 201 if (initialized)
197 return; 202 return;
198 lock_log_file = lock_log; 203 lock_log_file = lock_log;
199 if (lock_log_file == LOCK_LOG_FILE) {
200 #if defined(OS_WIN)
201 if (!log_mutex) {
202 std::wstring safe_name;
203 if (new_log_file)
204 safe_name = new_log_file;
205 else
206 safe_name = GetDefaultLogFile();
207 // \ is not a legal character in mutex names so we replace \ with /
208 std::replace(safe_name.begin(), safe_name.end(), '\\', '/');
209 std::wstring t(L"Global\\");
210 t.append(safe_name);
211 log_mutex = ::CreateMutex(nullptr, FALSE, t.c_str());
212 204
213 if (log_mutex == nullptr) { 205 if (lock_log_file != LOCK_LOG_FILE)
214 #if DEBUG
215 // Keep the error code for debugging
216 int error = GetLastError(); // NOLINT
217 base::debug::BreakDebugger();
218 #endif
219 // Return nicely without putting initialized to true.
220 return;
221 }
222 }
223 #endif
224 } else {
225 log_lock = new base::internal::LockImpl(); 206 log_lock = new base::internal::LockImpl();
226 } 207
227 initialized = true; 208 initialized = true;
228 } 209 }
229 210
230 private: 211 private:
231 static void LockLogging() { 212 static void LockLogging() {
232 if (lock_log_file == LOCK_LOG_FILE) { 213 if (lock_log_file == LOCK_LOG_FILE) {
233 #if defined(OS_WIN) 214 #if defined(OS_POSIX)
234 ::WaitForSingleObject(log_mutex, INFINITE);
235 // WaitForSingleObject could have returned WAIT_ABANDONED. We don't
236 // abort the process here. UI tests might be crashy sometimes,
237 // and aborting the test binary only makes the problem worse.
238 // We also don't use LOG macros because that might lead to an infinite
239 // loop. For more info see http://crbug.com/18028.
240 #elif defined(OS_POSIX)
241 pthread_mutex_lock(&log_mutex); 215 pthread_mutex_lock(&log_mutex);
242 #endif 216 #endif
243 } else { 217 } else {
244 // use the lock 218 // use the lock
245 log_lock->Lock(); 219 log_lock->Lock();
246 } 220 }
247 } 221 }
248 222
249 static void UnlockLogging() { 223 static void UnlockLogging() {
250 if (lock_log_file == LOCK_LOG_FILE) { 224 if (lock_log_file == LOCK_LOG_FILE) {
251 #if defined(OS_WIN) 225 #if defined(OS_POSIX)
252 ReleaseMutex(log_mutex);
253 #elif defined(OS_POSIX)
254 pthread_mutex_unlock(&log_mutex); 226 pthread_mutex_unlock(&log_mutex);
255 #endif 227 #endif
256 } else { 228 } else {
257 log_lock->Unlock(); 229 log_lock->Unlock();
258 } 230 }
259 } 231 }
260 232
261 // The lock is used if log file locking is false. It helps us avoid problems 233 // The lock is used if log file locking is false. It helps us avoid problems
262 // with multiple threads writing to the log file at the same time. Use 234 // with multiple threads writing to the log file at the same time. Use
263 // LockImpl directly instead of using Lock, because Lock makes logging calls. 235 // LockImpl directly instead of using Lock, because Lock makes logging calls.
264 static base::internal::LockImpl* log_lock; 236 static base::internal::LockImpl* log_lock;
265 237
266 // When we don't use a lock, we are using a global mutex. We need to do this 238 // When we don't use a lock, we are using a global mutex. We need to do this
267 // because LockFileEx is not thread safe. 239 // because LockFileEx is not thread safe.
268 #if defined(OS_WIN) 240 #if defined(OS_POSIX)
269 static MutexHandle log_mutex;
270 #elif defined(OS_POSIX)
271 static pthread_mutex_t log_mutex; 241 static pthread_mutex_t log_mutex;
272 #endif 242 #endif
273 243
274 static bool initialized; 244 static bool initialized;
275 static LogLockingState lock_log_file; 245 static LogLockingState lock_log_file;
276 }; 246 };
277 247
278 // static 248 // static
279 bool LoggingLock::initialized = false; 249 bool LoggingLock::initialized = false;
280 // static 250 // static
281 base::internal::LockImpl* LoggingLock::log_lock = nullptr; 251 base::internal::LockImpl* LoggingLock::log_lock = nullptr;
282 // static 252 // static
283 LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE; 253 LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE;
284 254
285 #if defined(OS_WIN) 255 #if defined(OS_POSIX)
286 // static
287 MutexHandle LoggingLock::log_mutex = nullptr;
288 #elif defined(OS_POSIX)
289 pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER; 256 pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER;
290 #endif 257 #endif
291 258
259 #endif // OS_WIN
260
292 // Called by logging functions to ensure that |g_log_file| is initialized 261 // Called by logging functions to ensure that |g_log_file| is initialized
293 // and can be used for writing. Returns false if the file could not be 262 // and can be used for writing. Returns false if the file could not be
294 // initialized. |g_log_file| will be nullptr in this case. 263 // initialized. |g_log_file| will be nullptr in this case.
295 bool InitializeLogFileHandle() { 264 bool InitializeLogFileHandle() {
296 if (g_log_file) 265 if (g_log_file)
297 return true; 266 return true;
298 267
299 if (!g_log_file_name) { 268 if (!g_log_file_name) {
300 // Nobody has called InitLogging to specify a debug log file, so here we 269 // Nobody has called InitLogging to specify a debug log file, so here we
301 // initialize the log file name to a default. 270 // initialize the log file name to a default.
302 g_log_file_name = new PathString(GetDefaultLogFile()); 271 g_log_file_name = new PathString(GetDefaultLogFile());
303 } 272 }
304 273
305 if ((g_logging_destination & LOG_TO_FILE) != 0) { 274 if ((g_logging_destination & LOG_TO_FILE) != 0) {
306 #if defined(OS_WIN) 275 #if defined(OS_WIN)
307 g_log_file = CreateFile(g_log_file_name->c_str(), GENERIC_WRITE, 276 // The FILE_APPEND_DATA access mask ensures that the file is atomically
277 // appended to across accesses from multiple threads.
278 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364399(v=vs.85 ).aspx
scottmg 2015/09/17 00:17:40 nit; (you could delete the "(v=vs.85)" from the ur
279 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85 ).aspx
280 g_log_file = CreateFile(g_log_file_name->c_str(), FILE_APPEND_DATA,
308 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, 281 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
309 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); 282 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
310 if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) { 283 if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) {
311 // try the current directory 284 // try the current directory
312 g_log_file = CreateFile(L".\\debug.log", GENERIC_WRITE, 285 base::FilePath file_path;
286 if (!base::GetCurrentDirectory(&file_path))
287 return false;
288
289 *g_log_file_name = file_path.Append(
290 FILE_PATH_LITERAL("debug.log")).value();
291
292 g_log_file = CreateFile(g_log_file_name->c_str(), FILE_APPEND_DATA,
313 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, 293 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
314 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); 294 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
315 if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) { 295 if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) {
316 g_log_file = nullptr; 296 g_log_file = nullptr;
317 return false; 297 return false;
318 } 298 }
319 } 299 }
320 SetFilePointer(g_log_file, 0, 0, FILE_END);
321 #elif defined(OS_POSIX) 300 #elif defined(OS_POSIX)
322 g_log_file = fopen(g_log_file_name->c_str(), "a"); 301 g_log_file = fopen(g_log_file_name->c_str(), "a");
323 if (g_log_file == nullptr) 302 if (g_log_file == nullptr)
324 return false; 303 return false;
325 #endif 304 #endif
326 } 305 }
327 306
328 return true; 307 return true;
329 } 308 }
330 309
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 command_line->GetSwitchValueASCII(switches::kVModule), 352 command_line->GetSwitchValueASCII(switches::kVModule),
374 &g_min_log_level); 353 &g_min_log_level);
375 } 354 }
376 355
377 g_logging_destination = settings.logging_dest; 356 g_logging_destination = settings.logging_dest;
378 357
379 // ignore file options unless logging to file is set. 358 // ignore file options unless logging to file is set.
380 if ((g_logging_destination & LOG_TO_FILE) == 0) 359 if ((g_logging_destination & LOG_TO_FILE) == 0)
381 return true; 360 return true;
382 361
362 // We don't need a lock on Windows for atomic appends.
rvargas (doing something else) 2015/09/17 18:51:58 tiny nit: the fact that LoggingLock is not defined
ananta 2015/09/17 20:34:59 Done.
363 #if !defined(OS_WIN)
383 LoggingLock::Init(settings.lock_log, settings.log_file); 364 LoggingLock::Init(settings.lock_log, settings.log_file);
384 LoggingLock logging_lock; 365 LoggingLock logging_lock;
366 #endif
385 367
386 // Calling InitLogging twice or after some log call has already opened the 368 // Calling InitLogging twice or after some log call has already opened the
387 // default log file will re-initialize to the new options. 369 // default log file will re-initialize to the new options.
388 CloseLogFileUnlocked(); 370 CloseLogFileUnlocked();
389 371
390 if (!g_log_file_name) 372 if (!g_log_file_name)
391 g_log_file_name = new PathString(); 373 g_log_file_name = new PathString();
392 *g_log_file_name = settings.log_file; 374 *g_log_file_name = settings.log_file;
393 if (settings.delete_old == DELETE_OLD_LOG_FILE) 375 if (settings.delete_old == DELETE_OLD_LOG_FILE)
394 DeleteFilePath(*g_log_file_name); 376 DeleteFilePath(*g_log_file_name);
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after
596 578
597 // write to log file 579 // write to log file
598 if ((g_logging_destination & LOG_TO_FILE) != 0) { 580 if ((g_logging_destination & LOG_TO_FILE) != 0) {
599 // We can have multiple threads and/or processes, so try to prevent them 581 // We can have multiple threads and/or processes, so try to prevent them
600 // from clobbering each other's writes. 582 // from clobbering each other's writes.
601 // If the client app did not call InitLogging, and the lock has not 583 // If the client app did not call InitLogging, and the lock has not
602 // been created do it now. We do this on demand, but if two threads try 584 // been created do it now. We do this on demand, but if two threads try
603 // to do this at the same time, there will be a race condition to create 585 // to do this at the same time, there will be a race condition to create
604 // the lock. This is why InitLogging should be called from the main 586 // the lock. This is why InitLogging should be called from the main
605 // thread at the beginning of execution. 587 // thread at the beginning of execution.
588 // We don't need a lock on Windows for atomic appends.
589 #if !defined(OS_WIN)
606 LoggingLock::Init(LOCK_LOG_FILE, nullptr); 590 LoggingLock::Init(LOCK_LOG_FILE, nullptr);
607 LoggingLock logging_lock; 591 LoggingLock logging_lock;
592 #endif
608 if (InitializeLogFileHandle()) { 593 if (InitializeLogFileHandle()) {
609 #if defined(OS_WIN) 594 #if defined(OS_WIN)
610 SetFilePointer(g_log_file, 0, 0, SEEK_END);
611 DWORD num_written; 595 DWORD num_written;
612 WriteFile(g_log_file, 596 WriteFile(g_log_file,
613 static_cast<const void*>(str_newline.c_str()), 597 static_cast<const void*>(str_newline.c_str()),
614 static_cast<DWORD>(str_newline.length()), 598 static_cast<DWORD>(str_newline.length()),
615 &num_written, 599 &num_written,
616 nullptr); 600 nullptr);
617 #else 601 #else
618 ignore_result(fwrite( 602 ignore_result(fwrite(
619 str_newline.data(), str_newline.size(), 1, g_log_file)); 603 str_newline.data(), str_newline.size(), 1, g_log_file));
620 fflush(g_log_file); 604 fflush(g_log_file);
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
760 : err_(err), 744 : err_(err),
761 log_message_(file, line, severity) { 745 log_message_(file, line, severity) {
762 } 746 }
763 747
764 ErrnoLogMessage::~ErrnoLogMessage() { 748 ErrnoLogMessage::~ErrnoLogMessage() {
765 stream() << ": " << SystemErrorCodeToString(err_); 749 stream() << ": " << SystemErrorCodeToString(err_);
766 } 750 }
767 #endif // defined(OS_WIN) 751 #endif // defined(OS_WIN)
768 752
769 void CloseLogFile() { 753 void CloseLogFile() {
754 // We don't need a lock on Windows for atomic appends.
755 #if !defined(OS_WIN)
770 LoggingLock logging_lock; 756 LoggingLock logging_lock;
757 #endif
771 CloseLogFileUnlocked(); 758 CloseLogFileUnlocked();
772 } 759 }
773 760
774 void RawLog(int level, const char* message) { 761 void RawLog(int level, const char* message) {
775 if (level >= g_min_log_level) { 762 if (level >= g_min_log_level) {
776 size_t bytes_written = 0; 763 size_t bytes_written = 0;
777 const size_t message_len = strlen(message); 764 const size_t message_len = strlen(message);
778 int rv; 765 int rv;
779 while (bytes_written < message_len) { 766 while (bytes_written < message_len) {
780 rv = HANDLE_EINTR( 767 rv = HANDLE_EINTR(
(...skipping 18 matching lines...) Expand all
799 } 786 }
800 787
801 if (level == LOG_FATAL) 788 if (level == LOG_FATAL)
802 base::debug::BreakDebugger(); 789 base::debug::BreakDebugger();
803 } 790 }
804 791
805 // This was defined at the beginning of this file. 792 // This was defined at the beginning of this file.
806 #undef write 793 #undef write
807 794
808 #if defined(OS_WIN) 795 #if defined(OS_WIN)
796 bool IsLoggingToFileEnabled() {
797 return g_logging_destination & LOG_TO_FILE;
798 }
799
809 std::wstring GetLogFileFullPath() { 800 std::wstring GetLogFileFullPath() {
810 if (g_log_file_name) 801 if (g_log_file_name)
811 return *g_log_file_name; 802 return *g_log_file_name;
812 return std::wstring(); 803 return std::wstring();
813 } 804 }
814 #endif 805 #endif
815 806
816 BASE_EXPORT void LogErrorNotReached(const char* file, int line) { 807 BASE_EXPORT void LogErrorNotReached(const char* file, int line) {
817 LogMessage(file, line, LOG_ERROR).stream() 808 LogMessage(file, line, LOG_ERROR).stream()
818 << "NOTREACHED() hit."; 809 << "NOTREACHED() hit.";
819 } 810 }
820 811
821 } // namespace logging 812 } // namespace logging
822 813
823 std::ostream& std::operator<<(std::ostream& out, const wchar_t* wstr) { 814 std::ostream& std::operator<<(std::ostream& out, const wchar_t* wstr) {
824 return out << base::WideToUTF8(wstr); 815 return out << base::WideToUTF8(wstr);
825 } 816 }
OLDNEW
« no previous file with comments | « base/logging.h ('k') | chrome/app/chrome_main_delegate.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698