Skip to main content

An extremely fast Python linter and code formatter, written in Rust.

Project description

Ruff

Ruff image image image Actions status Discord

Docs | Playground

An extremely fast Python linter and code formatter, written in Rust.

Shows a bar chart with benchmark results.

Linting the CPython codebase from scratch.

  • ⚡️ 10-100x faster than existing linters (like Flake8) and formatters (like Black)
  • 🐍 Installable via pip
  • 🛠️ pyproject.toml support
  • 🤝 Python 3.13 compatibility
  • ⚖️ Drop-in parity with Flake8, isort, and Black
  • 📦 Built-in caching, to avoid re-analyzing unchanged files
  • 🔧 Fix support, for automatic error correction (e.g., automatically remove unused imports)
  • 📏 Over 800 built-in rules, with native re-implementations of popular Flake8 plugins, like flake8-bugbear
  • ⌨️ First-party editor integrations for VS Code and more
  • 🌎 Monorepo-friendly, with hierarchical and cascading configuration

Ruff aims to be orders of magnitude faster than alternative tools while integrating more functionality behind a single, common interface.

Ruff can be used to replace Flake8 (plus dozens of plugins), Black, isort, pydocstyle, pyupgrade, autoflake, and more, all while executing tens or hundreds of times faster than any individual tool.

Ruff is extremely actively developed and used in major open-source projects like:

...and many more.

Ruff is backed by Astral. Read the launch post, or the original project announcement.

Testimonials

Sebastián Ramírez, creator of FastAPI:

Ruff is so fast that sometimes I add an intentional bug in the code just to confirm it's actually running and checking the code.

Nick Schrock, founder of Elementl, co-creator of GraphQL:

Why is Ruff a gamechanger? Primarily because it is nearly 1000x faster. Literally. Not a typo. On our largest module (dagster itself, 250k LOC) pylint takes about 2.5 minutes, parallelized across 4 cores on my M1. Running ruff against our entire codebase takes .4 seconds.

Bryan Van de Ven, co-creator of Bokeh, original author of Conda:

Ruff is ~150-200x faster than flake8 on my machine, scanning the whole repo takes ~0.2s instead of ~20s. This is an enormous quality of life improvement for local dev. It's fast enough that I added it as an actual commit hook, which is terrific.

Timothy Crosley, creator of isort:

Just switched my first project to Ruff. Only one downside so far: it's so fast I couldn't believe it was working till I intentionally introduced some errors.

Tim Abbott, lead developer of Zulip:

This is just ridiculously fast... ruff is amazing.

Table of Contents

For more, see the documentation.

  1. Getting Started
  2. Configuration
  3. Rules
  4. Contributing
  5. Support
  6. Acknowledgements
  7. Who's Using Ruff?
  8. License

Getting Started

For more, see the documentation.

Installation

Ruff is available as ruff on PyPI.

Invoke Ruff directly with uvx:

uvx ruff check   # Lint all files in the current directory.
uvx ruff format  # Format all files in the current directory.

Or install Ruff with uv (recommended), pip, or pipx:

# With uv.
uv tool install ruff@latest  # Install Ruff globally.
uv add --dev ruff            # Or add Ruff to your project.

# With pip.
pip install ruff

# With pipx.
pipx install ruff

Starting with version 0.5.0, Ruff can be installed with our standalone installers:

# On macOS and Linux.
curl -LsSf https://astral.sh/ruff/install.sh | sh

# On Windows.
powershell -c "irm https://astral.sh/ruff/install.ps1 | iex"

# For a specific version.
curl -LsSf https://astral.sh/ruff/0.9.3/install.sh | sh
powershell -c "irm https://astral.sh/ruff/0.9.3/install.ps1 | iex"

You can also install Ruff via Homebrew, Conda, and with a variety of other package managers.

Usage

To run Ruff as a linter, try any of the following:

