| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 typedef HANDLE FileHandle; | 10 typedef HANDLE FileHandle; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 53 #include "base/utf_string_conversions.h" | 53 #include "base/utf_string_conversions.h" |
| 54 | 54 |
| 55 namespace logging { | 55 namespace logging { |
| 56 | 56 |
| 57 bool g_enable_dcheck = false; | 57 bool g_enable_dcheck = false; |
| 58 | 58 |
| 59 const char* const log_severity_names[LOG_NUM_SEVERITIES] = { | 59 const char* const log_severity_names[LOG_NUM_SEVERITIES] = { |
| 60 "INFO", "WARNING", "ERROR", "ERROR_REPORT", "FATAL" }; | 60 "INFO", "WARNING", "ERROR", "ERROR_REPORT", "FATAL" }; |
| 61 | 61 |
| 62 int min_log_level = 0; | 62 int min_log_level = 0; |
| 63 LogLockingState lock_log_file = LOCK_LOG_FILE; | |
| 64 | 63 |
| 65 // The default set here for logging_destination will only be used if | 64 // The default set here for logging_destination will only be used if |
| 66 // InitLogging is not called. On Windows, use a file next to the exe; | 65 // InitLogging is not called. On Windows, use a file next to the exe; |
| 67 // on POSIX platforms, where it may not even be possible to locate the | 66 // on POSIX platforms, where it may not even be possible to locate the |
| 68 // executable on disk, use stderr. | 67 // executable on disk, use stderr. |
| 69 #if defined(OS_WIN) | 68 #if defined(OS_WIN) |
| 70 LoggingDestination logging_destination = LOG_ONLY_TO_FILE; | 69 LoggingDestination logging_destination = LOG_ONLY_TO_FILE; |
| 71 #elif defined(OS_POSIX) | 70 #elif defined(OS_POSIX) |
| 72 LoggingDestination logging_destination = LOG_ONLY_TO_SYSTEM_DEBUG_LOG; | 71 LoggingDestination logging_destination = LOG_ONLY_TO_SYSTEM_DEBUG_LOG; |
| 73 #endif | 72 #endif |
| (...skipping 28 matching lines...) Expand all Loading... |
| 102 | 101 |
| 103 // An assert handler override specified by the client to be called instead of | 102 // An assert handler override specified by the client to be called instead of |
| 104 // the debug message dialog and process termination. | 103 // the debug message dialog and process termination. |
| 105 LogAssertHandlerFunction log_assert_handler = NULL; | 104 LogAssertHandlerFunction log_assert_handler = NULL; |
| 106 // An report handler override specified by the client to be called instead of | 105 // An report handler override specified by the client to be called instead of |
| 107 // the debug message dialog. | 106 // the debug message dialog. |
| 108 LogReportHandlerFunction log_report_handler = NULL; | 107 LogReportHandlerFunction log_report_handler = NULL; |
| 109 // A log message handler that gets notified of every log message we process. | 108 // A log message handler that gets notified of every log message we process. |
| 110 LogMessageHandlerFunction log_message_handler = NULL; | 109 LogMessageHandlerFunction log_message_handler = NULL; |
| 111 | 110 |
| 112 // The lock is used if log file locking is false. It helps us avoid problems | |
| 113 // with multiple threads writing to the log file at the same time. Use | |
| 114 // LockImpl directly instead of using Lock, because Lock makes logging calls. | |
| 115 static LockImpl* log_lock = NULL; | |
| 116 | |
| 117 // When we don't use a lock, we are using a global mutex. We need to do this | |
| 118 // because LockFileEx is not thread safe. | |
| 119 #if defined(OS_WIN) | |
| 120 MutexHandle log_mutex = NULL; | |
| 121 #elif defined(OS_POSIX) | |
| 122 pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER; | |
| 123 #endif | |
| 124 | |
| 125 // Helper functions to wrap platform differences. | 111 // Helper functions to wrap platform differences. |
| 126 | 112 |
| 127 int32 CurrentProcessId() { | 113 int32 CurrentProcessId() { |
| 128 #if defined(OS_WIN) | 114 #if defined(OS_WIN) |
| 129 return GetCurrentProcessId(); | 115 return GetCurrentProcessId(); |
| 130 #elif defined(OS_POSIX) | 116 #elif defined(OS_POSIX) |
| 131 return getpid(); | 117 return getpid(); |
| 132 #endif | 118 #endif |
| 133 } | 119 } |
| 134 | 120 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 } | 157 } |
| 172 | 158 |
| 173 void DeleteFilePath(const PathString& log_name) { | 159 void DeleteFilePath(const PathString& log_name) { |
| 174 #if defined(OS_WIN) | 160 #if defined(OS_WIN) |
| 175 DeleteFile(log_name.c_str()); | 161 DeleteFile(log_name.c_str()); |
| 176 #else | 162 #else |
| 177 unlink(log_name.c_str()); | 163 unlink(log_name.c_str()); |
| 178 #endif | 164 #endif |
| 179 } | 165 } |
| 180 | 166 |
| 167 // This class acts as a wrapper for locking the logging files. |
| 168 // LoggingLock::Init() should be called from the main thread before any logging |
| 169 // is done. Then whenever logging, be sure to have a local LoggingLock |
| 170 // instance on the stack. This will ensure that the lock is unlocked upon |
| 171 // exiting the frame. |
| 172 // LoggingLocks can not be nested. |
| 173 class LoggingLock { |
| 174 public: |
| 175 LoggingLock() { |
| 176 LockLogging(); |
| 177 } |
| 178 |
| 179 ~LoggingLock() { |
| 180 UnlockLogging(); |
| 181 } |
| 182 |
| 183 static void Init(LogLockingState lock_log) { |
| 184 if (initialized) |
| 185 return; |
| 186 lock_log_file = lock_log; |
| 187 if (lock_log_file == LOCK_LOG_FILE) { |
| 188 #if defined(OS_WIN) |
| 189 if (!log_mutex) { |
| 190 // \ is not a legal character in mutex names so we replace \ with / |
| 191 std::wstring safe_name(*log_file_name); |
| 192 std::replace(safe_name.begin(), safe_name.end(), '\\', '/'); |
| 193 std::wstring t(L"Global\\"); |
| 194 t.append(safe_name); |
| 195 log_mutex = ::CreateMutex(NULL, FALSE, t.c_str()); |
| 196 } |
| 197 #endif |
| 198 } else { |
| 199 log_lock = new LockImpl(); |
| 200 } |
| 201 initialized = true; |
| 202 } |
| 203 |
| 204 private: |
| 205 static void LockLogging() { |
| 206 if (lock_log_file == LOCK_LOG_FILE) { |
| 207 #if defined(OS_WIN) |
| 208 ::WaitForSingleObject(log_mutex, INFINITE); |
| 209 // WaitForSingleObject could have returned WAIT_ABANDONED. We don't |
| 210 // abort the process here. UI tests might be crashy sometimes, |
| 211 // and aborting the test binary only makes the problem worse. |
| 212 // We also don't use LOG macros because that might lead to an infinite |
| 213 // loop. For more info see http://crbug.com/18028. |
| 214 #elif defined(OS_POSIX) |
| 215 pthread_mutex_lock(&log_mutex); |
| 216 #endif |
| 217 } else { |
| 218 // use the lock |
| 219 log_lock->Lock(); |
| 220 } |
| 221 } |
| 222 |
| 223 static void UnlockLogging() { |
| 224 if (lock_log_file == LOCK_LOG_FILE) { |
| 225 #if defined(OS_WIN) |
| 226 ReleaseMutex(log_mutex); |
| 227 #elif defined(OS_POSIX) |
| 228 pthread_mutex_unlock(&log_mutex); |
| 229 #endif |
| 230 } else { |
| 231 log_lock->Unlock(); |
| 232 } |
| 233 } |
| 234 |
| 235 // The lock is used if log file locking is false. It helps us avoid problems |
| 236 // with multiple threads writing to the log file at the same time. Use |
| 237 // LockImpl directly instead of using Lock, because Lock makes logging calls. |
| 238 static LockImpl* log_lock; |
| 239 |
| 240 // When we don't use a lock, we are using a global mutex. We need to do this |
| 241 // because LockFileEx is not thread safe. |
| 242 #if defined(OS_WIN) |
| 243 static MutexHandle log_mutex; |
| 244 #elif defined(OS_POSIX) |
| 245 static pthread_mutex_t log_mutex; |
| 246 #endif |
| 247 |
| 248 static bool initialized; |
| 249 static LogLockingState lock_log_file; |
| 250 }; |
| 251 |
| 252 // static |
| 253 bool LoggingLock::initialized = false; |
| 254 // static |
| 255 LockImpl* LoggingLock::log_lock = NULL; |
| 256 // static |
| 257 LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE; |
| 258 |
| 259 #if defined(OS_WIN) |
| 260 // static |
| 261 MutexHandle LoggingLock::log_mutex = NULL; |
| 262 #elif defined(OS_POSIX) |
| 263 pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER; |
| 264 #endif |
| 265 |
| 181 // Called by logging functions to ensure that debug_file is initialized | 266 // Called by logging functions to ensure that debug_file is initialized |
| 182 // and can be used for writing. Returns false if the file could not be | 267 // and can be used for writing. Returns false if the file could not be |
| 183 // initialized. debug_file will be NULL in this case. | 268 // initialized. debug_file will be NULL in this case. |
| 184 bool InitializeLogFileHandle() { | 269 bool InitializeLogFileHandle() { |
| 185 if (log_file) | 270 if (log_file) |
| 186 return true; | 271 return true; |
| 187 | 272 |
| 188 if (!log_file_name) { | 273 if (!log_file_name) { |
| 189 // Nobody has called InitLogging to specify a debug log file, so here we | 274 // Nobody has called InitLogging to specify a debug log file, so here we |
| 190 // initialize the log file name to a default. | 275 // initialize the log file name to a default. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 #elif defined(OS_POSIX) | 309 #elif defined(OS_POSIX) |
| 225 log_file = fopen(log_file_name->c_str(), "a"); | 310 log_file = fopen(log_file_name->c_str(), "a"); |
| 226 if (log_file == NULL) | 311 if (log_file == NULL) |
| 227 return false; | 312 return false; |
| 228 #endif | 313 #endif |
| 229 } | 314 } |
| 230 | 315 |
| 231 return true; | 316 return true; |
| 232 } | 317 } |
| 233 | 318 |
| 234 void InitLogMutex() { | |
| 235 #if defined(OS_WIN) | |
| 236 if (!log_mutex) { | |
| 237 // \ is not a legal character in mutex names so we replace \ with / | |
| 238 std::wstring safe_name(*log_file_name); | |
| 239 std::replace(safe_name.begin(), safe_name.end(), '\\', '/'); | |
| 240 std::wstring t(L"Global\\"); | |
| 241 t.append(safe_name); | |
| 242 log_mutex = ::CreateMutex(NULL, FALSE, t.c_str()); | |
| 243 } | |
| 244 #elif defined(OS_POSIX) | |
| 245 // statically initialized | |
| 246 #endif | |
| 247 } | |
| 248 | |
| 249 void BaseInitLoggingImpl(const PathChar* new_log_file, | 319 void BaseInitLoggingImpl(const PathChar* new_log_file, |
| 250 LoggingDestination logging_dest, | 320 LoggingDestination logging_dest, |
| 251 LogLockingState lock_log, | 321 LogLockingState lock_log, |
| 252 OldFileDeletionState delete_old) { | 322 OldFileDeletionState delete_old) { |
| 253 g_enable_dcheck = | 323 g_enable_dcheck = |
| 254 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableDCHECK); | 324 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableDCHECK); |
| 255 | 325 |
| 326 LoggingLock::Init(lock_log); |
| 327 |
| 328 LoggingLock logging_lock; |
| 329 |
| 256 if (log_file) { | 330 if (log_file) { |
| 257 // calling InitLogging twice or after some log call has already opened the | 331 // calling InitLogging twice or after some log call has already opened the |
| 258 // default log file will re-initialize to the new options | 332 // default log file will re-initialize to the new options |
| 259 CloseFile(log_file); | 333 CloseFile(log_file); |
| 260 log_file = NULL; | 334 log_file = NULL; |
| 261 } | 335 } |
| 262 | 336 |
| 263 lock_log_file = lock_log; | |
| 264 logging_destination = logging_dest; | 337 logging_destination = logging_dest; |
| 265 | 338 |
| 266 // ignore file options if logging is disabled or only to system | 339 // ignore file options if logging is disabled or only to system |
| 267 if (logging_destination == LOG_NONE || | 340 if (logging_destination == LOG_NONE || |
| 268 logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG) | 341 logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG) |
| 269 return; | 342 return; |
| 270 | 343 |
| 271 if (!log_file_name) | 344 if (!log_file_name) |
| 272 log_file_name = new PathString(); | 345 log_file_name = new PathString(); |
| 273 *log_file_name = new_log_file; | 346 *log_file_name = new_log_file; |
| 274 if (delete_old == DELETE_OLD_LOG_FILE) | 347 if (delete_old == DELETE_OLD_LOG_FILE) |
| 275 DeleteFilePath(*log_file_name); | 348 DeleteFilePath(*log_file_name); |
| 276 | 349 |
| 277 if (lock_log_file == LOCK_LOG_FILE) { | 350 InitializeLogFileHandle(); |
| 278 InitLogMutex(); | |
| 279 } else if (!log_lock) { | |
| 280 log_lock = new LockImpl(); | |
| 281 } | |
| 282 | 351 |
| 283 InitializeLogFileHandle(); | |
| 284 } | 352 } |
| 285 | 353 |
| 286 void SetMinLogLevel(int level) { | 354 void SetMinLogLevel(int level) { |
| 287 min_log_level = level; | 355 min_log_level = level; |
| 288 } | 356 } |
| 289 | 357 |
| 290 int GetMinLogLevel() { | 358 int GetMinLogLevel() { |
| 291 return min_log_level; | 359 return min_log_level; |
| 292 } | 360 } |
| 293 | 361 |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 fflush(stderr); | 578 fflush(stderr); |
| 511 } | 579 } |
| 512 } else if (severity_ >= kAlwaysPrintErrorLevel) { | 580 } else if (severity_ >= kAlwaysPrintErrorLevel) { |
| 513 // When we're only outputting to a log file, above a certain log level, we | 581 // When we're only outputting to a log file, above a certain log level, we |
| 514 // should still output to stderr so that we can better detect and diagnose | 582 // should still output to stderr so that we can better detect and diagnose |
| 515 // problems with unit tests, especially on the buildbots. | 583 // problems with unit tests, especially on the buildbots. |
| 516 fprintf(stderr, "%s", str_newline.c_str()); | 584 fprintf(stderr, "%s", str_newline.c_str()); |
| 517 fflush(stderr); | 585 fflush(stderr); |
| 518 } | 586 } |
| 519 | 587 |
| 588 // We can have multiple threads and/or processes, so try to prevent them |
| 589 // from clobbering each other's writes. |
| 590 // If the client app did not call InitLogging, and the lock has not |
| 591 // been created do it now. We do this on demand, but if two threads try |
| 592 // to do this at the same time, there will be a race condition to create |
| 593 // the lock. This is why InitLogging should be called from the main |
| 594 // thread at the beginning of execution. |
| 595 LoggingLock::Init(LOCK_LOG_FILE); |
| 520 // write to log file | 596 // write to log file |
| 521 if (logging_destination != LOG_NONE && | 597 if (logging_destination != LOG_NONE && |
| 522 logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG && | 598 logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG) { |
| 523 InitializeLogFileHandle()) { | 599 LoggingLock logging_lock; |
| 524 // We can have multiple threads and/or processes, so try to prevent them | 600 if (InitializeLogFileHandle()) { |
| 525 // from clobbering each other's writes. | |
| 526 if (lock_log_file == LOCK_LOG_FILE) { | |
| 527 // Ensure that the mutex is initialized in case the client app did not | |
| 528 // call InitLogging. This is not thread safe. See below. | |
| 529 InitLogMutex(); | |
| 530 | |
| 531 #if defined(OS_WIN) | 601 #if defined(OS_WIN) |
| 532 ::WaitForSingleObject(log_mutex, INFINITE); | 602 SetFilePointer(log_file, 0, 0, SEEK_END); |
| 533 // WaitForSingleObject could have returned WAIT_ABANDONED. We don't | 603 DWORD num_written; |
| 534 // abort the process here. UI tests might be crashy sometimes, | 604 WriteFile(log_file, |
| 535 // and aborting the test binary only makes the problem worse. | 605 static_cast<const void*>(str_newline.c_str()), |
| 536 // We also don't use LOG macros because that might lead to an infinite | 606 static_cast<DWORD>(str_newline.length()), |
| 537 // loop. For more info see http://crbug.com/18028. | 607 &num_written, |
| 538 #elif defined(OS_POSIX) | 608 NULL); |
| 539 pthread_mutex_lock(&log_mutex); | 609 #else |
| 610 fprintf(log_file, "%s", str_newline.c_str()); |
| 611 fflush(log_file); |
| 540 #endif | 612 #endif |
| 541 } else { | |
| 542 // use the lock | |
| 543 if (!log_lock) { | |
| 544 // The client app did not call InitLogging, and so the lock has not | |
| 545 // been created. We do this on demand, but if two threads try to do | |
| 546 // this at the same time, there will be a race condition to create | |
| 547 // the lock. This is why InitLogging should be called from the main | |
| 548 // thread at the beginning of execution. | |
| 549 log_lock = new LockImpl(); | |
| 550 } | |
| 551 log_lock->Lock(); | |
| 552 } | |
| 553 | |
| 554 #if defined(OS_WIN) | |
| 555 SetFilePointer(log_file, 0, 0, SEEK_END); | |
| 556 DWORD num_written; | |
| 557 WriteFile(log_file, | |
| 558 static_cast<const void*>(str_newline.c_str()), | |
| 559 static_cast<DWORD>(str_newline.length()), | |
| 560 &num_written, | |
| 561 NULL); | |
| 562 #else | |
| 563 fprintf(log_file, "%s", str_newline.c_str()); | |
| 564 fflush(log_file); | |
| 565 #endif | |
| 566 | |
| 567 if (lock_log_file == LOCK_LOG_FILE) { | |
| 568 #if defined(OS_WIN) | |
| 569 ReleaseMutex(log_mutex); | |
| 570 #elif defined(OS_POSIX) | |
| 571 pthread_mutex_unlock(&log_mutex); | |
| 572 #endif | |
| 573 } else { | |
| 574 log_lock->Unlock(); | |
| 575 } | 613 } |
| 576 } | 614 } |
| 577 | 615 |
| 578 if (severity_ == LOG_FATAL) { | 616 if (severity_ == LOG_FATAL) { |
| 579 // display a message or break into the debugger on a fatal error | 617 // display a message or break into the debugger on a fatal error |
| 580 if (DebugUtil::BeingDebugged()) { | 618 if (DebugUtil::BeingDebugged()) { |
| 581 DebugUtil::BreakDebugger(); | 619 DebugUtil::BreakDebugger(); |
| 582 } else { | 620 } else { |
| 583 if (log_assert_handler) { | 621 if (log_assert_handler) { |
| 584 // make a copy of the string for the handler out of paranoia | 622 // make a copy of the string for the handler out of paranoia |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 688 : err_(err), | 726 : err_(err), |
| 689 log_message_(file, line, severity) { | 727 log_message_(file, line, severity) { |
| 690 } | 728 } |
| 691 | 729 |
| 692 ErrnoLogMessage::~ErrnoLogMessage() { | 730 ErrnoLogMessage::~ErrnoLogMessage() { |
| 693 stream() << ": " << safe_strerror(err_); | 731 stream() << ": " << safe_strerror(err_); |
| 694 } | 732 } |
| 695 #endif // OS_WIN | 733 #endif // OS_WIN |
| 696 | 734 |
| 697 void CloseLogFile() { | 735 void CloseLogFile() { |
| 736 LoggingLock logging_lock; |
| 737 |
| 698 if (!log_file) | 738 if (!log_file) |
| 699 return; | 739 return; |
| 700 | 740 |
| 701 CloseFile(log_file); | 741 CloseFile(log_file); |
| 702 log_file = NULL; | 742 log_file = NULL; |
| 703 } | 743 } |
| 704 | 744 |
| 705 void RawLog(int level, const char* message) { | 745 void RawLog(int level, const char* message) { |
| 706 if (level >= min_log_level) { | 746 if (level >= min_log_level) { |
| 707 size_t bytes_written = 0; | 747 size_t bytes_written = 0; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 731 | 771 |
| 732 if (level == LOG_FATAL) | 772 if (level == LOG_FATAL) |
| 733 DebugUtil::BreakDebugger(); | 773 DebugUtil::BreakDebugger(); |
| 734 } | 774 } |
| 735 | 775 |
| 736 } // namespace logging | 776 } // namespace logging |
| 737 | 777 |
| 738 std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) { | 778 std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) { |
| 739 return out << WideToUTF8(std::wstring(wstr)); | 779 return out << WideToUTF8(std::wstring(wstr)); |
| 740 } | 780 } |
| OLD | NEW |