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
10 namespace v8 {
11 namespace internal {
12
13
14 const char* const Log::kLogToTemporaryFile = "&";
15 const char* const Log::kLogToConsole = "-";
16
17
Log(Logger * logger)18 Log::Log(Logger* logger)
19 : is_stopped_(false),
20 output_handle_(NULL),
21 message_buffer_(NULL),
22 logger_(logger) {
23 }
24
25
Initialize(const char * log_file_name)26 void 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
OpenStdout()56 void Log::OpenStdout() {
57 DCHECK(!IsEnabled());
58 output_handle_ = stdout;
59 }
60
61
OpenTemporaryFile()62 void Log::OpenTemporaryFile() {
63 DCHECK(!IsEnabled());
64 output_handle_ = base::OS::OpenTemporaryFile();
65 }
66
67
OpenFile(const char * name)68 void Log::OpenFile(const char* name) {
69 DCHECK(!IsEnabled());
70 output_handle_ = base::OS::FOpen(name, base::OS::LogFileOpenMode);
71 }
72
73
Close()74 FILE* 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
MessageBuilder(Log * log)93 Log::MessageBuilder::MessageBuilder(Log* log)
94 : log_(log),
95 lock_guard_(&log_->mutex_),
96 pos_(0) {
97 DCHECK(log_->message_buffer_ != NULL);
98 }
99
100
Append(const char * format,...)101 void 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
AppendVA(const char * format,va_list args)112 void 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
Append(const char c)127 void 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
AppendDoubleQuotedString(const char * string)135 void 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
Append(String * str)147 void 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
AppendAddress(Address addr)156 void Log::MessageBuilder::AppendAddress(Address addr) {
157 Append("0x%" V8PRIxPTR, addr);
158 }
159
160
AppendSymbolName(Symbol * symbol)161 void 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
AppendDetailed(String * str,bool show_impl_info)173 void 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
AppendStringPart(const char * str,int len)206 void 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
WriteToLogFile()220 void 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