diff --git a/odoo/addons/base/models/ir_actions.py b/odoo/addons/base/models/ir_actions.py index 68d4719a20f..8aee824604f 100644 --- a/odoo/addons/base/models/ir_actions.py +++ b/odoo/addons/base/models/ir_actions.py @@ -17,6 +17,32 @@ import logging from pytz import timezone _logger = logging.getLogger(__name__) +_server_action_logger = _logger.getChild("server_action_safe_eval") + + +class LoggerProxy: + """ Proxy of the `_logger` element in order to be used in server actions. + We purposefully restrict its method as it will be executed in `safe_eval`. + """ + @staticmethod + def log(level, message, *args, stack_info=False, exc_info=False): + _server_action_logger.log(level, message, *args, stack_info=stack_info, exc_info=exc_info) + + @staticmethod + def info(message, *args, stack_info=False, exc_info=False): + _server_action_logger.info(message, *args, stack_info=stack_info, exc_info=exc_info) + + @staticmethod + def warning(message, *args, stack_info=False, exc_info=False): + _server_action_logger.warning(message, *args, stack_info=stack_info, exc_info=exc_info) + + @staticmethod + def error(message, *args, stack_info=False, exc_info=False): + _server_action_logger.error(message, *args, stack_info=stack_info, exc_info=exc_info) + + @staticmethod + def exception(message, *args, stack_info=False, exc_info=True): + _server_action_logger.exception(message, *args, stack_info=stack_info, exc_info=exc_info) class IrActions(models.Model): @@ -610,6 +636,7 @@ class IrActionsServer(models.Model): 'records': records, # helpers 'log': log, + '_logger': LoggerProxy, }) return eval_context diff --git a/odoo/addons/base/tests/test_ir_actions.py b/odoo/addons/base/tests/test_ir_actions.py index 8646a341278..a6f5b81999e 100644 --- a/odoo/addons/base/tests/test_ir_actions.py +++ b/odoo/addons/base/tests/test_ir_actions.py @@ -59,8 +59,40 @@ class TestServerActionsBase(common.TransactionCase): 'code': 'record.write({"comment": "%s"})' % self.comment_html, }) + server_action_model = Model.search([('model', '=', 'ir.actions.server')]) + self.test_server_action = self.env['ir.actions.server'].create({ + 'name': 'TestDummyServerAction', + 'model_id': server_action_model.id, + 'state': 'code', + 'code': +""" +_logger.log(10, "This is a %s debug %s", "test", "log") +_logger.info("This is a %s info %s", "test", "log") +_logger.warning("This is a %s warning %s", "test", "log") +_logger.error("This is a %s error %s", "test", "log") +try: + 0/0 +except: + _logger.exception("This is a %s exception %s", "test", "log") +""", + }) + class TestServerActions(TestServerActionsBase): + def test_00_server_action(self): + with self.assertLogs('odoo.addons.base.models.ir_actions.server_action_safe_eval', + level='DEBUG') as log_catcher: + self.test_server_action.run() + self.assertEqual(log_catcher.output, [ + 'DEBUG:odoo.addons.base.models.ir_actions.server_action_safe_eval:This is a test debug log', + 'INFO:odoo.addons.base.models.ir_actions.server_action_safe_eval:This is a test info log', + 'WARNING:odoo.addons.base.models.ir_actions.server_action_safe_eval:This is a test warning log', + 'ERROR:odoo.addons.base.models.ir_actions.server_action_safe_eval:This is a test error log', +"""ERROR:odoo.addons.base.models.ir_actions.server_action_safe_eval:This is a test exception log +Traceback (most recent call last): + File "ir.actions.server(%d,)", line 6, in +ZeroDivisionError: division by zero""" % self.test_server_action.id + ]) def test_00_action(self): self.action.with_context(self.context).run() diff --git a/odoo/addons/base/views/ir_actions_views.xml b/odoo/addons/base/views/ir_actions_views.xml index e59d3b42bc1..faef35f41d4 100644 --- a/odoo/addons/base/views/ir_actions_views.xml +++ b/odoo/addons/base/views/ir_actions_views.xml @@ -331,13 +331,16 @@

Help with Python expressions

Various fields may use Python code or Python expressions. The following variables can be used: