diff --git a/newrelic/__init__.py b/newrelic/__init__.py new file mode 100644 index 00000000..39a2e959 --- /dev/null +++ b/newrelic/__init__.py @@ -0,0 +1,71 @@ +from . import controllers + +from logging import getLogger +_logger = getLogger(__name__) + +try: + import odoo + target = odoo.service.server.server + + try: + instrumented = target._nr_instrumented + except AttributeError: + instrumented = target._nr_instrumented = False + + if instrumented: + _logger.info("NewRelic instrumented already") + else: + import odoo.tools.config as config + import newrelic.agent + + + try: + newrelic.agent.initialize(config['new_relic_config_file'], config['new_relic_environment']) + except KeyError: + try: + newrelic.agent.initialize(config['new_relic_config_file']) + except KeyError: + _logger.info('NewRelic setting up from env variables') + newrelic.agent.initialize() + + # Main WSGI Application + target._nr_instrumented = True + target.app = newrelic.agent.WSGIApplicationWrapper(target.app) + + # Workers new WSGI Application + target = odoo.service.wsgi_server + target.application_unproxied = newrelic.agent.WSGIApplicationWrapper(target.application_unproxied) + + # Error handling + def should_ignore(exc, value, tb): + from werkzeug.exceptions import HTTPException + + # Werkzeug HTTPException can be raised internally by Odoo or in + # user code if they mix Odoo with Werkzeug. Filter based on the + # HTTP status code. + + if isinstance(value, HTTPException): + if newrelic.agent.ignore_status_code(value.code): + return True + + def _nr_wrapper_handle_exception_(wrapped): + def _handle_exception(*args, **kwargs): + transaction = newrelic.agent.current_transaction() + + if transaction is None: + return wrapped(*args, **kwargs) + + transaction.record_exception(ignore_errors=should_ignore) + + name = newrelic.agent.callable_name(args[1]) + with newrelic.agent.FunctionTrace(transaction, name): + return wrapped(*args, **kwargs) + + return _handle_exception + + target = odoo.http.WebRequest + target._handle_exception = _nr_wrapper_handle_exception_(target._handle_exception) + + +except ImportError: + _logger.warn('newrelic python module not installed or other missing module') \ No newline at end of file diff --git a/newrelic/__manifest__.py b/newrelic/__manifest__.py new file mode 100644 index 00000000..d842276c --- /dev/null +++ b/newrelic/__manifest__.py @@ -0,0 +1,12 @@ +{ + 'name': 'NewRelic Instrumentation', + 'description': 'Wraps requests etc.', + 'version': '1.0', + 'website': 'https://hibou.io/', + 'author': 'Hibou Corp. ', + 'license': 'AGPL-3', + 'category': 'Tool', + 'depends': [ + 'web', + ], +} diff --git a/newrelic/controllers/__init__.py b/newrelic/controllers/__init__.py new file mode 100644 index 00000000..12a7e529 --- /dev/null +++ b/newrelic/controllers/__init__.py @@ -0,0 +1 @@ +from . import main diff --git a/newrelic/controllers/main.py b/newrelic/controllers/main.py new file mode 100644 index 00000000..acd1dccb --- /dev/null +++ b/newrelic/controllers/main.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- + +from odoo import http, tools +import odoo.addons.bus.controllers.main + +try: + import newrelic + import newrelic.agent +except ImportError: + newrelic = None + + +class BusController(odoo.addons.bus.controllers.main.BusController): + + @http.route() + def send(self, channel, message): + if newrelic: + newrelic.agent.ignore_transaction() + return super(BusController, self).send(channel, message) + + @http.route() + def poll(self, channels, last, options=None): + if newrelic: + newrelic.agent.ignore_transaction() + return super(BusController, self).poll(channels, last, options) + +try: + if tools.config['debug_mode']: + class TestErrors(http.Controller): + @http.route('/test_errors_404', auth='public') + def test_errors_404(self): + import werkzeug + return werkzeug.exceptions.NotFound('Successful test of 404') + + @http.route('/test_errors_500', auth='public') + def test_errors_500(self): + raise ValueError +except KeyError: + pass