scout_apm_python icon indicating copy to clipboard operation
scout_apm_python copied to clipboard

Instrument the Odoo framework

Open adamchainz opened this issue 6 years ago • 4 comments

Odoo is an ERP web application framework with its own ORM. We should look into instrumenting it to capture web requests and the SQL queries it makes.

SQL Queries can be captured through monkey-patching the ORM's cursor wrapper here: https://github.com/odoo/odoo/blob/12.0/odoo/sql_db.py#L213 (Similar to how we do for Django <2.0)

It uses Jinja2 for its templating so we are already set there for instrumenting.

adamchainz avatar Aug 23 '19 07:08 adamchainz

We have integrated previously with NewRelic and it had a WSGIApplicationWrapper in the library as described here. It integrated quite neatly since it's the only thing which was necessary to get the data through.

kkarolis avatar Aug 23 '19 12:08 kkarolis

Oh cool, thanks for the reference. Providing a generic WSGI wrapper is probably a good idea so we can give basic support to all web frameworks.

adamchainz avatar Aug 23 '19 16:08 adamchainz

Hi @kkarolis

I've had a look through the documentation and it seems the normal Odoo deployment doesn't use the WSGI application, at least not directly. It's documented as an extra setup step.

I also found there's a third party Odoo module odoo-newrelic that adds New Relic wrapping through monkey patching rather than wsgi wrapping.

In your experience, have you always used the WSGI deployment mode, and is it common enough in the Odoo community? Or would it be better if we'd provide an official Odoo module, since that seems easier to install?

Thanks,

Adam

adamchainz avatar Aug 26 '19 16:08 adamchainz

Hey @adamchainz,

Indeed its not ordinary (from my experience) to deploy odoo using standard wsgi runners. However, as You figured out Yourself,- it is used indirectly. Normally, odoo is installed into virtualenv like environment, and odoo script is used to control server. Internally, it calls this main function which in turn calls this start function which launches odoo in a pre-fork web server model fashion. WSGI compliant application function handles the requests then.

Regarding the module You've posted,- I personally haven't used it, but it actually does something similar what we did with newrelic and newrelic.agent.WSGIApplicationWrapper. On the other hand, I see some corner case handling in there, which we don't do, so likely its more robust. We are loading the agent via odoo post-init-hook though, so I guess some improvements can be made as well. I'll drop in a snippet of what we have:

import logging
import threading

from odoo.service import server
from odoo.tools import config as odoo_config

_instrumentation_lock = threading.Lock()
_logger = logging.getLogger(__name__)

try:
    import newrelic.agent
except ImportError:
    _logger.info(
        'newrelic pip package is not installed, new_relic_agent will not work')


def install_newrelic():
    newrelic_config = odoo_config.get(
        'newrelic_config', '').strip()
    newrelic_environment = odoo_config.get(
        'newrelic_environment', 'test').strip()

    with _instrumentation_lock:
        if getattr(server.server.app, '_newrelic_agent_wrapped', False):
            return

        _logger.info('Installing New Relic agent')
        newrelic.agent.initialize(newrelic_config, newrelic_environment)

        server.server.app = newrelic.agent.WSGIApplicationWrapper(
            server.server.app)
        server.server.app._newrelic_agent_wrapped = True

Regarding wrapper vs odoo addon, in my opinion, WSGIApplicationWrapper like newrelic one would be quite useful already, but odoo addon would be super awesome. I'm not sure how willing are you to maintain it though :)

Regards, Karolis

kkarolis avatar Aug 27 '19 07:08 kkarolis