-
Notifications
You must be signed in to change notification settings - Fork 773
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
PrometheusExporter: New concurrency handling for scrape middleware + http server #2610
PrometheusExporter: New concurrency handling for scrape middleware + http server #2610
Conversation
Codecov Report
@@ Coverage Diff @@
## main #2610 +/- ##
==========================================
- Coverage 80.27% 80.22% -0.06%
==========================================
Files 256 257 +1
Lines 8826 8844 +18
==========================================
+ Hits 7085 7095 +10
- Misses 1741 1749 +8
|
src/OpenTelemetry.Exporter.Prometheus/Implementation/PrometheusCollectionManager.cs
Show resolved
Hide resolved
@@ -218,5 +148,46 @@ private void WorkerProc() | |||
} | |||
} | |||
} | |||
|
|||
private async Task ProcessRequestAsync(HttpListenerContext context) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks much cleaner 👍.
src/OpenTelemetry.Exporter.Prometheus/Implementation/PrometheusCollectionManager.cs
Outdated
Show resolved
Hide resolved
Interlocked.Increment(ref this.readerCount); | ||
this.ExitGlobalLock(); | ||
#if NETCOREAPP3_1_OR_GREATER | ||
return new ValueTask<ArraySegment<byte>>(this.previousDataView); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: for troubleshooting purposes, i think it'd be good to add some logging to indicate whether we re-used previous view, or triggered new collection.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or maybe use the Last-Modified
response header. I think we should exclude the change from this PR (to keep it small).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK I was working on a log message but I'll hold off and do this as a follow-up. I like the idea of using the header.
|
||
for (var i = 0; i < keys.Length; i++) | ||
int numberOfKeys = keys?.Length ?? 0; | ||
if (numberOfKeys > 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@reyang I think this was a bug. We were getting nullref exception when keys/labels were not specified.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I noticed this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me add a test case for it once this PR is merged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (i > 0) | ||
{ | ||
buffer[cursor++] = unchecked((byte)','); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@CodeBlanch Would there be benefit to moving this to above the for loop, starting i = 1
and also adding cursor = WriteLabel(buffer, cursor, keys[i], values[i]);
or would the compiler already do this loop unrolling?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops I misread the code. another idea would be to always add the comma character after the WriteLabel
call and then decrement the cursor after the loop so the next statement that modifies the buffer will overwrite it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool idea! Updated on #2749
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
private bool ExecuteCollect() | ||
{ | ||
this.exporter.OnExport = this.onCollectRef; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.exporter.OnExport = this.OnCollect;
Would this not have worked?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So what this is doing is preventing the allocation of a delegate. The only sure-fire way I know how to do that is using a field. If you do it locally, sometimes the compiler will generate a field and initialize it on the first invocation, other times it will just allocate a delegate for each call. Not totally sure how it decides. I can't remember if this particular case fell into the delegate path or if I was just being cautious. I did do some benchmarks over this when I was working on it so I probably saw allocations and used the field, but I can't remember exactly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the explanation, I had a hunch it was for perf reasons
if (value < 0) | ||
{ | ||
throw new ArgumentOutOfRangeException(nameof(value), "Value should be greater than or equal to zero."); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use Guard.Range(value, nameof(value), min: 0)
Changes
Removed the semaphore and added logic that returns the same response to concurrent scrape requests and then caches the response for a configurable period of time (10 seconds by default).
Public API Changes
TODOs
CHANGELOG.md
updated for non-trivial changesREADME.md
update for new setting