Metadata-Version: 2.1
Name: odoo-addon-sentry_client
Version: 18.0.1.0.0.3
Requires-Python: >=3.10
Requires-Dist: odoo==18.0.*
Summary: Capture Odoo web-client JS errors in Sentry, with tiered opt-in for tracing and session replay
Home-page: https://github.com/OCA/server-tools
License: AGPL-3
Author: Ledoent, Odoo Community Association (OCA)
Author-email: support@odoo-community.org
Classifier: Programming Language :: Python
Classifier: Framework :: Odoo
Classifier: Framework :: Odoo :: 18.0
Classifier: License :: OSI Approved :: GNU Affero General Public License v3
Description-Content-Type: text/x-rst

.. image:: https://odoo-community.org/readme-banner-image
   :target: https://odoo-community.org/get-involved?utm_source=readme
   :alt: Odoo Community Association

====================
Sentry — Browser SDK
====================

.. 
   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   !! This file is generated by oca-gen-addon-readme !!
   !! changes will be overwritten.                   !!
   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   !! source digest: sha256:aeafe18adcf6c82f2da1cda21ed088ccab53b477382226be115803a4494b0f6c
   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
    :target: https://odoo-community.org/page/development-status
    :alt: Beta
.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png
    :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
    :alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github
    :target: https://github.com/OCA/server-tools/tree/18.0/sentry_client
    :alt: OCA/server-tools
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
    :target: https://translation.odoo-community.org/projects/server-tools-18-0/server-tools-18-0-sentry_client
    :alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
    :target: https://runboat.odoo-community.org/builds?repo=OCA/server-tools&target_branch=18.0
    :alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

Capture uncaught JS errors and unhandled promise rejections in the Odoo
web client to Sentry, with optional Performance Monitoring
(BrowserTracing), Session Replay, Browser CPU Profiling, and Console-log
capture tiers behind explicit opt-in toggles.

The Sentry browser SDK ships **vendored inside the module** — no
external CDN call, air-gapped friendly out of the box.

**Standalone:** works on its own. Reads DSN / release / environment from
the ``sentry_*`` options in ``odoo.conf``. Captures browser-side errors
only.

**Better together with ``sentry``:** install alongside the server-side
```sentry`` <../sentry>`__ module to cluster client and server errors
for the same user / release / environment into one Sentry issue. Both
modules share the same ``sentry_*`` config options by convention — fill
them in once and client + server events land in the same Sentry project.

Each tier above Tier 0 is **off by default** and surfaces an in-form
warning about its perf cost when enabled. Sample rates are sliders so
admins can dial behaviour without a server restart. Individual users can
opt out of session replay via their own preferences page.

**Table of contents**

.. contents::
   :local:

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

1. Pick where the DSN comes from
--------------------------------

There are two ways to point the browser SDK at a Sentry project. Use
**one**:

**(a) Recommended — separate browser DSN via the Settings UI.** Sentry's
own guidance is one project per platform: a Python project for backend
errors and a JavaScript-Browser project for client-side errors. Set the
dedicated browser DSN under **Settings → General Settings → Sentry
Browser Monitoring → Connection**:

+-----------------+----------------------------------------------------------+-------------------------+
| Field           | Example                                                  | Notes                   |
+=================+==========================================================+=========================+
| **Browser DSN** | ``https://<public_key>@sentry.example.com/<project_id>`` | Public DSN of the       |
|                 |                                                          | JavaScript project.     |
|                 |                                                          | Safe to embed in client |
|                 |                                                          | code per Sentry's docs. |
+-----------------+----------------------------------------------------------+-------------------------+
| **Environment** | ``production-web``                                       | Tags every browser      |
|                 |                                                          | event. May differ from  |
|                 |                                                          | the backend env tag.    |
+-----------------+----------------------------------------------------------+-------------------------+
| **Release**     | asset-bundle hash or deploy SHA                          | Tags every browser      |
|                 |                                                          | event. May differ from  |
|                 |                                                          | the Odoo Python         |
|                 |                                                          | release.                |
+-----------------+----------------------------------------------------------+-------------------------+

No Odoo restart required — changes take effect on the next page load.

**(b) Fallback — shared DSN via ``odoo.conf``.** If the Connection
fields above are left blank, the controller reads the same top-level
``sentry_*`` options the OCA server-side ``sentry`` module uses on the
18.0 series (the dedicated ``[sentry]`` section only exists from 19.0):

.. code:: ini

   [options]
   sentry_dsn = https://<public_key>@sentry.example.com/<project_id>
   sentry_release = 1.3.2
   sentry_environment = production

