Skip to content

Split logging features of fastapi_log #8

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

Open
wants to merge 5 commits into
base: 16.0-add-fastapi_log
Choose a base branch
from

Conversation

SirPyTech
Copy link

@SirPyTech SirPyTech commented Apr 23, 2025

As suggested in

Thanks for working on this. I wanted to do it since a while 😅

Early feedback...

The way I was planning to handle this was to have a base module to collect any kind of "request/response log".
This can be used by fastapi, base_rest, edi framework, endpoints and any custom implementation of request/response feature.

Would you consider splitting this part to a module like request_log or something like that?

Originally posted by @simahawk in OCA#501 (comment)

Also add the module fastapi_log_mail to optionally send an email when an exception occurs.

Depends on:

@ak-git-bot
Copy link

Hi @paradoxxxzero,
some modules you are maintaining are being modified, check this out!

@SirPyTech SirPyTech force-pushed the 16.0-add-fastapi_log branch from 1e08ade to ff9d6af Compare April 28, 2025 09:48
@SirPyTech SirPyTech marked this pull request as draft April 28, 2025 09:54
@SirPyTech SirPyTech force-pushed the 16.0-add-fastapi_log branch from ff9d6af to 1e08ade Compare April 28, 2025 09:57
@SirPyTech SirPyTech marked this pull request as ready for review April 28, 2025 10:05
@PicchiSeba
Copy link

PicchiSeba commented Apr 30, 2025

Regarding the multi-slash PR maybe we should wait to include it in its entirety until we receive some feedback (and I implement some tests).

I could extract the get_endpoint method without the multi-slash part and put it in its own PR and then apply my PR on it.
This way we have a common method to work on.

What do you think?

@SirPyTech
Copy link
Author

Regarding the multi-slash PR maybe we should wait to include it in its entirety until we receive some feedback (and I implement some tests).

I could extract the get_endpoint method without the multi-slash part and put it in its own PR and then apply my PR on it. This way we have a common method to work on.

What do you think?

Yes that's a good conservative solution.
So you'll create a simple refactoring PR that only extracts the occurrences of self.search([("root_path", "=", root_path)]) in a get_endpoint method, leaving the rest unchanged; that should be merged easily.

Then OCA#515 will build on the new PR to edit the get_endpoint implementation and root_path definition.

I will then include the new refactoring PR instead of OCA#515.

@PicchiSeba
Copy link

@SirPyTech

OCA#524

I moved the common method to this PR

@SirPyTech SirPyTech force-pushed the 16.0-add-fastapi_log branch from 6632ff8 to 641d4df Compare May 6, 2025 07:26
@PicchiSeba
Copy link

@SirPyTech the commit 018f44d is missing.

@SirPyTech
Copy link
Author

@PicchiSeba
Copy link

Copy link

@PicchiSeba PicchiSeba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review: issue when processing requests with consumable bodies

Comment on lines 93 to 112
def log_request(self, request):
log_request_values = {
"request_url": request.url,
"request_method": request.method,
"request_headers": self._headers_to_dict(request.headers),
"request_body": request.data,
"request_date": fields.Datetime.now(),
"request_time": self._current_time(),
}
Copy link

@PicchiSeba PicchiSeba May 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: we should check if we can read request.data because if we don't and it is consumed then we get stuck into an infinite loop later on when calling ASGIMiddleware.__call__() (from https://github.com/OCA/rest-framework/blob/16.0/fastapi/middleware.py)

We could solve this like that

We change the method's signature to allow other parameters, then we move part of fastapi_log.models.api_log's implementation into the original method

Suggested change
def log_request(self, request):
log_request_values = {
"request_url": request.url,
"request_method": request.method,
"request_headers": self._headers_to_dict(request.headers),
"request_body": request.data,
"request_date": fields.Datetime.now(),
"request_time": self._current_time(),
}
def log_request(self, request, **kwargs):
log_request_values = {
"request_url": request.url,
"request_method": request.method,
"request_headers": self._headers_to_dict(request.headers),
"request_date": fields.Datetime.now(),
"request_time": self._current_time(),
}
stream = kwargs.get("fastapi_environ", {}).get("wsgi.input")
if stream and stream.seekable():
log_request_values["request_body"] = stream.read()
stream.seek(0)
else:
log_request_values["request_body"] = request.data

An easier solution would have been to copy the request object but it doesn't have access to such a method

EDIT: nvm, request should have access to a method called deepcopy

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the proposal, I prefer to avoid adding fastapi code in the generic module api_log so I have added a couple of hooks, please check

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: that's actually a better way to do it, gj

@SirPyTech SirPyTech marked this pull request as draft May 12, 2025 12:14
@SirPyTech SirPyTech force-pushed the 16.0-add-fastapi_log branch from 641d4df to 4e86b39 Compare May 13, 2025 09:05
@SirPyTech SirPyTech requested a review from PicchiSeba May 13, 2025 10:33
@SirPyTech SirPyTech marked this pull request as ready for review May 13, 2025 10:33
Copy link

@PicchiSeba PicchiSeba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review: good work! A couple of points

<field name="name">Fastapi Log: Read access</field>
<field name="model_id" ref="model_fastapi_log" />
<field name="group_id" ref="group_fastapi_log" />
<record id="access_api_log" model="ir.model.access">

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: does this change require a migration?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since fastapi_log isn't merged yet, I wouldn't bother doing migrations in general.

If we want to keep the user's edits on fastapi_log's record then a migration is needed, otherwise Odoo will remove the old record and create a new one; since this is not a record usually edited by the user I wouldn't do a migration.

@@ -6,8 +6,8 @@
-->
<odoo>

<record id="group_fastapi_log" model="res.groups">
<field name="name">Fastapi Log Access</field>
<record id="group_api_log" model="res.groups">

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: (same as above)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See response for the question above.

request = requests.Request(
headers={
"Api-Key": secret_api_key,
"Cookie": secret_cookie,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non-blocking: let's add another header, we should check that it does not get deleted when logged. For completeness

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, done

Copy link

@PicchiSeba PicchiSeba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We changed a few things in the multi-slash PR. Let's adapt to them

fastapi_endpoint = (
self.request.env["fastapi.endpoint"]
.sudo()
.search([("root_path", "=", root_path)])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: the latest changes from @lmignon renamed this method to _get_endpoint, we should adapt its use

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!
Actually, you did it 😉
Thanks

log.fastapi_endpoint_id = (
request.env["fastapi.endpoint"]
.sudo()
.get_endpoint(environ["PATH_INFO"])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: same as above

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!
Actually, you did it 😉
Thanks

@PicchiSeba PicchiSeba force-pushed the 16.0-add-fastapi_log branch 2 times, most recently from 49e7872 to 11defea Compare May 16, 2025 07:45
@SirPyTech SirPyTech force-pushed the 16.0-add-fastapi_log branch from 11defea to 05fb39b Compare May 20, 2025 09:05
@SirPyTech SirPyTech requested a review from PicchiSeba May 20, 2025 09:49
Copy link

@PicchiSeba PicchiSeba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code and functional review: LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants