Skip to content
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

Merged
merged 24 commits into from
Feb 4, 2021

Conversation

lalitb
Copy link
Member

@lalitb lalitb commented Feb 1, 2021

Current tracestate api is not compliant to opentelemetry and w3c trace specs. Attempt to fix in this PR.
To Summaries the changes

#537

@lalitb lalitb requested a review from a team February 1, 2021 16:07
@codecov
Copy link

codecov bot commented Feb 1, 2021

Codecov Report

Merging #551 (77e5574) into main (74ad7b1) will increase coverage by 0.08%.
The diff coverage is 96.42%.

Impacted file tree graph

@@            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     
Impacted Files Coverage Δ
api/test/trace/trace_state_test.cc 97.79% <95.83%> (ø)
api/include/opentelemetry/trace/trace_state.h 97.54% <96.87%> (ø)
sdk/test/metrics/counter_aggregator_test.cc 98.21% <0.00%> (-1.79%) ⬇️
sdk/src/logs/batch_log_processor.cc 93.82% <0.00%> (-1.24%) ⬇️
api/include/opentelemetry/nostd/string_view.h 97.95% <0.00%> (+0.08%) ⬆️
sdk/test/common/circular_buffer_test.cc 100.00% <0.00%> (+1.04%) ⬆️

@lalitb lalitb added the area:api label Feb 1, 2021
@lalitb lalitb changed the title TraceState api implementation as per spec TraceState implementation as per spec Feb 1, 2021
Copy link
Contributor

@pyohannes pyohannes left a 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
Copy link
Contributor

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.

Copy link
Member Author

@lalitb lalitb Feb 2, 2021

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.

Copy link
Member Author

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.

Copy link
Contributor

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.

Comment on lines 326 to 327
std::regex reg_key("^[a-z0-9][a-z0-9*_\\-/]{0,255}$");
std::regex reg_key_multitenant(
Copy link
Contributor

Choose a reason for hiding this comment

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

Those can be static.

Copy link
Member Author

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.

api/include/opentelemetry/trace/trace_state.h Outdated Show resolved Hide resolved
// An empty TraceState.
TraceState() noexcept : entries_(new Entry[kMaxKeyValuePairs]), num_entries_(0) {}
/**
* Returns a newly created Tracestate parsed from the header provided.
Copy link
Contributor

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?

Copy link
Member Author

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/include/opentelemetry/trace/trace_state.h Outdated Show resolved Hide resolved
api/include/opentelemetry/trace/trace_state.h Outdated Show resolved Hide resolved
api/include/opentelemetry/trace/trace_state.h Outdated Show resolved Hide resolved
api/test/trace/trace_state_test.cc Outdated Show resolved Hide resolved
Comment on lines 140 to 141
auto ts2_new = ts2.Set("n_k1", "n_v1"); // adding to max list, should fail and return empty
EXPECT_EQ(ts2_new.ToHeader(), "");
Copy link
Contributor

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?

Copy link
Member Author

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.

Copy link
Member Author

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.

lalitb and others added 4 commits February 3, 2021 09:14
Co-authored-by: Johannes Tax <johannes@johannes.tax>
Co-authored-by: Johannes Tax <johannes@johannes.tax>
Co-authored-by: Johannes Tax <johannes@johannes.tax>
Co-authored-by: Johannes Tax <johannes@johannes.tax>
else
{
// `end` points to end of current list member
end = end - 1;
Copy link
Contributor

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 ,?

Copy link
Member Author

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.

Copy link
Contributor

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?

Copy link
Member Author

@lalitb lalitb Feb 3, 2021

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.

Copy link
Member Author

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 (??)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* @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?

Copy link
Member Author

@lalitb lalitb Feb 3, 2021

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)
Copy link
Contributor

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>?

Copy link
Member Author

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));
Copy link
Contributor

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?

Copy link
Member Author

Choose a reason for hiding this comment

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

thanks fixed.

@lalitb
Copy link
Member Author

lalitb commented Feb 4, 2021

@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 :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants