diff --git a/server_action_logging/README.rst b/server_action_logging/README.rst new file mode 100644 index 00000000000..f2aaa2006ca --- /dev/null +++ b/server_action_logging/README.rst @@ -0,0 +1,92 @@ +===================== +Server Action Logging +===================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:058d2a1ebf09125d750fb4a66bfe09ad1c69db5ebe10d4fd98131ec923f92689 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github + :target: https://github.com/OCA/server-tools/tree/17.0/server_action_logging + :alt: OCA/server-tools +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/server-tools-17-0/server-tools-17-0-server_action_logging + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/server-tools&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows displaying logs when server actions are executed: + +1. a log is generated as soon as an action starts +2. a log is generated if the action is completed without any exception + being raised, and the log displays the duration (in seconds) of the + action itself +3. if action's field ``Enable SQL Debug`` is set, queries are logged too + during the action's execution + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To enable Odoo logs tracking the actions start and duration, you just +need to install this module. To track SQL queries during an action's +execution, open the action form view and check field +``Enable SQL Debug``. + +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 to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Camptocamp + +Contributors +------------ + +- Italo LOPES +- Silvio Gregorini + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/server-tools `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/server_action_logging/__init__.py b/server_action_logging/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/server_action_logging/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/server_action_logging/__manifest__.py b/server_action_logging/__manifest__.py new file mode 100644 index 00000000000..10c82c30f9a --- /dev/null +++ b/server_action_logging/__manifest__.py @@ -0,0 +1,15 @@ +# Copyright 2024 Camptocamp (https://www.camptocamp.com). +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +{ + "name": "Server Action Logging", + "summary": "Module that provides a logging mechanism for server actions", + "version": "18.0.1.0.0", + "category": "Hidden", + "website": "https://github.com/OCA/server-tools", + "author": "Camptocamp, Odoo Community Association (OCA)", + "license": "LGPL-3", + "data": ["views/ir_actions_server.xml"], + "installable": True, + "depends": ["base"], +} diff --git a/server_action_logging/i18n/fr.po b/server_action_logging/i18n/fr.po new file mode 100644 index 00000000000..2b7ef78d567 --- /dev/null +++ b/server_action_logging/i18n/fr.po @@ -0,0 +1,34 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * server_action_logging +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-30 18:33+0000\n" +"PO-Revision-Date: 2024-04-30 18:33+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: server_action_logging +#: model:ir.model.fields,field_description:server_action_logging.field_ir_actions_server__enable_sql_debug +#: model:ir.model.fields,field_description:server_action_logging.field_ir_cron__enable_sql_debug +msgid "Enable SQL Debug" +msgstr "Activer le débogage SQL" + +#. module: server_action_logging +#: model:ir.model.fields,help:server_action_logging.field_ir_actions_server__enable_sql_debug +#: model:ir.model.fields,help:server_action_logging.field_ir_cron__enable_sql_debug +msgid "Enable SQL Debug for this action" +msgstr "Activer le débogage SQL pour cette action" + +#. module: server_action_logging +#: model:ir.model,name:server_action_logging.model_ir_actions_server +msgid "Server Action" +msgstr "" diff --git a/server_action_logging/i18n/it.po b/server_action_logging/i18n/it.po new file mode 100644 index 00000000000..9c09d2aca93 --- /dev/null +++ b/server_action_logging/i18n/it.po @@ -0,0 +1,34 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * server_action_logging +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-07-08 10:58+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 5.6.2\n" + +#. module: server_action_logging +#: model:ir.model.fields,field_description:server_action_logging.field_ir_actions_server__enable_sql_debug +#: model:ir.model.fields,field_description:server_action_logging.field_ir_cron__enable_sql_debug +msgid "Enable SQL Debug" +msgstr "Abilita debug SQL" + +#. module: server_action_logging +#: model:ir.model.fields,help:server_action_logging.field_ir_actions_server__enable_sql_debug +#: model:ir.model.fields,help:server_action_logging.field_ir_cron__enable_sql_debug +msgid "Enable SQL Debug for this action" +msgstr "Abilita debug SQL per questa azione" + +#. module: server_action_logging +#: model:ir.model,name:server_action_logging.model_ir_actions_server +msgid "Server Action" +msgstr "Azione server" diff --git a/server_action_logging/i18n/pt_BR.po b/server_action_logging/i18n/pt_BR.po new file mode 100644 index 00000000000..24fd278ff2f --- /dev/null +++ b/server_action_logging/i18n/pt_BR.po @@ -0,0 +1,34 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * server_action_logging +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-30 18:33+0000\n" +"PO-Revision-Date: 2024-04-30 18:33+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: server_action_logging +#: model:ir.model.fields,field_description:server_action_logging.field_ir_actions_server__enable_sql_debug +#: model:ir.model.fields,field_description:server_action_logging.field_ir_cron__enable_sql_debug +msgid "Enable SQL Debug" +msgstr "Ativar depuração SQL" + +#. module: server_action_logging +#: model:ir.model.fields,help:server_action_logging.field_ir_actions_server__enable_sql_debug +#: model:ir.model.fields,help:server_action_logging.field_ir_cron__enable_sql_debug +msgid "Enable SQL Debug for this action" +msgstr "Ativar depuração SQL para esta ação" + +#. module: server_action_logging +#: model:ir.model,name:server_action_logging.model_ir_actions_server +msgid "Server Action" +msgstr "" diff --git a/server_action_logging/i18n/server_action_logging.pot b/server_action_logging/i18n/server_action_logging.pot new file mode 100644 index 00000000000..4d99b13e0c7 --- /dev/null +++ b/server_action_logging/i18n/server_action_logging.pot @@ -0,0 +1,31 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * server_action_logging +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: server_action_logging +#: model:ir.model.fields,field_description:server_action_logging.field_ir_actions_server__enable_sql_debug +#: model:ir.model.fields,field_description:server_action_logging.field_ir_cron__enable_sql_debug +msgid "Enable SQL Debug" +msgstr "" + +#. module: server_action_logging +#: model:ir.model.fields,help:server_action_logging.field_ir_actions_server__enable_sql_debug +#: model:ir.model.fields,help:server_action_logging.field_ir_cron__enable_sql_debug +msgid "Enable SQL Debug for this action" +msgstr "" + +#. module: server_action_logging +#: model:ir.model,name:server_action_logging.model_ir_actions_server +msgid "Server Action" +msgstr "" diff --git a/server_action_logging/models/__init__.py b/server_action_logging/models/__init__.py new file mode 100644 index 00000000000..4ab5cb105fe --- /dev/null +++ b/server_action_logging/models/__init__.py @@ -0,0 +1 @@ +from . import ir_actions_server diff --git a/server_action_logging/models/ir_actions_server.py b/server_action_logging/models/ir_actions_server.py new file mode 100644 index 00000000000..d6c6cbd15d4 --- /dev/null +++ b/server_action_logging/models/ir_actions_server.py @@ -0,0 +1,41 @@ +# Copyright 2024 Camptocamp (https://www.camptocamp.com). +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +import logging + +from odoo import fields, models + +_logger = logging.getLogger(__name__) + + +class IrActionsServer(models.Model): + _inherit = "ir.actions.server" + + enable_sql_debug = fields.Boolean( + string="Enable SQL Debug", + help="Enable SQL Debug for this action", + default=False, # Avoid too much log pollution + ) + + def run(self): + if self.env.context.get("server_action_run_with_logs"): # Avoid recursion + return super().run() + + actions = self.with_context(server_action_run_with_logs=True) + odoo_sql_db_logger = logging.getLogger("odoo.sql_db") + odoo_sql_db_logger_level = odoo_sql_db_logger.level + odoo_sql_db_logger_has_debug = odoo_sql_db_logger.isEnabledFor(logging.DEBUG) + res = False + for act in actions: + force_sql_debug = not odoo_sql_db_logger_has_debug and act.enable_sql_debug + if force_sql_debug: + odoo_sql_db_logger.setLevel(logging.DEBUG) + subject = f"Action {act.display_name} ({act})" + _logger.info(f"{subject} started") + start = fields.Datetime.now() + res = act.run() + delta = (fields.Datetime.now() - start).total_seconds() + _logger.info(f"{subject} completed in {delta:.3f} seconds") + if force_sql_debug: + odoo_sql_db_logger.setLevel(odoo_sql_db_logger_level) + return res or False diff --git a/server_action_logging/pyproject.toml b/server_action_logging/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/server_action_logging/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/server_action_logging/readme/CONTRIBUTORS.md b/server_action_logging/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..aa5d17855a8 --- /dev/null +++ b/server_action_logging/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +- Italo LOPES \<\> +- Silvio Gregorini \<\> diff --git a/server_action_logging/readme/DESCRIPTION.md b/server_action_logging/readme/DESCRIPTION.md new file mode 100644 index 00000000000..6cef5ea375f --- /dev/null +++ b/server_action_logging/readme/DESCRIPTION.md @@ -0,0 +1,8 @@ +This module allows displaying logs when server actions are executed: + +1. a log is generated as soon as an action starts +2. a log is generated if the action is completed without any exception + being raised, and the log displays the duration (in seconds) of the + action itself +3. if action's field `Enable SQL Debug` is set, queries are logged too + during the action's execution diff --git a/server_action_logging/readme/USAGE.md b/server_action_logging/readme/USAGE.md new file mode 100644 index 00000000000..5716f49985f --- /dev/null +++ b/server_action_logging/readme/USAGE.md @@ -0,0 +1,3 @@ +To enable Odoo logs tracking the actions start and duration, you just +need to install this module. To track SQL queries during an action's +execution, open the action form view and check field `Enable SQL Debug`. diff --git a/server_action_logging/static/description/icon.png b/server_action_logging/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/server_action_logging/static/description/icon.png differ diff --git a/server_action_logging/static/description/index.html b/server_action_logging/static/description/index.html new file mode 100644 index 00000000000..aac2543807a --- /dev/null +++ b/server_action_logging/static/description/index.html @@ -0,0 +1,437 @@ + + + + + +Server Action Logging + + + +
+

