Skip to content
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

Reduce access log overhead when logging is disabled #7240

Merged
merged 11 commits into from Apr 16, 2023

Conversation

bdraco
Copy link
Member

@bdraco bdraco commented Mar 23, 2023

What do these changes do?

If the logger was disabled the log message would be formatted and thrown away. Avoid formatting the log message when logging is not enabled at info level.

In testing this represented up to 12% of the run time of serving a static file.

Are there changes in behavior for the user?

No

Related issue number

Checklist

  • I think the code is well written
  • Unit tests for the changes exist
  • Documentation reflects the changes
  • If you provide code modification, please add yourself to CONTRIBUTORS.txt
    • The format is <Name> <Surname>.
    • Please keep alphabetical order, the file is sorted by names.
  • Add a new news fragment into the CHANGES folder
    • name it <issue_id>.<type> for example (588.bugfix)
    • if you don't have an issue_id change it to the pr id after creating the pr
    • ensure type is one of the following:
      • .feature: Signifying a new feature.
      • .bugfix: Signifying a bug fix.
      • .doc: Signifying a documentation improvement.
      • .removal: Signifying a deprecation or removal of public API.
      • .misc: A ticket has been closed, but it is not of interest to users.
    • Make sure to use full sentences with correct case and punctuation, for example: "Fix issue with non-ascii contents in doctest text files."

If the logger was disabled the log message would be
formatted and thrown away. Avoid formatting the log
message when logging is not enabled at info level.
@bdraco bdraco changed the title Reduce access log overhead when logging is disabled WIP: Reduce access log overhead when logging is disabled Mar 23, 2023
@psf-chronographer psf-chronographer bot added the bot:chronographer:provided There is a change note present in this PR label Mar 23, 2023
@codecov
Copy link

codecov bot commented Mar 23, 2023

Codecov Report

Merging #7240 (7eaa6fb) into master (6da0469) will decrease coverage by 0.01%.
The diff coverage is 100.00%.

@@            Coverage Diff             @@
##           master    #7240      +/-   ##
==========================================
- Coverage   97.31%   97.31%   -0.01%     
==========================================
  Files         107      107              
  Lines       31405    31414       +9     
  Branches     3926     3927       +1     
==========================================
+ Hits        30562    30569       +7     
- Misses        640      641       +1     
- Partials      203      204       +1     
Flag Coverage Δ
CI-GHA 97.21% <100.00%> (-0.01%) ⬇️
OS-Linux 96.87% <100.00%> (-0.01%) ⬇️
OS-Windows 95.29% <100.00%> (-0.01%) ⬇️
OS-macOS 96.45% <100.00%> (-0.01%) ⬇️
Py-3.10.10 ?
Py-3.10.11 96.97% <100.00%> (?)
Py-3.11.0 96.40% <100.00%> (+<0.01%) ⬆️
Py-3.7.16 96.69% <100.00%> (+<0.01%) ⬆️
Py-3.7.9 95.16% <100.00%> (-0.01%) ⬇️
Py-3.8.10 95.08% <100.00%> (-0.01%) ⬇️
Py-3.8.16 96.60% <100.00%> (+<0.01%) ⬆️
Py-3.9.13 95.07% <100.00%> (-0.01%) ⬇️
Py-3.9.16 96.62% <100.00%> (+<0.01%) ⬆️
Py-pypy7.3.11 94.12% <100.00%> (-0.01%) ⬇️
VM-macos 96.45% <100.00%> (-0.01%) ⬇️
VM-ubuntu 96.87% <100.00%> (-0.01%) ⬇️
VM-windows 95.29% <100.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
aiohttp/web_log.py 100.00% <100.00%> (ø)
tests/test_web_log.py 98.60% <100.00%> (+0.07%) ⬆️

... and 1 file with indirect coverage changes

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@bdraco bdraco changed the title WIP: Reduce access log overhead when logging is disabled Reduce access log overhead when logging is disabled Mar 23, 2023
@bdraco bdraco marked this pull request as ready for review March 23, 2023 20:00
@bdraco bdraco requested a review from asvetlov as a code owner March 23, 2023 20:00
CHANGES/7240.misc Outdated Show resolved Hide resolved
CHANGES/7240.misc Outdated Show resolved Hide resolved
bdraco and others added 3 commits March 23, 2023 15:31
Co-authored-by: Sviatoslav Sydorenko <wk.cvs.github@sydorenko.org.ua>
@Dreamsorcerer
Copy link
Member

I wonder if there isn't a better solution. The logging code there looks kind of wrong to me.

e.g. self.logger.info(self._log_format % tuple(values), extra=extra) should surely be self.logger.info(self._log_format, tuple(values), extra=extra) so the string formatting doesn't happen if it's not going to be logged (not sure the tuple() call is really needed either). Presumably all the code above that line should also be done as a logging Formatter, rather than done pre-emptively (https://docs.python.org/3/howto/logging.html#formatters), although I've not looked in detail so there could be a reason that won't work..

I suspect if that were refactored to use the logging module better, then we wouldn't need any extra checks for performance (and maybe lose that method entirely as it'd become a 1 liner).

@bdraco
Copy link
Member Author

bdraco commented Apr 8, 2023

I wonder if there isn't a better solution. The logging code there looks kind of wrong to me.

e.g. self.logger.info(self._log_format % tuple(values), extra=extra) should surely be self.logger.info(self._log_format, tuple(values), extra=extra) so the string formatting doesn't happen if it's not going to be logged (not sure the tuple() call is really needed either). Presumably all the code above that line should also be done as a logging Formatter, rather than done pre-emptively (docs.python.org/3/howto/logging.html#formatters), although I've not looked in detail so there could be a reason that won't work..

I suspect if that were refactored to use the logging module better, then we wouldn't need any extra checks for performance (and maybe lose that method entirely as it'd become a 1 liner).

There isn't much we can do to defer construction in LogRecord as most of this has to be constructed ahead of time for this case https://github.com/python/cpython/blob/70bc8c936dfbd936959efd32f0cddc2597598592/Lib/logging/__init__.py#L280

I don't think there is a way to defer the construction of extra here
https://github.com/python/cpython/blob/70bc8c936dfbd936959efd32f0cddc2597598592/Lib/logging/__init__.py#L1603

isEnabledFor is what the logging howto docs recommend at least:
https://docs.python.org/3/howto/logging.html#optimization

@Dreamsorcerer
Copy link
Member

There isn't much we can do to defer construction in LogRecord as most of this has to be constructed ahead of time for this case https://github.com/python/cpython/blob/70bc8c936dfbd936959efd32f0cddc2597598592/Lib/logging/__init__.py#L280

Maybe you're right, I just saw code that looks like it is doing formatting, and am wondering if it can't be done by a Formatter.

isEnabledFor is what the logging howto docs recommend at least:
https://docs.python.org/3/howto/logging.html#optimization

Well, that's more because you need to call an expensive function to get the logging object (e.g. get_user() to include the user in the log output or something). At a glance, this code looks like the objects to log are already passed in and the computation time is spent formatting them into the log message.

tests/test_web_log.py Outdated Show resolved Hide resolved
@Dreamsorcerer
Copy link
Member

Dreamsorcerer commented Apr 8, 2023

So, here's a section that talks about using filters to add contextual information (which looks an awful lot like what this code is doing):
https://docs.python.org/3/howto/logging-cookbook.html#using-filters-to-impart-contextual-information
Or LoggerAdapter above that section:
https://docs.python.org/3/howto/logging-cookbook.html#using-loggeradapters-to-impart-contextual-information

@bdraco
Copy link
Member Author

bdraco commented Apr 8, 2023

https://docs.python.org/3/howto/logging-cookbook.html#using-filters-to-impart-contextual-information

Filter instances are allowed to modify the LogRecords passed to them

I think the filter would happen too late as we already had to pay the overhead of constructing the LogRecord before it can be filtered.

