You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
103 lines
2.9 KiB
103 lines
2.9 KiB
# coding: utf-8
|
|
# License AGPL-3 or later (http://www.gnu.org/licenses/lgpl).
|
|
# Copyright 2014 Anybox <http://anybox.fr>
|
|
# Copyright 2016 Vauxoo (https://www.vauxoo.com) <info@vauxoo.com>
|
|
import logging
|
|
import os
|
|
from contextlib import contextmanager
|
|
from cProfile import Profile
|
|
|
|
import openerp
|
|
from openerp import sql_db
|
|
from openerp.http import WebRequest
|
|
from openerp.service.server import ThreadedServer
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class CoreProfile(object):
|
|
"""The thread-shared profile object"""
|
|
profile = None
|
|
# Indicates if the whole profiling functionality is globally active or not.
|
|
enabled = False
|
|
|
|
|
|
@contextmanager
|
|
def profiling():
|
|
"""Thread local profile management, according to the shared :data:`enabled`
|
|
"""
|
|
if CoreProfile.enabled:
|
|
CoreProfile.profile.enable()
|
|
yield
|
|
|
|
if CoreProfile.enabled:
|
|
CoreProfile.profile.disable()
|
|
|
|
|
|
def patch_odoo():
|
|
"""Modify Odoo entry points so that profile can record.
|
|
|
|
Odoo is a multi-threaded program. Therefore, the :data:`profile` object
|
|
needs to be enabled/disabled each in each thread to capture all the
|
|
execution.
|
|
|
|
For instance, Odoo spawns a new thread for each request.
|
|
|
|
Modify database connect method to add options to enable postgresql logging
|
|
based on PGOPTIONS environment variable
|
|
"""
|
|
_logger.info('Patching openerp.http.WebRequest._call_function')
|
|
webreq_f_origin = WebRequest._call_function
|
|
|
|
def webreq_f(*args, **kwargs):
|
|
with profiling():
|
|
return webreq_f_origin(*args, **kwargs)
|
|
WebRequest._call_function = webreq_f
|
|
|
|
_logger.info('Patching openerp.sql_db.db_connect')
|
|
db_connect_origin = sql_db.db_connect
|
|
|
|
def dbconnect_f(to, *args, **kwargs):
|
|
try:
|
|
to += " options='%s' " % (os.environ['PGOPTIONS'] or '')
|
|
except KeyError:
|
|
pass
|
|
return db_connect_origin(to, *args, **kwargs)
|
|
sql_db.db_connect = dbconnect_f
|
|
|
|
|
|
def dump_stats():
|
|
"""Dump stats to standard file"""
|
|
_logger.info('Dump stats')
|
|
CoreProfile.profile.dump_stats(
|
|
os.path.expanduser('~/.openerp_server.stats'))
|
|
|
|
|
|
def create_profile():
|
|
"""Create the global, shared profile object."""
|
|
_logger.info('Create profile')
|
|
CoreProfile.profile = Profile()
|
|
|
|
|
|
def patch_stop():
|
|
"""When the server is stopped then save the result of cProfile stats"""
|
|
origin_stop = ThreadedServer.stop
|
|
|
|
_logger.info('Patching openerp.service.server.ThreadedServer.stop')
|
|
|
|
def stop(*args, **kwargs):
|
|
if openerp.tools.config['test_enable']:
|
|
dump_stats()
|
|
return origin_stop(*args, **kwargs)
|
|
ThreadedServer.stop = stop
|
|
|
|
|
|
def post_load():
|
|
_logger.info('Post load')
|
|
create_profile()
|
|
patch_odoo()
|
|
if openerp.tools.config['test_enable']:
|
|
# Enable profile in test mode for orm methods.
|
|
_logger.info('Enabling profiler and apply patch')
|
|
CoreProfile.enabled = True
|
|
patch_stop()
|