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

Fill up C++ sections #2

Merged
merged 2 commits into from
Jan 18, 2024
Merged
Changes from all commits
Commits
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
163 changes: 118 additions & 45 deletions A72-open-telemetry-tracing.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
A72: OpenTelemetry Tracing
----
* Author(s): [Yifei Zhuang](https://github.com/YifeiZhuang)
* Author(s): [Yifei Zhuang](https://github.com/YifeiZhuang), [Yash Tibrewal](https://github.com/yashykt)
* Approver: [Eric Anderson](https://github.com/ejona86)
* Reviewers: [Mark Roth](https://github.com/markdroth), [Doug Fawley](https://github.com/dfawley),
[Feng Li](https://github.com/fengli79)
* Status: Ready for Implementation
* Implemented in: <language, ...>
* Last updated: 2023-07
* Last updated: 2024-01
* Discussion at: https://groups.google.com/g/grpc-io/c/e_ByaRmtJak

## Abstract
Expand Down Expand Up @@ -274,47 +274,122 @@ optimized path for the same reason. Similarly, the normal `get()` method handles
both binary headers and TextMap propagators.

#### Context Propagation APIs in C++
C++ will also support propagator APIs to provides API
uniformity among languages, as well as getting all the benefits of propagator APIs
mentioned before. Due to the language restriction, C++ can not take the optimization
path to workaround lacking the binary propagator API. That means using propagators
API with C++ needs base64 encoding and therefore is slower compared with just
using metadata API.

TODO: add pseudocode here in C++ for `GrpcTraceBinPropagator`,`GrpcTextMapCarrier`.
C++ will also support propagator APIs to provides API uniformity among
languages. Since gRPC C++ avoids RTTI, it can not use the same optimization path
as Java/Go. This will result in an extra base64 encoding/decoding step to
satisfy `TextMapPropagator` requirement that the key/value pair be a valid HTTP
field. There are possible optimizations C++ might pursue in the future, for
example, providing an explicit knob on `GrpcTraceBinTextMapPropagator` that
assumes that this propagator is being used with gRPC and can hence skirt `TextMapPropagator` compatibility requirements.

```C++
class GrpcTraceBinPropagator : public TextMapPropagator {
public:
void Inject(TextMapCarrier &carrier, const context::Context &context) {
// Slow path for C++. gRPC C++ does not have runtime type inspection, so we
// encode bytes to String to comply with the TextMapSetter API. This code
// path is also used in the situation where GrpcTraceBinPropagator
// is used with a TextMapSetter externally.
// TODO: add implementation
}
context::Context Extract(const TextMapCarrier &carrier, context::Context &context) {
// TODO: add implementaiton
}
}
std::unique_ptr<opentelemetry::context::TextMapCarrier>
MakeGrpcTraceBinTextMapPropagator();
```

The following shows a sketch on what the internal implementation details of this API would look within gRPC C++/Core.

```C++
class GrpcTextMapCarrier : public TextMapCarrier {
public:

namespace grpc {
namespace internal {

class GrpcTraceBinTextMapPropagator
: public opentelemetry::context::TextMapPropagator {
public:
void Inject(opentelemetry::context::TextMapCarrier& carrier,
const opentelemetry::context::Context& context) {
auto span_context = opentelemetry::trace::GetSpan(context)->GetContext();
if (!span_context.IsValid()) {
return;
}
carrier.Set(
"grpc-trace-bin",
absl::Base64Escape(
absl::string_view(SpanContextToGrpcTraceBinHeader(span_context))
.data()),
kGrpcTraceBinHeaderLen);
}

context::Context Extract(const context::propagation::TextMapCarrier& carrier,
opentelemetry::context::Context& context) {
return trace::SetSpan(
context, nostd::shared_ptr<Span> sp(new DefaultSpan(
GrpcTraceBinHeaderToSpanContext(absl::Base64Unescape(
carrier.Get("grpc-trace-bin"))))));
}

private:
constexpr int kGrpcTraceBinHeaderLen = 29;

std::array<uint8_t, kGrpcTraceBinHeaderLen> SpanContextToGrpcTraceBinHeader(
const opentelemetry::trace::SpanContext& ctx) {
std::array<uint8_t, kGrpcTraceBinHeaderLen> header;
header[0] = 0;
header[1] = 0;
ctx.trace_id().CopyBytesTo(&header[2], 16);
header[18] = 1;
ctx.span_id().CopyBytesTo(&header[19], 8);
header[27] = 2;
header[28] = ctx.trace_flags().flags();
return header;
}

opentelemetry::trace::SpanContext GrpcTraceBinHeaderToSpanContext(
nostd::string_view header) {
if (header.size() != kGrpcTraceBinHeaderLen || header[0] != 0 ||
header[1] != 0 || header[18] != 1 || header[27] != 2) {
return SpanContext::GetInvalid();
}
return SpanContext(TraceId(&header[2], 16), SpanId(&header[19], 8),
TraceFlags(header[28]), /*is_remote*/ true);
}
};

class GrpcTextMapCarrier : public opentelemetry::context::TextMapCarrier {
public:
GrpcTextMapCarrier(grpc_metadata_batch* metadata) : metadata_(metadata) {}

nostd::string_view Get(nostd::string_view key) {
// TODO: add implementation
if (key == "grpc-trace-bin") {
return absl::Base64Escape(metadata_->GetStringValue(key).value_or(""));
} else if (absl::EndsWith(key, "-bin")) {
// It's unclear how we want to handle other headers that end with "-bin".
// Return an empty string for now.
return "";
}
return metadata_->GetStringValue(key);
}

void Set(nostd::string_view key, nostd::string_view value) {
// TODO: add implementation
if (key == "grpc-trace-bin") {
metadata_->Set(
grpc_core::GrpcTraceBinMetadata(),
grpc_core::Slice::FromCopiedString(absl::Base64Unescape(value)));
} else if (absl::EndsWith(key, "-bin")) {
// It's unclear how we want to handle other headers that end with "-bin".
// Do nothing for now.
return;
} else {
// A propagator other than GrpcTraceBinTextMapPropagator was used.
metadata_->Append(key, grpc_core::Slice::FromCopiedString(value));
}
}
}
```

The `GrpcTextMapCarrier.set()` and `GrpcTextMapCarrier.get()` method in C++
should handle both binary (`-bin`) header
(e.g. `grpc-trace-bin`) and ASCII header from other TextMap
propagators that users configure into gRPC OpenTelemetry, e.g. W3C.
private:
grpc_metadata_batch* metadata_;
};

} // namespace internal

std::unique_ptr<opentelemetry::context::TextMapCarrier>
MakeGrpcTraceBinTextMapPropagator() {
return std::make_unique<internal::GrpcTraceBinTextMapPropagator>();
}

} // namespace grpc

```

### gRPC OpenTelemetry Tracing API
This section talks about enabling and configuring OpenTelemetry tracing.
Expand Down Expand Up @@ -364,22 +439,20 @@ GlobalInterceptors.setInterceptors(
```

#### C++
In C++, we will add a new method in `OpenTelemetryPluginBuilder`, see [gRPC A66][A66].
The following new methods will be added in `OpenTelemetryPluginBuilder`.

```C++
class OpenTelemetryPluginBuilder {
public:
OpenTelemetryPluginBuilder();
// If `SetMeterProvider()` is not called, no metrics are collected.
OpenTelemetryPluginBuilder& SetMeterProvider(
std::shared_ptr<opentelemetry::metrics::MeterProvider> meter_provider);
+ // Set one or multiple propagators for span context propagation, e.g.
+ // GrpcTraceBinPropagator or community standard ones like W3C, etc.
+ OpenTelemetryPluginBuilder& SetPropagator(
+ std::shared_ptr<opentelemetry::context::propagation::TextMapPropagator>
+ new grpc::GrpcTraceBinPropagator());
...
}
// If `SetTracerProvider()` is not called, no traces are collected.
OpenTelemetryPluginBuilder& SetTracerProvider(
std::shared_ptr<opentelemetry::metrics::TracerProvider> tracer_provider);
// Set one or multiple text map propagators for span context propagation, e.g.
// GrpcTraceBinTextMapPropagator or community standard ones like W3C, etc.
OpenTelemetryPluginBuilder& SetTextMapPropagator(
std::unique_ptr<opentelemetry::context::propagation::TextMapPropagator>
text_map_propagator);
};
```

#### Go
Expand Down