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

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: Address review comments 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
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 typedef HANDLE FileHandle; 10 typedef HANDLE FileHandle;
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698