-
Notifications
You must be signed in to change notification settings - Fork 524
Make connection reset logs less scary #1199
Conversation
@@ -188,6 +209,10 @@ public class Frame<TContext> : Frame | |||
// SetBadRequestState logs the error. | |||
SetBadRequestState(ex); | |||
} | |||
catch (IOException ex) when (ex.InnerException is UvException) |
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 don't you do all checks here and avoid the new try
/catch
block around the code that reads the request line?
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 isn't for that. The try/catch above handles that and completely swallows it if it's incomplete. This replaces the "Connection processing ended abnormally" with a better one which has an eventId, connectionId, etc... Since we know a bad connection can cause SocketInput to throw and cause request processing to end abnormally, it's better to handle that explicitly. This catch will handle any connection error, not just resets.
Log.LogWarning(0,...
is generally reserved for things we don't expect to happen under normalish circumstances.
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, what I meant was, let the code above throw and catch it here, then check those conditions up there (_requestLineStatus
and StatusCodes
) here and make the appropriate trace call.
I might be missing something, but I don't see the need for the try
/catch
above and going through the whole thing with _requestProcessingStopping
being false. You're ending the loop anyways, just let it throw.
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 (!Constants.ECONNRESET.HasValue) | ||
{ | ||
_logger.LogWarning("Unable to determine ECONNRESET value on this platform."); | ||
} |
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: add new line after this block
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 copied the formatting directly from 1.0.0. You wrote that, right? 😝 I think having them together is fine since they're so closely related.
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.
lol
when I see two if
blocks like that I sometimes mentally insert a non-existing else
before the second if
when reading the code.
But this is not really critical so you can leave it as is.
Assert.True(await connectionResetLogged.WaitAsync(_semaphoreWaitTimeout)); | ||
|
||
// Check the no log level higher than Debug was used for a reset before a request | ||
Assert.True(testSink.MaxLogLevel <= LogLevel.Debug); |
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.
Assert equality here.
@@ -191,12 +192,12 @@ public Task RemoteIPv6Address() | |||
} | |||
|
|||
[Fact] | |||
public async Task ConnectionResetAbortsRequest() | |||
public async Task ConnectionResetPriorToRequestIsLoggedQuietly() |
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.
...LoggedAsDebug
is more precise
Assert.Contains("reset", testSink.ConnectionResetMessage); | ||
} | ||
} | ||
|
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: remove extra blank line
Assert.All(waitAsyncResults, Assert.True); | ||
|
||
// Check the no log level lower than Information was used for a reset mid-request | ||
Assert.True(testSink.MaxLogLevel >= LogLevel.Information); |
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.
Assert equality.
catch (IOException ex) | ||
{ | ||
// Silence ECONNRESET errors made between requests | ||
if (_requestLineStatus == RequestLineStatus.Empty && |
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.
Place requestLineStatus
in an outer scope - better than making it a Frame
member.
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.
It means that we need to move TakeStartLine out of the while condition, or do assignment in the condition. Both seemd icky to me.
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.
Doesn't C# allow while (... && (requestLineStatus = TakeStartLine(...)) != ...)
?
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.
It does, but I don't 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.
You dislike it more than a break
in a catch
block?
|
||
|
||
[Fact] | ||
public async Task ConnectionResetMidRequestIsLoggedLessQuietly() |
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.
...LoggedAsInformation
6c79b25
to
8d00e94
Compare
Addressed pr feedback. |
f0c1110
to
329138a
Compare
{ | ||
// Don't log ECONNRESET errors made between requests. Browsers like IE will reset connections regularly. | ||
if (requestLineStatus != RequestLineStatus.Empty || | ||
((UvException)ex.InnerException).StatusCode != Constants.ECONNRESET.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.
Need to check HasValue
first
((UvException)ex.InnerException).StatusCode != Constants.ECONNRESET.Value) | ||
{ | ||
Log.RequestProcessingError(ConnectionId, ex); | ||
} |
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.
else Log.ConnectionReset
?
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.
We already log that in Connection.OnRead
. Part of this was getting rid of that double logging.
aedd6a3
to
408aef0
Compare
- Particularly between requests, connection resets aren't that abnormal.
408aef0
to
0d55946
Compare
#1176