Skip to content

Commit

Permalink
trace_events: add traced_value.cc/traced_value.h
Browse files Browse the repository at this point in the history
Port of the V8 internal v8::tracing::TracedValue that allows
structured data to be included in the trace event. The v8 class
is not exported in the public API so we cannot use it directly.

This is a simplified and slightly modified port. This commit only
adds the class, it does not add uses of it. Those will come in
separate PRs/commits.

PR-URL: #21475
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
  • Loading branch information
jasnell authored and targos committed Jul 14, 2018
1 parent 07cce88 commit 27d17d4
Show file tree
Hide file tree
Showing 4 changed files with 391 additions and 0 deletions.
3 changes: 3 additions & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@
'src/tracing/node_trace_buffer.cc',
'src/tracing/node_trace_writer.cc',
'src/tracing/trace_event.cc',
'src/tracing/traced_value.cc',
'src/tty_wrap.cc',
'src/udp_wrap.cc',
'src/util.cc',
Expand Down Expand Up @@ -437,6 +438,7 @@
'src/tracing/node_trace_buffer.h',
'src/tracing/node_trace_writer.h',
'src/tracing/trace_event.h',
'src/tracing/traced_value.h',
'src/util.h',
'src/util-inl.h',
'deps/http_parser/http_parser.h',
Expand Down Expand Up @@ -950,6 +952,7 @@
'test/cctest/test_node_postmortem_metadata.cc',
'test/cctest/test_environment.cc',
'test/cctest/test_platform.cc',
'test/cctest/test_traced_value.cc',
'test/cctest/test_util.cc',
'test/cctest/test_url.cc'
],
Expand Down
224 changes: 224 additions & 0 deletions src/tracing/traced_value.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "tracing/traced_value.h"

#include <math.h>
#include <sstream>
#include <stdio.h>
#include <string>

#if defined(NODE_HAVE_I18N_SUPPORT)
#include <unicode/utf8.h>
#include <unicode/utypes.h>
#endif

#if defined(_STLP_VENDOR_CSTD)
// STLPort doesn't import fpclassify into the std namespace.
#define FPCLASSIFY_NAMESPACE
#else
#define FPCLASSIFY_NAMESPACE std
#endif

