-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
tracing: general tracing support #16049
Conversation
cc @mattklein123 I think this simple design can make tracers become protocol-independent. But I don’t know if the community has any opinions? 🤔 |
Signed-off-by: wbpcode <[email protected]>
e328a9f
to
d78258e
Compare
Signed-off-by: wbpcode <[email protected]>
Signed-off-by: wbpcode <[email protected]>
Signed-off-by: wbpcode <[email protected]>
Signed-off-by: wbpcode <[email protected]>
Signed-off-by: wbpcode <[email protected]>
It's ready for a first review. @mattklein123 If necessary, I can split this PR into multiple PRs, which can reduce the complexity of review. 😄 |
Anyone from @envoyproxy/first-pass-reviewers want to take this? At a quick glance it is in right direction. |
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.
Basically this looks very good to me. Just couple of things to clarify.
|
||
/** | ||
* The way how to apply the custom tag to the span, | ||
* generally obtain the tag value from the context and attached it to the span. |
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.
Should it be "generally obtains the tag value from the context and attaches it to the span"?
@@ -317,12 +317,12 @@ RequestHeaderCustomTag::RequestHeaderCustomTag( | |||
default_value_(request_header.default_value()) {} | |||
|
|||
absl::string_view RequestHeaderCustomTag::value(const CustomTagContext& ctx) const { | |||
if (!ctx.request_headers) { | |||
if (!ctx.tracing_context) { |
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.
Better make it more explicit
if (ctx.tracing_context != nullptr) {
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.
Get it.
@@ -365,7 +365,11 @@ void MetadataCustomTag::apply(Span& span, const CustomTagContext& ctx) const { | |||
|
|||
const envoy::config::core::v3::Metadata* | |||
MetadataCustomTag::metadata(const CustomTagContext& ctx) const { | |||
const StreamInfo::StreamInfo& info = ctx.stream_info; | |||
if (!ctx.stream_info) { |
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.
and here
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.
👌
private: | ||
DriverPtr driver_; | ||
DriverSharedPtr driver_; |
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.
Whom the driver is shared with? I wonder if collective ownership is needed here.
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.
Yep. The factory will keep a shared_ptr of OpenCensus driver to ensure its uniqueness. This is a long-standing problem and I hope it can be resolved in the future.
/**
* Create a particular tracer driver implementation. If the implementation is unable to produce
* an tracer driver with the provided parameters, it should throw an EnvoyException in the case
* of general error or a Json::Exception if the json configuration is erroneous. The returned
* pointer should always be valid.
*
* NOTE: Due to the corner case of OpenCensus, who can only support a single tracing
* configuration per entire process, the returned Driver instance is not guaranteed
* to be unique.
* That is why the return type has been changed to std::shared_ptr<> instead of a more
* idiomatic std::unique_ptr<>.
*
* @param config supplies the proto configuration for the HttpTracer
* @param context supplies the factory context
*/
virtual Tracing::DriverSharedPtr createTracerDriver(const Protobuf::Message& config,
TracerFactoryContext& context) PURE;
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 see. Thanks!
@rojkov Thank you very much for your kind review comments. I will update this PR this weekend. 😃 |
message TracerProvider { | ||
// The name of the trace driver to instantiate. The name must match a supported trace driver. | ||
// See the :ref:`extensions listed in typed_config below <extension_category_envoy.tracers>` for the | ||
// default list of the trace driver. |
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.
In other places I see "tracing driver", "tracer driver" in addition to "trace driver" used interchangeably. Can we stick to a single term?
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.
👍
* protocol requests and provides Tracer Driver with common methods for obtaining and setting the | ||
* Tracing context. | ||
*/ | ||
class TracingContext { |
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.
Better rename the file to tracing_context.h
to reflect its content.
source/common/http/header_map_impl.h
Outdated
@@ -322,7 +322,8 @@ class HeaderMapImpl : NonCopyable { | |||
HeaderEntryImpl& maybeCreateInline(HeaderEntryImpl** entry, const LowerCaseString& key); | |||
HeaderEntryImpl& maybeCreateInline(HeaderEntryImpl** entry, const LowerCaseString& key, | |||
HeaderString&& value); | |||
HeaderMap::NonConstGetResult getExisting(const LowerCaseString& key); | |||
HeaderMap::NonConstGetResult getExisting(const absl::string_view key); |
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.
Here we change the function's contract by adding a new implicit requirement for a caller that key
must be lower case. Can we guarantee that or we don't care about casing now?
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.
getExisting(const absl::string_view key)
is a protected method that be used by get(const LowerCaseString& key)
and getTracingContext(const absl::string_view key)
.
The former is the interface of HeaderMap and can always keep the case constraint. The latter is the interface of TracingContext, which is designed to not care about the case of the key.
When developers use TracingContext based on RequestHeaderMapImpl, they should ensure that the key meets the requirements of RequestHeaderMap (key must be lowercase).
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.
@rojkov In the design of TracingContext, I hope it is completely protocol-independent, so a simple string_view is used as the key type.
But in actual use, the combination of TracingContext and HeaderMap is not perfect.
In getTracingContext, I must assume that the content of key is a lowercase string. In setTracingContext, I must create a LowCaseString copy of the key.
I am thinking about whether I can directly move LowCaseString to common, and then TracingContext directly uses LowCaseString as the key type.
But I am still struggling with it. Maybe the community can give some opinions. 🤔
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 don't have much experience with non-HTTP tracers and don't know if it's practical to convert to LowerCaseString always :( Will defer to the code owners to decide.
private: | ||
DriverPtr driver_; | ||
DriverSharedPtr driver_; |
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 see. Thanks!
Signed-off-by: wbpcode <[email protected]>
Signed-off-by: wbpcode <[email protected]>
…xt for case-insensitive key Signed-off-by: wbpcode <[email protected]>
Signed-off-by: wbpcode <[email protected]>
// Used by ASSERTs to validate internal consistency. E.g. valid HTTP header keys/values should | ||
// never contain embedded NULLs. | ||
static inline bool validHeaderString(absl::string_view s) { | ||
// If you modify this list of illegal embedded characters you will probably |
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.
drive-by comment: This is HTTP-specific and I think should under an http/ directory rather than under common.
I think I see why you wanted to do this: you wanted to add similar support for tracing that is not dependent on http, but then I think you would want to make the validator be pluggable or something, maybe via a template?
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.😄 Yes, I want add some similar support for tracing. A simple function pointer may be a good choice. Templates or virtual functions will introduce some type conversion problems, which is completely unnecessary.
The validation logic of validHeaderString should be universal, that is, it does not contain newline characters and does not contain null. We can use it as the default validator.
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'm not understanding why templates would create type conversion problems. But if you are going to use a function pointer you should use a new-style lambda.
Also you probably want to avoid having include/envoy/common/... reference include/envoy/http/... -- at least in my mind that should be a directed graph.
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'm not understanding why templates would create type conversion problems. But if you are going to use a function pointer you should use a new-style lambda.
Don't care, I should be wrong in my thinking.
Also you probably want to avoid having include/envoy/common/... reference include/envoy/http/... -- at least in my mind that should be a directed graph.
🤔 I was thinking too. Perhaps we can simply treat validHeaderString as a general validator. It does not have any special HTTP-specific logic, just ensure that the string is an ordinary single-line string that does not contain nulls.
This part will be a new independent PR. When it's ready, I will @ you, thanks 😄 .
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.
It is based on http char-set, though, isn't it?
The use of a template, or for that matter, a function pointer, lambda, or pure virtual function call, is that you could put the generic impl into common/ and the http-specific variant in http/ and you have a clean separation.
Come to think of it, do you want to always lower-case names for non-http?
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.
@jmarantz Thank you very much for your patience and suggestions.
If I just want to get a general LowerCaseString implementation, your idea is undoubtedly correct. But this question is somewhat different.
Why I want a common LowerCaseString?
Because using RequestHeaderMapImpl to implement the setTraceContext(absl::string_view)
/getTraceContext(absl::string_view)
interface, additional overhead will be introduced. We need to convert absl::string_view to lower case and always use copy semantics. So I hope to design a general LowerCaseString and add two overloaded interfaces that use LowerCaseString to TraceContext. In this way, for existing Http Tracer users, the introduction of general tracing will not bring any additional overhead.
Why is it difficult to achieve clean separation?
If I use virtual functions or inheritance solutions, use the base class in the TraceContext interface, such as LowerCaseStringBase. Then when RequestHeaderMapImpl implements the TraceContext interface, it will involve the protocol conversion from LowerCaseStringBase to Http::LowerCaseString (I now have some new ideals to circumvent this problem).
If I use function pointers, then we must use validHeaderString as the default value, because now Http::LowerCaseString has been widely used, we need to reduce the impact on existing code. The problem of using templates is similar to that of function pointers. In other words, LowerCaseString will depend on validHeaderString.
Signed-off-by: wbpcode <[email protected]>
Signed-off-by: wbpcode <[email protected]>
absl::optional<absl::string_view> getTraceContext(const LowerCaseString& key) const override { | ||
auto result = get(key); | ||
if (!result.empty()) { | ||
return result[0]->value().getStringView(); | ||
} | ||
return absl::nullopt; | ||
} | ||
|
||
void setTraceContext(const LowerCaseString& key, absl::string_view value) override { | ||
setReferenceKey(key, 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.
We might want to just add an implicit conversion from LowerCaseString
to string_view
, so you don't need those overloads? Though we might want setTraceContext by reference or copy versions.
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.
@lizan These overloads are designed to ensure that general tracing does not impose additional performance overhead on existing http tracer users. For example, the overhead of verifying that string_view is a legitimate lower case string.
Without this overload, there is only getTraceContext(absl::string_view key), so when RequestHeaderMapImpl implements this interface, we always have to make sure that the content of the key is a lower case string.
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 agree with the sentiment that this PR needs to be split up. So if necessary, this can be continued in a new PR.
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.
In general, this PR involves many refactoring that can be split out to other PR so it would be easier to review.
This PR could be split out to four different PRs:
The first PR and fourth PR will involve a large number of file updates, but no logical changes. |
This PR is part of #16049 to support general tracing. Please check #16049 get more details. Commit Message: remove trace drivers' dependency on HttpTracerImpl Additional Description: Now all tracers (zipkin, skywalking, etc.) will depend on HttpTracerImpl, making it difficult for Tracers to be reused by other protocols (Dubbo, Thrift, etc.). The purpose of this PR is to change this dependency. Risk Level: Low (No new logic). Testing: Add. Docs Changes: N/A Release Notes: N/A Signed-off-by: wbpcode <[email protected]>
This pull request has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
/no-stale |
Signed-off-by: wbpcode <[email protected]> Sub-PR of #16049. Check #16049 get more background information. This PR designed a new generic abstraction `TraceContext` to replace `Http::RequestHeaderMap` to provide tracing context to the tracer driver. `Http::RequestHeaderMapImpl` already inherits from TraceContext and implements the relevant interfaces. Next, we just need simply replace `Http::RequestHeaderMap` with `TraceContext` in all tracer drivers implementations. After that, the main body of the entire general tracing system is completed. I'm not sure, whether the replacement step requires a separate PR. Because it does not involve any new logic, but there will be a lot of file changes. Risk Level: Low. Testing: Added. Docs Changes: N/A Release Notes: N/A Signed-off-by: wbpcode <[email protected]>
Signed-off-by: wbpcode <[email protected]> Sub-PR of envoyproxy#16049. Check envoyproxy#16049 get more background information. This PR designed a new generic abstraction `TraceContext` to replace `Http::RequestHeaderMap` to provide tracing context to the tracer driver. `Http::RequestHeaderMapImpl` already inherits from TraceContext and implements the relevant interfaces. Next, we just need simply replace `Http::RequestHeaderMap` with `TraceContext` in all tracer drivers implementations. After that, the main body of the entire general tracing system is completed. I'm not sure, whether the replacement step requires a separate PR. Because it does not involve any new logic, but there will be a lot of file changes. Risk Level: Low. Testing: Added. Docs Changes: N/A Release Notes: N/A Signed-off-by: wbpcode <[email protected]> Signed-off-by: chris.xin <[email protected]>
Sub-PR of #16049. Check #16049 get more background information. This PR is last sub-PR of #16049. It simply replaces `Http::RequestHeaderMap` with general `Tracing::TraceContext` in all tracer drivers implementations. Check #16793 get more info about `Tracing::TraceContext`. After this PR, the main body of the entire general tracing system is completed. Next, we can try to use the new general tracing system in dubbo and thrift. Commit Message: replace RequestHeaderMap in tracers with general TraceContext Risk Level: Low. Testing: N/A. Docs Changes: N/A. Release Notes: N/A. Signed-off-by: wbpcode <[email protected]>
Check #16244 #16793 #17212
**Finally, thank you @lizan for your patience and help. ** |
Signed-off-by: wbpcode <[email protected]> Sub-PR of envoyproxy#16049. Check envoyproxy#16049 get more background information. This PR designed a new generic abstraction `TraceContext` to replace `Http::RequestHeaderMap` to provide tracing context to the tracer driver. `Http::RequestHeaderMapImpl` already inherits from TraceContext and implements the relevant interfaces. Next, we just need simply replace `Http::RequestHeaderMap` with `TraceContext` in all tracer drivers implementations. After that, the main body of the entire general tracing system is completed. I'm not sure, whether the replacement step requires a separate PR. Because it does not involve any new logic, but there will be a lot of file changes. Risk Level: Low. Testing: Added. Docs Changes: N/A Release Notes: N/A Signed-off-by: wbpcode <[email protected]>
…roxy#17212) Sub-PR of envoyproxy#16049. Check envoyproxy#16049 get more background information. This PR is last sub-PR of envoyproxy#16049. It simply replaces `Http::RequestHeaderMap` with general `Tracing::TraceContext` in all tracer drivers implementations. Check envoyproxy#16793 get more info about `Tracing::TraceContext`. After this PR, the main body of the entire general tracing system is completed. Next, we can try to use the new general tracing system in dubbo and thrift. Commit Message: replace RequestHeaderMap in tracers with general TraceContext Risk Level: Low. Testing: N/A. Docs Changes: N/A. Release Notes: N/A. Signed-off-by: wbpcode <[email protected]>
Signed-off-by: wbpcode [email protected]
Commit Message: tracing: general tracing support
Additional Description:
Check: #15784
Current tracing system only has great support to HTTP protocol. Other protocol such as Dubbo Proxy or Thrift Proxy cannot reuse tracers that designed for HTTP protocol.
This PR try to separate tracer implementation and HTTP protocol to make the current tracers protocol-independent.
There are mainly two protocol depentent design in current tracing system.
Http::RequestHeaderMap
for tracing context. Tracing Driver will try to obtain tracing context from downstreamHttp::RequestHeaderMap
and create tracing span. Tracing span will inject new context toHttp::RequestHeaderMap
to transfer it to upstream.HttpTracer
rather then rawDriver
.So, this PR design a new abstract class for tracing context to replace
Http::RequestHeaderMap
(While other protocols can implement an Http::RequestHeaderMap to directly reuse the existing Tracer, this requires a significant amount of work.):And then, we update tracing driver factory to make it no deps to
HttpTracer
:All other code modifications are just to adapt to the above changes.
A more detailed doc:
https://docs.google.com/document/d/1gxk5vfHl-Gt3wiNZ-f46Dwmk2NFiEzFJQugmZmpSXk8/edit?usp=sharing
Risk Level: mid
Testing: [WIP]
Docs Changes: N/A
Release Notes: [WIP]