1// Copyright 2009 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/v8.h" 6 7#include "src/log-utils.h" 8#include "src/string-stream.h" 9 10namespace v8 { 11namespace internal { 12 13 14const char* const Log::kLogToTemporaryFile = "&"; 15const char* const Log::kLogToConsole = "-"; 16 17 18Log::Log(Logger* logger) 19 : is_stopped_(false), 20 output_handle_(NULL), 21 message_buffer_(NULL), 22 logger_(logger) { 23} 24 25 26void Log::Initialize(const char* log_file_name) { 27 message_buffer_ = NewArray<char>(kMessageBufferSize); 28 29 // --log-all enables all the log flags. 30 if (FLAG_log_all) { 31 FLAG_log_api = true; 32 FLAG_log_code = true; 33 FLAG_log_gc = true; 34 FLAG_log_suspect = true; 35 FLAG_log_handles = true; 36 FLAG_log_regexp = true; 37 FLAG_log_internal_timer_events = true; 38 } 39 40 // --prof implies --log-code. 41 if (FLAG_prof) FLAG_log_code = true; 42 43 // If we're logging anything, we need to open the log file. 44 if (Log::InitLogAtStart()) { 45 if (strcmp(log_file_name, kLogToConsole) == 0) { 46 OpenStdout(); 47 } else if (strcmp(log_file_name, kLogToTemporaryFile) == 0) { 48 OpenTemporaryFile(); 49 } else { 50 OpenFile(log_file_name); 51 } 52 } 53} 54 55 56void Log::OpenStdout() { 57 DCHECK(!IsEnabled()); 58 output_handle_ = stdout; 59} 60 61 62void Log::OpenTemporaryFile() { 63 DCHECK(!IsEnabled()); 64 output_handle_ = base::OS::OpenTemporaryFile(); 65} 66 67 68void Log::OpenFile(const char* name) { 69 DCHECK(!IsEnabled()); 70 output_handle_ = base::OS::FOpen(name, base::OS::LogFileOpenMode); 71} 72 73 74FILE* Log::Close() { 75 FILE* result = NULL; 76 if (output_handle_ != NULL) { 77 if (strcmp(FLAG_logfile, kLogToTemporaryFile) != 0) { 78 fclose(output_handle_); 79 } else { 80 result = output_handle_; 81 } 82 } 83 output_handle_ = NULL; 84 85 DeleteArray(message_buffer_); 86 message_buffer_ = NULL; 87 88 is_stopped_ = false; 89 return result; 90} 91 92 93Log::MessageBuilder::MessageBuilder(Log* log) 94 : log_(log), 95 lock_guard_(&log_->mutex_), 96 pos_(0) { 97 DCHECK(log_->message_buffer_ != NULL); 98} 99 100 101void Log::MessageBuilder::Append(const char* format, ...) { 102 Vector<char> buf(log_->message_buffer_ + pos_, 103 Log::kMessageBufferSize - pos_); 104 va_list args; 105 va_start(args, format); 106 AppendVA(format, args); 107 va_end(args); 108 DCHECK(pos_ <= Log::kMessageBufferSize); 109} 110 111 112void Log::MessageBuilder::AppendVA(const char* format, va_list args) { 113 Vector<char> buf(log_->message_buffer_ + pos_, 114 Log::kMessageBufferSize - pos_); 115 int result = v8::internal::VSNPrintF(buf, format, args); 116 117 // Result is -1 if output was truncated. 118 if (result >= 0) { 119 pos_ += result; 120 } else { 121 pos_ = Log::kMessageBufferSize; 122 } 123 DCHECK(pos_ <= Log::kMessageBufferSize); 124} 125 126 127void Log::MessageBuilder::Append(const char c) { 128 if (pos_ < Log::kMessageBufferSize) { 129 log_->message_buffer_[pos_++] = c; 130 } 131 DCHECK(pos_ <= Log::kMessageBufferSize); 132} 133 134 135void Log::MessageBuilder::AppendDoubleQuotedString(const char* string) { 136 Append('"'); 137 for (const char* p = string; *p != '\0'; p++) { 138 if (*p == '"') { 139 Append('\\'); 140 } 141 Append(*p); 142 } 143 Append('"'); 144} 145 146 147void Log::MessageBuilder::Append(String* str) { 148 DisallowHeapAllocation no_gc; // Ensure string stay valid. 149 int length = str->length(); 150 for (int i = 0; i < length; i++) { 151 Append(static_cast<char>(str->Get(i))); 152 } 153} 154 155 156void Log::MessageBuilder::AppendAddress(Address addr) { 157 Append("0x%" V8PRIxPTR, addr); 158} 159 160 161void Log::MessageBuilder::AppendSymbolName(Symbol* symbol) { 162 DCHECK(symbol); 163 Append("symbol("); 164 if (!symbol->name()->IsUndefined()) { 165 Append("\""); 166 AppendDetailed(String::cast(symbol->name()), false); 167 Append("\" "); 168 } 169 Append("hash %x)", symbol->Hash()); 170} 171 172 173void Log::MessageBuilder::AppendDetailed(String* str, bool show_impl_info) { 174 if (str == NULL) return; 175 DisallowHeapAllocation no_gc; // Ensure string stay valid. 176 int len = str->length(); 177 if (len > 0x1000) 178 len = 0x1000; 179 if (show_impl_info) { 180 Append(str->IsOneByteRepresentation() ? 'a' : '2'); 181 if (StringShape(str).IsExternal()) 182 Append('e'); 183 if (StringShape(str).IsInternalized()) 184 Append('#'); 185 Append(":%i:", str->length()); 186 } 187 for (int i = 0; i < len; i++) { 188 uc32 c = str->Get(i); 189 if (c > 0xff) { 190 Append("\\u%04x", c); 191 } else if (c < 32 || c > 126) { 192 Append("\\x%02x", c); 193 } else if (c == ',') { 194 Append("\\,"); 195 } else if (c == '\\') { 196 Append("\\\\"); 197 } else if (c == '\"') { 198 Append("\"\""); 199 } else { 200 Append("%lc", c); 201 } 202 } 203} 204 205 206void Log::MessageBuilder::AppendStringPart(const char* str, int len) { 207 if (pos_ + len > Log::kMessageBufferSize) { 208 len = Log::kMessageBufferSize - pos_; 209 DCHECK(len >= 0); 210 if (len == 0) return; 211 } 212 Vector<char> buf(log_->message_buffer_ + pos_, 213 Log::kMessageBufferSize - pos_); 214 StrNCpy(buf, str, len); 215 pos_ += len; 216 DCHECK(pos_ <= Log::kMessageBufferSize); 217} 218 219 220void Log::MessageBuilder::WriteToLogFile() { 221 DCHECK(pos_ <= Log::kMessageBufferSize); 222 // Assert that we do not already have a new line at the end. 223 DCHECK(pos_ == 0 || log_->message_buffer_[pos_ - 1] != '\n'); 224 if (pos_ == Log::kMessageBufferSize) pos_--; 225 log_->message_buffer_[pos_++] = '\n'; 226 const int written = log_->WriteToFile(log_->message_buffer_, pos_); 227 if (written != pos_) { 228 log_->stop(); 229 log_->logger_->LogFailure(); 230 } 231} 232 233 234} } // namespace v8::internal 235