namespace node {
namespace tracing {

namespace {

std::string EscapeString(const char* value) {
std::string result;
result += '"';
char number_buffer[10];
#if defined(NODE_HAVE_I18N_SUPPORT)
int32_t len = strlen(value);
int32_t p = 0;
int32_t i = 0;
for (; i < len; p = i) {
UChar32 c;
U8_NEXT_OR_FFFD(value, i, len, c);
switch (c) {
case '\b': result += "\\b"; break;
case '\f': result += "\\f"; break;
case '\n': result += "\\n"; break;
case '\r': result += "\\r"; break;
case '\t': result += "\\t"; break;
case '\\': result += "\\\\"; break;
case '"': result += "\\\""; break;
default:
if (c < 32 || c > 126) {
snprintf(
number_buffer, arraysize(number_buffer), "\\u%04X",
static_cast<uint16_t>(static_cast<uint16_t>(c)));
result += number_buffer;
} else {
result.append(value + p, i - p);
}
}
}
#else
// If we do not have ICU, use a modified version of the non-UTF8 aware
// code from V8's own TracedValue implementation. Note, however, This
// will not produce correctly serialized results for UTF8 values.
while (*value) {
char c = *value++;
switch (c) {
case '\b': result += "\\b"; break;
case '\f': result += "\\f"; break;
case '\n': result += "\\n"; break;
case '\r': result += "\\r"; break;
case '\t': result += "\\t"; break;
case '\\': result += "\\\\"; break;
case '"': result += "\\\""; break;
default:
if (c < '\x20') {
snprintf(
number_buffer, arraysize(number_buffer), "\\u%04X",
static_cast<unsigned>(static_cast<unsigned char>(c)));
result += number_buffer;
} else {
result += c;
}
}
}
#endif // defined(NODE_HAVE_I18N_SUPPORT)
result += '"';
return result;
}

std::string DoubleToCString(double v) {
switch (FPCLASSIFY_NAMESPACE::fpclassify(v)) {
case FP_NAN: return "\"NaN\"";
case FP_INFINITE: return (v < 0.0 ? "\"-Infinity\"" : "\"Infinity\"");
case FP_ZERO: return "0";
default:
// This is a far less sophisticated version than the one used inside v8.
std::ostringstream stream;
stream.imbue(std::locale("C")); // Ignore locale
stream << v;
return stream.str();
}
}

} // namespace

std::unique_ptr<TracedValue> TracedValue::Create() {
return std::unique_ptr<TracedValue>(new TracedValue(false));
}

std::unique_ptr<TracedValue> TracedValue::CreateArray() {
return std::unique_ptr<TracedValue>(new TracedValue(true));
}

TracedValue::TracedValue(bool root_is_array) :
first_item_(true), root_is_array_(root_is_array) {}

TracedValue::~TracedValue() {}

void TracedValue::SetInteger(const char* name, int value) {
WriteName(name);
data_ += std::to_string(value);
}

void TracedValue::SetDouble(const char* name, double value) {
WriteName(name);
data_ += DoubleToCString(value);
}

void TracedValue::SetBoolean(const char* name, bool value) {
WriteName(name);
data_ += value ? "true" : "false";
}

void TracedValue::SetNull(const char* name) {
WriteName(name);
data_ += "null";
}

void TracedValue::SetString(const char* name, const char* value) {
WriteName(name);
data_ += EscapeString(value);
}

void TracedValue::BeginDictionary(const char* name) {
WriteName(name);
data_ += '{';
first_item_ = true;
}

void TracedValue::BeginArray(const char* name) {
WriteName(name);
data_ += '[';
first_item_ = true;
}

void TracedValue::AppendInteger(int value) {
WriteComma();
data_ += std::to_string(value);
}

void TracedValue::AppendDouble(double value) {
WriteComma();
data_ += DoubleToCString(value);
}

void TracedValue::AppendBoolean(bool value) {
WriteComma();
data_ += value ? "true" : "false";
}

void TracedValue::AppendNull() {
WriteComma();
data_ += "null";
}

void TracedValue::AppendString(const char* value) {
WriteComma();
data_ += EscapeString(value);
}

void TracedValue::BeginDictionary() {
WriteComma();
data_ += '{';
first_item_ = true;
}

void TracedValue::BeginArray() {
WriteComma();
data_ += '[';
first_item_ = true;
}

void TracedValue::EndDictionary() {
data_ += '}';
first_item_ = false;
}

void TracedValue::EndArray() {
data_ += ']';
first_item_ = false;
}

void TracedValue::WriteComma() {
if (first_item_) {
first_item_ = false;
} else {
data_ += ',';
}
}

void TracedValue::WriteName(const char* name) {
WriteComma();
data_ += '"';
data_ += name;
data_ += "\":";
}

void TracedValue::AppendAsTraceFormat(std::string* out) const {
*out += root_is_array_ ? '[' : '{';
*out += data_;
*out += root_is_array_ ? ']' : '}';
}

} // namespace tracing
} // namespace node
68 changes: 68 additions & 0 deletions src/tracing/traced_value.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef SRC_TRACING_TRACED_VALUE_H_
#define SRC_TRACING_TRACED_VALUE_H_

#include "node_internals.h"
#include "v8.h"

#include <stddef.h>
#include <memory>
#include <string>

namespace node {
namespace tracing {

class TracedValue : public v8::ConvertableToTraceFormat {
public:
~TracedValue() override;

static std::unique_ptr<TracedValue> Create();
static std::unique_ptr<TracedValue> CreateArray();

void EndDictionary();
void EndArray();

// These methods assume that |name| is a long lived "quoted" string.
void SetInteger(const char* name, int value);
void SetDouble(const char* name, double value);
void SetBoolean(const char* name, bool value);
void SetNull(const char* name);
void SetString(const char* name, const char* value);
void SetString(const char* name, const std::string& value) {
SetString(name, value.c_str());
}
void BeginDictionary(const char* name);
void BeginArray(const char* name);

void AppendInteger(int);
void AppendDouble(double);
void AppendBoolean(bool);
void AppendNull();
void AppendString(const char*);
void AppendString(const std::string& value) { AppendString(value.c_str()); }
void BeginArray();
void BeginDictionary();

// ConvertableToTraceFormat implementation.
void AppendAsTraceFormat(std::string* out) const override;

private:
explicit TracedValue(bool root_is_array = false);

void WriteComma();
void WriteName(const char* name);

std::string data_;
bool first_item_;
bool root_is_array_;

DISALLOW_COPY_AND_ASSIGN(TracedValue);
};

} // namespace tracing
} // namespace node

#endif // SRC_TRACING_TRACED_VALUE_H_
Loading

0 comments on commit 27d17d4

Please sign in to comment.