V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
trace-writer.cc
1 // Copyright 2016 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/libplatform/tracing/trace-writer.h"
6 
7 #include <cmath>
8 
9 #include "base/trace_event/common/trace_event_common.h"
10 #include "include/v8-platform.h"
11 #include "src/base/platform/platform.h"
12 
13 namespace v8 {
14 namespace platform {
15 namespace tracing {
16 
17 // Writes the given string to a stream, taking care to escape characters
18 // when necessary.
19 V8_INLINE static void WriteJSONStringToStream(const char* str,
20  std::ostream& stream) {
21  size_t len = strlen(str);
22  stream << "\"";
23  for (size_t i = 0; i < len; ++i) {
24  // All of the permitted escape sequences in JSON strings, as per
25  // https://mathiasbynens.be/notes/javascript-escapes
26  switch (str[i]) {
27  case '\b':
28  stream << "\\b";
29  break;
30  case '\f':
31  stream << "\\f";
32  break;
33  case '\n':
34  stream << "\\n";
35  break;
36  case '\r':
37  stream << "\\r";
38  break;
39  case '\t':
40  stream << "\\t";
41  break;
42  case '\"':
43  stream << "\\\"";
44  break;
45  case '\\':
46  stream << "\\\\";
47  break;
48  // Note that because we use double quotes for JSON strings,
49  // we don't need to escape single quotes.
50  default:
51  stream << str[i];
52  break;
53  }
54  }
55  stream << "\"";
56 }
57 
58 void JSONTraceWriter::AppendArgValue(uint8_t type,
59  TraceObject::ArgValue value) {
60  switch (type) {
61  case TRACE_VALUE_TYPE_BOOL:
62  stream_ << (value.as_bool ? "true" : "false");
63  break;
64  case TRACE_VALUE_TYPE_UINT:
65  stream_ << value.as_uint;
66  break;
67  case TRACE_VALUE_TYPE_INT:
68  stream_ << value.as_int;
69  break;
70  case TRACE_VALUE_TYPE_DOUBLE: {
71  std::string real;
72  double val = value.as_double;
73  if (std::isfinite(val)) {
74  std::ostringstream convert_stream;
75  convert_stream << val;
76  real = convert_stream.str();
77  // Ensure that the number has a .0 if there's no decimal or 'e'. This
78  // makes sure that when we read the JSON back, it's interpreted as a
79  // real rather than an int.
80  if (real.find('.') == std::string::npos &&
81  real.find('e') == std::string::npos &&
82  real.find('E') == std::string::npos) {
83  real += ".0";
84  }
85  } else if (std::isnan(val)) {
86  // The JSON spec doesn't allow NaN and Infinity (since these are
87  // objects in EcmaScript). Use strings instead.
88  real = "\"NaN\"";
89  } else if (val < 0) {
90  real = "\"-Infinity\"";
91  } else {
92  real = "\"Infinity\"";
93  }
94  stream_ << real;
95  break;
96  }
97  case TRACE_VALUE_TYPE_POINTER:
98  // JSON only supports double and int numbers.
99  // So as not to lose bits from a 64-bit pointer, output as a hex string.
100  stream_ << "\"" << value.as_pointer << "\"";
101  break;
102  case TRACE_VALUE_TYPE_STRING:
103  case TRACE_VALUE_TYPE_COPY_STRING:
104  if (value.as_string == nullptr) {
105  stream_ << "\"nullptr\"";
106  } else {
107  WriteJSONStringToStream(value.as_string, stream_);
108  }
109  break;
110  default:
111  UNREACHABLE();
112  break;
113  }
114 }
115 
116 void JSONTraceWriter::AppendArgValue(ConvertableToTraceFormat* value) {
117  std::string arg_stringified;
118  value->AppendAsTraceFormat(&arg_stringified);
119  stream_ << arg_stringified;
120 }
121 
122 JSONTraceWriter::JSONTraceWriter(std::ostream& stream)
123  : JSONTraceWriter(stream, "traceEvents") {}
124 
125 JSONTraceWriter::JSONTraceWriter(std::ostream& stream, const std::string& tag)
126  : stream_(stream) {
127  stream_ << "{\"" << tag << "\":[";
128 }
129 
130 JSONTraceWriter::~JSONTraceWriter() { stream_ << "]}"; }
131 
132 void JSONTraceWriter::AppendTraceEvent(TraceObject* trace_event) {
133  if (append_comma_) stream_ << ",";
134  append_comma_ = true;
135  stream_ << "{\"pid\":" << trace_event->pid()
136  << ",\"tid\":" << trace_event->tid()
137  << ",\"ts\":" << trace_event->ts()
138  << ",\"tts\":" << trace_event->tts() << ",\"ph\":\""
139  << trace_event->phase() << "\",\"cat\":\""
140  << TracingController::GetCategoryGroupName(
141  trace_event->category_enabled_flag())
142  << "\",\"name\":\"" << trace_event->name()
143  << "\",\"dur\":" << trace_event->duration()
144  << ",\"tdur\":" << trace_event->cpu_duration();
145  if (trace_event->flags() & TRACE_EVENT_FLAG_HAS_ID) {
146  if (trace_event->scope() != nullptr) {
147  stream_ << ",\"scope\":\"" << trace_event->scope() << "\"";
148  }
149  // So as not to lose bits from a 64-bit integer, output as a hex string.
150  stream_ << ",\"id\":\"0x" << std::hex << trace_event->id() << "\""
151  << std::dec;
152  }
153  stream_ << ",\"args\":{";
154  const char** arg_names = trace_event->arg_names();
155  const uint8_t* arg_types = trace_event->arg_types();
156  TraceObject::ArgValue* arg_values = trace_event->arg_values();
157  std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables =
158  trace_event->arg_convertables();
159  for (int i = 0; i < trace_event->num_args(); ++i) {
160  if (i > 0) stream_ << ",";
161  stream_ << "\"" << arg_names[i] << "\":";
162  if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
163  AppendArgValue(arg_convertables[i].get());
164  } else {
165  AppendArgValue(arg_types[i], arg_values[i]);
166  }
167  }
168  stream_ << "}}";
169  // TODO(fmeawad): Add support for Flow Events.
170 }
171 
172 void JSONTraceWriter::Flush() {}
173 
174 TraceWriter* TraceWriter::CreateJSONTraceWriter(std::ostream& stream) {
175  return new JSONTraceWriter(stream);
176 }
177 
178 TraceWriter* TraceWriter::CreateJSONTraceWriter(std::ostream& stream,
179  const std::string& tag) {
180  return new JSONTraceWriter(stream, tag);
181 }
182 
183 } // namespace tracing
184 } // namespace platform
185 } // namespace v8
Definition: libplatform.h:13