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

Refactor exporter - step 3 #1083

Merged
merged 2 commits into from
Aug 15, 2020
Merged

Refactor exporter - step 3 #1083

merged 2 commits into from
Aug 15, 2020

Conversation

reyang
Copy link
Member

@reyang reyang commented Aug 15, 2020

This is a follow up PR of #1078.

Changes

  • Switched ConsoleExporter to the new path.
  • Try to get feedback about [MethodImpl(MethodImplOptions.Synchronized)].

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

  • Design discussion issue #
  • Changes in public API reviewed

@reyang reyang requested a review from a team August 15, 2020 02:02
@codecov
Copy link

codecov bot commented Aug 15, 2020

Codecov Report

Merging #1083 into master will decrease coverage by 0.07%.
The diff coverage is 0.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1083      +/-   ##
==========================================
- Coverage   76.66%   76.59%   -0.08%     
==========================================
  Files         223      224       +1     
  Lines        6158     6165       +7     
==========================================
+ Hits         4721     4722       +1     
- Misses       1437     1443       +6     
Impacted Files Coverage Δ
src/OpenTelemetry/Trace/ActivityExporterSync.cs 0.00% <ø> (ø)
...elemetry/Trace/ReentrantExportActivityProcessor.cs 0.00% <0.00%> (ø)
...enTelemetry/Trace/SimpleExportActivityProcessor.cs 0.00% <0.00%> (ø)
...us/Implementation/PrometheusExporterEventSource.cs 72.72% <0.00%> (+9.09%) ⬆️

@@ -46,9 +47,10 @@ public ConsoleExporter(ConsoleExporterOptions options)
this.serializerOptions.Converters.Add(new ActivityTraceIdConverter());
}

public override Task<ExportResult> ExportAsync(IEnumerable<Activity> activityBatch, CancellationToken cancellationToken)
[MethodImpl(MethodImplOptions.Synchronized)]
Copy link
Member

Choose a reason for hiding this comment

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

I didn't even notice this until I read the description. My initial reaction... feels a little hackish. We shouldn't rely on users to add this, we should wrap the call in a lock if we want to make sure it isn't called concurrently? The spec says something about Export shouldn't be called concurrently, it doesn't say Exporters should implement Export so it isn't callable concurrently, which is what this feels like. 🤷

Copy link
Member Author

Choose a reason for hiding this comment

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

Or how about having the SimpleExportActivityProcessor taking a parameter which allows people to specify whether it is reentrant or not (and by default use lock), I was thinking about ETW/LTTng scenario where folks want ultimate concurrency.

Something like this.

Copy link
Member

Choose a reason for hiding this comment

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

I like the idea of a flag to opt into different behavior than what the spec says. We could also have a SimpleProcessor and a BatchingProcessor that are fully spec-compliant but also ship something like a ConcurrentProcessor or ReentrantProcessor that can be explicit in its changing of the rules?

Copy link
Member Author

Choose a reason for hiding this comment

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

That's works, too! 😄

Copy link
Member Author

Choose a reason for hiding this comment

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

I moved the current logic to ReentrantExportActivityProcessor, and changed SimpleExportActivityProcessor to simply call the reentrant one with a lock guard.

Copy link
Member Author

Choose a reason for hiding this comment

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

Now the PR got merged and OOP fans are staring at us - "Why are you guys making a non-reentrant class a child of reentrant one" 😂

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 a bit odd, isn't it? I know you were shooting for code re-use, maybe the flag/option idea would be better? You could make a base class that has everything but the OnEnd part?

Copy link
Member Author

Choose a reason for hiding this comment

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

Tracked by #898.

{
private readonly ActivityExporterSync exporter;
private bool stopped;
private readonly object lck = new object();
Copy link
Member

Choose a reason for hiding this comment

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

nit: Looks like "ick" 😄 Probably syncObject or lockObject is more common?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not a C# developer, borrowed/learned this from @cijothomas 😺

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

:D Thanks for fixing the names throughout.

@CodeBlanch CodeBlanch merged commit 20bf5c9 into master Aug 15, 2020
@CodeBlanch CodeBlanch deleted the reyang/exporter branch August 15, 2020 04:31
@reyang reyang mentioned this pull request Aug 15, 2020
2 tasks
/// </summary>
/// <param name="disposing"><see langword="true"/> to release both managed and unmanaged resources; <see langword="false"/> to release only unmanaged resources.</param>
protected override void Dispose(bool disposing)
{
Copy link
Member

Choose a reason for hiding this comment

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

@reyang Just noticed you're not calling Shutdown from Dispose. You did that on purpose, right?

You know, TracerProviderSdk doesn't seem to call Shutdown on anything, only Dispose. Why don't we just remove Shutdown methods across the board? I know the spec says we need it, but we have Dispose pattern in .NET for shutdown. Breaking with the spec here (in name only) might actually lead to a simpler, more easy-to-use & implement library?

Copy link
Member Author

Choose a reason for hiding this comment

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

Tracked by #1024.

Yep, I think Dispose is essentially the language idiomatic version of Shutdown. Dispose doesn't take any parameter, Shutdown might potentially take a timeout value, and that can be engineered as a property of the object instead of an argument to the function.

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.

3 participants