Showing preview only (496K chars total). Download the full file or copy to clipboard to get everything.
Repository: rollbar/pyrollbar
Branch: master
Commit: c01b721d24c1
Files: 104
Total size: 465.5 KB
Directory structure:
gitextract_s7qvive8/
├── .flake8
├── .github/
│ ├── pull_request_template.md
│ └── workflows/
│ └── ci.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── THANKS.md
├── pyproject.toml
└── rollbar/
├── __init__.py
├── cli.py
├── contrib/
│ ├── __init__.py
│ ├── asgi/
│ │ ├── __init__.py
│ │ ├── integration.py
│ │ ├── middleware.py
│ │ └── types.py
│ ├── bottle/
│ │ └── __init__.py
│ ├── django/
│ │ ├── __init__.py
│ │ ├── context_processors.py
│ │ ├── middleware.py
│ │ ├── models.py
│ │ ├── tests.py
│ │ └── utils.py
│ ├── django_rest_framework/
│ │ └── __init__.py
│ ├── fastapi/
│ │ ├── __init__.py
│ │ ├── logger.py
│ │ ├── middleware.py
│ │ ├── routing.py
│ │ └── utils.py
│ ├── flask/
│ │ └── __init__.py
│ ├── pyramid/
│ │ └── __init__.py
│ ├── quart/
│ │ └── __init__.py
│ ├── rq/
│ │ └── __init__.py
│ └── starlette/
│ ├── __init__.py
│ ├── logger.py
│ ├── middleware.py
│ └── requests.py
├── examples/
│ ├── asgi/
│ │ └── app.py
│ ├── django/
│ │ └── app.py
│ ├── fastapi/
│ │ ├── app.py
│ │ ├── app_global_request.py
│ │ ├── app_logger.py
│ │ └── app_middleware.py
│ ├── flask/
│ │ └── app.py
│ ├── starlette/
│ │ ├── app.py
│ │ ├── app_global_request.py
│ │ └── app_logger.py
│ └── twisted/
│ └── simpleserv.py
├── lib/
│ ├── __init__.py
│ ├── _async.py
│ ├── events.py
│ ├── filters/
│ │ ├── __init__.py
│ │ └── basic.py
│ ├── payload.py
│ ├── session.py
│ ├── thread_pool.py
│ ├── transform.py
│ ├── transforms/
│ │ ├── __init__.py
│ │ ├── batched.py
│ │ ├── scrub.py
│ │ ├── scrub_redact.py
│ │ ├── scruburl.py
│ │ ├── serializable.py
│ │ └── shortener.py
│ ├── transport.py
│ ├── traverse.py
│ └── type_info.py
├── logger.py
└── test/
├── __init__.py
├── asgi_tests/
│ ├── __init__.py
│ ├── test_integration.py
│ ├── test_middleware.py
│ └── test_spec.py
├── async_tests/
│ ├── __init__.py
│ └── test_async.py
├── fastapi_tests/
│ ├── __init__.py
│ ├── test_logger.py
│ ├── test_middleware.py
│ ├── test_routing.py
│ └── test_utils.py
├── flask_tests/
│ ├── __init__.py
│ └── test_flask.py
├── starlette_tests/
│ ├── __init__.py
│ ├── test_logger.py
│ ├── test_middleware.py
│ └── test_requests.py
├── test_basic_filters.py
├── test_batched_transform.py
├── test_custom_filters.py
├── test_lib.py
├── test_loghandler.py
├── test_pyramid.py
├── test_rollbar.py
├── test_scrub_redact_transform.py
├── test_scrub_transform.py
├── test_scruburl_transform.py
├── test_serializable_transform.py
├── test_session.py
├── test_shortener_transform.py
├── test_transform.py
├── test_traverse.py
├── twisted_tests/
│ ├── __init__.py
│ └── test_twisted.py
└── utils.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .flake8
================================================
[flake8]
max-line-length = 100
max-complexity = 10
exclude = test/*
================================================
FILE: .github/pull_request_template.md
================================================
## Description of the change
> Please include a summary of the change and which issues are fixed.
> Please also include relevant motivation and context.
## Type of change
- [ ] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Maintenance
- [ ] New release
## Related issues
> Shortcut stories and GitHub issues (delete irrelevant)
- Fix [SC-]
- Fix #1
## Checklists
### Development
- [ ] Lint rules pass locally
- [ ] The code changed/added as part of this pull request has been covered with tests
- [ ] All tests related to the changed code pass in development
### Code review
- [ ] This pull request has a descriptive title and information useful to a reviewer. There may be a screenshot or screencast attached
- [ ] "Ready for review" label attached to the PR and reviewers assigned
- [ ] Issue from task tracker has a link to this pull request
- [ ] Changes have been reviewed by at least one other engineer
================================================
FILE: .github/workflows/ci.yml
================================================
name: Pyrollbar CI
on:
push:
branches: [ master ]
tags: [ v* ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.9, '3.10', 3.11, 3.12, 3.13, 3.14]
framework:
- NONE
- FLASK_VERSION=2.3.3
- FLASK_VERSION=3.1.2
- DJANGO_VERSION=4.2.25
- DJANGO_VERSION=5.2.7
- PYRAMID_VERSION=1.10.8
- PYRAMID_VERSION=2.0.2
- FASTAPI_VERSION=0.115.1 httpx==0.27.2 python-multipart==0.0.12
- FASTAPI_VERSION=0.118.3 httpx==0.28.1 python-multipart==0.0.20
exclude:
# Test frameworks on the python versions they support, according to pypi registry
# Django
- framework: DJANGO_VERSION=5.2.7
python-version: 3.9
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install package with test dependencies
run: pip install --group test .
- name: Set the framework
if: ${{ matrix.framework != 'NONE' }}
run: echo ${{ matrix.framework }} >> $GITHUB_ENV
- name: Install Flask
if: ${{ contains(matrix.framework, 'FLASK_VERSION') }}
run: pip install Flask==$FLASK_VERSION
- name: Install Twisted
if: ${{ contains(matrix.framework, 'TWISTED_VERSION') }}
run: pip install Twisted==$TWISTED_VERSION idna==2.10
- name: Install Django
if: ${{ contains(matrix.framework, 'DJANGO_VERSION') }}
run: pip install Django==$DJANGO_VERSION
- name: Install Pyramid
if: ${{ contains(matrix.framework, 'PYRAMID_VERSION') }}
run: pip install pyramid==$PYRAMID_VERSION
- name: Install Starlette
if: ${{ contains(matrix.framework, 'STARLETTE_VERSION') }}
run: pip install starlette==$STARLETTE_VERSION
- name: Install FastAPI
if: ${{ contains(matrix.framework, 'FASTAPI_VERSION') }}
run: pip install fastapi==$FASTAPI_VERSION
- name: Run tests
run: pytest
================================================
FILE: .gitignore
================================================
*.pyc
*.swp
*.swo
dist/
build/
rollbar.egg-info/
*.egg
.eggs/
.idea/
*~
Pipfile
Pipfile.lock
.pytest_cache/
.python-version
.tox/
/venv*
================================================
FILE: CHANGELOG.md
================================================
# Change Log
The change log is also available on the [GitHub Releases Page](https://github.com/rollbar/pyrollbar/releases).
**1.4.0-beta**
- Added support for Python 3.14 by @danielmorell in [#484](https://github.com/rollbar/pyrollbar/pull/484)
- Added support for error correlation headers. by @danielmorell in [#491](https://github.com/rollbar/pyrollbar/pull/491)
**1.3.0**
- Added support for classes to define the method `__rollbar_repr__` to control how objects are serialized by @danielmorell in [#479](https://github.com/rollbar/pyrollbar/pull/479)
- Added support for Python 3.13 by @danielmorell in [#477](https://github.com/rollbar/pyrollbar/pull/477)
- Removed support for Python 3.6 by @danielmorell in [#480](https://github.com/rollbar/pyrollbar/pull/480)
- Updated framework versions tested against by @danielmorell in [#480](https://github.com/rollbar/pyrollbar/pull/480)
**1.2.0**
- Added support for custom payload transforms by @danielmorell in [#470](https://github.com/rollbar/pyrollbar/pull/470)
- Added custom data to the message body by @waltjones in [#473](https://github.com/rollbar/pyrollbar/pull/473)
- Added support for host override setting by @danielmorell in [#468](https://github.com/rollbar/pyrollbar/pull/468)
- Fixed `RollbarHandler` reconfigures root logger by @ilkecan in [#463](https://github.com/rollbar/pyrollbar/pull/463)
- Fixed `include_request_body` setting not checked for various frameworks by @danielmorell in [#469](https://github.com/rollbar/pyrollbar/pull/469)
- Fixed `namedtuple` fields not being scrubbed by @danielmorell in [#474](https://github.com/rollbar/pyrollbar/pull/474)
**1.1.2**
Fixed build missing entrypoints for pyramid and cli in [#471](https://github.com/rollbar/pyrollbar/pull/471)
**1.1.1**
Fixed #465 httpx 0.28.0 not compatible with pyrollbar by @danielmorell in [#466](https://github.com/rollbar/pyrollbar/pull/466)
**1.1.0**
- Updated supported/tested frameworks and modernized tests and packaging by @danielmorell in [#455](https://github.com/rollbar/pyrollbar/pull/455)
- Fixed #398 FastAPI integration fails if docs are disabled by @danielmorell in [#459](https://github.com/rollbar/pyrollbar/pull/459)
- Support `pathlib.Path()` objects by @singingwolfboy in [$450](https://github.com/rollbar/pyrollbar/pull/450)
- Added support for Python 3.12 by @danielmorell in [#460](https://github.com/rollbar/pyrollbar/pull/460)
- Changed the `ShortenerTransform` to use breadth first traversal by @danielmorell in [#461](https://github.com/rollbar/pyrollbar/pull/461)
- Fixed shortener multi level shortening by @danielmorell and @pawelsz-rb. See [#449](https://github.com/rollbar/pyrollbar/pull/449)
**1.1.0-beta**
- Updated supported/tested frameworks and modernized tests and packaging by @danielmorell in [#455](https://github.com/rollbar/pyrollbar/pull/455)
- Fixed #398 FastAPI integration fails if docs are disabled by @danielmorell in [#459](https://github.com/rollbar/pyrollbar/pull/459)
- Support `pathlib.Path()` objects by @singingwolfboy in [$450](https://github.com/rollbar/pyrollbar/pull/450)
- Added support for Python 3.12 by @danielmorell in [#460](https://github.com/rollbar/pyrollbar/pull/460)
- Changed the `ShortenerTransform` to use breadth first traversal by @danielmorell in [#461](https://github.com/rollbar/pyrollbar/pull/461)
**1.1.0-alpha**
- Fixed shortener multi level shortening by @danielmorell and @pawelsz-rb. See [#449](https://github.com/rollbar/pyrollbar/pull/449)
**1.0.0**
- Fixed handling `sensitive_post_parameters` decorator in Django by @pawelsz-rb. See [#413](https://github.com/rollbar/pyrollbar/pull/413)
- Fixed Werkzeug DeprecationWarning of `BaseRequest` by @compyman. See [#410](https://github.com/rollbar/pyrollbar/pull/410)
- Fixed missing locals shortening on items with "trace_chain" instead of "trace" by @terencehonles. See [#365](https://github.com/rollbar/pyrollbar/pull/365)
- Fixed FastAPI version comparison by @ayharano. See [#433](https://github.com/rollbar/pyrollbar/pull/433)
- Fixed #436 `WSGIRequest` has no attribute `sensitive_post_parameters`. by @danielmorell. See [#437](https://github.com/rollbar/pyrollbar/pull/437)
- Added new `thread_pool` handler by @danielmorell. See [#416](https://github.com/rollbar/pyrollbar/pull/416)
- Added Rollbar branding to the readme by @paulserraino. See [#418](https://github.com/rollbar/pyrollbar/pull/418)
- Added batched transform to increase sanitization and serialization performance by @ijsnow. See [#421](https://github.com/rollbar/pyrollbar/pull/421)
- Replaced unittest2 with unittest by @brianr. See [#420](https://github.com/rollbar/pyrollbar/pull/420)
- Removed unittest2 by @mcepl. See [#419](https://github.com/rollbar/pyrollbar/pull/419)
- Remove deprecated flask `before_first_request` by @albertyw. See [#428](https://github.com/rollbar/pyrollbar/pull/428)
- Removed support for Python 2 by @danielmorell. See [#435](https://github.com/rollbar/pyrollbar/pull/435)
- Updated the base Ubuntu for CI to 20.04 test runner by @danielmorell and @waltjones. See [#427](https://github.com/rollbar/pyrollbar/pull/427)
- Replaced `httpx.post` `data` kwarg with `content` by @ayharano. See [#425](https://github.com/rollbar/pyrollbar/pull/425)
**0.16.3**
- Pinned Python 2 CI tests to legacy version of dependencies. See [#408](https://github.com/rollbar/pyrollbar/pull/408)
- Add PyPI badge for supported Python versions. See [#408](https://github.com/rollbar/pyrollbar/pull/401)
- Add Django 4.0+ compatibility. See [#408](https://github.com/rollbar/pyrollbar/pull/400)
- Update PR template. See [#408](https://github.com/rollbar/pyrollbar/pull/395)
- SC-95272: Remove support for Python 3.3. See [#408](https://github.com/rollbar/pyrollbar/pull/394)
**0.16.2**
- Fix building person data in Django. See [#385](https://github.com/rollbar/pyrollbar/pull/385)
- Fix circular error logging for non-HTTP events in Starlette. See [#390](https://github.com/rollbar/pyrollbar/pull/390)
- Fix Python 3.4 builds. See [#389](https://github.com/rollbar/pyrollbar/pull/389)
**0.16.1**
- Fix PyPI artifacts
**0.16.0**
- Add support for FastAPI framework. See [#373](https://github.com/rollbar/pyrollbar/pull/373)
- Add support for Starlette framework. See [#373](https://github.com/rollbar/pyrollbar/pull/373)
- Add support for ASGI-based frameworks. See [#373](https://github.com/rollbar/pyrollbar/pull/373)
- Add support for HTTPX async handler. See [#373](https://github.com/rollbar/pyrollbar/pull/373)
- Add support for async report_exc_info and report_message. See [#373](https://github.com/rollbar/pyrollbar/pull/373)
- Collect user IP from X-Forwarded-For, fall back to X-Real-Ip. See [#370](https://github.com/rollbar/pyrollbar/pull/370)
- Improve examples. See [#368](https://github.com/rollbar/pyrollbar/pull/368)
- Fix Python 3.3 builds. See [#374](https://github.com/rollbar/pyrollbar/pull/374)
- Fix Flask 0.x builds. See [#376](https://github.com/rollbar/pyrollbar/pull/376)
**0.15.2**
- Add support for whitelist/blacklist for safelist/blocklist. See [#354](https://github.com/rollbar/pyrollbar/pull/343)
- Add Twisted to the available frameworks. See [#360](https://github.com/rollbar/pyrollbar/pull/360)
**0.15.1**
- Add support to Python 3.8. See [#351](https://github.com/rollbar/pyrollbar/pull/351)
- Fix deque test. See [#349](https://github.com/rollbar/pyrollbar/pull/349)
- Add alternatives to exception handler. See [#335](https://github.com/rollbar/pyrollbar/pull/335)
- Change dict_merge to allow strict mode. See [#339](https://github.com/rollbar/pyrollbar/pull/339)
- Improve scrubbing test case. See [#343](https://github.com/rollbar/pyrollbar/pull/343)
**0.15.0**
- Prevent recursive re-raising of exceptions. See [#317](https://github.com/rollbar/pyrollbar/pull/317)
- Correctly apply logger formatting to Rollbar messages. See [#312](https://github.com/rollbar/pyrollbar/pull/312)
- Fix deprecation warnings. See [#325](https://github.com/rollbar/pyrollbar/pull/319) and [#331](https://github.com/rollbar/pyrollbar/pull/331)
- Allow the request pool to be configured. See [#305](https://github.com/rollbar/pyrollbar/pull/305)
- Use callable() instead of try/except TypeError. See [#319](https://github.com/rollbar/pyrollbar/pull/319)
- Update Travis CI matrix. See [#317](https://github.com/rollbar/pyrollbar/pull/317)
- Fix Travis build errors. See [#328](https://github.com/rollbar/pyrollbar/pull/328)
- Update trove classifiers. See [#331](https://github.com/rollbar/pyrollbar/pull/331)
**0.14.7**
- Allow the raw request body to be included if desired. See [#304](https://github.com/rollbar/pyrollbar/pull/304)
- Send Rollbar access token in HTTP header. See [#303](https://github.com/rollbar/pyrollbar/pull/303)
- Add support for Django 1.7 & 1.8 in \_build_django_request_data. See [#301](https://github.com/rollbar/pyrollbar/pull/301)
- Add support for Quart framework. See [#300](https://github.com/rollbar/pyrollbar/pull/300)
**0.14.6**
- Add the authorization header to the default scrub fields list. See [#299](https://github.com/rollbar/pyrollbar/pull/299)
- Encode the payload properly for newer versions of Twisted. See [#298](https://github.com/rollbar/pyrollbar/pull/298)
- Don't fail to send payloads because some inner object is not JSON serializable. See [#297](https://github.com/rollbar/pyrollbar/pull/297)
- Allow floats as circular references. See [#291](https://github.com/rollbar/pyrollbar/pull/291)
**0.14.5**
- Fix bug in which error params were not being passed correctly to Pyramid middleware. See [#287](https://github.com/rollbar/pyrollbar/pull/287)
**0.14.4**
- Fix bug in Pyramid middleware where exc_info was not being passed to handle_error. See [#283](https://github.com/rollbar/pyrollbar/pull/283)
- Fix bug where errors in the serialization of local variables caused errors to be dropped. They will now make it to Rollbar. See [#284](https://github.com/rollbar/pyrollbar/pull/284)
**0.14.3**
- Add support for HTTP(S) proxies. See [#276](https://github.com/rollbar/pyrollbar/pull/276)
**0.14.2**
- Fix bug with file-based logging config in Python 3. See [#277](https://github.com/rollbar/pyrollbar/issues/277)
- Fix bug in Django middleware when request has no META attribute. See [#273](https://github.com/rollbar/pyrollbar/pull/273)
**0.14.1**
- Add Django middlewares that differentiate between 404 and other exceptions. See [#270](https://github.com/rollbar/pyrollbar/pull/270)
- Make Werkzeug request handling more general. See [#271](https://github.com/rollbar/pyrollbar/pull/271)
- Fix incorrect handling rollbar.init() arguments when using LOGGER in Django. See [#235](https://github.com/rollbar/pyrollbar/pull/235)
- Use thread local storage for not thead-safe requests.Sessions. See [#269](https://github.com/rollbar/pyrollbar/pull/269)
- Swallow known error that happens in add_person_data. See [#268](https://github.com/rollbar/pyrollbar/pull/268)
- Only write a log about a rate limit once. See [#267](https://github.com/rollbar/pyrollbar/pull/267)
- Adapt Django view monkey patch to support Django 2. See [#257](https://github.com/rollbar/pyrollbar/pull/257)
- Add support request objects from Django REST framework. See [#18](https://github.com/rollbar/pyrollbar/pull/18)
- Add support for Falcon framework requests. See [#51](https://github.com/rollbar/pyrollbar/pull/51)
- Add support for Django Channels' AsgiRequest. See [#272](https://github.com/rollbar/pyrollbar/pull/272)
**0.14.0**
- Create the configuration options, `capture_username` and `capture_email`. Prior to this release,
if we gather person data automatically, we would try to capture the id, email, and username.
Starting with this release by default we will only capture the id. If you set `capture_username`
to `True` then we will also attempt to capture the username. Similarly for `capture_email` with
the email. (See [#262](https://github.com/rollbar/pyrollbar/pull/262))
- Create the configuration option `capture_ip`. This can take one of three values: `True`,
`'anonymize'`, or `False`. This controls how we handle IP addresses that are captured from
requests. If `True`, then we will send the full IP address. This is the current behaviour and the
default. If set to the string `'anonymize'` which is also available as the constant `ANONYMIZE` on
the `rollbar` module, we will mask out the least significant bits of the IP address. If set to
`False`, then we will not capture the IP address. (See [#262](https://github.com/rollbar/pyrollbar/pull/262))
- Fix `request.files_keys` for Flask [#263](https://github.com/rollbar/pyrollbar/pull/263)
- If you call `init` multiple times we will update the settings at each call. Prior to
this release we emitted a warning and did not update settings. [#259](https://github.com/rollbar/pyrollbar/pull/259)
- Better Tornado support [#256](https://github.com/rollbar/pyrollbar/pull/256)
**0.13.18**
- See Release Notes
**0.13.17**
- Fix deprecation warning related to Logging.warn
- Fix bug where non-copyable objects could cause an exception if they end up trying to get passed to
one of the logging methods.
- Fix bug where both `trace` and `trace_chain` could appear in the final payload, which is not
allowed by the API.
**0.13.16**
- Fix PyPI documentation
**0.13.15**
- Fix shortener issue for Python 3
**0.13.14**
- Fix bug that caused some payload objects to be turned into the wrong type when
shortening is applied. This would lead to API rejections. See [#200](https://github.com/rollbar/pyrollbar/pull/200)
- Add `suppress_reinit_warning` option if you want to allow calling init twice. See [#198](https://github.com/rollbar/pyrollbar/pull/198)
- Pass through keyword arguments from the logging handler to the underling Rollbar init call. See
[#203](https://github.com/rollbar/pyrollbar/pull/203)
**0.13.13**
- Add support for AWS Lambda. See [#191](https://github.com/rollbar/pyrollbar/pull/191)
**0.13.12**
- Remove the Django request body from the payload as it can contain sensitive data. See [#174](https://github.com/rollbar/pyrollbar/pull/174)
- Allow users to shorten arbitrary parts of the payload. See [#173](https://github.com/rollbar/pyrollbar/pull/173)
- Fix a Django deprecation warning. See [#165](https://github.com/rollbar/pyrollbar/pull/165)
**0.13.11**
- Handle environments where `sys.argv` does not exist. See [#131](https://github.com/rollbar/pyrollbar/pull/131)
**0.13.10**
- Gather request method from WebOb requests. See [#152](https://github.com/rollbar/pyrollbar/pull/152)
**0.13.9**
- Change `_check_config()` to deal with agent handler. See [#147](https://github.com/rollbar/pyrollbar/pull/147)
- Fix settings values not being booleans in Pyramid. See [#150](https://github.com/rollbar/pyrollbar/pull/150)
**0.13.8**
- Fix regression from 0.13.7. See [#141](https://github.com/rollbar/pyrollbar/pull/141)
**0.13.7**
- Update Django middleware to support Django 1.10+. See [#138](https://github.com/rollbar/pyrollbar/pull/138)
**0.13.6**
- Fixed a referenced before assignment in the failsafe. See [#136](https://github.com/rollbar/pyrollbar/pull/136)
**0.13.5**
- Fixed record message formatting issues breaking the log handler's history. See [#135](https://github.com/rollbar/pyrollbar/pull/135)
**0.13.4**
- Fixed failsafe handling for payloads that are too large. See [#133](https://github.com/rollbar/pyrollbar/pull/133)
**0.13.3**
- Improved handling of Enums. See [#121](https://github.com/rollbar/pyrollbar/pull/121)
**0.13.2**
- Improved handling of Nan and (Negative)Infinity. See [#117](https://github.com/rollbar/pyrollbar/pull/117)
- RollbarHandler now ignores log records from Rollbar. See [#118](https://github.com/rollbar/pyrollbar/pull/118)
**0.13.1**
- Failsafe handling for payloads that are too large. See [#116](https://github.com/rollbar/pyrollbar/pull/116)
- Failsafe Behavior
- Log an error containing the original payload and the UUID from it
- Send a new payload to Rollbar with the custom attribute containing the UUID and host from the original payload
**0.13.0**
- Frame payload refactor and varargs scrubbing. See [#113](https://github.com/rollbar/pyrollbar/pull/113)
- Frame Payload Changes
- remove args and kwargs
- add argspec as the list of argument names to the function call
- add varargspec as the name of the list containing the arbitrary unnamed positional arguments to the function call if any exist
- add keywordspec as the name of the object containing the arbitrary keyword arguments to the function call if any exist
- Other Changes:
- Arguments with default values are no longer removed from args and placed into kwargs
- varargs are now scrubbable and scrubbed by default
- Switched to using a Session object to perform HTTPS requests to optimize for keepalive connections. See [#114](https://github.com/rollbar/pyrollbar/pull/114)
**0.12.1**
- Keep blank values from request query strings when scrubbing URLs. See [#110](https://github.com/rollbar/pyrollbar/pull/110)
**0.12.0**
- Fix and update Twisted support. See [#109](https://github.com/rollbar/pyrollbar/pull/109)
- **Breaking Changes**: [treq](https://github.com/twisted/treq) is now required for using Twisted with pyrollbar.
**0.11.6**
- Improve object handling for SQLAlchemy. See [#108](https://github.com/rollbar/pyrollbar/pull/108)
**0.11.5**
- Fixed a bug when custom `__repr__()` calls resulted in an exception being thrown. See [#102](https://github.com/rollbar/pyrollbar/pull/102)
**0.11.4**
- Revert changes from 0.11.3 since they ended-up having the unintended side effect by that exceptions messages weren't processing as expected.
- Update settings in init first so that custom scrub_fields entries are handled correctly
**0.11.3**
- Obey safe repr for exceptions. See [#91](https://github.com/rollbar/pyrollbar/pull/91)
**0.11.2**
- Fixed a bug when calling logging.exception() when not in an exception handler. Now it correctly determines it doesn't have any exception info and uses report_message() instead of report_exc_info().
**0.11.1**
- Added a new configuration option to expose the serializer's `safelisted_types` param
- Allows users to safelist types to be serialized using `repr(obj)` instead of `str(type(obj))`
- Fixed a bug that was not taking the `safe_repr` option into account. See [#87](https://github.com/rollbar/pyrollbar/pull/87)
**0.11.0**
- Overhauled the scrubbing and serialization mechanisms to provide deep object scrubbing and better handling of UTF-8 data from local variables. See [#75](https://github.com/rollbar/pyrollbar/pull/75)
- This fixes a bunch of problems with reporting local variables, including `UnicodeEncodeError`s and attempting to read variables after the thread they were in has died.
- Local variables and payload data is now sent over in their original structure.
- If a variable was a `dict`, it will be transmitted as a `dict` instead of turned into a string representation of the variable.
- The entire payload is now scrubbed and URL password fields are scrubbed as well.
- Added a Django example.
- Wrote many, many more tests :)
- Integrated the `six` library to provide cleaner support for Python3.
- Added some additional scrub fields.
**0.10.1**
- Added a warning message if `init()` is called more than once.
**0.10.0**
- Added support for Twisted framework. See [#69](https://github.com/rollbar/pyrollbar/pull/69)
- Fix a bug that was causing max recursion errors while collecting local variables. See [#77](https://github.com/rollbar/pyrollbar/pull/77)
- Added a configuration option, `safe_repr: True` which will cause payload serialization to use the type name for non-built-in objects.
This option defaults to `True` which may cause data reported to Rollbar to contain less information for custom types.
Prior to this change, serialization of custom objects called `__repr__()` which may have had undesired side effects.
- Fixed a bug that did not correctly handle anonymous tuple arguments while gathering local variables.
**0.9.14**
- Fix logging loop when using Flask in a non-request context, and also using the Rollbar logging handler. See [#68](https://github.com/rollbar/pyrollbar/pull/68)
**0.9.13**
- If present, get request from log record. Otherwise try to guess current request as usual.
**0.9.12**
- Fix a bug that was causing a crash while reporting an error that happened in a Werkzeug request that had no `request.json`. See [#64](https://github.com/rollbar/pyrollbar/pull/64)
**0.9.11**
- Implement workarounds for NaN and Infinity "numbers" in payloads. See [#62](https://github.com/rollbar/pyrollbar/pull/62)
**0.9.10**
- Fix request data collection in Flask 0.9. See [#61](https://github.com/rollbar/pyrollbar/pull/61)
**0.9.9**
- Add exception handler for RQ (requires some instrumentation). See [#57](https://github.com/rollbar/pyrollbar/pull/57)
- Scrub fields inside `extra_data`
- Gather the process PID and report it along with the other 'server' data
**0.9.8**
- Support bare WSGI requests ([#55](https://github.com/rollbar/pyrollbar/pull/55))
**0.9.7**
- Add support for Google App Engine ([#53](https://github.com/rollbar/pyrollbar/pull/53))
**0.9.6**
- Fix memory leak when using the RollbarHandler logging handler (see [#43](https://github.com/rollbar/pyrollbar/pull/43))
- Fix bug where named function arguments were not scrubbed correctly
**0.9.5**
- Fix bug with local variable gathering that was breaking when getting the arguments for a class constructor.
**0.9.4**
- Request headers are now scrubbed, [pr#41](https://github.com/rollbar/pyrollbar/pull/41).
**0.9.3**
- `exception_level_filters` can now take a string that defines the class to filter, [#38](https://github.com/rollbar/pyrollbar/pull/38).
**0.9.2**
- Added an option to disable SSL certificate verification, [#36](https://github.com/rollbar/pyrollbar/pull/36).
- Added `__version__` specifier to `__init__.py`.
**0.9.1**
New features:
- For Tornado requests, gather the request start time. See [#33](https://github.com/rollbar/pyrollbar/pull/33)
- Add handler which uses Tornado's `AsyncHTTPClient`. To use this, set your 'handler' to 'tornado'. See [#34](https://github.com/rollbar/pyrollbar/pull/34)
**0.9.0**
- Improvements to RollbarHandler logging handler. It now:
- extracts more information out of each record (i.e. metadata like pathname and creation time)
- uses the format string, with arguments not yet replaced, as the main message body. This will result in much better grouping in Rollbar.
Note about upgrading from 0.8.x: unless you are using RollbarHandler, there are no breaking changes. If you are using RolbarHandler, then this will change the way your data appears in Rollbar (to the better, in our opinion).
**0.8.3**
- Provide a way to blocklist types from being repr()'d while gathering local variables.
**0.8.2**
- Fix uncaught ImproperlyConfigured exception when importing Rollbar in a Django REST Framework environment without a settings module loaded ([#28](https://github.com/rollbar/pyrollbar/pull/28))
**0.8.1**
- Only attempt local variable extraction if traceback frames are of the correct type, print a warning otherwise
- Fix JSON request param extraction for Werkzeug requests (Pyramid, Flask, etc)
**0.8.0**
- Local variables collection now enabled by default.
- Fixed scrubbing for utf8 param names.
**0.7.6**
- Added local variables for all in-project frames and the last frame.
**0.7.5**
- Initial support for sending args and kwargs for traceback frames.
- Optimization to send the access token in a header.
**0.7.4**
- Level kwarg added to `rollbar.report_exc_info()` ([#22](https://github.com/rollbar/pyrollbar/pull/22))
**0.7.3**
- Added in an optional `endpoint` parameter to `search_items()`.
**0.7.2**
- Fix for scrubbing werkzeug json bodies ([#20](https://github.com/rollbar/pyrollbar/pull/20))
**0.7.1**
- Support scrubbing for werkzeug json bodies ([#19](https://github.com/rollbar/pyrollbar/pull/19))
**0.7.0**
- Python 3 support
- Now support extracting data from Django REST framework requests
- New `enabled` configuration setting
**0.6.2**
- Fixed json request data formatting for reports in Bottle requests
- Now send json request data for Django and Pyramid apps
- Set framework and request context properly for all reports in Flask and Bottle apps
**0.6.1**
- Added Django, Pyramid, Flask and Bottle support for default contexts.
**0.6.0**
- `report_message()` now returns the UUID of the reported occurrence.
**0.5.14**
- Fix bug with non-JSON post data in Flask
- Add slightly better integration with Flask. See [rollbar-flask-example](https://github.com/rollbar/rollbar-flask-example) for example usage.
**0.5.13**
- Collect JSON post data in Flask when mimetype is `application/json`
**0.5.12**
- Add sys.argv to server data
**0.5.11**
- Don't report bottle.BaseResponse exceptions in the bottle plugin
**0.5.10**
- Added `code_version` configuration setting
- Added support for bottle request objects
**0.5.9**
- Added a command line interface for reporting messages to Rollbar
**0.5.8**
- Added `allow_logging_basic_config` config flag for compatability with Flask. If using Flask, set to False.
**0.5.7**
- Added `exception_level_filters` configuration setting to customize the level that specific exceptions are reported as.
**0.5.6**
- First argument to `rollbar.report_exc_info()` is now optional. You can now call it with no arguments from within an `except` block, and it will behave is if you had called like `rollbar.report_exc_info(sys.exc_info())`
**0.5.5**
- Support for ignoring exceptions by setting `exc._rollbar_ignore = True`. Such exceptions reported through rollbar.report_exc_info() -- which is used under the hood in the Django and Pyramid middlewares -- will be ignored instead of reported.
**0.5.4**
- Django: catch exceptions when patching the debugview, for better support for django 1.3.
**0.5.3**
- Fixed bug when reporting messages without a request object
**0.5.2**
- Fixed bug where django debug page can get patched twice
**0.5.1**
- Catching possible malformed API responses
**0.5.0**
- Rename to rollbar
**0.4.1**
- report_exc_info() now takes two additional named args: `extra_data` and `payload_data`, like report_message().
- on 429 response (over rate limit), log a warning but don't parse and print an exception.
**0.3.2**
- Added new default scrub fields
**0.3.1**
- Fixed pypi package
**0.3.0**
- Merge django-ratchet and pyramid_ratchet into pyratchet
- Add ability to write to a ratchet-agent log file
**0.2.0**
- Add "person" support
**0.1.14**
- Added payload_data arg to report_message()
**0.1.13**
- Added extra_data arg to report_message()
**0.1.12**
- Use custom JSON encoder to skip objects that can't be encoded.
- Bump default timeout from 1 to 3 seconds.
**0.1.11**
- Sensitive params now scrubbed out of POST. Param name list is customizable via the `scrub_fields` config option.
**0.1.10**
- Add support for Tornado request objects (`tornado.httpserver.HTTPRequest`)
**0.1.9**
- Fix support for Pyramid request objects
**0.1.8**
- Add support for Django request objects
================================================
FILE: LICENSE
================================================
Copyright (c) 2014 Rollbar, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
<p align="center">
<img alt="rollbar-logo" src="https://user-images.githubusercontent.com/3300063/207964480-54eda665-d6fe-4527-ba51-b0ab3f41f10b.png" />
</p>
<h1 align="center">Pyrollbar</h1>
<p align="center">
<strong>Proactively discover, predict, and resolve errors in real-time with <a href="https://rollbar.com">Rollbar’s</a> error monitoring platform. <a href="https://rollbar.com/signup/">Start tracking errors today</a>!</strong>
</p>
[](https://github.com/rollbar/pyrollbar/actions)

Python notifier for reporting exceptions, errors, and log messages to [Rollbar](https://rollbar.com).
## Key benefits of using Pyrollbar are:
- **Frameworks:** Pyrollbar supports popular Python frameworks such as <a href="https://docs.rollbar.com/docs/django">Django</a>, <a href="https://docs.rollbar.com/docs/flask">Flask</a>, <a href="https://docs.rollbar.com/docs/fastapi">FastAPI</a>, <a href="https://docs.rollbar.com/docs/aws-lambda-1">AWS Lambda</a> and more!
- **Automatic error grouping:** Rollbar aggregates Occurrences caused by the same error into Items that represent application issues. <a href="https://docs.rollbar.com/docs/grouping-occurrences">Learn more about reducing log noise</a>.
- **Advanced search:** Filter items by many different properties. <a href="https://docs.rollbar.com/docs/search-items">Learn more about search</a>.
- **Customizable notifications:** Rollbar supports several messaging and incident management tools where your team can get notified about errors and important events by real-time alerts. <a href="https://docs.rollbar.com/docs/notifications">Learn more about Rollbar notifications</a>.
## Python Versions Supported
| PyRollbar Version | Python Version Compatibility | Support Level |
|-------------------|-----------------------------------------------|---------------------|
| 1.4.0 | 3.9, 3.10, 3.11, 3.12, 3.13, 3.14 | Full |
| 0.16.3 | 2.7, 3.4, 3.5, 3.6, 3.7. 3.8, 3.9, 3.10, 3.11 | Security Fixes Only |
#### Support Level Definitions
**Full** - We will support new features of the library and test against all supported versions.
**Security Fixes Only** - We will only provide critical security fixes for the library.
## Frameworks Supported
Generally, PyRollbar can be used with any Python framework. However, we have official support for the following frameworks:
| Framework | Support Duration | Tested Versions |
|-----------|----------------------------|-----------------|
| Celery | Release +1 year | None |
| Django | Release or LTS end +1 year | 4.2, 5.2 |
| FastAPI | Release +1 year | 0.115, 0.118 |
| Flask | Release +1 year | 2.3, 3.1 |
| Pyramid | Release +1 year | 1.10, 2.0 |
Official support means that we ship and maintain integrations for these frameworks. It also means that we test against these frameworks as part of our CI pipeline.
Generally, we will support the last year of releases for a framework. If a framework has a defined support period (including LTS releases), we will support the release for the duration of that period plus one year.
### Community Supported
There are also a number of community-supported integrations available. For more information, see the [Python SDK docs](https://docs.rollbar.com/docs/python-community-supported-sdks).
## Setup Instructions
1. [Sign up for a Rollbar account](https://rollbar.com/signup)
2. Follow the [Quick Start](https://docs.rollbar.com/docs/python#section-quick-start) instructions in our [Python SDK docs](https://docs.rollbar.com/docs/python) to install pyrollbar and configure it for your platform.
## Usage and Reference
For complete usage instructions and configuration reference, see our [Python SDK docs](https://docs.rollbar.com/docs/python).
## Release History & Changelog
See our [Releases](https://github.com/rollbar/pyrollbar/releases) page for a list of all releases, including changes.
## Help / Support
If you run into any issues, please email us at [support@rollbar.com](mailto:support@rollbar.com)
For bug reports, please [open an issue on GitHub](https://github.com/rollbar/pyrollbar/issues/new).
## Contributing
1. Fork it
2. Create your feature branch (```git checkout -b my-new-feature```).
3. Commit your changes (```git commit -am 'Added some feature'```)
4. Push to the branch (```git push origin my-new-feature```)
5. Create new Pull Request
Tests are in `rollbar/test`. To run the tests: `python setup.py test`
================================================
FILE: THANKS.md
================================================
# Contributors
Huge thanks to the following contributors (by github username). For the most up-to-date list, see https://github.com/rollbar/pyrollbar/graphs/contributors
- [alex-laties](https://github.com/alex-laties)
- [dmitry-mukhin](https://github.com/dmitry-mukhin)
- [homm](https://github.com/homm)
- [isra17](https://github.com/isra17)
- [jamesonjlee](https://github.com/jamesonjlee)
- [jbowes](https://github.com/jbowes)
- [jbrumwell](https://github.com/jbrumwell)
- [jedipi](https://github.com/jedipi)
- [juggernaut](https://github.com/juggernaut)
- [rhcarvalho](https://github.com/rhcarvalho)
- [tschieggm](https://github.com/tschieggm)
- [zvirusz](https://github.com/zvirusz)
- [benkuhn](https://github.com/benkuhn)
- [pmourlanne](https://github.com/pmourlanne)
================================================
FILE: pyproject.toml
================================================
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[project]
name = "rollbar"
dynamic = ["version"]
description = "Easy and powerful exception tracking with Rollbar. Send messages and exceptions with arbitrary context, get back aggregates, and debug production issues quickly."
readme = "README.md"
license = {file = "LICENSE"}
maintainers = [{name = "Rollbar, Inc.", email = "support@rollbar.com"}]
classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3 :: Only",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Development Status :: 5 - Production/Stable",
"Environment :: Web Environment",
"Framework :: AsyncIO",
"Framework :: Bottle",
"Framework :: Django",
"Framework :: Flask",
"Framework :: Pylons",
"Framework :: Pyramid",
"Framework :: Twisted",
"Intended Audience :: Developers",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Software Development",
"Topic :: Software Development :: Bug Tracking",
"Topic :: Software Development :: Testing",
"Topic :: Software Development :: Quality Assurance",
"Topic :: System :: Logging",
"Topic :: System :: Monitoring",
]
requires-python = ">=3.9"
dependencies = [
"requests>=0.12.1",
]
[dependency-groups]
test = [
"blinker",
"httpx",
"pytest",
"webob",
]
[project.urls]
Homepage = "https://rollbar.com/"
Documentation = "https://docs.rollbar.com/docs/python"
Changes = "https://github.com/rollbar/pyrollbar/blob/master/CHANGELOG.md"
Source = "https://github.com/rollbar/pyrollbar/"
[project.scripts]
rollbar = "rollbar.cli:main"
[project.entry-points."paste.filter_app_factory"]
pyramid = "rollbar.contrib.pyramid:create_rollbar_middleware"
[tool.pytest]
testpaths = [
"rollbar/test",
]
[tool.setuptools.dynamic]
version = {attr = "rollbar.__version__"}
[tool.tox]
requires = ["tox>=4.22"]
[tool.tox.env_run_base]
dependency_groups = ["test"]
description = "run unit tests"
commands = [["pytest", "{posargs}"]]
================================================
FILE: rollbar/__init__.py
================================================
from __future__ import absolute_import, annotations
from __future__ import unicode_literals
import copy
import functools
import inspect
import json
import logging
import os
import socket
import sys
import threading
import time
import traceback
import types
import uuid
import wsgiref.util
import warnings
import queue
from urllib.parse import parse_qs, urljoin
import requests
from rollbar.lib import events, filters, dict_merge, transport, defaultJSONEncode
from rollbar.lib.payload import Attribute
from rollbar.lib.session import get_current_session, set_current_session, parse_session_request_baggage_headers
__version__ = '1.4.0-beta'
__log_name__ = 'rollbar'
log = logging.getLogger(__log_name__)
# import request objects from various frameworks, if available
try:
from webob import BaseRequest as WebobBaseRequest
except ImportError:
WebobBaseRequest = None
try:
from django.core.exceptions import ImproperlyConfigured
except ImportError:
DjangoHttpRequest = None
RestFrameworkRequest = None
else:
try:
from django.http import HttpRequest as DjangoHttpRequest
except (ImportError, ImproperlyConfigured):
DjangoHttpRequest = None
try:
from rest_framework.request import Request as RestFrameworkRequest
except (ImportError, ImproperlyConfigured):
RestFrameworkRequest = None
del ImproperlyConfigured
try:
from werkzeug.wrappers import Request as WerkzeugRequest
except (ImportError, SyntaxError):
WerkzeugRequest = None
try:
from werkzeug.local import LocalProxy as WerkzeugLocalProxy
except (ImportError, SyntaxError):
WerkzeugLocalProxy = None
try:
from tornado.httpserver import HTTPRequest as TornadoRequest
except ImportError:
TornadoRequest = None
try:
from bottle import BaseRequest as BottleRequest
except ImportError:
BottleRequest = None
try:
from sanic.request import Request as SanicRequest
except ImportError:
SanicRequest = None
try:
from google.appengine.api.urlfetch import fetch as AppEngineFetch
except (ImportError, KeyError):
AppEngineFetch = None
try:
from starlette.requests import Request as StarletteRequest
except ImportError:
StarletteRequest = None
try:
from fastapi.requests import Request as FastAPIRequest
except ImportError:
FastAPIRequest = None
try:
import httpx
except ImportError:
httpx = None
AsyncHTTPClient = httpx
def passthrough_decorator(func):
def wrap(*args, **kwargs):
return func(*args, **kwargs)
return wrap
try:
from tornado.httpclient import AsyncHTTPClient as TornadoAsyncHTTPClient
except ImportError:
TornadoAsyncHTTPClient = None
try:
import treq
from twisted.python import log as twisted_log
from twisted.web.iweb import IPolicyForHTTPS
from twisted.web.client import BrowserLikePolicyForHTTPS, Agent
from twisted.internet.ssl import CertificateOptions
from twisted.internet import task, defer, ssl, reactor
from zope.interface import implementer
@implementer(IPolicyForHTTPS)
class VerifyHTTPS(object):
def __init__(self):
# by default, handle requests like a browser would
self.default_policy = BrowserLikePolicyForHTTPS()
def creatorForNetloc(self, hostname, port):
# check if the hostname is in the the whitelist, otherwise return the default policy
if not SETTINGS['verify_https']:
return ssl.CertificateOptions(verify=False)
return self.default_policy.creatorForNetloc(hostname, port)
def log_handler(event):
"""
Default uncaught error handler
"""
try:
if not event.get('isError') or 'failure' not in event:
return
err = event['failure']
# Don't report Rollbar internal errors to ourselves
if issubclass(err.type, ApiException):
log.error('Rollbar internal error: %s', err.value)
else:
report_exc_info((err.type, err.value, err.getTracebackObject()))
except:
log.exception('Error while reporting to Rollbar')
# Add Rollbar as a log handler which will report uncaught errors
twisted_log.addObserver(log_handler)
except ImportError:
treq = None
try:
from falcon import Request as FalconRequest
except ImportError:
FalconRequest = None
def get_request():
"""
Get the current request object. Implementation varies on
library support. Modified below when we know which framework
is being used.
"""
# TODO(cory): add in a generic _get_locals_request() which
# will iterate up through the call stack and look for a variable
# that appears to be valid request object.
for fn in (_get_fastapi_request,
_get_starlette_request,
_get_bottle_request,
_get_flask_request,
_get_pyramid_request,
_get_pylons_request):
try:
req = fn()
if req is not None:
return req
except:
pass
return None
def _get_bottle_request():
if BottleRequest is None:
return None
from bottle import request
return request
def _get_flask_request():
if WerkzeugRequest is None:
return None
from flask import request
return request
def _get_pyramid_request():
if WebobBaseRequest is None:
return None
from pyramid.threadlocal import get_current_request
return get_current_request()
def _get_pylons_request():
if WebobBaseRequest is None:
return None
from pylons import request
return request
def _get_starlette_request():
# Do not modify the returned object
if StarletteRequest is None:
return None
from rollbar.contrib.starlette import get_current_request
return get_current_request()
def _get_fastapi_request():
# Do not modify the returned object
if FastAPIRequest is None:
return None
from rollbar.contrib.fastapi import get_current_request
return get_current_request()
BASE_DATA_HOOK = None
agent_log = None
VERSION = __version__
DEFAULT_ENDPOINT = 'https://api.rollbar.com/api/1/'
DEFAULT_TIMEOUT = 3
ANONYMIZE = 'anonymize'
DEFAULT_LOCALS_SIZES = {
'maxlevel': 5,
'maxdict': 10,
'maxlist': 10,
'maxtuple': 10,
'maxset': 10,
'maxfrozenset': 10,
'maxdeque': 10,
'maxarray': 10,
'maxstring': 100,
'maxlong': 40,
'maxother': 100,
}
# configuration settings
# configure by calling init() or overriding directly
SETTINGS = {
'access_token': None,
'enabled': True,
'environment': 'production',
'exception_level_filters': [],
'root': None, # root path to your code
'host': None, # custom hostname of the current host
'branch': None, # git branch name
'code_version': None,
# 'blocking', 'thread' (default), 'async', 'agent', 'tornado', 'gae', 'twisted', 'httpx' or 'thread_pool'
# 'async' requires Python 3.4 or higher.
# 'httpx' requires Python 3.7 or higher.
# 'thread_pool' requires Python 3.2 or higher.
'handler': 'default',
'thread_pool_workers': None,
'endpoint': DEFAULT_ENDPOINT,
'timeout': DEFAULT_TIMEOUT,
'agent.log_file': 'log.rollbar',
'scrub_fields': [
'pw',
'passwd',
'password',
'secret',
'confirm_password',
'confirmPassword',
'password_confirmation',
'passwordConfirmation',
'access_token',
'accessToken',
'auth',
'authentication',
'authorization',
],
'url_fields': ['url', 'link', 'href'],
'notifier': {
'name': 'pyrollbar',
'version': VERSION
},
'allow_logging_basic_config': True, # set to False to avoid a call to logging.basicConfig()
'locals': {
'enabled': True,
'safe_repr': True,
'scrub_varargs': True,
'sizes': DEFAULT_LOCALS_SIZES,
'safelisted_types': [],
'whitelisted_types': []
},
'verify_https': True,
'shortener_keys': [],
'suppress_reinit_warning': False,
'capture_email': False,
'capture_username': False,
'capture_ip': True,
'log_all_rate_limited_items': True,
'log_payload_on_error': True,
'http_proxy': None,
'http_proxy_user': None,
'http_proxy_password': None,
'include_request_body': False,
'request_pool_connections': None,
'request_pool_maxsize': None,
'request_max_retries': None,
'batch_transforms': False,
'custom_transforms': [],
}
_CURRENT_LAMBDA_CONTEXT = None
_LAST_RESPONSE_STATUS = None
# Set in init()
_transforms = []
_serialize_transform = None
_scrub_redact_transform = None
_initialized = False
from rollbar.lib.transforms.scrub_redact import REDACT_REF
from rollbar.lib import transforms
from rollbar.lib import type_info
from rollbar.lib.transforms.scrub import ScrubTransform
from rollbar.lib.transforms.scruburl import ScrubUrlTransform
from rollbar.lib.transforms.scrub_redact import ScrubRedactTransform
from rollbar.lib.transforms.serializable import SerializableTransform
from rollbar.lib.transforms.shortener import ShortenerTransform
from rollbar.lib.transforms.batched import BatchedTransform
## public api
def init(access_token, environment='production', scrub_fields=None, url_fields=None, **kw):
"""
Saves configuration variables in this module's SETTINGS.
access_token: project access token. Get this from the Rollbar UI:
- click "Settings" in the top nav
- click "Projects" in the left nav
- copy-paste the appropriate token.
environment: environment name. Can be any string; suggestions: 'production', 'development',
'staging', 'yourname'
**kw: provided keyword arguments will override keys in SETTINGS.
"""
global SETTINGS, agent_log, _initialized, _transforms, _serialize_transform, _scrub_redact_transform, _threads
if scrub_fields is not None:
SETTINGS['scrub_fields'] = list(scrub_fields)
if url_fields is not None:
SETTINGS['url_fields'] = list(url_fields)
# Merge the extra config settings into SETTINGS
SETTINGS = dict_merge(SETTINGS, kw)
if _initialized:
# NOTE: Temp solution to not being able to re-init.
# New versions of pyrollbar will support re-initialization
# via the (not-yet-implemented) configure() method.
if not SETTINGS.get('suppress_reinit_warning'):
log.warning('Rollbar already initialized. Ignoring re-init.')
return
SETTINGS['access_token'] = access_token
SETTINGS['environment'] = environment
_configure_transport(**SETTINGS)
if SETTINGS.get('allow_logging_basic_config'):
logging.basicConfig()
if SETTINGS.get('handler') == 'agent':
agent_log = _create_agent_log()
elif SETTINGS.get('handler') == 'thread_pool':
from rollbar.lib.thread_pool import init_pool
init_pool(SETTINGS.get('thread_pool_workers', None))
if not SETTINGS['locals']['safelisted_types'] and SETTINGS['locals']['whitelisted_types']:
warnings.warn('whitelisted_types deprecated use safelisted_types instead', DeprecationWarning)
SETTINGS['locals']['safelisted_types'] = SETTINGS['locals']['whitelisted_types']
# We will perform these transforms in order:
# 1. Serialize the payload to be all python built-in objects
# 2. Scrub the payloads based on the key suffixes in SETTINGS['scrub_fields']
# 3. Scrub URLs in the payload for keys that end with 'url'
# 4. Optional - If local variable gathering is enabled, transform the
# trace frame values using the ShortReprTransform.
_serialize_transform = SerializableTransform(safe_repr=SETTINGS['locals']['safe_repr'],
safelist_types=SETTINGS['locals']['safelisted_types'])
_scrub_redact_transform = ScrubRedactTransform(suffixes=[(field,) for field in SETTINGS['scrub_fields']], redact_char='*')
# A list of key prefixes to apply our shortener transform to. The request
# being included in the body key is old behavior and is being retained for
# backwards compatibility.
shortener_keys = [
('request', 'POST'),
('request', 'json'),
('body', 'request', 'POST'),
('body', 'request', 'json'),
]
if SETTINGS['locals']['enabled']:
for prefix in (('body', 'trace'), ('body', 'trace_chain', '*')):
shortener_keys.append(prefix + ('frames', '*', 'code'))
shortener_keys.append(prefix + ('frames', '*', 'args', '*'))
shortener_keys.append(prefix + ('frames', '*', 'kwargs', '*'))
shortener_keys.append(prefix + ('frames', '*', 'locals', '*'))
shortener_keys.extend(SETTINGS['shortener_keys'])
shortener = ShortenerTransform(safe_repr=SETTINGS['locals']['safe_repr'],
keys=shortener_keys,
**SETTINGS['locals']['sizes'])
_transforms = [
shortener, # priority: 10
_scrub_redact_transform, # priority: 20
_serialize_transform, # priority: 30
ScrubUrlTransform(suffixes=[(field,) for field in SETTINGS['url_fields']],
params_to_scrub=SETTINGS['scrub_fields']) # priority: 50
]
# Add custom transforms
if len(SETTINGS['custom_transforms']) > 0:
_transforms.extend(SETTINGS['custom_transforms'])
# Sort the transforms by priority
_transforms = sorted(_transforms, key=lambda x: x.priority)
_threads = queue.Queue()
events.reset()
filters.add_builtin_filters(SETTINGS)
_initialized = True
def _configure_transport(**kw):
configuration = _requests_configuration(**kw)
transport.configure_pool(**configuration)
def _requests_configuration(**kw):
keys = {
'request_pool_connections': 'pool_connections',
'request_pool_maxsize': 'pool_maxsize',
'request_max_retries': 'max_retries',
}
return {keys[k]: kw.get(k, None) for k in keys}
def lambda_function(f):
"""
Decorator for making error handling on AWS Lambda easier
"""
@functools.wraps(f)
def wrapper(event, context):
global _CURRENT_LAMBDA_CONTEXT
_CURRENT_LAMBDA_CONTEXT = context
try:
result = f(event, context)
return wait(lambda: result)
except:
cls, exc, trace = sys.exc_info()
report_exc_info((cls, exc, trace.tb_next))
wait()
raise
return wrapper
def report_exc_info(exc_info=None, request=None, extra_data=None, payload_data=None, level=None, **kw):
"""
Reports an exception to Rollbar, using exc_info (from calling sys.exc_info())
exc_info: optional, should be the result of calling sys.exc_info(). If omitted, sys.exc_info() will be called here.
request: optional, a WebOb, Werkzeug-based or Sanic request object.
extra_data: optional, will be included in the 'custom' section of the payload
payload_data: optional, dict that will override values in the final payload
(e.g. 'level' or 'fingerprint')
kw: provided for legacy purposes; unused.
Example usage:
rollbar.init(access_token='YOUR_PROJECT_ACCESS_TOKEN')
try:
do_something()
except:
rollbar.report_exc_info(sys.exc_info(), request, {'foo': 'bar'}, {'level': 'warning'})
"""
if exc_info is None:
exc_info = sys.exc_info()
try:
return _report_exc_info(exc_info, request, extra_data, payload_data, level=level)
except Exception as e:
log.exception("Exception while reporting exc_info to Rollbar. %r", e)
def report_message(message, level='error', request=None, extra_data=None, payload_data=None):
"""
Reports an arbitrary string message to Rollbar.
message: the string body of the message
level: level to report at. One of: 'critical', 'error', 'warning', 'info', 'debug'
request: the request object for the context of the message
extra_data: optional, will be included in the 'custom' section of the payload
payload_data: param names to pass in the 'data' level of the payload; overrides defaults.
"""
try:
return _report_message(message, level, request, extra_data, payload_data)
except Exception as e:
log.exception("Exception while reporting message to Rollbar. %r", e)
def send_payload(payload, access_token):
"""
Sends a payload object, (the result of calling _build_payload() + _serialize_payload()).
Uses the configured handler from SETTINGS['handler']
Available handlers:
- 'blocking': calls _send_payload() (which makes an HTTP request) immediately, blocks on it
- 'thread': starts a single-use thread that will call _send_payload(). returns immediately.
- 'async': calls _send_payload_async() (which makes an async HTTP request using default async handler)
- 'agent': writes to a log file to be processed by rollbar-agent
- 'tornado': calls _send_payload_tornado() (which makes an async HTTP request using tornado's AsyncHTTPClient)
- 'gae': calls _send_payload_appengine() (which makes a blocking call to Google App Engine)
- 'twisted': calls _send_payload_twisted() (which makes an async HTTP request using Twisted and Treq)
- 'httpx': calls _send_payload_httpx() (which makes an async HTTP request using HTTPX)
- 'thread_pool': uses a pool of worker threads to make HTTP requests off the main thread. Returns immediately.
"""
payload = events.on_payload(payload)
if payload is False:
return
if sys.version_info >= (3, 6):
from rollbar.lib._async import get_current_handler
handler = get_current_handler()
else:
handler = SETTINGS.get('handler')
if handler == 'twisted':
payload['data']['framework'] = 'twisted'
payload_str = _serialize_payload(payload)
if handler == 'blocking':
_send_payload(payload_str, access_token)
elif handler == 'agent':
agent_log.error(payload_str)
elif handler == 'tornado':
if TornadoAsyncHTTPClient is None:
log.error('Unable to find tornado')
return
_send_payload_tornado(payload_str, access_token)
elif handler == 'gae':
if AppEngineFetch is None:
log.error('Unable to find AppEngine URLFetch module')
return
_send_payload_appengine(payload_str, access_token)
elif handler == 'twisted':
if treq is None:
log.error('Unable to find Treq')
return
_send_payload_twisted(payload_str, access_token)
elif handler == 'httpx':
if httpx is None:
log.error('Unable to find HTTPX')
return
_send_payload_httpx(payload_str, access_token)
elif handler == 'async':
if AsyncHTTPClient is None:
log.error('Unable to find async handler')
return
_send_payload_async(payload_str, access_token)
elif handler == 'thread':
_send_payload_thread(payload_str, access_token)
elif handler == 'thread_pool':
_send_payload_thread_pool(payload_str, access_token)
else:
# default to 'thread'
_send_payload_thread(payload_str, access_token)
def search_items(title, return_fields=None, access_token=None, endpoint=None, **search_fields):
"""
Searches a project for items that match the input criteria.
title: all or part of the item's title to search for.
return_fields: the fields that should be returned for each item.
e.g. ['id', 'project_id', 'status'] will return a dict containing
only those fields for each item.
access_token: a project access token. If this is not provided,
the one provided to init() will be used instead.
search_fields: additional fields to include in the search.
currently supported: status, level, environment
"""
if not title:
return []
if return_fields is not None:
return_fields = ','.join(return_fields)
return _get_api('search/',
title=title,
fields=return_fields,
access_token=access_token,
endpoint=endpoint,
**search_fields)
def wait(f=None):
_threads.join()
if f is not None:
return f()
class ApiException(Exception):
"""
This exception will be raised if there was a problem decoding the
response from an API call.
"""
pass
class ApiError(ApiException):
"""
This exception will be raised if the API response contains an 'err'
field, denoting there was a problem fulfilling the api request.
"""
pass
class Result(object):
"""
This class encapsulates the response from an API call.
Usage:
result = search_items(title='foo', fields=['id'])
print result.data
"""
def __init__(self, access_token, path, params, data):
self.access_token = access_token
self.path = path
self.params = params
self.data = data
def __str__(self):
return str(self.data)
class PagedResult(Result):
"""
This class wraps the response from an API call that responded with
a page of results.
Usage:
result = search_items(title='foo', fields=['id'])
print 'First page: %d, data: %s' % (result.page, result.data)
result = result.next_page()
print 'Second page: %d, data: %s' % (result.page, result.data)
"""
def __init__(self, access_token, path, page_num, params, data, endpoint=None):
super(PagedResult, self).__init__(access_token, path, params, data)
self.page = page_num
self.endpoint = endpoint
def next_page(self):
params = copy.copy(self.params)
params['page'] = self.page + 1
return _get_api(self.path, endpoint=self.endpoint, **params)
def prev_page(self):
if self.page <= 1:
return self
params = copy.copy(self.params)
params['page'] = self.page - 1
return _get_api(self.path, endpoint=self.endpoint, **params)
## internal functions
def _resolve_exception_class(idx, filter):
cls, level = filter
if isinstance(cls, str):
# Lazily resolve class name
parts = cls.split('.')
module = '.'.join(parts[:-1])
if module in sys.modules and hasattr(sys.modules[module], parts[-1]):
cls = getattr(sys.modules[module], parts[-1])
SETTINGS['exception_level_filters'][idx] = (cls, level)
else:
cls = None
return cls, level
def _filtered_level(exception):
for i, filter in enumerate(SETTINGS['exception_level_filters']):
cls, level = _resolve_exception_class(i, filter)
if cls and isinstance(exception, cls):
return level
return None
def _is_ignored(exception):
return _filtered_level(exception) == 'ignored'
def _create_agent_log():
"""
Creates .rollbar log file for use with rollbar-agent
"""
log_file = SETTINGS['agent.log_file']
if not log_file.endswith('.rollbar'):
log.error("Provided agent log file does not end with .rollbar, which it must. "
"Using default instead.")
log_file = DEFAULTS['agent.log_file']
retval = logging.getLogger('rollbar_agent')
handler = logging.FileHandler(log_file, 'a', 'utf-8')
formatter = logging.Formatter('%(message)s')
handler.setFormatter(formatter)
retval.addHandler(handler)
retval.setLevel(logging.WARNING)
return retval
def _report_exc_info(exc_info, request, extra_data, payload_data, level=None):
"""
Called by report_exc_info() wrapper
"""
if not _check_config():
return
filtered_level = _filtered_level(exc_info[1])
if level is None:
level = filtered_level
filtered_exc_info = events.on_exception_info(exc_info,
request=request,
extra_data=extra_data,
payload_data=payload_data,
level=level)
if filtered_exc_info is False:
return
cls, exc, trace = filtered_exc_info
data = _build_base_data(request)
if level is not None:
data['level'] = level
# walk the trace chain to collect cause and context exceptions
trace_chain = _walk_trace_chain(cls, exc, trace)
extra_trace_data = None
if len(trace_chain) > 1:
data['body'] = {
'trace_chain': trace_chain
}
if payload_data and ('body' in payload_data) and ('trace' in payload_data['body']):
extra_trace_data = payload_data['body']['trace']
del payload_data['body']['trace']
else:
data['body'] = {
'trace': trace_chain[0]
}
if extra_data:
extra_data = extra_data
if not isinstance(extra_data, dict):
extra_data = {'value': extra_data}
if extra_trace_data:
extra_data = dict_merge(extra_data, extra_trace_data, silence_errors=True)
data['custom'] = extra_data
if extra_trace_data and not extra_data:
data['custom'] = extra_trace_data
request = _get_actual_request(request)
_add_request_data(data, request)
_add_person_data(data, request)
_add_lambda_context_data(data)
_add_session_data(data)
data['server'] = _build_server_data()
if payload_data:
data = dict_merge(data, payload_data, silence_errors=True)
payload = _build_payload(data)
send_payload(payload, payload.get('access_token'))
return data['uuid']
def _walk_trace_chain(cls, exc, trace):
trace_chain = [_trace_data(cls, exc, trace)]
seen_exceptions = {exc}
while True:
exc = getattr(exc, '__cause__', None) or getattr(exc, '__context__', None)
if not exc:
break
trace_chain.append(_trace_data(type(exc), exc, getattr(exc, '__traceback__', None)))
if exc in seen_exceptions:
break
seen_exceptions.add(exc)
return trace_chain
def _trace_data(cls, exc, trace):
# exception info
# most recent call last
raw_frames = traceback.extract_tb(trace)
frames = [{'filename': f[0], 'lineno': f[1], 'method': f[2], 'code': f[3]} for f in raw_frames]
trace_data = {
'frames': frames,
'exception': {
'class': getattr(cls, '__name__', cls.__class__.__name__),
'message': str(exc),
}
}
_add_locals_data(trace_data, (cls, exc, trace))
return trace_data
def _report_message(message, level, request, extra_data, payload_data):
"""
Called by report_message() wrapper
"""
if not _check_config():
return
filtered_message = events.on_message(message,
request=request,
extra_data=extra_data,
payload_data=payload_data,
level=level)
if filtered_message is False:
return
data = _build_base_data(request, level=level)
# message
data['body'] = {
'message': {
'body': filtered_message
}
}
if extra_data:
extra_data = extra_data
data['body']['message'].update(extra_data)
data['custom'] = extra_data
request = _get_actual_request(request)
_add_request_data(data, request)
_add_person_data(data, request)
_add_lambda_context_data(data)
_add_session_data(data)
data['server'] = _build_server_data()
if payload_data:
data = dict_merge(data, payload_data, silence_errors=True)
payload = _build_payload(data)
send_payload(payload, payload.get('access_token'))
return data['uuid']
def _add_session_data(data: dict) -> None:
"""
Adds session data to the payload data if it can be found in the current session or request.
"""
session_data = get_current_session()
if session_data:
_add_session_attributes(data, session_data)
return
request = _session_data_from_request(data)
if request is None:
return
session_data = parse_session_request_baggage_headers(request.get('headers', None))
if session_data:
_add_session_attributes(data, session_data)
def _add_session_attributes(data: dict, session_data: list[Attribute]) -> None:
"""
Adds session attributes to the payload data. This function is careful to not overwrite any existing data in the
payload.
"""
if 'attributes' not in data:
data['attributes'] = session_data
return
existing_keys = {a['key'] for a in data['attributes']}
for attribute in session_data:
if attribute['key'] not in existing_keys:
data['attributes'].append(attribute)
def _session_data_from_request(data: dict) -> dict:
"""
Tries to find session data in the request object. Use the request object if provided, otherwise check the data as
it may already contain the request object. This is true for some frameworks (e.g. Django).
"""
if data is not None and 'request' in data:
return data.get('request', None)
return _get_actual_request(_build_request_data(get_request()))
def _check_config():
if not SETTINGS.get('enabled'):
log.info("pyrollbar: Not reporting because rollbar is disabled.")
return False
# skip access token check for the agent handler
if SETTINGS.get('handler') == 'agent':
return True
# make sure we have an access_token
if not SETTINGS.get('access_token'):
log.warning("pyrollbar: No access_token provided. Please configure by calling rollbar.init() with your access token.")
return False
return True
def _build_base_data(request, level='error'):
data = {
'timestamp': int(time.time()),
'environment': SETTINGS['environment'],
'level': level,
'language': 'python %s' % '.'.join(str(x) for x in sys.version_info[:3]),
'notifier': SETTINGS['notifier'],
'uuid': str(uuid.uuid4()),
}
if SETTINGS.get('code_version'):
data['code_version'] = SETTINGS['code_version']
if BASE_DATA_HOOK:
BASE_DATA_HOOK(request, data)
return data
def _add_person_data(data, request):
try:
person_data = _build_person_data(request)
except Exception as e:
log.exception("Exception while building person data for Rollbar payload: %r", e)
else:
if person_data:
if not SETTINGS['capture_username'] and 'username' in person_data:
person_data['username'] = None
if not SETTINGS['capture_email'] and 'email' in person_data:
person_data['email'] = None
data['person'] = person_data
def _build_person_data(request):
"""
Returns a dictionary describing the logged-in user using data from `request`.
Try request.rollbar_person first, then 'user', then 'user_id'
"""
if hasattr(request, 'rollbar_person'):
rollbar_person_prop = request.rollbar_person
person = rollbar_person_prop() if callable(rollbar_person_prop) else rollbar_person_prop
if person and isinstance(person, dict):
return person
else:
return None
if StarletteRequest:
from rollbar.contrib.starlette.requests import hasuser
else:
def hasuser(request): return True
if hasuser(request) and hasattr(request, 'user'):
user_prop = request.user
user = user_prop() if callable(user_prop) else user_prop
if not user:
return None
elif isinstance(user, dict):
return user
else:
retval = {}
if getattr(user, 'id', None):
retval['id'] = str(user.id)
elif getattr(user, 'user_id', None):
retval['id'] = str(user.user_id)
# id is required, so only include username/email if we have an id
if retval.get('id'):
username = getattr(user, 'username', None)
email = getattr(user, 'email', None)
retval.update({
'username': username,
'email': email
})
return retval
if hasattr(request, 'user_id'):
user_id_prop = request.user_id
user_id = user_id_prop() if callable(user_id_prop) else user_id_prop
if not user_id:
return None
return {'id': str(user_id)}
def _get_func_from_frame(frame):
func_name = inspect.getframeinfo(frame).function
caller = frame.f_back
if caller:
func = caller.f_locals.get(func_name,
caller.f_globals.get(func_name))
else:
func = None
return func
def _add_locals_data(trace_data, exc_info):
if not SETTINGS['locals']['enabled']:
return
frames = trace_data['frames']
cur_tb = exc_info[2]
frame_num = 0
num_frames = len(frames)
while cur_tb:
cur_frame = frames[frame_num]
tb_frame = cur_tb.tb_frame
cur_tb = cur_tb.tb_next
if not isinstance(tb_frame, types.FrameType):
# this can happen if the traceback or frame is wrapped in some way,
# for example by `ExceptionInfo` in
# https://github.com/celery/billiard/blob/master/billiard/einfo.py
log.warning('Traceback frame not a types.FrameType. Ignoring.')
frame_num += 1
continue
# Create placeholders for argspec/varargspec/keywordspec/locals
argspec = None
varargspec = None
keywordspec = None
_locals = {}
try:
arginfo = inspect.getargvalues(tb_frame)
# Optionally fill in locals for this frame
if arginfo.locals and _check_add_locals(cur_frame, frame_num, num_frames):
# Get all of the named args
argspec = arginfo.args
if arginfo.varargs is not None:
varargspec = arginfo.varargs
if SETTINGS['locals']['scrub_varargs']:
temp_varargs = list(arginfo.locals[varargspec])
for i, arg in enumerate(temp_varargs):
temp_varargs[i] = REDACT_REF
arginfo.locals[varargspec] = tuple(temp_varargs)
if arginfo.keywords is not None:
keywordspec = arginfo.keywords
_locals.update(arginfo.locals.items())
except Exception:
log.exception('Error while extracting arguments from frame. Ignoring.')
# Finally, serialize each arg/kwarg/local separately so that we only report
# CircularReferences for each variable, instead of for the entire payload
# as would be the case if we serialized that payload in one-shot.
if argspec:
cur_frame['argspec'] = argspec
if varargspec:
cur_frame['varargspec'] = varargspec
if keywordspec:
cur_frame['keywordspec'] = keywordspec
if _locals:
try:
cur_frame['locals'] = {k: _serialize_frame_data(v) for k, v in _locals.items()}
except Exception:
log.exception('Error while serializing frame data.')
frame_num += 1
def _serialize_frame_data(data):
return transforms.transform(
data,
[_scrub_redact_transform, _serialize_transform],
batch_transforms=SETTINGS['batch_transforms']
)
def _add_lambda_context_data(data):
"""
Attempts to add information from the lambda context if it exists
"""
global _CURRENT_LAMBDA_CONTEXT
context = _CURRENT_LAMBDA_CONTEXT
if context is None:
return
try:
lambda_data = {
'lambda': {
'remaining_time_in_millis': context.get_remaining_time_in_millis(),
'function_name': context.function_name,
'function_version': context.function_version,
'arn': context.invoked_function_arn,
'request_id': context.aws_request_id,
}
}
if 'custom' in data:
data['custom'] = dict_merge(data['custom'], lambda_data, silence_errors=True)
else:
data['custom'] = lambda_data
except Exception as e:
log.exception("Exception while adding lambda context data: %r", e)
finally:
_CURRENT_LAMBDA_CONTEXT = None
def _add_request_data(data, request):
"""
Attempts to build request data; if successful, sets the 'request' key on `data`.
"""
try:
request_data = _build_request_data(request)
except Exception as e:
log.exception("Exception while building request_data for Rollbar payload: %r", e)
else:
if request_data:
_filter_ip(request_data, SETTINGS['capture_ip'])
data['request'] = request_data
def _check_add_locals(frame, frame_num, total_frames):
"""
Returns True if we should record local variables for the given frame.
"""
# Include the last frames locals
# Include any frame locals that came from a file in the project's root
root = SETTINGS.get('root')
if root:
# coerce to string, in case root is a Path object
root = str(root)
else:
root = ''
return any(((frame_num == total_frames - 1),
('root' in SETTINGS and (frame.get('filename') or '').lower().startswith(root.lower()))))
def _get_actual_request(request):
if WerkzeugLocalProxy and isinstance(request, WerkzeugLocalProxy):
try:
actual_request = request._get_current_object()
except RuntimeError:
return None
return actual_request
return request
def _build_request_data(request):
"""
Returns a dictionary containing data from the request.
"""
# webob (pyramid)
if WebobBaseRequest and isinstance(request, WebobBaseRequest):
return _build_webob_request_data(request)
# django
if DjangoHttpRequest and isinstance(request, DjangoHttpRequest):
return _build_django_request_data(request)
# django rest framework
if RestFrameworkRequest and isinstance(request, RestFrameworkRequest):
return _build_django_request_data(request)
# werkzeug (flask)
if WerkzeugRequest and isinstance(request, WerkzeugRequest):
return _build_werkzeug_request_data(request)
# tornado
if TornadoRequest and isinstance(request, TornadoRequest):
return _build_tornado_request_data(request)
# bottle
if BottleRequest and isinstance(request, BottleRequest):
return _build_bottle_request_data(request)
# Sanic
if SanicRequest and isinstance(request, SanicRequest):
return _build_sanic_request_data(request)
# falcon
if FalconRequest and isinstance(request, FalconRequest):
return _build_falcon_request_data(request)
# Plain wsgi (should be last)
if isinstance(request, dict) and 'wsgi.version' in request:
return _build_wsgi_request_data(request)
# FastAPI (built on top of Starlette, so keep the order)
if FastAPIRequest and isinstance(request, FastAPIRequest):
return _build_fastapi_request_data(request)
# Starlette (should be the last one for Starlette based frameworks)
if StarletteRequest and isinstance(request, StarletteRequest):
return _build_starlette_request_data(request)
return None
def _build_webob_request_data(request):
request_data = {
'url': request.url,
'GET': dict(request.GET),
'user_ip': _extract_user_ip(request),
'headers': dict(request.headers),
'method': request.method,
}
try:
if request.json:
request_data['json'] = request.json
except:
pass
# pyramid matchdict
if getattr(request, 'matchdict', None):
request_data['params'] = request.matchdict
# workaround for webob bug when the request body contains binary data but has a text
# content-type
try:
request_data['POST'] = dict(request.POST)
except UnicodeDecodeError:
request_data['body'] = request.body
return request_data
def _extract_wsgi_headers(items):
headers = {}
for k, v in items:
if k.startswith('HTTP_'):
header_name = '-'.join(k[len('HTTP_'):].replace('_', ' ').title().split(' '))
headers[header_name] = v
return headers
def _build_django_request_data(request):
url = request.build_absolute_uri()
request_data = {
'url': url,
'method': request.method,
'GET': dict(request.GET),
'POST': dict(request.POST),
'user_ip': _wsgi_extract_user_ip(request.META),
}
if SETTINGS['include_request_body']:
try:
request_data['body'] = request.body
except:
pass
request_data['headers'] = _extract_wsgi_headers(request.META.items())
return request_data
def _build_werkzeug_request_data(request):
request_data = {
'url': request.url,
'GET': dict(request.args),
'POST': dict(request.form),
'user_ip': _extract_user_ip(request),
'headers': dict(request.headers),
'method': request.method,
'files_keys': list(request.files.keys()),
}
if SETTINGS['include_request_body']:
try:
if request.json:
request_data['body'] = request.json
except Exception:
pass
return request_data
def _build_tornado_request_data(request):
request_data = {
'url': request.full_url(),
'user_ip': request.remote_ip,
'headers': dict(request.headers),
'method': request.method,
'files_keys': request.files.keys(),
'start_time': getattr(request, '_start_time', None),
}
request_data[request.method] = request.arguments
return request_data
def _build_bottle_request_data(request):
request_data = {
'url': request.url,
'user_ip': request.remote_addr,
'headers': dict(request.headers),
'method': request.method,
'GET': dict(request.query)
}
if SETTINGS['include_request_body']:
if request.json:
try:
request_data['body'] = request.body.getvalue()
except:
pass
else:
request_data['POST'] = dict(request.forms)
return request_data
def _build_sanic_request_data(request):
request_data = {
'url': request.url,
'user_ip': request.remote_addr,
'headers': request.headers,
'method': request.method,
'GET': dict(request.args)
}
if SETTINGS['include_request_body']:
if request.json:
try:
request_data['body'] = request.json
except:
pass
else:
request_data['POST'] = request.form
return request_data
def _build_falcon_request_data(request):
request_data = {
'url': request.url,
'user_ip': _wsgi_extract_user_ip(request.env),
'headers': dict(request.headers),
'method': request.method,
'GET': dict(request.params),
'context': dict(request.context),
}
return request_data
def _build_wsgi_request_data(request):
request_data = {
'url': wsgiref.util.request_uri(request),
'user_ip': _wsgi_extract_user_ip(request),
'method': request.get('REQUEST_METHOD'),
}
if 'QUERY_STRING' in request:
request_data['GET'] = parse_qs(request['QUERY_STRING'], keep_blank_values=True)
# Collapse single item arrays
request_data['GET'] = {k: (v[0] if len(v) == 1 else v) for k, v in request_data['GET'].items()}
request_data['headers'] = _extract_wsgi_headers(request.items())
if SETTINGS['include_request_body']:
try:
length = int(request.get('CONTENT_LENGTH', 0))
except ValueError:
length = 0
input = request.get('wsgi.input')
if length and input and hasattr(input, 'seek') and hasattr(input, 'tell'):
pos = input.tell()
input.seek(0, 0)
request_data['body'] = input.read(length)
input.seek(pos, 0)
return request_data
def _build_starlette_request_data(request):
from starlette.datastructures import UploadFile
request_data = {
'url': str(request.url),
'GET': dict(request.query_params),
'headers': dict(request.headers),
'method': request.method,
'user_ip': _starlette_extract_user_ip(request),
'params': dict(request.path_params),
}
if hasattr(request, '_form') and request._form is not None:
request_data['POST'] = {
k: v.filename if isinstance(v, UploadFile) else v
for k, v in request._form.items()
}
request_data['files_keys'] = [
field.filename
for field in request._form.values()
if isinstance(field, UploadFile)
]
if hasattr(request, '_body'):
body = request._body.decode()
else:
body = None
if body and SETTINGS['include_request_body']:
request_data['body'] = body
if hasattr(request, '_json'):
request_data['json'] = request._json
elif body:
try:
request_data['json'] = json.loads(body)
except json.JSONDecodeError:
pass
# Filter out empty values
request_data = {k: v for k, v in request_data.items() if v}
return request_data
def _build_fastapi_request_data(request):
return _build_starlette_request_data(request)
def _filter_ip(request_data, capture_ip):
if 'user_ip' not in request_data or capture_ip == True:
return
current_ip = request_data['user_ip']
if not current_ip:
return
new_ip = current_ip
if not capture_ip:
new_ip = None
elif capture_ip == ANONYMIZE:
try:
if '.' in current_ip:
new_ip = '.'.join(current_ip.split('.')[0:3]) + '.0'
elif ':' in current_ip:
parts = current_ip.split(':')
if len(parts) > 2:
terminal = '0000:0000:0000:0000:0000'
new_ip = ':'.join(parts[0:3] + [terminal])
else:
new_ip = None
except:
new_ip = None
request_data['user_ip'] = new_ip
def _build_server_data():
"""
Returns a dictionary containing information about the server environment.
"""
# server environment
host = SETTINGS.get('host') or socket.gethostname()
server_data = {
'host': host,
'pid': os.getpid()
}
# argv does not always exist in embedded python environments
argv = getattr(sys, 'argv', None)
if argv:
server_data['argv'] = argv
for key in ['branch', 'root']:
if SETTINGS.get(key):
server_data[key] = SETTINGS[key]
return server_data
def _transform(obj, key=None):
return transforms.transform(
obj,
_transforms,
key=key,
batch_transforms=SETTINGS['batch_transforms']
)
def _build_payload(data):
"""
Returns the full payload as a string.
"""
for k, v in data.items():
data[k] = _transform(v, key=(k,))
payload = {
'access_token': SETTINGS['access_token'],
'data': data
}
return payload
def _serialize_payload(payload):
return json.dumps(payload, default=defaultJSONEncode)
def _send_payload(payload_str, access_token):
try:
_post_api('item/', payload_str, access_token=access_token)
except Exception as e:
log.exception('Exception while posting item %r', e)
try:
_threads.get_nowait()
_threads.task_done()
except queue.Empty:
pass
def _send_payload_thread(payload_str, access_token):
thread = threading.Thread(target=_send_payload, args=(payload_str, access_token))
_threads.put(thread)
thread.start()
def _send_payload_pool(payload_str, access_token):
try:
_post_api('item/', payload_str, access_token=access_token)
except Exception as e:
log.exception('Exception while posting item %r', e)
def _send_payload_thread_pool(payload_str, access_token):
from rollbar.lib.thread_pool import submit
submit(_send_payload_pool, payload_str, access_token)
def _send_payload_appengine(payload_str, access_token):
try:
_post_api_appengine('item/', payload_str, access_token=access_token)
except Exception as e:
log.exception('Exception while posting item %r', e)
def _post_api_appengine(path, payload_str, access_token=None):
headers = {'Content-Type': 'application/json'}
if access_token is not None:
headers['X-Rollbar-Access-Token'] = access_token
url = urljoin(SETTINGS['endpoint'], path)
resp = AppEngineFetch(url,
method="POST",
payload=payload_str,
headers=headers,
allow_truncated=False,
deadline=SETTINGS.get('timeout', DEFAULT_TIMEOUT),
validate_certificate=SETTINGS.get('verify_https', True))
return _parse_response(path, SETTINGS['access_token'], payload_str, resp)
def _post_api(path, payload_str, access_token=None):
headers = {'Content-Type': 'application/json'}
if access_token is not None:
headers['X-Rollbar-Access-Token'] = access_token
url = urljoin(SETTINGS['endpoint'], path)
resp = transport.post(url,
data=payload_str,
headers=headers,
timeout=SETTINGS.get('timeout', DEFAULT_TIMEOUT),
verify=SETTINGS.get('verify_https', True),
proxy=SETTINGS.get('http_proxy'),
proxy_user=SETTINGS.get('http_proxy_user'),
proxy_password=SETTINGS.get('http_proxy_password'))
return _parse_response(path, SETTINGS['access_token'], payload_str, resp)
def _get_api(path, access_token=None, endpoint=None, **params):
access_token = access_token or SETTINGS['access_token']
url = urljoin(endpoint or SETTINGS['endpoint'], path)
params['access_token'] = access_token
resp = transport.get(url,
params=params,
verify=SETTINGS.get('verify_https', True),
proxy=SETTINGS.get('http_proxy'),
proxy_user=SETTINGS.get('http_proxy_user'),
proxy_password=SETTINGS.get('http_proxy_password'))
return _parse_response(path, access_token, params, resp, endpoint=endpoint)
def _send_payload_tornado(payload_str, access_token):
try:
_post_api_tornado('item/', payload_str, access_token=access_token)
except Exception as e:
log.exception('Exception while posting item %r', e)
def _post_api_tornado(path, payload_str, access_token=None):
headers = {'Content-Type': 'application/json'}
if access_token is not None:
headers['X-Rollbar-Access-Token'] = access_token
else:
access_token = SETTINGS['access_token']
url = urljoin(SETTINGS['endpoint'], path)
def post_tornado_cb(resp):
r = requests.Response()
r._content = resp.body
r.status_code = resp.code
r.headers.update(resp.headers)
try:
_parse_response(path, access_token, payload_str, r)
except Exception as e:
log.exception('Exception while posting item %r', e)
TornadoAsyncHTTPClient().fetch(url,
callback=post_tornado_cb,
raise_error=False,
body=payload_str,
method='POST',
connect_timeout=SETTINGS.get('timeout', DEFAULT_TIMEOUT),
request_timeout=SETTINGS.get('timeout', DEFAULT_TIMEOUT))
def _send_payload_twisted(payload_str, access_token):
try:
_post_api_twisted('item/', payload_str, access_token=access_token)
except Exception as e:
log.exception('Exception while posting item %r', e)
def _post_api_twisted(path, payload_str, access_token=None):
def post_data_cb(data, resp):
resp._content = data
_parse_response(path, SETTINGS['access_token'], payload_str, resp)
def post_cb(resp):
r = requests.Response()
r.status_code = resp.code
r.headers.update(resp.headers.getAllRawHeaders())
return treq.content(resp).addCallback(post_data_cb, r)
headers = {'Content-Type': ['application/json; charset=utf-8']}
if access_token is not None:
headers['X-Rollbar-Access-Token'] = [access_token]
url = urljoin(SETTINGS['endpoint'], path)
try:
encoded_payload = payload_str.encode('utf8')
except (UnicodeDecodeError, UnicodeEncodeError):
encoded_payload = payload_str
treq_client = treq.client.HTTPClient(Agent(reactor, contextFactory=VerifyHTTPS()))
d = treq_client.post(url, encoded_payload, headers=headers,
timeout=SETTINGS.get('timeout', DEFAULT_TIMEOUT))
d.addCallback(post_cb)
def _send_payload_httpx(payload_str, access_token):
from rollbar.lib._async import call_later, _post_api_httpx
try:
call_later(_post_api_httpx('item/', payload_str,
access_token=access_token))
except Exception as e:
log.exception('Exception while posting item %r', e)
def _send_payload_async(payload_str, access_token):
try:
_send_payload_httpx(payload_str, access_token=access_token)
except Exception as e:
log.exception('Exception while posting item %r', e)
def _send_failsafe(message, uuid, host):
body_message = ('Failsafe from pyrollbar: {0}. Original payload may be found '
'in your server logs by searching for the UUID.').format(message)
data = {
'level': 'error',
'environment': SETTINGS['environment'],
'body': {
'message': {
'body': body_message
}
},
'notifier': SETTINGS['notifier'],
'custom': {
'orig_uuid': uuid,
'orig_host': host
},
'failsafe': True,
'internal': True,
}
payload = _build_payload(data)
try:
send_payload(payload, SETTINGS['access_token'])
except Exception:
log.exception('Rollbar: Error sending failsafe.')
def _parse_response(path, access_token, params, resp, endpoint=None):
if isinstance(resp, requests.Response):
try:
data = resp.text
except Exception:
data = resp.content
log.error('resp.text is undefined, resp.content is %r', resp.content)
else:
data = resp.content
global _LAST_RESPONSE_STATUS
last_response_was_429 = _LAST_RESPONSE_STATUS == 429
_LAST_RESPONSE_STATUS = resp.status_code
if resp.status_code == 429:
if SETTINGS['log_all_rate_limited_items'] or not last_response_was_429:
log.warning("Rollbar: over rate limit, data was dropped.")
if SETTINGS['log_payload_on_error']:
log.warning("Payload was: %r", params)
return
elif resp.status_code == 502:
log.exception('Rollbar api returned a 502')
return
elif resp.status_code == 413:
uuid = None
host = None
try:
payload = json.loads(params)
uuid = payload['data']['uuid']
host = payload['data']['server']['host']
log.error("Rollbar: request entity too large for UUID %r\n.", uuid)
if SETTINGS['log_payload_on_error']:
log.error("Payload:\n%r", payload)
except (TypeError, ValueError):
log.exception('Unable to decode JSON for failsafe.')
except KeyError:
log.exception('Unable to find payload parameters for failsafe.')
_send_failsafe('payload too large', uuid, host)
# TODO: Should we return here?
elif resp.status_code != 200:
log.warning("Got unexpected status code from Rollbar api: %s\nResponse:\n%s",
resp.status_code, data)
# TODO: Should we also return here?
try:
json_data = json.loads(data)
except (TypeError, ValueError):
log.exception('Could not decode Rollbar api response:\n%s', data)
raise ApiException('Request to %s returned invalid JSON response', path)
else:
if json_data.get('err'):
raise ApiError(json_data.get('message') or 'Unknown error')
result = json_data.get('result', {})
if 'page' in result:
return PagedResult(access_token, path, result['page'], params, result, endpoint=endpoint)
else:
return Result(access_token, path, params, result)
def _extract_user_ip_from_headers(request):
forwarded_for = request.headers.get('X-Forwarded-For')
if forwarded_for:
return forwarded_for
real_ip = request.headers.get('X-Real-Ip')
if real_ip:
return real_ip
return None
def _extract_user_ip(request):
return _extract_user_ip_from_headers(request) or request.remote_addr
def _wsgi_extract_user_ip(environ):
forwarded_for = environ.get('HTTP_X_FORWARDED_FOR')
if forwarded_for:
return forwarded_for
real_ip = environ.get('HTTP_X_REAL_IP')
if real_ip:
return real_ip
return environ['REMOTE_ADDR']
def _starlette_extract_user_ip(request):
if not hasattr(request, 'client'):
return _extract_user_ip_from_headers(request)
if not hasattr(request.client, 'host'):
return _extract_user_ip_from_headers(request)
return request.client.host or _extract_user_ip_from_headers(request)
================================================
FILE: rollbar/cli.py
================================================
import optparse
import sys
import rollbar
VERSION = '0.1'
verbose = False
def _gen_report_message(level):
def _wrapped(lines):
line_data = '\n'.join(lines)
if verbose:
print('Rollbar [%s]: %s' % (level, line_data))
rollbar.report_message(line_data, level=level, extra_data={'cli_version': VERSION})
return _wrapped
CMDS = {
'debug': _gen_report_message('debug'),
'info': _gen_report_message('info'),
'warning': _gen_report_message('warning'),
'error': _gen_report_message('error'),
'critical': _gen_report_message('critical'),
}
def main():
global verbose
parser = optparse.OptionParser(version='%prog version ' + VERSION)
parser.add_option('-t', '--access_token',
dest='access_token',
help="You project's access token from rollbar.com.",
metavar='ACCESS_TOKEN')
parser.add_option('-e', '--environment',
dest='environment',
help="The environment to report errors and messages to. \
Can be any string; suggestions: 'production', 'development', 'staging'",
metavar='ENVIRONMENT')
parser.add_option('-u', '--url',
dest='endpoint_url',
help="The Rollbar API endpoint url to send data to.",
metavar='ENDPOINT_URL',
default=rollbar.DEFAULT_ENDPOINT)
parser.add_option('-m', '--handler',
dest='handler',
help="The method in which to report errors.",
metavar='HANDLER',
choices=["thread", "blocking", "agent"],
default="blocking")
parser.add_option('-v', '--verbose',
dest='verbose',
help="Print verbose output.",
action='store_true',
default=False)
options, args = parser.parse_args()
access_token = options.access_token
env = options.environment
endpoint = options.endpoint_url
handler = options.handler
verbose = options.verbose
if not access_token:
parser.error('missing access_token')
if not env:
parser.error('missing environment')
rollbar.init(access_token, environment=env, endpoint=endpoint, handler=handler)
def _do_cmd(cmd_name, line):
cmd = CMDS.get(cmd_name.lower())
if cmd:
cmd([line])
return True
return False
if len(args) > 1:
sent = _do_cmd(args[0], ' '.join(args[1:]))
sys.exit(0 if sent else 1)
cur_cmd_name = None
try:
cur_line = sys.stdin.readline()
while cur_line:
cur_line = cur_line.strip()
parts = cur_line.split(' ')
if parts:
cur_cmd_name = parts[0]
parts = parts[1:]
_do_cmd(cur_cmd_name, ' '.join(parts))
cur_line = sys.stdin.readline()
except (KeyboardInterrupt, SystemExit) as e:
pass
================================================
FILE: rollbar/contrib/__init__.py
================================================
================================================
FILE: rollbar/contrib/asgi/__init__.py
================================================
__all__ = ['ReporterMiddleware']
from .middleware import ReporterMiddleware
================================================
FILE: rollbar/contrib/asgi/integration.py
================================================
import inspect
import functools
import rollbar
class IntegrationBase:
"""
Superclass for class integrations.
"""
def __init__(self):
if hasattr(self, '_integrate'):
self._integrate()
class integrate:
"""
Integrates functions and classes (derived from IntegrationBase) in the SDK.
"""
def __init__(self, *, framework_name='unknown'):
self._framework_name = framework_name
def __call__(self, obj):
if inspect.isclass(obj):
obj._integrate = self._register_hook
return obj
else:
return self._insert_hook(obj)
def _register_hook(self):
def _hook(request, data):
data['framework'] = self._framework_name
rollbar.BASE_DATA_HOOK = _hook
def _insert_hook(self, func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
self._register_hook()
return func(*args, **kwargs)
return wrapper
================================================
FILE: rollbar/contrib/asgi/middleware.py
================================================
import logging
import sys
from typing import Iterable
import rollbar
from .integration import IntegrationBase, integrate
from .types import ASGIApp, Receive, Scope, Send
from rollbar.lib._async import RollbarAsyncError, try_report
from rollbar.lib.session import set_current_session, reset_current_session
log = logging.getLogger(__name__)
@integrate(framework_name='asgi')
class ReporterMiddleware(IntegrationBase):
def __init__(self, app: ASGIApp) -> None:
super().__init__()
self.app = app
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
if scope['type'] == 'http':
set_current_session(self._format_headers(scope['headers']))
try:
await self.app(scope, receive, send)
except Exception:
if scope['type'] == 'http':
exc_info = sys.exc_info()
try:
await try_report(exc_info)
except RollbarAsyncError:
log.warning(
'Failed to report asynchronously. Trying to report synchronously.'
)
rollbar.report_exc_info(exc_info)
raise
finally:
if scope['type'] == 'http':
reset_current_session()
@staticmethod
def _format_headers(headers: Iterable[tuple[bytes, bytes]]) -> dict[str, str]:
"""
Convert list of header tuples to a dictionary with string keys and values.
Headers are expected to be in the format: [(b'header-name', b'header-value'), ...]
"""
return {key.decode('latin-1'): value.decode('latin-1') for key, value in headers}
================================================
FILE: rollbar/contrib/asgi/types.py
================================================
# Copyright © 2018, [Encode OSS Ltd](https://www.encode.io/).
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import typing
Scope = typing.MutableMapping[str, typing.Any]
Message = typing.MutableMapping[str, typing.Any]
Receive = typing.Callable[[], typing.Awaitable[Message]]
Send = typing.Callable[[Message], typing.Awaitable[None]]
ASGIApp = typing.Callable[[Scope, Receive, Send], typing.Awaitable[None]]
================================================
FILE: rollbar/contrib/bottle/__init__.py
================================================
import bottle, rollbar, sys
class RollbarBottleReporter(object):
'''
A Bottle plugin that reports errors to Rollbar
All args and kwargs are passed to `rollbar.init`
'''
name = 'rollbar-bottle-reporter'
api = 2
def __init__(self, *args, **kwargs):
if 'exception_level_filters' in kwargs:
kwargs['exception_level_filters'].append((bottle.BaseResponse, 'ignored'))
else:
kwargs['exception_level_filters'] = [(bottle.BaseResponse, 'ignored')]
rollbar.init(*args, **kwargs)
def hook(request, data):
data['framework'] = 'bottle'
if request:
route = request['bottle.route']
data['context'] = route.name or route.rule
rollbar.BASE_DATA_HOOK = hook
def __call__(self, callback):
def wrapper(*args, **kwargs):
try:
return callback(*args, **kwargs)
except Exception as e:
rollbar.report_exc_info(sys.exc_info(), request=bottle.request)
raise
return wrapper
================================================
FILE: rollbar/contrib/django/__init__.py
================================================
================================================
FILE: rollbar/contrib/django/context_processors.py
================================================
"""
django-rollbar context processor
To install, add the following in your settings.py:
1. add 'rollbar.contrib.django.context_processors.rollbar_settings' to TEMPLATE_CONTEXT_PROCESSORS
2. add a section like this:
ROLLBAR = {
'client_access_token': 'tokengoeshere',
}
3. you can now access your rollbar settings as rollbar_settings from within your django templates
See README.rst for full installation and configuration instructions.
"""
from django.conf import settings
def rollbar_settings(request):
"""Grabs the rollbar settings to make them available to templates."""
if not hasattr(settings, 'ROLLBAR'):
return {}
return {'rollbar_settings': settings.ROLLBAR}
================================================
FILE: rollbar/contrib/django/middleware.py
================================================
r"""
django-rollbar middleware
There are two options for installing the Rollbar middleware. Both options
require modifying your settings.py file.
The first option is to use
'rollbar.contrib.django.middleware.RollbarNotifierMiddleware' which will
report all exceptions to Rollbar including 404s. This middlware should be
placed as the last item in your middleware list which is:
* MIDDLEWARE_CLASSES in Django 1.9 and earlier
* MIDDLEWARE in Django 1.10 and up
The other option is two use the two separate middlewares:
* 'rollbar.contrib.django.middleware.RollbarNotifierMiddlewareExcluding404'
* 'rollbar.contrib.django.middleware.RollbarNotifierMiddlewareOnly404'
The Excluding404 middleware should be placed as the last item in your middleware
list, and the Only404 middleware should be placed as the first item in your
middleware list. This allows 404s to be processed by your other middlewares
before sendind an item to Rollbar. Therefore if you handle the 404 differently
in a way that returns a response early you won't end up with a Rollbar item.
Regardless of which method you use, you also should add a section to settings.py
like this:
ROLLBAR = {
'access_token': 'tokengoeshere',
}
This can be used for passing configuration options to Rollbar. Additionally,
you can use the key 'ignorable_404_urls' to set an iterable of regular expression
patterns to use to determine whether a 404 exception should be ignored based
on the full url path for the request. For example,
import re
ROLLBAR = {
'access_token': 'YOUR_TOKEN',
'ignorable_404_urls': (
re.compile(r'/index\.php'),
re.compile('/foobar'),
),
}
To get more control of middleware and enrich it with custom data
you can subclass any of the middleware classes described above
and optionally override the methods:
def get_extra_data(self, request, exc):
''' May be defined. Must return a dict or None. Use it to put some custom extra data on rollbar event. '''
return
def get_payload_data(self, request, exc):
''' May be defined. Must return a dict or None. Use it to put some custom payload data on rollbar event. '''
return
You would then insert your custom subclass into your middleware
configuration in the same place as the base class as described above.
For example:
1. create a 'middleware.py' file on your project (name is up to you)
2. import the rollbar default middleware: 'from rollbar.contrib.django.middleware import RollbarNotifierMiddleware'
3. create your own middleware like this:
class CustomRollbarNotifierMiddleware(RollbarNotifierMiddleware):
def get_extra_data(self, request, exc):
''' May be defined. Must return a dict or None. Use it to put some custom extra data on rollbar event. '''
return
def get_payload_data(self, request, exc):
''' May be defined. Must return a dict or None. Use it to put some custom payload data on rollbar event. '''
return
4. add 'path.to.your.CustomRollbarNotifierMiddleware' in your settings.py to
a. MIDDLEWARE_CLASSES in Django 1.9 and earlier
b. MIDDLEWARE in Django 1.10 and up
5. add a section like this in your settings.py:
ROLLBAR = {
'access_token': 'tokengoeshere',
}
See README.rst for full installation and configuration instructions.
"""
import logging
import sys
import rollbar
from django.core.exceptions import MiddlewareNotUsed
from django.conf import settings
from django.http import Http404
from rollbar import set_current_session
from rollbar.lib.session import reset_current_session
try:
from django.urls import resolve
except ImportError:
from django.core.urlresolvers import resolve
try:
from django.utils.deprecation import MiddlewareMixin
except ImportError:
from rollbar.contrib.django.utils import MiddlewareMixin
log = logging.getLogger(__name__)
DEFAULTS = {
'web_base': 'https://rollbar.com',
'enabled': True,
'patch_debugview': True,
'exception_level_filters': [
(Http404, 'warning')
]
}
def _patch_debugview(rollbar_web_base):
try:
from django.views import debug
except ImportError:
return
if rollbar_web_base.endswith('/'):
rollbar_web_base = rollbar_web_base[:-1]
# modify the TECHNICAL_500_TEMPLATE
new_data = """
{% if view_in_rollbar_url %}
<h3 style="margin-bottom:15px;"><a href="{{ view_in_rollbar_url }}" target="_blank">View in Rollbar</a></h3>
{% endif %}
"""
insert_before = '<table class="meta">'
replacement = new_data + insert_before
if hasattr(debug, 'TECHNICAL_500_TEMPLATE'):
if new_data in debug.TECHNICAL_500_TEMPLATE:
return
debug.TECHNICAL_500_TEMPLATE = debug.TECHNICAL_500_TEMPLATE.replace(insert_before, replacement, 1)
elif hasattr(debug, 'CURRENT_DIR'):
# patch ExceptionReporter.get_traceback_html if this version of Django is using
# the file system templates rather than the ones in code
# This code comes from:
# https://github.com/django/django/blob/d79cf1e9e2887aa12567c8f27e384195253cb847/django/views/debug.py#L329,L334
# There are theoretical issues with the code below, for example t.render could throw because
# t might be None, but this is the code from Django
from pathlib import Path
from django.template import Context
def new_get_traceback_html(exception_reporter):
"""Return HTML version of debug 500 HTTP error page."""
with Path(debug.CURRENT_DIR, 'templates', 'technical_500.html').open() as fh:
template_string = fh.read()
template_string = template_string.replace(insert_before, replacement, 1)
t = debug.DEBUG_ENGINE.from_string(template_string)
c = Context(exception_reporter.get_traceback_data(), use_l10n=False)
return t.render(c)
debug.ExceptionReporter.get_traceback_html = new_get_traceback_html
else:
# patch ExceptionReporter.get_traceback_html for Django versions 4.0+
def new_get_traceback_html(self):
"""Return HTML version of debug 500 HTTP error page."""
with self.html_template_path.open(encoding='utf-8') as fh:
t = debug.DEBUG_ENGINE.from_string(fh.read())
c = Context(self.get_traceback_data(), use_l10n=False)
return t.render(c)
if hasattr(debug.ExceptionReporter, '__rollbar__patched'):
return
# patch ExceptionReporter.get_traceback_data
old_get_traceback_data = debug.ExceptionReporter.get_traceback_data
def new_get_traceback_data(exception_reporter):
data = old_get_traceback_data(exception_reporter)
try:
item_uuid = exception_reporter.request.META.get('rollbar.uuid')
if item_uuid:
url = '%s/item/uuid/?uuid=%s' % (rollbar_web_base, item_uuid)
data['view_in_rollbar_url'] = url
except:
log.exception("Exception while adding view-in-rollbar link to technical_500_template.")
return data
debug.ExceptionReporter.get_traceback_data = new_get_traceback_data
debug.ExceptionReporter.__rollbar__patched = True
def _should_ignore_404(url):
url_patterns = getattr(settings, 'ROLLBAR', {}).get('ignorable_404_urls', ())
return any(p.search(url) for p in url_patterns)
def _apply_sensitive_post_params(request):
sensitive_post_parameters = getattr(
request, "sensitive_post_parameters", []
)
if not sensitive_post_parameters:
return
mutable = request.POST._mutable
request.POST._mutable = True
if sensitive_post_parameters == "__ALL__":
for param in request.POST:
request.POST[param] = "******"
return
for param in sensitive_post_parameters:
if param in request.POST:
request.POST[param] = "******"
request.POST._mutable = mutable
class RollbarNotifierMiddleware(MiddlewareMixin):
def __init__(self, get_response=None):
super(RollbarNotifierMiddleware, self).__init__(get_response)
self.settings = getattr(settings, 'ROLLBAR', {})
if not self.settings.get('access_token'):
raise MiddlewareNotUsed
if not self._get_setting('enabled'):
raise MiddlewareNotUsed
self._ensure_log_handler()
kw = self.settings.copy()
access_token = kw.pop('access_token')
environment = kw.pop('environment', 'development' if settings.DEBUG else 'production')
kw.setdefault('exception_level_filters', DEFAULTS['exception_level_filters'])
# ignorable_404_urls is only relevant for this middleware not as an argument to init
kw.pop('ignorable_404_urls', None)
rollbar.init(access_token, environment, **kw)
def hook(request, data):
try:
# try django 1.5 method for getting url_name
url_name = request.resolver_match.url_name
except:
# fallback to older method
try:
url_name = resolve(request.path_info).url_name
except:
url_name = None
if url_name:
data['context'] = url_name
data['framework'] = 'django'
if request and hasattr(request, 'META'):
request.META['rollbar.uuid'] = data['uuid']
rollbar.BASE_DATA_HOOK = hook
# monkeypatch debug module
if self._get_setting('patch_debugview'):
try:
_patch_debugview(self._get_setting('web_base'))
except Exception as e:
log.error(
"Rollbar - unable to monkeypatch debugview to add 'View in Rollbar' link."
" To disable, set `ROLLBAR['patch_debugview'] = False` in settings.py."
" Exception was: %r", e
)
def __call__(self, request):
headers = {}
for k, v in request.META.items():
if k.startswith('HTTP_'):
header_name = '-'.join(k[len('HTTP_'):].replace('_', ' ').title().split(' '))
headers[header_name] = v
set_current_session(headers)
try:
response = self.get_response(request)
return response
finally:
reset_current_session()
def _ensure_log_handler(self):
"""
If there's no log configuration, set up a default handler.
"""
if log.handlers:
return
handler = logging.StreamHandler()
formatter = logging.Formatter(
'%(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s')
handler.setFormatter(formatter)
log.addHandler(handler)
def _get_setting(self, name, default=None):
try:
return self.settings[name]
except KeyError:
if name in DEFAULTS:
default_val = DEFAULTS[name]
if hasattr(default_val, '__call__'):
return default_val()
return default_val
return default
def get_extra_data(self, request, exc):
return
def get_payload_data(self, request, exc):
return
def process_response(self, request, response):
return response
def process_exception(self, request, exc):
if isinstance(exc, Http404) and _should_ignore_404(request.get_full_path()):
return
_apply_sensitive_post_params(request)
rollbar.report_exc_info(
sys.exc_info(),
request,
extra_data=self.get_extra_data(request, exc),
payload_data=self.get_payload_data(request, exc),
)
class RollbarNotifierMiddlewareOnly404(MiddlewareMixin):
def get_extra_data(self, request, exc):
return
def get_payload_data(self, request, exc):
return
def process_response(self, request, response):
if response.status_code != 404:
return response
if _should_ignore_404(request.get_full_path()):
return response
try:
if hasattr(request, '_rollbar_notifier_original_http404_exc_info'):
exc_type, exc_value, exc_traceback = request._rollbar_notifier_original_http404_exc_info
if exc_value is None:
exc_value = Http404()
raise exc_value.with_traceback(exc_traceback)
else:
raise Http404()
except Exception as exc:
_apply_sensitive_post_params(request)
rollbar.report_exc_info(
sys.exc_info(),
request,
extra_data=self.get_extra_data(request, exc),
payload_data=self.get_payload_data(request, exc),
)
return response
class RollbarNotifierMiddlewareExcluding404(RollbarNotifierMiddleware):
def process_exception(self, request, exc):
if isinstance(exc, Http404):
request._rollbar_notifier_original_http404_exc_info = sys.exc_info()
else:
super(RollbarNotifierMiddlewareExcluding404, self).process_exception(request, exc)
================================================
FILE: rollbar/contrib/django/models.py
================================================
"""
No models - this file is here so django recognizes this as an application for running unit tests.
"""
================================================
FILE: rollbar/contrib/django/tests.py
================================================
"""
Unit tests
"""
from django.test import TestCase
from django.conf import settings
class BasicTests(TestCase):
def test_configuration(self):
"""
Test that the configuration is sane.
"""
self.assertTrue('ROLLBAR' in dir(settings),
msg='The ROLLBAR setting is not present.')
self.assertTrue(settings.ROLLBAR.get('access_token'),
msg='The ROLLBAR["access_token"] setting is blank.')
================================================
FILE: rollbar/contrib/django/utils.py
================================================
class MiddlewareMixin(object):
def __init__(self, get_response=None):
super(MiddlewareMixin, self).__init__()
================================================
FILE: rollbar/contrib/django_rest_framework/__init__.py
================================================
try:
from django.core.exceptions import ImproperlyConfigured
except ImportError:
ImproperlyConfigured = RuntimeError
try:
from rest_framework.views import exception_handler as _exception_handler
except (ImportError, ImproperlyConfigured):
_exception_handler = None
def post_exception_handler(exc, context):
# This is to be used with the Django REST Framework (DRF) as its
# global exception handler. It replaces the POST data of the Django
# request with the parsed data from the DRF. This is necessary
# because we cannot read the request data/stream more than once.
# This will allow us to see the parsed POST params in the rollbar
# exception log.
if _exception_handler is None:
raise ImproperlyConfigured(
'Could not import rest_framework.views.exception_handler')
try:
context['request']._request.POST = context['request'].data
except Exception:
pass
return _exception_handler(exc, context)
================================================
FILE: rollbar/contrib/fastapi/__init__.py
================================================
__all__ = ['add_to', 'ReporterMiddleware', 'LoggerMiddleware', 'get_current_request']
# Optional requirements:
#
# - FastAPI requires `python-multipart` package to support requests body parsing
# - `LoggerMiddleware` and `get_current_request` require `aiocontextvars` package
# to be installed when running in Python 3.6
from .middleware import ReporterMiddleware
from .logger import LoggerMiddleware
from .routing import add_to
# Do not modify the returned request object
from rollbar.contrib.starlette import get_current_request
================================================
FILE: rollbar/contrib/fastapi/logger.py
================================================
__all__ = ['LoggerMiddleware']
from fastapi import __version__
from rollbar.contrib.asgi.integration import integrate
from rollbar.contrib.starlette import LoggerMiddleware as StarletteLoggerMiddleware
@integrate(framework_name=f'fastapi {__version__}')
class LoggerMiddleware(StarletteLoggerMiddleware):
...
================================================
FILE: rollbar/contrib/fastapi/middleware.py
================================================
__all__ = ['ReporterMiddleware']
from fastapi import __version__
from rollbar.contrib.asgi.integration import integrate
from rollbar.contrib.starlette import ReporterMiddleware as StarletteReporterMiddleware
@integrate(framework_name=f'fastapi {__version__}')
class ReporterMiddleware(StarletteReporterMiddleware):
...
================================================
FILE: rollbar/contrib/fastapi/routing.py
================================================
__all__ = ['add_to']
import logging
import sys
from typing import Callable, Optional, Type, Union
from fastapi import APIRouter, FastAPI, __version__
from fastapi.routing import APIRoute
from rollbar.lib.session import reset_current_session, set_current_session
try:
from fastapi import Request, Response
except ImportError:
# Added in FastAPI v0.51.0
from starlette.requests import Request
from starlette.responses import Response
import rollbar
from .utils import fastapi_min_version, get_installed_middlewares, has_bare_routing
from rollbar.contrib.asgi.integration import integrate
from rollbar.contrib.starlette.requests import store_current_request
from rollbar.lib._async import RollbarAsyncError, try_report
log = logging.getLogger(__name__)
@fastapi_min_version('0.41.0')
@integrate(framework_name=f'fastapi {__version__}')
def add_to(app_or_router: Union[FastAPI, APIRouter]) -> Optional[Type[APIRoute]]:
"""
Adds RollbarLoggingRoute handler to the router app.
This is the recommended way for integration with FastAPI.
Alternatively to using middleware, the handler may fill
more data in the payload (e.g. request body).
app_or_router: FastAPI app or router
Note: The route handler must be added before adding user routes
Requirements: FastAPI v0.41.0+
Example usage:
from fastapi import FastAPI
from rollbar.contrib.fastapi import add_to as rollbar_add_to
app = FastAPI()
rollbar_add_to(app)
"""
if not has_bare_routing(app_or_router):
log.error(
'RollbarLoggingRoute must to be added to a bare router'
' (before adding routes). See docs for more details.'
)
return None
installed_middlewares = get_installed_middlewares(app_or_router)
if installed_middlewares:
log.warning(
f'Detected middleware installed {installed_middlewares}'
' while loading Rollbar route handler.'
' This can cause in duplicate occurrences.'
)
if isinstance(app_or_router, FastAPI):
_add_to_app(app_or_router)
elif isinstance(app_or_router, APIRouter):
_add_to_router(app_or_router)
else:
log.error('Error adding RollbarLoggingRoute to application.')
return None
return RollbarLoggingRoute
class RollbarLoggingRoute(APIRoute):
def get_route_handler(self) -> Callable:
router_handler = super().get_route_handler()
async def rollbar_route_handler(request: Request) -> Response:
set_current_session(dict(request.headers))
try:
store_current_request(request)
return await router_handler(request)
except Exception:
# FastAPI requires the `python-multipart` package to parse the content
if not request._stream_consumed:
await request.body()
await request.form()
exc_info = sys.exc_info()
try:
await try_report(exc_info, request)
except RollbarAsyncError:
log.warning(
'Failed to report asynchronously. Trying to report synchronously.'
)
rollbar.report_exc_info(exc_info, request)
raise
finally:
reset_current_session()
return rollbar_route_handler
def _add_to_app(app):
app.router.route_class = RollbarLoggingRoute
def _add_to_router(router):
router.route_class = RollbarLoggingRoute
================================================
FILE: rollbar/contrib/fastapi/utils.py
================================================
import functools
import logging
from typing import Union
import fastapi
from fastapi import APIRouter, FastAPI
from . import ReporterMiddleware as FastAPIReporterMiddleware
from rollbar.contrib.starlette import ReporterMiddleware as StarletteReporterMiddleware
from rollbar.contrib.asgi import ReporterMiddleware as ASGIReporterMiddleware
log = logging.getLogger(__name__)
class FastAPIVersionError(Exception):
def __init__(self, version, reason=''):
err_msg = f'FastAPI {version}+ is required'
if reason:
err_msg += f' {reason}'
log.error(err_msg)
return super().__init__(err_msg)
def is_current_version_higher_or_equal(current_version, min_version):
"""
Compare two version strings and return True if the current version is higher or equal to the minimum version.
Note: This function only compares the release segment of the version string.
"""
def parse_version(version):
"""Parse the release segment of a version string into a list of strings."""
parsed = ['']
current_segment = 0
for c in version:
if c.isdigit():
parsed[current_segment] += c
elif c == '.':
current_segment += 1
parsed.append('')
else:
break
if parsed[-1] == '':
parsed.pop()
return parsed
current = tuple(map(int, parse_version(current_version)))
minimum = tuple(map(int, parse_version(min_version)))
return current >= minimum
class fastapi_min_version:
def __init__(self, min_version):
self.min_version = min_version
def __call__(self, func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
if not is_current_version_higher_or_equal(
fastapi.__version__,
self.min_version,
):
raise FastAPIVersionError(
self.min_version, reason=f'to use {func.__name__}() function'
)
return func(*args, **kwargs)
return wrapper
def get_installed_middlewares(app):
candidates = (
FastAPIReporterMiddleware,
StarletteReporterMiddleware,
ASGIReporterMiddleware,
)
middlewares = []
if hasattr(app, 'user_middleware'): # FastAPI v0.51.0+
middlewares = [
middleware.cls
for middleware in app.user_middleware
if middleware.cls in candidates
]
elif hasattr(app, 'error_middleware'):
middleware = app.error_middleware
while hasattr(middleware, 'app'):
if isinstance(middleware, candidates):
middlewares.append(middleware)
middleware = middleware.app
middlewares = [middleware.__class__ for middleware in middlewares]
return middlewares
def has_bare_routing(app_or_router: Union[FastAPI, APIRouter]):
if not isinstance(app_or_router, (FastAPI, APIRouter)):
return False
urls = [
getattr(app_or_router, 'openapi_url', None),
getattr(app_or_router, 'docs_url', None),
getattr(app_or_router, 'redoc_url', None),
getattr(app_or_router, 'swagger_ui_oauth2_redirect_url', None),
]
for route in app_or_router.routes:
if route is None or route.path in urls:
continue
return False
return True
================================================
FILE: rollbar/contrib/flask/__init__.py
================================================
"""
Integration with Flask
"""
from flask import request, got_request_exception, Flask
import rollbar
from rollbar.lib.session import reset_current_session, set_current_session
def report_exception(app, exception):
rollbar.report_exc_info(request=request)
def _hook(request, data):
data['framework'] = 'flask'
if request:
data['context'] = str(request.url_rule)
rollbar.BASE_DATA_HOOK = _hook
def init(app: Flask, access_token, environment='production', scrub_fields=None, url_fields=None, **kw):
"""
Initializes the Rollbar Flask integration.
"""
with app.app_context():
rollbar.init(
access_token=access_token,
environment=environment,
scrub_fields=scrub_fields,
url_fields=url_fields,
**kw,
)
# send exceptions from `app` to rollbar, using flask's signal system.
got_request_exception.connect(report_exception, app)
@app.before_request
def before_request():
set_current_session(dict(request.headers))
@app.teardown_request
def teardown_request(exception):
reset_current_session()
================================================
FILE: rollbar/contrib/pyramid/__init__.py
================================================
"""
Plugin for Pyramid apps to submit errors to Rollbar
"""
import logging
import sys
from pyramid.httpexceptions import WSGIHTTPException
from pyramid.tweens import EXCVIEW
from pyramid.util import DottedNameResolver
from pyramid.settings import asbool
import rollbar
from rollbar import set_current_session
from rollbar.lib.session import reset_current_session
DEFAULT_WEB_BASE = 'https://rollbar.com'
BOOLEAN_SETTINGS = [
'rollbar.enabled', 'rollbar.allow_logging_basic_config',
'rollbar.verify_https'
]
log = logging.getLogger(__name__)
EXCEPTION_BLOCKLIST = (WSGIHTTPException,)
EXCEPTION_SAFELIST = tuple()
def handle_error(request, exception, exc_info):
if(
isinstance(exception, EXCEPTION_BLOCKLIST) and
not isinstance(exception, EXCEPTION_SAFELIST)
):
return
rollbar.report_exc_info(exc_info, request)
def parse_settings(settings):
prefix = 'rollbar.'
out = {}
for k, v in settings.items():
if k.startswith(prefix):
if k in BOOLEAN_SETTINGS:
v = asbool(v)
out[k[len(prefix):]] = v
return out
def rollbar_tween_factory(pyramid_handler, registry):
settings = parse_settings(registry.settings)
def rollbar_tween(request):
set_current_session(dict(request.headers))
# for testing out the integration
try:
if (settings.get('allow_test', 'true') == 'true' and
request.GET.get('pyramid_rollbar_test') == 'true'):
try:
raise Exception("pyramid_rollbar test exception")
except Exception as exc:
handle_error(request, exc, sys.exc_info())
except:
log.exception("Error in pyramid_rollbar_test block")
try:
response = pyramid_handler(request)
except Exception as exc:
handle_error(request, exc, sys.exc_info())
raise
finally:
reset_current_session()
if request.exception is not None:
handle_error(request, request.exception, request.exc_info)
return response
return rollbar_tween
def patch_debugtoolbar(settings):
"""
Patches the pyramid_debugtoolbar (if installed) to display a link to the related rollbar item.
"""
try:
from pyramid_debugtoolbar import tbtools
except ImportError:
return
rollbar_web_base = settings.get('rollbar.web_base', DEFAULT_WEB_BASE)
if rollbar_web_base.endswith('/'):
rollbar_web_base = rollbar_web_base[:-1]
def insert_rollbar_console(request, html):
# insert after the closing </h1>
item_uuid = request.environ.get('rollbar.uuid')
if not item_uuid:
return html
url = '%s/item/uuid/?uuid=%s' % (rollbar_web_base, item_uuid)
link = '<a style="color:white;" href="%s">View in Rollbar</a>' % url
new_data = "<h2>Rollbar: %s</h2>" % link
insertion_marker = "</h1>"
replacement = insertion_marker + new_data
return html.replace(insertion_marker, replacement, 1)
# patch tbtools.Traceback.render_full
old_render_full = tbtools.Traceback.render_full
def new_render_full(self, request, *args, **kw):
html = old_render_full(self, request, *args, **kw)
return insert_rollbar_console(request, html)
tbtools.Traceback.render_full = new_render_full
def includeme(config):
"""
Pyramid entry point
"""
settings = config.registry.settings
config.add_tween('rollbar.contrib.pyramid.rollbar_tween_factory', over=EXCVIEW)
# run patch_debugtoolbar, unless they disabled it
if asbool(settings.get('rollbar.patch_debugtoolbar', True)):
patch_debugtoolbar(settings)
def hook(request, data):
data['framework'] = 'pyramid'
if request:
request.environ['rollbar.uuid'] = data['uuid']
if request.matched_route:
data['context'] = request.matched_route.name
rollbar.BASE_DATA_HOOK = hook
kw = parse_settings(settings)
access_token = kw.pop('access_token')
environment = kw.pop('environment', 'production')
if kw.get('scrub_fields'):
kw['scrub_fields'] = {str.strip(x) for x in kw.get('scrub_fields').split('\n') if x}
if kw.get('exception_level_filters'):
r = DottedNameResolver()
exception_level_filters = []
for line in kw.get('exception_level_filters').split('\n'):
if line:
dotted_path, level = line.split()
try:
cls = r.resolve(dotted_path)
exception_level_filters.append((cls, level))
except ImportError:
log.error('Could not import %r' % dotted_path)
kw['exception_level_filters'] = exception_level_filters
kw['enabled'] = asbool(kw.get('enabled', True))
rollbar.init(access_token, environment, **kw)
def create_rollbar_middleware(app, global_config=None, **kw):
access_token = kw.pop('access_token')
environment = kw.pop('environment', 'production')
rollbar.init(access_token, environment, **kw)
return RollbarMiddleware(global_config or {}, app)
class RollbarMiddleware(object):
def __init__(self, settings, app):
self.settings = settings
self.app = app
def __call__(self, environ, start_resp):
try:
return self.app(environ, start_resp)
except Exception as exc:
from pyramid.request import Request
handle_error(Request(environ), exc, sys.exc_info())
raise
================================================
FILE: rollbar/contrib/quart/__init__.py
================================================
"""
Integration with Quart
"""
from quart import request
import rollbar
def report_exception(app, exception):
rollbar.report_exc_info(request=request)
def _hook(request, data):
data['framework'] = 'quart'
if request:
data['context'] = str(request.url_rule)
rollbar.BASE_DATA_HOOK = _hook
================================================
FILE: rollbar/contrib/rq/__init__.py
================================================
"""
Exception handler hook for RQ (http://python-rq.org/)
How to use:
1. Instead of using the default "rqworker" script to run the worker, write your own short script
as shown in this example:
https://github.com/nvie/rq/blob/master/examples/run_worker.py
2. In this script, initialize rollbar with `handler='blocking'`, for example:
rollbar.init('your access token', 'production', handler='blocking')
3. After constructing the worker but before calling `.work()`, add
`rollbar.contrib.rq.exception_handler` as an exception handler.
Full example:
```
import rollbar
from rq import Connection, Queue, Worker
if __name__ == '__main__':
rollbar.init('your_access_token', 'production', handler='blocking')
with Connection():
q = Queue()
worker = Worker(q)
worker.push_exc_handler(rollbar.contrib.rq.exception_handler)
worker.work()
```
"""
import rollbar
def exception_handler(job, *exc_info):
"""
Called by RQ when there is a failure in a worker.
NOTE: Make sure that in your RQ worker process, rollbar.init() has been called with
handler='blocking'. The default handler, 'thread', does not work from inside an RQ worker.
"""
# Report data about the job with the exception.
job_info = job.to_dict()
# job_info['data'] is the pickled representation of the job, and doesn't json-serialize well.
# repr() works nicely.
job_info['data'] = repr(job_info['data'])
extra_data = {'job': job_info}
payload_data = {'framework': 'rq'}
rollbar.report_exc_info(exc_info, extra_data=extra_data, payload_data=payload_data)
# continue to the next handler
return True
================================================
FILE: rollbar/contrib/starlette/__init__.py
================================================
__all__ = ['ReporterMiddleware', 'LoggerMiddleware', 'get_current_request']
# Optional requirements:
#
# - Starlette requires `python-multipart` package to support requests body parsing
# - `LoggerMiddleware` and `get_current_request` require `aiocontextvars` package
# to be installed when running in Python 3.6
from .middleware import ReporterMiddleware
from .logger import LoggerMiddleware
# Do not modify the returned request object
from .requests import get_current_request
================================================
FILE: rollbar/contrib/starlette/logger.py
================================================
__all__ = ['LoggerMiddleware']
import logging
import sys
from starlette import __version__
from starlette.types import ASGIApp, Receive, Scope, Send
from rollbar.contrib.asgi import ReporterMiddleware as ASGIReporterMiddleware
from rollbar.contrib.asgi.integration import integrate
from rollbar.contrib.starlette.requests import store_current_request
log = logging.getLogger(__name__)
@integrate(framework_name=f'starlette {__version__}')
class LoggerMiddleware(ASGIReporterMiddleware):
def __init__(self, app: ASGIApp) -> None:
if sys.version_info < (3, 6):
log.error(
'LoggerMiddleware requires Python 3.7+ (or 3.6 with `aiocontextvars` package)'
)
raise RuntimeError(
'LoggerMiddleware requires Python 3.7+ (or 3.6 with `aiocontextvars` package)'
)
super().__init__(app)
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
store_current_request(scope, receive)
await self.app(scope, receive, send)
================================================
FILE: rollbar/contrib/starlette/middleware.py
================================================
import logging
import sys
from starlette import __version__
from starlette.requests import Request
from starlette.types import Receive, Scope, Send
import rollbar
from .requests import store_current_request
from rollbar.contrib.asgi import ReporterMiddleware as ASGIReporterMiddleware
from rollbar.contrib.asgi.integration import integrate
from rollbar.lib._async import RollbarAsyncError, try_report
from rollbar.lib.session import set_current_session, reset_current_session
log = logging.getLogger(__name__)
@integrate(framework_name=f'starlette {__version__}')
class ReporterMiddleware(ASGIReporterMiddleware):
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
if scope['type'] == 'http':
set_current_session(self._format_headers(scope['headers']))
try:
store_current_request(scope, receive)
await self.app(scope, receive, send)
except Exception:
if scope['type'] == 'http':
request = Request(scope, receive)
# Consuming the request body in Starlette middleware is problematic.
# See: https://github.com/encode/starlette/issues/495#issuecomment-494008175
#
# Uncomment lines below if you know the risks.
#
# Starlette requires the `python-multipart` package to parse the content
# await request.body()
# await request.form()
exc_info = sys.exc_info()
try:
await try_report(exc_info, request)
except RollbarAsyncError:
log.warning(
'Failed to report asynchronously. Trying to report synchronously.'
)
rollbar.report_exc_info(exc_info, request)
raise
finally:
if scope['type'] == 'http':
reset_current_session()
================================================
FILE: rollbar/contrib/starlette/requests.py
================================================
__all__ = ['get_current_request']
import logging
import sys
from typing import Optional, Union
from starlette.requests import Request
from starlette.types import Receive, Scope
log = logging.getLogger(__name__)
if sys.version_info[:2] == (3, 6):
# Backport PEP 567
try:
import aiocontextvars
except ImportError:
# Do not raise an exception as the module is exported to package API
# but is still optional
log.error(
'Python 3.6 requires `aiocontextvars` package to be installed'
' to support global access to request objects'
)
try:
from contextvars import ContextVar
except ImportError:
ContextVar = None
if ContextVar:
_current_request: ContextVar[Optional[Request]] = ContextVar(
'rollbar-request-object', default=None
)
def get_current_request() -> Optional[Request]:
"""
Return current request.
Do NOT modify the returned request object.
"""
if ContextVar is None:
log.error(
'Python 3.7+ (or aiocontextvars package)'
' is required to receive current request.'
)
return None
return _current_request.get()
def store_current_request(
request_or_scope: Union[Request, Scope], receive: Optional[Receive] = None
) -> Optional[Request]:
if ContextVar is None:
return None
if receive is None:
request = request_or_scope
elif request_or_scope['type'] == 'http':
request = Request(request_or_scope, receive)
else:
request = None
_current_request.set(request)
return request
def hasuser(request: Request) -> bool:
try:
return hasattr(request, 'user')
except AssertionError:
return False
================================================
FILE: rollbar/examples/asgi/app.py
================================================
#!/usr/bin/env python
# ASGI middleware is ASGI v3 compliant. It can integrate with any
# ASGIv3-compliant applications.
# This example demonstrates Rollbar integration with the Starlette app.
#
# NOTE: Rollbar provides dedicated framework integrations that are more
# feature-rich. Currently available: Starlette and FastAPI.
#
# This example uses Uvicorn package that must be installed. However, it can be
# replaced with any other ASGI-compliant server.
#
# Optional asynchronous reporting requires HTTPX package to be installed.
#
# Run: python app.py
import rollbar
import uvicorn
from rollbar.contrib.asgi import ReporterMiddleware as RollbarMiddleware
from starlette.applications import Starlette
from starlette.responses import PlainTextResponse
# Initialize Rollbar SDK with your server-side ACCESS_TOKEN
rollbar.init(
'ACCESS_TOKEN',
environment='staging',
handler='async', # For asynchronous reporting use: default, async or httpx
)
# Integrate Rollbar with Starlette application
app = Starlette()
app.add_middleware(RollbarMiddleware) # should be added as the first middleware
# Verify application runs correctly
#
# $ curl http://localhost:8888
@app.route('/')
async def root(request):
return PlainTextResponse('hello world')
# Cause an uncaught exception to be sent to Rollbar
# GET query params will be sent to Rollbar and available in the UI
#
# $ curl http://localhost:8888/error?param1=hello¶m2=world
async def localfunc(arg1, arg2, arg3):
# Both local variables and function arguments will be sent to Rollbar
# and available in the UI
localvar = 'local variable'
cause_error_with_local_variables
@app.route('/error')
async def error(request):
await localfunc('func_arg1', 'func_arg2', 1)
return PlainTextResponse("You shouldn't be seeing this")
if __name__ == '__main__':
uvicorn.run(app, host='localhost', port=8888)
================================================
FILE: rollbar/examples/django/app.py
================================================
import os
import sys
import django
from django.conf import settings
# use settings compatible with the installed Django version
# v1.10+ requires MIDDLEWARE keyname
# older versions require MIDDLEWARE_CLASSES keyname
ROLLBAR_CONFIG = {
'access_token': 'POST_SERVER_ITEM_ACCESS_TOKEN',
'environment': 'development',
'branch': 'master',
'root': os.getcwd()
}
MIDDLEWARE_CONFIG = (
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
# Rollbar middleware
'rollbar.contrib.django.middleware.RollbarNotifierMiddleware',
)
if django.VERSION >= (1, 10):
settings.configure(
DEBUG=True,
SECRET_KEY='thisisthesecretkey',
ROOT_URLCONF=__name__,
ROLLBAR = ROLLBAR_CONFIG,
MIDDLEWARE = MIDDLEWARE_CONFIG,
)
else:
settings.configure(
DEBUG=True,
SECRET_KEY='thisisthesecretkey',
ROOT_URLCONF=__name__,
ROLLBAR = ROLLBAR_CONFIG,
MIDDLEWARE_CLASSES = MIDDLEWARE_CONFIG,
)
from django.conf.urls import url
from django.http import HttpResponse
def index(request):
return HttpResponse('Hello World')
def error(request):
foo()
return HttpResponse('You shouldn\'t be seeing this')
urlpatterns = (
url(r'^$', index),
url(r'^error$', error),
)
if __name__ == "__main__":
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
================================================
FILE: rollbar/examples/fastapi/app.py
================================================
#!/usr/bin/env python
# This example uses Uvicorn package that must be installed. However, it can be
# replaced with any other ASGI-compliant server.
#
# Optional asynchronous reporting requires HTTPX package to be installed.
#
# NOTE: This example requires FastAPI v0.41.0+ (see app_middleware.py for alternative).
#
# Run: python app.py
import fastapi
import rollbar
import uvicorn
from rollbar.contrib.fastapi import add_to as rollbar_add_to
# Initialize Rollbar SDK with your server-side ACCESS_TOKEN
rollbar.init(
'ACCESS_TOKEN',
environment='staging',
handler='async', # For asynchronous reporting use: default, async or httpx
include_request_body=True,
)
# Integrate Rollbar with FastAPI application before adding routes to the app
app = fastapi.FastAPI()
rollbar_add_to(app)
# Verify application runs correctly
#
# $ curl http://localhost:8888
@app.get('/')
async def read_root():
return {'hello': 'world'}
# Cause an uncaught exception to be sent to Rollbar
# GET query params will be sent to Rollbar and available in the UI
#
# $ curl http://localhost:8888/error?param1=hello¶m2=world
async def localfunc(arg1, arg2, arg3):
# Both local variables and function arguments will be sent to Rollbar
# and available in the UI
localvar = 'local variable'
cause_error_with_local_variables
@app.get('/error')
async def read_error():
await localfunc('func_arg1', 'func_arg2', 1)
return {'result': "You shouldn't be seeing this"}
# Cause an uncaught exception to be sent to Rollbar
# POST request body will be sent to Rollbar and available in the UI
#
# curl http://localhost:8888/body -d '{"param1": "hello", "param2": "world"}'
@app.post('/body')
async def read_body():
cause_error_with_body
return {'result': "You shouldn't be seeing this"}
# Cause an uncaught exception to be sent to Rollbar
# POST form data will be sent to Rollbar and available in the UI
#
# curl http://localhost:8888/form -F 'param1=hello' -F 'param2=world'
@app.post('/form')
async def read_form():
cause_error_with_form
return {'result': "You shouldn't be seeing this"}
if __name__ == '__main__':
uvicorn.run(app, host='localhost', port=8888)
================================================
FILE: rollbar/examples/fastapi/app_global_request.py
================================================
#!/usr/bin/env python
# This example uses Uvicorn package that must be installed. However, it can be
# replaced with any other ASGI-compliant server.
#
# NOTE: Python 3.6 requires aiocontextvars package to be installed.
#
# Run: python app_global_request.py
import fastapi
import rollbar
import uvicorn
from rollbar.contrib.fastapi import LoggerMiddleware
# Integrate Rollbar with FastAPI application
app = fastapi.FastAPI()
app.add_middleware(LoggerMiddleware) # should be added as the last middleware
async def get_user_agent():
# Global access to the current request object
request = rollbar.get_request()
user_agent = request.headers['User-Agent']
return user_agent
# $ curl -i http://localhost:8888
@app.get('/')
async def read_root():
user_agent = await get_user_agent()
return {'user-agent': user_agent}
if __name__ == '__main__':
uvicorn.run(app, host='localhost', port=8888)
================================================
FILE: rollbar/examples/fastapi/app_logger.py
================================================
#!/usr/bin/env python
# This example uses Uvicorn package that must be installed. However, it can be
# replaced with any other ASGI-compliant server.
#
# NOTE: Python 3.6 requires aiocontextvars package to be installed.
# Optional asynchronous reporting requires HTTPX package to be installed.
#
# Run: python app_logger.py
import logging
import fastapi
import rollbar
import uvicorn
from rollbar.contrib.fastapi import LoggerMiddleware
from rollbar.logger import RollbarHandler
# Initialize Rollbar SDK with your server-side ACCESS_TOKEN
rollbar.init(
'ACCESS_TOKEN',
environment='staging',
handler='async', # For asynchronous reporting use: default, async or httpx
)
# Set root logger to log DEBUG and above
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# Report ERROR and above to Rollbar
rollbar_handler = RollbarHandler()
rollbar_handler.setLevel(logging.ERROR)
# Attach Rollbar handler to the root logger
logger.addHandler(rollbar_handler)
# Integrate Rollbar with FastAPI application
app = fastapi.FastAPI()
app.add_middleware(LoggerMiddleware) # should be added as the last middleware
# GET query params will be sent to Rollbar and available in the UI
# $ curl http://localhost:8888?param1=hello¶m2=world
@app.get('/')
async def read_root():
# Report log entries
logger.critical('Critical message sent to Rollbar')
logger.error('Error message sent to Rollbar')
# Ignore log entries
logger.warning('Warning message is not sent to Rollbar')
logger.info('Info message is not sent to Rollbar')
logger.debug('Debug message is not sent to Rollbar')
return {'hello': 'world'}
if __name__ == '__main__':
uvicorn.run(app, host='localhost', port=8888)
================================================
FILE: rollbar/examples/fastapi/app_middleware.py
================================================
#!/usr/bin/env python
# This example uses Uvicorn package that must be installed. However, it can be
# replaced with any other ASGI-compliant server.
#
# Optional asynchronous reporting requires HTTPX package to be installed.
#
# NOTE: FastAPI middlewares don't allow to collect streamed content like a request body.
# You may consider to use routing integration instead (see app.py example).
#
# Run: python app_middleware.py
import fastapi
import rollbar
import uvicorn
from rollbar.contrib.fastapi import ReporterMiddleware as RollbarMiddleware
# Initialize Rollbar SDK with your server-side ACCESS_TOKEN
rollbar.init(
'ACCESS_TOKEN',
environment='staging',
handler='async', # For asynchronous reporting use: default, async or httpx
)
# Integrate Rollbar with FastAPI application
app = fastapi.FastAPI()
app.add_middleware(RollbarMiddleware) # should be added as the first middleware
# Verify application runs correctly
#
# $ curl http://localhost:8888
@app.get('/')
async def read_root():
return {'hello': 'world'}
# Cause an uncaught exception to be sent to Rollbar
# GET query params will be sent to Rollbar and available in the UI
#
# $ curl http://localhost:8888/error?param1=hello¶m2=world
async def localfunc(arg1, arg2, arg3):
# Both local variables and function arguments will be sent to Rollbar
# and available in the UI
localvar = 'local variable'
cause_error_with_local_variables
@app.get('/error')
async def read_error():
await localfunc('func_arg1', 'func_arg2', 1)
return {'result': "You shouldn't be seeing this"}
if __name__ == '__main__':
uvicorn.run(app, host='localhost', port=8888)
================================================
FILE: rollbar/examples/flask/app.py
================================================
# NOTE: pyrollbar requires both `Flask` and `blinker` packages to be installed first
from flask import Flask
from flask import got_request_exception
import rollbar
import rollbar.contrib.flask
app = Flask(__name__)
with app.app_context():
rollbar.init('ACCESS_TOKEN', environment='development')
# send exceptions from `app` to rollbar, using flask's signal system.
got_request_exception.connect(rollbar.contrib.flask.report_exception, app)
@app.route('/')
def root():
foo()
return '<html><body>Hello World</body></html>'
if __name__ == '__main__':
app.run()
================================================
FILE: rollbar/examples/starlette/app.py
================================================
#!/usr/bin/env python
# This example uses Uvicorn package that must be installed. However, it can be
# replaced with any other ASGI-compliant server.
#
# Optional asynchronous reporting requires HTTPX package to be installed.
#
# NOTE: Starlette middlewares don't allow to collect streamed content like a request body.
#
# Run: python app.py
import rollbar
import uvicorn
from rollbar.contrib.starlette import ReporterMiddleware as RollbarMiddleware
from starlette.applications import Starlette
from starlette.responses import PlainTextResponse
# Initialize Rollbar SDK with your server-side ACCESS_TOKEN
rollbar.init(
'ACCESS_TOKEN',
environment='staging',
handler='async', # For asynchronous reporting use: default, async or httpx
)
# Integrate Rollbar with Starlette application
app = Starlette()
app.add_middleware(RollbarMiddleware) # should be added as the first middleware
# Verify application runs correctly
#
# $ curl http://localhost:8888
@app.route('/')
async def root(request):
return PlainTextResponse('hello world')
# Cause an uncaught exception to be sent to Rollbar
# GET query params will be sent to Rollbar and available in the UI
#
# $ curl http://localhost:8888/error?param1=hello¶m2=world
async def localfunc(arg1, arg2, arg3):
# Both local variables and function arguments will be sent to Rollbar
# and available in the UI
localvar = 'local variable'
cause_error_with_local_variables
@app.route('/error')
async def error(request):
await localfunc('func_arg1', 'func_arg2', 1)
return PlainTextResponse("You shouldn't be seeing this")
if __name__ == '__main__':
uvicorn.run(app, host='localhost', port=8888)
================================================
FILE: rollbar/examples/starlette/app_global_request.py
================================================
#!/usr/bin/env python
# This example uses Uvicorn package that must be installed. However, it can be
# replaced with any other ASGI-compliant server.
#
# NOTE: Python 3.6 requires aiocontextvars package to be installed.
#
# Run: python app_global_request.py
import rollbar
import uvicorn
from rollbar.contrib.starlette import LoggerMiddleware
from starlette.applications import Starlette
from starlette.responses import JSONResponse
# Integrate Rollbar with Starlette application
app = Starlette()
app.add_middleware(LoggerMiddleware) # should be added as the last middleware
async def get_user_agent():
# Global access to the current request object
request = rollbar.get_request()
user_agent = request.headers['User-Agent']
return user_agent
# $ curl -i http://localhost:8888
@app.route('/')
async def root(request):
user_agent = await get_user_agent()
return JSONResponse({'user-agent': user_agent})
if __name__ == '__main__':
uvicorn.run(app, host='localhost', port=8888)
================================================
FILE: rollbar/examples/starlette/app_logger.py
================================================
#!/usr/bin/env python
# This example uses Uvicorn package that must be installed. However, it can be
# replaced with any other ASGI-compliant server.
#
# NOTE: Python 3.6 requires aiocontextvars package to be installed.
# Optional asynchronous reporting requires HTTPX package to be installed.
#
# Run: python app_logger.py
import logging
import rollbar
import uvicorn
from rollbar.contrib.starlette import LoggerMiddleware
from rollbar.logger import RollbarHandler
from starlette.applications import Starlette
from starlette.responses import PlainTextResponse
# Initialize Rollbar SDK with your server-side ACCESS_TOKEN
rollbar.init(
'ACCESS_TOKEN',
environment='staging',
handler='async', # For asynchronous reporting use: default, async or httpx
)
# Set root logger to log DEBUG and above
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# Report ERROR and above to Rollbar
rollbar_handler = RollbarHandler()
rollbar_handler.setLevel(logging.ERROR)
# Attach Rollbar handler to the root logger
logger.addHandler(rollbar_handler)
# Integrate Rollbar with Starlette application
app = Starlette()
app.add_middleware(LoggerMiddleware) # should be added as the last middleware
# GET query params will be sent to Rollbar and available in the UI
# $ curl http://localhost:8888?param1=hello¶m2=world
@app.route('/')
async def root(request):
# Report log entries
logger.critical('Critical message sent to Rollbar')
logger.error('Error message sent to Rollbar')
# Ignore log entries
logger.warning('Warning message is not sent to Rollbar')
logger.info('Info message is not sent to Rollbar')
logger.debug('Debug message is not sent to Rollbar')
return PlainTextResponse('hello world')
if __name__ == '__main__':
uvicorn.run(app, host='localhost', port=8888)
================================================
FILE: rollbar/examples/twisted/simpleserv.py
================================================
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
#
# From https://twistedmatrix.com/documents/current/_downloads/simpleserv.py
# NOTE: pyrollbar requires both `Twisted` and `treq` packages to be installed
from twisted.internet import reactor, protocol
import rollbar
def bar(p):
# These local variables will be sent to Rollbar and available in the UI
a = 33
b = a * 5
baz()
def foo():
hello = 'world'
bar(hello)
class Echo(protocol.Protocol):
"""This is just about the simplest possible protocol"""
def dataReceived(self, data):
"As soon as any data is received, write it back."
# Cause an uncaught exception to be sent to Rollbar
foo()
self.transport.write(data)
def main():
rollbar.init('ACCESS_TOKEN', environment='test', handler='twisted')
"""This runs the protocol on port 8000"""
factory = protocol.ServerFactory()
factory.protocol = Echo
reactor.listenTCP(8000, factory)
reactor.run()
# this only runs if the module was *not* imported
if __name__ == '__main__':
main()
================================================
FILE: rollbar/lib/__init__.py
================================================
import base64
import collections
import copy
from array import array
from collections.abc import Mapping
binary_type = bytes
integer_types = int
number_types = (float, int)
string_types = str
sequence_types = (Mapping, list, tuple, set, frozenset, array, collections.deque)
def force_lower(val):
try:
return val.lower()
except:
return str(val).lower()
def prefix_match(key, prefixes):
if not key:
return False
for prefix in prefixes:
if len(prefix) > len(key):
continue
if prefix == key[:len(prefix)]:
return True
return False
def key_in(key, canonicals):
if not key:
return False
for c in canonicals:
if key_match(key, c):
return True
return False
def key_depth(key, canonicals) -> int:
if not key:
return 0
for c in canonicals:
if key_match(key, c):
return len(c)
return 0
def key_match(key, canonical):
if len(key) < len(canonical):
return False
for k, c in zip(key, canonical):
if '*' == c:
continue
if c == k:
continue
return False
return True
def reverse_list_of_lists(l, apply_each_fn=None):
apply_each_fn = apply_each_fn or (lambda x: x)
return [reversed([apply_each_fn(x) for x in inner]) for inner in l or []]
def build_key_matcher(prefixes_or_suffixes, type='prefix', case_sensitive=False):
_prefixes = []
if type == 'prefix':
_iter = iter
elif type == 'suffix':
_iter = reversed
else:
raise ValueError('type must be either "prefix" or "suffix"')
prefixes_or_suffixes = prefixes_or_suffixes or []
for prefix in prefixes_or_suffixes:
if case_sensitive:
# Copy the list of lists
_prefix = list(_iter(prefix))
else:
# Lowercase all of the elements
_prefix = [force_lower(x) for x in _iter(prefix)]
_prefixes.append(_prefix)
def matcher(prefix_or_suffix):
if case_sensitive:
prefix = list(_iter(prefix_or_suffix))
else:
prefix = [force_lower(x) for x in _iter(prefix_or_suffix)]
return prefix_match(prefix, _prefixes)
return matcher
def is_builtin_type(obj):
return obj.__class__.__module__ in ('__builtin__', 'builtins')
# http://www.xormedia.com/recursively-merge-dictionaries-in-python.html
def dict_merge(a, b, silence_errors=False):
"""
Recursively merges dict's. not just simple a['key'] = b['key'], if
both a and bhave a key who's value is a dict then dict_merge is called
on both values and the result stored in the returned dictionary.
"""
if not isinstance(b, dict):
return b
result = a
for k, v in b.items():
if k in result and isinstance(result[k], dict):
result[k] = dict_merge(result[k], v, silence_errors=silence_errors)
else:
try:
result[k] = copy.deepcopy(v)
except Exception as e:
if not silence_errors:
raise e
result[k] = '<Uncopyable obj:(%s)>' % (v,)
return result
def circular_reference_label(data, ref_key=None):
ref = '.'.join([str(x) for x in ref_key])
return '<CircularReference type:(%s) ref:(%s)>' % (type(data).__name__, ref)
def float_nan_label(data):
return '<NaN>'
def float_infinity_label(data):
if data > 1:
return '<Infinity>'
else:
return '<NegativeInfinity>'
def unencodable_object_label(data):
return '<Unencodable type:(%s) base64:(%s)>' % (type(data).__name__,
base64.b64encode(data).decode('ascii'))
def undecodable_object_label(data):
return '<Undecodable type:(%s) base64:(%s)>' % (type(data).__name__,
base64.b64encode(data).decode('ascii'))
try:
from django.utils.functional import SimpleLazyObject
except ImportError:
SimpleLazyObject = None
def defaultJSONEncode(o):
if SimpleLazyObject and isinstance(o, SimpleLazyObject):
if not o._wrapped:
o._setup()
return o._wrapped
return repr(o) + " is not JSON serializable"
================================================
FILE: rollbar/lib/_async.py
================================================
import asyncio
import contextlib
import inspect
import logging
import sys
from unittest import mock
from urllib.parse import urljoin
try:
import httpx
except ImportError:
httpx = None
import rollbar
from rollbar import DEFAULT_TIMEOUT
from rollbar.lib import transport
log = logging.getLogger(__name__)
ALLOWED_HANDLERS = (
'async',
'httpx',
)
if sys.version_info[:2] == (3, 6):
# Backport PEP 567
try:
import aiocontextvars
except ImportError:
log.warning(
'Python3.6 does not provide the `contextvars` module.'
' Some advanced features may not work as expected.'
' Please upgrade Python or install `aiocontextvars`.'
)
try:
from contextvars import ContextVar
except ImportError:
ContextVar = None
if ContextVar:
_ctx_handler = ContextVar('rollbar-handler', default=None)
else:
_ctx_handler = None
class RollbarAsyncError(Exception):
...
async def report_exc_info(
exc_info=None, request=None, extra_data=None, payload_data=None, level=None, **kw
):
"""
Asynchronously reports an exception to Rollbar, using exc_info (from calling sys.exc_info())
exc_info: optional, should be the result of calling sys.exc_info(). If omitted, sys.exc_info() will be called here.
request: optional, a Starlette, WebOb, Werkzeug-based or Sanic request object.
extra_data: optional, will be included in the 'custom' section of the payload
payload_data: optional, dict that will override values in the final payload
(e.g. 'level' or 'fingerprint')
kw: provided for legacy purposes; unused.
Example usage:
rollbar.init(access_token='YOUR_PROJECT_ACCESS_TOKEN')
async def func():
try:
do_something()
except:
await report_exc_info(sys.exc_info(), request, {'foo': 'bar'}, {'level': 'warning'})
"""
with AsyncHandler():
try:
return await call_later(
_report_exc_info(
exc_info, request, extra_data, payload_data, level, **kw
)
)
except Exception as e:
log.exception('Exception while reporting exc_info to Rollbar. %r', e)
async def report_message(
message, level='error', request=None, extra_data=None, payload_data=None, **kw
):
"""
Asynchronously reports an arbitrary string message to Rollbar.
message: the string body of the message
level: level to report at. One of: 'critical', 'error', 'warning', 'info', 'debug'
request: the request object for the context of the message
extra_data: dictionary of params to include with the message. 'body' is reserved.
payload_data: param names to pass in the 'data' level of the payload; overrides defaults.
"""
with AsyncHandler():
try:
return await call_later(
_report_message(message, level, request, extra_data, payload_data)
)
except Exception as e:
log.exception('Exception while reporting message to Rollbar. %r', e)
async def _report_exc_info(
exc_info=None, request=None, extra_data=None, payload_data=None, level=None, **kw
):
return rollbar.report_exc_info(
exc_info, request, extra_data, payload_data, level, **kw
)
async def _report_message(
message, level='error', request=None, extra_data=None, payload_data=None, **kw
):
return rollbar.report_message(message, level, request, extra_data, payload_data)
async def _post_api_httpx(path, payload_str, access_token=None):
headers = {'Content-Type': 'application/json'}
if access_token is not None:
headers['X-Rollbar-Access-Token'] = access_token
else:
headers['X-Rollbar-Access-Token'] = rollbar.SETTINGS.get('access_token')
proxy_cfg = {
'proxy': rollbar.SETTINGS.get('http_proxy'),
'proxy_user': rollbar.SETTINGS.get('http_proxy_user'),
'proxy_password': rollbar.SETTINGS.get('http_proxy_password'),
}
proxies = transport._get_proxy_cfg(proxy_cfg)
mounts = None
if proxies:
mounts = {
'http://': httpx.HTTPTransport(proxy=proxies['http']),
'https://': httpx.HTTPTransport(proxy=proxies['https']),
}
url = urljoin(rollbar.SETTINGS['endpoint'], path)
async with httpx.AsyncClient(
mounts=mounts, verify=rollbar.SETTINGS.get('verify_https', True)
) as client:
resp = await client.post(
url,
content=payload_str,
headers=headers,
timeout=rollbar.SETTINGS.get('timeout', DEFAULT_TIMEOUT),
)
try:
return rollbar._parse_response(path, access_token, payload_str, resp)
except Exception as e:
log.exception('Exception while posting item %r', e)
async def try_report(
exc_info=None, request=None, extra_data=None, payload_data=None, level=None, **kw
):
current_handler = rollbar.SETTINGS.get('handler')
if not (current_handler in ALLOWED_HANDLERS or current_handler == 'default'):
raise RollbarAsyncError('No async handler set.')
if httpx is None:
raise RollbarAsyncError('HTTPX is required')
return await report_exc_info(
exc_info, request, extra_data, payload_data, level, **kw
)
class AsyncHandler:
def __init__(self):
self.global_handler = None
self.token = None
def with_ctx_handler(self):
if self.global_handler in ALLOWED_HANDLERS:
self.token = _ctx_handler.set(self.global_handler)
else:
log.warning(
'Running coroutines requires async compatible handler. Switching to default async handler.'
)
self.token = _ctx_handler.set('async')
return _ctx_handler.get()
def with_global_handler(self):
return self.global_handler
def __enter__(self):
self.global_handler = rollbar.SETTINGS.get('handler')
if _ctx_handler:
return self.with_ctx_handler()
else:
return self.with_global_handler()
def __exit__(self, exc_type, exc_value, traceback):
if _ctx_handler and self.token:
_ctx_handler.reset(self.token)
def get_current_handler():
if _ctx_handler is None:
return rollbar.SETTINGS.get('handler')
handler = _ctx_handler.get()
if handler is None:
return rollbar.SETTINGS.get('handler')
return handler
def call_later(coro):
if sys.version_info < (3, 7):
return asyncio.ensure_future(coro)
return asyncio.create_task(coro)
# test helpers
# TODO: move to rollbar.test.async_helper after migrating from unittest
def run(coro):
if sys.version_info >= (3, 7):
return asyncio.run(coro)
assert inspect.iscoroutine(coro)
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
return loop.run_until_complete(coro)
finally:
loop.close()
asyncio.set_event_loop(None)
def async_receive(message):
async def receive():
return message
assert message['type'] == 'http.request'
return receive
async def coroutine():
...
class BareMiddleware:
def __init__(self, app):
self.app = app
async def __call__(self, scope, receive, send):
await self.app(scope, receive, send)
class FailingTestASGIApp:
async def __call__(self, scope, receive, send):
await self.app(scope, receive, send)
async def app(self, scope, receive, send):
raise RuntimeError('Invoked only for testing')
# for Python 3.7- compatibility
class AsyncMock(mock.MagicMock):
async def __call__(self, *args, **kwargs):
return super().__call__(*args, **kwargs)
================================================
FILE: rollbar/lib/events.py
================================================
EXCEPTION_INFO = 'exception_info'
MESSAGE = 'message'
PAYLOAD = 'payload'
_event_handlers = {
EXCEPTION_INFO: [],
MESSAGE: [],
PAYLOAD: []
}
def _check_type(typ):
if typ not in _event_handlers:
raise ValueError('Unknown type: %s. Must be one of %s' % (typ, _event_handlers.keys()))
def _add_handler(typ, handler_fn, pos):
_check_type(typ)
pos = pos if pos is not None else -1
handlers = _event_handlers[typ]
try:
handlers.index(handler_fn)
except ValueError:
handlers.insert(pos, handler_fn)
def _remove_handler(typ, handler_fn):
_check_type(typ)
handlers = _event_handlers[typ]
try:
index = handlers.index(handler_fn)
handlers.pop(index)
except ValueError:
pass
def _on_event(typ, target, **kw):
_check_type(typ)
ref = target
for handler in _event_handlers[typ]:
result = handler(ref, **kw)
if result is False:
return False
ref = result
return ref
# Add/remove event handlers
def add_exception_info_handler(handler_fn, pos=None):
_add_handler(EXCEPTION_INFO, handler_fn, pos)
def remove_exception_info_handler(handler_fn):
_remove_handler(EXCEPTION_INFO, handler_fn)
def add_message_handler(handler_fn, pos=None):
_add_handler(MESSAGE, handler_fn, pos)
def remove_message_handler(handler_fn):
_remove_handler(MESSAGE, handler_fn)
def add_payload_handler(handler_fn, pos=None):
_add_handler(PAYLOAD, handler_fn, pos)
def remove_payload_handler(handler_fn):
_remove_handler(PAYLOAD, handler_fn)
# Event handler processing
def on_exception_info(exc_info, **kw):
return _on_event(EXCEPTION_INFO, exc_info, **kw)
def on_message(message, **kw):
return _on_event(MESSAGE, message, **kw)
def on_payload(payload, **kw):
return _on_event(PAYLOAD, payload, **kw)
# Misc
def reset():
for handlers in _event_handlers.values():
del handlers[:]
================================================
FILE: rollbar/lib/filters/__init__.py
================================================
from rollbar.lib import events
from rollbar.lib.filters.basic import filter_rollbar_ignored_exceptions, filter_by_level
def add_builtin_filters(settings):
# exc_info filters
events.add_exception_info_handler(filter_rollbar_ignored_exceptions)
events.add_exception_info_handler(filter_by_level)
# message filters
events.add_message_handler(filter_by_level)
================================================
FILE: rollbar/lib/filters/basic.py
================================================
def filter_rollbar_ignored_exceptions(exc_info, **kw):
_, exc, _ = exc_info
if getattr(exc, '_rollbar_ignore', False):
return False
return exc_info
def filter_by_level(target, **kw):
if 'level' in kw and kw['level'] == 'ignored':
return False
return target
================================================
FILE: rollbar/lib/payload.py
================================================
from typing import TypedDict
class Attribute(TypedDict):
"""
Represents the `data.attributes` field in the payload, which is used to store session, execution scope information,
and other key-value pairs.
"""
key: str
value: str
================================================
FILE: rollbar/lib/session.py
================================================
from __future__ import annotations
import random
import threading
from contextvars import ContextVar
from rollbar.lib.payload import Attribute
_context_session: ContextVar[list[Attribute]|None] = ContextVar('rollbar-session', default=None)
_thread_session: threading.local = threading.local()
def set_current_session(headers: dict[str, str]) -> None:
"""
Set current session data.
The session data should be a dictionary with string keys and string values.
"""
session_data = parse_session_request_baggage_headers(headers, generate_missing=True)
_context_session.set(session_data)
_thread_session.data = session_data
def get_current_session() -> list[Attribute]:
"""
Return current session data.
Do NOT modify the returned session data.
"""
session_data = _context_session.get()
if session_data is not None:
return session_data
# Fallback to thread local storage for non-async contexts.
return getattr(_thread_session, 'data', None) or []
def reset_current_session() -> None:
"""
Reset current session data.
"""
_context_session.set(None)
_thread_session.data = None
def parse_session_request_baggage_headers(headers: dict, generate_missing: bool = False) -> list[Attribute]:
"""
Parse the 'baggage' header from the request headers to extract session information. If the 'baggage' header is not
present or does not contain the expected keys, a new execution scope ID will be generated and returned as part of
the session attributes.
:param headers: The request headers as a dictionary.
:param generate_missing: If True, generates a new execution scope ID if it's missing from the baggage header. If
False, it is not generated. This should only be set to True when the session data is being
stored for the first time in the request context. Generally, `set_current_session()`, and
`get_current_session()` should be used instead.
"""
if not headers:
if generate_missing:
return _build_new_scope_attributes()
return []
baggage_header = None
# Make sure to handle case-insensitive header keys.
for key in headers.keys():
if key.lower() == 'baggage':
baggage_header = headers[key]
break
if not baggage_header:
if generate_missing:
return _build_new_scope_attributes()
return []
baggage_items = baggage_header.split(',')
baggage_data = []
has_scope_id = False
for item in baggage_items:
if '=' not in item:
continue
key, value = item.split('=', 1)
key = key.strip()
if key == 'rollbar.session.id':
baggage_data.append({'key': 'session_id', 'value': value.strip()})
if key == 'rollbar.execution.scope.id':
has_scope_id = True
baggage_data.append({'key': 'execution_scope_id', 'value': value.strip()})
if not baggage_data:
if generate_missing:
return _build_new_scope_attributes()
return []
# Always ensure we have an execution scope ID, even if the baggage header is present but doesn't contain it.
if not has_scope_id and generate_missing:
baggage_data.extend(_build_new_scope_attributes())
return baggage_data
def _build_new_scope_attributes() -> list[Attribute]:
"""
Generates a new value for the `rollbar.execution.scope.id` attribute.
"""
new_id = _new_scope_id()
if new_id is None:
return []
return [{'key': 'execution_scope_id', 'value': new_id}]
def _new_scope_id() -> str | None:
"""
Generate a new random ID with 128 bits of randomness, formatted as a 32-character hexadecimal string. To be used as
an execution scope ID.
"""
try:
# Generate a random integer with exactly 128 random bits
num = random.getrandbits(128)
except Exception as e:
return None
return format(num, "032x")
================================================
FILE: rollbar/lib/thread_pool.py
================================================
import logging
import os
import sys
from concurrent.futures import ThreadPoolExecutor
_pool = None # type: ThreadPoolExecutor|None
log = logging.getLogger(__name__)
def init_pool(max_workers):
"""
Creates the thread pool with the max workers.
:type max_workers: int|None
:param max_workers: If max_workers is None it will use the logic from the standard library to calculate the number
of threads. However, we ported the logic from Python 3.5 to earlier versions.
"""
if max_workers is None and sys.version_info < (3, 5):
max_workers = (os.cpu_count() or 1) * 5
global _pool
_pool = ThreadPoolExecutor(max_workers)
def submit(worker, payload_str, access_token):
"""
Submit a new task to the thread pool.
:type worker: function
:type payload_str: str
:type access_token: str
"""
global _pool
if _pool is None:
log.warning('pyrollbar: Thead pool not initialized. Please ensure init_pool() is called prior to submit().')
return
_pool.submit(worker, payload_str, access_token)
================================================
FILE: rollbar/lib/transform.py
================================================
from typing import Optional
class Transform(object):
depth_first = True
priority = 100
def default(self, o, key=None):
return o
def transform_circular_reference(self, o, key=None, ref_key=None):
# By default, we just perform a no-op for circular references.
# Subclasses should implement this method to return whatever representation
# for the circular reference they need.
return self.default(o, key=key)
def transform_tuple(self, o, key=None):
return self.default(o, key=key)
def transform_namedtuple(self, o, key=None):
return self.default(o, key=key)
def transform_list(self, o, key=None):
return self.default(o, key=key)
def transform_dict(self, o, key=None):
return self.default(o, key=key)
def transform_number(self, o, key=None):
return self.default(o, key=key)
def transform_bytes(self, o, key=None):
return self.default(o, key=key)
def transform_unicode(self, o, key=None):
return self.default(o, key=key)
def transform_boolean(self, o, key=None):
return self.default(o, key=key)
def transform_path(self, o, key=None):
return self.default(str(o), key=key)
def transform_custom(self, o, key=None):
return self.default(o, key=key)
@staticmethod
def rollbar_repr(obj: object) -> Optional[str]:
r = None
if hasattr(obj, '__rollbar_repr__'):
r = obj.__rollbar_repr__()
if not isinstance(r, str):
raise TypeError(f'__rollbar_repr__ returned non-string (type {type(r)})')
return r
================================================
FILE: rollbar/lib/transforms/__init__.py
================================================
from collections.abc import Iterable
from rollbar.lib import (
binary_type,
string_types,
number_types,
traverse,
)
# NOTE: Don't remove this import, it would cause a breaking change to the library's API.
# The `Transform` class was moved out of this file to prevent a cyclical dependency issue.
from rollbar.lib.transform import Transform
from rollbar.lib.transforms.batched import BatchedTransform
_ALLOWED_CIRCULAR_REFERENCE_TYPES = [binary_type, bool, type(None)]
if isinstance(string_types, tuple):
_ALLOWED_CIRCULAR_REFERENCE_TYPES.extend(string_types)
else:
_ALLOWED_CIRCULAR_REFERENCE_TYPES.append(string_types)
if isinstance(number_types, tuple):
_ALLOWED_CIRCULAR_REFERENCE_TYPES.extend(number_types)
else:
_ALLOWED_CIRCULAR_REFERENCE_TYPES.append(number_types)
_ALLOWED_CIRCULAR_REFERENCE_TYPES = tuple(_ALLOWED_CIRCULAR_REFERENCE_TYPES)
def transform(obj, transforms, key=None, batch_transforms=False):
if isinstance(transforms, Transform):
transforms = [transforms]
if batch_transforms:
transforms = [BatchedTransform(transforms)]
for transform in transforms:
if not isinstance(transform, Transform):
continue
obj = _transform(obj, transform, key=key)
return obj
def _transform(obj, transform, key=None):
key = key or ()
def do_transform(type_name, val, key=None, **kw):
fn = getattr(transform, "transform_%s" % type_name, transform.transform_custom)
val = fn(val, key=key, **kw)
return val
def string_handler(s, key=None):
if isinstance(s, bytes):
return do_transform("bytes", s, key=key)
elif isinstance(s, str):
return do_transform("unicode", s, key=key)
def default_handler(o, key=None):
if isinstance(o, bool):
return do_transform("boolean", o, key=key)
# There is a quirk in the current version (1.1.6) of the enum
# backport enum34 which causes it to not have the same
# behavior as Python 3.4+. One way to identify IntEnums is that
# they are instances of numbers but not number types.
if isinstance(o, number_types):
if type(o) not in number_types:
return do_transform("custom", o, key=key)
else:
return do_transform("number", o, key=key)
return do_transform("custom", o, key=key)
handlers = {
"string_handler": string_handler,
"tuple_handler": lambda o, key=None: do_transform("tuple", o, key=key),
"namedtuple_handler": lambda o, key=None: do_transform(
"namedtuple", o, key=key
),
"list_handler": lambda o, key=None: do_transform("list", o, key=key),
"set_handler": lambda o, key=None: do_transform("set", o, key=key),
"mapping_handler": lambda o, key=None: do_transform("dict", o, key=key),
"path_handler": lambda o, key=None: do_transform("path", o, key=key),
"circular_reference_handler": lambda o, key=None, ref_key=None: do_transform(
"circular_reference", o, key=key, ref_key=ref_key
),
"default_handler": default_handler,
"allowed_circular_reference_types": _ALLOWED_CIRCULAR_REFERENCE_TYPES,
}
return traverse.traverse(obj, key=key, depth_first=transform.depth_first, **handlers)
__all__ = ["transform", "Transform"]
================================================
FILE: rollbar/lib/transforms/batched.py
================================================
from rollbar.lib.transform import Transform
from rollbar.lib import (
number_types,
type_info,
)
def do_transform(transform, type_name, val, key=None, **kw):
fn = getattr(transform, "transform_%s" % type_name, transform.transform_custom)
val = fn(val, key=key, **kw)
return val
def string_handler(transform, s, key=None):
if isinstance(s, bytes):
return do_transform(transform, "bytes", s, key=key)
elif isinstance(s, str):
return do_transform(transform, "unicode", s, key=key)
def default_handler(transform, o, key=None):
if isinstance(o, bool):
return do_transform(transform, "boolean", o, key=key)
# There is a quirk in the current version (1.1.6) of the enum
# backport enum34 which causes it to not have the same
# behavior as Python 3.4+. One way to identify IntEnums is that
# they are instances of numbers but not number types.
if isinstance(o, number_types):
if type(o) not in number_types:
return do_transform(transform, "custom", o, key=key)
else:
return do_transform(transform, "number", o, key=key)
return do_transform(transform, "custom", o, key=key)
handlers = {
type_info.STRING: string_handler,
type_info.TUPLE: lambda transform, o, key=None: do_transform(
transform, "tuple", o, key=key
),
type_info.NAMEDTUPLE: lambda transform, o, key=None: do_transform(
transform, "namedtuple", o, key=key
),
type_info.LIST: lambda transform, o, key=None: do_transform(
transform, "list", o, key=key
),
type_info.SET: lambda transform, o, key=None: do_transform(
transform, "set", o, key=key
),
type_info.MAPPING: lambda transform, o, key=None: do_transform(
transform, "dict", o, key=key
),
type_info.CIRCULAR: lambda transform, o, key=None, ref_key=None: do_transform(
transform, "circular_reference", o, key=key, ref_key=ref_key
),
type_info.DEFAULT: default_handler,
}
class BatchedTransform(Transform):
def __init__(self, transforms):
super(BatchedTransform, self).__init__()
self._transforms = transforms
def default(self, o, key=None):
for transform in self._transforms:
node_type = type_info.get_type(o)
handler = handlers.get(node_type, handlers.get(type_info.DEFAULT))
o = handler(transform, o, key=key)
return o
__all__ = ["BatchedTransform"]
================================================
FILE: rollbar/lib/transforms/scrub.py
================================================
import random
from rollbar.lib import build_key_matcher
from rollbar.lib.transform import Transform
class ScrubTransform(Transform):
suffix_matcher = None
priority = 40
def __init__(self, suffixes=None, redact_char='*', randomize_len=True):
super(ScrubTransform, self).__init__()
if suffixes is not None and len(suffixes) > 0:
self.suffix_matcher = build_key_matcher(suffixes, type='suffix')
self.redact_char = redact_char
self.randomize_len = randomize_len
def in_scrub_fields(self, key):
if self.suffix_matcher is None:
return False
return self.suffix_matcher(key)
def redact(self, val):
if self.randomize_len:
_len = random.randint(3, 20)
else:
try:
_len = len(val)
except:
_len = len(str(val))
return self.redact_char * _len
def default(self, o, key=None):
if self.in_scrub_fields(key):
return self.redact(o)
return o
__all__ = ['ScrubTransform']
================================================
FILE: rollbar/lib/transforms/scrub_redact.py
================================================
from rollbar.lib.transforms.scrub import ScrubTransform
class RedactRef(object):
pass
REDACT_REF = RedactRef()
class ScrubRedactTransform(ScrubTransform):
priority = 20
def default(self, o, key=None):
if o is REDACT_REF:
return self.redact(o)
return super(ScrubRedactTransform, self).default(o, key=key)
__all__ = ['ScrubRedactTransform']
================================================
FILE: rollbar/lib/transforms/scruburl.py
================================================
import re
from urllib.parse import urlsplit, urlencode, urlunsplit, parse_qs
from rollbar.lib import string_types, binary_type
from rollbar.lib.transforms.scrub import ScrubTransform
_starts_with_auth_re = re.compile(r'^[a-zA-Z0-9-_]*(:[^@/]+)?@')
class ScrubUrlTransform(ScrubTransform):
priority = 50
def __init__(self,
suffixes=None,
scrub_username=False,
scrub_password=True,
params_to_scrub=None,
redact_char='-',
randomize_len=True):
super(ScrubUrlTransform, self).__init__(suffixes=suffixes,
redact_char=redact_char,
randomize_len=randomize_len)
self.scrub_username = scrub_username
self.scrub_password = scrub_password
self.params_to_scrub = {x.lower() for x in params_to_scrub or []}
def in_scrub_fields(self, key):
# Returning True here because we want to scrub URLs out of
# every string, not just ones th
gitextract_s7qvive8/
├── .flake8
├── .github/
│ ├── pull_request_template.md
│ └── workflows/
│ └── ci.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── THANKS.md
├── pyproject.toml
└── rollbar/
├── __init__.py
├── cli.py
├── contrib/
│ ├── __init__.py
│ ├── asgi/
│ │ ├── __init__.py
│ │ ├── integration.py
│ │ ├── middleware.py
│ │ └── types.py
│ ├── bottle/
│ │ └── __init__.py
│ ├── django/
│ │ ├── __init__.py
│ │ ├── context_processors.py
│ │ ├── middleware.py
│ │ ├── models.py
│ │ ├── tests.py
│ │ └── utils.py
│ ├── django_rest_framework/
│ │ └── __init__.py
│ ├── fastapi/
│ │ ├── __init__.py
│ │ ├── logger.py
│ │ ├── middleware.py
│ │ ├── routing.py
│ │ └── utils.py
│ ├── flask/
│ │ └── __init__.py
│ ├── pyramid/
│ │ └── __init__.py
│ ├── quart/
│ │ └── __init__.py
│ ├── rq/
│ │ └── __init__.py
│ └── starlette/
│ ├── __init__.py
│ ├── logger.py
│ ├── middleware.py
│ └── requests.py
├── examples/
│ ├── asgi/
│ │ └── app.py
│ ├── django/
│ │ └── app.py
│ ├── fastapi/
│ │ ├── app.py
│ │ ├── app_global_request.py
│ │ ├── app_logger.py
│ │ └── app_middleware.py
│ ├── flask/
│ │ └── app.py
│ ├── starlette/
│ │ ├── app.py
│ │ ├── app_global_request.py
│ │ └── app_logger.py
│ └── twisted/
│ └── simpleserv.py
├── lib/
│ ├── __init__.py
│ ├── _async.py
│ ├── events.py
│ ├── filters/
│ │ ├── __init__.py
│ │ └── basic.py
│ ├── payload.py
│ ├── session.py
│ ├── thread_pool.py
│ ├── transform.py
│ ├── transforms/
│ │ ├── __init__.py
│ │ ├── batched.py
│ │ ├── scrub.py
│ │ ├── scrub_redact.py
│ │ ├── scruburl.py
│ │ ├── serializable.py
│ │ └── shortener.py
│ ├── transport.py
│ ├── traverse.py
│ └── type_info.py
├── logger.py
└── test/
├── __init__.py
├── asgi_tests/
│ ├── __init__.py
│ ├── test_integration.py
│ ├── test_middleware.py
│ └── test_spec.py
├── async_tests/
│ ├── __init__.py
│ └── test_async.py
├── fastapi_tests/
│ ├── __init__.py
│ ├── test_logger.py
│ ├── test_middleware.py
│ ├── test_routing.py
│ └── test_utils.py
├── flask_tests/
│ ├── __init__.py
│ └── test_flask.py
├── starlette_tests/
│ ├── __init__.py
│ ├── test_logger.py
│ ├── test_middleware.py
│ └── test_requests.py
├── test_basic_filters.py
├── test_batched_transform.py
├── test_custom_filters.py
├── test_lib.py
├── test_loghandler.py
├── test_pyramid.py
├── test_rollbar.py
├── test_scrub_redact_transform.py
├── test_scrub_transform.py
├── test_scruburl_transform.py
├── test_serializable_transform.py
├── test_session.py
├── test_shortener_transform.py
├── test_transform.py
├── test_traverse.py
├── twisted_tests/
│ ├── __init__.py
│ └── test_twisted.py
└── utils.py
SYMBOL INDEX (780 symbols across 86 files)
FILE: rollbar/__init__.py
function passthrough_decorator (line 105) | def passthrough_decorator(func):
class VerifyHTTPS (line 125) | class VerifyHTTPS(object):
method __init__ (line 126) | def __init__(self):
method creatorForNetloc (line 130) | def creatorForNetloc(self, hostname, port):
function log_handler (line 136) | def log_handler(event):
function get_request (line 167) | def get_request():
function _get_bottle_request (line 193) | def _get_bottle_request():
function _get_flask_request (line 200) | def _get_flask_request():
function _get_pyramid_request (line 207) | def _get_pyramid_request():
function _get_pylons_request (line 214) | def _get_pylons_request():
function _get_starlette_request (line 221) | def _get_starlette_request():
function _get_fastapi_request (line 231) | def _get_fastapi_request():
function init (line 356) | def init(access_token, environment='production', scrub_fields=None, url_...
function _configure_transport (line 457) | def _configure_transport(**kw):
function _requests_configuration (line 462) | def _requests_configuration(**kw):
function lambda_function (line 471) | def lambda_function(f):
function report_exc_info (line 490) | def report_exc_info(exc_info=None, request=None, extra_data=None, payloa...
function report_message (line 518) | def report_message(message, level='error', request=None, extra_data=None...
function send_payload (line 534) | def send_payload(payload, access_token):
function search_items (line 602) | def search_items(title, return_fields=None, access_token=None, endpoint=...
function wait (line 629) | def wait(f=None):
class ApiException (line 635) | class ApiException(Exception):
class ApiError (line 643) | class ApiError(ApiException):
class Result (line 651) | class Result(object):
method __init__ (line 660) | def __init__(self, access_token, path, params, data):
method __str__ (line 666) | def __str__(self):
class PagedResult (line 670) | class PagedResult(Result):
method __init__ (line 681) | def __init__(self, access_token, path, page_num, params, data, endpoin...
method next_page (line 686) | def next_page(self):
method prev_page (line 691) | def prev_page(self):
function _resolve_exception_class (line 702) | def _resolve_exception_class(idx, filter):
function _filtered_level (line 716) | def _filtered_level(exception):
function _is_ignored (line 725) | def _is_ignored(exception):
function _create_agent_log (line 729) | def _create_agent_log():
function _report_exc_info (line 748) | def _report_exc_info(exc_info, request, extra_data, payload_data, level=...
function _walk_trace_chain (line 817) | def _walk_trace_chain(cls, exc, trace):
function _trace_data (line 834) | def _trace_data(cls, exc, trace):
function _report_message (line 853) | def _report_message(message, level, request, extra_data, payload_data):
function _add_session_data (line 899) | def _add_session_data(data: dict) -> None:
function _add_session_attributes (line 917) | def _add_session_attributes(data: dict, session_data: list[Attribute]) -...
function _session_data_from_request (line 933) | def _session_data_from_request(data: dict) -> dict:
function _check_config (line 943) | def _check_config():
function _build_base_data (line 960) | def _build_base_data(request, level='error'):
function _add_person_data (line 979) | def _add_person_data(data, request):
function _build_person_data (line 993) | def _build_person_data(request):
function _get_func_from_frame (line 1044) | def _get_func_from_frame(frame):
function _add_locals_data (line 1056) | def _add_locals_data(trace_data, exc_info):
function _serialize_frame_data (line 1127) | def _serialize_frame_data(data):
function _add_lambda_context_data (line 1135) | def _add_lambda_context_data(data):
function _add_request_data (line 1163) | def _add_request_data(data, request):
function _check_add_locals (line 1177) | def _check_add_locals(frame, frame_num, total_frames):
function _get_actual_request (line 1193) | def _get_actual_request(request):
function _build_request_data (line 1203) | def _build_request_data(request):
function _build_webob_request_data (line 1255) | def _build_webob_request_data(request):
function _extract_wsgi_headers (line 1284) | def _extract_wsgi_headers(items):
function _build_django_request_data (line 1293) | def _build_django_request_data(request):
function _build_werkzeug_request_data (line 1315) | def _build_werkzeug_request_data(request):
function _build_tornado_request_data (line 1336) | def _build_tornado_request_data(request):
function _build_bottle_request_data (line 1350) | def _build_bottle_request_data(request):
function _build_sanic_request_data (line 1372) | def _build_sanic_request_data(request):
function _build_falcon_request_data (line 1393) | def _build_falcon_request_data(request):
function _build_wsgi_request_data (line 1406) | def _build_wsgi_request_data(request):
function _build_starlette_request_data (line 1433) | def _build_starlette_request_data(request):
function _build_fastapi_request_data (line 1477) | def _build_fastapi_request_data(request):
function _filter_ip (line 1481) | def _filter_ip(request_data, capture_ip):
function _build_server_data (line 1509) | def _build_server_data():
function _transform (line 1532) | def _transform(obj, key=None):
function _build_payload (line 1541) | def _build_payload(data):
function _serialize_payload (line 1557) | def _serialize_payload(payload):
function _send_payload (line 1561) | def _send_payload(payload_str, access_token):
function _send_payload_thread (line 1573) | def _send_payload_thread(payload_str, access_token):
function _send_payload_pool (line 1579) | def _send_payload_pool(payload_str, access_token):
function _send_payload_thread_pool (line 1586) | def _send_payload_thread_pool(payload_str, access_token):
function _send_payload_appengine (line 1591) | def _send_payload_appengine(payload_str, access_token):
function _post_api_appengine (line 1598) | def _post_api_appengine(path, payload_str, access_token=None):
function _post_api (line 1616) | def _post_api(path, payload_str, access_token=None):
function _get_api (line 1635) | def _get_api(path, access_token=None, endpoint=None, **params):
function _send_payload_tornado (line 1648) | def _send_payload_tornado(payload_str, access_token):
function _post_api_tornado (line 1655) | def _post_api_tornado(path, payload_str, access_token=None):
function _send_payload_twisted (line 1684) | def _send_payload_twisted(payload_str, access_token):
function _post_api_twisted (line 1690) | def _post_api_twisted(path, payload_str, access_token=None):
function _send_payload_httpx (line 1716) | def _send_payload_httpx(payload_str, access_token):
function _send_payload_async (line 1726) | def _send_payload_async(payload_str, access_token):
function _send_failsafe (line 1733) | def _send_failsafe(message, uuid, host):
function _parse_response (line 1762) | def _parse_response(path, access_token, params, resp, endpoint=None):
function _extract_user_ip_from_headers (line 1825) | def _extract_user_ip_from_headers(request):
function _extract_user_ip (line 1835) | def _extract_user_ip(request):
function _wsgi_extract_user_ip (line 1839) | def _wsgi_extract_user_ip(environ):
function _starlette_extract_user_ip (line 1849) | def _starlette_extract_user_ip(request):
FILE: rollbar/cli.py
function _gen_report_message (line 10) | def _gen_report_message(level):
function main (line 27) | def main():
FILE: rollbar/contrib/asgi/integration.py
class IntegrationBase (line 7) | class IntegrationBase:
method __init__ (line 12) | def __init__(self):
class integrate (line 17) | class integrate:
method __init__ (line 22) | def __init__(self, *, framework_name='unknown'):
method __call__ (line 25) | def __call__(self, obj):
method _register_hook (line 32) | def _register_hook(self):
method _insert_hook (line 38) | def _insert_hook(self, func):
FILE: rollbar/contrib/asgi/middleware.py
class ReporterMiddleware (line 15) | class ReporterMiddleware(IntegrationBase):
method __init__ (line 16) | def __init__(self, app: ASGIApp) -> None:
method __call__ (line 21) | async def __call__(self, scope: Scope, receive: Receive, send: Send) -...
method _format_headers (line 43) | def _format_headers(headers: Iterable[tuple[bytes, bytes]]) -> dict[st...
FILE: rollbar/contrib/bottle/__init__.py
class RollbarBottleReporter (line 3) | class RollbarBottleReporter(object):
method __init__ (line 11) | def __init__(self, *args, **kwargs):
method __call__ (line 28) | def __call__(self, callback):
FILE: rollbar/contrib/django/context_processors.py
function rollbar_settings (line 18) | def rollbar_settings(request):
FILE: rollbar/contrib/django/middleware.py
function _patch_debugview (line 116) | def _patch_debugview(rollbar_web_base):
function _should_ignore_404 (line 186) | def _should_ignore_404(url):
function _apply_sensitive_post_params (line 190) | def _apply_sensitive_post_params(request):
class RollbarNotifierMiddleware (line 209) | class RollbarNotifierMiddleware(MiddlewareMixin):
method __init__ (line 210) | def __init__(self, get_response=None):
method __call__ (line 264) | def __call__(self, request):
method _ensure_log_handler (line 278) | def _ensure_log_handler(self):
method _get_setting (line 290) | def _get_setting(self, name, default=None):
method get_extra_data (line 301) | def get_extra_data(self, request, exc):
method get_payload_data (line 304) | def get_payload_data(self, request, exc):
method process_response (line 307) | def process_response(self, request, response):
method process_exception (line 310) | def process_exception(self, request, exc):
class RollbarNotifierMiddlewareOnly404 (line 323) | class RollbarNotifierMiddlewareOnly404(MiddlewareMixin):
method get_extra_data (line 324) | def get_extra_data(self, request, exc):
method get_payload_data (line 327) | def get_payload_data(self, request, exc):
method process_response (line 330) | def process_response(self, request, response):
class RollbarNotifierMiddlewareExcluding404 (line 356) | class RollbarNotifierMiddlewareExcluding404(RollbarNotifierMiddleware):
method process_exception (line 357) | def process_exception(self, request, exc):
FILE: rollbar/contrib/django/tests.py
class BasicTests (line 7) | class BasicTests(TestCase):
method test_configuration (line 8) | def test_configuration(self):
FILE: rollbar/contrib/django/utils.py
class MiddlewareMixin (line 1) | class MiddlewareMixin(object):
method __init__ (line 2) | def __init__(self, get_response=None):
FILE: rollbar/contrib/django_rest_framework/__init__.py
function post_exception_handler (line 12) | def post_exception_handler(exc, context):
FILE: rollbar/contrib/fastapi/logger.py
class LoggerMiddleware (line 10) | class LoggerMiddleware(StarletteLoggerMiddleware):
FILE: rollbar/contrib/fastapi/middleware.py
class ReporterMiddleware (line 10) | class ReporterMiddleware(StarletteReporterMiddleware):
FILE: rollbar/contrib/fastapi/routing.py
function add_to (line 30) | def add_to(app_or_router: Union[FastAPI, APIRouter]) -> Optional[Type[AP...
class RollbarLoggingRoute (line 80) | class RollbarLoggingRoute(APIRoute):
method get_route_handler (line 81) | def get_route_handler(self) -> Callable:
function _add_to_app (line 111) | def _add_to_app(app):
function _add_to_router (line 115) | def _add_to_router(router):
FILE: rollbar/contrib/fastapi/utils.py
class FastAPIVersionError (line 15) | class FastAPIVersionError(Exception):
method __init__ (line 16) | def __init__(self, version, reason=''):
function is_current_version_higher_or_equal (line 25) | def is_current_version_higher_or_equal(current_version, min_version):
class fastapi_min_version (line 52) | class fastapi_min_version:
method __init__ (line 53) | def __init__(self, min_version):
method __call__ (line 56) | def __call__(self, func):
function get_installed_middlewares (line 72) | def get_installed_middlewares(app):
function has_bare_routing (line 100) | def has_bare_routing(app_or_router: Union[FastAPI, APIRouter]):
FILE: rollbar/contrib/flask/__init__.py
function report_exception (line 10) | def report_exception(app, exception):
function _hook (line 14) | def _hook(request, data):
function init (line 23) | def init(app: Flask, access_token, environment='production', scrub_field...
FILE: rollbar/contrib/pyramid/__init__.py
function handle_error (line 30) | def handle_error(request, exception, exc_info):
function parse_settings (line 39) | def parse_settings(settings):
function rollbar_tween_factory (line 51) | def rollbar_tween_factory(pyramid_handler, registry):
function patch_debugtoolbar (line 81) | def patch_debugtoolbar(settings):
function includeme (line 117) | def includeme(config):
function create_rollbar_middleware (line 168) | def create_rollbar_middleware(app, global_config=None, **kw):
class RollbarMiddleware (line 176) | class RollbarMiddleware(object):
method __init__ (line 177) | def __init__(self, settings, app):
method __call__ (line 181) | def __call__(self, environ, start_resp):
FILE: rollbar/contrib/quart/__init__.py
function report_exception (line 9) | def report_exception(app, exception):
function _hook (line 13) | def _hook(request, data):
FILE: rollbar/contrib/rq/__init__.py
function exception_handler (line 36) | def exception_handler(job, *exc_info):
FILE: rollbar/contrib/starlette/logger.py
class LoggerMiddleware (line 17) | class LoggerMiddleware(ASGIReporterMiddleware):
method __init__ (line 18) | def __init__(self, app: ASGIApp) -> None:
method __call__ (line 29) | async def __call__(self, scope: Scope, receive: Receive, send: Send) -...
FILE: rollbar/contrib/starlette/middleware.py
class ReporterMiddleware (line 19) | class ReporterMiddleware(ASGIReporterMiddleware):
method __call__ (line 20) | async def __call__(self, scope: Scope, receive: Receive, send: Send) -...
FILE: rollbar/contrib/starlette/requests.py
function get_current_request (line 35) | def get_current_request() -> Optional[Request]:
function store_current_request (line 52) | def store_current_request(
function hasuser (line 69) | def hasuser(request: Request) -> bool:
FILE: rollbar/examples/asgi/app.py
function root (line 40) | async def root(request):
function localfunc (line 48) | async def localfunc(arg1, arg2, arg3):
function error (line 56) | async def error(request):
FILE: rollbar/examples/django/app.py
function index (line 49) | def index(request):
function error (line 52) | def error(request):
FILE: rollbar/examples/fastapi/app.py
function read_root (line 35) | async def read_root():
function localfunc (line 43) | async def localfunc(arg1, arg2, arg3):
function read_error (line 51) | async def read_error():
function read_body (line 61) | async def read_body():
function read_form (line 71) | async def read_form():
FILE: rollbar/examples/fastapi/app_global_request.py
function get_user_agent (line 21) | async def get_user_agent():
function read_root (line 31) | async def read_root():
FILE: rollbar/examples/fastapi/app_logger.py
function read_root (line 46) | async def read_root():
FILE: rollbar/examples/fastapi/app_middleware.py
function read_root (line 35) | async def read_root():
function localfunc (line 43) | async def localfunc(arg1, arg2, arg3):
function read_error (line 51) | async def read_error():
FILE: rollbar/examples/flask/app.py
function root (line 18) | def root():
FILE: rollbar/examples/starlette/app.py
function root (line 35) | async def root(request):
function localfunc (line 43) | async def localfunc(arg1, arg2, arg3):
function error (line 51) | async def error(request):
FILE: rollbar/examples/starlette/app_global_request.py
function get_user_agent (line 22) | async def get_user_agent():
function root (line 32) | async def root(request):
FILE: rollbar/examples/starlette/app_logger.py
function root (line 47) | async def root(request):
FILE: rollbar/examples/twisted/simpleserv.py
function bar (line 14) | def bar(p):
function foo (line 21) | def foo():
class Echo (line 26) | class Echo(protocol.Protocol):
method dataReceived (line 29) | def dataReceived(self, data):
function main (line 37) | def main():
FILE: rollbar/lib/__init__.py
function force_lower (line 15) | def force_lower(val):
function prefix_match (line 22) | def prefix_match(key, prefixes):
function key_in (line 36) | def key_in(key, canonicals):
function key_depth (line 47) | def key_depth(key, canonicals) -> int:
function key_match (line 58) | def key_match(key, canonical):
function reverse_list_of_lists (line 72) | def reverse_list_of_lists(l, apply_each_fn=None):
function build_key_matcher (line 77) | def build_key_matcher(prefixes_or_suffixes, type='prefix', case_sensitiv...
function is_builtin_type (line 109) | def is_builtin_type(obj):
function dict_merge (line 114) | def dict_merge(a, b, silence_errors=False):
function circular_reference_label (line 140) | def circular_reference_label(data, ref_key=None):
function float_nan_label (line 145) | def float_nan_label(data):
function float_infinity_label (line 149) | def float_infinity_label(data):
function unencodable_object_label (line 156) | def unencodable_object_label(data):
function undecodable_object_label (line 161) | def undecodable_object_label(data):
function defaultJSONEncode (line 171) | def defaultJSONEncode(o):
FILE: rollbar/lib/_async.py
class RollbarAsyncError (line 48) | class RollbarAsyncError(Exception):
function report_exc_info (line 52) | async def report_exc_info(
function report_message (line 86) | async def report_message(
function _report_exc_info (line 108) | async def _report_exc_info(
function _report_message (line 116) | async def _report_message(
function _post_api_httpx (line 122) | async def _post_api_httpx(path, payload_str, access_token=None):
function try_report (line 159) | async def try_report(
class AsyncHandler (line 174) | class AsyncHandler:
method __init__ (line 175) | def __init__(self):
method with_ctx_handler (line 179) | def with_ctx_handler(self):
method with_global_handler (line 190) | def with_global_handler(self):
method __enter__ (line 193) | def __enter__(self):
method __exit__ (line 201) | def __exit__(self, exc_type, exc_value, traceback):
function get_current_handler (line 206) | def get_current_handler():
function call_later (line 218) | def call_later(coro):
function run (line 229) | def run(coro):
function async_receive (line 244) | def async_receive(message):
function coroutine (line 252) | async def coroutine():
class BareMiddleware (line 256) | class BareMiddleware:
method __init__ (line 257) | def __init__(self, app):
method __call__ (line 260) | async def __call__(self, scope, receive, send):
class FailingTestASGIApp (line 264) | class FailingTestASGIApp:
method __call__ (line 265) | async def __call__(self, scope, receive, send):
method app (line 268) | async def app(self, scope, receive, send):
class AsyncMock (line 273) | class AsyncMock(mock.MagicMock):
method __call__ (line 274) | async def __call__(self, *args, **kwargs):
FILE: rollbar/lib/events.py
function _check_type (line 12) | def _check_type(typ):
function _add_handler (line 17) | def _add_handler(typ, handler_fn, pos):
function _remove_handler (line 29) | def _remove_handler(typ, handler_fn):
function _on_event (line 41) | def _on_event(typ, target, **kw):
function add_exception_info_handler (line 57) | def add_exception_info_handler(handler_fn, pos=None):
function remove_exception_info_handler (line 61) | def remove_exception_info_handler(handler_fn):
function add_message_handler (line 65) | def add_message_handler(handler_fn, pos=None):
function remove_message_handler (line 69) | def remove_message_handler(handler_fn):
function add_payload_handler (line 73) | def add_payload_handler(handler_fn, pos=None):
function remove_payload_handler (line 77) | def remove_payload_handler(handler_fn):
function on_exception_info (line 83) | def on_exception_info(exc_info, **kw):
function on_message (line 87) | def on_message(message, **kw):
function on_payload (line 91) | def on_payload(payload, **kw):
function reset (line 97) | def reset():
FILE: rollbar/lib/filters/__init__.py
function add_builtin_filters (line 5) | def add_builtin_filters(settings):
FILE: rollbar/lib/filters/basic.py
function filter_rollbar_ignored_exceptions (line 1) | def filter_rollbar_ignored_exceptions(exc_info, **kw):
function filter_by_level (line 9) | def filter_by_level(target, **kw):
FILE: rollbar/lib/payload.py
class Attribute (line 4) | class Attribute(TypedDict):
FILE: rollbar/lib/session.py
function set_current_session (line 13) | def set_current_session(headers: dict[str, str]) -> None:
function get_current_session (line 24) | def get_current_session() -> list[Attribute]:
function reset_current_session (line 38) | def reset_current_session() -> None:
function parse_session_request_baggage_headers (line 46) | def parse_session_request_baggage_headers(headers: dict, generate_missin...
function _build_new_scope_attributes (line 102) | def _build_new_scope_attributes() -> list[Attribute]:
function _new_scope_id (line 112) | def _new_scope_id() -> str | None:
FILE: rollbar/lib/thread_pool.py
function init_pool (line 11) | def init_pool(max_workers):
function submit (line 26) | def submit(worker, payload_str, access_token):
FILE: rollbar/lib/transform.py
class Transform (line 4) | class Transform(object):
method default (line 8) | def default(self, o, key=None):
method transform_circular_reference (line 11) | def transform_circular_reference(self, o, key=None, ref_key=None):
method transform_tuple (line 17) | def transform_tuple(self, o, key=None):
method transform_namedtuple (line 20) | def transform_namedtuple(self, o, key=None):
method transform_list (line 23) | def transform_list(self, o, key=None):
method transform_dict (line 26) | def transform_dict(self, o, key=None):
method transform_number (line 29) | def transform_number(self, o, key=None):
method transform_bytes (line 32) | def transform_bytes(self, o, key=None):
method transform_unicode (line 35) | def transform_unicode(self, o, key=None):
method transform_boolean (line 38) | def transform_boolean(self, o, key=None):
method transform_path (line 41) | def transform_path(self, o, key=None):
method transform_custom (line 44) | def transform_custom(self, o, key=None):
method rollbar_repr (line 48) | def rollbar_repr(obj: object) -> Optional[str]:
FILE: rollbar/lib/transforms/__init__.py
function transform (line 29) | def transform(obj, transforms, key=None, batch_transforms=False):
function _transform (line 44) | def _transform(obj, transform, key=None):
FILE: rollbar/lib/transforms/batched.py
function do_transform (line 8) | def do_transform(transform, type_name, val, key=None, **kw):
function string_handler (line 15) | def string_handler(transform, s, key=None):
function default_handler (line 22) | def default_handler(transform, o, key=None):
class BatchedTransform (line 63) | class BatchedTransform(Transform):
method __init__ (line 64) | def __init__(self, transforms):
method default (line 68) | def default(self, o, key=None):
FILE: rollbar/lib/transforms/scrub.py
class ScrubTransform (line 7) | class ScrubTransform(Transform):
method __init__ (line 10) | def __init__(self, suffixes=None, redact_char='*', randomize_len=True):
method in_scrub_fields (line 17) | def in_scrub_fields(self, key):
method redact (line 22) | def redact(self, val):
method default (line 33) | def default(self, o, key=None):
FILE: rollbar/lib/transforms/scrub_redact.py
class RedactRef (line 4) | class RedactRef(object):
class ScrubRedactTransform (line 11) | class ScrubRedactTransform(ScrubTransform):
method default (line 13) | def default(self, o, key=None):
FILE: rollbar/lib/transforms/scruburl.py
class ScrubUrlTransform (line 11) | class ScrubUrlTransform(ScrubTransform):
method __init__ (line 13) | def __init__(self,
method in_scrub_fields (line 28) | def in_scrub_fields(self, key):
method redact (line 33) | def redact(self, url_string):
method default (line 84) | def default(self, o, key=None):
FILE: rollbar/lib/transforms/serializable.py
class SerializableTransform (line 11) | class SerializableTransform(Transform):
method __init__ (line 13) | def __init__(self, safe_repr=True, safelist_types=None):
method transform_circular_reference (line 18) | def transform_circular_reference(self, o, key=None, ref_key=None):
method transform_namedtuple (line 21) | def transform_namedtuple(self, o, key=None):
method transform_number (line 30) | def transform_number(self, o, key=None):
method transform_bytes (line 38) | def transform_bytes(self, o, key=None):
method transform_unicode (line 46) | def transform_unicode(self, o, key=None):
method transform_dict (line 54) | def transform_dict(self, o, key=None):
method transform_custom (line 69) | def transform_custom(self, o, key=None):
FILE: rollbar/lib/transforms/shortener.py
function _max_left_right (line 29) | def _max_left_right(max_len: int, seperator_len: int) -> Tuple[int, int]:
function shorten_array (line 35) | def shorten_array(obj: array, max_len: int) -> array:
function shorten_bytes (line 42) | def shorten_bytes(obj: bytes, max_len: int) -> bytes:
function shorten_deque (line 49) | def shorten_deque(obj: collections.deque, max_len: int) -> collections.d...
function shorten_frozenset (line 56) | def shorten_frozenset(obj: frozenset, max_len: int) -> frozenset:
function shorten_int (line 63) | def shorten_int(obj: int, max_len: int) -> Union[int, str]:
function shorten_list (line 72) | def shorten_list(obj: list, max_len: int) -> list:
function shorten_mapping (line 79) | def shorten_mapping(obj: Union[dict, Mapping], max_keys: int) -> dict:
function shorten_set (line 86) | def shorten_set(obj: set, max_len: int) -> set:
function shorten_string (line 93) | def shorten_string(obj: str, max_len: int) -> str:
function shorten_tuple (line 101) | def shorten_tuple(obj: tuple, max_len: int) -> tuple:
class ShortenerTransform (line 108) | class ShortenerTransform(Transform):
method __init__ (line 112) | def __init__(self, safe_repr=True, keys=None, **sizes):
method _get_max_size (line 121) | def _get_max_size(self, obj):
method _shorten (line 133) | def _shorten(self, val):
method _shorten_other (line 161) | def _shorten_other(self, obj):
method _should_shorten (line 175) | def _should_shorten(self, val, key):
method _should_drop (line 181) | def _should_drop(self, val, key) -> bool:
method default (line 191) | def default(self, o, key=None):
FILE: rollbar/lib/transport.py
function _session (line 10) | def _session():
function _get_proxy_cfg (line 17) | def _get_proxy_cfg(kw: dict) -> Optional[dict]:
function configure_pool (line 33) | def configure_pool(**kw):
function post (line 44) | def post(*args, **kw):
function get (line 49) | def get(*args, **kw):
FILE: rollbar/lib/traverse.py
function _noop_circular (line 26) | def _noop_circular(a, **kw):
function _noop (line 30) | def _noop(a, **_):
function _noop_tuple (line 34) | def _noop_tuple(a, **_):
function _noop_namedtuple (line 38) | def _noop_namedtuple(a, **_):
function _noop_list (line 42) | def _noop_list(a, **_):
function _noop_set (line 46) | def _noop_set(a, **_):
function _noop_mapping (line 50) | def _noop_mapping(a, **_):
function _noop_path (line 53) | def _noop_path(a, **_):
function traverse (line 70) | def traverse(
FILE: rollbar/lib/type_info.py
function get_type (line 19) | def get_type(obj):
FILE: rollbar/logger.py
function resolve_logging_types (line 47) | def resolve_logging_types(obj):
class RollbarHandler (line 58) | class RollbarHandler(logging.Handler):
method __init__ (line 63) | def __init__(self,
method setLevel (line 87) | def setLevel(self, level):
method setHistoryLevel (line 95) | def setHistoryLevel(self, level):
method emit (line 103) | def emit(self, record):
method _add_history (line 190) | def _add_history(self, record, payload_data):
method _build_history_data (line 204) | def _build_history_data(self, record):
FILE: rollbar/test/__init__.py
class BaseTest (line 8) | class BaseTest(unittest.TestCase):
function discover (line 12) | def discover():
FILE: rollbar/test/asgi_tests/__init__.py
function _load_tests (line 5) | def _load_tests(loader, tests, pattern):
FILE: rollbar/test/asgi_tests/test_integration.py
class IntegrationTest (line 10) | class IntegrationTest(BaseTest):
method test_should_integrate_if__integrate_defined (line 11) | def test_should_integrate_if__integrate_defined(self):
method test_should_not_fail_if__integrate_not_exists (line 28) | def test_should_not_fail_if__integrate_not_exists(self):
FILE: rollbar/test/asgi_tests/test_middleware.py
class ReporterMiddlewareTest (line 18) | class ReporterMiddlewareTest(BaseTest):
method setUp (line 21) | def setUp(self):
method test_should_catch_and_report_errors (line 27) | def test_should_catch_and_report_errors(self, mock_report):
method test_should_add_framework_name_to_payload (line 48) | def test_should_add_framework_name_to_payload(self, mock_send_payload,...
method test_should_use_async_report_exc_info_if_default_handler (line 65) | def test_should_use_async_report_exc_info_if_default_handler(
method test_should_use_async_report_exc_info_if_any_async_handler (line 84) | def test_should_use_async_report_exc_info_if_any_async_handler(
method test_should_use_sync_report_exc_info_if_non_async_handlers (line 104) | def test_should_use_sync_report_exc_info_if_non_async_handlers(
method test_should_support_http_only (line 123) | def test_should_support_http_only(self):
method test_should_support_type_hints (line 141) | def test_should_support_type_hints(self):
FILE: rollbar/test/asgi_tests/test_spec.py
class ASGISpecTest (line 12) | class ASGISpecTest(BaseTest):
method test_asgi_v3_middleware_is_single_callable_coroutine (line 13) | def test_asgi_v3_middleware_is_single_callable_coroutine(self):
method test_asgi_v3_app_signature (line 22) | def test_asgi_v3_app_signature(self):
FILE: rollbar/test/async_tests/__init__.py
function _load_tests (line 5) | def _load_tests(loader, tests, pattern):
FILE: rollbar/test/async_tests/test_async.py
class AsyncLibTest (line 16) | class AsyncLibTest(BaseTest):
method setUp (line 19) | def setUp(self):
method test_report_exception (line 26) | def test_report_exception(self, send_payload):
method test_report_messsage (line 60) | def test_report_messsage(self, send_payload):
method test_should_run_rollbar_report_exc_info (line 77) | def test_should_run_rollbar_report_exc_info(self, rollbar_report_exc_i...
method test_should_run_rollbar_report_message (line 99) | def test_should_run_rollbar_report_message(self, rollbar_report_message):
method test_report_exc_info_should_use_async_handler_regardless_of_settings (line 110) | def test_report_exc_info_should_use_async_handler_regardless_of_settings(
method test_report_message_should_use_async_handler_regardless_of_settings (line 129) | def test_report_message_should_use_async_handler_regardless_of_settings(
method test_report_exc_info_should_allow_async_handler (line 148) | def test_report_exc_info_should_allow_async_handler(
method test_report_message_should_allow_async_handler (line 165) | def test_report_message_should_allow_async_handler(
method test_report_exc_info_should_allow_httpx_handler (line 182) | def test_report_exc_info_should_allow_httpx_handler(
method test_report_message_should_allow_httpx_handler (line 199) | def test_report_message_should_allow_httpx_handler(
method test_ctx_manager_should_use_async_handler (line 215) | def test_ctx_manager_should_use_async_handler(self, mock_log):
method test_ctx_manager_should_use_global_handler_if_contextvar_is_not_supported (line 229) | def test_ctx_manager_should_use_global_handler_if_contextvar_is_not_su...
method test_ctx_manager_should_not_substitute_global_handler (line 254) | def test_ctx_manager_should_not_substitute_global_handler(self, mock_l...
method test_report_exc_info_message_should_allow_multiple_async_handlers (line 273) | def test_report_exc_info_message_should_allow_multiple_async_handlers(
method test_report_message_should_allow_multiple_async_handlers (line 297) | def test_report_message_should_allow_multiple_async_handlers(
method test_report_exc_info_should_allow_multiple_handlers (line 320) | def test_report_exc_info_should_allow_multiple_handlers(
method test_report_message_should_allow_multiple_handlers (line 364) | def test_report_message_should_allow_multiple_handlers(
method test_report_exc_info_should_allow_multiple_handlers_with_threads (line 401) | def test_report_exc_info_should_allow_multiple_handlers_with_threads(
method test_report_message_should_allow_multiple_handlers_with_threads (line 445) | def test_report_message_should_allow_multiple_handlers_with_threads(
method test_should_try_report_with_async_handler (line 480) | def test_should_try_report_with_async_handler(self, async_report_exc_i...
method test_should_try_report_if_default_handler (line 492) | def test_should_try_report_if_default_handler(self, async_report_exc_i...
method test_should_not_try_report_with_async_handler_if_non_async_handler (line 504) | def test_should_not_try_report_with_async_handler_if_non_async_handler(
method test_try_report_should_raise_exc_if_httpx_package_is_missing (line 519) | def test_try_report_should_raise_exc_if_httpx_package_is_missing(self):
method test_should_schedule_task_in_event_loop (line 530) | def test_should_schedule_task_in_event_loop(self, ensure_future):
FILE: rollbar/test/fastapi_tests/__init__.py
function _load_tests (line 5) | def _load_tests(loader, tests, pattern):
FILE: rollbar/test/fastapi_tests/test_logger.py
class LoggerMiddlewareTest (line 25) | class LoggerMiddlewareTest(BaseTest):
method setUp (line 26) | def setUp(self):
method test_should_add_framework_version_to_payload (line 31) | def test_should_add_framework_version_to_payload(self, mock_send_paylo...
method test_should_support_type_hints (line 51) | def test_should_support_type_hints(self):
method test_should_store_current_request (line 61) | def test_should_store_current_request(self, store_current_request):
method test_should_return_current_request (line 104) | def test_should_return_current_request(self):
method test_should_not_return_current_request_for_older_python (line 130) | def test_should_not_return_current_request_for_older_python(self, mock...
FILE: rollbar/test/fastapi_tests/test_middleware.py
class ReporterMiddlewareTest (line 27) | class ReporterMiddlewareTest(BaseTest):
method setUp (line 30) | def setUp(self):
method test_should_catch_and_report_errors (line 36) | def test_should_catch_and_report_errors(self, mock_report):
method test_should_report_with_request_data (line 67) | def test_should_report_with_request_data(self, mock_report):
method test_should_send_payload_with_request_data (line 97) | def test_should_send_payload_with_request_data(self, mock_send_payload...
method test_should_add_framework_version_to_payload (line 146) | def test_should_add_framework_version_to_payload(self, mock_send_paylo...
method test_should_use_async_report_exc_info_if_default_handler (line 168) | def test_should_use_async_report_exc_info_if_default_handler(
method test_should_use_async_report_exc_info_if_any_async_handler (line 198) | def test_should_use_async_report_exc_info_if_any_async_handler(
method test_should_use_sync_report_exc_info_if_non_async_handlers (line 229) | def test_should_use_sync_report_exc_info_if_non_async_handlers(
method test_should_store_current_request (line 264) | def test_should_store_current_request(self, store_current_request):
method test_should_return_current_request (line 310) | def test_should_return_current_request(self):
method test_should_not_return_current_request_for_older_python (line 336) | def test_should_not_return_current_request_for_older_python(self, mock...
method test_should_support_http_only (line 365) | def test_should_support_http_only(self):
method test_should_support_type_hints (line 383) | def test_should_support_type_hints(self):
FILE: rollbar/test/fastapi_tests/test_routing.py
class LoggingRouteUnsupportedFastAPIVersionTest (line 30) | class LoggingRouteUnsupportedFastAPIVersionTest(BaseTest):
method test_should_disable_loading_route_handler_if_fastapi_is_too_old (line 31) | def test_should_disable_loading_route_handler_if_fastapi_is_too_old(se...
class LoggingRouteTest (line 68) | class LoggingRouteTest(BaseTest):
method setUp (line 71) | def setUp(self):
method test_should_catch_and_report_errors (line 77) | def test_should_catch_and_report_errors(self, mock_report):
method test_should_report_with_request_data (line 108) | def test_should_report_with_request_data(self, mock_report):
method test_should_send_payload_with_request_data (line 138) | def test_should_send_payload_with_request_data(self, mock_send_payload...
method test_should_send_payload_with_request_body (line 186) | def test_should_send_payload_with_request_body(self, mock_send_payload...
method test_should_send_payload_with_form_data (line 238) | def test_should_send_payload_with_form_data(self, mock_send_payload, *...
method test_should_add_framework_version_to_payload (line 288) | def test_should_add_framework_version_to_payload(self, mock_send_paylo...
method test_should_use_async_report_exc_info_if_default_handler (line 309) | def test_should_use_async_report_exc_info_if_default_handler(
method test_should_use_async_report_exc_info_if_any_async_handler (line 339) | def test_should_use_async_report_exc_info_if_any_async_handler(
method test_should_use_sync_report_exc_info_if_non_async_handlers (line 370) | def test_should_use_sync_report_exc_info_if_non_async_handlers(
method test_should_enable_loading_route_handler_if_fastapi_version_is_sufficient (line 401) | def test_should_enable_loading_route_handler_if_fastapi_version_is_suf...
method test_should_enable_loading_route_handler_before_adding_routes_to_app (line 418) | def test_should_enable_loading_route_handler_before_adding_routes_to_a...
method test_should_disable_loading_route_handler_after_adding_routes_to_app (line 442) | def test_should_disable_loading_route_handler_after_adding_routes_to_app(
method test_should_enable_loading_route_handler_before_adding_routes_to_router (line 468) | def test_should_enable_loading_route_handler_before_adding_routes_to_r...
method test_should_disable_loading_route_handler_after_adding_routes_to_router (line 501) | def test_should_disable_loading_route_handler_after_adding_routes_to_r...
method test_should_enable_loading_route_handler_for_multiple_routers (line 536) | def test_should_enable_loading_route_handler_for_multiple_routers(self):
method test_should_enable_loading_route_handler_for_fastapi_app (line 593) | def test_should_enable_loading_route_handler_for_fastapi_app(self):
method test_should_enable_loading_route_handler_for_fastapi_router (line 609) | def test_should_enable_loading_route_handler_for_fastapi_router(self):
method test_should_disable_loading_route_handler_for_unknown_app (line 626) | def test_should_disable_loading_route_handler_for_unknown_app(self, mo...
method test_should_disable_loading_route_handler_for_unknown_router (line 648) | def test_should_disable_loading_route_handler_for_unknown_router(self,...
method test_should_warn_if_middleware_in_use (line 666) | def test_should_warn_if_middleware_in_use(self):
method test_should_store_current_request (line 690) | def test_should_store_current_request(self, store_current_request):
method test_should_return_current_request (line 736) | def test_should_return_current_request(self):
method test_should_not_return_current_request_for_older_python (line 762) | def test_should_not_return_current_request_for_older_python(self, mock...
method test_should_support_type_hints (line 791) | def test_should_support_type_hints(self):
FILE: rollbar/test/fastapi_tests/test_utils.py
class UtilsMiddlewareTest (line 20) | class UtilsMiddlewareTest(BaseTest):
method test_should_return_installed_rollbar_middlewares (line 21) | def test_should_return_installed_rollbar_middlewares(self):
method test_should_return_empty_list_if_rollbar_middlewares_not_installed (line 48) | def test_should_return_empty_list_if_rollbar_middlewares_not_installed...
class UtilsBareRoutingTest (line 72) | class UtilsBareRoutingTest(BaseTest):
method test_should_return_true_if_has_bare_routing (line 73) | def test_should_return_true_if_has_bare_routing(self):
method test_should_return_false_if_user_routes_added_to_app (line 83) | def test_should_return_false_if_user_routes_added_to_app(self):
method test_should_return_false_if_user_routes_added_to_router (line 96) | def test_should_return_false_if_user_routes_added_to_router(self):
method test_should_return_false_if_router_added_to_app (line 109) | def test_should_return_false_if_router_added_to_app(self):
method test_should_return_true_if_docs_disabled (line 125) | def test_should_return_true_if_docs_disabled(self):
class UtilsVersionCompareTest (line 144) | class UtilsVersionCompareTest(BaseTest):
method test_is_current_version_higher_or_equal (line 145) | def test_is_current_version_higher_or_equal(self):
FILE: rollbar/test/flask_tests/test_flask.py
function create_app (line 29) | def create_app():
function init_rollbar (line 51) | def init_rollbar(app):
class FlaskTest (line 62) | class FlaskTest(BaseTest):
method setUp (line 63) | def setUp(self):
method test_index (line 70) | def test_index(self):
method assertStringEqual (line 74) | def assertStringEqual(self, left, right):
method test_uncaught (line 86) | def test_uncaught(self, send_payload):
method test_uncaught_baggage_header (line 120) | def test_uncaught_baggage_header(self, send_payload):
method test_uncaught_json_request (line 140) | def test_uncaught_json_request(self, send_payload):
method test_uncaught_no_username_no_email (line 168) | def test_uncaught_no_username_no_email(self, send_payload):
method test_uncaught_no_body (line 207) | def test_uncaught_no_body(self, send_payload):
FILE: rollbar/test/starlette_tests/__init__.py
function _load_tests (line 5) | def _load_tests(loader, tests, pattern):
FILE: rollbar/test/starlette_tests/test_logger.py
class LoggerMiddlewareTest (line 25) | class LoggerMiddlewareTest(BaseTest):
method setUp (line 26) | def setUp(self):
method test_should_add_framework_version_to_payload (line 31) | def test_should_add_framework_version_to_payload(self, mock_send_paylo...
method test_should_support_type_hints (line 51) | def test_should_support_type_hints(self):
method test_should_store_current_request (line 61) | def test_should_store_current_request(self, store_current_request):
method test_should_return_current_request (line 101) | def test_should_return_current_request(self):
method test_should_not_return_current_request_for_older_python (line 122) | def test_should_not_return_current_request_for_older_python(self, mock...
FILE: rollbar/test/starlette_tests/test_middleware.py
class ReporterMiddlewareTest (line 27) | class ReporterMiddlewareTest(BaseTest):
method setUp (line 30) | def setUp(self):
method test_should_catch_and_report_errors (line 36) | def test_should_catch_and_report_errors(self, mock_report):
method test_should_report_with_request_data (line 63) | def test_should_report_with_request_data(self, mock_report):
method test_should_send_payload_with_request_data (line 88) | def test_should_send_payload_with_request_data(self, mock_send_payload...
method test_should_add_framework_version_to_payload (line 132) | def test_should_add_framework_version_to_payload(self, mock_send_paylo...
method test_should_use_async_report_exc_info_if_default_handler (line 154) | def test_should_use_async_report_exc_info_if_default_handler(
method test_should_use_async_report_exc_info_if_any_async_handler (line 180) | def test_should_use_async_report_exc_info_if_any_async_handler(
method test_should_use_sync_report_exc_info_if_non_async_handlers (line 207) | def test_should_use_sync_report_exc_info_if_non_async_handlers(
method test_should_store_current_request (line 238) | def test_should_store_current_request(self, store_current_request):
method test_should_return_current_request (line 281) | def test_should_return_current_request(self):
method test_should_not_return_current_request_for_older_python (line 304) | def test_should_not_return_current_request_for_older_python(self, mock...
method test_should_support_http_only (line 330) | def test_should_support_http_only(self):
method test_should_support_type_hints (line 348) | def test_should_support_type_hints(self):
FILE: rollbar/test/starlette_tests/test_requests.py
class RequestTest (line 22) | class RequestTest(BaseTest):
method test_should_accept_request_param (line 23) | def test_should_accept_request_param(self):
method test_should_accept_scope_param_if_http_type (line 55) | def test_should_accept_scope_param_if_http_type(self):
method test_should_not_accept_scope_param_if_not_http_type (line 87) | def test_should_not_accept_scope_param_if_not_http_type(self):
method test_hasuser (line 97) | def test_hasuser(self):
FILE: rollbar/test/test_basic_filters.py
class BasicFiltersTest (line 6) | class BasicFiltersTest(BaseTest):
method setUp (line 7) | def setUp(self):
method test_rollbar_ignored_exception (line 11) | def test_rollbar_ignored_exception(self):
method test_filter_by_level (line 21) | def test_filter_by_level(self):
FILE: rollbar/test/test_batched_transform.py
class TrackingTransformer (line 8) | class TrackingTransformer(Transform):
method __init__ (line 9) | def __init__(self):
method default (line 12) | def default(self, o, key=None):
class BatchedTransformTest (line 17) | class BatchedTransformTest(BaseTest):
method assertTrackingTransform (line 18) | def assertTrackingTransform(self, input):
method test_number (line 49) | def test_number(self):
method test_flat_list (line 52) | def test_flat_list(self):
method test_flat_tuple (line 55) | def test_flat_tuple(self):
method test_nested_object (line 58) | def test_nested_object(self):
FILE: rollbar/test/test_custom_filters.py
class CustomFiltersTest (line 8) | class CustomFiltersTest(BaseTest):
method setUp (line 9) | def setUp(self):
method test_ignore_by_setting_rollbar_ignore (line 13) | def test_ignore_by_setting_rollbar_ignore(self):
method test_ignore_messages_by_regex (line 29) | def test_ignore_messages_by_regex(self):
method test_modify_payload (line 43) | def test_modify_payload(self):
FILE: rollbar/test/test_lib.py
class RollbarLibTest (line 7) | class RollbarLibTest(BaseTest):
method test_prefix_match (line 8) | def test_prefix_match(self):
method test_prefix_match_dont_match (line 12) | def test_prefix_match_dont_match(self):
method test_key_match (line 16) | def test_key_match(self):
method test_key_match_dont_match (line 22) | def test_key_match_dont_match(self):
method test_key_match_wildcard_end (line 28) | def test_key_match_wildcard_end(self):
method test_key_match_too_short (line 34) | def test_key_match_too_short(self):
method test_key_depth (line 40) | def test_key_depth(self):
method test_key_depth_dont_match (line 46) | def test_key_depth_dont_match(self):
method test_key_depth_wildcard_end (line 52) | def test_key_depth_wildcard_end(self):
method test_dict_merge_not_dict (line 58) | def test_dict_merge_not_dict(self):
method test_dict_merge_dicts_independent (line 65) | def test_dict_merge_dicts_independent(self):
method test_dict_merge_dicts (line 77) | def test_dict_merge_dicts(self):
method test_dict_merge_dicts_second_wins (line 88) | def test_dict_merge_dicts_second_wins(self):
method test_dict_merge_dicts_select_poll (line 97) | def test_dict_merge_dicts_select_poll(self):
method test_transport_get_proxy_cfg (line 113) | def test_transport_get_proxy_cfg(self):
FILE: rollbar/test/test_loghandler.py
class CauseException (line 21) | class CauseException(Exception):
class LogHandlerTest (line 25) | class LogHandlerTest(BaseTest):
method setUp (line 26) | def setUp(self):
method tearDown (line 37) | def tearDown(self):
method test_message_gets_formatted (line 41) | def test_message_gets_formatted(self, send_payload):
method test_string_or_int_level (line 53) | def test_string_or_int_level(self, send_payload):
method test_request_is_get_from_log_record_if_present (line 67) | def test_request_is_get_from_log_record_if_present(self):
method test_nested_exception_trace_chain (line 98) | def test_nested_exception_trace_chain(self, send_payload):
method test_not_nested_exception_trace_chain (line 135) | def test_not_nested_exception_trace_chain(self, send_payload):
method test_logging_extra (line 162) | def test_logging_extra(self, send_payload):
method test_logging_extra_data (line 172) | def test_logging_extra_data(self, send_payload):
method test_log_formatting (line 184) | def test_log_formatting(self, send_payload):
FILE: rollbar/test/test_pyramid.py
class PyramidMiddlewareTest (line 15) | class PyramidMiddlewareTest(BaseTest):
method test_catch_exception_in_the_wsgi_app (line 16) | def test_catch_exception_in_the_wsgi_app(self):
FILE: rollbar/test/test_rollbar.py
class RollbarTest (line 45) | class RollbarTest(BaseTest):
method setUp (line 46) | def setUp(self):
method test_merged_settings (line 52) | def test_merged_settings(self):
method test_default_configuration (line 58) | def test_default_configuration(self):
method test_disabled (line 63) | def test_disabled(self, send_payload):
method test_server_data (line 74) | def test_server_data(self):
method test_wsgi_request_data (line 94) | def test_wsgi_request_data(self):
method test_wsgi_request_data_no_body (line 128) | def test_wsgi_request_data_no_body(self):
method test_starlette_request_data (line 142) | def test_starlette_request_data(self):
method test_starlette_request_baggage_headers (line 189) | def test_starlette_request_baggage_headers(self):
method test_starlette_request_data_with_consumed_body (line 229) | def test_starlette_request_data_with_consumed_body(self):
method test_starlette_request_data_empty_values (line 261) | def test_starlette_request_data_empty_values(self):
method test_fastapi_request_data (line 288) | def test_fastapi_request_data(self):
method test_fastapi_request_baggage_headers (line 335) | def test_fastapi_request_baggage_headers(self):
method test_fastapi_request_data_with_consumed_body (line 375) | def test_fastapi_request_data_with_consumed_body(self):
method test_fastapi_request_data_empty_values (line 406) | def test_fastapi_request_data_empty_values(self):
method test_django_build_person_data (line 433) | def test_django_build_person_data(self):
method test_django_baggage_headers (line 463) | def test_django_baggage_headers(self):
method test_starlette_build_person_data_if_user_authenticated (line 494) | def test_starlette_build_person_data_if_user_authenticated(self):
method test_starlette_failsafe_build_person_data_if_user_not_authenticated (line 523) | def test_starlette_failsafe_build_person_data_if_user_not_authenticate...
method test_get_request_starlette_middleware (line 537) | def test_get_request_starlette_middleware(self):
method test_get_request_starlette_logger (line 564) | def test_get_request_starlette_logger(self):
method test_get_request_fastapi_middleware (line 591) | def test_get_request_fastapi_middleware(self):
method test_get_request_fastapi_logger (line 618) | def test_get_request_fastapi_logger(self):
method test_get_request_fastapi_router (line 645) | def test_get_request_fastapi_router(self):
method test_report_exception (line 676) | def test_report_exception(self, send_payload):
method test_lambda_function_good (line 704) | def test_lambda_function_good(self, _post_api):
method test_lambda_function_bad (line 723) | def test_lambda_function_bad(self, _post_api):
method test_lambda_function_method_good (line 744) | def test_lambda_function_method_good(self, _post_api):
method test_lambda_function_method_bad (line 770) | def test_lambda_function_method_bad(self, _post_api):
method test_report_exception_with_cause (line 798) | def test_report_exception_with_cause(self, send_payload):
method test_report_exception_with_same_exception_as_cause (line 844) | def test_report_exception_with_same_exception_as_cause(self, send_payl...
method test_report_exception_with_context (line 905) | def test_report_exception_with_context(self, send_payload):
method test_exception_filters (line 950) | def test_exception_filters(self, send_payload):
method test_report_messsage (line 986) | def test_report_messsage(self, send_payload):
method test_uuid (line 1000) | def test_uuid(self, send_payload):
method test_report_exc_info_level (line 1008) | def test_report_exc_info_level(self, send_payload):
method test_report_exc_info_nones (line 1039) | def test_report_exc_info_nones(self, send_payload):
method test_trigger_failsafe (line 1050) | def test_trigger_failsafe(self, post, _send_failsafe):
method test_502_failsafe (line 1069) | def test_502_failsafe(self, post, _send_failsafe):
method test_send_failsafe (line 1079) | def test_send_failsafe(self, send_payload):
method test_fail_to_send_failsafe (line 1110) | def test_fail_to_send_failsafe(self, send_payload, mock_log):
method test_async_handler (line 1118) | def test_async_handler(self, send_payload_async):
method test_httpx_handler (line 1132) | def test_httpx_handler(self, send_payload_httpx):
method test_thread_pool_handler (line 1146) | def test_thread_pool_handler(self, send_payload_thread_pool):
method test_thread_pool_submit (line 1158) | def test_thread_pool_submit(self):
method test_args_constructor (line 1171) | def test_args_constructor(self, send_payload):
method test_failed_locals_serialization (line 1195) | def test_failed_locals_serialization(self, send_payload):
method test_args_lambda_no_args (line 1211) | def test_args_lambda_no_args(self, send_payload):
method test_args_lambda_with_args (line 1230) | def test_args_lambda_with_args(self, send_payload):
method test_args_lambda_with_defaults (line 1254) | def test_args_lambda_with_defaults(self, send_payload):
method test_args_lambda_with_star_args (line 1278) | def test_args_lambda_with_star_args(self, send_payload):
method test_args_lambda_with_star_args_and_args (line 1301) | def test_args_lambda_with_star_args_and_args(self, send_payload):
method test_args_lambda_with_kwargs (line 1329) | def test_args_lambda_with_kwargs(self, send_payload):
method test_args_lambda_with_kwargs_and_args (line 1353) | def test_args_lambda_with_kwargs_and_args(self, send_payload):
method test_args_lambda_with_kwargs_and_args_and_defaults (line 1383) | def test_args_lambda_with_kwargs_and_args_and_defaults(self, send_payl...
method test_args_generators (line 1416) | def test_args_generators(self, send_payload):
method test_anonymous_tuple_args (line 1443) | def test_anonymous_tuple_args(self, send_payload):
method test_scrub_defaults (line 1470) | def test_scrub_defaults(self, send_payload):
method test_dont_scrub_star_args (line 1497) | def test_dont_scrub_star_args(self, send_payload):
method test_scrub_kwargs (line 1524) | def test_scrub_kwargs(self, send_payload):
method test_scrub_locals (line 1551) | def test_scrub_locals(self, send_payload):
method test_scrub_namedtuple (line 1585) | def test_scrub_namedtuple(self, send_payload):
method test_scrub_nans (line 1608) | def test_scrub_nans(self, send_payload):
method test_scrub_self_referencing (line 1629) | def test_scrub_self_referencing(self, send_payload):
method test_scrub_local_ref (line 1671) | def test_scrub_local_ref(self, send_payload):
method test_large_arg_val (line 1694) | def test_large_arg_val(self, send_payload):
method test_long_list_arg_val (line 1719) | def test_long_list_arg_val(self, send_payload):
method test_last_frame_has_locals (line 1756) | def test_last_frame_has_locals(self, send_payload):
method test_all_project_frames_have_locals (line 1782) | def test_all_project_frames_have_locals(self, send_payload):
method test_only_last_frame_has_locals (line 1801) | def test_only_last_frame_has_locals(self, send_payload):
method test_modify_arg (line 1825) | def test_modify_arg(self, send_payload):
method test_unicode_exc_info (line 1847) | def test_unicode_exc_info(self, send_payload):
method test_serialize_and_send_payload (line 1860) | def test_serialize_and_send_payload(self, post=None):
method test_scrub_webob_request_data (line 1892) | def test_scrub_webob_request_data(self):
method test_filter_ip_no_user_ip (line 1931) | def test_filter_ip_no_user_ip(self):
method test_filter_ip_capture_true (line 1936) | def test_filter_ip_capture_true(self):
method test_filter_ip_anonymize (line 1942) | def test_filter_ip_anonymize(self):
method test_filter_ip_capture_false (line 1949) | def test_filter_ip_capture_false(self):
method test_filter_ip_ipv6_capture_false (line 1956) | def test_filter_ip_ipv6_capture_false(self):
method test_filter_ip_anonymize_ipv6 (line 1963) | def test_filter_ip_anonymize_ipv6(self):
method test_starlette_extract_user_ip_from_client_host (line 1975) | def test_starlette_extract_user_ip_from_client_host(self):
method test_starlette_extract_user_ip_from_headers (line 1998) | def test_starlette_extract_user_ip_from_headers(self):
method test_root_path (line 2032) | def test_root_path(self, send_payload):
function step1 (line 2050) | def step1():
function step2 (line 2055) | def step2():
function called_with (line 2060) | def called_with(arg1):
class CauseException (line 2065) | class CauseException(Exception):
class MockResponse (line 2069) | class MockResponse:
method __init__ (line 2070) | def __init__(self, json_data, status_code):
method content (line 2075) | def content(self):
method json (line 2078) | def json(self):
class MockRawResponse (line 2082) | class MockRawResponse:
method __init__ (line 2083) | def __init__(self, data, status_code):
method content (line 2088) | def content(self):
method json (line 2091) | def json(self):
class MockLambdaContext (line 2095) | class MockLambdaContext(object):
method __init__ (line 2096) | def __init__(self, x):
method get_remaining_time_in_millis (line 2103) | def get_remaining_time_in_millis(self):
function fastapi_add_route_with_request_param (line 2107) | def fastapi_add_route_with_request_param(app, endpoint, path, request_pa...
FILE: rollbar/test/test_scrub_redact_transform.py
class NotRedactRef (line 9) | class NotRedactRef():
class ScrubRedactTransformTest (line 20) | class ScrubRedactTransformTest(BaseTest):
method _assertScrubbed (line 21) | def _assertScrubbed(self, start, expected, redact_char='*', skip_id_ch...
method test_no_scrub (line 41) | def test_no_scrub(self):
method test_scrub (line 46) | def test_scrub(self):
method test_scrub_list (line 51) | def test_scrub_list(self):
method test_scrub_set (line 56) | def test_scrub_set(self):
method test_scrub_tuple (line 61) | def test_scrub_tuple(self):
method test_scrub_namedtuple (line 66) | def test_scrub_namedtuple(self):
method test_scrub_dict (line 73) | def test_scrub_dict(self):
FILE: rollbar/test/test_scrub_transform.py
class ScrubTransformTest (line 11) | class ScrubTransformTest(BaseTest):
method _assertScrubbed (line 12) | def _assertScrubbed(self, suffixes, start, expected, redact_char='*', ...
method test_string (line 36) | def test_string(self):
method test_num (line 44) | def test_num(self):
method test_None (line 49) | def test_None(self):
method test_list_of_None (line 54) | def test_list_of_None(self):
method test_no_suffixes (line 59) | def test_no_suffixes(self):
method test_scrub_named_tuple (line 64) | def test_scrub_named_tuple(self):
method test_scrub_named_tuple_in_list (line 71) | def test_scrub_named_tuple_in_list(self):
method test_scrub_simple_dict (line 78) | def test_scrub_simple_dict(self):
method test_scrub_dict_in_list (line 84) | def test_scrub_dict_in_list(self):
method test_scrub_dict_in_tuple (line 90) | def test_scrub_dict_in_tuple(self):
method test_scrub_dict_in_dict (line 96) | def test_scrub_dict_in_dict(self):
method test_scrub_multiple_suffixes (line 102) | def test_scrub_multiple_suffixes(self):
method test_scrub_no_suffix_match (line 109) | def test_scrub_no_suffix_match(self):
method test_scrub_full_dict (line 114) | def test_scrub_full_dict(self):
method test_scrub_full_list (line 120) | def test_scrub_full_list(self):
method test_scrub_full_dict_with_nested_secret (line 126) | def test_scrub_full_dict_with_nested_secret(self):
method test_scrub_one_secret_and_one_clear_reference (line 132) | def test_scrub_one_secret_and_one_clear_reference(self):
method test_scrub_circular (line 139) | def test_scrub_circular(self):
method test_circular (line 157) | def test_circular(self):
method test_unicode_keys (line 170) | def test_unicode_keys(self):
method test_scrub_unicode_keys (line 177) | def test_scrub_unicode_keys(self):
method test_scrub_unicode_values (line 186) | def test_scrub_unicode_values(self):
FILE: rollbar/test/test_scruburl_transform.py
class ScrubUrlTransformTest (line 12) | class ScrubUrlTransformTest(BaseTest):
method _assertScrubbed (line 13) | def _assertScrubbed(self,
method _compare_urls (line 36) | def _compare_urls(self, url1, url2):
method test_no_scrub (line 56) | def test_no_scrub(self):
method test_not_url (line 61) | def test_not_url(self):
method test_scrub_simple_url_params (line 66) | def test_scrub_simple_url_params(self):
method test_scrub_utf8_url_params (line 71) | def test_scrub_utf8_url_params(self):
method test_scrub_utf8_url_keys (line 76) | def test_scrub_utf8_url_keys(self):
method test_scrub_multi_url_params (line 81) | def test_scrub_multi_url_params(self):
method test_scrub_password_auth (line 86) | def test_scrub_password_auth(self):
method test_scrub_username_auth (line 91) | def test_scrub_username_auth(self):
method test_scrub_username_and_password_auth (line 96) | def test_scrub_username_and_password_auth(self):
method test_scrub_missing_scheme (line 101) | def test_scrub_missing_scheme(self):
method test_scrub_missing_scheme_and_double_slash (line 106) | def test_scrub_missing_scheme_and_double_slash(self):
method test_keep_blank_url_params (line 111) | def test_keep_blank_url_params(self):
method test_scrub_dict_val_isnt_string (line 116) | def test_scrub_dict_val_isnt_string(self):
method test_scrub_dict_nested_key_match_with_circular_ref (line 131) | def test_scrub_dict_nested_key_match_with_circular_ref(self):
FILE: rollbar/test/test_serializable_transform.py
class SerializableTransformTest (line 25) | class SerializableTransformTest(BaseTest):
method _assertSerialized (line 26) | def _assertSerialized(self, start, expected, safe_repr=True, safelist=...
method test_simple_dict (line 50) | def test_simple_dict(self):
method test_enum (line 58) | def test_enum(self):
method test_enum_no_safe_repr (line 67) | def test_enum_no_safe_repr(self):
method test_int_enum (line 76) | def test_int_enum(self):
method test_int_enum_no_safe_repr (line 85) | def test_int_enum_no_safe_repr(self):
method test_encode_dict_with_invalid_utf8 (line 94) | def test_encode_dict_with_invalid_utf8(self):
method test_encode_utf8 (line 102) | def test_encode_utf8(self):
method test_encode_None (line 107) | def test_encode_None(self):
method test_encode_float (line 112) | def test_encode_float(self):
method test_encode_float_nan (line 117) | def test_encode_float_nan(self):
method test_encode_float_infinity (line 122) | def test_encode_float_infinity(self):
method test_encode_float_neg_infinity (line 127) | def test_encode_float_neg_infinity(self):
method test_encode_int (line 132) | def test_encode_int(self):
method test_encode_empty_tuple (line 137) | def test_encode_empty_tuple(self):
method test_encode_empty_list (line 148) | def test_encode_empty_list(self):
method test_encode_empty_dict (line 153) | def test_encode_empty_dict(self):
method test_encode_namedtuple (line 158) | def test_encode_namedtuple(self):
method test_encode_tuple_with_bytes (line 167) | def test_encode_tuple_with_bytes(self):
method test_encode_list_with_bytes (line 173) | def test_encode_list_with_bytes(self):
method test_encode_dict_with_bytes (line 179) | def test_encode_dict_with_bytes(self):
method test_encode_dict_with_bytes_key (line 185) | def test_encode_dict_with_bytes_key(self):
method test_encode_with_rollbar_repr (line 192) | def test_encode_with_rollbar_repr(self):
method test_encode_with_custom_repr_no_safelist (line 202) | def test_encode_with_custom_repr_no_safelist(self):
method test_encode_with_custom_repr_no_safelist_no_safe_repr (line 212) | def test_encode_with_custom_repr_no_safelist_no_safe_repr(self):
method test_encode_with_custom_repr_safelist (line 222) | def test_encode_with_custom_repr_safelist(self):
method test_encode_with_custom_repr_returns_bytes (line 232) | def test_encode_with_custom_repr_returns_bytes(self):
method test_encode_with_custom_repr_returns_object (line 244) | def test_encode_with_custom_repr_returns_object(self):
method test_encode_with_custom_repr_returns_unicode (line 255) | def test_encode_with_custom_repr_returns_unicode(self):
method test_encode_with_bad_repr_doesnt_die (line 265) | def test_encode_with_bad_repr_doesnt_die(self):
method test_encode_with_bad_str_doesnt_die (line 275) | def test_encode_with_bad_str_doesnt_die(self):
FILE: rollbar/test/test_session.py
class SessionTest (line 9) | class SessionTest(BaseTest):
method test_session_threading (line 10) | def test_session_threading(self):
method test_parse_session_request_baggage_headers (line 45) | def test_parse_session_request_baggage_headers(self):
method test_parse_session_request_baggage_headers_lower (line 55) | def test_parse_session_request_baggage_headers_lower(self):
method test_parse_session_request_baggage_headers_scope_only (line 64) | def test_parse_session_request_baggage_headers_scope_only(self):
method test_parse_session_request_baggage_headers_empty (line 73) | def test_parse_session_request_baggage_headers_empty(self):
method test_parse_session_request_baggage_headers_empty_generate (line 80) | def test_parse_session_request_baggage_headers_empty_generate(self):
method test_parse_session_request_baggage_headers_other (line 90) | def test_parse_session_request_baggage_headers_other(self):
method test_parse_session_request_baggage_headers_other_generate (line 97) | def test_parse_session_request_baggage_headers_other_generate(self):
method test_build_new_session_attributes (line 107) | def test_build_new_session_attributes(self):
method test_new_session_id (line 113) | def test_new_session_id(self):
class TestSessionAsync (line 118) | class TestSessionAsync(unittest.IsolatedAsyncioTestCase):
method test_session_async (line 123) | async def test_session_async(self):
FILE: rollbar/test/test_shortener_transform.py
class TestClassWithAVeryVeryVeryVeryVeryVeryVeryLongName (line 11) | class TestClassWithAVeryVeryVeryVeryVeryVeryVeryLongName:
class KeyMemShortenerTransform (line 15) | class KeyMemShortenerTransform(ShortenerTransform):
method default (line 21) | def default(self, o, key=None):
class ShortenerTransformTest (line 26) | class ShortenerTransformTest(BaseTest):
method setUp (line 27) | def setUp(self):
method test_shorten_string (line 30) | def test_shorten_string(self):
method test_shorten_long (line 36) | def test_shorten_long(self):
method test_shorten_mapping (line 42) | def test_shorten_mapping(self):
method test_shorten_bytes (line 71) | def test_shorten_bytes(self):
method test_shorten_list (line 77) | def test_shorten_list(self):
method test_shorten_tuple (line 83) | def test_shorten_tuple(self):
method test_shorten_set (line 89) | def test_shorten_set(self):
method test_shorten_frozenset (line 95) | def test_shorten_frozenset(self):
method test_shorten_array (line 101) | def test_shorten_array(self):
method test_shorten_deque (line 107) | def test_shorten_deque(self):
method test_shorten_other (line 113) | def test_shorten_other(self):
method test_shorten_object (line 119) | def test_shorten_object(self):
method test_shorten_custom_rollbar_repr (line 133) | def test_shorten_custom_rollbar_repr(self):
method test_shorten_frame (line 146) | def test_shorten_frame(self):
method test_breadth_first (line 240) | def test_breadth_first(self):
FILE: rollbar/test/test_transform.py
class TransformTest (line 16) | class TransformTest(BaseTest):
method setUp (line 17) | def setUp(self):
method test_default_transforms (line 22) | def test_default_transforms(self):
method test_add_custom_transform (line 32) | def test_add_custom_transform(self):
method test_add_custom_transform_first (line 64) | def test_add_custom_transform_first(self):
FILE: rollbar/test/test_traverse.py
class NamedTuple (line 7) | class NamedTuple(tuple):
method __new__ (line 12) | def __new__(cls, vals, labels=None):
method keys (line 19) | def keys(self):
class KeyMemTransform (line 23) | class KeyMemTransform(Transform):
method default (line 29) | def default(self, o, key=None):
class RollbarTraverseTest (line 34) | class RollbarTraverseTest(BaseTest):
method setUp (line 41) | def setUp(self):
method test_base_case (line 44) | def test_base_case(self):
method test_bad_object (line 47) | def test_bad_object(self):
method test_depth_first (line 51) | def test_depth_first(self):
method test_breadth_first (line 107) | def test_breadth_first(self):
FILE: rollbar/test/twisted_tests/test_twisted.py
class SquareProtocol (line 28) | class SquareProtocol(protocol.Protocol):
method dataReceived (line 29) | def dataReceived(self, data):
class SquareFactory (line 38) | class SquareFactory(protocol.Factory):
class TwistedTest (line 41) | class TwistedTest(unittest.TestCase):
method setUp (line 42) | def setUp(self):
method test_base_case (line 50) | def test_base_case(self, send_payload):
method test_caught_exception (line 57) | def test_caught_exception(self, send_payload):
FILE: rollbar/test/utils.py
function get_public_attrs (line 3) | def get_public_attrs(obj: Mapping) -> dict:
Condensed preview — 104 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (498K chars).
[
{
"path": ".flake8",
"chars": 68,
"preview": "[flake8]\nmax-line-length = 100\nmax-complexity = 10\nexclude = test/*\n"
},
{
"path": ".github/pull_request_template.md",
"chars": 1097,
"preview": "## Description of the change\n\n> Please include a summary of the change and which issues are fixed.\n> Please also include"
},
{
"path": ".github/workflows/ci.yml",
"chars": 2230,
"preview": "name: Pyrollbar CI\n\non:\n push:\n branches: [ master ]\n tags: [ v* ]\n pull_request:\n branches: [ master ]\n\njobs"
},
{
"path": ".gitignore",
"chars": 137,
"preview": "*.pyc\n*.swp\n*.swo\ndist/\nbuild/\nrollbar.egg-info/\n*.egg\n.eggs/\n.idea/\n*~\nPipfile\nPipfile.lock\n.pytest_cache/\n.python-vers"
},
{
"path": "CHANGELOG.md",
"chars": 27242,
"preview": "# Change Log\n\nThe change log is also available on the [GitHub Releases Page](https://github.com/rollbar/pyrollbar/releas"
},
{
"path": "LICENSE",
"chars": 1057,
"preview": "Copyright (c) 2014 Rollbar, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this s"
},
{
"path": "README.md",
"chars": 4748,
"preview": "<p align=\"center\">\n <img alt=\"rollbar-logo\" src=\"https://user-images.githubusercontent.com/3300063/207964480-54eda665-d"
},
{
"path": "THANKS.md",
"chars": 774,
"preview": "# Contributors\n\nHuge thanks to the following contributors (by github username). For the most up-to-date list, see https:"
},
{
"path": "pyproject.toml",
"chars": 2396,
"preview": "[build-system]\nrequires = [\"setuptools>=61.0\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"rollbar\"\ndynam"
},
{
"path": "rollbar/__init__.py",
"chars": 58653,
"preview": "from __future__ import absolute_import, annotations\nfrom __future__ import unicode_literals\n\nimport copy\nimport functool"
},
{
"path": "rollbar/cli.py",
"chars": 3113,
"preview": "import optparse\nimport sys\n\nimport rollbar\n\nVERSION = '0.1'\n\nverbose = False\n\ndef _gen_report_message(level):\n def _w"
},
{
"path": "rollbar/contrib/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "rollbar/contrib/asgi/__init__.py",
"chars": 77,
"preview": "__all__ = ['ReporterMiddleware']\n\nfrom .middleware import ReporterMiddleware\n"
},
{
"path": "rollbar/contrib/asgi/integration.py",
"chars": 990,
"preview": "import inspect\nimport functools\n\nimport rollbar\n\n\nclass IntegrationBase:\n \"\"\"\n Superclass for class integrations.\n"
},
{
"path": "rollbar/contrib/asgi/middleware.py",
"chars": 1695,
"preview": "import logging\nimport sys\nfrom typing import Iterable\n\nimport rollbar\nfrom .integration import IntegrationBase, integrat"
},
{
"path": "rollbar/contrib/asgi/types.py",
"chars": 1869,
"preview": "# Copyright © 2018, [Encode OSS Ltd](https://www.encode.io/).\n# All rights reserved.\n#\n# Redistribution and use in sourc"
},
{
"path": "rollbar/contrib/bottle/__init__.py",
"chars": 1096,
"preview": "import bottle, rollbar, sys\n\nclass RollbarBottleReporter(object):\n '''\n A Bottle plugin that reports errors to Rol"
},
{
"path": "rollbar/contrib/django/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "rollbar/contrib/django/context_processors.py",
"chars": 696,
"preview": "\"\"\"\ndjango-rollbar context processor\n\nTo install, add the following in your settings.py:\n1. add 'rollbar.contrib.django."
},
{
"path": "rollbar/contrib/django/middleware.py",
"chars": 13259,
"preview": "r\"\"\"\ndjango-rollbar middleware\n\nThere are two options for installing the Rollbar middleware. Both options\nrequire modify"
},
{
"path": "rollbar/contrib/django/models.py",
"chars": 106,
"preview": "\"\"\"\nNo models - this file is here so django recognizes this as an application for running unit tests.\n\"\"\"\n"
},
{
"path": "rollbar/contrib/django/tests.py",
"chars": 460,
"preview": "\"\"\"\nUnit tests\n\"\"\"\nfrom django.test import TestCase\nfrom django.conf import settings\n\nclass BasicTests(TestCase):\n de"
},
{
"path": "rollbar/contrib/django/utils.py",
"chars": 122,
"preview": "class MiddlewareMixin(object):\n def __init__(self, get_response=None):\n super(MiddlewareMixin, self).__init__("
},
{
"path": "rollbar/contrib/django_rest_framework/__init__.py",
"chars": 996,
"preview": "try:\n from django.core.exceptions import ImproperlyConfigured\nexcept ImportError:\n ImproperlyConfigured = RuntimeE"
},
{
"path": "rollbar/contrib/fastapi/__init__.py",
"chars": 536,
"preview": "__all__ = ['add_to', 'ReporterMiddleware', 'LoggerMiddleware', 'get_current_request']\n\n# Optional requirements:\n#\n# - Fa"
},
{
"path": "rollbar/contrib/fastapi/logger.py",
"chars": 317,
"preview": "__all__ = ['LoggerMiddleware']\n\nfrom fastapi import __version__\n\nfrom rollbar.contrib.asgi.integration import integrate\n"
},
{
"path": "rollbar/contrib/fastapi/middleware.py",
"chars": 327,
"preview": "__all__ = ['ReporterMiddleware']\n\nfrom fastapi import __version__\n\nfrom rollbar.contrib.asgi.integration import integrat"
},
{
"path": "rollbar/contrib/fastapi/routing.py",
"chars": 3593,
"preview": "__all__ = ['add_to']\n\nimport logging\nimport sys\nfrom typing import Callable, Optional, Type, Union\n\nfrom fastapi import "
},
{
"path": "rollbar/contrib/fastapi/utils.py",
"chars": 3416,
"preview": "import functools\nimport logging\nfrom typing import Union\n\nimport fastapi\nfrom fastapi import APIRouter, FastAPI\n\nfrom . "
},
{
"path": "rollbar/contrib/flask/__init__.py",
"chars": 1153,
"preview": "\"\"\"\nIntegration with Flask\n\"\"\"\n\nfrom flask import request, got_request_exception, Flask\nimport rollbar\nfrom rollbar.lib."
},
{
"path": "rollbar/contrib/pyramid/__init__.py",
"chars": 5647,
"preview": "\"\"\"\nPlugin for Pyramid apps to submit errors to Rollbar\n\"\"\"\n\nimport logging\nimport sys\n\nfrom pyramid.httpexceptions impo"
},
{
"path": "rollbar/contrib/quart/__init__.py",
"chars": 315,
"preview": "\"\"\"\nIntegration with Quart\n\"\"\"\n\nfrom quart import request\nimport rollbar\n\n\ndef report_exception(app, exception):\n rol"
},
{
"path": "rollbar/contrib/rq/__init__.py",
"chars": 1668,
"preview": "\"\"\"\nException handler hook for RQ (http://python-rq.org/)\n\nHow to use: \n\n1. Instead of using the default \"rqworker\" scri"
},
{
"path": "rollbar/contrib/starlette/__init__.py",
"chars": 484,
"preview": "__all__ = ['ReporterMiddleware', 'LoggerMiddleware', 'get_current_request']\n\n# Optional requirements:\n#\n# - Starlette re"
},
{
"path": "rollbar/contrib/starlette/logger.py",
"chars": 1056,
"preview": "__all__ = ['LoggerMiddleware']\n\nimport logging\nimport sys\n\nfrom starlette import __version__\nfrom starlette.types import"
},
{
"path": "rollbar/contrib/starlette/middleware.py",
"chars": 1969,
"preview": "import logging\nimport sys\n\nfrom starlette import __version__\nfrom starlette.requests import Request\nfrom starlette.types"
},
{
"path": "rollbar/contrib/starlette/requests.py",
"chars": 1755,
"preview": "__all__ = ['get_current_request']\n\nimport logging\nimport sys\nfrom typing import Optional, Union\n\nfrom starlette.requests"
},
{
"path": "rollbar/examples/asgi/app.py",
"chars": 1900,
"preview": "#!/usr/bin/env python\n\n# ASGI middleware is ASGI v3 compliant. It can integrate with any\n# ASGIv3-compliant applications"
},
{
"path": "rollbar/examples/django/app.py",
"chars": 1517,
"preview": "import os\nimport sys\n\nimport django\nfrom django.conf import settings\n\n\n# use settings compatible with the installed Djan"
},
{
"path": "rollbar/examples/fastapi/app.py",
"chars": 2205,
"preview": "#!/usr/bin/env python\n\n# This example uses Uvicorn package that must be installed. However, it can be\n# replaced with an"
},
{
"path": "rollbar/examples/fastapi/app_global_request.py",
"chars": 924,
"preview": "#!/usr/bin/env python\n\n# This example uses Uvicorn package that must be installed. However, it can be\n# replaced with an"
},
{
"path": "rollbar/examples/fastapi/app_logger.py",
"chars": 1747,
"preview": "#!/usr/bin/env python\n\n# This example uses Uvicorn package that must be installed. However, it can be\n# replaced with an"
},
{
"path": "rollbar/examples/fastapi/app_middleware.py",
"chars": 1675,
"preview": "#!/usr/bin/env python\n\n# This example uses Uvicorn package that must be installed. However, it can be\n# replaced with an"
},
{
"path": "rollbar/examples/flask/app.py",
"chars": 589,
"preview": "# NOTE: pyrollbar requires both `Flask` and `blinker` packages to be installed first\nfrom flask import Flask\nfrom flask "
},
{
"path": "rollbar/examples/starlette/app.py",
"chars": 1691,
"preview": "#!/usr/bin/env python\n\n# This example uses Uvicorn package that must be installed. However, it can be\n# replaced with an"
},
{
"path": "rollbar/examples/starlette/app_global_request.py",
"chars": 1015,
"preview": "#!/usr/bin/env python\n\n# This example uses Uvicorn package that must be installed. However, it can be\n# replaced with an"
},
{
"path": "rollbar/examples/starlette/app_logger.py",
"chars": 1843,
"preview": "#!/usr/bin/env python\n\n# This example uses Uvicorn package that must be installed. However, it can be\n# replaced with an"
},
{
"path": "rollbar/examples/twisted/simpleserv.py",
"chars": 1108,
"preview": "\n# Copyright (c) Twisted Matrix Laboratories.\n# See LICENSE for details.\n#\n# From https://twistedmatrix.com/documents/cu"
},
{
"path": "rollbar/lib/__init__.py",
"chars": 4300,
"preview": "import base64\nimport collections\nimport copy\nfrom array import array\n\nfrom collections.abc import Mapping\n\nbinary_type ="
},
{
"path": "rollbar/lib/_async.py",
"chars": 7763,
"preview": "import asyncio\nimport contextlib\nimport inspect\nimport logging\nimport sys\nfrom unittest import mock\nfrom urllib.parse im"
},
{
"path": "rollbar/lib/events.py",
"chars": 1970,
"preview": "EXCEPTION_INFO = 'exception_info'\nMESSAGE = 'message'\nPAYLOAD = 'payload'\n\n_event_handlers = {\n EXCEPTION_INFO: [],\n "
},
{
"path": "rollbar/lib/filters/__init__.py",
"chars": 379,
"preview": "from rollbar.lib import events\nfrom rollbar.lib.filters.basic import filter_rollbar_ignored_exceptions, filter_by_level\n"
},
{
"path": "rollbar/lib/filters/basic.py",
"chars": 297,
"preview": "def filter_rollbar_ignored_exceptions(exc_info, **kw):\n _, exc, _ = exc_info\n if getattr(exc, '_rollbar_ignore', F"
},
{
"path": "rollbar/lib/payload.py",
"chars": 254,
"preview": "from typing import TypedDict\n\n\nclass Attribute(TypedDict):\n \"\"\"\n Represents the `data.attributes` field in the pay"
},
{
"path": "rollbar/lib/session.py",
"chars": 4060,
"preview": "from __future__ import annotations\n\nimport random\nimport threading\nfrom contextvars import ContextVar\n\nfrom rollbar.lib."
},
{
"path": "rollbar/lib/thread_pool.py",
"chars": 1099,
"preview": "import logging\nimport os\nimport sys\nfrom concurrent.futures import ThreadPoolExecutor\n\n_pool = None # type: ThreadPoolE"
},
{
"path": "rollbar/lib/transform.py",
"chars": 1647,
"preview": "from typing import Optional\n\n\nclass Transform(object):\n depth_first = True\n priority = 100\n\n def default(self, "
},
{
"path": "rollbar/lib/transforms/__init__.py",
"chars": 3400,
"preview": "from collections.abc import Iterable\n\nfrom rollbar.lib import (\n binary_type,\n string_types,\n number_types,\n "
},
{
"path": "rollbar/lib/transforms/batched.py",
"chars": 2476,
"preview": "from rollbar.lib.transform import Transform\nfrom rollbar.lib import (\n number_types,\n type_info,\n)\n\n\ndef do_transf"
},
{
"path": "rollbar/lib/transforms/scrub.py",
"chars": 1077,
"preview": "import random\n\nfrom rollbar.lib import build_key_matcher\nfrom rollbar.lib.transform import Transform\n\n\nclass ScrubTransf"
},
{
"path": "rollbar/lib/transforms/scrub_redact.py",
"chars": 388,
"preview": "from rollbar.lib.transforms.scrub import ScrubTransform\n\n\nclass RedactRef(object):\n pass\n\n\nREDACT_REF = RedactRef()\n\n"
},
{
"path": "rollbar/lib/transforms/scruburl.py",
"chars": 3165,
"preview": "import re\nfrom urllib.parse import urlsplit, urlencode, urlunsplit, parse_qs\n\nfrom rollbar.lib import string_types, bina"
},
{
"path": "rollbar/lib/transforms/serializable.py",
"chars": 3427,
"preview": "import math\n\nfrom rollbar.lib import binary_type, string_types\nfrom rollbar.lib import (\n circular_reference_label, f"
},
{
"path": "rollbar/lib/transforms/shortener.py",
"chars": 5435,
"preview": "from array import array\nimport collections\nimport itertools\nimport reprlib\n\nfrom collections.abc import Mapping\nfrom typ"
},
{
"path": "rollbar/lib/transport.py",
"chars": 1435,
"preview": "from typing import Optional\n\nimport requests\nimport threading\n\n\n_local = threading.local()\n\n\ndef _session():\n if hasa"
},
{
"path": "rollbar/lib/traverse.py",
"chars": 5381,
"preview": "import logging\nfrom pathlib import Path\n\nfrom rollbar.lib import binary_type, string_types, circular_reference_label\n\n# "
},
{
"path": "rollbar/lib/type_info.py",
"chars": 836,
"preview": "from rollbar.lib import binary_type, string_types\n\n\nfrom collections.abc import Mapping, Sequence, Set\nfrom pathlib impo"
},
{
"path": "rollbar/logger.py",
"chars": 7070,
"preview": "\"\"\"\nHooks for integrating with the python logging framework.\n\nUsage:\n import logging\n from rollbar.logger import R"
},
{
"path": "rollbar/test/__init__.py",
"chars": 239,
"preview": "import unittest\n\n\nSNOWMAN = b'\\xe2\\x98\\x83'\nSNOWMAN_UNICODE = SNOWMAN.decode('utf8')\n\n\nclass BaseTest(unittest.TestCase)"
},
{
"path": "rollbar/test/asgi_tests/__init__.py",
"chars": 163,
"preview": "import sys\nimport unittest\n\n\ndef _load_tests(loader, tests, pattern):\n return unittest.TestSuite()\n\n\nif sys.version_i"
},
{
"path": "rollbar/test/asgi_tests/test_integration.py",
"chars": 1088,
"preview": "import unittest\nimport sys\n\nfrom rollbar.test import BaseTest\n\nALLOWED_PYTHON_VERSION = sys.version_info >= (3, 5)\n\n\n@un"
},
{
"path": "rollbar/test/asgi_tests/test_middleware.py",
"chars": 5571,
"preview": "import copy\nimport importlib\nimport sys\n\nfrom unittest import mock\n\nimport unittest\n\nimport rollbar\nfrom rollbar.lib._as"
},
{
"path": "rollbar/test/asgi_tests/test_spec.py",
"chars": 861,
"preview": "import inspect\nimport sys\n\nimport unittest\n\nfrom rollbar.test import BaseTest\n\nALLOWED_PYTHON_VERSION = sys.version_info"
},
{
"path": "rollbar/test/async_tests/__init__.py",
"chars": 163,
"preview": "import sys\nimport unittest\n\n\ndef _load_tests(loader, tests, pattern):\n return unittest.TestSuite()\n\n\nif sys.version_i"
},
{
"path": "rollbar/test/async_tests/test_async.py",
"chars": 18965,
"preview": "import copy\nimport sys\n\nfrom unittest import mock\n\nimport unittest\n\nimport rollbar\nfrom rollbar.lib._async import AsyncM"
},
{
"path": "rollbar/test/fastapi_tests/__init__.py",
"chars": 163,
"preview": "import sys\nimport unittest\n\n\ndef _load_tests(loader, tests, pattern):\n return unittest.TestSuite()\n\n\nif sys.version_i"
},
{
"path": "rollbar/test/fastapi_tests/test_logger.py",
"chars": 4759,
"preview": "import importlib\nimport sys\n\nfrom unittest import mock\n\ntry:\n import fastapi\n\n FASTAPI_INSTALLED = True\nexcept Imp"
},
{
"path": "rollbar/test/fastapi_tests/test_middleware.py",
"chars": 12980,
"preview": "import copy\nimport importlib\nimport sys\n\nfrom unittest import mock\n\ntry:\n import fastapi\n\n FASTAPI_INSTALLED = Tru"
},
{
"path": "rollbar/test/fastapi_tests/test_routing.py",
"chars": 28218,
"preview": "import copy\nimport importlib\nimport json\nimport sys\n\nfrom unittest import mock\n\ntry:\n import fastapi\n\n FASTAPI_INS"
},
{
"path": "rollbar/test/fastapi_tests/test_utils.py",
"chars": 5212,
"preview": "import sys\n\ntry:\n import fastapi\n\n FASTAPI_INSTALLED = True\nexcept ImportError:\n FASTAPI_INSTALLED = False\n\nimp"
},
{
"path": "rollbar/test/flask_tests/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "rollbar/test/flask_tests/test_flask.py",
"chars": 8609,
"preview": "\"\"\"\nTests for Flask instrumentation\n\"\"\"\n\nimport json\nimport sys\nimport os\n\nfrom unittest import mock\n\nimport rollbar\nfro"
},
{
"path": "rollbar/test/starlette_tests/__init__.py",
"chars": 163,
"preview": "import sys\nimport unittest\n\n\ndef _load_tests(loader, tests, pattern):\n return unittest.TestSuite()\n\n\nif sys.version_i"
},
{
"path": "rollbar/test/starlette_tests/test_logger.py",
"chars": 4631,
"preview": "import importlib\nimport sys\n\nfrom unittest import mock\n\ntry:\n import starlette\n\n STARLETTE_INSTALLED = True\nexcept"
},
{
"path": "rollbar/test/starlette_tests/test_middleware.py",
"chars": 12078,
"preview": "import copy\nimport importlib\nimport sys\n\nfrom unittest import mock\n\ntry:\n import starlette\n\n STARLETTE_INSTALLED ="
},
{
"path": "rollbar/test/starlette_tests/test_requests.py",
"chars": 3453,
"preview": "import sys\n\ntry:\n import starlette\n\n STARLETTE_INSTALLED = True\nexcept ImportError:\n STARLETTE_INSTALLED = Fals"
},
{
"path": "rollbar/test/test_basic_filters.py",
"chars": 1094,
"preview": "from rollbar.lib import events, filters\n\nfrom rollbar.test import BaseTest\n\n\nclass BasicFiltersTest(BaseTest):\n def s"
},
{
"path": "rollbar/test/test_batched_transform.py",
"chars": 1622,
"preview": "from rollbar.lib.transforms import transform\nfrom rollbar.lib.transform import Transform\nfrom rollbar.lib.traverse impor"
},
{
"path": "rollbar/test/test_custom_filters.py",
"chars": 1558,
"preview": "import re\n\nfrom rollbar.lib import events, filters\n\nfrom rollbar.test import BaseTest\n\n\nclass CustomFiltersTest(BaseTest"
},
{
"path": "rollbar/test/test_lib.py",
"chars": 4407,
"preview": "from rollbar.lib import dict_merge, prefix_match, key_match, key_depth\nfrom rollbar.lib.transport import _get_proxy_cfg\n"
},
{
"path": "rollbar/test/test_loghandler.py",
"chars": 8030,
"preview": "\"\"\"\nTests for the RollbarHandler logging handler\n\"\"\"\nimport copy\nimport json\nimport logging\nimport sys\n\nfrom unittest im"
},
{
"path": "rollbar/test/test_pyramid.py",
"chars": 1123,
"preview": "from unittest import mock\n\nfrom rollbar.test import BaseTest\n\ntry:\n from pyramid.request import Request\n\n PYRAMID_"
},
{
"path": "rollbar/test/test_rollbar.py",
"chars": 79664,
"preview": "import base64\nimport copy\nimport json\nimport socket\nimport threading\nimport uuid\n\nimport sys\nfrom collections import nam"
},
{
"path": "rollbar/test/test_scrub_redact_transform.py",
"chars": 2592,
"preview": "from collections.abc import Mapping\n\nfrom rollbar.lib import transforms\nfrom rollbar.lib.transforms.scrub_redact import "
},
{
"path": "rollbar/test/test_scrub_transform.py",
"chars": 6870,
"preview": "import copy\n\nfrom collections.abc import Mapping\n\nfrom rollbar.lib import transforms\nfrom rollbar.lib.transforms.scrub i"
},
{
"path": "rollbar/test/test_scruburl_transform.py",
"chars": 6392,
"preview": "from urllib.parse import urlparse, parse_qs\n\nfrom rollbar.lib import transforms, string_types\nfrom rollbar.lib.transform"
},
{
"path": "rollbar/test/test_serializable_transform.py",
"chars": 9365,
"preview": "import collections\nimport base64\nimport copy\nimport enum\nimport sys\n\nfrom collections.abc import Mapping\n\nfrom rollbar.l"
},
{
"path": "rollbar/test/test_session.py",
"chars": 5747,
"preview": "import asyncio\nimport threading\nimport unittest\n\nfrom rollbar.test import BaseTest\nfrom rollbar.lib import session\n\n\ncla"
},
{
"path": "rollbar/test/test_shortener_transform.py",
"chars": 12212,
"preview": "import sys\nfrom array import array\nfrom collections import deque\n\nfrom rollbar import DEFAULT_LOCALS_SIZES, SETTINGS\nfro"
},
{
"path": "rollbar/test/test_transform.py",
"chars": 3203,
"preview": "import copy\n\nimport rollbar\nfrom rollbar.test import BaseTest\nfrom rollbar.lib.transforms import Transform\nfrom rollbar."
},
{
"path": "rollbar/test/test_traverse.py",
"chars": 4922,
"preview": "from rollbar.lib.transform import Transform\nfrom rollbar.lib.traverse import traverse\n\nfrom rollbar.test import BaseTest"
},
{
"path": "rollbar/test/twisted_tests/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "rollbar/test/twisted_tests/test_twisted.py",
"chars": 3212,
"preview": "\"\"\"\nTests for Twisted instrumentation\n\"\"\"\n\nimport json\nimport sys\n\nfrom unittest import mock\n\nimport rollbar\n\n# access t"
},
{
"path": "rollbar/test/utils.py",
"chars": 142,
"preview": "from collections.abc import Mapping\n\ndef get_public_attrs(obj: Mapping) -> dict:\n return {k: obj[k] for k in obj if n"
}
]
About this extraction
This page contains the full source code of the rollbar/pyrollbar GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 104 files (465.5 KB), approximately 111.4k tokens, and a symbol index with 780 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.