Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
e7ad40a
Initial check-in of Zipkin tracing code (#430).
fabolive Mar 29, 2017
3f1225c
Add span buffer method to generate a JSON payload for posting spans t…
fabolive Mar 30, 2017
05bf311
Have ZipkinReporter use Zipkin::SpanBuffer (#430)
fabolive Mar 30, 2017
01838f8
Make ZipkinReporter use HttpAsyncClient (#430)
fabolive Mar 31, 2017
40e945e
Add binary annotations to Zipkin spans, and a few optimizations (#430)
fabolive Apr 4, 2017
7e7bf38
Fixed file permissions (#430)
fabolive Apr 4, 2017
9cdf72f
Reverting some files in order to split PR 692 (#430)
fabolive Apr 5, 2017
d264083
Changed include statements to conform with Bazel (#430)
fabolive Apr 5, 2017
aeb15f5
Added BUILD file for Bazel (#430)
fabolive Apr 5, 2017
7e9fc97
Reformatted CMakelists.txt and BUILD - clang (#430)
fabolive Apr 5, 2017
4a5d901
Reformatted BUILD and CMakeLists.txt (#430)
fabolive Apr 5, 2017
9f0e96e
Removed empty deps array from BUILD file (#430)
fabolive Apr 6, 2017
4ae612c
Added first batch of test cases for the zipkin library (#430)
fabolive Apr 6, 2017
6e2e7b6
Fixed memory safety issue (#430)
fabolive Apr 7, 2017
eaedc32
Renamed host to endpoint in the zipkin data structures and cleaned th…
fabolive Apr 11, 2017
f899947
Removed un-used Zipkin JSON field names (#430)
fabolive Apr 11, 2017
6d740b4
Added the last batch of tests for the zipkin library (#430)
fabolive Apr 11, 2017
6f1b778
Fixed file permissions (#430)
fabolive Apr 11, 2017
0c79766
Added test to verify finishing a span with an SR annotation (#430)
fabolive Apr 11, 2017
ea4e8f4
Added test to check SpanContext's behavior when setting Span's traceI…
fabolive Apr 11, 2017
fdd3933
Moved the Zipkin library to common/tracing/zipkin. Removed precompile…
fabolive Apr 12, 2017
63f9183
Make sure all variables use snake case (#430)
fabolive Apr 12, 2017
c5daf35
Make sure all variables use snake case (#430)
fabolive Apr 12, 2017
2874f88
Make pointer definitions more explicit (#430)
fabolive Apr 12, 2017
2c8884a
Use file-level namespace for constant definitions (#430)
fabolive Apr 12, 2017
7bb9fe2
Added comments to all classes, structs, enums, and methods. Made seve…
fabolive Apr 12, 2017
b994a8c
Optimized the conversion from uint64_t into a 16-char hex string (#430)
fabolive Apr 12, 2017
9b001e5
Minor fixes, optimizations, and stylistic changes (#430)
fabolive Apr 13, 2017
04e373e
Minor improvements and clean-up to SpanBuffer (#430)
fabolive Apr 13, 2017
dfda5be
Cleaning up SpanContext (#430)
fabolive Apr 13, 2017
4cd118a
Minor clean-ups on Tracer (#430)
fabolive Apr 13, 2017
41c0f57
Renamed utility method name, removed unused header file, and made min…
fabolive Apr 13, 2017
a54f433
Fixed struct name. Minor changes to comments (#430)
fabolive Apr 13, 2017
e0ecb77
Code clean-up (#430)
fabolive Apr 13, 2017
c1e8841
Improved legibility of tests by using raw strings (#430)
fabolive Apr 14, 2017
7ace62b
Support setting a custom random-number generator (#430)
fabolive Apr 17, 2017
d5bcc2f
Add new dependencies to BUILD file of zipkin library (#430)
fabolive Apr 17, 2017
8ad37c3
Improvements to zipkin library tests (#430)
fabolive Apr 17, 2017
dc1e357
SpanBuffer consistently handles a unique_ptr to Span. Streamlined Spa…
fabolive Apr 25, 2017
c53be46
Safer handling of static string variable. Cleaned up SpanContext. (#430)
fabolive Apr 25, 2017
759c6bc
Zipkin Tracer must return unique_ptr to Span. Cleaned up Tracer. (#430)
fabolive Apr 25, 2017
6cb2ac9
Using MonotonicTime to compute Zipkin span duration. Using SystemTime…
fabolive Apr 27, 2017
e14d861
Moved uintToHex() from the Zipkin library to the Hex library. (#430)
fabolive Apr 27, 2017
9560f8e
Added TODO to remove explicit rapidjson header files (#430)
fabolive Apr 27, 2017
50322ee
Refactored Zipkin library to use Network::Address and to handle IPv6.…
fabolive Apr 27, 2017
4628898
Refactored Zipkin library to use the Optional class. (#430)
fabolive Apr 28, 2017
a06e89b
Fixed BUILD files. Removed CMakeLists files. (#430)
fabolive Apr 28, 2017
be09c20
Fixed file permission (#430)
fabolive Apr 28, 2017
cff6194
Fixed format of BUILD file (#430)
fabolive Apr 28, 2017
d236ceb
Minor code improvements (#430)
fabolive Apr 28, 2017
7c5dfae
Merge branch 'master' into zipkin
fabolive Apr 28, 2017
f0fda03
Fixed BUILD files (#430)
fabolive Apr 28, 2017
4d424c9
Minor code improvements (#430)
fabolive May 1, 2017
8b0d96a
Merge branch 'master' into zipkin
fabolive May 1, 2017
11318bb
Use MockMonotonicTimeSource and MockRandomGenerator (#430)
fabolive May 1, 2017
e27d597
Use the Singleton template for string constants. Minor improvements. …
fabolive May 1, 2017
55e8dbf
Merge branch 'master' into zipkin
fabolive May 2, 2017
a157ad0
Use the Singleton template for string constants (#430)
fabolive May 2, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/envoy/runtime/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class RandomGenerator {
virtual std::string uuid() PURE;
};

typedef std::unique_ptr<RandomGenerator> RandomGeneratorPtr;

/**
* A snapshot of runtime data.
*/
Expand Down
17 changes: 17 additions & 0 deletions source/common/common/hex.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "common/common/hex.h"

#include <array>
#include <cstdint>
#include <string>
#include <vector>
Expand Down Expand Up @@ -43,3 +44,19 @@ std::vector<uint8_t> Hex::decode(const std::string& hex_string) {

return segment;
}

std::string Hex::uint64ToHex(uint64_t value) {
std::array<uint8_t, 8> data;

// This is explicitly done for performance reasons
data[7] = (value & 0x00000000000000FF);
data[6] = (value & 0x000000000000FF00) >> 8;
data[5] = (value & 0x0000000000FF0000) >> 16;
data[4] = (value & 0x00000000FF000000) >> 24;
data[3] = (value & 0x000000FF00000000) >> 32;
data[2] = (value & 0x0000FF0000000000) >> 40;
data[1] = (value & 0x00FF000000000000) >> 48;
data[0] = (value & 0xFF00000000000000) >> 56;

return encode(&data[0], data.size());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also be done with std::hex and std::stringstream in 2-3 lines of code. Is there a reason you opted to do the manual unrolling? If so, please add a comment to the code.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason is performance.

}
6 changes: 6 additions & 0 deletions source/common/common/hex.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,10 @@ class Hex final {
* @return binary data
*/
static std::vector<uint8_t> decode(const std::string& input);

/**
* Converts the given 64-bit integer into a hexadecimal string.
* @param value The integer to be converted.
*/
static std::string uint64ToHex(uint64_t value);
};
36 changes: 36 additions & 0 deletions source/common/tracing/zipkin/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
licenses(["notice"]) # Apache 2

package(default_visibility = ["//visibility:public"])

load("//bazel:envoy_build_system.bzl", "envoy_cc_library")

envoy_cc_library(
name = "zipkin_lib",
srcs = [
"span_buffer.cc",
"span_context.cc",
"tracer.cc",
"util.cc",
"zipkin_core_types.cc",
],
hdrs = [
"span_buffer.h",
"span_context.h",
"tracer.h",
"tracer_interface.h",
"util.h",
"zipkin_core_constants.h",
"zipkin_core_types.h",
"zipkin_json_field_names.h",
],
external_deps = ["rapidjson"],
deps = [
"//include/envoy/common:optional",
"//include/envoy/common:time_interface",
"//include/envoy/runtime:runtime_interface",
"//source/common/common:hex_lib",
"//source/common/common:singleton",
"//source/common/common:utility_lib",
"//source/common/network:address_lib",
],
)
30 changes: 30 additions & 0 deletions source/common/tracing/zipkin/span_buffer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include "common/tracing/zipkin/span_buffer.h"

namespace Zipkin {

bool SpanBuffer::addSpan(SpanPtr&& span) {
if (span_buffer_.size() == span_buffer_.capacity()) {
// Buffer full
return false;
}
span_buffer_.push_back(std::move(span));

return true;
}

std::string SpanBuffer::toStringifiedJsonArray() {
std::string stringified_json_array = "[";

if (pendingSpans()) {
stringified_json_array += span_buffer_[0]->toJson();
const uint64_t size = span_buffer_.size();
for (uint64_t i = 1; i < size; i++) {
stringified_json_array += ",";
stringified_json_array += span_buffer_[i]->toJson();
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could consider using https://github.com/lyft/envoy/blob/master/source/common/json/json_loader.h#L22, which does basically what's being done here.

Copy link
Copy Markdown
Contributor Author

@fabolive fabolive May 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, Json::Factory::listAsJsonString() does not do exactly the same thing. As a result of that method, the elements of the stringified json array are stringified as well, which means that an extra level of double-quote escaping would be present. That was not my intention.
I would, therefore, prefer to keep this code unchanged.

}
stringified_json_array += "]";

return stringified_json_array;
}
} // Zipkin
63 changes: 63 additions & 0 deletions source/common/tracing/zipkin/span_buffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#pragma once

#include "common/tracing/zipkin/zipkin_core_types.h"

namespace Zipkin {

/**
* This class implements a simple buffer to store Zipkin tracing spans
* prior to flushing them.
*/
class SpanBuffer {
public:
/**
* Constructor that creates an empty buffer. Space needs to be allocated by invoking
* the method allocateBuffer(size).
*/
SpanBuffer() {}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does anyone use the default constructor? If not I'd suggest removing it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is used by the code on PR #700. PR #700, which is supposed to be merged after this, makes use of the classes on this PR to perform the actual Zipkin tracing.


/**
* Constructor that initializes a buffer with the given size.
*
* @param size The desired buffer size.
*/
SpanBuffer(uint64_t size) { allocateBuffer(size); }

/**
* Allocates space for an empty buffer or resizes a previously-allocated one.
*
* @param size The desired buffer size.
*/
void allocateBuffer(uint64_t size) { span_buffer_.reserve(size); }

/**
* Adds the given Zipkin span to the buffer.
*
* @param span The span to be added to the buffer.
*
* @return true if the span was successfully added, or false if the buffer was full.
*/
bool addSpan(SpanPtr&& span);

/**
* Empties the buffer. This method is supposed to be called when all buffered spans
* have been sent to to the Zipkin service.
*/
void clear() { span_buffer_.clear(); }

/**
* @return the number of spans currently buffered.
*/
uint64_t pendingSpans() { return span_buffer_.size(); }

/**
* @return the contents of the buffer as a stringified array of JSONs, where
* each JSON in the array corresponds to one Zipkin span.
*/
std::string toStringifiedJsonArray();

private:
// We use a pre-allocated vector to improve performance
std::vector<SpanPtr> span_buffer_;
};
} // Zipkin
152 changes: 152 additions & 0 deletions source/common/tracing/zipkin/span_context.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
#include "common/tracing/zipkin/span_context.h"

#include "common/common/utility.h"
#include "common/tracing/zipkin/zipkin_core_constants.h"

namespace Zipkin {

namespace {
// The functions below are needed due to the "C++ static initialization order fiasco."

/**
* @return String that separates the span-context fields in its string-serialized form.
*/
static const std::string& fieldSeparator() {
static const std::string* field_separator = new std::string(";");

return *field_separator;
}

/**
* @return String value corresponding to an empty span context.
*/
static const std::string& unitializedSpanContext() {
static const std::string* unitialized_span_context =
new std::string("0000000000000000" + fieldSeparator() + "0000000000000000" +
fieldSeparator() + "0000000000000000");

return *unitialized_span_context;
}

/**
* @return String with regular expression to match a 16-digit hexadecimal number.
*/
static const std::string& hexDigitGroupRegexStr() {
static const std::string* hex_digit_group_regex_str = new std::string("([0-9,a-z]{16})");

return *hex_digit_group_regex_str;
}

/**
* @return a string with a regular expression to match a valid string-serialized span context.
*
* Note that a function is needed because we cannot concatenate static strings from
* different compilation units at initialization time (the initialization order is not
* guaranteed). In this case, the compilation units are ZipkinCoreConstants and SpanContext.
*/
static const std::string& spanContextRegexStr() {
// ^([0-9,a-z]{16});([0-9,a-z]{16});([0-9,a-z]{16})((;(cs|sr|cr|ss))*)$
static const std::string* span_context_regex_str = new std::string(
"^" + hexDigitGroupRegexStr() + fieldSeparator() + hexDigitGroupRegexStr() +
fieldSeparator() + hexDigitGroupRegexStr() + "((" + fieldSeparator() + "(" +
ZipkinCoreConstants::get().CLIENT_SEND + "|" + ZipkinCoreConstants::get().SERVER_RECV + "|" +
ZipkinCoreConstants::get().CLIENT_RECV + "|" + ZipkinCoreConstants::get().SERVER_SEND +
"))*)$");

return *span_context_regex_str;
}

/**
* @return a regex to match a valid string-serialization of a span context.
*
* Note that a function is needed because the string used to build the regex
* cannot be initialized statically.
*/
static const std::regex& spanContextRegex() {
static const std::regex* span_context_regex = new std::regex(spanContextRegexStr());

return *span_context_regex;
}
} // namespace

SpanContext::SpanContext(const Span& span) {
trace_id_ = span.traceId();
id_ = span.id();
parent_id_ = span.isSetParentId() ? span.parentId() : 0;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you initialize these via the constructor's member initializer list? It might allows you to make these fields const.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These fields are not supposed to be const. The method populateFromString() changes the object state, i.e., it changes the values of those fields.


for (const Annotation& annotation : span.annotations()) {
if (annotation.value() == ZipkinCoreConstants::get().CLIENT_RECV) {
annotation_values_.cr_ = true;
} else if (annotation.value() == ZipkinCoreConstants::get().CLIENT_SEND) {
annotation_values_.cs_ = true;
} else if (annotation.value() == ZipkinCoreConstants::get().SERVER_RECV) {
annotation_values_.sr_ = true;
} else if (annotation.value() == ZipkinCoreConstants::get().SERVER_SEND) {
annotation_values_.ss_ = true;
}
}

is_initialized_ = true;
}

const std::string SpanContext::serializeToString() {
if (!is_initialized_) {
return unitializedSpanContext();
}

std::string result;
result = traceIdAsHexString() + fieldSeparator() + idAsHexString() + fieldSeparator() +
parentIdAsHexString();

if (annotation_values_.cr_) {
result += fieldSeparator() + ZipkinCoreConstants::get().CLIENT_RECV;
}
if (annotation_values_.cs_) {
result += fieldSeparator() + ZipkinCoreConstants::get().CLIENT_SEND;
}
if (annotation_values_.sr_) {
result += fieldSeparator() + ZipkinCoreConstants::get().SERVER_RECV;
}
if (annotation_values_.ss_) {
result += fieldSeparator() + ZipkinCoreConstants::get().SERVER_SEND;
}

return result;
}

void SpanContext::populateFromString(const std::string& span_context_str) {
std::smatch match;

trace_id_ = parent_id_ = id_ = 0;
annotation_values_.cs_ = annotation_values_.cr_ = annotation_values_.ss_ =
annotation_values_.sr_ = false;

if (std::regex_search(span_context_str, match, spanContextRegex())) {
// This is a valid string encoding of the context
trace_id_ = std::stoull(match.str(1), nullptr, 16);
id_ = std::stoull(match.str(2), nullptr, 16);
parent_id_ = std::stoull(match.str(3), nullptr, 16);

std::string matched_annotations = match.str(4);
if (matched_annotations.size() > 0) {
std::vector<std::string> annotation_value_strings =
StringUtil::split(matched_annotations, fieldSeparator());
for (const std::string& annotation_value : annotation_value_strings) {
if (annotation_value == ZipkinCoreConstants::get().CLIENT_RECV) {
annotation_values_.cr_ = true;
} else if (annotation_value == ZipkinCoreConstants::get().CLIENT_SEND) {
annotation_values_.cs_ = true;
} else if (annotation_value == ZipkinCoreConstants::get().SERVER_RECV) {
annotation_values_.sr_ = true;
} else if (annotation_value == ZipkinCoreConstants::get().SERVER_SEND) {
annotation_values_.ss_ = true;
}
Copy link
Copy Markdown
Member

@htuch htuch May 3, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is some commonality in this if-else block with the constructor block that does the same. Please consider refactoring in the future.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@htuch, @mattklein123, @RomanDzhabarov, @adriancole : Thanks for your reviews!
@htuch: I will make sure the other PRs are smaller and will pull you early on in the process. I will consider the code refactoring suggested above.
I will resume the work on PR #700 and let you guys know when you can take a look at it. The code in that branch is outdated now.

}
}

is_initialized_ = true;
} else {
is_initialized_ = false;
}
}
} // Zipkin
Loading