Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions sentry/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,36 @@ your Odoo config 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``.

Environment variables
---------------------

Every option above can also be set through an environment variable,
named after the option it carries with an ``ODOO_`` prefix:
``sentry_dsn`` becomes ``ODOO_SENTRY_DSN``,
``sentry_traces_sample_rate`` becomes
``ODOO_SENTRY_TRACES_SAMPLE_RATE``. This is the same shape *queue_job*
uses for ``ODOO_QUEUE_JOB_*``.

Both sources stay supported and are merged per option, the environment
winning where the two disagree. An existing ``[sentry]`` section keeps
working as it is, and a deployment that would rather not ship a
configuration file at all can set everything through the environment
instead.

The ``ODOO_`` prefix is what keeps these apart from the ``SENTRY_*``
variables *sentry-sdk* reads on its own. ``SENTRY_DSN`` addresses
whichever process the library runs in, so it is left alone rather than
reused here.

Two reasons a container may prefer the environment:

- Odoo reads only ``[options]`` from its configuration file, and logs
``unknown option ... in the config file`` for anything there it does
not know. The ``[sentry]`` section is quiet, but it exists only
because these options had to leave ``[options]`` for that reason.
- ``odoo-bin -s`` rewrites the configuration file out of its own
options, which drops every other section, ``[sentry]`` included.

Example Odoo configuration
--------------------------

Expand Down Expand Up @@ -100,6 +130,24 @@ options:
sentry_odoo_dir = /home/odoo/odoo/
sentry_startup_message = true

Example environment
-------------------

The same setup, with ``server_wide_modules`` left in the configuration
file because that one is Odoo's own option:

::

ODOO_SENTRY_DSN=https://<public_key>:<secret_key>@sentry.example.com/<project id>
ODOO_SENTRY_ENABLED=true
ODOO_SENTRY_LOGGING_LEVEL=warn
ODOO_SENTRY_EXCLUDE_LOGGERS=werkzeug
ODOO_SENTRY_INCLUDE_CONTEXT=true
ODOO_SENTRY_ENVIRONMENT=production
ODOO_SENTRY_RELEASE=1.3.2
ODOO_SENTRY_ODOO_DIR=/home/odoo/odoo/
ODOO_SENTRY_STARTUP_MESSAGE=true

Usage
=====

Expand Down
52 changes: 52 additions & 0 deletions sentry/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import collections
import logging
import os

from sentry_sdk import HttpTransport
from sentry_sdk.consts import DEFAULT_OPTIONS
Expand Down Expand Up @@ -29,6 +30,26 @@ def to_float_if_defined(value):
return float(value)


TRUTHY_VALUES = ("1", "on", "true", "yes")


def to_bool(value, default=False):
"""Read a boolean out of a value that a configuration file or an environment
variable can only deliver as a string.

``bool("False")`` is ``True``, so a plain truth test on a string turns an option
the user switched off back on.
"""
if value is None:
return default
if isinstance(value, str):
value = value.strip().lower()
# An option present but left empty says nothing, so it is not an answer of
# "off": keep the default the caller asked for.
return default if not value else value in TRUTHY_VALUES
return bool(value)


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

# Mapping of Odoo logging level -> Python stdlib logging library log level.
Expand Down Expand Up @@ -132,3 +153,34 @@ def get_sentry_options():
)

return res


# ENV_OPTION_PREFIX is what the options are already called in the configuration
# file, so ODOO_SENTRY_DSN and sentry_dsn name the same option and neither source
# needs a translation table.
ENV_PREFIX = "ODOO_"
ENV_OPTION_PREFIX = "SENTRY_"


