V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
log-utils.cc
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/log-utils.h"
6 
7 #include "src/assert-scope.h"
8 #include "src/base/platform/platform.h"
9 #include "src/objects-inl.h"
10 #include "src/string-stream.h"
11 #include "src/utils.h"
12 #include "src/vector.h"
13 #include "src/version.h"
14 
15 namespace v8 {
16 namespace internal {
17 
18 
19 const char* const Log::kLogToTemporaryFile = "&";
20 const char* const Log::kLogToConsole = "-";
21 
22 // static
23 FILE* Log::CreateOutputHandle(const char* file_name) {
24  // If we're logging anything, we need to open the log file.
25  if (!Log::InitLogAtStart()) {
26  return nullptr;
27  } else if (strcmp(file_name, kLogToConsole) == 0) {
28  return stdout;
29  } else if (strcmp(file_name, kLogToTemporaryFile) == 0) {
30  return base::OS::OpenTemporaryFile();
31  } else {
32  return base::OS::FOpen(file_name, base::OS::LogFileOpenMode);
33  }
34 }
35 
36 Log::Log(Logger* logger, const char* file_name)
37  : is_stopped_(false),
38  output_handle_(Log::CreateOutputHandle(file_name)),
39  os_(output_handle_ == nullptr ? stdout : output_handle_),
40  format_buffer_(NewArray<char>(kMessageBufferSize)),
41  logger_(logger) {
42  // --log-all enables all the log flags.
43  if (FLAG_log_all) {
44  FLAG_log_api = true;
45  FLAG_log_code = true;
46  FLAG_log_suspect = true;
47  FLAG_log_handles = true;
48  FLAG_log_internal_timer_events = true;
49  FLAG_log_function_events = true;
50  }
51 
52  // --prof implies --log-code.
53  if (FLAG_prof) FLAG_log_code = true;
54 
55  if (output_handle_ == nullptr) return;
56  Log::MessageBuilder msg(this);
57  LogSeparator kNext = LogSeparator::kSeparator;
58  msg << "v8-version" << kNext << Version::GetMajor() << kNext
59  << Version::GetMinor() << kNext << Version::GetBuild() << kNext
60  << Version::GetPatch();
61  if (strlen(Version::GetEmbedder()) != 0) {
62  msg << kNext << Version::GetEmbedder();
63  }
64  msg << kNext << Version::IsCandidate();
65  msg.WriteToLogFile();
66 }
67 
68 FILE* Log::Close() {
69  FILE* result = nullptr;
70  if (output_handle_ != nullptr) {
71  if (strcmp(FLAG_logfile, kLogToTemporaryFile) != 0) {
72  fclose(output_handle_);
73  } else {
74  result = output_handle_;
75  }
76  }
77  output_handle_ = nullptr;
78 
79  DeleteArray(format_buffer_);
80  format_buffer_ = nullptr;
81 
82  is_stopped_ = false;
83  return result;
84 }
85 
86 Log::MessageBuilder::MessageBuilder(Log* log)
87  : log_(log), lock_guard_(&log_->mutex_) {
88  DCHECK_NOT_NULL(log_->format_buffer_);
89 }
90 
91 void Log::MessageBuilder::AppendString(String str,
92  base::Optional<int> length_limit) {
93  if (str.is_null()) return;
94 
95  DisallowHeapAllocation no_gc; // Ensure string stays valid.
96  int length = str->length();
97  if (length_limit) length = std::min(length, *length_limit);
98  for (int i = 0; i < length; i++) {
99  uint16_t c = str->Get(i);
100  if (c <= 0xFF) {
101  AppendCharacter(static_cast<char>(c));
102  } else {
103  // Escape non-ascii characters.
104  AppendRawFormatString("\\u%04x", c & 0xFFFF);
105  }
106  }
107 }
108 
109 void Log::MessageBuilder::AppendString(Vector<const char> str) {
110  for (auto i = str.begin(); i < str.end(); i++) AppendCharacter(*i);
111 }
112 
113 void Log::MessageBuilder::AppendString(const char* str) {
114  if (str == nullptr) return;
115  AppendString(str, strlen(str));
116 }
117 
118 void Log::MessageBuilder::AppendString(const char* str, size_t length) {
119  if (str == nullptr) return;
120 
121  for (size_t i = 0; i < length; i++) {
122  DCHECK_NE(str[i], '\0');
123  AppendCharacter(str[i]);
124  }
125 }
126 
127 void Log::MessageBuilder::AppendFormatString(const char* format, ...) {
128  va_list args;
129  va_start(args, format);
130  const int length = FormatStringIntoBuffer(format, args);
131  va_end(args);
132  for (int i = 0; i < length; i++) {
133  DCHECK_NE(log_->format_buffer_[i], '\0');
134  AppendCharacter(log_->format_buffer_[i]);
135  }
136 }
137 
138 void Log::MessageBuilder::AppendCharacter(char c) {
139  if (c >= 32 && c <= 126) {
140  if (c == ',') {
141  // Escape commas to avoid adding column separators.
142  AppendRawFormatString("\\x2C");
143  } else if (c == '\\') {
144  AppendRawFormatString("\\\\");
145  } else {
146  // Safe, printable ascii character.
147  AppendRawCharacter(c);
148  }
149  } else if (c == '\n') {
150  // Escape newlines to avoid adding row separators.
151  AppendRawFormatString("\\n");
152  } else {
153  // Escape non-printable characters.
154  AppendRawFormatString("\\x%02x", c & 0xFF);
155  }
156 }
157 
158 void Log::MessageBuilder::AppendSymbolName(Symbol symbol) {
159  DCHECK(!symbol.is_null());
160  OFStream& os = log_->os_;
161  os << "symbol(";
162  if (!symbol->name()->IsUndefined()) {
163  os << "\"";
164  AppendSymbolNameDetails(String::cast(symbol->name()), false);
165  os << "\" ";
166  }
167  os << "hash " << std::hex << symbol->Hash() << std::dec << ")";
168 }
169 
170 void Log::MessageBuilder::AppendSymbolNameDetails(String str,
171  bool show_impl_info) {
172  if (str.is_null()) return;
173 
174  DisallowHeapAllocation no_gc; // Ensure string stays valid.
175  OFStream& os = log_->os_;
176  int limit = str->length();
177  if (limit > 0x1000) limit = 0x1000;
178  if (show_impl_info) {
179  os << (str->IsOneByteRepresentation() ? 'a' : '2');
180  if (StringShape(str).IsExternal()) os << 'e';
181  if (StringShape(str).IsInternalized()) os << '#';
182  os << ':' << str->length() << ':';
183  }
184  AppendString(str, limit);
185 }
186 
187 int Log::MessageBuilder::FormatStringIntoBuffer(const char* format,
188  va_list args) {
189  Vector<char> buf(log_->format_buffer_, Log::kMessageBufferSize);
190  int length = v8::internal::VSNPrintF(buf, format, args);
191  // |length| is -1 if output was truncated.
192  if (length == -1) length = Log::kMessageBufferSize;
193  DCHECK_LE(length, Log::kMessageBufferSize);
194  DCHECK_GE(length, 0);
195  return length;
196 }
197 
198 void Log::MessageBuilder::AppendRawFormatString(const char* format, ...) {
199  va_list args;
200  va_start(args, format);
201  const int length = FormatStringIntoBuffer(format, args);
202  va_end(args);
203  for (int i = 0; i < length; i++) {
204  DCHECK_NE(log_->format_buffer_[i], '\0');
205  AppendRawCharacter(log_->format_buffer_[i]);
206  }
207 }
208 
209 void Log::MessageBuilder::AppendRawCharacter(char c) { log_->os_ << c; }
210 
211 void Log::MessageBuilder::WriteToLogFile() { log_->os_ << std::endl; }
212 
213 template <>
214 Log::MessageBuilder& Log::MessageBuilder::operator<<<const char*>(
215  const char* string) {
216  this->AppendString(string);
217  return *this;
218 }
219 
220 template <>
221 Log::MessageBuilder& Log::MessageBuilder::operator<<<void*>(void* pointer) {
222  OFStream& os = log_->os_;
223  // Manually format the pointer since on Windows we do not consistently
224  // get a "0x" prefix.
225  os << "0x" << std::hex << reinterpret_cast<intptr_t>(pointer) << std::dec;
226  return *this;
227 }
228 
229 template <>
230 Log::MessageBuilder& Log::MessageBuilder::operator<<<char>(char c) {
231  this->AppendCharacter(c);
232  return *this;
233 }
234 
235 template <>
236 Log::MessageBuilder& Log::MessageBuilder::operator<<<String>(String string) {
237  this->AppendString(string);
238  return *this;
239 }
240 
241 template <>
242 Log::MessageBuilder& Log::MessageBuilder::operator<<<Symbol>(Symbol symbol) {
243  this->AppendSymbolName(symbol);
244  return *this;
245 }
246 
247 template <>
248 Log::MessageBuilder& Log::MessageBuilder::operator<<<Name>(Name name) {
249  if (name->IsString()) {
250  this->AppendString(String::cast(name));
251  } else {
252  this->AppendSymbolName(Symbol::cast(name));
253  }
254  return *this;
255 }
256 
257 template <>
258 Log::MessageBuilder& Log::MessageBuilder::operator<<<LogSeparator>(
259  LogSeparator separator) {
260  // Skip escaping to create a new column.
261  this->AppendRawCharacter(',');
262  return *this;
263 }
264 
265 } // namespace internal
266 } // namespace v8
Definition: libplatform.h:13