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

Suppress instrumentation in Zipkin exporter #1150

Conversation

alanwest
Copy link
Member

@alanwest alanwest commented Aug 24, 2020

Changes

We had previously discussed that it should be up to the exporter author to deal with instrumentation suppression (see: #1098 (comment)). This PR suppresses instrumentation from Zipkin.

For significant contributions please make sure you have completed the following items:

  • Design discussion issue #
  • Changes in public API reviewed

@alanwest alanwest requested a review from a team August 24, 2020 21:04
Copy link
Member

@reyang reyang left a comment

Choose a reason for hiding this comment

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

LGTM.

@alanwest
Copy link
Member Author

alanwest commented Aug 24, 2020

Cool! And I think this PR may have also highlighted a bug in the RuntimeContext stuff for the net452 test. Taking a look at this now...

There is a bug, but I think it is in the HttpWebRequest instrumentation. It has it's own ActivitySource and even though instrumentation is suppressed StartActivity returns non null.

Ah, found it. The ZipkinExportTests adds its own listener:

var listener = new ActivityListener
{
ShouldListenTo = _ => true,
GetRequestedDataUsingParentId = (ref ActivityCreationOptions<string> options) => ActivityDataRequest.AllData,
GetRequestedDataUsingContext = (ref ActivityCreationOptions<ActivityContext> options) => ActivityDataRequest.AllData,
};
ActivitySource.AddActivityListener(listener);

Ok, what I learned from this is that I think our Sdk.SuppressInstrumentation checks in ActivityListener.GetRequestedDataUsingContext is insufficient to suppress instrumentation from ActivitySource based activities. That is, if any listener responds with ActivityDataRequest.AllDataAndRecorded then ActivityStarted and ActivityStopped will fire on the listener created by the SDK. So, I think this means we should add checks in these callbacks too.

Is this the expected behavior from the .NET side? That is, if:

  • ActivityListener A says ActivityDataRequest.None, and
  • ActivityListener B says ActivityDataRequest.AllData, then
  • should A's ActivityStarted and ActivityStopped events get fired?

@cijothomas @reyang @CodeBlanch

@codecov
Copy link

codecov bot commented Aug 24, 2020

Codecov Report

Merging #1150 into master will increase coverage by 0.31%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1150      +/-   ##
==========================================
+ Coverage   77.10%   77.41%   +0.31%     
==========================================
  Files         219      219              
  Lines        6259     6253       -6     
==========================================
+ Hits         4826     4841      +15     
+ Misses       1433     1412      -21     
Impacted Files Coverage Δ
...mentation.Http/HttpClientInstrumentationOptions.cs 100.00% <ø> (ø)
...rc/OpenTelemetry.Exporter.Zipkin/ZipkinExporter.cs 87.01% <100.00%> (+0.17%) ⬆️
src/OpenTelemetry/Trace/TracerProviderSdk.cs 94.69% <100.00%> (ø)
...plementation/ZipkinActivityConversionExtensions.cs 91.20% <0.00%> (+1.09%) ⬆️
...ter.ZPages/Implementation/ZPagesActivityTracker.cs 100.00% <0.00%> (+2.85%) ⬆️
...nTelemetry/Internal/OpenTelemetrySdkEventSource.cs 80.95% <0.00%> (+3.17%) ⬆️
...penTelemetry/Trace/BatchExportActivityProcessor.cs 57.33% <0.00%> (+22.66%) ⬆️

@@ -68,7 +68,7 @@ static TracerProviderSdk()
// Callback when Activity is started.
ActivityStarted = (activity) =>
{
if (activity.IsAllDataRequested)
if (!Sdk.SuppressInstrumentation && activity.IsAllDataRequested)
Copy link
Member

Choose a reason for hiding this comment

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

we shouldn't need this as we already prevented the activity from being created in the 1st place right?

Copy link
Member Author

@alanwest alanwest Aug 25, 2020

Choose a reason for hiding this comment

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

See the info I left about this above ⬆️. Basically, if any listener says 👍, then all listeners ActivityStarted/ActivityStopped gets fired. I posed the question of whether this is the expected behavior from .NET.

Copy link
Member Author

Choose a reason for hiding this comment

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

Opened dotnet/runtime#41306 to validate whether this is expected or not.

Copy link
Member

Choose a reason for hiding this comment

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

Great find @alanwest. I seem to remember seeing some discussion about that behavior somewhere and that is the correct behavior but let's see what they say.

var zipkinExporter = new ZipkinExporter(exporterOptions);
var exportActivityProcessor = new BatchExportActivityProcessor(zipkinExporter, scheduledDelayMilliseconds: 1);

var openTelemetrySdk = Sdk.CreateTracerProviderBuilder()
Copy link
Member

Choose a reason for hiding this comment

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

@cijothomas I guess we want to use traceProvider everywhere?

Copy link
Member

Choose a reason for hiding this comment

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

yes. I'll doing mass cleanup for other places.

@reyang reyang self-requested a review August 25, 2020 00:45
@cijothomas
Copy link
Member

@alanwest sorry this got delayed and has conflict now :) PLease resolve and we are good to go.

@cijothomas cijothomas merged commit c21bd58 into open-telemetry:master Aug 25, 2020
@alanwest alanwest deleted the alanwest/zipkin-suppress-instrumentation branch August 25, 2020 17:01
@@ -44,32 +44,10 @@ public class HttpClientInstrumentationOptions
/// </summary>
public Func<HttpRequestMessage, bool> FilterFunc { get; set; }

internal static bool IsInternalUrl(Uri requestUri)
Copy link
Member

Choose a reason for hiding this comment

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

It was a long road but we finally got this removed! 🎊

internal bool EventFilter(string activityName, object arg1)
{
if (TryParseHttpRequestMessage(activityName, arg1, out HttpRequestMessage requestMessage))
{
Uri requestUri;
Copy link
Member

Choose a reason for hiding this comment

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

@cijothomas @alanwest @eddynaka We could probably improve the perf on this now by changing the order of things.

internal bool EventFilter(string activityName, object arg1)
{
   return (this.FilterFunc == null || !TryParseHttpRequestMessage(activityName, arg1, out HttpRequestMessage requestMessage))
      ? true
      : this.FilterFunc(requestMessage);
}

Maybe also add the inline hint on this & TryParseHttpRequestMessage?

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

Successfully merging this pull request may close these issues.

4 participants