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