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

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: 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 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 if (last_backslash != PathString::npos) 169 if (last_backslash != PathString::npos)
170 log_name.erase(last_backslash + 1); 170 log_name.erase(last_backslash + 1);
171 log_name += L"debug.log"; 171 log_name += L"debug.log";
172 return log_name; 172 return log_name;
173 #elif defined(OS_POSIX) 173 #elif defined(OS_POSIX)
174 // On other platforms we just use the current directory. 174 // On other platforms we just use the current directory.
175 return PathString("debug.log"); 175 return PathString("debug.log");
176 #endif 176 #endif
177 } 177 }
178 178
179 // We don't need locks on Windows for atomically appending to files. The OS
180 // provides this functionality.
181 #if !defined(OS_WIN)
179 // This class acts as a wrapper for locking the logging files. 182 // This class acts as a wrapper for locking the logging files.
180 // LoggingLock::Init() should be called from the main thread before any logging 183 // 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 184 // 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 185 // instance on the stack. This will ensure that the lock is unlocked upon
183 // exiting the frame. 186 // exiting the frame.
184 // LoggingLocks can not be nested. 187 // LoggingLocks can not be nested.
185 class LoggingLock { 188 class LoggingLock {
186 public: 189 public:
187 LoggingLock() { 190 LoggingLock() {
188 LockLogging(); 191 LockLogging();
189 } 192 }
190 193
191 ~LoggingLock() { 194 ~LoggingLock() {
192 UnlockLogging(); 195 UnlockLogging();
193 } 196 }
194 197
195 static void Init(LogLockingState lock_log, const PathChar* new_log_file) { 198 static void Init(LogLockingState lock_log, const PathChar* new_log_file) {
196 if (initialized) 199 if (initialized)
197 return; 200 return;
198 lock_log_file = lock_log; 201 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 202
213 if (log_mutex == nullptr) { 203 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(); 204 log_lock = new base::internal::LockImpl();
226 } 205
227 initialized = true; 206 initialized = true;
228 } 207 }
229 208
230 private: 209 private:
231 static void LockLogging() { 210 static void LockLogging() {
232 if (lock_log_file == LOCK_LOG_FILE) { 211 if (lock_log_file == LOCK_LOG_FILE) {
233 #if defined(OS_WIN) 212 #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); 213 pthread_mutex_lock(&log_mutex);
242 #endif 214 #endif
243 } else { 215 } else {
244 // use the lock 216 // use the lock
245 log_lock->Lock(); 217 log_lock->Lock();
246 } 218 }
247 } 219 }
248 220
249 static void UnlockLogging() { 221 static void UnlockLogging() {
250 if (lock_log_file == LOCK_LOG_FILE) { 222 if (lock_log_file == LOCK_LOG_FILE) {
251 #if defined(OS_WIN) 223 #if defined(OS_POSIX)
252 ReleaseMutex(log_mutex);
253 #elif defined(OS_POSIX)
254 pthread_mutex_unlock(&log_mutex); 224 pthread_mutex_unlock(&log_mutex);
255 #endif 225 #endif
256 } else { 226 } else {
257 log_lock->Unlock(); 227 log_lock->Unlock();
258 } 228 }
259 } 229 }
260 230
261 // The lock is used if log file locking is false. It helps us avoid problems 231 // 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 232 // 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. 233 // LockImpl directly instead of using Lock, because Lock makes logging calls.
264 static base::internal::LockImpl* log_lock; 234 static base::internal::LockImpl* log_lock;
265 235
266 // When we don't use a lock, we are using a global mutex. We need to do this 236 // 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. 237 // because LockFileEx is not thread safe.
268 #if defined(OS_WIN) 238 #if defined(OS_POSIX)
269 static MutexHandle log_mutex;
270 #elif defined(OS_POSIX)
271 static pthread_mutex_t log_mutex; 239 static pthread_mutex_t log_mutex;
272 #endif 240 #endif
273 241
274 static bool initialized; 242 static bool initialized;
275 static LogLockingState lock_log_file; 243 static LogLockingState lock_log_file;
276 }; 244 };
277 245
278 // static 246 // static
279 bool LoggingLock::initialized = false; 247 bool LoggingLock::initialized = false;
280 // static 248 // static
281 base::internal::LockImpl* LoggingLock::log_lock = nullptr; 249 base::internal::LockImpl* LoggingLock::log_lock = nullptr;
282 // static 250 // static
283 LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE; 251 LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE;
284 252
285 #if defined(OS_WIN) 253 #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; 254 pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER;
290 #endif 255 #endif
291 256
257 #endif // OS_WIN
258
292 // Called by logging functions to ensure that |g_log_file| is initialized 259 // 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 260 // 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. 261 // initialized. |g_log_file| will be nullptr in this case.
295 bool InitializeLogFileHandle() { 262 bool InitializeLogFileHandle() {
296 if (g_log_file) 263 if (g_log_file)
297 return true; 264 return true;
298 265
299 if (!g_log_file_name) { 266 if (!g_log_file_name) {
300 // Nobody has called InitLogging to specify a debug log file, so here we 267 // Nobody has called InitLogging to specify a debug log file, so here we
301 // initialize the log file name to a default. 268 // initialize the log file name to a default.
302 g_log_file_name = new PathString(GetDefaultLogFile()); 269 g_log_file_name = new PathString(GetDefaultLogFile());
303 } 270 }
304 271
305 if ((g_logging_destination & LOG_TO_FILE) != 0) { 272 if ((g_logging_destination & LOG_TO_FILE) != 0) {
306 #if defined(OS_WIN) 273 #if defined(OS_WIN)
307 g_log_file = CreateFile(g_log_file_name->c_str(), GENERIC_WRITE, 274 g_log_file = CreateFile(g_log_file_name->c_str(), FILE_APPEND_DATA,
scottmg 2015/09/16 23:30:47 do we need FILE_APPEND_DATA | SYNCHRONIZE? (and be
scottmg 2015/09/16 23:34:58 https://msdn.microsoft.com/en-us/library/gg258116(
ananta 2015/09/16 23:49:38 msdn says that FILE_APPEND_DATA is enough.
308 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, 275 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
309 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); 276 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
310 if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) { 277 if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) {
311 // try the current directory 278 // try the current directory
312 g_log_file = CreateFile(L".\\debug.log", GENERIC_WRITE, 279 g_log_file = CreateFile(L".\\debug.log", FILE_APPEND_DATA,
scottmg 2015/09/16 23:30:47 this case won't get a sandbox policy based on usin
ananta 2015/09/16 23:49:38 Fixed
313 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, 280 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
314 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); 281 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
315 if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) { 282 if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) {
316 g_log_file = nullptr; 283 g_log_file = nullptr;
317 return false; 284 return false;
318 } 285 }
319 } 286 }
320 SetFilePointer(g_log_file, 0, 0, FILE_END);
321 #elif defined(OS_POSIX) 287 #elif defined(OS_POSIX)
322 g_log_file = fopen(g_log_file_name->c_str(), "a"); 288 g_log_file = fopen(g_log_file_name->c_str(), "a");
323 if (g_log_file == nullptr) 289 if (g_log_file == nullptr)
324 return false; 290 return false;
325 #endif 291 #endif
326 } 292 }
327 293
328 return true; 294 return true;
329 } 295 }
330 296
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 command_line->GetSwitchValueASCII(switches::kVModule), 339 command_line->GetSwitchValueASCII(switches::kVModule),
374 &g_min_log_level); 340 &g_min_log_level);
375 } 341 }
376 342
377 g_logging_destination = settings.logging_dest; 343 g_logging_destination = settings.logging_dest;
378 344
379 // ignore file options unless logging to file is set. 345 // ignore file options unless logging to file is set.
380 if ((g_logging_destination & LOG_TO_FILE) == 0) 346 if ((g_logging_destination & LOG_TO_FILE) == 0)
381 return true; 347 return true;
382 348
349 // We don't need a lock on Windows for atomic appends.
350 #if !defined(OS_WIN)
383 LoggingLock::Init(settings.lock_log, settings.log_file); 351 LoggingLock::Init(settings.lock_log, settings.log_file);
384 LoggingLock logging_lock; 352 LoggingLock logging_lock;
353 #endif
385 354
386 // Calling InitLogging twice or after some log call has already opened the 355 // Calling InitLogging twice or after some log call has already opened the
387 // default log file will re-initialize to the new options. 356 // default log file will re-initialize to the new options.
388 CloseLogFileUnlocked(); 357 CloseLogFileUnlocked();
389 358
390 if (!g_log_file_name) 359 if (!g_log_file_name)
391 g_log_file_name = new PathString(); 360 g_log_file_name = new PathString();
392 *g_log_file_name = settings.log_file; 361 *g_log_file_name = settings.log_file;
393 if (settings.delete_old == DELETE_OLD_LOG_FILE) 362 if (settings.delete_old == DELETE_OLD_LOG_FILE)
394 DeleteFilePath(*g_log_file_name); 363 DeleteFilePath(*g_log_file_name);
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after
596 565
597 // write to log file 566 // write to log file
598 if ((g_logging_destination & LOG_TO_FILE) != 0) { 567 if ((g_logging_destination & LOG_TO_FILE) != 0) {
599 // We can have multiple threads and/or processes, so try to prevent them 568 // We can have multiple threads and/or processes, so try to prevent them
600 // from clobbering each other's writes. 569 // from clobbering each other's writes.
601 // If the client app did not call InitLogging, and the lock has not 570 // 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 571 // 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 572 // 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 573 // the lock. This is why InitLogging should be called from the main
605 // thread at the beginning of execution. 574 // thread at the beginning of execution.
575 // We don't need a lock on Windows for atomic appends.
576 #if !defined(OS_WIN)
606 LoggingLock::Init(LOCK_LOG_FILE, nullptr); 577 LoggingLock::Init(LOCK_LOG_FILE, nullptr);
607 LoggingLock logging_lock; 578 LoggingLock logging_lock;
579 #endif
608 if (InitializeLogFileHandle()) { 580 if (InitializeLogFileHandle()) {
609 #if defined(OS_WIN) 581 #if defined(OS_WIN)
610 SetFilePointer(g_log_file, 0, 0, SEEK_END);
611 DWORD num_written; 582 DWORD num_written;
612 WriteFile(g_log_file, 583 WriteFile(g_log_file,
613 static_cast<const void*>(str_newline.c_str()), 584 static_cast<const void*>(str_newline.c_str()),
614 static_cast<DWORD>(str_newline.length()), 585 static_cast<DWORD>(str_newline.length()),
615 &num_written, 586 &num_written,
616 nullptr); 587 nullptr);
617 #else 588 #else
618 ignore_result(fwrite( 589 ignore_result(fwrite(
619 str_newline.data(), str_newline.size(), 1, g_log_file)); 590 str_newline.data(), str_newline.size(), 1, g_log_file));
620 fflush(g_log_file); 591 fflush(g_log_file);
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
760 : err_(err), 731 : err_(err),
761 log_message_(file, line, severity) { 732 log_message_(file, line, severity) {
762 } 733 }
763 734
764 ErrnoLogMessage::~ErrnoLogMessage() { 735 ErrnoLogMessage::~ErrnoLogMessage() {
765 stream() << ": " << SystemErrorCodeToString(err_); 736 stream() << ": " << SystemErrorCodeToString(err_);
766 } 737 }
767 #endif // defined(OS_WIN) 738 #endif // defined(OS_WIN)
768 739
769 void CloseLogFile() { 740 void CloseLogFile() {
741 // We don't need a lock on Windows for atomic appends.
742 #if !defined(OS_WIN)
770 LoggingLock logging_lock; 743 LoggingLock logging_lock;
744 #endif
771 CloseLogFileUnlocked(); 745 CloseLogFileUnlocked();
772 } 746 }
773 747
774 void RawLog(int level, const char* message) { 748 void RawLog(int level, const char* message) {
775 if (level >= g_min_log_level) { 749 if (level >= g_min_log_level) {
776 size_t bytes_written = 0; 750 size_t bytes_written = 0;
777 const size_t message_len = strlen(message); 751 const size_t message_len = strlen(message);
778 int rv; 752 int rv;
779 while (bytes_written < message_len) { 753 while (bytes_written < message_len) {
780 rv = HANDLE_EINTR( 754 rv = HANDLE_EINTR(
(...skipping 18 matching lines...) Expand all
799 } 773 }
800 774
801 if (level == LOG_FATAL) 775 if (level == LOG_FATAL)
802 base::debug::BreakDebugger(); 776 base::debug::BreakDebugger();
803 } 777 }
804 778
805 // This was defined at the beginning of this file. 779 // This was defined at the beginning of this file.
806 #undef write 780 #undef write
807 781
808 #if defined(OS_WIN) 782 #if defined(OS_WIN)
783 bool IsLoggingToFileEnabled() {
784 return g_logging_destination & LOG_TO_FILE;
785 }
786
809 std::wstring GetLogFileFullPath() { 787 std::wstring GetLogFileFullPath() {
810 if (g_log_file_name) 788 if (g_log_file_name)
811 return *g_log_file_name; 789 return *g_log_file_name;
812 return std::wstring(); 790 return std::wstring();
813 } 791 }
814 #endif 792 #endif
815 793
816 BASE_EXPORT void LogErrorNotReached(const char* file, int line) { 794 BASE_EXPORT void LogErrorNotReached(const char* file, int line) {
817 LogMessage(file, line, LOG_ERROR).stream() 795 LogMessage(file, line, LOG_ERROR).stream()
818 << "NOTREACHED() hit."; 796 << "NOTREACHED() hit.";
819 } 797 }
820 798
821 } // namespace logging 799 } // namespace logging
822 800
823 std::ostream& std::operator<<(std::ostream& out, const wchar_t* wstr) { 801 std::ostream& std::operator<<(std::ostream& out, const wchar_t* wstr) {
824 return out << base::WideToUTF8(wstr); 802 return out << base::WideToUTF8(wstr);
825 } 803 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698