This path is convenient for single-project deployments that want both
backend Python events and browser JavaScript events going to the same
Sentry project. Editing ``odoo.conf`` requires an Odoo restart. A legacy
DSN with a secret (``https://key:secret@…``) is served to the browser
without the secret part.

The UI value always wins when both are set. Whichever source the DSN
comes from, the controller strips a legacy ``:<secret>`` component
before serving it — the browser only ever needs the public key — and the
Settings form refuses a Browser DSN that carries one.

2. Settings → General Settings → Sentry Browser Monitoring
----------------------------------------------------------

Each tier is independently toggleable:

Tier 0 — Capture browser errors (recommended default once a DSN is set)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Loads ``bundle.min.js`` (~30KB gzipped). Wires ``window.onerror`` and
``window.onunhandledrejection``. Sends events with the logged-in user's
id + email as ``Sentry.setUser(...)``.

Tier 1 — Performance monitoring
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Enables ``BrowserTracing``. Auto-instruments fetch / XHR, navigation
timing, and long-task observer. **Adds roughly 5–10% per-request
overhead at sample rate 1.0** plus extra bandwidth per traced request.
Recommended in production: ``0.05`` or below.

Tier 2 — Session replay
~~~~~~~~~~~~~~~~~~~~~~~

Enables ``@sentry/replay``. **Adds ~100KB to every page** and records
DOM mutations + console + network activity. Strongly recommend
``Healthy-session sample = 0.0`` and ``On-error sample = 1.0`` so
recording only kicks in for sessions that already hit an error.

Tier 3 — Optional extras
~~~~~~~~~~~~~~~~~~~~~~~~

- **User feedback widget** — adds a feedback button.
- **Browser CPU profiling** — captures JS Self-Profiling samples for
  traced transactions. Has its own sample-rate slider. **Requires the
  page to be served with a ``Document-Policy: js-profiling`` HTTP
  header.** See "Browser profiling — extra setup" below.
- **Console-log capture** — uploads ``console.log`` / ``console.warn``
  calls as Sentry Log entries. Spammy without filtering.

3. User preferences → Privacy — per-user session-replay opt-out
---------------------------------------------------------------

Each user can disable session replay for their own sessions, regardless
of the database-wide Tier 2 setting. The browser SDK still loads (the
bundle URL doesn't change), but the Replay integration is never
registered for the opted-out user — no DOM observer, no recording.

To enable: open the user's profile (top-right avatar → My Profile →
Preferences → Privacy) and check **Disable Sentry session replay**.

The toggle is self-writeable: users can manage it without administrator
help.

What leaves the server per user: events carry the numeric user id plus
the app categories of the user's groups (e.g. ``Sales,Accounting``) as
the ``odoo.category`` tag, cut to Sentry's 200-character tag limit. No
group names, email or display name are sent; replay masking covers all
text, inputs and media by default.

4. Backend errors and OWL component context
-------------------------------------------

In the backend (``/odoo/*``) Odoo's error service already catches every
window error and unhandled rejection, so the module registers one
``error_handlers`` entry and turns the SDK's own global handlers and
callback wrappers (``GlobalHandlers``, ``BrowserApiErrors``) off there.
Each crash is reported once, and OWL component crashes carry two extra
fields:

- ``tags.owl = true``
- ``extra.component_tree`` — the OWL component path of the failing
  render

Server-side and transport errors (``RPCError``, including session
expiry, ``ConnectionLostError``, ``ConnectionAbortedError``,
``RequestEntityTooLargeError``) are not reported from the browser — the
OCA ``sentry`` module already reports the server-side ones — they only
leave an ``odoo.rpc`` breadcrumb on the next browser event. When Tier 2
replay is on, a server error still uploads the buffered replay, so the
server-side event has a recording to link to through the trace
propagated on the request. Odoo's standard *"Oops!"* dialog still shows
as before. No configuration needed. Portal and website pages have no
error service, so the SDK's global handlers stay on there.

Browser profiling — extra setup
-------------------------------

The JS Self-Profiling API requires the browser to receive a permission
header on the document HTML response:

::

   Document-Policy: js-profiling

Odoo's default web responses do not emit this header. You'll need to add
it at your reverse proxy. nginx example:

.. code:: nginx

   location /odoo {
       proxy_pass http://odoo:8069;
       add_header Document-Policy "js-profiling";
   }

Without the header, the Profiling integration registers cleanly and
sends profile payloads, but they will be empty — no client-side error,
just no useful data in Sentry's Profiling tab.

Vendored Sentry SDK
-------------------

The browser SDK ships **vendored inside the module** under
``sentry_client/static/lib/sentry/<version>/``. The default **Sentry SDK
source URL** points at this in-module path, so the browser loads the SDK
from the same origin as Odoo — no traffic to ``browser.sentry-cdn.com``,
no air-gap workarounds needed.

To bump the vendored version, run the refresh script:

.. code:: bash

   cd sentry_client/
   ./scripts/refresh-vendor-bundle.sh 10.55.0   # whatever you want
   git add static/lib/sentry/10.55.0/
   git commit -m "[IMP] sentry_client: bump vendored SDK to 10.55.0"

The script downloads each bundle from ``browser.sentry-cdn.com``,
verifies it against Sentry's published SHA-384 SRI hash, drops the
LICENSE file, and writes a SHA256SUMS for reviewers. After committing,
update the **Sentry SDK version** in Settings → General Settings →
Sentry Browser Monitoring to match.

To revert to the public CDN at runtime (e.g. for quick A/B testing),
override **Sentry SDK source URL** to ``https://browser.sentry-cdn.com``
in the Settings page.

Sentry server compatibility
---------------------------

The browser SDK talks to whatever Sentry instance you point the DSN at —
either sentry.io or a self-hosted instance. Feature support depends on
the Sentry server version:

+----------------------+----------------------+------------------------------------------------------------+
| Feature              | Minimum Sentry       | Notes                                                      |
|                      | server               |                                                            |
+======================+======================+============================================================+
| Tier 0 — error       | v9.0+                | Basic event ingest, supported by every modern Sentry.      |
| capture              |                      |                                                            |
+----------------------+----------------------+------------------------------------------------------------+
| Tier 1 — performance | v10.0+               | The tracing UI shipped in Sentry 10.                       |
| / tracing            |                      |                                                            |
+----------------------+----------------------+------------------------------------------------------------+
| Tier 2 — session     | v22.10.0+ (Oct 2022) | Replay ingest was introduced in self-hosted 22.10. The     |
| replay               | + feature flag       | feature must also be enabled on the server: set            |
|                      |                      | ``SENTRY_FEATURES["organizations:session-replay"] = True`` |
|                      |                      | (and ``…-ui``, ``…-recording-scrubbing``) in               |
|                      |                      | ``sentry.conf.py``, then restart ``web`` +                 |
|                      |                      | ``ingest-replay-recordings``. Without the flag, browser    |
|                      |                      | envelopes arrive at ``/api/<n>/envelope/`` but are         |
|                      |                      | silently discarded — no UI surface, no error.              |
+----------------------+----------------------+------------------------------------------------------------+
| Tier 3 — feedback    | v23.6.0+ (Jun 2023)  | The modern programmatic feedback API. Older versions still |
| widget               |                      | work with the legacy ``Sentry.showReportDialog`` path,     |
|                      |                      | which this module does not use.                            |
+----------------------+----------------------+------------------------------------------------------------+
| Tier 3 — browser     | v24.0+ (Jan 2024)    | Plus the ``Document-Policy: js-profiling`` header (see     |
| profiling            |                      | above).                                                    |
+----------------------+----------------------+------------------------------------------------------------+
| Tier 3 — console-log | v25.0+ (Mar 2025)    | Sentry Logs API. Server versions before v25 will ingest    |
| capture              |                      | the events as a generic log envelope; the dedicated Logs   |
|                      |                      | UI requires v25+.                                          |
+----------------------+----------------------+------------------------------------------------------------+

For sentry.io: all features are always available.

For self-hosted: check your tag at ``/opt/sentry/install/_version.sh``
(or ``docker exec <sentry-web> sentry --version``). If a feature you've
enabled isn't supported by your Sentry server, the browser SDK still
sends the envelope but the server discards it — no client-side error.

Usage
=====

Once Tier 0 is enabled and a DSN is configured, the next page load
injects the (vendored) Sentry browser SDK and starts capturing errors.
No further user action needed.

To verify the integration:

1. Open the browser dev tools console on any Odoo page.
2. Run ``throw new Error("sentry_client smoke test")``.
3. The error appears in your Sentry project within a few seconds, tagged
   with your Odoo ``user.id``, ``release``, and ``environment``.

Per-user opt-out
----------------

Top-right avatar → My Profile → Preferences → Privacy → **Disable Sentry
session replay**. Saves to your own user record. The opt-out only
suppresses session replay; basic error capture (Tier 0) still fires.

OWL component context
---------------------

When the backend OWL stack raises an exception (the usual "Oops!" dialog
you see in the Odoo web client), the resulting Sentry event
automatically carries:

- ``tags.owl = true``
- ``extra.component_tree`` — the OWL component path

No configuration needed — the OCA ``sentry_client`` module registers an
entry in ``@web/core/error_handlers`` at install time. Standard Odoo
error UX is unaffected.

Known issues / Roadmap
======================

- **OWL error-boundary depth** — the current handler captures the
  failing component tree + props. Could also enrich with the action
  context (active model, record IDs, view type) by reading
  ``env.services.action.currentController``. Optional polish.
- **Asset-bundle profiling preload** — the JS Self-Profiling API needs
  the ``Document-Policy: js-profiling`` HTTP header on the document
  response, which Odoo doesn't emit by default. CONFIGURE.md documents
  the nginx workaround; a small ``ir.http.dispatch`` hook in this module
  could set the header conditionally when Tier 3 profiling is on.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/server-tools/issues>`_.
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
`feedback <https://github.com/OCA/server-tools/issues/new?body=module:%20sentry_client%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* Ledoent

Contributors
------------

- Don Kendall <dkendall@ledoweb.com>

Other credits
-------------

The development of this module is led by
`Ledoent <https://ledoweb.com>`__.

Companion to the OCA ```sentry`` <../sentry>`__ module for server-side
error capture.

Maintainers
-----------

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
   :alt: Odoo Community Association
   :target: https://odoo-community.org

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-dnplkndll| image:: https://github.com/dnplkndll.png?size=40px
    :target: https://github.com/dnplkndll
    :alt: dnplkndll

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

|maintainer-dnplkndll| 

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

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
