diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ec51f8640..a94aa63f7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,6 @@ exclude: | ^fastapi_auth_jwt/| ^fastapi_auth_jwt_demo/| ^model_serializer/| - ^rest_log/| # END NOT INSTALLABLE ADDONS # Files and folders generated by bots, to avoid loops ^setup/|/static/description/index\.html$| diff --git a/rest_log/README.rst b/rest_log/README.rst index 72a6377f5..54e9d8461 100644 --- a/rest_log/README.rst +++ b/rest_log/README.rst @@ -2,10 +2,13 @@ REST Log ======== -.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:f93e58dbd77af1254adb0cd7ace54af0b0609569883ed4a22028f11f0b663139 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status @@ -14,26 +17,26 @@ REST Log :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html :alt: License: LGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Frest--framework-lightgray.png?logo=github - :target: https://github.com/OCA/rest-framework/tree/15.0/rest_log + :target: https://github.com/OCA/rest-framework/tree/17.0/rest_log :alt: OCA/rest-framework .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/rest-framework-15-0/rest-framework-15-0-rest_log + :target: https://translation.odoo-community.org/projects/rest-framework-17-0/rest-framework-17-0-rest_log :alt: Translate me on Weblate -.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/271/15.0 - :alt: Try me on Runbot +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/rest-framework&target_branch=17.0 + :alt: Try me on Runboat -|badge1| |badge2| |badge3| |badge4| |badge5| +|badge1| |badge2| |badge3| |badge4| |badge5| When exposing REST services is often useful to see what's happening especially in case of errors. -This module add DB logging for REST requests. -It also inject in the response the URL of the log entry created. +This module add DB logging for REST requests. It also inject in the +response the URL of the log entry created. -NOTE: this feature was implemented initially inside shopfloor app. -Up to version 13.0.1.2.1 of this module, -if shopfloor is installed, log records will be copied from its table. +NOTE: this feature was implemented initially inside shopfloor app. Up to +version 13.0.1.2.1 of this module, if shopfloor is installed, log +records will be copied from its table. **Table of contents** @@ -44,44 +47,48 @@ Configuration ============= Logs retention -~~~~~~~~~~~~~~ +-------------- -Logs are kept in database for every REST requests made by a client application. -They can be used for debugging and monitoring of the activity. +Logs are kept in database for every REST requests made by a client +application. They can be used for debugging and monitoring of the +activity. -The Logs menu is shown only with Developer tools (``?debug=1``) activated. +The Logs menu is shown only with Developer tools (``?debug=1``) +activated. -By default, REST logs are kept 30 days. -You can change the duration of the retention by changing the System Parameter +By default, REST logs are kept 30 days. You can change the duration of +the retention by changing the System Parameter ``rest.log.retention.days``. If the value is set to 0, the logs are not stored at all. -Logged data is: request URL and method, parameters, headers, result or error. - +Logged data is: request URL and method, parameters, headers, result or +error. Logs activation -~~~~~~~~~~~~~~~ +--------------- You have 2 ways to activate logging: -* on the service component set `_log_calls_in_db = True` -* via configuration +- on the service component set \_log_calls_in_db = True +- via configuration In the 1st case, calls will be always be logged. -In the 2nd case you can set ``rest.log.active`` param as:: +In the 2nd case you can set ``rest.log.active`` param as: + +:: - `collection_name` # enable for all endpoints of the collection - `collection_name.usage` # enable for specific endpoints - `collection_name.usage.endpoint` # enable for specific endpoints - `collection_name*:state` # enable only for specific state (success, failed) + `collection_name` # enable for all endpoints of the collection + `collection_name.usage` # enable for specific endpoints + `collection_name.usage.endpoint` # enable for specific endpoints + `collection_name*:state` # enable only for specific state (success, failed) Changelog ========= 13.0.1.0.0 -~~~~~~~~~~ +---------- First official version. @@ -90,8 +97,8 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. -If you spotted it first, help us smashing it by providing a detailed and welcomed -`feedback `_. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -99,28 +106,28 @@ Credits ======= Authors -~~~~~~~ +------- * Camptocamp * ACSONE Contributors -~~~~~~~~~~~~ +------------ -* Guewen Baconnier -* Simone Orsi +- Guewen Baconnier +- Simone Orsi Other credits -~~~~~~~~~~~~~ +------------- **Financial support** -* Cosanum -* Camptocamp R&D -* ACSONE R&D +- Cosanum +- Camptocamp R&D +- ACSONE R&D Maintainers -~~~~~~~~~~~ +----------- This module is maintained by the OCA. @@ -140,6 +147,6 @@ Current `maintainer `__: |maintainer-simahawk| -This module is part of the `OCA/rest-framework `_ project on GitHub. +This module is part of the `OCA/rest-framework `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/rest_log/__manifest__.py b/rest_log/__manifest__.py index 2e6b9f263..3f7da663f 100644 --- a/rest_log/__manifest__.py +++ b/rest_log/__manifest__.py @@ -5,7 +5,7 @@ { "name": "REST Log", "summary": "Track REST API calls into DB", - "version": "15.0.1.0.0", + "version": "17.0.1.0.0", "development_status": "Beta", "website": "https://github.com/OCA/rest-framework", "author": "Camptocamp, ACSONE, Odoo Community Association (OCA)", @@ -20,5 +20,4 @@ "views/rest_log_views.xml", "views/menu.xml", ], - "installable": False, } diff --git a/rest_log/components/service.py b/rest_log/components/service.py index 7fe8ff9ea..bbb45503f 100644 --- a/rest_log/components/service.py +++ b/rest_log/components/service.py @@ -4,26 +4,30 @@ # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). import json +import logging import traceback from werkzeug.urls import url_encode, url_join from odoo import exceptions, registry -from odoo.http import request +from odoo.http import Response, request from odoo.addons.base_rest.http import JSONEncoder from odoo.addons.component.core import AbstractComponent from ..exceptions import ( RESTServiceDispatchException, + RESTServiceMissingErrorException, RESTServiceUserErrorException, RESTServiceValidationErrorException, ) +_logger = logging.getLogger(__name__) + def json_dump(data): """Encode data to JSON as we like.""" - return json.dumps(data, cls=JSONEncoder, indent=4, sort_keys=True) + return json.dumps(data, cls=JSONEncoder, indent=4, sort_keys=True, default=str) class BaseRESTService(AbstractComponent): @@ -37,10 +41,17 @@ def dispatch(self, method_name, *args, params=None): return self._dispatch_with_db_logging(method_name, *args, params=params) def _dispatch_with_db_logging(self, method_name, *args, params=None): - # TODO: consider refactoring thi using a savepoint as described here - # https://github.com/OCA/rest-framework/pull/106#pullrequestreview-582099258 try: - result = super().dispatch(method_name, *args, params=params) + with self.env.cr.savepoint(): + result = super().dispatch(method_name, *args, params=params) + except exceptions.MissingError as orig_exception: + self._dispatch_exception( + method_name, + RESTServiceMissingErrorException, + orig_exception, + *args, + params=params, + ) except exceptions.ValidationError as orig_exception: self._dispatch_exception( method_name, @@ -65,34 +76,41 @@ def _dispatch_with_db_logging(self, method_name, *args, params=None): *args, params=params, ) - log_entry = self._log_call_in_db( - self.env, request, method_name, *args, params=params, result=result - ) - if log_entry and isinstance(result, dict): - log_entry_url = self._get_log_entry_url(log_entry) - result["log_entry_url"] = log_entry_url + self._log_dispatch_success(method_name, result, *args, params) return result + def _log_dispatch_success(self, method_name, result, *args, params=None): + try: + with self.env.cr.savepoint(): + log_entry = self._log_call_in_db( + self.env, request, method_name, *args, params, result=result + ) + if log_entry and not isinstance(result, Response): + log_entry_url = self._get_log_entry_url(log_entry) + result["log_entry_url"] = log_entry_url + except Exception as e: + _logger.exception("Rest Log Error Creation: %s", e) + def _dispatch_exception( self, method_name, exception_klass, orig_exception, *args, params=None ): - tb = traceback.format_exc() - # TODO: how to test this? Cannot rollback nor use another cursor - self.env.cr.rollback() - with registry(self.env.cr.dbname).cursor() as cr: - env = self.env(cr=cr) - log_entry = self._log_call_in_db( - env, - request, - method_name, - *args, - params=params, - traceback=tb, - orig_exception=orig_exception, - ) - log_entry_url = self._get_log_entry_url(log_entry) - # UserError and alike have `name` attribute to store the msg - exc_msg = self._get_exception_message(orig_exception) + exc_msg, log_entry_url = None, None # in case it fails below + try: + exc_msg = self._get_exception_message(orig_exception) + tb = traceback.format_exc() + with registry(self.env.cr.dbname).cursor() as cr: + log_entry = self._log_call_in_db( + self.env(cr=cr), + request, + method_name, + *args, + params=params, + traceback=tb, + orig_exception=orig_exception, + ) + log_entry_url = self._get_log_entry_url(log_entry) + except Exception as e: + _logger.exception("Rest Log Error Creation: %s", e) raise exception_klass(exc_msg, log_entry_url) from orig_exception def _get_exception_message(self, exception): @@ -115,45 +133,75 @@ def _log_call_header_strip(self): def _log_call_in_db_values(self, _request, *args, params=None, **kw): httprequest = _request.httprequest - headers = dict(httprequest.headers) - for header_key in self._log_call_header_strip: - if header_key in headers: - headers[header_key] = "" + headers = self._log_call_sanitize_headers(dict(httprequest.headers or [])) + params = dict(params or {}) if args: - params = dict(params or {}, args=args) - - result = kw.get("result") - error = kw.get("traceback") - orig_exception = kw.get("orig_exception") - exception_name = None - exception_message = None - if orig_exception: - exception_name = orig_exception.__class__.__name__ - if hasattr(orig_exception, "__module__"): - exception_name = orig_exception.__module__ + "." + exception_name - exception_message = self._get_exception_message(orig_exception) + params.update(args=args) + params = self._log_call_sanitize_params(params) + error, exception_name, exception_message = self._log_call_prepare_error(**kw) + result, state = self._log_call_prepare_result(kw.get("result")) collection = self.work.collection return { "collection": collection._name, "collection_id": collection.id, "request_url": httprequest.url, "request_method": httprequest.method, - "params": json_dump(params), - "headers": json_dump(headers), - "result": json_dump(result), + "params": params, + "headers": headers, + "result": result, "error": error, "exception_name": exception_name, "exception_message": exception_message, - "state": "success" if result else "failed", + "state": state, } + def _log_call_prepare_result(self, result): + # NB: ``result`` might be an object of class ``odoo.http.Response``, + # for example when you try to download a file. In this case, we need to + # handle it properly, without the assumption that ``result`` is a dict. + if isinstance(result, Response): + status_code = result.status_code + result = { + "status": status_code, + "headers": self._log_call_sanitize_headers(dict(result.headers or [])), + } + state = "success" if status_code in range(200, 300) else "failed" + else: + state = "success" if result else "failed" + return result, state + + def _log_call_prepare_error(self, traceback=None, orig_exception=None, **kw): + exception_name = None + exception_message = None + if orig_exception: + exception_name = orig_exception.__class__.__name__ + if hasattr(orig_exception, "__module__"): + exception_name = orig_exception.__module__ + "." + exception_name + exception_message = self._get_exception_message(orig_exception) + return traceback, exception_name, exception_message + + _log_call_in_db_keys_to_serialize = ("params", "headers", "result") + def _log_call_in_db(self, env, _request, method_name, *args, params=None, **kw): values = self._log_call_in_db_values(_request, *args, params=params, **kw) + for k in self._log_call_in_db_keys_to_serialize: + values[k] = json_dump(values[k]) enabled_states = self._get_matching_active_conf(method_name) if not values or enabled_states and values["state"] not in enabled_states: return return env["rest.log"].sudo().create(values) + def _log_call_sanitize_params(self, params: dict) -> dict: + if "password" in params: + params["password"] = "" + return params + + def _log_call_sanitize_headers(self, headers: dict) -> dict: + for header_key in self._log_call_header_strip: + if header_key in headers: + headers[header_key] = "" + return headers + def _db_logging_active(self, method_name): enabled = self._log_calls_in_db if not enabled: diff --git a/rest_log/exceptions.py b/rest_log/exceptions.py index 700cf6aa7..0da7dc2ad 100644 --- a/rest_log/exceptions.py +++ b/rest_log/exceptions.py @@ -5,7 +5,6 @@ class RESTServiceDispatchException(Exception): - rest_json_info = {} def __init__(self, message, log_entry_url): @@ -13,6 +12,12 @@ def __init__(self, message, log_entry_url): self.rest_json_info = {"log_entry_url": log_entry_url} +class RESTServiceMissingErrorException( + RESTServiceDispatchException, odoo_exceptions.MissingError +): + """Missing error wrapped exception.""" + + class RESTServiceUserErrorException( RESTServiceDispatchException, odoo_exceptions.UserError ): diff --git a/rest_log/hooks.py b/rest_log/hooks.py index f7f8f4b5b..80450ebbe 100644 --- a/rest_log/hooks.py +++ b/rest_log/hooks.py @@ -5,15 +5,15 @@ _logger = logging.getLogger(__name__) -def post_init_hook(cr, version): +def post_init_hook(env): """Preserve log entries from old implementation in shopfloor.""" - cr.execute("SELECT 1 FROM pg_class WHERE relname = 'shopfloor_log'") - if not cr.fetchone(): + env.cr.execute("SELECT 1 FROM pg_class WHERE relname = 'shopfloor_log'") + if not env.cr.fetchone(): # shopfloor_log was already removed return _logger.info("Copy shopfloor.log records to rest.log") - cr.execute( + env.cr.execute( """ INSERT INTO rest_log ( request_url, @@ -50,4 +50,4 @@ def post_init_hook(cr, version): """ ) _logger.info("Delete legacy records in shopfloor_log") - cr.execute("""DELETE FROM shopfloor_log""") + env.cr.execute("""DELETE FROM shopfloor_log""") diff --git a/rest_log/i18n/it.po b/rest_log/i18n/it.po new file mode 100644 index 000000000..336578e51 --- /dev/null +++ b/rest_log/i18n/it.po @@ -0,0 +1,230 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * rest_log +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-01-18 09:34+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: rest_log +#: model:ir.actions.server,name:rest_log.ir_cron_autovacuum_rest_log_ir_actions_server +#: model:ir.cron,cron_name:rest_log.ir_cron_autovacuum_rest_log +msgid "Auto-vacuum REST Logs" +msgstr "Registri REST auto-pulenti" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log__collection +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_search_view +msgid "Collection" +msgstr "Raccolta" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log__collection_id +msgid "Collection ID" +msgstr "ID raccolta" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log__create_uid +msgid "Created by" +msgstr "Creato da" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log__create_date +msgid "Created on" +msgstr "Creato il" + +#. module: rest_log +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_search_view +msgid "Date" +msgstr "Data" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log__error +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_form_view +msgid "Error" +msgstr "Errore" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log__exception_name +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_search_view +msgid "Exception" +msgstr "Eccezione" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log__exception_message +msgid "Exception Message" +msgstr "Messaggio eccezione" + +#. module: rest_log +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_search_view +msgid "Exception message" +msgstr "Messaggio eccezione" + +#. module: rest_log +#: model:ir.model.fields.selection,name:rest_log.selection__rest_log__state__failed +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_search_view +msgid "Failed" +msgstr "Fallito" + +#. module: rest_log +#: model:ir.model.fields.selection,name:rest_log.selection__rest_log__severity__functional +msgid "Functional" +msgstr "Funzionale" + +#. module: rest_log +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_search_view +msgid "Functional errors" +msgstr "Errori funzionali" + +#. module: rest_log +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_search_view +msgid "Group By" +msgstr "Raggruppa per" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log__headers +msgid "Headers" +msgstr "Intestazioni" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log__id +msgid "ID" +msgstr "ID" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log____last_update +msgid "Last Modified on" +msgstr "Ultima modifica il" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log__write_uid +msgid "Last Updated by" +msgstr "Ultimo aggiornamento di" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log__write_date +msgid "Last Updated on" +msgstr "Ultimo aggiornamento il" + +#. module: rest_log +#: model:ir.ui.menu,name:rest_log.menu_rest_api_log +msgid "Logs" +msgstr "Log" + +#. module: rest_log +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_search_view +msgid "Logs generated today" +msgstr "Log generati oggi" + +#. module: rest_log +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_form_view +msgid "Parameters" +msgstr "Parametri" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log__params +msgid "Params" +msgstr "Parametri" + +#. module: rest_log +#: model:ir.model,name:rest_log.model_rest_log +msgid "REST API Logging" +msgstr "Registrazione API REST" + +#. module: rest_log +#: model:res.groups,name:rest_log.group_rest_log_manager +msgid "REST Log Manager" +msgstr "Gestore log REST" + +#. module: rest_log +#: model:ir.actions.act_window,name:rest_log.action_rest_log +msgid "REST Logs" +msgstr "Log REST" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log__request_method +msgid "Request Method" +msgstr "Metodo richiesta" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log__request_url +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_search_view +msgid "Request URL" +msgstr "URL richiesta" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log__result +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_form_view +msgid "Result" +msgstr "Risultato" + +#. module: rest_log +#: model:ir.model.fields.selection,name:rest_log.selection__rest_log__severity__severe +msgid "Severe" +msgstr "Grave" + +#. module: rest_log +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_search_view +msgid "Severe errors" +msgstr "Errori gravi" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log__severity +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_search_view +msgid "Severity" +msgstr "Gravità" + +#. module: rest_log +#: model:ir.model.fields,field_description:rest_log.field_rest_log__state +msgid "State" +msgstr "Stato" + +#. module: rest_log +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_search_view +msgid "Status" +msgstr "Stato" + +#. module: rest_log +#: model:ir.model.fields.selection,name:rest_log.selection__rest_log__state__success +msgid "Success" +msgstr "Successo" + +#. module: rest_log +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_search_view +msgid "Today" +msgstr "Oggi" + +#. module: rest_log +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_search_view +msgid "User" +msgstr "Utente" + +#. module: rest_log +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_form_view +msgid "View collection" +msgstr "Visualizza raccolta" + +#. module: rest_log +#: model:ir.model.fields.selection,name:rest_log.selection__rest_log__severity__warning +msgid "Warning" +msgstr "Attenzione" + +#. module: rest_log +#: model_terms:ir.ui.view,arch_db:rest_log.rest_log_search_view +msgid "Warning errors" +msgstr "Errori attenzione" diff --git a/rest_log/i18n/rest_log.pot b/rest_log/i18n/rest_log.pot index 0d4c5cd56..8af54c47d 100644 --- a/rest_log/i18n/rest_log.pot +++ b/rest_log/i18n/rest_log.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 15.0\n" +"Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: \n" "Language-Team: \n" @@ -16,7 +16,6 @@ msgstr "" #. module: rest_log #: model:ir.actions.server,name:rest_log.ir_cron_autovacuum_rest_log_ir_actions_server #: model:ir.cron,cron_name:rest_log.ir_cron_autovacuum_rest_log -#: model:ir.cron,name:rest_log.ir_cron_autovacuum_rest_log msgid "Auto-vacuum REST Logs" msgstr "" diff --git a/rest_log/models/rest_log.py b/rest_log/models/rest_log.py index 2e3248113..50665c521 100644 --- a/rest_log/models/rest_log.py +++ b/rest_log/models/rest_log.py @@ -85,7 +85,7 @@ def _get_exception_severity_mapping(self): continue exc_name = severity = None try: - exc_name, severity = [x.strip() for x in rule.split(":")] + exc_name, severity = (x.strip() for x in rule.split(":")) if not exc_name or not severity: raise ValueError except ValueError: diff --git a/rest_log/pyproject.toml b/rest_log/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/rest_log/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/rest_log/readme/CONFIGURE.rst b/rest_log/readme/CONFIGURE.md similarity index 52% rename from rest_log/readme/CONFIGURE.rst rename to rest_log/readme/CONFIGURE.md index 0955ee00a..f6d55151a 100644 --- a/rest_log/readme/CONFIGURE.rst +++ b/rest_log/readme/CONFIGURE.md @@ -1,31 +1,30 @@ -Logs retention -~~~~~~~~~~~~~~ +## Logs retention -Logs are kept in database for every REST requests made by a client application. -They can be used for debugging and monitoring of the activity. +Logs are kept in database for every REST requests made by a client +application. They can be used for debugging and monitoring of the +activity. -The Logs menu is shown only with Developer tools (``?debug=1``) activated. +The Logs menu is shown only with Developer tools (`?debug=1`) activated. -By default, REST logs are kept 30 days. -You can change the duration of the retention by changing the System Parameter -``rest.log.retention.days``. +By default, REST logs are kept 30 days. You can change the duration of +the retention by changing the System Parameter +`rest.log.retention.days`. If the value is set to 0, the logs are not stored at all. -Logged data is: request URL and method, parameters, headers, result or error. +Logged data is: request URL and method, parameters, headers, result or +error. - -Logs activation -~~~~~~~~~~~~~~~ +## Logs activation You have 2 ways to activate logging: -* on the service component set `_log_calls_in_db = True` -* via configuration +- on the service component set \_log_calls_in_db = True +- via configuration In the 1st case, calls will be always be logged. -In the 2nd case you can set ``rest.log.active`` param as:: +In the 2nd case you can set `rest.log.active` param as: `collection_name` # enable for all endpoints of the collection `collection_name.usage` # enable for specific endpoints diff --git a/rest_log/readme/CONTRIBUTORS.md b/rest_log/readme/CONTRIBUTORS.md new file mode 100644 index 000000000..f43f5cd1a --- /dev/null +++ b/rest_log/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +- Guewen Baconnier \ +- Simone Orsi \ diff --git a/rest_log/readme/CONTRIBUTORS.rst b/rest_log/readme/CONTRIBUTORS.rst deleted file mode 100644 index 26011c7ac..000000000 --- a/rest_log/readme/CONTRIBUTORS.rst +++ /dev/null @@ -1,2 +0,0 @@ -* Guewen Baconnier -* Simone Orsi diff --git a/rest_log/readme/CREDITS.md b/rest_log/readme/CREDITS.md new file mode 100644 index 000000000..eeff7f5f1 --- /dev/null +++ b/rest_log/readme/CREDITS.md @@ -0,0 +1,5 @@ +**Financial support** + +- Cosanum +- Camptocamp R&D +- ACSONE R&D diff --git a/rest_log/readme/CREDITS.rst b/rest_log/readme/CREDITS.rst deleted file mode 100644 index 1ace41f2d..000000000 --- a/rest_log/readme/CREDITS.rst +++ /dev/null @@ -1,5 +0,0 @@ -**Financial support** - -* Cosanum -* Camptocamp R&D -* ACSONE R&D diff --git a/rest_log/readme/DESCRIPTION.md b/rest_log/readme/DESCRIPTION.md new file mode 100644 index 000000000..8300876f7 --- /dev/null +++ b/rest_log/readme/DESCRIPTION.md @@ -0,0 +1,9 @@ +When exposing REST services is often useful to see what's happening +especially in case of errors. + +This module add DB logging for REST requests. It also inject in the +response the URL of the log entry created. + +NOTE: this feature was implemented initially inside shopfloor app. Up to +version 13.0.1.2.1 of this module, if shopfloor is installed, log +records will be copied from its table. diff --git a/rest_log/readme/DESCRIPTION.rst b/rest_log/readme/DESCRIPTION.rst deleted file mode 100644 index dd0d8f674..000000000 --- a/rest_log/readme/DESCRIPTION.rst +++ /dev/null @@ -1,9 +0,0 @@ -When exposing REST services is often useful to see what's happening -especially in case of errors. - -This module add DB logging for REST requests. -It also inject in the response the URL of the log entry created. - -NOTE: this feature was implemented initially inside shopfloor app. -Up to version 13.0.1.2.1 of this module, -if shopfloor is installed, log records will be copied from its table. diff --git a/rest_log/readme/HISTORY.rst b/rest_log/readme/HISTORY.md similarity index 53% rename from rest_log/readme/HISTORY.rst rename to rest_log/readme/HISTORY.md index dc27ee260..0c490c262 100644 --- a/rest_log/readme/HISTORY.rst +++ b/rest_log/readme/HISTORY.md @@ -1,4 +1,3 @@ -13.0.1.0.0 -~~~~~~~~~~ +## 13.0.1.0.0 First official version. diff --git a/rest_log/static/description/index.html b/rest_log/static/description/index.html index 9fce1a724..5c74b5478 100644 --- a/rest_log/static/description/index.html +++ b/rest_log/static/description/index.html @@ -1,20 +1,20 @@ - - + REST Log