ruff check                          # Lint all files in the current directory (and any subdirectories).
ruff check path/to/code/            # Lint all files in `/path/to/code` (and any subdirectories).
ruff check path/to/code/*.py        # Lint all `.py` files in `/path/to/code`.
ruff check path/to/code/to/file.py  # Lint `file.py`.
ruff check @arguments.txt           # Lint using an input file, treating its contents as newline-delimited command-line arguments.

Or, to run Ruff as a formatter:

ruff format                          # Format all files in the current directory (and any subdirectories).
ruff format path/to/code/            # Format all files in `/path/to/code` (and any subdirectories).
ruff format path/to/code/*.py        # Format all `.py` files in `/path/to/code`.
ruff format path/to/code/to/file.py  # Format `file.py`.
ruff format @arguments.txt           # Format using an input file, treating its contents as newline-delimited command-line arguments.

Ruff can also be used as a pre-commit hook via ruff-pre-commit:

- repo: https://github.com/astral-sh/ruff-pre-commit
  # Ruff version.
  rev: v0.9.3
  hooks:
    # Run the linter.
    - id: ruff
      args: [ --fix ]
    # Run the formatter.
    - id: ruff-format

Ruff can also be used as a VS Code extension or with various other editors.

Ruff can also be used as a GitHub Action via ruff-action:

name: Ruff
on: [ push, pull_request ]
jobs:
  ruff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/ruff-action@v3

Configuration

Ruff can be configured through a pyproject.toml, ruff.toml, or .ruff.toml file (see: Configuration, or Settings for a complete list of all configuration options).

If left unspecified, Ruff's default configuration is equivalent to the following ruff.toml file:

# Exclude a variety of commonly ignored directories.
exclude = [
    ".bzr",
    ".direnv",
    ".eggs",
    ".git",
    ".git-rewrite",
    ".hg",
    ".ipynb_checkpoints",
    ".mypy_cache",
    ".nox",
    ".pants.d",
    ".pyenv",
    ".pytest_cache",
    ".pytype",
    ".ruff_cache",
    ".svn",
    ".tox",
    ".venv",
    ".vscode",
    "__pypackages__",
    "_build",
    "buck-out",
    "build",
    "dist",
    "node_modules",
    "site-packages",
    "venv",
]

# Same as Black.
line-length = 88
indent-width = 4

# Assume Python 3.9
target-version = "py39"

[lint]
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`)  codes by default.
select = ["E4", "E7", "E9", "F"]
ignore = []

# Allow fix for all enabled rules (when `--fix`) is provided.
fixable = ["ALL"]
unfixable = []

# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"

[format]
# Like Black, use double quotes for strings.
quote-style = "double"

# Like Black, indent with spaces, rather than tabs.
indent-style = "space"

# Like Black, respect magic trailing commas.
skip-magic-trailing-comma = false

# Like Black, automatically detect the appropriate line ending.
line-ending = "auto"

Note that, in a pyproject.toml, each section header should be prefixed with tool.ruff. For example, [lint] should be replaced with [tool.ruff.lint].

Some configuration options can be provided via dedicated command-line arguments, such as those related to rule enablement and disablement, file discovery, and logging level:

ruff check --select F401 --select F403 --quiet

The remaining configuration options can be provided through a catch-all --config argument:

ruff check --config "lint.per-file-ignores = {'some_file.py' = ['F841']}"

To opt in to the latest lint rules, formatter style changes, interface updates, and more, enable preview mode by setting preview = true in your configuration file or passing --preview on the command line. Preview mode enables a collection of unstable features that may change prior to stabilization.

See ruff help for more on Ruff's top-level commands, or ruff help check and ruff help format for more on the linting and formatting commands, respectively.

Rules

Ruff supports over 800 lint rules, many of which are inspired by popular tools like Flake8, isort, pyupgrade, and others. Regardless of the rule's origin, Ruff re-implements every rule in Rust as a first-party feature.

By default, Ruff enables Flake8's F rules, along with a subset of the E rules, omitting any stylistic rules that overlap with the use of a formatter, like ruff format or Black.

If you're just getting started with Ruff, the default rule set is a great place to start: it catches a wide variety of common errors (like unused imports) with zero configuration.

Beyond the defaults, Ruff re-implements some of the most popular Flake8 plugins and related code quality tools, including:

For a complete enumeration of the supported rules, see Rules.

Contributing

Contributions are welcome and highly appreciated. To get started, check out the contributing guidelines.

You can also join us on Discord.

Support

Having trouble? Check out the existing issues on GitHub, or feel free to open a new one.

You can also ask for help on Discord.

Acknowledgements

Ruff's linter draws on both the APIs and implementation details of many other tools in the Python ecosystem, especially Flake8, Pyflakes, pycodestyle, pydocstyle, pyupgrade, and isort.

In some cases, Ruff includes a "direct" Rust port of the corresponding tool. We're grateful to the maintainers of these tools for their work, and for all the value they've provided to the Python community.

Ruff's formatter is built on a fork of Rome's rome_formatter, and again draws on both API and implementation details from Rome, Prettier, and Black.

Ruff's import resolver is based on the import resolution algorithm from Pyright.

Ruff is also influenced by a number of tools outside the Python ecosystem, like Clippy and ESLint.

Ruff is the beneficiary of a large number of contributors.

Ruff is released under the MIT license.

Who's Using Ruff?

Ruff is used by a number of major open-source projects and companies, including:

Show Your Support

If you're using Ruff, consider adding the Ruff badge to your project's README.md:

[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)

...or README.rst:

.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
    :target: https://github.com/astral-sh/ruff
    :alt: Ruff

...or, as HTML:

<a href="https://github.com/astral-sh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff" style="max-width:100%;"></a>

License

This repository is licensed under the MIT License

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ruff-0.9.3.tar.gz (3.6 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

ruff-0.9.3-py3-none-win_arm64.whl (10.0 MB view details)

Uploaded Python 3Windows ARM64

ruff-0.9.3-py3-none-win_amd64.whl (10.8 MB view details)

Uploaded Python 3Windows x86-64

ruff-0.9.3-py3-none-win32.whl (9.8 MB view details)

Uploaded Python 3Windows x86

ruff-0.9.3-py3-none-musllinux_1_2_x86_64.whl (12.5 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

ruff-0.9.3-py3-none-musllinux_1_2_i686.whl (12.0 MB view details)

Uploaded Python 3musllinux: musl 1.2+ i686

ruff-0.9.3-py3-none-musllinux_1_2_armv7l.whl (11.5 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARMv7l

ruff-0.9.3-py3-none-musllinux_1_2_aarch64.whl (11.8 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARM64

ruff-0.9.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (12.4 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

ruff-0.9.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl (14.5 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ s390x

ruff-0.9.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (12.7 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ppc64le

ruff-0.9.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl (13.2 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ppc64

ruff-0.9.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl (12.6 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ i686

ruff-0.9.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (11.4 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARMv7l

ruff-0.9.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (11.9 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

ruff-0.9.3-py3-none-macosx_11_0_arm64.whl (11.0 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

ruff-0.9.3-py3-none-macosx_10_12_x86_64.whl (11.6 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

ruff-0.9.3-py3-none-linux_armv6l.whl (11.7 MB view details)

Uploaded Python 3

File details

Details for the file ruff-0.9.3.tar.gz.

File metadata

  • Download URL: ruff-0.9.3.tar.gz
  • Upload date:
  • Size: 3.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.5.23

File hashes

Hashes for ruff-0.9.3.tar.gz
Algorithm Hash digest
SHA256 8293f89985a090ebc3ed1064df31f3b4b56320cdfcec8b60d3295bddb955c22a
MD5 07f2ecc8dfa3b307109ce477533a2ce8
BLAKE2b-256 1e7f60fda2eec81f23f8aa7cbbfdf6ec2ca11eb11c273827933fb2541c2ce9d8

See more details on using hashes here.

File details

Details for the file ruff-0.9.3-py3-none-win_arm64.whl.

File metadata

  • Download URL: ruff-0.9.3-py3-none-win_arm64.whl
  • Upload date:
  • Size: 10.0 MB
  • Tags: Python 3, Windows ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.5.23

File hashes

Hashes for ruff-0.9.3-py3-none-win_arm64.whl
Algorithm Hash digest
SHA256 800d773f6d4d33b0a3c60e2c6ae8f4c202ea2de056365acfa519aa48acf28e0b
MD5 7c392f3beec6540f955165c442dc8981
BLAKE2b-256 69cbb3fe58a136a27d981911cba2f18e4b29f15010623b79f0f2510fd0d31fd3

See more details on using hashes here.

File details

Details for the file ruff-0.9.3-py3-none-win_amd64.whl.

File metadata

  • Download URL: ruff-0.9.3-py3-none-win_amd64.whl
  • Upload date:
  • Size: 10.8 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.5.23

File hashes

Hashes for ruff-0.9.3-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 040ceb7f20791dfa0e78b4230ee9dce23da3b64dd5848e40e3bf3ab76468dcf4
MD5 111671cfd801c7f3cbbdb73e00dfcf7b
BLAKE2b-256 c30165cadb59bf8d4fbe33d1a750103e6883d9ef302f60c28b73b773092fbde5

See more details on using hashes here.

File details

Details for the file ruff-0.9.3-py3-none-win32.whl.

File metadata

  • Download URL: ruff-0.9.3-py3-none-win32.whl
  • Upload date:
  • Size: 9.8 MB
  • Tags: Python 3, Windows x86
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.5.23

File hashes

Hashes for ruff-0.9.3-py3-none-win32.whl
Algorithm Hash digest
SHA256 eabe5eb2c19a42f4808c03b82bd313fc84d4e395133fb3fc1b1516170a31213c
MD5 5e15d83d9aadb513d4a20f52ae35358d
BLAKE2b-256 cb44a673647105b1ba6da9824a928634fe23186ab19f9d526d7bdf278cd27bc3

See more details on using hashes here.

File details

Details for the file ruff-0.9.3-py3-none-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for ruff-0.9.3-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 90230a6b8055ad47d3325e9ee8f8a9ae7e273078a66401ac66df68943ced029b
MD5 16a3004d92d02bcf31779a4182f7e308
BLAKE2b-256 73b18d9a2c0efbbabe848b55f877bc10c5001a37ab10aca13c711431673414e5

See more details on using hashes here.

File details

Details for the file ruff-0.9.3-py3-none-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for ruff-0.9.3-py3-none-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 ba6eea4459dbd6b1be4e6bfc766079fb9b8dd2e5a35aff6baee4d9b1514ea519
MD5 6951c0c6f25e28270ff25bee18ca06f8
BLAKE2b-256 a3c8ff8acbd33addc7e797e702cf00bfde352ab469723720c5607b964491d5cf

See more details on using hashes here.

File details

Details for the file ruff-0.9.3-py3-none-musllinux_1_2_armv7l.whl.

File metadata

File hashes

Hashes for ruff-0.9.3-py3-none-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 006e5de2621304c8810bcd2ee101587712fa93b4f955ed0985907a36c427e0c2
MD5 5d7692f8493a8a33567c06ba2e921586
BLAKE2b-256 9ebe3f341ceb1c62b565ec1fb6fd2139cc40b60ae6eff4b6fb8f94b1bb37c7a9

See more details on using hashes here.

File details

Details for the file ruff-0.9.3-py3-none-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for ruff-0.9.3-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 33866c3cc2a575cbd546f2cd02bdd466fed65118e4365ee538a3deffd6fcb730
MD5 f5b929cae95ba6be4b68e5d58f625bab
BLAKE2b-256 845dde0b7652e09f7dda49e1a3825a164a65f4998175b6486603c7601279baad

See more details on using hashes here.

File details

Details for the file ruff-0.9.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ruff-0.9.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 cabc332b7075a914ecea912cd1f3d4370489c8018f2c945a30bcc934e3bc06a6
MD5 7927dac58af26aeec13c0e1200e3d2d2
BLAKE2b-256 63a647fd0e96990ee9b7a4abda62de26d291bd3f7647218d05b7d6d38af47c30

See more details on using hashes here.

File details

Details for the file ruff-0.9.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl.

File metadata

File hashes

Hashes for ruff-0.9.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl
Algorithm Hash digest
SHA256 9bb7554aca6f842645022fe2d301c264e6925baa708b392867b7a62645304df4
MD5 747bd8e457ab337d7665055e1692df9c
BLAKE2b-256 be38266fbcbb3d0088862c9bafa8b1b99486691d2945a90b9a7316336a0d9a1b

See more details on using hashes here.

File details

Details for the file ruff-0.9.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl.

File metadata

File hashes

Hashes for ruff-0.9.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl
Algorithm Hash digest
SHA256 96a87ec31dc1044d8c2da2ebbed1c456d9b561e7d087734336518181b26b3aa5
MD5 3403addcaea7c3e2cfe10dab9fa8b1fa
BLAKE2b-256 d0b43c600758e320f5bf7de16858502e849f4216cb0151f819fa0d1154874802

See more details on using hashes here.

File details

Details for the file ruff-0.9.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl.

File metadata

File hashes

Hashes for ruff-0.9.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl
Algorithm Hash digest
SHA256 c4bb09d2bbb394e3730d0918c00276e79b2de70ec2a5231cd4ebb51a57df9ba1
MD5 607145552a6aa4440dbaf75a0ac86270
BLAKE2b-256 a6a13167023f23e3530fde899497ccfe239e4523854cb874458ac082992d206c

See more details on using hashes here.

File details

Details for the file ruff-0.9.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for ruff-0.9.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 5a5a46e09355695fbdbb30ed9889d6cf1c61b77b700a9fafc21b41f097bfbba4
MD5 ba1c16fc6acf64f4501292bdf0f34240
BLAKE2b-256 ef42b7ca38ffd568ae9b128a2fa76353e9a9a3c80ef19746408d4ce99217ecc1

See more details on using hashes here.

File details

Details for the file ruff-0.9.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl.

File metadata

File hashes

Hashes for ruff-0.9.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm Hash digest
SHA256 646909a1e25e0dc28fbc529eab8eb7bb583079628e8cbe738192853dbbe43af5
MD5 3632ad8d5d081dedde6df68086204278
BLAKE2b-256 7fc63e14e09be29587393d188454064a4aa85174910d16644051a80444e4fd88

See more details on using hashes here.

File details

Details for the file ruff-0.9.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for ruff-0.9.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 2dc153c25e715be41bb228bc651c1e9b1a88d5c6e5ed0194fa0dfea02b026439
MD5 8c024ffa829a7b1fafd0ccf929dcf290
BLAKE2b-256 b2bd1d775eac5e51409535804a3a888a9623e87a8f4b53e2491580858a083692

See more details on using hashes here.

File details

Details for the file ruff-0.9.3-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for ruff-0.9.3-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c59ab92f8e92d6725b7ded9d4a31be3ef42688a115c6d3da9457a5bda140e2b4
MD5 a955f090073714cf482ca85242e2f9cb
BLAKE2b-256 8e89320223c3421962762531a6b2dd58579b858ca9916fb2674874df5e97d628

See more details on using hashes here.

File details

Details for the file ruff-0.9.3-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for ruff-0.9.3-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 a187171e7c09efa4b4cc30ee5d0d55a8d6c5311b3e1b74ac5cb96cc89bafc43c
MD5 8d0796065e4696bda2108f3753c92148
BLAKE2b-256 a2a83338ecb97573eafe74505f28431df3842c1933c5f8eae615427c1de32858

See more details on using hashes here.

File details

Details for the file ruff-0.9.3-py3-none-linux_armv6l.whl.

File metadata

File hashes

Hashes for ruff-0.9.3-py3-none-linux_armv6l.whl
Algorithm Hash digest
SHA256 7f39b879064c7d9670197d91124a75d118d00b0990586549949aae80cdc16624
MD5 427f448751822e488b415b99055b4e76
BLAKE2b-256 f9774fb790596d5d52c87fd55b7160c557c400e90f6116a56d82d76e95d9374a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page