def get_options_from_env(environ=None):
"""Return the options set through environment variables.

Keys come back in the shape the configuration file uses, so the caller merges
both sources without caring where each value came from: ``ODOO_SENTRY_DSN``
becomes ``sentry_dsn``. Every option is covered, including the ones this module
does not name itself, because the prefix is what selects them rather than a
list that would have to be kept up to date.

The ``ODOO_`` prefix follows ``queue_job``, which reads ``ODOO_QUEUE_JOB_*``
this way, and keeps these apart from the ``SENTRY_*`` variables ``sentry-sdk``
reads on its own. ``SENTRY_DSN`` addresses whichever process the library runs
in, so reusing it here would point Odoo at a DSN meant for something else.
"""
if environ is None:
environ = os.environ
prefix = f"{ENV_PREFIX}{ENV_OPTION_PREFIX}"
return {
name[len(ENV_PREFIX) :].lower(): value
for name, value in environ.items()
if name.startswith(prefix)
}
15 changes: 12 additions & 3 deletions sentry/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,13 @@ def initialize_sentry(config):
:param config: Sentry configuration
:param client: class used to instantiate the sentry_sdk client.
"""
enabled = config.get("sentry_enabled", False)
# An environment variable wins over the file, the precedence queue_job's
# jobrunner has been applying to ODOO_QUEUE_JOB_* for years. Both sources stay
# supported, so an existing [sentry] section keeps working untouched, and a
# deployment that would rather not carry a configuration file at all can set
# every option through the environment instead.
config = {**config, **const.get_options_from_env()}
enabled = const.to_bool(config.get("sentry_enabled", False))
if not (HAS_SENTRY_SDK and enabled):
return
_logger.info("Initializing sentry...")
Expand Down Expand Up @@ -149,7 +155,10 @@ def initialize_sentry(config):

client = sentry_sdk.init(**options)

sentry_sdk.set_tag("include_context", config.get("sentry_include_context", True))
sentry_sdk.set_tag(
"include_context",
const.to_bool(config.get("sentry_include_context", True), default=True),
)

if exclude_loggers:
for item in exclude_loggers:
Expand Down Expand Up @@ -179,7 +188,7 @@ def sentry_application_call(self, environ, start_response):

odoo.http.Application.__call__ = sentry_application_call

if config.get("sentry_startup_message", True) not in (False, "False", "false"):
if const.to_bool(config.get("sentry_startup_message", True), default=True):
with sentry_sdk.new_scope() as scope:
scope.set_extra("debug", False)
sentry_sdk.capture_message("Starting Odoo Server", "info")
Expand Down
41 changes: 41 additions & 0 deletions sentry/readme/CONFIGURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,32 @@ be configured by prepending the argument name with *sentry\_* in your
Odoo config 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`.

## Environment variables

Every option above can also be set through an environment variable, named after
the option it carries with an `ODOO_` prefix: `sentry_dsn` becomes
`ODOO_SENTRY_DSN`, `sentry_traces_sample_rate` becomes
`ODOO_SENTRY_TRACES_SAMPLE_RATE`. This is the same shape *queue_job* uses for
`ODOO_QUEUE_JOB_*`.

Both sources stay supported and are merged per option, the environment winning
where the two disagree. An existing `[sentry]` section keeps working as it is,
and a deployment that would rather not ship a configuration file at all can set
everything through the environment instead.

The `ODOO_` prefix is what keeps these apart from the `SENTRY_*` variables
*sentry-sdk* reads on its own. `SENTRY_DSN` addresses whichever process the
library runs in, so it is left alone rather than reused here.

Two reasons a container may prefer the environment:

- Odoo reads only `[options]` from its configuration file, and logs
`unknown option ... in the config file` for anything there it does not know.
The `[sentry]` section is quiet, but it exists only because these options had
to leave `[options]` for that reason.
- `odoo-bin -s` rewrites the configuration file out of its own options, which
drops every other section, `[sentry]` included.

## Example Odoo configuration

Below is an example of Odoo configuration file with *Odoo Sentry*
Expand All @@ -33,3 +59,18 @@ options:
sentry_release = 1.3.2
sentry_odoo_dir = /home/odoo/odoo/
sentry_startup_message = true

## Example environment

The same setup, with `server_wide_modules` left in the configuration file
because that one is Odoo's own option:

ODOO_SENTRY_DSN=https://<public_key>:<secret_key>@sentry.example.com/<project id>
ODOO_SENTRY_ENABLED=true
ODOO_SENTRY_LOGGING_LEVEL=warn
ODOO_SENTRY_EXCLUDE_LOGGERS=werkzeug
ODOO_SENTRY_INCLUDE_CONTEXT=true
ODOO_SENTRY_ENVIRONMENT=production
ODOO_SENTRY_RELEASE=1.3.2
ODOO_SENTRY_ODOO_DIR=/home/odoo/odoo/
ODOO_SENTRY_STARTUP_MESSAGE=true
81 changes: 63 additions & 18 deletions sentry/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -382,17 +382,19 @@ <h1>Sentry</h1>
<ul class="simple">
<li><a class="reference internal" href="#installation" id="toc-entry-1">Installation</a></li>
<li><a class="reference internal" href="#configuration" id="toc-entry-2">Configuration</a><ul>
<li><a class="reference internal" href="#example-odoo-configuration" id="toc-entry-3">Example Odoo configuration</a></li>
<li><a class="reference internal" href="#environment-variables" id="toc-entry-3">Environment variables</a></li>
<li><a class="reference internal" href="#example-odoo-configuration" id="toc-entry-4">Example Odoo configuration</a></li>
<li><a class="reference internal" href="#example-environment" id="toc-entry-5">Example environment</a></li>
</ul>
</li>
<li><a class="reference internal" href="#usage" id="toc-entry-4">Usage</a></li>
<li><a class="reference internal" href="#known-issues-roadmap" id="toc-entry-5">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-6">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-7">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-8">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-9">Contributors</a></li>
<li><a class="reference internal" href="#other-credits" id="toc-entry-10">Other credits</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-11">Maintainers</a></li>
<li><a class="reference internal" href="#usage" id="toc-entry-6">Usage</a></li>
<li><a class="reference internal" href="#known-issues-roadmap" id="toc-entry-7">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-8">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-9">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-10">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-11">Contributors</a></li>
<li><a class="reference internal" href="#other-credits" id="toc-entry-12">Other credits</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-13">Maintainers</a></li>
</ul>
</li>
</ul>
Expand Down Expand Up @@ -422,8 +424,35 @@ <h2><a class="toc-backref" href="#toc-entry-2">Configuration</a></h2>
your Odoo config file. Currently supported additional client arguments
are:
<tt class="docutils literal">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</tt>.</p>
<div class="section" id="environment-variables">
<h3><a class="toc-backref" href="#toc-entry-3">Environment variables</a></h3>
<p>Every option above can also be set through an environment variable,
named after the option it carries with an <tt class="docutils literal">ODOO_</tt> prefix:
<tt class="docutils literal">sentry_dsn</tt> becomes <tt class="docutils literal">ODOO_SENTRY_DSN</tt>,
<tt class="docutils literal">sentry_traces_sample_rate</tt> becomes
<tt class="docutils literal">ODOO_SENTRY_TRACES_SAMPLE_RATE</tt>. This is the same shape <em>queue_job</em>
uses for <tt class="docutils literal">ODOO_QUEUE_JOB_*</tt>.</p>
<p>Both sources stay supported and are merged per option, the environment
winning where the two disagree. An existing <tt class="docutils literal">[sentry]</tt> section keeps
working as it is, and a deployment that would rather not ship a
configuration file at all can set everything through the environment
instead.</p>
<p>The <tt class="docutils literal">ODOO_</tt> prefix is what keeps these apart from the <tt class="docutils literal">SENTRY_*</tt>
variables <em>sentry-sdk</em> reads on its own. <tt class="docutils literal">SENTRY_DSN</tt> addresses
whichever process the library runs in, so it is left alone rather than
reused here.</p>
<p>Two reasons a container may prefer the environment:</p>
<ul class="simple">
<li>Odoo reads only <tt class="docutils literal">[options]</tt> from its configuration file, and logs
<tt class="docutils literal">unknown option ... in the config file</tt> for anything there it does
not know. The <tt class="docutils literal">[sentry]</tt> section is quiet, but it exists only
because these options had to leave <tt class="docutils literal">[options]</tt> for that reason.</li>
<li><tt class="docutils literal"><span class="pre">odoo-bin</span> <span class="pre">-s</span></tt> rewrites the configuration file out of its own
options, which drops every other section, <tt class="docutils literal">[sentry]</tt> included.</li>
</ul>
</div>
<div class="section" id="example-odoo-configuration">
<h3><a class="toc-backref" href="#toc-entry-3">Example Odoo configuration</a></h3>
<h3><a class="toc-backref" href="#toc-entry-4">Example Odoo configuration</a></h3>
<p>Below is an example of Odoo configuration file with <em>Odoo Sentry</em>
options:</p>
<pre class="literal-block">
Expand All @@ -448,16 +477,32 @@ <h3><a class="toc-backref" href="#toc-entry-3">Example Odoo configuration</a></h
sentry_startup_message = true
</pre>
</div>
<div class="section" id="example-environment">
<h3><a class="toc-backref" href="#toc-entry-5">Example environment</a></h3>
<p>The same setup, with <tt class="docutils literal">server_wide_modules</tt> left in the configuration
file because that one is Odoo’s own option:</p>
<pre class="literal-block">
ODOO_SENTRY_DSN=https://&lt;public_key&gt;:&lt;secret_key&gt;&#64;sentry.example.com/&lt;project id&gt;
ODOO_SENTRY_ENABLED=true
ODOO_SENTRY_LOGGING_LEVEL=warn
ODOO_SENTRY_EXCLUDE_LOGGERS=werkzeug
ODOO_SENTRY_INCLUDE_CONTEXT=true
ODOO_SENTRY_ENVIRONMENT=production
ODOO_SENTRY_RELEASE=1.3.2
ODOO_SENTRY_ODOO_DIR=/home/odoo/odoo/
ODOO_SENTRY_STARTUP_MESSAGE=true
</pre>
</div>
</div>
<div class="section" id="usage">
<h2><a class="toc-backref" href="#toc-entry-4">Usage</a></h2>
<h2><a class="toc-backref" href="#toc-entry-6">Usage</a></h2>
<p>Once configured and installed, the module will report any logging event
at and above the configured Sentry logging level, no additional actions
are necessary.</p>
<p><a class="reference external image-reference" href="https://runbot.odoo-community.org/runbot/149/14.0"><img alt="Try me on Runbot" src="https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas" /></a></p>
</div>
<div class="section" id="known-issues-roadmap">
<h2><a class="toc-backref" href="#toc-entry-5">Known issues / Roadmap</a></h2>
<h2><a class="toc-backref" href="#toc-entry-7">Known issues / Roadmap</a></h2>
<ul class="simple">
<li><strong>No database separation</strong> – This module functions by intercepting
all Odoo logging records in a running Odoo process. This means that
Expand All @@ -473,17 +518,17 @@ <h2><a class="toc-backref" href="#toc-entry-5">Known issues / Roadmap</a></h2>
</ul>
</div>
<div class="section" id="bug-tracker">
<h2><a class="toc-backref" href="#toc-entry-6">Bug Tracker</a></h2>
<h2><a class="toc-backref" href="#toc-entry-8">Bug Tracker</a></h2>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/server-tools/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/server-tools/issues/new?body=module:%20sentry%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h2><a class="toc-backref" href="#toc-entry-7">Credits</a></h2>
<h2><a class="toc-backref" href="#toc-entry-9">Credits</a></h2>
<div class="section" id="authors">
<h3><a class="toc-backref" href="#toc-entry-8">Authors</a></h3>
<h3><a class="toc-backref" href="#toc-entry-10">Authors</a></h3>
<ul class="simple">
<li>Mohammed Barsi</li>
<li>Versada</li>
Expand All @@ -492,7 +537,7 @@ <h3><a class="toc-backref" href="#toc-entry-8">Authors</a></h3>
</ul>
</div>
<div class="section" id="contributors">
<h3><a class="toc-backref" href="#toc-entry-9">Contributors</a></h3>
<h3><a class="toc-backref" href="#toc-entry-11">Contributors</a></h3>
<ul class="simple">
<li>Mohammed Barsi &lt;<a class="reference external" href="mailto:barsintod&#64;gmail.com">barsintod&#64;gmail.com</a>&gt;</li>
<li>Andrius Preimantas &lt;<a class="reference external" href="mailto:andrius&#64;versada.eu">andrius&#64;versada.eu</a>&gt;</li>
Expand All @@ -506,13 +551,13 @@ <h3><a class="toc-backref" href="#toc-entry-9">Contributors</a></h3>
</ul>
</div>
<div class="section" id="other-credits">
<h3><a class="toc-backref" href="#toc-entry-10">Other credits</a></h3>
<h3><a class="toc-backref" href="#toc-entry-12">Other credits</a></h3>
<ul class="simple">
<li>Vauxoo</li>
</ul>
</div>
<div class="section" id="maintainers">
<h3><a class="toc-backref" href="#toc-entry-11">Maintainers</a></h3>
<h3><a class="toc-backref" href="#toc-entry-13">Maintainers</a></h3>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
Expand Down
Loading
Loading