-
Notifications
You must be signed in to change notification settings - Fork 438
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
TraceState implementation as per spec #551
Conversation
Codecov Report
@@ Coverage Diff @@
## main #551 +/- ##
==========================================
+ Coverage 94.32% 94.40% +0.08%
==========================================
Files 198 200 +2
Lines 8807 9067 +260
==========================================
+ Hits 8307 8560 +253
- Misses 500 507 +7
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, that looks very good! I'll give it another detailed review tomorrow.
|
||
// Returns false if no such key, otherwise returns true and populates the value parameter with the | ||
// associated value. | ||
bool Get(nostd::string_view key, nostd::string_view &value) const noexcept | ||
std::string Get(nostd::string_view key) const noexcept |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should preserve the ability to distinguish between an key not being specified and a key given but having an empty value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per w3c specs ( https://www.w3.org/TR/trace-context/#value) the value can't be empty string ( should have at-least one non-blank character ). This is validated before storing from header. But I don't have strong preference on this, we can switch back to earlier prototype if that's more clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have made comments consistent with method prototype.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. Your method signature is fine.
std::regex reg_key("^[a-z0-9][a-z0-9*_\\-/]{0,255}$"); | ||
std::regex reg_key_multitenant( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those can be static
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Fixed this now.
Co-authored-by: Johannes Tax <[email protected]>
// An empty TraceState. | ||
TraceState() noexcept : entries_(new Entry[kMaxKeyValuePairs]), num_entries_(0) {} | ||
/** | ||
* Returns a newly created Tracestate parsed from the header provided. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: change spelling of Tracestate
in this comment to TraceState
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. changed it now :)
api/test/trace/trace_state_test.cc
Outdated
auto ts2_new = ts2.Set("n_k1", "n_v1"); // adding to max list, should fail and return empty | ||
EXPECT_EQ(ts2_new.ToHeader(), ""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What consequence would this behavior have for the user?
Let's say one receives a tracestate
header with 32 entries, then adds one (this returns an empty tracestate
), and then passes on the header. If the user doesn't do explicit checks, an empty header will be passed on. I don't think that's ideal.
What do you think about Set
just returning the unaltered tracestate
when the limit is exceeded?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I didn't find anything in specs on how to address this, and different languages implementation are behaving differently ( python returns empty, JS doesn't do any check on limit, java returns reference to itself ). Said that, it make sense to return unaltered tracestate
instead of empty. I will do the change. Thanks for the comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fixed as discussed.
Co-authored-by: Johannes Tax <[email protected]>
Co-authored-by: Johannes Tax <[email protected]>
Co-authored-by: Johannes Tax <[email protected]>
Co-authored-by: Johannes Tax <[email protected]>
else | ||
{ | ||
// `end` points to end of current list member | ||
end = end - 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just --end
? Also could it get -1
if the first character is ,
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made it --end
. If would be fine if first char is ,
, as this will make control to go to below condition:
if (list_member.size() == 0)
{
// empty list member, move to next in list
begin = end + 2; // begin points to start of next member
continue;
}
and process next list member. I have added test case to validate this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the first char is ,
, then end
will be -1
, so the call to TrimString
will trigger access violation when accessing the input string, like header[static_cast<size_t>(-1)]
which happens before the empty list_member
check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you are right and bazel asan fails because of that. I am fixing it now :) Thanks for pointing out the issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, the easy solution was to add special conditional check for ,
as first char.
/** | ||
* Returns `new` TransState object after removing the attribute with given key ( if present ) | ||
* @returns empty TransState object if key is invalid | ||
* @returns copy of original TransState object if key is not present (??) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @returns copy of original TransState object if key is not present (??) | |
* @returns copy of original TraceState object if key is not present (??) |
Seems for now an empty instance is returned if the key is not present, should we return original TraceState
like mentioned in the comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for suggestion TransState
. Have changed it now as part of other changes.
Also,
empty instance is returned if the key is not present,
- As of now, as per code it return empty instance if key is not valid, and copy of original instance if key is not present.
|
||
static nostd::string_view TrimString(nostd::string_view str, size_t left, size_t right) | ||
{ | ||
while (str[(std::size_t)right] == ' ' && left < right) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: C++ style static_cast<std::size_t>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. fixed it now.
|
||
auto entry = (entries_.get())[count]; | ||
header_s.append(std::string(entry.GetKey())); | ||
header_s.append(std::string(1, kKeyValueSeparator)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to construct a temporary std::string
here, just pass kKeyValueSeparator
to std::string::append
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks fixed.
@ThomsonTan - Thanks for your review. Can we merge this PR if there are no further comments. I have a another PR dependent on these changes so the ask :) |
Current tracestate api is not compliant to
opentelemetry
andw3c trace
specs. Attempt to fix in this PR.To Summaries the changes
As per the opentelemetry specs (https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#tracestate), TraceState object is immutable, and
add
,update
anddelete
methds should return newly created object. Added/updated needed methods.Methods to serialize and de-serialize TraceState object to/from w3c trace header ( as defined here: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#tracestate)
Much accurate validation check for tracestate list members using regex in non-gcc4.8 compiler.
#537