diff --git a/.travis.yml b/.travis.yml index ce0ca1c..5df21a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,7 @@ env: - TESTS="1" ODOO_REPO="odoo/odoo" EXCLUDE="cloud_platform,cloud_platform_ovh,cloud_platform_exoscale" - TESTS="1" ODOO_REPO="OCA/OCB" EXCLUDE="cloud_platform,cloud_platform_ovh,cloud_platform_exoscale" global: - - VERSION="15.0" LINT_CHECK="0" TESTS="0" + - VERSION="16.0" LINT_CHECK="0" TESTS="0" install: - git clone --depth=1 https://github.com/OCA/maintainer-quality-tools.git ${HOME}/maintainer-quality-tools diff --git a/base_attachment_object_storage/models/ir_attachment.py b/base_attachment_object_storage/models/ir_attachment.py index ed43c69..425bb9e 100644 --- a/base_attachment_object_storage/models/ir_attachment.py +++ b/base_attachment_object_storage/models/ir_attachment.py @@ -5,7 +5,7 @@ import inspect import logging import os import time -from distutils.util import strtobool +from .strtobool import strtobool import psycopg2 import odoo diff --git a/base_attachment_object_storage/models/strtobool.py b/base_attachment_object_storage/models/strtobool.py new file mode 100644 index 0000000..44d1eb2 --- /dev/null +++ b/base_attachment_object_storage/models/strtobool.py @@ -0,0 +1,21 @@ +_MAP = { + 'y': True, + 'yes': True, + 't': True, + 'true': True, + 'on': True, + '1': True, + 'n': False, + 'no': False, + 'f': False, + 'false': False, + 'off': False, + '0': False +} + + +def strtobool(value): + try: + return _MAP[str(value).lower()] + except KeyError: + raise ValueError('"{}" is not a valid bool value'.format(value)) diff --git a/cloud_platform/models/cloud_platform.py b/cloud_platform/models/cloud_platform.py index 750f4bd..65a4d11 100644 --- a/cloud_platform/models/cloud_platform.py +++ b/cloud_platform/models/cloud_platform.py @@ -6,7 +6,7 @@ import os import re from collections import namedtuple -from distutils.util import strtobool +from .strtobool import strtobool from odoo import api, models from odoo.tools.config import config diff --git a/cloud_platform/models/strtobool.py b/cloud_platform/models/strtobool.py new file mode 100644 index 0000000..44d1eb2 --- /dev/null +++ b/cloud_platform/models/strtobool.py @@ -0,0 +1,21 @@ +_MAP = { + 'y': True, + 'yes': True, + 't': True, + 'true': True, + 'on': True, + '1': True, + 'n': False, + 'no': False, + 'f': False, + 'false': False, + 'off': False, + '0': False +} + + +def strtobool(value): + try: + return _MAP[str(value).lower()] + except KeyError: + raise ValueError('"{}" is not a valid bool value'.format(value)) diff --git a/logging_json/json_log.py b/logging_json/json_log.py index 8215df4..60313b3 100644 --- a/logging_json/json_log.py +++ b/logging_json/json_log.py @@ -6,7 +6,7 @@ import os import threading import uuid -from distutils.util import strtobool +from .strtobool import strtobool from odoo import http @@ -20,30 +20,29 @@ except ImportError: def is_true(strval): - return bool(strtobool(strval or '0'.lower())) + return bool(strtobool(strval or "0".lower())) class OdooJsonFormatter(jsonlogger.JsonFormatter): - def add_fields(self, log_record, record, message_dict): record.pid = os.getpid() - record.dbname = getattr(threading.currentThread(), 'dbname', '?') - record.request_id = getattr(threading.current_thread(), 'request_uuid', None) - record.uid = getattr(threading.current_thread(), 'uid', None) + record.dbname = getattr(threading.currentThread(), "dbname", "?") + record.request_id = getattr(threading.current_thread(), "request_uuid", None) + record.uid = getattr(threading.current_thread(), "uid", None) _super = super(OdooJsonFormatter, self) return _super.add_fields(log_record, record, message_dict) -if is_true(os.environ.get('ODOO_LOGGING_JSON')): +if is_true(os.environ.get("ODOO_LOGGING_JSON")): formatted_message = ( - '%(asctime)s %(pid)s %(levelname)s %(dbname)s %(name)s: %(message)s' + "%(asctime)s %(pid)s %(levelname)s %(dbname)s %(name)s: %(message)s" ) formatter = OdooJsonFormatter(formatted_message) logging.getLogger().handlers[0].formatter = formatter -# monkey patch WebRequest constructor to store request_uuid -org_init = http.WebRequest.__init__ +# monkey patch Request constructor to store request_uuid +org_init = http.Request.__init__ def new_init(self, httprequest): @@ -51,4 +50,4 @@ def new_init(self, httprequest): threading.current_thread().request_uuid = uuid.uuid4() -http.WebRequest.__init__ = new_init +http.Request.__init__ = new_init diff --git a/logging_json/strtobool.py b/logging_json/strtobool.py new file mode 100644 index 0000000..44d1eb2 --- /dev/null +++ b/logging_json/strtobool.py @@ -0,0 +1,21 @@ +_MAP = { + 'y': True, + 'yes': True, + 't': True, + 'true': True, + 'on': True, + '1': True, + 'n': False, + 'no': False, + 'f': False, + 'false': False, + 'off': False, + '0': False +} + + +def strtobool(value): + try: + return _MAP[str(value).lower()] + except KeyError: + raise ValueError('"{}" is not a valid bool value'.format(value)) diff --git a/monitoring_log_requests/models/ir_http.py b/monitoring_log_requests/models/ir_http.py index abaf46b..559115d 100644 --- a/monitoring_log_requests/models/ir_http.py +++ b/monitoring_log_requests/models/ir_http.py @@ -10,27 +10,28 @@ from odoo.http import request as http_request from odoo.tools.config import config -_logger = logging.getLogger('monitoring.http.requests') +_logger = logging.getLogger("monitoring.http.requests") class IrHttp(models.AbstractModel): - _inherit = 'ir.http' + _inherit = "ir.http" @classmethod - def _dispatch(cls): + def _dispatch(cls, endpoint): begin = time.time() - response = super()._dispatch() + response = super()._dispatch(endpoint) end = time.time() - if (not cls._monitoring_blacklist(http_request) and - cls._monitoring_filter(http_request)): + if not cls._monitoring_blacklist(http_request) and cls._monitoring_filter( + http_request + ): info = cls._monitoring_info(http_request, response, begin, end) cls._monitoring_log(info) return response @classmethod def _monitoring_blacklist(cls, request): - path_info = request.httprequest.environ.get('PATH_INFO') - if path_info.startswith('/longpolling/'): + path_info = request.httprequest.environ.get("PATH_INFO") + if path_info.startswith("/longpolling/"): return True return False @@ -40,42 +41,45 @@ class IrHttp(models.AbstractModel): @classmethod def _monitoring_info(cls, request, response, begin, end): - path = request.httprequest.environ.get('PATH_INFO') + path = request.httprequest.environ.get("PATH_INFO") info = { # timing - 'start_time': time.strftime("%Y-%m-%d %H:%M:%S", - time.gmtime(begin)), - 'duration': end - begin, + "start_time": time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(begin)), + "duration": end - begin, # HTTP things - 'method': request.httprequest.method, - 'url': request.httprequest.url, - 'path': path, - 'content_type': request.httprequest.environ.get('CONTENT_TYPE'), - 'user_agent': request.httprequest.environ.get('HTTP_USER_AGENT'), + "method": request.httprequest.method, + "url": request.httprequest.url, + "path": path, + "content_type": request.httprequest.environ.get("CONTENT_TYPE"), + "user_agent": request.httprequest.environ.get("HTTP_USER_AGENT"), # Odoo things - 'db': None, - 'uid': request.uid, - 'login': None, - 'server_environment': config.get('running_env'), - 'model': None, - 'model_method': None, - 'workflow_signal': None, + "db": None, + "uid": request.uid, + "login": None, + "server_environment": config.get("running_env"), + "model": None, + "model_method": None, + "workflow_signal": None, # response things - 'response_status_code': None, + "response_status_code": None, } - if hasattr(request, 'status_code'): - info['status_code'] = response.status_code - if hasattr(request, 'session'): - info.update({ - 'login': request.session.get('login'), - 'db': request.session.get('db'), - }) - if hasattr(request, 'params'): - info.update({ - 'model': request.params.get('model'), - 'model_method': request.params.get('method'), - 'workflow_signal': request.params.get('signal'), - }) + if hasattr(request, "status_code"): + info["status_code"] = response.status_code + if hasattr(request, "session"): + info.update( + { + "login": request.session.get("login"), + "db": request.session.get("db"), + } + ) + if hasattr(request, "params"): + info.update( + { + "model": request.params.get("model"), + "model_method": request.params.get("method"), + "workflow_signal": request.params.get("signal"), + } + ) return info @classmethod diff --git a/monitoring_prometheus/models/ir_http.py b/monitoring_prometheus/models/ir_http.py index 0c026d6..050ca5b 100644 --- a/monitoring_prometheus/models/ir_http.py +++ b/monitoring_prometheus/models/ir_http.py @@ -16,15 +16,15 @@ class IrHttp(models.AbstractModel): _inherit = "ir.http" @classmethod - def _dispatch(cls): + def _dispatch(cls, endpoint): path_info = request.httprequest.environ.get("PATH_INFO") if path_info.startswith("/longpolling/"): LONGPOLLING_COUNT.inc() - return super()._dispatch() + return super()._dispatch(endpoint) if path_info.startswith("/metrics"): - return super()._dispatch() + return super()._dispatch(endpoint) if path_info.startswith("/web/static"): label = "assets" @@ -35,6 +35,6 @@ class IrHttp(models.AbstractModel): res = None with REQUEST_TIME.labels(label).time(): - res = super()._dispatch() + res = super()._dispatch(endpoint) return res diff --git a/monitoring_statsd/models/ir_http.py b/monitoring_statsd/models/ir_http.py index ba4f538..db430d9 100644 --- a/monitoring_statsd/models/ir_http.py +++ b/monitoring_statsd/models/ir_http.py @@ -11,13 +11,13 @@ class IrHttp(models.AbstractModel): _inherit = 'ir.http' @classmethod - def _dispatch(cls): + def _dispatch(cls, endpoint): if not statsd: - return super()._dispatch() + return super()._dispatch(endpoint) path_info = request.httprequest.environ.get('PATH_INFO') if path_info.startswith('/longpolling/'): - return super()._dispatch() + return super()._dispatch(endpoint) parts = ['http', ] if path_info.startswith('/web/dataset/call_button'): @@ -38,4 +38,4 @@ class IrHttp(models.AbstractModel): ] with statsd.timer('.'.join(parts)): - return super()._dispatch() + return super()._dispatch(endpoint) diff --git a/monitoring_statsd/models/strtobool.py b/monitoring_statsd/models/strtobool.py new file mode 100644 index 0000000..44d1eb2 --- /dev/null +++ b/monitoring_statsd/models/strtobool.py @@ -0,0 +1,21 @@ +_MAP = { + 'y': True, + 'yes': True, + 't': True, + 'true': True, + 'on': True, + '1': True, + 'n': False, + 'no': False, + 'f': False, + 'false': False, + 'off': False, + '0': False +} + + +def strtobool(value): + try: + return _MAP[str(value).lower()] + except KeyError: + raise ValueError('"{}" is not a valid bool value'.format(value)) diff --git a/monitoring_statsd/statsd_client.py b/monitoring_statsd/statsd_client.py index 1ab1bba..a86b759 100644 --- a/monitoring_statsd/statsd_client.py +++ b/monitoring_statsd/statsd_client.py @@ -4,9 +4,7 @@ import logging import os -from distutils.util import strtobool - -from odoo.tools.config import config +from .strtobool import strtobool _logger = logging.getLogger(__name__) @@ -14,40 +12,39 @@ try: from statsd import defaults from statsd.client import StatsClient except ImportError: - _logger.warning('statds must be installed') + _logger.warning("statds must be installed") defaults = None # noqa StatsClient = None # noqa def is_true(strval): - return bool(strtobool(strval or '0'.lower())) + return bool(strtobool(strval or "0".lower())) -statsd_active = is_true(os.environ.get('ODOO_STATSD')) +statsd_active = is_true(os.environ.get("ODOO_STATSD")) statsd = None customer = None environment = None if statsd_active and statsd is None and StatsClient is not None: - if not os.environ.get('STATSD_CUSTOMER'): - raise Exception( - 'STATSD_CUSTOMER must contain the name of the customer' - ) - customer = os.environ.get('STATSD_CUSTOMER') - if os.environ.get('STATSD_ENVIRONMENT'): - environment = os.environ['STATSD_ENVIRONMENT'] - elif config.get('running_env'): - environment = config['running_env'] + if not os.environ.get("STATSD_CUSTOMER"): + raise Exception("STATSD_CUSTOMER must contain the name of the customer") + customer = os.environ.get("STATSD_CUSTOMER") + if os.environ.get("STATSD_ENVIRONMENT"): + environment = os.environ["STATSD_ENVIRONMENT"] + elif config.get("running_env"): + environment = config["running_env"] else: raise Exception( - 'Either STATSD_ENVIRONMENT or configuration option running_env ' - 'must contain the environment (prod, integration, ...)' + "Either STATSD_ENVIRONMENT or configuration option running_env " + "must contain the environment (prod, integration, ...)" ) - host = os.getenv('STATSD_HOST', defaults.HOST) - port = int(os.getenv('STATSD_PORT', defaults.PORT)) - prefix = os.getenv('STATSD_PREFIX', defaults.PREFIX) - maxudpsize = int(os.getenv('STATSD_MAXUDPSIZE', defaults.MAXUDPSIZE)) - ipv6 = bool(int(os.getenv('STATSD_IPV6', defaults.IPV6))) - statsd = StatsClient(host=host, port=port, prefix='odoo', - maxudpsize=maxudpsize, ipv6=ipv6) + host = os.getenv("STATSD_HOST", defaults.HOST) + port = int(os.getenv("STATSD_PORT", defaults.PORT)) + prefix = os.getenv("STATSD_PREFIX", defaults.PREFIX) + maxudpsize = int(os.getenv("STATSD_MAXUDPSIZE", defaults.MAXUDPSIZE)) + ipv6 = bool(int(os.getenv("STATSD_IPV6", defaults.IPV6))) + statsd = StatsClient( + host=host, port=port, prefix="odoo", maxudpsize=maxudpsize, ipv6=ipv6 + ) diff --git a/session_redis/http.py b/session_redis/http.py index 48902af..c10f84c 100644 --- a/session_redis/http.py +++ b/session_redis/http.py @@ -4,7 +4,7 @@ import logging import os -from distutils.util import strtobool +from .strtobool import strtobool import odoo from odoo import http @@ -23,46 +23,46 @@ except ImportError: def is_true(strval): - return bool(strtobool(strval or '0'.lower())) + return bool(strtobool(strval or "0".lower())) -sentinel_host = os.environ.get('ODOO_SESSION_REDIS_SENTINEL_HOST') -sentinel_master_name = os.environ.get( - 'ODOO_SESSION_REDIS_SENTINEL_MASTER_NAME' -) +sentinel_host = os.environ.get("ODOO_SESSION_REDIS_SENTINEL_HOST") +sentinel_master_name = os.environ.get("ODOO_SESSION_REDIS_SENTINEL_MASTER_NAME") if sentinel_host and not sentinel_master_name: raise Exception( "ODOO_SESSION_REDIS_SENTINEL_MASTER_NAME must be defined " "when using session_redis" ) -sentinel_port = int(os.environ.get('ODOO_SESSION_REDIS_SENTINEL_PORT', 26379)) -host = os.environ.get('ODOO_SESSION_REDIS_HOST', 'localhost') -port = int(os.environ.get('ODOO_SESSION_REDIS_PORT', 6379)) -prefix = os.environ.get('ODOO_SESSION_REDIS_PREFIX') -url = os.environ.get('ODOO_SESSION_REDIS_URL') -password = os.environ.get('ODOO_SESSION_REDIS_PASSWORD') -expiration = os.environ.get('ODOO_SESSION_REDIS_EXPIRATION') -anon_expiration = os.environ.get('ODOO_SESSION_REDIS_EXPIRATION_ANONYMOUS') +sentinel_port = int(os.environ.get("ODOO_SESSION_REDIS_SENTINEL_PORT", 26379)) +host = os.environ.get("ODOO_SESSION_REDIS_HOST", "localhost") +port = int(os.environ.get("ODOO_SESSION_REDIS_PORT", 6379)) +prefix = os.environ.get("ODOO_SESSION_REDIS_PREFIX") +url = os.environ.get("ODOO_SESSION_REDIS_URL") +password = os.environ.get("ODOO_SESSION_REDIS_PASSWORD") +expiration = os.environ.get("ODOO_SESSION_REDIS_EXPIRATION") +anon_expiration = os.environ.get("ODOO_SESSION_REDIS_EXPIRATION_ANONYMOUS") @lazy_property def session_store(self): if sentinel_host: - sentinel = Sentinel([(sentinel_host, sentinel_port)], - password=password) + sentinel = Sentinel([(sentinel_host, sentinel_port)], password=password) redis_client = sentinel.master_for(sentinel_master_name) elif url: redis_client = redis.from_url(url) else: redis_client = redis.Redis(host=host, port=port, password=password) - return RedisSessionStore(redis=redis_client, prefix=prefix, - expiration=expiration, - anon_expiration=anon_expiration, - session_class=http.OpenERPSession) + return RedisSessionStore( + redis=redis_client, + prefix=prefix, + expiration=expiration, + anon_expiration=anon_expiration, + session_class=http.OpenERPSession, + ) def session_gc(session_store): - """ Do not garbage collect the sessions + """Do not garbage collect the sessions Redis keys are automatically cleaned at the end of their expiration. @@ -79,14 +79,22 @@ def purge_fs_sessions(path): pass -if is_true(os.environ.get('ODOO_SESSION_REDIS')): +if is_true(os.environ.get("ODOO_SESSION_REDIS")): if sentinel_host: - _logger.debug("HTTP sessions stored in Redis with prefix '%s'. " - "Using Sentinel on %s:%s", - prefix or '', sentinel_host, sentinel_port) + _logger.debug( + "HTTP sessions stored in Redis with prefix '%s'. " + "Using Sentinel on %s:%s", + prefix or "", + sentinel_host, + sentinel_port, + ) else: - _logger.debug("HTTP sessions stored in Redis with prefix '%s' on " - "%s:%s", prefix or '', host, port) + _logger.debug( + "HTTP sessions stored in Redis with prefix '%s' on " "%s:%s", + prefix or "", + host, + port, + ) http.Root.session_store = session_store http.session_gc = session_gc diff --git a/session_redis/strtobool.py b/session_redis/strtobool.py new file mode 100644 index 0000000..44d1eb2 --- /dev/null +++ b/session_redis/strtobool.py @@ -0,0 +1,21 @@ +_MAP = { + 'y': True, + 'yes': True, + 't': True, + 'true': True, + 'on': True, + '1': True, + 'n': False, + 'no': False, + 'f': False, + 'false': False, + 'off': False, + '0': False +} + + +def strtobool(value): + try: + return _MAP[str(value).lower()] + except KeyError: + raise ValueError('"{}" is not a valid bool value'.format(value))