-
Notifications
You must be signed in to change notification settings - Fork 5k
Add telemetry to System.Net.NameResolution #38409
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
Conversation
Tagging subscribers to this area: @dotnet/ncl |
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs
Show resolved
Hide resolved
/azp run runtime-libraries outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs
Outdated
Show resolved
Hide resolved
// coreTask is not actually a base Task, but Task<IPHostEntry> / Task<IPAddress[]> | ||
// We have to return it and not the continuation | ||
return coreTask; | ||
} |
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.
I'd rather this be a separate async method, e.g.
return NameResolutionTelemetry.IsEnabled ?
WithLogging(hostName, justReturnParsedIp, throwOnIPAny, justAddresses) :
NameResolutionPal.GetAddrInfoAsync(hostName, justAddresses);
static async Task WithLogging(string hostName, bool ustAddresses)
{
ValueStopwatch stopwatch = NameResolutionTelemetry.Log.ResolutionStart(hostName);
bool successful = true;
try
{
await NameResolutionPal.GetAddrInfoAsync(hostName, justAddresses);
}
catch
{
LogFailure(hostName, stopwatch);
successful = false;
}
NameResolutionTelemetry.Log.AfterResolution(hostName, stopwatch, successful);
}
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.
Ah, I just saw your comment at the end. Ok.
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.
But NameResolutionPal.GetAddrInfoAsync
returns a Task
object that is actually Task<IPHostEntry>
/ Task<IPAddress[]>
, so we have to return that task itself
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.
I suspect you could still do @stephentoub's suggestion by using a generic parameter and evaluating typeof(T) == typeof(IPAddress[])
in place of justAddresses parameter. For example:
class Program
{
static async Task Main(string[] args)
{
await LogDoWork<IPAddress[]>();
await LogDoWork<IPHostEntry>();
}
static Task<T> DoWork<T>()
{
Debug.Assert(typeof(T) == typeof(IPAddress[]) ||
typeof(T) == typeof(IPHostEntry));
if (typeof(T) == typeof(IPAddress[]))
{
return Unsafe.As<Task<T>>(Task.FromResult(new IPAddress[1]));
}
else
{
return Unsafe.As<Task<T>>(Task.FromResult(new IPHostEntry()));
}
}
static async Task<T> LogDoWork<T>()
{
Console.WriteLine("starting");
T ret = await DoWork<T>();
Console.WriteLine("ending:" + ret.GetType());
return ret;
}
}
class IPAddress { }
class IPHostEntry { }
I don't mean to push it though, its a style choice that you can feel free to use if you like 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.
Unresolving this to make sure the comment I added is visible, resolve again any time
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs
Show resolved
Hide resolved
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs
Show resolved
Hide resolved
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs
Show resolved
Hide resolved
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs
Show resolved
Hide resolved
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs
Show resolved
Hide resolved
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs
Outdated
Show resolved
Hide resolved
Gist of new changes:
|
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.
Great to see more telemetry being added : ) A few questions/recommendations inline
// coreTask is not actually a base Task, but Task<IPHostEntry> / Task<IPAddress[]> | ||
// We have to return it and not the continuation | ||
return coreTask; | ||
} |
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.
I suspect you could still do @stephentoub's suggestion by using a generic parameter and evaluating typeof(T) == typeof(IPAddress[])
in place of justAddresses parameter. For example:
class Program
{
static async Task Main(string[] args)
{
await LogDoWork<IPAddress[]>();
await LogDoWork<IPHostEntry>();
}
static Task<T> DoWork<T>()
{
Debug.Assert(typeof(T) == typeof(IPAddress[]) ||
typeof(T) == typeof(IPHostEntry));
if (typeof(T) == typeof(IPAddress[]))
{
return Unsafe.As<Task<T>>(Task.FromResult(new IPAddress[1]));
}
else
{
return Unsafe.As<Task<T>>(Task.FromResult(new IPHostEntry()));
}
}
static async Task<T> LogDoWork<T>()
{
Console.WriteLine("starting");
T ret = await DoWork<T>();
Console.WriteLine("ending:" + ret.GetType());
return ret;
}
}
class IPAddress { }
class IPHostEntry { }
I don't mean to push it though, its a style choice that you can feel free to use if you like it.
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs
Show resolved
Hide resolved
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs
Outdated
Show resolved
Hide resolved
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.
LGTM, no expert here though, you probably want other approvals as well.
src/libraries/System.Net.NameResolution/src/System.Net.NameResolution.csproj
Outdated
Show resolved
Hide resolved
{ | ||
name = NameResolutionPal.GetHostName(); | ||
} | ||
catch when (LogFailure(stopwatch)) |
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.
Nice trick, I like 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.
Overall looks good, but please fix IsEnabled checks.
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs
Show resolved
Hide resolved
/azp run runtime-libraries outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
@brianrob You requested changes, I believe they were addressed. If so, please approve so that the PR can be 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.
LGTM, thanks!
/azp run runtime-libraries outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run runtime-libraries outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
Failure: #37540 |
Added 2 counters:
dns-lookups-requested
- total number of lookups since process started*dns-lookups-duration
- EventCounter for min/mean/max duration of requests in the last event counter intervalAdded 3 EventSource events:
ResolutionStart(hostNameOrAddress)
ResolutionStop()
ResolutionFailed()
*since telemetry was enabled. This can be changed to since process started by moving the
Interlocked.Increment
calls outside theIsEnabled()
check. That would avoid the race condition mentioned for Net.Http at the cost of an extra Interlocked operation even when telemetry is disabled.I've manually verified that the counters and events are emitted.
Contributes to #37428