Skip to content

Conversation

@ishg
Copy link
Contributor

@ishg ishg commented Mar 11, 2021

Adding support for Envoy Propagator, i.e. injecting Span context as a binary string under a single x-ot-span-context header. This is required for applications making requests to services behind Istio. Istio currently uses the envoy propagator which defaults to looking for this header as an incoming value to decode existence of trace.

cc: @austinlparker

@ishg ishg requested review from mwear and obecny March 11, 2021 19:55

const CARRIER_ENVOY_HEADER_KEY = 'x-ot-span-context';

const BINARY_PROTO = {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure if this should be in here like this. I tried using a local file but it doesn't get generated with webpack. Any tips or recommendations for proto?

Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure if this should be in here like this. I tried using a local file but it doesn't get generated with webpack. Any tips or recommendations for proto?

I think we should generate the lightstep.proto in the same way that we generate the collector.proto. The resulting file would end up in the src/imp/generated_proto directory. See the Makefile.

If we do that, we can probably avoid the dependency on protobufjs since we already use google-protobuf.

this._propagators[this._opentracing.FORMAT_HTTP_HEADERS] = new LightStepPropagator(this);
this._propagators[this._opentracing.FORMAT_TEXT_MAP] = new LightStepPropagator(this);
this._propagators[this._opentracing.FORMAT_BINARY] = new UnsupportedPropagator(this,
this._propagators[this._opentracing.FORMAT_BINARY] = new LightStepPropagator(this,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does it make sense to have the LightstepPropagator now have a default for FORMAT_BINARY?

Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like go uses the BinaryPropagator by default: https://github.com/lightstep/lightstep-tracer-go/blob/master/tracer.go#L180. I think that corresponds to the EnvoyPropagator from this PR.

I think this makes sense, but have we thought about how this will work with or impact the no-protobuf version of this library?

Copy link
Contributor

Choose a reason for hiding this comment

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

FORMAT_BINARY should correspond to the binary propagator. BinaryPropagator/EnvoyPropagator/whatever are all the same.

Theoretically this shouldn't impact the no-pb version (as FORMAT_BINARY should map to UnsupportedPropagator correctly over there)

});

it("should propagate binary carriers");
it('should propagate binary carriers', () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the modified test in here, the rest of the changes were just formatting based on es-lint.

Copy link
Contributor

@mwear mwear left a comment

Choose a reason for hiding this comment

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

I am not super familiar with the lightstep binary format, so perhaps @austinlparker can weigh in to confirm or correct some of my feedback in this review. I made a pass through this and have provided some suggestions on how I think this should be done though.


const CARRIER_ENVOY_HEADER_KEY = 'x-ot-span-context';

const BINARY_PROTO = {
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure if this should be in here like this. I tried using a local file but it doesn't get generated with webpack. Any tips or recommendations for proto?

I think we should generate the lightstep.proto in the same way that we generate the collector.proto. The resulting file would end up in the src/imp/generated_proto directory. See the Makefile.

If we do that, we can probably avoid the dependency on protobufjs since we already use google-protobuf.

let msg = binaryCarrier.create(payload);
let buffer = binaryCarrier.encode(msg).finish();
let bufferString = pb.util.base64.encode(buffer, 0, buffer.length);
carrier[this._envoyHeaderKey] = bufferString;
Copy link
Contributor

Choose a reason for hiding this comment

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

I could be mistaken, but for binary, isn't the carrier just a byte array? If so, I don't think there is a notion of a string key, with a binary value. I think it just writes bytes into the array.

Copy link
Contributor

Choose a reason for hiding this comment

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

it still needs a key in the headers, and you still need to base64 the output. maybe this would be one-step with google protos?

keep in mind that adding another proto will cause the tracer file size to creep up again, to your above point

Copy link
Contributor

Choose a reason for hiding this comment

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

Do any of the other Lightstep tracers have an EnvoyPropagator? As I look around I only see BinaryPropagator (this is true for Go and Python anyway).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

C++ has one too that just uses the binary propagator to do the encoding but then puts it in the envoy key header.

Copy link
Contributor

Choose a reason for hiding this comment

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

I was thinking that we should probably try to do the same. Would it be possible to split to this work into a BinaryPropagator and an Envoy propagator (or instrumentation) that uses it to do the header manipulation?

let traceGUID = null;
let sampled = true;

if (carrier[this._envoyHeaderKey] === undefined) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe the same comment for inject about the carrier being a byte array applies here as well.

this._propagators[this._opentracing.FORMAT_HTTP_HEADERS] = new LightStepPropagator(this);
this._propagators[this._opentracing.FORMAT_TEXT_MAP] = new LightStepPropagator(this);
this._propagators[this._opentracing.FORMAT_BINARY] = new UnsupportedPropagator(this,
this._propagators[this._opentracing.FORMAT_BINARY] = new LightStepPropagator(this,
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like go uses the BinaryPropagator by default: https://github.com/lightstep/lightstep-tracer-go/blob/master/tracer.go#L180. I think that corresponds to the EnvoyPropagator from this PR.

I think this makes sense, but have we thought about how this will work with or impact the no-protobuf version of this library?

@@ -0,0 +1,11 @@
// Underscore.js-like wrapper to left pad a string to a certain length with a character
export default function _leftpad(str, len, ch) {
Copy link
Contributor

Choose a reason for hiding this comment

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

is this going to be used in node.js only ? , if so then use String.prototype.repeat instead

var span = Tracer.startSpan('my_span');
var spanContext = span.context();
it('should propagate text map carriers', () => {
let span = Tracer.startSpan('my_span');
Copy link
Contributor

Choose a reason for hiding this comment

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

why let, instead of const ?

var span = Tracer.startSpan('my_span');
var spanContext = span.context();
it('should propagate http header carriers', () => {
let span = Tracer.startSpan('my_span');
Copy link
Contributor

Choose a reason for hiding this comment

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

let -> const

Tracer._propagators[Tracer._opentracing.FORMAT_HTTP_HEADERS] = new lightstep.B3Propagator(Tracer);
var span = Tracer.startSpan('my_span');
var spanContext = span.context();
let span = Tracer.startSpan('my_span');
Copy link
Contributor

Choose a reason for hiding this comment

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

let -> const

expect(carrier['ot-baggage-creditcard']).to.equal('visa');

var extractedContext = Tracer.extract(opentracing.FORMAT_HTTP_HEADERS, carrier);
let extractedContext = Tracer.extract(opentracing.FORMAT_HTTP_HEADERS, carrier);
Copy link
Contributor

Choose a reason for hiding this comment

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

let -> const

};

var context = Tracer.extract(opentracing.FORMAT_HTTP_HEADERS, headers);
let context = Tracer.extract(opentracing.FORMAT_HTTP_HEADERS, headers);
Copy link
Contributor

Choose a reason for hiding this comment

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

let -> const

};

var context = Tracer.extract(opentracing.FORMAT_HTTP_HEADERS, headers);
let context = Tracer.extract(opentracing.FORMAT_HTTP_HEADERS, headers);
Copy link
Contributor

Choose a reason for hiding this comment

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

let -> const

it('should propagate binary carriers', () => {
Tracer._propagators[Tracer._opentracing.FORMAT_BINARY] = new lightstep.EnvoyPropagator(Tracer);

let carrier = {};
Copy link
Contributor

Choose a reason for hiding this comment

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

let -> const

var span = Tracer.startSpan('test');
describe('Tracer#flush', () => {
it('supports passing no arguments', () => {
let span = Tracer.startSpan('test');
Copy link
Contributor

Choose a reason for hiding this comment

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

let -> const

it("supports passing a callback argument", function(done) {
var span = Tracer.startSpan('test');
it('supports passing a callback argument', (done) => {
let span = Tracer.startSpan('test');
Copy link
Contributor

Choose a reason for hiding this comment

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

let -> const

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants