-
Notifications
You must be signed in to change notification settings - Fork 164
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
Trace Actuator Updates #1356
base: main
Are you sure you want to change the base?
Trace Actuator Updates #1356
Conversation
/azp run cleanup-code |
Azure Pipelines successfully started running 1 pipeline(s). |
Code cleanup failed to reformat and push changes. View details here. |
a51e47c
to
ba2fd37
Compare
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.
First glance over the changes. It's pretty hard to see what's changed on GitHub due to renames. I'll run a file-by-file diff in the next round.
src/Management/src/Endpoint/Actuators/HttpExchanges/EndpointServiceCollectionExtensions.cs
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchange.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchangesEndpointOptions.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchangesDiagnosticObserver.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchangesDiagnosticObserver.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchangesEndpointOptions.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/ManagementWebHostBuilderExtensions.cs
Outdated
Show resolved
Hide resolved
src/Management/test/Endpoint.Test/Actuators/HttpExchanges/EndpointMiddlewareTest.cs
Outdated
Show resolved
Hide resolved
3609088
to
27ff773
Compare
src/Management/src/Endpoint/Actuators/HttpExchanges/ConfigureHttpExchangesEndpointOptions.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/ConfigureHttpExchangesEndpointOptions.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchangesDiagnosticObserver.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchangesDiagnosticObserver.cs
Outdated
Show resolved
Hide resolved
return new HttpExchangesResult(recentExchanges); | ||
} | ||
|
||
public override void ProcessEvent(string eventName, object? value) |
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.
Can we just type-check value
for HttpContext
instead of the reflection-based properly lookups? Same for the other two observers. I suspect this is a leftover from the split between base/core and support for the full .NET framework.
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 think we should drop HttpClientDesktopObserver
(which reads from WebRequest
) entirely, because it was obsoleted in .NET 6.
Then rename the renaming remaining one to just HttpClientObserver
.
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.
value
is an anonymous type with a HttpContext
as a property... I can't seem to get type checking to work in this scenario and haven't found anything in several web searches.
You're probably right about the other observers, I'm not sure yet if it's something I want to include in this PR though
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.
value is an anonymous type with a HttpContext as a property... I can't seem to get type checking to work in this scenario and haven't found anything in several web searches.
These are just the tests acting silly by passing an anonymous type. As can be seen here, ASP.NET always passes in a HttpContext
instance. So the code can just be:
if (value is HttpContext httpContext)
{
RecordHttpExchange(current, httpContext);
}
When using that and debugging the test AddSeveralActuators_WebApplicationBuilder_NoConflict
(breakpoint in method HttpExchangesDiagnosticObserver.ProcessEvent
), it always sends an HttpContext
instance.
You're probably right about the other observers, I'm not sure yet if it's something I want to include in this PR though
Why not, do you have any concerns? The current names are just confusing. The other observers suffer from the same issues as addressed in this PR, such as obtaining Activity.Current
when not needed. Please open an issue otherwise.
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.
These are just the tests acting silly by passing an anonymous type...
I should know by now not to trust that these tests are always doing the right thing 🙄
Why not, do you have any concerns? The current names are just confusing. The other observers suffer from the same issues as addressed in this PR, such as obtaining
Activity.Current
when not needed. Please open an issue otherwise.
Not any specific concerns, more a question of maintaining focus... If I have time to tackle it before your next review I will, otherwise I'll create a follow-up issue so this PR doesn't keep dragging on
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 can do the delete & rename, but it looks like we can't currently adjust the reflection-based property access code: dotnet/runtime#82910
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 don't understand what's going on. The code was updated to type-check for HttpContext
as I suggested, and now only unit tests call the method GetHttpContextPropertyValue
(so it has basically become redundant). But the runtime issue states we still need to use reflection?
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.
Oh right... I didn't come back and check on other usages of GetHttpContextPropertyValue
after trying to adjust the other observers. I'll remove this method and the two tests. The runtime issue is the reason why I can't do the same for the HttpClient Observer(s)
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.
Okay, I understand that HttpClientObserver
needs to keep using reflection due to the runtime issue. But that doesn't apply to AspNetCoreHostingObserver
, so please update to remove the reflection there.
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchangesResult.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/ServiceCollectionExtensions.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/RouteMappings/RouteMappingsEndpointHandler.cs
Show resolved
Hide resolved
src/Management/test/Endpoint.Test/Actuators/CloudFoundry/EndpointMiddlewareTest.cs
Outdated
Show resolved
Hide resolved
src/Management/test/Endpoint.Test/ManagementWebApplicationBuilderExtensionsTest.cs
Outdated
Show resolved
Hide resolved
c25ef15
to
8d78612
Compare
/azp run cleanup-code |
Azure Pipelines successfully started running 1 pipeline(s). |
Code cleanup successfully reformatted files and pushed changes. |
/azp run cleanup-code |
Azure Pipelines successfully started running 1 pipeline(s). |
Code cleanup successfully reformatted files and pushed changes. |
df33a65
to
38337b9
Compare
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchangesDiagnosticObserver.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/ConfigureHttpExchangesEndpointOptions.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchangesDiagnosticObserver.cs
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchangesDiagnosticObserver.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchange.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchangesDiagnosticObserver.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchangesDiagnosticObserver.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchangesDiagnosticObserver.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchangesDiagnosticObserver.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchangesEndpointOptions.cs
Outdated
Show resolved
Hide resolved
src/Management/test/Endpoint.Test/Actuators/CloudFoundry/EndpointMiddlewareTest.cs
Outdated
Show resolved
Hide resolved
5955f36
to
42752ce
Compare
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've completed a full sweep of all changes. Please don't rebase anymore until this PR is approved.
src/Management/src/Endpoint/Actuators/HttpExchanges/ServiceCollectionExtensions.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/ServiceCollectionExtensions.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/ManagementHostApplicationBuilderExtensions.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/ManagementWebHostBuilderExtensions.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchangesDiagnosticObserver.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchangesDiagnosticObserver.cs
Outdated
Show resolved
Hide resolved
src/Management/src/Endpoint/Actuators/HttpExchanges/ConfigureHttpExchangesEndpointOptions.cs
Outdated
Show resolved
Hide resolved
return new HttpExchangesResult(recentExchanges); | ||
} | ||
|
||
public override void ProcessEvent(string eventName, object? value) |
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 don't understand what's going on. The code was updated to type-check for HttpContext
as I suggested, and now only unit tests call the method GetHttpContextPropertyValue
(so it has basically become redundant). But the runtime issue states we still need to use reflection?
src/Management/src/Endpoint/Actuators/HttpExchanges/HttpExchangesDiagnosticObserver.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Bart Koelman <[email protected]>
Co-authored-by: Bart Koelman <[email protected]>
Co-authored-by: Bart Koelman <[email protected]>
/azp run Steeltoe.All |
Azure Pipelines successfully started running 1 pipeline(s). |
1 similar comment
Azure Pipelines successfully started running 1 pipeline(s). |
Code cleanup successfully reformatted files and pushed changes. |
[Fact] | ||
public async Task HttpExchangesActuator_DoesNotCaptureAuthInUri() | ||
{ | ||
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create(); | ||
builder.Configuration.AddInMemoryCollection(AppSettings); | ||
builder.AddHttpExchangesActuator(); | ||
await using WebApplication host = builder.Build(); | ||
|
||
host.UseRouting(); | ||
await host.StartAsync(); | ||
using HttpClient httpClient = host.GetTestClient(); | ||
|
||
var requestUri = new Uri("http://username:password@localhost/actuator/httpexchanges"); | ||
_ = await httpClient.GetAsync(requestUri); | ||
HttpResponseMessage response = await httpClient.GetAsync(requestUri); | ||
response.StatusCode.Should().Be(HttpStatusCode.OK); | ||
|
||
string json = await response.Content.ReadAsStringAsync(); | ||
json.Should().NotContain("username").And.NotContain("password"); | ||
json.Should().Contain("http://localhost:80/actuator/httpexchanges"); | ||
} |
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.
[Fact] | |
public async Task HttpExchangesActuator_DoesNotCaptureAuthInUri() | |
{ | |
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create(); | |
builder.Configuration.AddInMemoryCollection(AppSettings); | |
builder.AddHttpExchangesActuator(); | |
await using WebApplication host = builder.Build(); | |
host.UseRouting(); | |
await host.StartAsync(); | |
using HttpClient httpClient = host.GetTestClient(); | |
var requestUri = new Uri("http://username:password@localhost/actuator/httpexchanges"); | |
_ = await httpClient.GetAsync(requestUri); | |
HttpResponseMessage response = await httpClient.GetAsync(requestUri); | |
response.StatusCode.Should().Be(HttpStatusCode.OK); | |
string json = await response.Content.ReadAsStringAsync(); | |
json.Should().NotContain("username").And.NotContain("password"); | |
json.Should().Contain("http://localhost:80/actuator/httpexchanges"); | |
} | |
[Fact] | |
public async Task HttpExchangesActuator_DoesNotCaptureAuthInUri() | |
{ | |
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.CreateDefault(false); | |
builder.Configuration.AddInMemoryCollection(AppSettings); | |
builder.AddHttpExchangesActuator(); | |
await using WebApplication host = builder.Build(); | |
host.UseRouting(); | |
host.MapGet("/hello", () => "Hello World!"); | |
await host.StartAsync(); | |
using var httpClient = new HttpClient(); | |
HttpResponseMessage helloResponse = await httpClient.GetAsync("http://username:password@localhost:5000/hello"); | |
helloResponse.StatusCode.Should().Be(HttpStatusCode.OK); | |
HttpResponseMessage actuatorResponse = await httpClient.GetAsync(new Uri("http://localhost:5000/actuator/httpexchanges")); | |
actuatorResponse.StatusCode.Should().Be(HttpStatusCode.OK); | |
var actuatorRootElement = await actuatorResponse.Content.ReadFromJsonAsync<JsonElement>(); | |
JsonElement[] exchangesArray = actuatorRootElement.GetProperty("exchanges").EnumerateArray().ToArray(); | |
exchangesArray.Should().HaveCount(1); | |
string requestUri = exchangesArray[0].GetProperty("request").GetProperty("uri").ToString(); | |
requestUri.Should().Be("http://localhost:5000/hello"); | |
} |
The suggested test is more reliable because:
- It starts a real server, bypassing short-circuiting from TestServer.
- It verifies a regular request, instead of an actuator endpoint.
- It verifies we're actually getting back a response that's not an empty exchanges array.
- It verifies the URI is correct, not empty/omitted, etc.
Note: Taking this suggestion requires adding using System.Text.Json;
at the top.
filteredHeaders.Response.Headers["HeaderA"][0].Should().Be(HttpExchangesDiagnosticObserver.Redacted); | ||
filteredHeaders.Response.Headers["HeaderB"][0].Should().Be("headerBValue"); | ||
filteredHeaders.Response.Headers[HeaderNames.SetCookie][0].Should().Be(HttpExchangesDiagnosticObserver.Redacted); | ||
filteredHeaders.Principal?.Name.Should().Be("MyTestName"); |
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.
Never use ?.
in FluentAssertions-style assertions. If null
, the right-hand side doesn't execute, thus no assertion is performed.
Aside from multiple occurrences in this file, please also correct the ones in ApplicationInstanceCertificateTest
.
observer.ProcessEvent("Microsoft.AspNetCore.Hosting.HttpRequestIn.Stop", context); | ||
} | ||
|
||
observer.Queue.Count.Should().Be(option.CurrentValue.Capacity); |
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 is a poor assertion, because it won't dump the collection contents on failure. The best it can show is "5 should be 4".
Instead, use:
observer.Queue.Should().HaveCount(option.CurrentValue.Capacity);
Applies to multiple places in this file.
{ | ||
using var listener = new DiagnosticListener("test"); | ||
|
||
IOptionsMonitor<HttpExchangesEndpointOptions> option = |
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.
Please rename these vars to optionsMonitor
, which is what they are.
...Management/test/Endpoint.Test/Actuators/HttpExchanges/HttpExchangesDiagnosticObserverTest.cs
Show resolved
Hide resolved
|
||
public sealed class HttpExchange | ||
{ | ||
[JsonPropertyName("TimeTaken")] |
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.
Why is this Pascal-cased, whereas all other properties aren't?
And this doesn't actually work because the JSON serializer skips internal properties. Test coverage is missing. And apparently, it hasn't been manually tested either.
Having unit tests is no excuse for omitting tests that verify the entire feature works, which was already identified in #1028. What ultimately matters the most is the response being returned, because that's what users observe. So at the minimum, there must be a test that asserts on the JSON returned when all options are turned on, and one for when all options are turned off. As they are still missing (this far in the review process), I wrote them myself in aaf76b6. In doing so, I've identified various bugs.
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.
Sorry, that was a combination of copy/paste from the property name and being distracted by time stamp in the response without paying close enough attention. Thanks for writing the tests, I pulled in that commit
|
||
public sealed class HttpExchange | ||
{ | ||
public DateTime Timestamp { get; } |
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 is still a UTC date/time in the response, not a timestamp in Unix Epoch ticks.
response = await httpClient.GetAsync(new Uri("http://localhost/actuator/httpexchanges")); | ||
response.StatusCode.Should().Be(HttpStatusCode.OK); | ||
string json = await response.Content.ReadAsStringAsync(); | ||
json.Should().NotContain("username").And.NotContain("password"); |
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 doesn't make sense, there's no username/password anywhere in this test.
json.Should().Contain("http://localhost:80/actuator/httpexchanges"); | ||
json.Should().Contain($"\"timestamp\":\"{DateTime.UtcNow.Date:yyyy-MM-dd}"); |
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.
These assertions are way insufficient, see my other comment.
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 test and the one above now effectively do the same thing but with different assertions, so I'm just going to consolidate them and fill out the assertion set for all of the properties
return new HttpExchangesResult(recentExchanges); | ||
} | ||
|
||
public override void ProcessEvent(string eventName, object? value) |
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.
Okay, I understand that HttpClientObserver
needs to keep using reflection due to the runtime issue. But that doesn't apply to AspNetCoreHostingObserver
, so please update to remove the reflection there.
…re/better assertions
Azure Pipelines successfully started running 1 pipeline(s). |
Quality Gate passedIssues Measures |
Description
While adding support for header filtering, I discovered we're a bit out of sync with Spring on this actuator in general, so I also decided to:
I also ran into an unhandled exception with the mappings actuator and included a fix for that
Fixes #1351
Quality checklist
If your change affects other repositories, such as Documentation, Samples and/or MainSite, add linked PRs here.