1/* 2 * Copyright (C) 2012 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "DataLog.h" 28#include <stdarg.h> 29#include <string.h> 30#include <wtf/FilePrintStream.h> 31#include <wtf/WTFThreadData.h> 32#include <wtf/Threading.h> 33 34#if OS(UNIX) || OS(DARWIN) 35#include <unistd.h> 36#endif 37 38#if OS(WINCE) 39#ifndef _IONBF 40#define _IONBF 0x0004 41#endif 42#endif 43 44#define DATA_LOG_TO_FILE 0 45 46// Set to 1 to use the temp directory from confstr instead of hardcoded directory. 47// The last component of DATA_LOG_FILENAME will still be used. 48#define DATA_LOG_TO_DARWIN_TEMP_DIR 0 49 50// Uncomment to force logging to the given file regardless of what the environment variable says. 51// Note that we will append ".<pid>.txt" where <pid> is the PID. 52// This path won't work on Windows, make sure to change to something like C:\\Users\\<more path>\\log.txt. 53#define DATA_LOG_FILENAME "/tmp/WTFLog" 54 55namespace WTF { 56 57#if USE(PTHREADS) 58static pthread_once_t initializeLogFileOnceKey = PTHREAD_ONCE_INIT; 59#endif 60 61static FilePrintStream* file; 62 63static uint64_t fileData[(sizeof(FilePrintStream) + 7) / 8]; 64 65static void initializeLogFileOnce() 66{ 67#if DATA_LOG_TO_FILE 68 const long maxPathLength = 1024; 69 70 char filenameSuffix[maxPathLength + 1]; 71 72#if PLATFORM(WIN) 73 _snprintf(filenameSuffix, sizeof(filenameSuffix), ".%d.txt", GetCurrentProcessId()); 74#else 75 snprintf(filenameSuffix, sizeof(filenameSuffix), ".%d.txt", getpid()); 76#endif 77 78#if DATA_LOG_TO_DARWIN_TEMP_DIR 79 char filenameBuffer[maxPathLength + 1]; 80 unsigned suffixLength = strlen(filenameSuffix); 81 82#if defined(DATA_LOG_FILENAME) 83 char* logBasename = strrchr(DATA_LOG_FILENAME, '/'); 84 if (!logBasename) 85 logBasename = (char*)DATA_LOG_FILENAME; 86#else 87 const char* logBasename = "WTFLog"; 88#endif 89 90 const char* filename = 0; 91 92 size_t lastComponentLength = strlen(logBasename) + suffixLength; 93 size_t dirnameLength = confstr(_CS_DARWIN_USER_TEMP_DIR, filenameBuffer, 1024); 94 if ((dirnameLength + lastComponentLength + suffixLength) < maxPathLength) { 95 strncat(filenameBuffer, logBasename, maxPathLength - dirnameLength); 96 filename = filenameBuffer; 97 } 98#elif defined(DATA_LOG_FILENAME) 99 const char* filename = DATA_LOG_FILENAME; 100#else 101 const char* filename = getenv("WTF_DATA_LOG_FILENAME"); 102#endif 103 char actualFilename[maxPathLength + 1]; 104 105 if (filename) { 106#if PLATFORM(WIN) 107 _snprintf(actualFilename, sizeof(actualFilename), "%s%s", filename, filenameSuffix); 108#else 109 snprintf(actualFilename, sizeof(actualFilename), "%s%s", filename, filenameSuffix); 110#endif 111 112 file = FilePrintStream::open(actualFilename, "w").release(); 113 if (file) 114 WTFLogAlways("*** DataLog output to \"%s\" ***\n", actualFilename); 115 else 116 WTFLogAlways("Warning: Could not open DataLog file %s for writing.\n", actualFilename); 117 } 118#endif // DATA_LOG_TO_FILE 119 if (!file) { 120 // Use placement new; this makes it easier to use dataLog() to debug 121 // fastMalloc. 122 file = new (fileData) FilePrintStream(stderr, FilePrintStream::Borrow); 123 } 124 125 setvbuf(file->file(), 0, _IONBF, 0); // Prefer unbuffered output, so that we get a full log upon crash or deadlock. 126} 127 128static void initializeLogFile() 129{ 130#if USE(PTHREADS) 131 pthread_once(&initializeLogFileOnceKey, initializeLogFileOnce); 132#else 133 if (!file) 134 initializeLogFileOnce(); 135#endif 136} 137 138FilePrintStream& dataFile() 139{ 140 initializeLogFile(); 141 return *file; 142} 143 144void dataLogFV(const char* format, va_list argList) 145{ 146 dataFile().vprintf(format, argList); 147} 148 149void dataLogF(const char* format, ...) 150{ 151 va_list argList; 152 va_start(argList, format); 153 dataLogFV(format, argList); 154 va_end(argList); 155} 156 157void dataLogFString(const char* str) 158{ 159 dataFile().printf("%s", str); 160} 161 162} // namespace WTF 163 164