Skip to content

Add ForceFlush to TracerProvider#1837

Merged
cijothomas merged 6 commits into
open-telemetry:mainfrom
kipwoker:forceflush-tracerprovider
Feb 23, 2021
Merged

Add ForceFlush to TracerProvider#1837
cijothomas merged 6 commits into
open-telemetry:mainfrom
kipwoker:forceflush-tracerprovider

Conversation

@kipwoker

@kipwoker kipwoker commented Feb 17, 2021

Copy link
Copy Markdown
Contributor

I'm using OpenTelemetry for AWS lambda functions. And I'm using dotnet opentelemetry library to achieve that. After each call, lambda goes to sleep and freezes background threads. Therefore I need to send activities to the exporter forcibly if I want to use the batch processor instead of the simple one.

Thankfully, BaseProcessor already contains a ForceFlush method that works perfectly in this case.

I've made a proof of concept

public static void ForceFlush(this TracerProvider tracerProvider)
{
	var tracerProviderSdkType = typeof(BaseProcessor<>).Assembly.GetType("OpenTelemetry.Trace.TracerProviderSdk");
	var tracerProviderSdk = tracerProvider.Cast(tracerProviderSdkType);
	var processorObj = tracerProviderSdk.GetFieldValue("processor");
	var processor = (BaseProcessor<Activity>) processorObj;
	processor.ForceFlush();
}

and it works as I expected. The only problem — access modifiers. This PR allows the user to trigger TracerProvider.ForceFlush without reflection. As I can see java solution has the same feature.

Related to: open-telemetry/opentelemetry-java#1068

@kipwoker kipwoker requested a review from a team February 17, 2021 09:10
@linux-foundation-easycla

linux-foundation-easycla Bot commented Feb 17, 2021

Copy link
Copy Markdown

CLA Signed

The committers are authorized under a signed CLA.

  • ✅ Kirill Ivanov (5085a32865a85f559f89d5e23830b7a86563a5f6)

@kipwoker kipwoker changed the title Added ForceFlush to TracerProvider Add ForceFlush to TracerProvider Feb 17, 2021
@utpilla

utpilla commented Feb 18, 2021

Copy link
Copy Markdown
Contributor

If you want to do a ForceFlush on your BatchExporter, you could store a reference to the BatchExportProcessor, pass it AddProcessor method when building the TracerProvider, and call ForceFlush on it when needed. You could try something like this:

var exporter = new ConsoleActivityExporter(new ConsoleExporterOptions());
var processor = new BatchActivityExportProcessor(exporter); // store a reference to the BatchExportProcessor so that you can call ForceFlush on it later on
var tracerProvider = Sdk.CreateTracerProviderBuilder()
       .SetSampler(new AlwaysOnSampler())
       .AddSource("MyCompany.MyProduct.MyLibrary")
       .AddProcessor(processor) // Pass the reference to the BatchExportProcessor here
       .Build();

// Create activities

processor.ForceFlush(); // Call ForceFlush on the BatchExportProcessor

ForceFlush is not meant for TracerProvider. According to the spec, it is only provided for Processors and is relevant only to BatchExportProcessors.

@reyang

reyang commented Feb 18, 2021

Copy link
Copy Markdown
Member

The latest link of OpenTelemetry Java SdkTracerProvider.forceFlush is here.

I guess we want to test the water if this is something that should be added in the spec?

@kipwoker

Copy link
Copy Markdown
Contributor Author

If you want to do a ForceFlush on your BatchExporter, you could store a reference to the BatchExportProcessor, pass it AddProcessor method when building the TracerProvider, and call ForceFlush on it when needed. You could try something like this:

var exporter = new ConsoleActivityExporter(new ConsoleExporterOptions());
var processor = new BatchActivityExportProcessor(exporter); // store a reference to the BatchExportProcessor so that you can call ForceFlush on it later on
var tracerProvider = Sdk.CreateTracerProviderBuilder()
       .SetSampler(new AlwaysOnSampler())
       .AddSource("MyCompany.MyProduct.MyLibrary")
       .AddProcessor(processor) // Pass the reference to the BatchExportProcessor here
       .Build();

// Create activities

processor.ForceFlush(); // Call ForceFlush on the BatchExportProcessor

ForceFlush is not meant for TracerProvider. According to the spec, it is only provided for Processors and is relevant only to BatchExportProcessors.

@utpilla I thought about this approach, but if you have a look at exporters none of them provides such a feature.
Examples:

ForceFlush is not meant for TracerProvider. According to the spec, it is only provided for Processors and is relevant only to BatchExportProcessors.