Server Action Logging

+ + +

Beta License: LGPL-3 OCA/server-tools Translate me on Weblate Try me on Runboat

+

This module allows displaying logs when server actions are executed:

+
    +
  1. a log is generated as soon as an action starts
  2. +
  3. a log is generated if the action is completed without any exception +being raised, and the log displays the duration (in seconds) of the +action itself
  4. +
  5. if action’s field Enable SQL Debug is set, queries are logged too +during the action’s execution
  6. +
+

Table of contents

+ +
+

Usage

+

To enable Odoo logs tracking the actions start and duration, you just +need to install this module. To track SQL queries during an action’s +execution, open the action form view and check field +Enable SQL Debug.

+
+
+

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 to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Camptocamp
  • +
+
+ +
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/server-tools project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/server_action_logging/tests/__init__.py b/server_action_logging/tests/__init__.py new file mode 100644 index 00000000000..25baf4e117c --- /dev/null +++ b/server_action_logging/tests/__init__.py @@ -0,0 +1 @@ +from . import test_server_action_logging diff --git a/server_action_logging/tests/test_server_action_logging.py b/server_action_logging/tests/test_server_action_logging.py new file mode 100644 index 00000000000..8636331bcd5 --- /dev/null +++ b/server_action_logging/tests/test_server_action_logging.py @@ -0,0 +1,101 @@ +import logging + +from odoo.tests.common import TransactionCase + + +class TestServerActionLogging(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.action_no_sql_log = cls.env["ir.actions.server"].create( + { + "name": "Test Action w/o SQL Logging", + "enable_sql_debug": False, + "state": "code", + "model_id": cls.env.ref("base.model_res_users").id, + "model_name": "res.users", + "code": "model.sudo().search([]).read(['name', 'login'])", + } + ) + cls.action_with_sql_log = cls.env["ir.actions.server"].create( + { + "name": "Test Action w/ SQL Logging", + "enable_sql_debug": True, + "state": "code", + "model_id": cls.env.ref("base.model_res_users").id, + "model_name": "res.users", + "code": "model.sudo().search([]).read(['name', 'login'])", + } + ) + cls.action_with_error = cls.env["ir.actions.server"].create( + { + "name": "Test Action w/ Error", + "enable_sql_debug": False, + "state": "code", + "model_id": cls.env.ref("base.model_res_users").id, + "model_name": "res.users", + "code": "model.sudo().search([]).read(['invalid_field'])", + } + ) + cls.log_action = logging.getLogger( + "odoo.addons.server_action_logging.models.ir_actions_server" + ) + cls.log_sql_db = logging.getLogger("odoo.sql_db") + + def setUp(self): + super().setUp() + # Odoo logger may be disabled for level ``logging.INFO`` when running tests + if not self.log_action.isEnabledFor(logging.INFO): + self.log_action.setLevel(logging.INFO) + + def test_00_log_action_timing(self): + """Tests Odoo logs while running an action""" + self.assertTrue(self.log_action.isEnabledFor(logging.INFO)) + self.assertFalse(self.log_sql_db.isEnabledFor(logging.DEBUG)) + with self.assertLogs(self.log_action, logging.INFO) as log_action_watcher: + self.action_no_sql_log.run() + self.assertFalse(self.log_sql_db.isEnabledFor(logging.DEBUG)) + logs = log_action_watcher.output + self.assertEqual(len(logs), 2) + self.assertEqual( + f"INFO:{self.log_action.name}:Action {self.action_no_sql_log.display_name}" + f" ({self.action_no_sql_log}) started", + logs[0], + ) + self.assertIn( + f"INFO:{self.log_action.name}:Action {self.action_no_sql_log.display_name}" + f" ({self.action_no_sql_log}) completed in", + logs[1], + ) + + def test_01_log_action_sql_db(self): + """Tests SQL logs while running an action""" + self.assertTrue(self.log_action.isEnabledFor(logging.INFO)) + self.assertFalse(self.log_sql_db.isEnabledFor(logging.DEBUG)) + with self.assertLogs(self.log_sql_db, logging.DEBUG) as log_sql_db_watcher: + # NB: ``self.assertLogs`` will automatically enable the ``logging.DEBUG`` + # level for the ``odoo.sql_db`` logger, which would make it impossible to + # check whether the logging is dynamically enabled for actions which + # require it; therefore, we manually disable the logger before executing + # the action itself + self.log_sql_db.setLevel(logging.NOTSET) + self.action_with_sql_log.run() + self.assertFalse(self.log_sql_db.isEnabledFor(logging.DEBUG)) + self.assertGreaterEqual(len(log_sql_db_watcher.output), 1) + + def test_02_log_action_failure(self): + """Tests Odoo logs while running an action that fails""" + self.assertTrue(self.log_action.isEnabledFor(logging.INFO)) + self.assertFalse(self.log_sql_db.isEnabledFor(logging.DEBUG)) + with self.assertLogs(self.log_action, logging.INFO) as log_action_watcher: + with self.assertRaises(ValueError): + self.action_with_error.run() + self.assertFalse(self.log_sql_db.isEnabledFor(logging.DEBUG)) + logs = log_action_watcher.output + self.assertEqual(len(logs), 1) + self.assertEqual( + f"INFO:{self.log_action.name}:Action {self.action_with_error.display_name}" + f" ({self.action_with_error}) started", + logs[0], + ) diff --git a/server_action_logging/views/ir_actions_server.xml b/server_action_logging/views/ir_actions_server.xml new file mode 100644 index 00000000000..a9b9ceea559 --- /dev/null +++ b/server_action_logging/views/ir_actions_server.xml @@ -0,0 +1,15 @@ + + + + + ir.actions.server.form.inherit + ir.actions.server + + + + + + + + +