https://docs.python.org/3/howto/logging.html#optimization

However, computing the arguments passed to the logging method can also be expensive

Unless I've been dense, I think the problem we are solving is computing the arguments is computationally expensive.

@Dreamsorcerer
Copy link
Member

I think the filter would happen too late as we already had to pay the overhead of constructing the LogRecord before it can be filtered.

When an event is logged and not filtered out by a logger’s level, a LogRecord is created
https://docs.python.org/3/howto/logging-cookbook.html#customizing-logrecord

So, this is only happening only if the log level is enabled (likewise with the LoggerAdapter).

However, computing the arguments passed to the logging method can also be expensive

Unless I've been dense, I think the problem we are solving is computing the arguments is computationally expensive.

My point is that we should just pass the request etc. with extra= and then do the processing to format the message correctly as shown in one of those examples. i.e. The arguments being passed here are not arguments of the message, they are contextual information that can be parsed separately, rather than being included in the main message. If you look at those examples, they seem very similar to what we are doing here (we're just not leveraging the logger module fully and instead preprocessing all the contextual information).

@bdraco
Copy link
Member Author

bdraco commented Apr 8, 2023

My point is that we should just pass the request etc. with extra= and then do the processing to format the message correctly as shown in one of those examples. i.e. The arguments being passed here are not arguments of the message, they are contextual information that can be parsed separately, rather than being included in the main message. If you look at those examples, they seem very similar to what we are doing here (we're just not leveraging the logger module fully and instead preprocessing all the contextual information).

I think that would work to defer the extra processing but it won't solve the cost of constructing values which is a large part of the expense.

The code from the example is operating on the LogRecord

    def filter(self, record):

        record.ip = choice(ContextFilter.IPS)
        record.user = choice(ContextFilter.USERS)
        return True

But its not deferring the construction of the other arguments

a2.log(lvl, 'A message at %s level with %d %s', lvlname, 2, 'parameters')

@Dreamsorcerer
Copy link
Member

I think that would work to defer the extra processing but it won't solve the cost of constructing values which is a large part of the expense.

values is the contextual information. What I'm proposing is to do all of that work in a Filter or LoggerAdapter, so there is no code before the actual log call. At that point, the AccessLogger could maybe just become a normal Logger and you just call access_logger.info(..., extra={"request": request, "response": response}), I'm not sure if the custom class is actually needed at that point.

@bdraco
Copy link
Member Author

bdraco commented Apr 8, 2023

values is the contextual information. What I'm proposing is to do all of that work in a Filter or LoggerAdapter, so there is no code before the actual log call. At that point, the AccessLogger could maybe just become a normal Logger and you just call access_logger.info(..., extra={"request": request, "response": response}), I'm not sure if the custom class is actually needed at that point.

That should solve the performance problem, but its going to break anything that operates on LogRecord objects like Home Assistant's system_log integration because it won't know how to reconstruct the logger message in the standard way.

@Dreamsorcerer
Copy link
Member

That should solve the performance problem, but its going to break anything that operates on LogRecord objects like Home Assistant's system_log integration because it won't know how to reconstruct the logger message in the standard way.

My impression was that the Filter modifies the LogRecord and passes it on, so I'd assume the resulting LogRecord could look identical to the current one?

@bdraco
Copy link
Member Author

bdraco commented Apr 8, 2023

That should solve the performance problem, but its going to break anything that operates on LogRecord objects like Home Assistant's system_log integration because it won't know how to reconstruct the logger message in the standard way.

My impression was that the Filter modifies the LogRecord and passes it on, so I'd assume the resulting LogRecord could look identical to the current one?

It looks like the emit happens after the filter so that should work.

https://github.com/python/cpython/blob/4fa5fda14b11457dda7ef389e5486bfe3ea7b8f5/Lib/logging/__init__.py#L978

@bdraco
Copy link
Member Author

bdraco commented Apr 8, 2023

I started a draft as #7251 but I ran into a problem

We have to attach the logging filter to the logger object that gets passed in which affects anything else being logged with that logger which seems like a breaking change

@Dreamsorcerer
Copy link
Member

Yep, if it still looks good we could use that in master and merge this PR for 3.9.

@bdraco
Copy link
Member Author

bdraco commented Apr 8, 2023

I think adding the filter is going to be too much of a breaking change as the what the user needs to do section looks something like this. I stopped writing it when it became clear the side effects are going to be a problem

Are there changes in behavior for the user?

If you are using multiple aiohttp.web.AppRunner in the same python process you must also now pass a unique logger to each because AccessLogger will now attach a filter which affects the state of any logger object passed in and is not re-entrant.

Consumers of AccessLogger MUST use a new unique logger as the AccessLogger will now add logging filter to any existing logger that is passed in which will affect logging for all handlers attached to that logger. Be sure to generate a unique logger object for each instance of AccessLogger. It is important the logger is unique because if other code is using the same logger, the logging filter will likely raise an exception or mutate the log messages in an unexpected way.

        log = logging.getLogger("my_unique_logger_per_instance_of_aiohttp")
        log_format = "%a %{User-Agent}i"
        access_logger = AccessLogger(log, log_format)
        access_logger.log(request, response, time)

If multiple aiohttp instances use the same logger object then the log filter will be attached multiple times which will lead to undefined behavior.

@Dreamsorcerer
Copy link
Member

OK, I guess I was thinking of the access logger as more of an internal logger, rather than using another logger. Looks like it's not worth the hassle then. Thanks for investigating though!

@Dreamsorcerer Dreamsorcerer added the backport-3.9 Trigger automatic backporting to the 3.9 release branch by Patchback robot label Apr 8, 2023
Co-authored-by: J. Nick Koston <nick@koston.org>
@Dreamsorcerer Dreamsorcerer enabled auto-merge (squash) April 16, 2023 15:13
@Dreamsorcerer Dreamsorcerer merged commit 315ae90 into aio-libs:master Apr 16, 2023
29 of 31 checks passed
@patchback
Copy link
Contributor

patchback bot commented Apr 16, 2023

Backport to 3.9: 💚 backport PR created

✅ Backport PR branch: patchback/backports/3.9/315ae9037438351b48a712734173020374e5ff33/pr-7240

Backported as #7254

🤖 @patchback
I'm built with octomachinery and
my source is open — https://github.com/sanitizers/patchback-github-app.

patchback bot pushed a commit that referenced this pull request Apr 16, 2023
<!-- Thank you for your contribution! -->

## What do these changes do?

If the logger was disabled the log message would be formatted and thrown
away. Avoid formatting the log message when logging is not enabled at
info level.

In testing this represented up to 12% of the run time of serving a
static file.

## Are there changes in behavior for the user?

No

## Related issue number

<!-- Are there any issues opened that will be resolved by merging this
change? -->

## Checklist

- [x] I think the code is well written
- [x] Unit tests for the changes exist
- [ ] Documentation reflects the changes
- [ ] If you provide code modification, please add yourself to
`CONTRIBUTORS.txt`
  * The format is &lt;Name&gt; &lt;Surname&gt;.
  * Please keep alphabetical order, the file is sorted by names.
- [x] Add a new news fragment into the `CHANGES` folder
  * name it `<issue_id>.<type>` for example (588.bugfix)
* if you don't have an `issue_id` change it to the pr id after creating
the pr
  * ensure type is one of the following:
    * `.feature`: Signifying a new feature.
    * `.bugfix`: Signifying a bug fix.
    * `.doc`: Signifying a documentation improvement.
    * `.removal`: Signifying a deprecation or removal of public API.
* `.misc`: A ticket has been closed, but it is not of interest to users.
* Make sure to use full sentences with correct case and punctuation, for
example: "Fix issue with non-ascii contents in doctest text files."

---------

Co-authored-by: Sviatoslav Sydorenko <wk.cvs.github@sydorenko.org.ua>
Co-authored-by: Sam Bull <aa6bs0@sambull.org>
(cherry picked from commit 315ae90)
Dreamsorcerer pushed a commit that referenced this pull request Apr 16, 2023
…ging is disabled (#7254)

**This is a backport of PR #7240 as merged into master
(315ae90).**



<!-- Thank you for your contribution! -->

## What do these changes do?

If the logger was disabled the log message would be formatted and thrown
away. Avoid formatting the log message when logging is not enabled at
info level.

In testing this represented up to 12% of the run time of serving a
static file.

## Are there changes in behavior for the user?

No

## Related issue number

<!-- Are there any issues opened that will be resolved by merging this
change? -->

## Checklist

- [x] I think the code is well written
- [x] Unit tests for the changes exist
- [ ] Documentation reflects the changes
- [ ] If you provide code modification, please add yourself to
`CONTRIBUTORS.txt`
  * The format is &lt;Name&gt; &lt;Surname&gt;.
  * Please keep alphabetical order, the file is sorted by names.
- [x] Add a new news fragment into the `CHANGES` folder
  * name it `<issue_id>.<type>` for example (588.bugfix)
* if you don't have an `issue_id` change it to the pr id after creating
the pr
  * ensure type is one of the following:
    * `.feature`: Signifying a new feature.
    * `.bugfix`: Signifying a bug fix.
    * `.doc`: Signifying a documentation improvement.
    * `.removal`: Signifying a deprecation or removal of public API.
* `.misc`: A ticket has been closed, but it is not of interest to users.
* Make sure to use full sentences with correct case and punctuation, for
example: "Fix issue with non-ascii contents in doctest text files."

Co-authored-by: J. Nick Koston <nick@koston.org>
@bdraco
Copy link
Member Author

bdraco commented Apr 16, 2023

Thanks

renovate bot added a commit to allenporter/pyrainbird that referenced this pull request Nov 20, 2023
[![Mend Renovate logo
banner](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [aiohttp](https://togithub.com/aio-libs/aiohttp) | `==3.8.6` ->
`==3.9.0` |
[![age](https://developer.mend.io/api/mc/badges/age/pypi/aiohttp/3.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/aiohttp/3.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/aiohttp/3.8.6/3.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/aiohttp/3.8.6/3.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>aio-libs/aiohttp (aiohttp)</summary>

###
[`v3.9.0`](https://togithub.com/aio-libs/aiohttp/blob/HEAD/CHANGES.rst#390-2023-11-18)

[Compare
Source](https://togithub.com/aio-libs/aiohttp/compare/v3.8.6...v3.9.0)

\==================

## Features

- Introduced `AppKey` for static typing support of `Application`
storage.
See
https://docs.aiohttp.org/en/stable/web_advanced.html#application-s-config

    `#&#8203;5864 <https://github.com/aio-libs/aiohttp/issues/5864>`\_

- Added a graceful shutdown period which allows pending tasks to
complete before the application's cleanup is called.
The period can be adjusted with the `shutdown_timeout` parameter. -- by
:user:`Dreamsorcerer`.
See
https://docs.aiohttp.org/en/latest/web_advanced.html#graceful-shutdown

    `#&#8203;7188 <https://github.com/aio-libs/aiohttp/issues/7188>`\_

- Added `handler_cancellation
<https://docs.aiohttp.org/en/stable/web_advanced.html#web-handler-cancellation>`\_
parameter to cancel web handler on client disconnection. -- by
:user:`mosquito`
This (optionally) reintroduces a feature removed in a previous release.
Recommended for those looking for an extra level of protection against
denial-of-service attacks.

    `#&#8203;7056 <https://github.com/aio-libs/aiohttp/issues/7056>`\_

- Added support for setting response header parameters `max_line_size`
and `max_field_size`.

    `#&#8203;2304 <https://github.com/aio-libs/aiohttp/issues/2304>`\_

- Added `auto_decompress` parameter to `ClientSession.request` to
override `ClientSession._auto_decompress`. -- by :user:`Daste745`

    `#&#8203;3751 <https://github.com/aio-libs/aiohttp/issues/3751>`\_

-   Changed `raise_for_status` to allow a coroutine.

    `#&#8203;3892 <https://github.com/aio-libs/aiohttp/issues/3892>`\_

- Added client brotli compression support (optional with runtime check).

    `#&#8203;5219 <https://github.com/aio-libs/aiohttp/issues/5219>`\_

- Added `client_max_size` to `BaseRequest.clone()` to allow overriding
the request body size. -- :user:`anesabml`.

    `#&#8203;5704 <https://github.com/aio-libs/aiohttp/issues/5704>`\_

-   Added a middleware type alias `aiohttp.typedefs.Middleware`.

    `#&#8203;5898 <https://github.com/aio-libs/aiohttp/issues/5898>`\_

- Exported `HTTPMove` which can be used to catch any redirection request
    that has a location -- :user:`dreamsorcerer`.

    `#&#8203;6594 <https://github.com/aio-libs/aiohttp/issues/6594>`\_

- Changed the `path` parameter in `web.run_app()` to accept a
`pathlib.Path` object.

    `#&#8203;6839 <https://github.com/aio-libs/aiohttp/issues/6839>`\_

- Performance: Skipped filtering `CookieJar` when the jar is empty or
all cookies have expired.

    `#&#8203;7819 <https://github.com/aio-libs/aiohttp/issues/7819>`\_

- Performance: Only check origin if insecure scheme and there are
origins to treat as secure, in `CookieJar.filter_cookies()`.

    `#&#8203;7821 <https://github.com/aio-libs/aiohttp/issues/7821>`\_

- Performance: Used timestamp instead of `datetime` to achieve faster
cookie expiration in `CookieJar`.

    `#&#8203;7824 <https://github.com/aio-libs/aiohttp/issues/7824>`\_

- Added support for passing a custom server name parameter to HTTPS
connection.

    `#&#8203;7114 <https://github.com/aio-libs/aiohttp/issues/7114>`\_

- Added support for using Basic Auth credentials from :file:`.netrc`
file when making HTTP requests with the
:py:class:`~aiohttp.ClientSession` `trust_env` argument is set to
`True`. -- by :user:`yuvipanda`.

    `#&#8203;7131 <https://github.com/aio-libs/aiohttp/issues/7131>`\_

-   Turned access log into no-op when the logger is disabled.

    `#&#8203;7240 <https://github.com/aio-libs/aiohttp/issues/7240>`\_

- Added typing information to `RawResponseMessage`. -- by
:user:`Gobot1234`

    `#&#8203;7365 <https://github.com/aio-libs/aiohttp/issues/7365>`\_

- Removed `async-timeout` for Python 3.11+ (replaced with
`asyncio.timeout()` on newer releases).

    `#&#8203;7502 <https://github.com/aio-libs/aiohttp/issues/7502>`\_

- Added support for `brotlicffi` as an alternative to `brotli` (fixing
Brotli support on PyPy).

    `#&#8203;7611 <https://github.com/aio-libs/aiohttp/issues/7611>`\_

- Added `WebSocketResponse.get_extra_info()` to access a protocol
transport's extra info.

    `#&#8203;7078 <https://github.com/aio-libs/aiohttp/issues/7078>`\_

-   Allow `link` argument to be set to None/empty in HTTP 451 exception.

    `#&#8203;7689 <https://github.com/aio-libs/aiohttp/issues/7689>`\_

## Bugfixes

- Implemented stripping the trailing dots from fully-qualified domain
names in `Host` headers and TLS context when acting as an HTTP client.
This allows the client to connect to URLs with FQDN host name like
`https://example.com./`.
    \-- by :user:`martin-sucha`.

    `#&#8203;3636 <https://github.com/aio-libs/aiohttp/issues/3636>`\_

- Fixed client timeout not working when incoming data is always
available without waiting. -- by :user:`Dreamsorcerer`.

    `#&#8203;5854 <https://github.com/aio-libs/aiohttp/issues/5854>`\_

- Fixed `readuntil` to work with a delimiter of more than one character.

    `#&#8203;6701 <https://github.com/aio-libs/aiohttp/issues/6701>`\_

-   Added `__repr__` to `EmptyStreamReader` to avoid `AttributeError`.

    `#&#8203;6916 <https://github.com/aio-libs/aiohttp/issues/6916>`\_

-   Fixed bug when using `TCPConnector` with `ttl_dns_cache=0`.

    `#&#8203;7014 <https://github.com/aio-libs/aiohttp/issues/7014>`\_

- Fixed response returned from expect handler being thrown away. -- by
:user:`Dreamsorcerer`

    `#&#8203;7025 <https://github.com/aio-libs/aiohttp/issues/7025>`\_

- Avoided raising `UnicodeDecodeError` in multipart and in HTTP headers
parsing.

    `#&#8203;7044 <https://github.com/aio-libs/aiohttp/issues/7044>`\_

- Changed `sock_read` timeout to start after writing has finished,
avoiding read timeouts caused by an unfinished write. -- by
:user:`dtrifiro`

    `#&#8203;7149 <https://github.com/aio-libs/aiohttp/issues/7149>`\_

-   Fixed missing query in tracing method URLs when using `yarl` 1.9+.

    `#&#8203;7259 <https://github.com/aio-libs/aiohttp/issues/7259>`\_

- Changed max 32-bit timestamp to an aware datetime object, for
consistency with the non-32-bit one, and to avoid a `DeprecationWarning`
on Python 3.12.

    `#&#8203;7302 <https://github.com/aio-libs/aiohttp/issues/7302>`\_

- Fixed `EmptyStreamReader.iter_chunks()` never ending. -- by
:user:`mind1m`

    `#&#8203;7616 <https://github.com/aio-libs/aiohttp/issues/7616>`\_

- Fixed a rare `RuntimeError: await wasn't used with future` exception.
-- by :user:`stalkerg`

    `#&#8203;7785 <https://github.com/aio-libs/aiohttp/issues/7785>`\_

-   Fixed issue with insufficient HTTP method and version validation.

    `#&#8203;7700 <https://github.com/aio-libs/aiohttp/issues/7700>`\_

-   Added check to validate that absolute URIs have schemes.

    `#&#8203;7712 <https://github.com/aio-libs/aiohttp/issues/7712>`\_

- Fixed unhandled exception when Python HTTP parser encounters unpaired
Unicode surrogates.

    `#&#8203;7715 <https://github.com/aio-libs/aiohttp/issues/7715>`\_

- Updated parser to disallow invalid characters in header field names
and stop accepting LF as a request line separator.

    `#&#8203;7719 <https://github.com/aio-libs/aiohttp/issues/7719>`\_

-   Fixed Python HTTP parser not treating 204/304/1xx as an empty body.

    `#&#8203;7755 <https://github.com/aio-libs/aiohttp/issues/7755>`\_

-   Ensure empty body response for 1xx/204/304 per RFC 9112 sec 6.3.

    `#&#8203;7756 <https://github.com/aio-libs/aiohttp/issues/7756>`\_

- Fixed an issue when a client request is closed before completing a
chunked payload. -- by :user:`Dreamsorcerer`

    `#&#8203;7764 <https://github.com/aio-libs/aiohttp/issues/7764>`\_

-   Edge Case Handling for ResponseParser for missing reason value.

    `#&#8203;7776 <https://github.com/aio-libs/aiohttp/issues/7776>`\_

- Fixed `ClientWebSocketResponse.close_code` being erroneously set to
`None` when there are concurrent async tasks receiving data and closing
the connection.

    `#&#8203;7306 <https://github.com/aio-libs/aiohttp/issues/7306>`\_

-   Added HTTP method validation.

    `#&#8203;6533 <https://github.com/aio-libs/aiohttp/issues/6533>`\_

- Fixed arbitrary sequence types being allowed to inject values via
version parameter. -- by :user:`Dreamsorcerer`

    `#&#8203;7835 <https://github.com/aio-libs/aiohttp/issues/7835>`\_

- Performance: Fixed increase in latency with small messages from
websocket compression changes.

    `#&#8203;7797 <https://github.com/aio-libs/aiohttp/issues/7797>`\_

## Improved Documentation

- Fixed the `ClientResponse.release`'s type in the doc. Changed from
`comethod` to `method`.

    `#&#8203;5836 <https://github.com/aio-libs/aiohttp/issues/5836>`\_

- Added information on behavior of base_url parameter in
`ClientSession`.

    `#&#8203;6647 <https://github.com/aio-libs/aiohttp/issues/6647>`\_

-   Fixed `ClientResponseError` docs.

    `#&#8203;6700 <https://github.com/aio-libs/aiohttp/issues/6700>`\_

-   Updated Redis code examples to follow the latest API.

    `#&#8203;6907 <https://github.com/aio-libs/aiohttp/issues/6907>`\_

- Added a note about possibly needing to update headers when using
`on_response_prepare`. -- by :user:`Dreamsorcerer`

    `#&#8203;7283 <https://github.com/aio-libs/aiohttp/issues/7283>`\_

- Completed `trust_env` parameter description to honor `wss_proxy`,
`ws_proxy` or `no_proxy` env.

    `#&#8203;7325 <https://github.com/aio-libs/aiohttp/issues/7325>`\_

- Expanded SSL documentation with more examples (e.g. how to use
certifi). -- by :user:`Dreamsorcerer`

    `#&#8203;7334 <https://github.com/aio-libs/aiohttp/issues/7334>`\_

-   Fix, update, and improve client exceptions documentation.

    `#&#8203;7733 <https://github.com/aio-libs/aiohttp/issues/7733>`\_

## Deprecations and Removals

-   Added `shutdown_timeout` parameter to `BaseRunner`, while
deprecating `shutdown_timeout` parameter from `BaseSite`. -- by
:user:`Dreamsorcerer`

    `#&#8203;7718 <https://github.com/aio-libs/aiohttp/issues/7718>`\_

-   Dropped Python 3.6 support.

    `#&#8203;6378 <https://github.com/aio-libs/aiohttp/issues/6378>`\_

-   Dropped Python 3.7 support. -- by :user:`Dreamsorcerer`

    `#&#8203;7336 <https://github.com/aio-libs/aiohttp/issues/7336>`\_

- Removed support for abandoned `tokio` event loop. -- by
:user:`Dreamsorcerer`

    `#&#8203;7281 <https://github.com/aio-libs/aiohttp/issues/7281>`\_

## Misc

-   Made `print` argument in `run_app()` optional.

    `#&#8203;3690 <https://github.com/aio-libs/aiohttp/issues/3690>`\_

-   Improved performance of `ceil_timeout` in some cases.

    `#&#8203;6316 <https://github.com/aio-libs/aiohttp/issues/6316>`\_

- Changed importing Gunicorn to happen on-demand, decreasing import time
by ~53%. -- :user:`Dreamsorcerer`

    `#&#8203;6591 <https://github.com/aio-libs/aiohttp/issues/6591>`\_

- Improved import time by replacing `http.server` with
`http.HTTPStatus`.

    `#&#8203;6903 <https://github.com/aio-libs/aiohttp/issues/6903>`\_

- Fixed annotation of `ssl` parameter to disallow `True`. -- by
:user:`Dreamsorcerer`.

    `#&#8203;7335 <https://github.com/aio-libs/aiohttp/issues/7335>`\_

***

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/allenporter/pyrainbird).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy41OS44IiwidXBkYXRlZEluVmVyIjoiMzcuNTkuOCIsInRhcmdldEJyYW5jaCI6Im1haW4ifQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport-3.9 Trigger automatic backporting to the 3.9 release branch by Patchback robot bot:chronographer:provided There is a change note present in this PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants