Skip to content

Commit

Permalink
Merge PR #2254 into 14.0
Browse files Browse the repository at this point in the history
Signed-off-by sebastienbeau
  • Loading branch information
OCA-git-bot committed Sep 20, 2022
2 parents 1e62177 + 4c413fa commit a82db86
Show file tree
Hide file tree
Showing 17 changed files with 716 additions and 349 deletions.
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ odoorpc
openpyxl
openupgradelib
pysftp
raven
sentry_sdk
unidecode
74 changes: 54 additions & 20 deletions sentry/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ Odoo.
.. contents::
:local:

Installation
============

The module can be installed just like any other Odoo module, by adding the
module's directory to Odoo *addons_path*. In order for the module to correctly
wrap the Odoo WSGI application, it also needs to be loaded as a server-wide
module. This can be done with the ``server_wide_modules`` parameter in your
Odoo config file or with the ``--load`` command-line parameter.

This module additionally requires the sentry-sdk Python package to be available on
the system. It can be installed using pip::

pip install sentry-sdk

Configuration
=============

Expand Down Expand Up @@ -67,16 +81,6 @@ configuration file:
odoo.exceptions.Warning,
odoo.exceptions.except_orm``

``sentry_processors`` A string of comma-separated processor classes which will be applied ``raven.processors.SanitizePasswordsProcessor,
on an event before sending it to Sentry. odoo.addons.sentry.logutils.SanitizeOdooCookiesProcessor``

``sentry_transport`` Transport class which will be used to send events to Sentry. ``threaded``
Possible values: *threaded*: spawns an async worker for processing
messages, *synchronous*: a synchronous blocking transport;
*requests_threaded*: an asynchronous transport using the *requests*
library; *requests_synchronous* - blocking transport using the
*requests* library.

``sentry_include_context`` If enabled, additional context data will be extracted from current ``True``
HTTP request and user session (if available). This has no effect
for Cron jobs, as no request/session is available inside a Cron job.
Expand All @@ -94,11 +98,14 @@ configuration file:
============================= ==================================================================== ==========================================================

Other `client arguments
<https://docs.sentry.io/clients/python/advanced/#client-arguments>`_ can be
<https://docs.sentry.io/platforms/python/configuration/>`_ can be
configured by prepending the argument name with *sentry_* in your Odoo config
file. Currently supported additional client arguments are: ``install_sys_hook,
include_paths, exclude_paths, machine, auto_log_stacks, capture_locals,
string_max_length, list_max_length, site, include_versions, environment``.
file. Currently supported additional client arguments are: ``with_locals,
max_breadcrumbs, release, environment, server_name, shutdown_timeout,
in_app_include, in_app_exclude, default_integrations, dist, sample_rate,
send_default_pii, http_proxy, https_proxy, request_bodies, debug,
attach_stacktrace, ca_certs, propagate_traces, traces_sample_rate,
auto_enabling_integrations``.

Example Odoo configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -110,14 +117,15 @@ Below is an example of Odoo configuration file with *Odoo Sentry* options::
sentry_enabled = true
sentry_logging_level = warn
sentry_exclude_loggers = werkzeug
sentry_ignore_exceptions = odoo.exceptions.AccessDenied,odoo.exceptions.AccessError,odoo.exceptions.MissingError,odoo.exceptions.RedirectWarning,odoo.exceptions.UserError,odoo.exceptions.ValidationError,odoo.exceptions.Warning,odoo.exceptions.except_orm
sentry_processors = raven.processors.SanitizePasswordsProcessor,odoo.addons.sentry.logutils.SanitizeOdooCookiesProcessor
sentry_transport = threaded
sentry_ignore_exceptions = odoo.exceptions.AccessDenied,
odoo.exceptions.AccessError,odoo.exceptions.MissingError,
odoo.exceptions.RedirectWarning,odoo.exceptions.UserError,
odoo.exceptions.ValidationError,odoo.exceptions.Warning,
odoo.exceptions.except_orm
sentry_include_context = true
sentry_environment = production
sentry_auto_log_stacks = false
sentry_odoo_dir = /home/odoo/odoo/
sentry_release = 1.3.2
sentry_odoo_dir = /home/odoo/odoo/

Usage
=====
Expand All @@ -127,7 +135,7 @@ above the configured Sentry logging level, no additional actions are necessary.

.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/149/13.0
:target: https://runbot.odoo-community.org/runbot/149/14.0

Known issues / Roadmap
======================
Expand Down Expand Up @@ -163,6 +171,7 @@ Authors
* Mohammed Barsi
* Versada
* Nicolas JEUDY
* Vauxoo

Contributors
~~~~~~~~~~~~
Expand All @@ -172,6 +181,11 @@ Contributors
* Naglis Jonaitis <[email protected]>
* Atte Isopuro <[email protected]>

Other credits
~~~~~~~~~~~~~

* Vauxoo

Maintainers
~~~~~~~~~~~

Expand All @@ -185,6 +199,26 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

.. |maintainer-barsi| image:: https://github.com/barsi.png?size=40px
:target: https://github.com/barsi
:alt: barsi
.. |maintainer-naglis| image:: https://github.com/naglis.png?size=40px
:target: https://github.com/naglis
:alt: naglis
.. |maintainer-versada| image:: https://github.com/versada.png?size=40px
:target: https://github.com/versada
:alt: versada
.. |maintainer-moylop260| image:: https://github.com/moylop260.png?size=40px
:target: https://github.com/moylop260
:alt: moylop260
.. |maintainer-fernandahf| image:: https://github.com/fernandahf.png?size=40px
:target: https://github.com/fernandahf
:alt: fernandahf

Current `maintainers <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-barsi| |maintainer-naglis| |maintainer-versada| |maintainer-moylop260| |maintainer-fernandahf|

This module is part of the `OCA/server-tools <https://github.com/OCA/server-tools/tree/14.0/sentry>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
87 changes: 1 addition & 86 deletions sentry/__init__.py
Original file line number Diff line number Diff line change
@@ -1,86 +1 @@
# Copyright 2016-2017 Versada <https://versada.eu/>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import logging

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

from . import const
from .logutils import LoggerNameFilter, OdooSentryHandler

from collections import abc

_logger = logging.getLogger(__name__)
HAS_RAVEN = True
try:
import raven
from raven.middleware import Sentry
except ImportError:
HAS_RAVEN = False
_logger.debug('Cannot import "raven". Please make sure it is installed.')


def get_odoo_commit(odoo_dir):
"""Attempts to get Odoo git commit from :param:`odoo_dir`."""
if not odoo_dir:
return
try:
return raven.fetch_git_sha(odoo_dir)
except raven.exceptions.InvalidGitRepository:
_logger.debug('Odoo directory: "%s" not a valid git repository', odoo_dir)


def initialize_raven(config, client_cls=None):
"""
Setup an instance of :class:`raven.Client`.
:param config: Sentry configuration
:param client: class used to instantiate the raven client.
"""
enabled = config.get("sentry_enabled", False)
if not (HAS_RAVEN and enabled):
return

if config.get("sentry_odoo_dir") and config.get("sentry_release"):
_logger.debug(
"Both sentry_odoo_dir and sentry_release defined, choosing sentry_release"
)
options = {}
for option in const.get_sentry_options():
value = config.get("sentry_%s" % option.key, option.default)
if isinstance(option.converter, abc.Callable):
value = option.converter(value)
options[option.key] = value

level = config.get("sentry_logging_level", const.DEFAULT_LOG_LEVEL)
exclude_loggers = const.split_multiple(
config.get("sentry_exclude_loggers", const.DEFAULT_EXCLUDE_LOGGERS)
)
if level not in const.LOG_LEVEL_MAP:
level = const.DEFAULT_LOG_LEVEL

if not options.get("release"):
options["release"] = config.get(
"sentry_release", get_odoo_commit(config.get("sentry_odoo_dir"))
)

client_cls = client_cls or raven.Client
client = client_cls(**options)
handler = OdooSentryHandler(
config.get("sentry_include_context", True),
client=client,
level=const.LOG_LEVEL_MAP[level],
)
if exclude_loggers:
handler.addFilter(
LoggerNameFilter(exclude_loggers, name="sentry.logger.filter")
)
raven.conf.setup_logging(handler)
wsgi_server.application = Sentry(wsgi_server.application, client=client)

client.captureMessage("Starting Odoo Server")
return client


sentry_client = initialize_raven(odoo_config)
from .hooks import post_load
17 changes: 13 additions & 4 deletions sentry/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,25 @@
{
"name": "Sentry",
"summary": "Report Odoo errors to Sentry",
"version": "14.0.1.0.2",
"version": "14.0.1.1.0",
"category": "Extra Tools",
"website": "https://github.com/OCA/server-tools",
"author": "Mohammed Barsi,"
"Versada,"
"Nicolas JEUDY,"
"Odoo Community Association (OCA)",
"Odoo Community Association (OCA),"
"Vauxoo",
"maintainers": ["barsi", "naglis", "versada", "moylop260", "fernandahf"],
"license": "AGPL-3",
"application": False,
"installable": True,
"external_dependencies": {"python": ["raven"]},
"depends": ["base"],
"external_dependencies": {
"python": [
"sentry_sdk",
]
},
"depends": [
"base",
],
"post_load": "post_load",
}
101 changes: 68 additions & 33 deletions sentry/const.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
# Copyright 2016-2017 Versada <https://versada.eu/>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import collections
import logging

import odoo.loglevels
from sentry_sdk import HttpTransport
from sentry_sdk.consts import DEFAULT_OPTIONS
from sentry_sdk.integrations.logging import LoggingIntegration

_logger = logging.getLogger(__name__)
try:
import raven
from raven.conf import defaults
except ImportError:
_logger.debug('Cannot import "raven". Please make sure it is installed.')
import odoo.loglevels


def split_multiple(string, delimiter=",", strip_chars=None):
Expand All @@ -21,6 +17,18 @@ def split_multiple(string, delimiter=",", strip_chars=None):
return [v.strip(strip_chars) for v in string.split(delimiter)]


def to_int_if_defined(value):
if value == "" or value is None:
return
return int(value)


def to_float_if_defined(value):
if value == "" or value is None:
return
return float(value)


SentryOption = collections.namedtuple("SentryOption", ["key", "default", "converter"])

# Mapping of Odoo logging level -> Python stdlib logging library log level.
Expand All @@ -43,43 +51,70 @@ def split_multiple(string, delimiter=",", strip_chars=None):
]
DEFAULT_IGNORED_EXCEPTIONS = ",".join(ODOO_USER_EXCEPTIONS)

PROCESSORS = (
"raven.processors.SanitizePasswordsProcessor",
"odoo.addons.sentry.logutils.SanitizeOdooCookiesProcessor",
)
DEFAULT_PROCESSORS = ",".join(PROCESSORS)

EXCLUDE_LOGGERS = ("werkzeug",)
DEFAULT_EXCLUDE_LOGGERS = ",".join(EXCLUDE_LOGGERS)

DEFAULT_ENVIRONMENT = "develop"

DEFAULT_TRANSPORT = "threaded"


def select_transport(name=DEFAULT_TRANSPORT):
return {
"requests_synchronous": raven.transport.RequestsHTTPTransport,
"requests_threaded": raven.transport.ThreadedRequestsHTTPTransport,
"synchronous": raven.transport.HTTPTransport,
"threaded": raven.transport.ThreadedHTTPTransport,
}.get(name, DEFAULT_TRANSPORT)
"threaded": HttpTransport,
}.get(name, HttpTransport)


def get_sentry_logging(level=DEFAULT_LOG_LEVEL):
if level not in LOG_LEVEL_MAP:
level = DEFAULT_LOG_LEVEL

return LoggingIntegration(level=LOG_LEVEL_MAP[level], event_level=logging.WARNING)


def get_sentry_options():
return [
SentryOption("dsn", "", str.strip),
SentryOption("install_sys_hook", False, None),
SentryOption("transport", DEFAULT_TRANSPORT, select_transport),
SentryOption("include_paths", "", split_multiple),
SentryOption("exclude_paths", "", split_multiple),
SentryOption("machine", defaults.NAME, None),
SentryOption("auto_log_stacks", defaults.AUTO_LOG_STACKS, None),
SentryOption("capture_locals", defaults.CAPTURE_LOCALS, None),
SentryOption("string_max_length", defaults.MAX_LENGTH_STRING, None),
SentryOption("list_max_length", defaults.MAX_LENGTH_LIST, None),
SentryOption("site", None, None),
SentryOption("include_versions", True, None),
SentryOption("transport", DEFAULT_OPTIONS["transport"], select_transport),
SentryOption("logging_level", DEFAULT_LOG_LEVEL, get_sentry_logging),
SentryOption("with_locals", DEFAULT_OPTIONS["with_locals"], None),
SentryOption(
"max_breadcrumbs", DEFAULT_OPTIONS["max_breadcrumbs"], to_int_if_defined
),
SentryOption("release", DEFAULT_OPTIONS["release"], None),
SentryOption("environment", DEFAULT_OPTIONS["environment"], None),
SentryOption("server_name", DEFAULT_OPTIONS["server_name"], None),
SentryOption("shutdown_timeout", DEFAULT_OPTIONS["shutdown_timeout"], None),
SentryOption("integrations", DEFAULT_OPTIONS["integrations"], None),
SentryOption(
"in_app_include", DEFAULT_OPTIONS["in_app_include"], split_multiple
),
SentryOption(
"in_app_exclude", DEFAULT_OPTIONS["in_app_exclude"], split_multiple
),
SentryOption(
"default_integrations", DEFAULT_OPTIONS["default_integrations"], None
),
SentryOption("dist", DEFAULT_OPTIONS["dist"], None),
SentryOption(
"sample_rate", DEFAULT_OPTIONS["sample_rate"], to_float_if_defined
),
SentryOption("send_default_pii", DEFAULT_OPTIONS["send_default_pii"], None),
SentryOption("http_proxy", DEFAULT_OPTIONS["http_proxy"], None),
SentryOption("https_proxy", DEFAULT_OPTIONS["https_proxy"], None),
SentryOption("ignore_exceptions", DEFAULT_IGNORED_EXCEPTIONS, split_multiple),
SentryOption("processors", DEFAULT_PROCESSORS, split_multiple),
SentryOption("environment", None, None),
SentryOption("release", None, None),
SentryOption("request_bodies", DEFAULT_OPTIONS["request_bodies"], None),
SentryOption("attach_stacktrace", DEFAULT_OPTIONS["attach_stacktrace"], None),
SentryOption("ca_certs", DEFAULT_OPTIONS["ca_certs"], None),
SentryOption("propagate_traces", DEFAULT_OPTIONS["propagate_traces"], None),
SentryOption(
"traces_sample_rate",
DEFAULT_OPTIONS["traces_sample_rate"],
to_float_if_defined,
),
SentryOption(
"auto_enabling_integrations",
DEFAULT_OPTIONS["auto_enabling_integrations"],
None,
),
]
Loading

0 comments on commit a82db86

Please sign in to comment.