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 #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 Loading... |
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 |
| 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 Loading... |
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 #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 #if !defined(OS_WIN) |
606 LoggingLock::Init(LOCK_LOG_FILE, nullptr); | 588 LoggingLock::Init(LOCK_LOG_FILE, nullptr); |
607 LoggingLock logging_lock; | 589 LoggingLock logging_lock; |
| 590 #endif |
608 if (InitializeLogFileHandle()) { | 591 if (InitializeLogFileHandle()) { |
609 #if defined(OS_WIN) | 592 #if defined(OS_WIN) |
610 SetFilePointer(g_log_file, 0, 0, SEEK_END); | |
611 DWORD num_written; | 593 DWORD num_written; |
612 WriteFile(g_log_file, | 594 WriteFile(g_log_file, |
613 static_cast<const void*>(str_newline.c_str()), | 595 static_cast<const void*>(str_newline.c_str()), |
614 static_cast<DWORD>(str_newline.length()), | 596 static_cast<DWORD>(str_newline.length()), |
615 &num_written, | 597 &num_written, |
616 nullptr); | 598 nullptr); |
617 #else | 599 #else |
618 ignore_result(fwrite( | 600 ignore_result(fwrite( |
619 str_newline.data(), str_newline.size(), 1, g_log_file)); | 601 str_newline.data(), str_newline.size(), 1, g_log_file)); |
620 fflush(g_log_file); | 602 fflush(g_log_file); |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
760 : err_(err), | 742 : err_(err), |
761 log_message_(file, line, severity) { | 743 log_message_(file, line, severity) { |
762 } | 744 } |
763 | 745 |
764 ErrnoLogMessage::~ErrnoLogMessage() { | 746 ErrnoLogMessage::~ErrnoLogMessage() { |
765 stream() << ": " << SystemErrorCodeToString(err_); | 747 stream() << ": " << SystemErrorCodeToString(err_); |
766 } | 748 } |
767 #endif // defined(OS_WIN) | 749 #endif // defined(OS_WIN) |
768 | 750 |
769 void CloseLogFile() { | 751 void CloseLogFile() { |
| 752 #if !defined(OS_WIN) |
770 LoggingLock logging_lock; | 753 LoggingLock logging_lock; |
| 754 #endif |
771 CloseLogFileUnlocked(); | 755 CloseLogFileUnlocked(); |
772 } | 756 } |
773 | 757 |
774 void RawLog(int level, const char* message) { | 758 void RawLog(int level, const char* message) { |
775 if (level >= g_min_log_level) { | 759 if (level >= g_min_log_level) { |
776 size_t bytes_written = 0; | 760 size_t bytes_written = 0; |
777 const size_t message_len = strlen(message); | 761 const size_t message_len = strlen(message); |
778 int rv; | 762 int rv; |
779 while (bytes_written < message_len) { | 763 while (bytes_written < message_len) { |
780 rv = HANDLE_EINTR( | 764 rv = HANDLE_EINTR( |
(...skipping 18 matching lines...) Expand all Loading... |
799 } | 783 } |
800 | 784 |
801 if (level == LOG_FATAL) | 785 if (level == LOG_FATAL) |
802 base::debug::BreakDebugger(); | 786 base::debug::BreakDebugger(); |
803 } | 787 } |
804 | 788 |
805 // This was defined at the beginning of this file. | 789 // This was defined at the beginning of this file. |
806 #undef write | 790 #undef write |
807 | 791 |
808 #if defined(OS_WIN) | 792 #if defined(OS_WIN) |
| 793 bool IsLoggingToFileEnabled() { |
| 794 return g_logging_destination & LOG_TO_FILE; |
| 795 } |
| 796 |
809 std::wstring GetLogFileFullPath() { | 797 std::wstring GetLogFileFullPath() { |
810 if (g_log_file_name) | 798 if (g_log_file_name) |
811 return *g_log_file_name; | 799 return *g_log_file_name; |
812 return std::wstring(); | 800 return std::wstring(); |
813 } | 801 } |
814 #endif | 802 #endif |
815 | 803 |
816 BASE_EXPORT void LogErrorNotReached(const char* file, int line) { | 804 BASE_EXPORT void LogErrorNotReached(const char* file, int line) { |
817 LogMessage(file, line, LOG_ERROR).stream() | 805 LogMessage(file, line, LOG_ERROR).stream() |
818 << "NOTREACHED() hit."; | 806 << "NOTREACHED() hit."; |
819 } | 807 } |
820 | 808 |
821 } // namespace logging | 809 } // namespace logging |
822 | 810 |
823 std::ostream& std::operator<<(std::ostream& out, const wchar_t* wstr) { | 811 std::ostream& std::operator<<(std::ostream& out, const wchar_t* wstr) { |
824 return out << base::WideToUTF8(wstr); | 812 return out << base::WideToUTF8(wstr); |
825 } | 813 } |
OLD | NEW |