Implement IHttpRequestIdentifierFeature on Frame#1578
Implement IHttpRequestIdentifierFeature on Frame#1578natemcmaster merged 1 commit intoaspnet:devfrom
Conversation
|
|
||
| namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure | ||
| { | ||
| internal static class CorrelationIdGenerator |
There was a problem hiding this comment.
Depending on the outcome of dotnet/extensions#197, this may move to Microsoft.Extensions.Primitives
There was a problem hiding this comment.
Why not leave it in HttpAbstractions? Kestrel and Hosting would have access to it there. Or does something else need it?
There was a problem hiding this comment.
I'll refer you to dotnet/extensions#197 on that one. @muratg is looking into it.
|
Sample log when application request has an error: |
| bool IHttpResponseFeature.HasStarted | ||
| { | ||
| get { return HasResponseStarted; } | ||
| get => HasResponseStarted; |
There was a problem hiding this comment.
These can be reduced to bool IHttpResponseFeature.HasStarted => HasResponseStarted; right?
There was a problem hiding this comment.
Yes. Will update.
| { | ||
| try | ||
| { | ||
| KestrelEventSource.Log.RequestStart(this); |
There was a problem hiding this comment.
I wonder if we need these events. Hosting does the exact same thing what value do we add here?
There was a problem hiding this comment.
Hosting only logs method and path. This logs connectionId and requestId to make it possible to correlate connections and requests.
| var stop = Assert.Single(events, e => e.EventName == "ConnectionStop"); | ||
| Assert.All(new[] { "connectionId" }, p => Assert.Contains(p, stop.PayloadNames)); | ||
| Assert.Same(KestrelEventSource.Log, stop.EventSource); | ||
| { |
There was a problem hiding this comment.
avoiding copy+paste errors. Because the asserts for each event type looks so similar.
| var id = Encoding.ASCII.GetBytes(context.TraceIdentifier); | ||
| Assert.Equal(IdentifierLength, id.Length); | ||
| context.Response.ContentLength = id.Length; | ||
| context.Response.Body.Write(id, 0, id.Length); |
There was a problem hiding this comment.
Returns chunked encoding, which made it more difficult to pull the response body via StreamReader.
| })) | ||
| { | ||
| var usedIds = new HashSet<string>(); | ||
| var usedIdsLock = new object(); |
There was a problem hiding this comment.
Why not ConcurrentBag instead of set + lock?
There was a problem hiding this comment.
Yeah, i'll use that. will update
| }); | ||
|
|
||
| // requests on same connection | ||
| using (var conn = server.CreateConnection()) |
There was a problem hiding this comment.
nit: call it connection since that's we call it in all other tests
| // requests on same connection | ||
| using (var conn = server.CreateConnection()) | ||
| { | ||
| var buff = new char[IdentifierLength]; |
There was a problem hiding this comment.
Buff is a funny name, call it either buf or buffer 😄
| Assert.NotNull(id); | ||
| Assert.Equal(id, _frame.TraceIdentifier); | ||
|
|
||
| _frame.TraceIdentifier = null; |
There was a problem hiding this comment.
It's implicit as we already asserted id != null.
| void NotAllConnectionsAborted(); | ||
|
|
||
| void ApplicationError(string connectionId, Exception ex); | ||
| void ApplicationError(string connectionId, string traceIdentifier, Exception ex); |
|
Would it make sense to give connection and request id's unique prefixes to make them easier to distinguish in logs? |
| { | ||
| public static class EventSourceExtensions | ||
| { | ||
| public static void ConnectionStart(this KestrelEventSource eventSource, Connection connection) |
There was a problem hiding this comment.
Since you are moving KestrelEventSource back to the Core project, can this change also move the connection start/stop logging to core? It would be nice if this tracing could be shared between transports.
There was a problem hiding this comment.
This change was required to decouple Connection which is in Transport.Libuv and KestrelEventSource which is now in Core. ConnectionStop/Start are still on KestrelEventSource which is in Kestrel.Core, but the public methods now take string arguments directly instead of Connection.
There was a problem hiding this comment.
I still think this is worth doing now. Rather than partially moving KestrelEventSource to Core, let's move it completely. I think this might require adding some sort of OnConnectionClosed() method to IConnectionContext, but it should still be a pretty quick/simple change.
@shirhatti thoughts? Another idea I played with making each request ID contain the connection id so correlation is even easier. // pseudocode
var count = _connectionRequests++;
var requestId = $"{_connectionId}:{count}"; |
|
🆙 📅 |
| { | ||
| await connection.Send("GET / HTTP/1.1", | ||
| "Content-Length: 0", | ||
| "Host: localhost", |
There was a problem hiding this comment.
No need to send Content-Length and Host here.
|
|
||
| await connection.Receive($"HTTP/1.1 200 OK", | ||
| $"Date: {server.Context.DateHeaderValue}", | ||
| "Content-Length: " + IdentifierLength, |
YES please! @glennc Thoughts? |
|
@shirhatti I will follow up via email. Not everyone checks PR comments. |
| string ConnectionId { get; } | ||
| IPipeWriter Input { get; } | ||
| IPipeReader Output { get; } | ||
| void OnConnectionClosed(); |
There was a problem hiding this comment.
Nit: Move below "// TODO: Remove these (Use Pipes instead?)"
There is a task that will be added to Pipes that should let us track when SocketOutputConsumer complete's it's pipe reader which will be right after disposing the socket.
This feature generates a unique ID per request. This unique ID can be used in event source and logging. Also, this change improves KestrelEventSource by moving it back into the Kestrel.Core assembly and de-coupling from the Libuv transport. This adds two new events, RequestStart and RequestStop, which can be used to identify the correlation between connection ID and request trace identifier.
c05230e to
8395888
Compare
This feature generates a unique ID per request. This unique ID can be used in event source and logging.
Also, this change improves KestrelEventSource by moving it back into the Kestrel.Core assembly and de-coupling from the Libuv transport. This adds two new events, RequestStart and RequestStop, which can be used to identify the correlation between connection ID and request trace
identifier.
Resolves #1367
Benchmark
-n Plaintext --kestrelThreadCount 2
dev
RPS: 1344136.86
RPS: 1374674.53
log-request-id
RPS: 1341543.62
RPS: 1360439.85