Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 typedef HANDLE FileHandle; | 10 typedef HANDLE FileHandle; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 59 #include "base/threading/platform_thread.h" | 59 #include "base/threading/platform_thread.h" |
| 60 #include "base/vlog.h" | 60 #include "base/vlog.h" |
| 61 #if defined(OS_POSIX) | 61 #if defined(OS_POSIX) |
| 62 #include "base/posix/safe_strerror.h" | 62 #include "base/posix/safe_strerror.h" |
| 63 #endif | 63 #endif |
| 64 | 64 |
| 65 #if defined(OS_ANDROID) | 65 #if defined(OS_ANDROID) |
| 66 #include <android/log.h> | 66 #include <android/log.h> |
| 67 #endif | 67 #endif |
| 68 | 68 |
| 69 #if defined(OS_WIN) | |
|
scottmg
2015/09/16 23:56:51
put this up in the first OS_WIN at the top
ananta
2015/09/17 00:06:00
Done.
| |
| 70 #include "base/files/file_path.h" | |
| 71 #include "base/files/file_util.h" | |
| 72 #endif | |
| 73 | |
| 69 namespace logging { | 74 namespace logging { |
| 70 | 75 |
| 71 namespace { | 76 namespace { |
| 72 | 77 |
| 73 VlogInfo* g_vlog_info = nullptr; | 78 VlogInfo* g_vlog_info = nullptr; |
| 74 VlogInfo* g_vlog_info_prev = nullptr; | 79 VlogInfo* g_vlog_info_prev = nullptr; |
| 75 | 80 |
| 76 const char* const log_severity_names[LOG_NUM_SEVERITIES] = { | 81 const char* const log_severity_names[LOG_NUM_SEVERITIES] = { |
| 77 "INFO", "WARNING", "ERROR", "FATAL" }; | 82 "INFO", "WARNING", "ERROR", "FATAL" }; |
| 78 | 83 |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 169 if (last_backslash != PathString::npos) | 174 if (last_backslash != PathString::npos) |
| 170 log_name.erase(last_backslash + 1); | 175 log_name.erase(last_backslash + 1); |
| 171 log_name += L"debug.log"; | 176 log_name += L"debug.log"; |
| 172 return log_name; | 177 return log_name; |
| 173 #elif defined(OS_POSIX) | 178 #elif defined(OS_POSIX) |
| 174 // On other platforms we just use the current directory. | 179 // On other platforms we just use the current directory. |
| 175 return PathString("debug.log"); | 180 return PathString("debug.log"); |
| 176 #endif | 181 #endif |
| 177 } | 182 } |
| 178 | 183 |
| 184 // We don't need locks on Windows for atomically appending to files. The OS | |
| 185 // provides this functionality. | |
| 186 #if !defined(OS_WIN) | |
| 179 // This class acts as a wrapper for locking the logging files. | 187 // This class acts as a wrapper for locking the logging files. |
| 180 // LoggingLock::Init() should be called from the main thread before any logging | 188 // 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 | 189 // 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 | 190 // instance on the stack. This will ensure that the lock is unlocked upon |
| 183 // exiting the frame. | 191 // exiting the frame. |
| 184 // LoggingLocks can not be nested. | 192 // LoggingLocks can not be nested. |
| 185 class LoggingLock { | 193 class LoggingLock { |
| 186 public: | 194 public: |
| 187 LoggingLock() { | 195 LoggingLock() { |
| 188 LockLogging(); | 196 LockLogging(); |
| 189 } | 197 } |
| 190 | 198 |
| 191 ~LoggingLock() { | 199 ~LoggingLock() { |
| 192 UnlockLogging(); | 200 UnlockLogging(); |
| 193 } | 201 } |
| 194 | 202 |
| 195 static void Init(LogLockingState lock_log, const PathChar* new_log_file) { | 203 static void Init(LogLockingState lock_log, const PathChar* new_log_file) { |
| 196 if (initialized) | 204 if (initialized) |
| 197 return; | 205 return; |
| 198 lock_log_file = lock_log; | 206 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 | 207 |
| 213 if (log_mutex == nullptr) { | 208 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(); | 209 log_lock = new base::internal::LockImpl(); |
| 226 } | 210 |
| 227 initialized = true; | 211 initialized = true; |
| 228 } | 212 } |
| 229 | 213 |
| 230 private: | 214 private: |
| 231 static void LockLogging() { | 215 static void LockLogging() { |
| 232 if (lock_log_file == LOCK_LOG_FILE) { | 216 if (lock_log_file == LOCK_LOG_FILE) { |
| 233 #if defined(OS_WIN) | 217 #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); | 218 pthread_mutex_lock(&log_mutex); |
| 242 #endif | 219 #endif |
| 243 } else { | 220 } else { |
| 244 // use the lock | 221 // use the lock |
| 245 log_lock->Lock(); | 222 log_lock->Lock(); |
| 246 } | 223 } |
| 247 } | 224 } |
| 248 | 225 |
| 249 static void UnlockLogging() { | 226 static void UnlockLogging() { |
| 250 if (lock_log_file == LOCK_LOG_FILE) { | 227 if (lock_log_file == LOCK_LOG_FILE) { |
| 251 #if defined(OS_WIN) | 228 #if defined(OS_POSIX) |
| 252 ReleaseMutex(log_mutex); | |
| 253 #elif defined(OS_POSIX) | |
| 254 pthread_mutex_unlock(&log_mutex); | 229 pthread_mutex_unlock(&log_mutex); |
| 255 #endif | 230 #endif |
| 256 } else { | 231 } else { |
| 257 log_lock->Unlock(); | 232 log_lock->Unlock(); |
| 258 } | 233 } |
| 259 } | 234 } |
| 260 | 235 |
| 261 // The lock is used if log file locking is false. It helps us avoid problems | 236 // 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 | 237 // 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. | 238 // LockImpl directly instead of using Lock, because Lock makes logging calls. |
| 264 static base::internal::LockImpl* log_lock; | 239 static base::internal::LockImpl* log_lock; |
| 265 | 240 |
| 266 // When we don't use a lock, we are using a global mutex. We need to do this | 241 // 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. | 242 // because LockFileEx is not thread safe. |
| 268 #if defined(OS_WIN) | 243 #if defined(OS_POSIX) |
| 269 static MutexHandle log_mutex; | |
| 270 #elif defined(OS_POSIX) | |
| 271 static pthread_mutex_t log_mutex; | 244 static pthread_mutex_t log_mutex; |
| 272 #endif | 245 #endif |
| 273 | 246 |
| 274 static bool initialized; | 247 static bool initialized; |
| 275 static LogLockingState lock_log_file; | 248 static LogLockingState lock_log_file; |
| 276 }; | 249 }; |
| 277 | 250 |
| 278 // static | 251 // static |
| 279 bool LoggingLock::initialized = false; | 252 bool LoggingLock::initialized = false; |
| 280 // static | 253 // static |
| 281 base::internal::LockImpl* LoggingLock::log_lock = nullptr; | 254 base::internal::LockImpl* LoggingLock::log_lock = nullptr; |
| 282 // static | 255 // static |
| 283 LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE; | 256 LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE; |
| 284 | 257 |
| 285 #if defined(OS_WIN) | 258 #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; | 259 pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER; |
| 290 #endif | 260 #endif |
| 291 | 261 |
| 262 #endif // OS_WIN | |
| 263 | |
| 292 // Called by logging functions to ensure that |g_log_file| is initialized | 264 // 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 | 265 // 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. | 266 // initialized. |g_log_file| will be nullptr in this case. |
| 295 bool InitializeLogFileHandle() { | 267 bool InitializeLogFileHandle() { |
| 296 if (g_log_file) | 268 if (g_log_file) |
| 297 return true; | 269 return true; |
| 298 | 270 |
| 299 if (!g_log_file_name) { | 271 if (!g_log_file_name) { |
| 300 // Nobody has called InitLogging to specify a debug log file, so here we | 272 // Nobody has called InitLogging to specify a debug log file, so here we |
| 301 // initialize the log file name to a default. | 273 // initialize the log file name to a default. |
| 302 g_log_file_name = new PathString(GetDefaultLogFile()); | 274 g_log_file_name = new PathString(GetDefaultLogFile()); |
| 303 } | 275 } |
| 304 | 276 |
| 305 if ((g_logging_destination & LOG_TO_FILE) != 0) { | 277 if ((g_logging_destination & LOG_TO_FILE) != 0) { |
| 306 #if defined(OS_WIN) | 278 #if defined(OS_WIN) |
| 307 g_log_file = CreateFile(g_log_file_name->c_str(), GENERIC_WRITE, | 279 g_log_file = CreateFile(g_log_file_name->c_str(), FILE_APPEND_DATA, |
|
scottmg
2015/09/16 23:56:51
Maybe an MSDN link in a comment would be nice for
ananta
2015/09/17 00:06:00
Done.
| |
| 308 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, | 280 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, |
| 309 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); | 281 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); |
| 310 if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) { | 282 if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) { |
| 311 // try the current directory | 283 // try the current directory |
| 312 g_log_file = CreateFile(L".\\debug.log", GENERIC_WRITE, | 284 base::FilePath file_path; |
| 285 if (!base::GetCurrentDirectory(&file_path)) | |
| 286 return false; | |
| 287 | |
| 288 *g_log_file_name = file_path.value(); | |
|
scottmg
2015/09/16 23:56:51
*g_log_file_name = file_path.Append(FILE_PATH_LITE
ananta
2015/09/17 00:06:00
Done.
| |
| 289 g_log_file_name->append(L"\\debug.log"); | |
| 290 | |
| 291 g_log_file = CreateFile(g_log_file_name->c_str(), FILE_APPEND_DATA, | |
| 313 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, | 292 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, |
| 314 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); | 293 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); |
| 315 if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) { | 294 if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) { |
| 316 g_log_file = nullptr; | 295 g_log_file = nullptr; |
| 317 return false; | 296 return false; |
| 318 } | 297 } |
| 319 } | 298 } |
| 320 SetFilePointer(g_log_file, 0, 0, FILE_END); | |
| 321 #elif defined(OS_POSIX) | 299 #elif defined(OS_POSIX) |
| 322 g_log_file = fopen(g_log_file_name->c_str(), "a"); | 300 g_log_file = fopen(g_log_file_name->c_str(), "a"); |
| 323 if (g_log_file == nullptr) | 301 if (g_log_file == nullptr) |
| 324 return false; | 302 return false; |
| 325 #endif | 303 #endif |
| 326 } | 304 } |
| 327 | 305 |
| 328 return true; | 306 return true; |
| 329 } | 307 } |
| 330 | 308 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 373 command_line->GetSwitchValueASCII(switches::kVModule), | 351 command_line->GetSwitchValueASCII(switches::kVModule), |
| 374 &g_min_log_level); | 352 &g_min_log_level); |
| 375 } | 353 } |
| 376 | 354 |
| 377 g_logging_destination = settings.logging_dest; | 355 g_logging_destination = settings.logging_dest; |
| 378 | 356 |
| 379 // ignore file options unless logging to file is set. | 357 // ignore file options unless logging to file is set. |
| 380 if ((g_logging_destination & LOG_TO_FILE) == 0) | 358 if ((g_logging_destination & LOG_TO_FILE) == 0) |
| 381 return true; | 359 return true; |
| 382 | 360 |
| 361 // We don't need a lock on Windows for atomic appends. | |
| 362 #if !defined(OS_WIN) | |
| 383 LoggingLock::Init(settings.lock_log, settings.log_file); | 363 LoggingLock::Init(settings.lock_log, settings.log_file); |
| 384 LoggingLock logging_lock; | 364 LoggingLock logging_lock; |
| 365 #endif | |
| 385 | 366 |
| 386 // Calling InitLogging twice or after some log call has already opened the | 367 // Calling InitLogging twice or after some log call has already opened the |
| 387 // default log file will re-initialize to the new options. | 368 // default log file will re-initialize to the new options. |
| 388 CloseLogFileUnlocked(); | 369 CloseLogFileUnlocked(); |
| 389 | 370 |
| 390 if (!g_log_file_name) | 371 if (!g_log_file_name) |
| 391 g_log_file_name = new PathString(); | 372 g_log_file_name = new PathString(); |
| 392 *g_log_file_name = settings.log_file; | 373 *g_log_file_name = settings.log_file; |
| 393 if (settings.delete_old == DELETE_OLD_LOG_FILE) | 374 if (settings.delete_old == DELETE_OLD_LOG_FILE) |
| 394 DeleteFilePath(*g_log_file_name); | 375 DeleteFilePath(*g_log_file_name); |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 596 | 577 |
| 597 // write to log file | 578 // write to log file |
| 598 if ((g_logging_destination & LOG_TO_FILE) != 0) { | 579 if ((g_logging_destination & LOG_TO_FILE) != 0) { |
| 599 // We can have multiple threads and/or processes, so try to prevent them | 580 // We can have multiple threads and/or processes, so try to prevent them |
| 600 // from clobbering each other's writes. | 581 // from clobbering each other's writes. |
| 601 // If the client app did not call InitLogging, and the lock has not | 582 // 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 | 583 // 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 | 584 // 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 | 585 // the lock. This is why InitLogging should be called from the main |
| 605 // thread at the beginning of execution. | 586 // thread at the beginning of execution. |
| 587 // We don't need a lock on Windows for atomic appends. | |
| 588 #if !defined(OS_WIN) | |
| 606 LoggingLock::Init(LOCK_LOG_FILE, nullptr); | 589 LoggingLock::Init(LOCK_LOG_FILE, nullptr); |
| 607 LoggingLock logging_lock; | 590 LoggingLock logging_lock; |
| 591 #endif | |
| 608 if (InitializeLogFileHandle()) { | 592 if (InitializeLogFileHandle()) { |
| 609 #if defined(OS_WIN) | 593 #if defined(OS_WIN) |
| 610 SetFilePointer(g_log_file, 0, 0, SEEK_END); | |
| 611 DWORD num_written; | 594 DWORD num_written; |
| 612 WriteFile(g_log_file, | 595 WriteFile(g_log_file, |
| 613 static_cast<const void*>(str_newline.c_str()), | 596 static_cast<const void*>(str_newline.c_str()), |
| 614 static_cast<DWORD>(str_newline.length()), | 597 static_cast<DWORD>(str_newline.length()), |
| 615 &num_written, | 598 &num_written, |
| 616 nullptr); | 599 nullptr); |
| 617 #else | 600 #else |
| 618 ignore_result(fwrite( | 601 ignore_result(fwrite( |
| 619 str_newline.data(), str_newline.size(), 1, g_log_file)); | 602 str_newline.data(), str_newline.size(), 1, g_log_file)); |
| 620 fflush(g_log_file); | 603 fflush(g_log_file); |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 760 : err_(err), | 743 : err_(err), |
| 761 log_message_(file, line, severity) { | 744 log_message_(file, line, severity) { |
| 762 } | 745 } |
| 763 | 746 |
| 764 ErrnoLogMessage::~ErrnoLogMessage() { | 747 ErrnoLogMessage::~ErrnoLogMessage() { |
| 765 stream() << ": " << SystemErrorCodeToString(err_); | 748 stream() << ": " << SystemErrorCodeToString(err_); |
| 766 } | 749 } |
| 767 #endif // defined(OS_WIN) | 750 #endif // defined(OS_WIN) |
| 768 | 751 |
| 769 void CloseLogFile() { | 752 void CloseLogFile() { |
| 753 // We don't need a lock on Windows for atomic appends. | |
| 754 #if !defined(OS_WIN) | |
| 770 LoggingLock logging_lock; | 755 LoggingLock logging_lock; |
| 756 #endif | |
| 771 CloseLogFileUnlocked(); | 757 CloseLogFileUnlocked(); |
| 772 } | 758 } |
| 773 | 759 |
| 774 void RawLog(int level, const char* message) { | 760 void RawLog(int level, const char* message) { |
| 775 if (level >= g_min_log_level) { | 761 if (level >= g_min_log_level) { |
| 776 size_t bytes_written = 0; | 762 size_t bytes_written = 0; |
| 777 const size_t message_len = strlen(message); | 763 const size_t message_len = strlen(message); |
| 778 int rv; | 764 int rv; |
| 779 while (bytes_written < message_len) { | 765 while (bytes_written < message_len) { |
| 780 rv = HANDLE_EINTR( | 766 rv = HANDLE_EINTR( |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 799 } | 785 } |
| 800 | 786 |
| 801 if (level == LOG_FATAL) | 787 if (level == LOG_FATAL) |
| 802 base::debug::BreakDebugger(); | 788 base::debug::BreakDebugger(); |
| 803 } | 789 } |
| 804 | 790 |
| 805 // This was defined at the beginning of this file. | 791 // This was defined at the beginning of this file. |
| 806 #undef write | 792 #undef write |
| 807 | 793 |
| 808 #if defined(OS_WIN) | 794 #if defined(OS_WIN) |
| 795 bool IsLoggingToFileEnabled() { | |
| 796 return g_logging_destination & LOG_TO_FILE; | |
| 797 } | |
| 798 | |
| 809 std::wstring GetLogFileFullPath() { | 799 std::wstring GetLogFileFullPath() { |
| 810 if (g_log_file_name) | 800 if (g_log_file_name) |
| 811 return *g_log_file_name; | 801 return *g_log_file_name; |
| 812 return std::wstring(); | 802 return std::wstring(); |
| 813 } | 803 } |
| 814 #endif | 804 #endif |
| 815 | 805 |
| 816 BASE_EXPORT void LogErrorNotReached(const char* file, int line) { | 806 BASE_EXPORT void LogErrorNotReached(const char* file, int line) { |
| 817 LogMessage(file, line, LOG_ERROR).stream() | 807 LogMessage(file, line, LOG_ERROR).stream() |
| 818 << "NOTREACHED() hit."; | 808 << "NOTREACHED() hit."; |
| 819 } | 809 } |
| 820 | 810 |
| 821 } // namespace logging | 811 } // namespace logging |
| 822 | 812 |
| 823 std::ostream& std::operator<<(std::ostream& out, const wchar_t* wstr) { | 813 std::ostream& std::operator<<(std::ostream& out, const wchar_t* wstr) { |
| 824 return out << base::WideToUTF8(wstr); | 814 return out << base::WideToUTF8(wstr); |
| 825 } | 815 } |
| OLD | NEW |