The same you can say about Shutdown method, but there is an extension TracerProviderExtensions that allows to do it, isn't it?
And, honestly, semantically ForceFlush is a "subset" of Shudown according to spec you linked:

Shutdown MUST include the effects of ForceFlush.

So my question is:
Why having Shutdown method is okay and what wrong could happen if we add ForceFlush?

@kipwoker

Copy link
Copy Markdown
Contributor Author

The latest link of OpenTelemetry Java SdkTracerProvider.forceFlush is here.

I guess we want to test the water if this is something that should be added in the spec?

@reyang thank you, fixed the link :)
I didn't get your question. What exactly you want to test? :)

@reyang

reyang commented Feb 18, 2021

Copy link
Copy Markdown
Member

I didn't get your question. What exactly you want to test? :)

If you check the issue template, it mentioned:

Before opening a feature request against this repo, consider whether the feature should/could be implemented in the other OpenTelemetry client libraries. If so, please open an issue on opentelemetry-specification first.

What I want to test: if the spec is okay to take the change and add TracerProvider.ForceFlush.

@kipwoker

Copy link
Copy Markdown
Contributor Author

Also, found the java PR. The conversation there may be useful. The author of this PR had the same issue with the lambda, so probably people will want to have something like this feature.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This could throw NullReferenceException if this.processor is null.

@reyang reyang left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The change and the rationale make sense to me.
LGTM assuming the NullReferenceException comment is resolved.

Comment thread src/OpenTelemetry/Trace/TracerProviderExtensions.cs Outdated
@reyang

reyang commented Feb 18, 2021

Copy link
Copy Markdown
Member

Consider adding a small test case just to prevent the regression.

@reyang

reyang commented Feb 18, 2021

Copy link
Copy Markdown
Member

Consider updating the CHANGELOG.

@kipwoker

Copy link
Copy Markdown
Contributor Author

@reyang thank you, good points. Everything is fixed. Please, check it's correct.

@codecov

codecov Bot commented Feb 18, 2021

Copy link
Copy Markdown

Codecov Report

Merging #1837 (9e078fe) into main (fe24768) will increase coverage by 0.91%.
The diff coverage is 67.81%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1837      +/-   ##
==========================================
+ Coverage   82.88%   83.79%   +0.91%     
==========================================
  Files         193      187       -6     
  Lines        6005     5967      -38     
==========================================
+ Hits         4977     5000      +23     
+ Misses       1028      967      -61     
Impacted Files Coverage Δ
...nTelemetry.Exporter.Jaeger/Implementation/Batch.cs 84.09% <ø> (+3.65%) ⬆️
....Exporter.Jaeger/JaegerExporterHelperExtensions.cs 15.38% <ø> (ø)
...Telemetry.Exporter.Jaeger/JaegerExporterOptions.cs 100.00% <ø> (ø)
...metryProtocol/OtlpTraceExporterHelperExtensions.cs 92.30% <ø> (ø)
....Exporter.Zipkin/ZipkinExporterHelperExtensions.cs 15.38% <ø> (ø)
...Telemetry.Exporter.Zipkin/ZipkinExporterOptions.cs 100.00% <ø> (ø)
...xporter.OpenTelemetryProtocol/OtlpTraceExporter.cs 47.22% <40.62%> (-10.23%) ⬇️
...rc/OpenTelemetry/Trace/TracerProviderExtensions.cs 32.25% <45.45%> (+7.25%) ⬆️
...rc/OpenTelemetry.Exporter.Jaeger/JaegerExporter.cs 85.00% <84.21%> (-0.27%) ⬇️
...orter.OpenTelemetryProtocol/OtlpExporterOptions.cs 100.00% <100.00%> (ø)
... and 12 more

/// Thrown when the <c>timeoutMilliseconds</c> is smaller than -1.
/// </exception>
/// <remarks>
/// This function guarantees thread-safety. Only the first call will

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

/// This function guarantees thread-safety.

The semantic is a bit different than Shutdown, ForceFlush can be called multiple times and there is no restriction on which call will win (it is a win-win situation😄).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Consider borrow the wording from

/// Flushes the processor, blocks the current thread until flush
.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Consider borrow the wording from

Thank you. Took this part and also added information about TracerProviderSdk like it was made on the Shutdown method.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks perfect to me now. :shipit:

@reyang reyang added pkg:OpenTelemetry Issues related to OpenTelemetry NuGet package enhancement New feature or request labels Feb 18, 2021
@utpilla

