-
Notifications
You must be signed in to change notification settings - Fork 16
Add support for x-cloud-trace-context #248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
20545c7
Add support for x-cloud-trace-context
rob-spotify d311a7a
needs debugging
rob-spotify c5b1149
Fixed one test, just need to implement the parsing and serialising of…
rob-spotify dbbcff6
Now supports long format trace_id/span_id;o=[0-1] - TODO support the …
rob-spotify d6d90b9
Support medium and short form cloud-trace headers (TODO verify what w…
rob-spotify 252358a
Revert CMakeLists.txt change
rob-spotify 6181730
Revert CMakeLists.txt
rob-spotify be25e16
Expect span ID to be 0 when none is given (need to confirm this is th…
rob-spotify b1d0b38
Add cloud_trace propagator to CMakeLists.txt
rob-spotify 4ae8982
span ID is an unsigned long, not a hex value
rob-spotify 4630635
Fix the max length of the x-cloud-trace-context header
rob-spotify 022b2e2
incorrect char array assignment
rob-spotify 8176a65
set the header length properly
rob-spotify 1fbdd02
Revert CMakeLists.txt
rob-spotify 13e0e72
fix style error
rob-spotify cf4eb97
fix linting issues
rob-spotify 5f7a33f
unused import
rob-spotify 395af64
Add cloud_trace_propagator.cpp to build list
rob-spotify 7a230b2
Fix portability error
rob-spotify 2c9c678
use string_view and nullptr
rob-spotify 0c0f66a
Fix span_id short parsing
rob-spotify 19d62e0
Simplify serialize method with snprintf
rob-spotify 54323d6
cover error handling with additional test cases
rob-spotify c9bd7ab
Test potential maximum ID values for propagators
rob-spotify 6c18e33
Cover the bad trace flag case
rob-spotify 4e3411d
Was adding a space at the end of the header
rob-spotify b214ed8
Extend header length (it looks like it does need it for the possible …
rob-spotify 146f9b9
Review comments
rob-spotify baa3603
Fix clang-tidy error
rob-spotify fc3d3c3
Review comments
rob-spotify b7bd88d
Fix failing test
rob-spotify File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
#include "tracer/propagation/cloud_trace_propagator.h" | ||
|
||
#include "common/hex_conversion.h" | ||
|
||
#include "tracer/propagation/binary_propagation.h" | ||
#include "tracer/propagation/utility.h" | ||
|
||
const opentracing::string_view PropagationSingleKey = "x-cloud-trace-context"; | ||
const opentracing::string_view PrefixBaggage = "ot-baggage-"; | ||
|
||
namespace lightstep { | ||
//-------------------------------------------------------------------------------------------------- | ||
// InjectSpanContext | ||
//-------------------------------------------------------------------------------------------------- | ||
opentracing::expected<void> CloudTracePropagator::InjectSpanContext( | ||
const opentracing::TextMapWriter& carrier, | ||
const TraceContext& trace_context, opentracing::string_view /*trace_state*/, | ||
const BaggageProtobufMap& /*baggage*/) const { | ||
return this->InjectSpanContextImpl(carrier, trace_context); | ||
} | ||
|
||
opentracing::expected<void> CloudTracePropagator::InjectSpanContext( | ||
const opentracing::TextMapWriter& carrier, | ||
const TraceContext& trace_context, opentracing::string_view /*trace_state*/, | ||
const BaggageFlatMap& /*baggage*/) const { | ||
return this->InjectSpanContextImpl(carrier, trace_context); | ||
} | ||
//-------------------------------------------------------------------------------------------------- | ||
// ExtractSpanContext | ||
//-------------------------------------------------------------------------------------------------- | ||
opentracing::expected<bool> CloudTracePropagator::ExtractSpanContext( | ||
const opentracing::TextMapReader& carrier, bool case_sensitive, | ||
TraceContext& trace_context, std::string& /*trace_state*/, | ||
BaggageProtobufMap& baggage) const { | ||
auto iequals = | ||
[](opentracing::string_view lhs, opentracing::string_view rhs) noexcept { | ||
return lhs.length() == rhs.length() && | ||
std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs), | ||
[](char a, char b) { | ||
return std::tolower(a) == std::tolower(b); | ||
}); | ||
}; | ||
opentracing::expected<bool> result; | ||
if (case_sensitive) { | ||
result = this->ExtractSpanContextImpl(carrier, trace_context, | ||
std::equal_to<opentracing::string_view>{}, baggage); | ||
} else { | ||
result = this->ExtractSpanContextImpl(carrier, trace_context, iequals, baggage); | ||
} | ||
if (!result || !*result) { | ||
return result; | ||
} | ||
|
||
return result; | ||
} | ||
|
||
//-------------------------------------------------------------------------------------------------- | ||
// InjectSpanContextImpl | ||
//-------------------------------------------------------------------------------------------------- | ||
opentracing::expected<void> CloudTracePropagator::InjectSpanContextImpl( | ||
const opentracing::TextMapWriter& carrier, | ||
const TraceContext& trace_context) const { | ||
std::array<char, CloudContextLength> buffer; | ||
auto data_length = this->SerializeCloudTrace(trace_context, buffer.data()); | ||
return carrier.Set(PropagationSingleKey, | ||
opentracing::string_view{buffer.data(), data_length}); | ||
} | ||
|
||
//-------------------------------------------------------------------------------------------------- | ||
// ExtractSpanContextImpl | ||
//-------------------------------------------------------------------------------------------------- | ||
template <class KeyCompare> | ||
opentracing::expected<bool> CloudTracePropagator::ExtractSpanContextImpl( | ||
const opentracing::TextMapReader& carrier, TraceContext& trace_context, const KeyCompare& key_compare, | ||
BaggageProtobufMap& baggage) const { | ||
bool parent_header_found = false; | ||
auto result = | ||
carrier.ForeachKey([&](opentracing::string_view key, | ||
opentracing::string_view | ||
value) noexcept->opentracing::expected<void> { | ||
if (key_compare(key, PropagationSingleKey)) { | ||
auto was_successful = this->ParseCloudTrace(value, trace_context); | ||
if (!was_successful) { | ||
return opentracing::make_unexpected(was_successful.error()); | ||
} | ||
parent_header_found = true; | ||
} else if (key.length() > PrefixBaggage.size() && | ||
key_compare(opentracing::string_view{key.data(), | ||
PrefixBaggage.size()}, | ||
PrefixBaggage)) { | ||
baggage.insert(BaggageProtobufMap::value_type( | ||
ToLower( | ||
opentracing::string_view{key.data() + PrefixBaggage.size(), | ||
key.size() - PrefixBaggage.size()}), | ||
value)); | ||
} | ||
return {}; | ||
}); | ||
if (!result) { | ||
return opentracing::make_unexpected(result.error()); | ||
} | ||
return parent_header_found; | ||
} | ||
|
||
opentracing::expected<void> CloudTracePropagator::ParseCloudTrace( | ||
opentracing::string_view s, TraceContext& trace_context) const noexcept { | ||
if (s.size() < Num128BitHexDigits) { | ||
return opentracing::make_unexpected( | ||
std::make_error_code(std::errc::invalid_argument)); | ||
} | ||
size_t offset = 0; | ||
|
||
// default sampled to on (this comes from the ;o=1 part of | ||
// x-cloud-trace-context; if it is not set we will default to sampling | ||
// this request) | ||
trace_context.trace_flags = SetTraceFlag<SampledFlagMask>(trace_context.trace_flags, true); | ||
|
||
// trace-id | ||
auto error_maybe = NormalizedHexToUint128( | ||
opentracing::string_view{s.data() + offset, Num128BitHexDigits}, | ||
trace_context.trace_id_high, trace_context.trace_id_low); | ||
if (!error_maybe) { | ||
return error_maybe; | ||
rob-spotify marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
offset += Num128BitHexDigits; | ||
if (s.size() - offset < 2) { | ||
// only a short form trace ID has been given (not a "trace id/span id") | ||
return {}; | ||
} | ||
|
||
if (s[offset] != '/') { | ||
return opentracing::make_unexpected( | ||
std::make_error_code(std::errc::invalid_argument)); | ||
rob-spotify marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
++offset; | ||
|
||
std::array<char, Num64BitDecimalDigits + 1> parent_id; | ||
size_t i; | ||
for (i=0; i < Num64BitDecimalDigits; ++i) { | ||
if (offset == s.length() || std::isdigit(s[offset]) == 0) { | ||
break; | ||
} | ||
parent_id[i] = s[offset]; | ||
++offset; | ||
} | ||
parent_id[i] = '\0'; | ||
|
||
// parent-id | ||
errno = 0; | ||
trace_context.parent_id = std::strtoull(parent_id.data(), nullptr, 10); | ||
if (errno == ERANGE) { | ||
return opentracing::make_unexpected( | ||
std::make_error_code(std::errc::result_out_of_range)); | ||
} | ||
|
||
if (s.size() - offset < 4) { | ||
// only a "trace ID/span ID" has been given (not a "trace id/span id;o=[0-1]") | ||
return {}; | ||
} | ||
|
||
if(opentracing::string_view(s.begin() + offset, 3) != opentracing::string_view(";o=")) { | ||
return opentracing::make_unexpected( | ||
std::make_error_code(std::errc::invalid_argument)); | ||
} | ||
|
||
offset += 3; | ||
|
||
// trace-flags | ||
if (s[offset] == '0') { | ||
// don't sample | ||
trace_context.trace_flags = SetTraceFlag<SampledFlagMask>(trace_context.trace_flags, false); | ||
} | ||
|
||
return {}; | ||
} | ||
|
||
size_t CloudTracePropagator::SerializeCloudTrace(const TraceContext& trace_context, | ||
char* s) const noexcept { | ||
size_t offset = 0; | ||
// trace-id | ||
Uint64ToHex(trace_context.trace_id_high, s); | ||
offset += Num64BitHexDigits; | ||
Uint64ToHex(trace_context.trace_id_low, s + offset); | ||
offset += Num64BitHexDigits; | ||
|
||
offset += snprintf(s + offset, CloudContextLength - offset, "/%lu;o=%d", trace_context.parent_id, IsTraceFlagSet<SampledFlagMask>(trace_context.trace_flags) ? 1 : 0); | ||
|
||
return offset; | ||
} | ||
} // namespace lightstep |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#pragma once | ||
|
||
#include "tracer/propagation/propagator.h" | ||
|
||
namespace lightstep { | ||
|
||
const size_t CloudContextLength = 58; // max x-cloud-trace-context header | ||
|
||
const size_t Num64BitDecimalDigits = 20; | ||
|
||
class CloudTracePropagator final : public Propagator { | ||
public: | ||
// Propagator | ||
opentracing::expected<void> InjectSpanContext( | ||
const opentracing::TextMapWriter& carrier, | ||
const TraceContext& trace_context, opentracing::string_view trace_state, | ||
const BaggageProtobufMap& baggage) const override; | ||
|
||
opentracing::expected<void> InjectSpanContext( | ||
const opentracing::TextMapWriter& carrier, | ||
const TraceContext& trace_context, opentracing::string_view trace_state, | ||
const BaggageFlatMap& baggage) const override; | ||
|
||
opentracing::expected<bool> ExtractSpanContext( | ||
const opentracing::TextMapReader& carrier, bool case_sensitive, | ||
TraceContext& trace_context, std::string& trace_state, | ||
BaggageProtobufMap& baggage) const override; | ||
|
||
private: | ||
opentracing::expected<void> InjectSpanContextImpl( | ||
const opentracing::TextMapWriter& carrier, | ||
const TraceContext& trace_context) const; | ||
|
||
template <class KeyCompare> | ||
opentracing::expected<bool> ExtractSpanContextImpl( | ||
const opentracing::TextMapReader& carrier, TraceContext& trace_context, | ||
const KeyCompare& key_compare, BaggageProtobufMap& baggage) const; | ||
|
||
opentracing::expected<void> ParseCloudTrace( | ||
opentracing::string_view s, lightstep::TraceContext& trace_context) const noexcept; | ||
|
||
size_t SerializeCloudTrace(const TraceContext& trace_context, | ||
char* s) const noexcept; | ||
}; | ||
} // namespace lightstep |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.