-
Notifications
You must be signed in to change notification settings - Fork 296
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
[Instrumentation.AspNetCore, Instrumentation.Http] Cache activity names #1854
Changes from 5 commits
9bbc7e4
3cf42c1
dedeff8
905ff72
aec213e
8e4e39f
77319f3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
|
||
#pragma warning disable IDE0005 // Using directive is unnecessary. | ||
using System; | ||
using System.Collections.Concurrent; | ||
#if NET8_0_OR_GREATER | ||
using System.Collections.Frozen; | ||
#endif | ||
|
@@ -20,12 +21,14 @@ namespace OpenTelemetry.Internal; | |
internal sealed class RequestDataHelper | ||
{ | ||
private const string KnownHttpMethodsEnvironmentVariable = "OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS"; | ||
private const int DisplayNameCacheSize = 1000; | ||
|
||
// The value "_OTHER" is used for non-standard HTTP methods. | ||
// https://github.com/open-telemetry/semantic-conventions/blob/v1.23.0/docs/http/http-spans.md#common-attributes | ||
private const string OtherHttpMethod = "_OTHER"; | ||
|
||
private static readonly char[] SplitChars = new[] { ',' }; | ||
private static readonly ConcurrentDictionary<string, string> DisplayNameCache = new ConcurrentDictionary<string, string>(); | ||
|
||
#if NET8_0_OR_GREATER | ||
private readonly FrozenDictionary<string, string> knownHttpMethods; | ||
|
@@ -84,7 +87,27 @@ public void SetActivityDisplayName(Activity activity, string originalHttpMethod, | |
var normalizedHttpMethod = this.GetNormalizedHttpMethod(originalHttpMethod); | ||
var namePrefix = normalizedHttpMethod == "_OTHER" ? "HTTP" : normalizedHttpMethod; | ||
|
||
activity.DisplayName = string.IsNullOrEmpty(httpRoute) ? namePrefix : $"{namePrefix} {httpRoute}"; | ||
activity.DisplayName = GetDisplayName(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How much performance would it gain? The new method seems to have enough if checks to counter the benefit. Plus the additional memory usage. |
||
|
||
string GetDisplayName() | ||
{ | ||
if (string.IsNullOrEmpty(httpRoute)) | ||
{ | ||
return namePrefix; | ||
} | ||
|
||
if (DisplayNameCache.TryGetValue(httpRoute!, out var displayName)) | ||
{ | ||
return displayName; | ||
} | ||
|
||
if (DisplayNameCache.Count < DisplayNameCacheSize) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that's what the benchmark above shows. |
||
{ | ||
return DisplayNameCache.GetOrAdd(httpRoute!, $"{namePrefix} {httpRoute}"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Re-checking - Can two http methods have the same route values?. if that happens, we will incorrectly set the display name here. e.g. |
||
} | ||
|
||
return $"{namePrefix} {httpRoute}"; | ||
} | ||
} | ||
|
||
internal static string GetHttpProtocolVersion(Version httpVersion) | ||
|
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.
Should be the size limit for this 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.
@joegoldman2 - What happens if a service receives huge number of requests with invalid routes?
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.
You're right, the dictionary will grow without limit. Let me try to think about a solution.
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.
My understanding is that there's no built-in "bounded" collection in .NET. While it's possible to implement a custom one, probably by wrapping
ConcurrentDictionary
with additional checks, I'm not entirely enthusiastic about it. I'm open to suggestions.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.
@joegoldman2 - One possible option is to check the Count of items within the dictionary before adding a new item. The Count could be some pre-defined number. If the Count exceeds that number, then we could simply skip adding items to the Dictionary.