utpilla commented Feb 18, 2021

Copy link
Copy Markdown
Contributor

If you want to do a ForceFlush on your BatchExporter, you could store a reference to the BatchExportProcessor, pass it AddProcessor method when building the TracerProvider, and call ForceFlush on it when needed. You could try something like this:

var exporter = new ConsoleActivityExporter(new ConsoleExporterOptions());
var processor = new BatchActivityExportProcessor(exporter); // store a reference to the BatchExportProcessor so that you can call ForceFlush on it later on
var tracerProvider = Sdk.CreateTracerProviderBuilder()
       .SetSampler(new AlwaysOnSampler())
       .AddSource("MyCompany.MyProduct.MyLibrary")
       .AddProcessor(processor) // Pass the reference to the BatchExportProcessor here
       .Build();

// Create activities

processor.ForceFlush(); // Call ForceFlush on the BatchExportProcessor

ForceFlush is not meant for TracerProvider. According to the spec, it is only provided for Processors and is relevant only to BatchExportProcessors.

@utpilla I thought about this approach, but if you have a look at exporters none of them provides such a feature.
Examples:

You can achieve the same for Zipkin or Jaeger or any other exporter using the same approach:

var exporter = new JaegerExporter(new JaegerExporterOptions());
var processor = new BatchActivityExportProcessor(exporter);

.....
processor.ForceFlush();

ForceFlush is not meant for TracerProvider. According to the spec, it is only provided for Processors and is relevant only to BatchExportProcessors.

The same you can say about Shutdown method, but there is an extension TracerProviderExtensions that allows to do it, isn't it?

No the spec explicitly asks to provide a Shutdown method for TracerProvider. Here is the link to that: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#shutdown.

And, honestly, semantically ForceFlush is a "subset" of Shudown according to spec you linked:

Shutdown MUST include the effects of ForceFlush.

"Shutdown MUST include the effects of ForceFlush." is applicable to the Shutdown of Span Processors. Also, if you look at the requirements for TracerProvider Shutdown it says that: Shutdown MUST be implemented at least by invoking Shutdown within all internal processors. So, in effect, if you call the Shutdown on the TracerProvider, it will call the Shutdown on all of its processor which include the effects of a ForceFlush.

So my question is:
Why having Shutdown method is okay and what wrong could happen if we add ForceFlush?

I have just been stating why we have the TracerProvider and Processors implemented the way they are. Having said that, if we feel that we need to add ForceFlush to TracerProvider, we should go forward with it and also update the spec.

@cijothomas

Copy link
Copy Markdown
Member

@kipwoker Thanks for the PR.
Could you open an issue in the spec repo to have this requirement added to the spec itself? While the feature itself is good, we generally try to limit adding features (esp. ones require public API change), unless this is a spec requirement, or a .NET specific requirement.

In this case, this issue is not limited to .NET or Java, so please open a spec issue.
And please confirm if holding reference to processor, and calling ForceFlush() on it works for you or not.

@reyang reyang added the needs-spec-change Issues which require the OpenTelemetry Specification to clarify or define behavior label Feb 19, 2021
Comment thread test/OpenTelemetry.Tests/Trace/TracerProviderSdkTest.cs Outdated
@cijothomas cijothomas removed the needs-spec-change Issues which require the OpenTelemetry Specification to clarify or define behavior label Feb 22, 2021
@cijothomas

Copy link
Copy Markdown
Member

@kipwoker

Copy link
Copy Markdown
Contributor Author

open-telemetry/opentelemetry-specification#1452 is merged

For me, it seems done and ready to merge.
Feel free to ask if you need anything else from me related to this PR. :)

throw new ArgumentNullException(nameof(provider));
}

if (provider is TracerProviderSdk tracerProviderSdk)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This seems like a hack. There should be some public type (class or interface) representing TracerProviderSdk. But I guess it's too late for that 😃

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agree. :)
I just made it like it was done for Shutdown method. In my opinion, it's better to change nothing at the moment and make architectural changes at separate PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Lets not address any other issue in this PR :)
Happy to address them separate. (or not address :D)

Comment thread src/OpenTelemetry/CHANGELOG.md Outdated
Co-authored-by: Cijo Thomas <cithomas@microsoft.com>
@cijothomas cijothomas merged commit cb066cb into open-telemetry:main Feb 23, 2021
@kipwoker kipwoker deleted the forceflush-tracerprovider branch February 24, 2021 07:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request pkg:OpenTelemetry Issues related to OpenTelemetry NuGet package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants