|
|
# -*- coding: utf-8 -*- # Copyright 2017 Camptocamp (http://www.camptocamp.com). # @author Guewen Baconnier <guewen.baconnier@camptocamp.com> # Copyright 2017 Akretion (http://www.akretion.com). # @author Sébastien BEAU <sebastien.beau@akretion.com> # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging import os import threading import re import json
from distutils.util import strtobool from openerp.netsvc import ColoredFormatter
_logger = logging.getLogger(__name__)
try: from pythonjsonlogger.jsonlogger import JsonFormatter, RESERVED_ATTRS except ImportError: JsonFormatter = object _logger.debug("Cannot 'import pythonjsonlogger'.")
def is_true(strval): return bool(strtobool(strval or '0'.lower()))
# The following regex are use to extract information from native odoo log # We struct is the following # {name_of_the_log : [regex, formatter, extra_vals]} # The extra_vals "dict" will be merged into the jsonlogger if the regex match # In order to make understandable the regex please add an string example that # match REGEX = { 'openerp.addons.base.ir.ir_cron': [ # "cron.object.execute('db', 1, '*', u'base.action.rule', u'_check')" (r"cron\.object\.execute\('.+'(?P<cron_model>[\w.]+).+" r"'(?P<cron_method>[\w.]+)'\)", {}, {'cron_running': True}),
# "0.016s (base.action.rule, _check)" (r"(?P<cron_duration_second>[\d.]+)s \(" r"(?P<cron_model>[\w.]+), (?P<cron_method>[\w.]+)", {'cron_duration_second': float}, {'cron_running': False, 'cron_status': 'succeeded'}),
# Call of self.pool.get('base.action.rule')._check( # cr, uid, *u'()') failed in Job 43 (r"Call of self\.pool\.get\('(?P<cron_model>[\w.]+)'\)" r".(?P<cron_method>[\w.]+)", {}, {'cron_running': False, 'cron_status': 'failed'}), ], }
class OdooJsonFormatter(JsonFormatter):
def add_fields(self, log_record, record, message_dict): record.pid = os.getpid() record.dbname = getattr(threading.currentThread(), 'dbname', '?') _super = super(OdooJsonFormatter, self) res = _super.add_fields(log_record, record, message_dict) if log_record['name'] in REGEX: for regex, formatters, extra_vals in REGEX[log_record['name']]: match = re.match(regex, log_record['message']) if match: vals = match.groupdict() for key, func in formatters.items(): vals[key] = func(vals[key]) log_record.update(vals) if extra_vals: log_record.update(extra_vals) return res
class OdooJsonDevFormatter(ColoredFormatter):
def format(self, record): response = super(OdooJsonDevFormatter, self).format(record) extra = {} reserved_attrs = list(RESERVED_ATTRS) + ["dbname", "pid"] for key, value in record.__dict__.items(): if (key not in reserved_attrs and not (hasattr(key, "startswith") and key.startswith('_'))): extra[key] = value if extra: response += " extra: " + json.dumps( extra, indent=4, sort_keys=True) return response
if is_true(os.environ.get('ODOO_LOGGING_JSON')): format = ('%(asctime)s %(pid)s %(levelname)s' '%(dbname)s %(name)s: %(message)s') formatter = OdooJsonFormatter(format) logging.getLogger().handlers[0].formatter = formatter elif is_true(os.environ.get('ODOO_LOGGING_JSON_DEV')): format = ('%(asctime)s %(pid)s %(levelname)s' '%(dbname)s %(name)s: %(message)s') formatter = OdooJsonDevFormatter(format) logging.getLogger().handlers[0].formatter = formatter
|