Skip to content

Add EventGrid distributed tracing#15850

Merged
YijunXieMS merged 10 commits intoAzure:masterfrom
YijunXieMS:eg_tracing
Oct 2, 2020
Merged

Add EventGrid distributed tracing#15850
YijunXieMS merged 10 commits intoAzure:masterfrom
YijunXieMS:eg_tracing

Conversation

@YijunXieMS
Copy link
Contributor

  1. Add distributed tracing to EventGridEvent, CloudEvent and system events.
  2. For CloudEvent, If the tracestate/traceparent are not populated in the event, then we want to copy the traceparent/tracestate into the CloudEvent extensions. Closes Distributed Tracing in EventGrid #14851
  3. Fixed NullPointerException bug for CloudEvent.getExtensionAttributes() and addExtensionAttributes().
  4. Update version number data type from Integer to Long for two classes AcsChatMessageEventBaseProperties and AcsChatThreadEventBaseProperties because the swagger file is changed. Closes Make EventGrid ACS chat events "version" property as Long #15848

@YijunXieMS YijunXieMS added Event Grid Client This issue points to a problem in the data-plane of the library. labels Oct 1, 2020
@YijunXieMS YijunXieMS added this to the [2020] October milestone Oct 1, 2020
@YijunXieMS YijunXieMS self-assigned this Oct 1, 2020
@YijunXieMS YijunXieMS requested a review from samvaity October 1, 2020 00:47
.collectList()
.flatMap(list -> this.impl.publishCloudEventEventsAsync(this.hostname, list, context));
.flatMap(list -> this.impl.publishCloudEventEventsAsync(this.hostname, list,
context.addData(AZ_TRACING_NAMESPACE_KEY, Constants.EVENT_GRID_TRACING_NAMESPACE_VALUE)));
Copy link
Member

Choose a reason for hiding this comment

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

Make sure to check context for null on the calling function to avoid NPE when doing addData

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 withContext guarantee context to be not null?

Copy link
Member

Choose a reason for hiding this comment

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

In some cases, we end up calling this from the sync client and hence the context could be null. Need a check there when passing.

Comment on lines 185 to 186
event.addExtensionAttribute(Constants.TRACE_PARENT, Constants.TRACE_PARENT_PLACEHOLDER);
event.addExtensionAttribute(Constants.TRACE_STATE, Constants.TRACE_STATE_PLACEHOLDER);
Copy link
Member

Choose a reason for hiding this comment

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

Do we need both?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I put the two placeholder separately. After placeholder replacement, whatever in the request headers will be put into the body eventually. There won't be two in the header has just one.

Comment on lines 39 to 40
// Please see <a href=https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/azure-services-resource-providers>here</a>
// for more information on Azure resource provider namespaces.
Copy link
Member

Choose a reason for hiding this comment

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

Not sure how this resource provide namespace link is relevant to the constructor.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's for a constant, which is copied to Constants.java but I didn't copy this together. Good catch.

.collectList()
.flatMap(list -> this.impl.publishEventsAsync(this.hostname, list, context));
.flatMap(list -> this.impl.publishEventsAsync(this.hostname,
list, context.addData(AZ_TRACING_NAMESPACE_KEY, Constants.EVENT_GRID_TRACING_NAMESPACE_VALUE)));
Copy link
Member

Choose a reason for hiding this comment

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

Should have a null check for context before using it.

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 internal api is called by a public API, which calls FluxUtil.withContext to create a Context. So I assume the context won't be null.
In debugging, I see it's an empty Context instance instead of null.

Copy link
Member

Choose a reason for hiding this comment

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

@YijunXieMS - this method is also called from sync client and the user can pass a null context.

User can call sendEventsWithResponse(events, null)

    public Response<Void> sendEventsWithResponse(Iterable<EventGridEvent> events, Context context) {
        return asyncClient.sendEventsWithResponse(events, context).block();
    }


private void addCloudEventTracePlaceHolder(Iterable<CloudEvent> events) {
if (TracerProxy.isTracingEnabled()) {
for (CloudEvent event : events) {
Copy link
Member

Choose a reason for hiding this comment

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

events can be null since the public APIs don't seem to check. It might be better to have the null check and include an error message to indicate that events cannot be null.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added null check like in EventHubs

import java.nio.charset.StandardCharsets;


public class CloudEventTracingPipelinePolicy implements HttpPipelinePolicy {
Copy link
Member

Choose a reason for hiding this comment

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

Add javadoc

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added

}

static String replaceTracingPlaceHolder(HttpRequest request, ByteBuffer byteBuffer) {
String bodyString = new String(byteBuffer.array(), StandardCharsets.UTF_8);
Copy link
Member

@srnagar srnagar Oct 1, 2020

Choose a reason for hiding this comment

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

Can the Flux stream have strings that are split across multiple ByteBuffer boundaries?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to use a StringBuilder to take everything from the Flux. Good question.

String bodyString = new String(byteBuffer.array(), StandardCharsets.UTF_8);
final HttpHeader traceparentHeader = request.getHeaders().get(Constants.TRACE_PARENT);
final HttpHeader tracestateHeader = request.getHeaders().get(Constants.TRACE_STATE);
bodyString = bodyString.replace(Constants.TRACE_PARENT_REPLACE,
Copy link
Member

Choose a reason for hiding this comment

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

It is not very clear why we are replacing the trace names. It might be good to add some documentation for this method.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added Javadoc and some comments.

.collectList()
.flatMap(list -> this.impl.publishEventsAsync(this.hostname, list, context));
.flatMap(list -> this.impl.publishEventsAsync(this.hostname,
list, context.addData(AZ_TRACING_NAMESPACE_KEY, Constants.EVENT_GRID_TRACING_NAMESPACE_VALUE)));
Copy link
Member

Choose a reason for hiding this comment

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

@YijunXieMS - this method is also called from sync client and the user can pass a null context.

User can call sendEventsWithResponse(events, null)

    public Response<Void> sendEventsWithResponse(Iterable<EventGridEvent> events, Context context) {
        return asyncClient.sendEventsWithResponse(events, context).block();
    }

.collectList()
.flatMap(list -> this.impl.publishEventsWithResponseAsync(this.hostname, list, context));
.flatMap(list -> this.impl.publishEventsWithResponseAsync(this.hostname, list,
context.addData(AZ_TRACING_NAMESPACE_KEY, Constants.EVENT_GRID_TRACING_NAMESPACE_VALUE)));
Copy link
Member

Choose a reason for hiding this comment

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

I think my comment about user passing null for context applies to this method.

Copy link
Member

@samvaity samvaity left a comment

Choose a reason for hiding this comment

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

👍

@YijunXieMS
Copy link
Contributor Author

/azp run java - eventgrid - tests

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@YijunXieMS YijunXieMS merged commit eaf0db9 into Azure:master Oct 2, 2020
@YijunXieMS YijunXieMS deleted the eg_tracing branch October 2, 2020 03:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Client This issue points to a problem in the data-plane of the library. Event Grid

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make EventGrid ACS chat events "version" property as Long Distributed Tracing in EventGrid

3 participants