Conversation
|
@simahawk here I addressed your latest comments akretion#8 (comment) and akretion#8 (comment), please have a look |
| try: | ||
| headers_dict = {key: value for key, value in headers.items()} | ||
| return self._sanitize_headers_dict(headers_dict) | ||
| except AttributeError: |
There was a problem hiding this comment.
when do you expect to have this kind of error?
There was a problem hiding this comment.
I'm suspicious about the headers argument, if it does not have the items method then an AttributeError would be raised.
But you're right, let's be optimistic and remove the exception handling 😄
| def _prepare_log_response(self, response): | ||
| return { | ||
| "response_status_code": response.status_code, | ||
| "response_headers": self._headers_to_dict(response.headers), |
There was a problem hiding this comment.
One of the things done in rest_log was to inject a reference to the log entry in the response.
There we assumed the response was always JSON data and added a key.
Here we could inject a response header (eg: API_LOG_ENTRY_URL)
There was a problem hiding this comment.
I have added the identifier (api.log.id) of the log record, that is enough to find the log record to whoever has access to them.
Please keep in mind that I agree with the author of #501 that wrote:
This is not a migration of rest_log, this module aims to be simpler, at least in the first iterations.
A more elaborated feature (like building the full URL of the log record) can be added later, after the first simple module is merged.
| def _compute_log_ids(self): | ||
| for collection in self: | ||
| collection.log_ids = self.env["api.log"].search( | ||
| [("collection_ref", "=", "%s,%s" % (collection._name, collection.id))] |
There was a problem hiding this comment.
see my comment above on how to search for logs
| from odoo import api, models | ||
|
|
||
|
|
||
| class FastapiLog(models.Model): |
There was a problem hiding this comment.
| class FastapiLog(models.Model): | |
| class ApiLog(models.Model): |
7674bd7 to
d1f3eec
Compare
|
The error in the tests (https://github.com/OCA/rest-framework/actions/runs/17124124402/job/48571725570?pr=554#step:8:120) does not seem to be related to these changes Stack2025-08-21 10:24:04,335 340 INFO odoo odoo.modules.loading: Loading module graphql_base (12/53)
2025-08-21 10:24:04,475 340 CRITICAL odoo odoo.modules.module: Couldn't load module graphql_base
2025-08-21 10:24:04,475 340 CRITICAL odoo odoo.modules.module: cannot import name 'HttpQueryError' from 'graphql_server' (/opt/odoo-venv/lib/python3.10/site-packages/graphql_server/__init__.py)
2025-08-21 10:24:04,477 340 WARNING odoo odoo.modules.loading: Transient module states were reset
2025-08-21 10:24:04,477 340 ERROR odoo odoo.modules.registry: Failed to load registry
Traceback (most recent call last):
File "/opt/odoo/odoo/modules/registry.py", line 87, in new
odoo.modules.load_modules(registry, force_demo, status, update_module)
File "/opt/odoo/odoo/modules/loading.py", line 493, in load_modules
processed_modules += load_marked_modules(cr, graph,
File "/opt/odoo/odoo/modules/loading.py", line 374, in load_marked_modules
loaded, processed = load_module_graph(
File "/opt/odoo/odoo/modules/loading.py", line 190, in load_module_graph
load_openerp_module(package.name)
File "/opt/odoo/odoo/modules/module.py", line 471, in load_openerp_module
__import__('odoo.addons.' + module_name)
File "/__w/rest-framework/rest-framework/graphql_base/__init__.py", line 4, in
from .controllers import GraphQLControllerMixin
File "/__w/rest-framework/rest-framework/graphql_base/controllers/__init__.py", line 1, in
from .main import GraphQLControllerMixin
File "/__w/rest-framework/rest-framework/graphql_base/controllers/main.py", line 6, in
from graphql_server import (
ImportError: cannot import name 'HttpQueryError' from 'graphql_server' (/opt/odoo-venv/lib/python3.10/site-packages/graphql_server/__init__.py)
2025-08-21 10:24:04,478 340 CRITICAL odoo odoo.service.server: Failed to initialize database `odoo`.
Traceback (most recent call last):
File "/opt/odoo/odoo/service/server.py", line 1333, in preload_registries
registry = Registry.new(dbname, update_module=update_module)
File "", line 2, in new
File "/opt/odoo/odoo/tools/func.py", line 87, in locked
return func(inst, *args, **kwargs)
File "/opt/odoo/odoo/modules/registry.py", line 87, in new
odoo.modules.load_modules(registry, force_demo, status, update_module)
File "/opt/odoo/odoo/modules/loading.py", line 493, in load_modules
processed_modules += load_marked_modules(cr, graph,
File "/opt/odoo/odoo/modules/loading.py", line 374, in load_marked_modules
loaded, processed = load_module_graph(
File "/opt/odoo/odoo/modules/loading.py", line 190, in load_module_graph
load_openerp_module(package.name)
File "/opt/odoo/odoo/modules/module.py", line 471, in load_openerp_module
__import__('odoo.addons.' + module_name)
File "/__w/rest-framework/rest-framework/graphql_base/__init__.py", line 4, in
from .controllers import GraphQLControllerMixin
File "/__w/rest-framework/rest-framework/graphql_base/controllers/__init__.py", line 1, in
from .main import GraphQLControllerMixin
File "/__w/rest-framework/rest-framework/graphql_base/controllers/main.py", line 6, in
from graphql_server import (
ImportError: cannot import name 'HttpQueryError' from 'graphql_server' (/opt/odoo-venv/lib/python3.10/site-packages/graphql_server/__init__.py)
|
SirPyTech
left a comment
There was a problem hiding this comment.
Thanks for the review!
Please check the latest changes
| try: | ||
| headers_dict = {key: value for key, value in headers.items()} | ||
| return self._sanitize_headers_dict(headers_dict) | ||
| except AttributeError: |
There was a problem hiding this comment.
I'm suspicious about the headers argument, if it does not have the items method then an AttributeError would be raised.
But you're right, let's be optimistic and remove the exception handling 😄
| def _prepare_log_response(self, response): | ||
| return { | ||
| "response_status_code": response.status_code, | ||
| "response_headers": self._headers_to_dict(response.headers), |
There was a problem hiding this comment.
I have added the identifier (api.log.id) of the log record, that is enough to find the log record to whoever has access to them.
Please keep in mind that I agree with the author of #501 that wrote:
This is not a migration of rest_log, this module aims to be simpler, at least in the first iterations.
A more elaborated feature (like building the full URL of the log record) can be added later, after the first simple module is merged.
| def _compute_log_ids(self): | ||
| for collection in self: | ||
| collection.log_ids = self.env["api.log"].search( | ||
| [("collection_ref", "=", "%s,%s" % (collection._name, collection.id))] |
| from odoo import api, models | ||
|
|
||
|
|
||
| class FastapiLog(models.Model): |
paradoxxxzero
left a comment
There was a problem hiding this comment.
Good work thanks. Nothing blocking except the exception commit problem. Once it’s fixed I’ll close my old PR.
|
|
||
| def _prepare_log_response(self, response): | ||
| headers_dict = self._headers_to_dict(response.headers) | ||
| headers_dict["API_LOG_ENTRY_ID"] = self.id |
There was a problem hiding this comment.
This does not add the id to the headers of the response, only in the logs. Set it in the response instead.
There was a problem hiding this comment.
Right, thanks for catching that!
I have added a quick assert in the tests too
| <field name="response_status_code" /> | ||
| <field name="response_headers_preview" /> | ||
| <field | ||
| name="response_preview" |
There was a problem hiding this comment.
There is no way to access the full response in the view anymore since the removal of the b64 field.
I think it should be kept one way or another.
| _logger.warning("Failed to log exception", exc_info=e) | ||
| else: | ||
| # Be sure to commit/save the exception's log | ||
| env.cr.commit() |
There was a problem hiding this comment.
This is very wrong. You are committing a transaction of a failed request.
Consider this simple case :
@router.post("/create_partner")
def create_partner(env: Annotated[api.Environment, Depends(optionally_authenticated_partner_env)]):
partner = env["res.partner"].create({...})
if is_something_wrong_with_new_partner(partner):
raise UserError("Something is wrong with new partner")
return "Ok"If logging is enabled the wrong partner will be stored in database.
Please restore the separate cursor (https://github.com/OCA/rest-framework/pull/501/files#diff-67e6f9ad0c4d04c8de3dcd507c53fa5bbebf76b169c660d976f36c84c236ea68R38) or find another way to commit the exception.
There was a problem hiding this comment.
I verified this and you are correct.
I added the separate cursor in a commit with you as a co-author to fix this, could you please check?
d1f3eec to
4e1d2b8
Compare
SirPyTech
left a comment
There was a problem hiding this comment.
Thanks for the review @paradoxxxzero, please check the latest changes
|
|
||
| def _prepare_log_response(self, response): | ||
| headers_dict = self._headers_to_dict(response.headers) | ||
| headers_dict["API_LOG_ENTRY_ID"] = self.id |
There was a problem hiding this comment.
Right, thanks for catching that!
I have added a quick assert in the tests too
| _logger.warning("Failed to log exception", exc_info=e) | ||
| else: | ||
| # Be sure to commit/save the exception's log | ||
| env.cr.commit() |
There was a problem hiding this comment.
I verified this and you are correct.
I added the separate cursor in a commit with you as a co-author to fix this, could you please check?
| <field name="response_status_code" /> | ||
| <field name="response_headers_preview" /> | ||
| <field | ||
| name="response_preview" |
4e1d2b8 to
d7bf717
Compare
paradoxxxzero
left a comment
There was a problem hiding this comment.
Except for missing header in exception, LGTM
| return self.sudo().create(log_request_values) | ||
|
|
||
| def _prepare_log_response(self, response): | ||
| response.headers["API_LOG_ENTRY_ID"] = self.id |
There was a problem hiding this comment.
I think it could be better to use kebab-case here
There was a problem hiding this comment.
Right, it is the common convention for headers keys but I didn't know that, thanks!
| return self.sudo().write(log_response_values) | ||
|
|
||
| def _prepare_log_exception(self, exception): | ||
| values = { |
There was a problem hiding this comment.
API_LOG_ENTRY_ID header is not set in case of exception
There was a problem hiding this comment.
Thanks, I added it, please check.
Note that it won't be returned in the response to the client but only stored in the log record, because in case of an exception the dispatcher simply propagates the exception raised by the endpoint.
d7bf717 to
fb9fad2
Compare
| values = { | ||
| "stack_trace": "".join(format_exception(exception)), | ||
| "response_headers": self._inject_log_entry(dict()), |
There was a problem hiding this comment.
I think it is especially important to return the header in case of exception, luckily we can do this by setting exception headers attribute, see: https://github.com/OCA/rest-framework/blob/18.0/fastapi/fastapi_dispatcher.py#L46
| values = { | |
| "stack_trace": "".join(format_exception(exception)), | |
| "response_headers": self._inject_log_entry(dict()), | |
| exception.headers = getattr(exception, "headers", {}) | |
| values = { | |
| "stack_trace": "".join(format_exception(exception)), | |
| "response_headers": self._inject_log_entry(exception.headers), | |
| } |
There was a problem hiding this comment.
I agree, that's why I mentioned it specifically, but I didn't know a way to inject it; the solution you proposed is awesome and works great!
I included it, please check the new changes.
fb9fad2 to
67660fd
Compare
paradoxxxzero
left a comment
There was a problem hiding this comment.
LGTM
Also please rename this PR to something like: [16.0][ADD] fastapi_log
67660fd to
0fae517
Compare
|
Rebased to check if this is affected by fastapi/fastapi@51ad909. |
|
I don't use this addon. @simahawk as you made a review, is-it ok for you? |
|
Hi, I'm currently trying this module, and I found a bug I'd want to report. Describe the bug
This is my traceback During handling of the above exception, another exception occurred: Traceback (most recent call last): The line of the error is this one |
Thanks for the feedback, would you mind dropping an approval in this PR? This would speed up the merge process.
|
claudio-mano
left a comment
There was a problem hiding this comment.
Tested my scenario described here: #554 (comment)
This comment was marked as resolved.
This comment was marked as resolved.
This way other APIs might use the new module `api_log` to store logs.
Co-authored-by: Florian Mounier <paradoxxx.zero@gmail.com>
3217ffc to
281e0ee
Compare
281e0ee to
3fd6a4e
Compare
|
@SirPyTech @paradoxxxzero Is this PR ready to merge? |
Thanks @lmignon for taking care of this PR! I am probably biased because I'm the author of several commits, but in my opinion this could be merged 🚀 |
|
/ocabot merge nobump |
|
What a great day to merge this nice PR. Let's do it! |
|
Congratulations, your PR was merged at 5de4d3a. Thanks a lot for contributing to OCA. ❤️ |
In the past months we have been proposing many improvements to #501 with akretion#8.
From more than a month ago, the branch is outdated (akretion#8 (comment)) and it is causing conflicts in akretion#8.
Here we are proposing all those improvements to OCA directly.