Skip to main content

chDB is an in-process SQL OLAP Engine powered by ClickHouse

Project description

Build X86 PyPI Downloads Discord Twitter

chDB

chDB is an in-process SQL OLAP Engine powered by ClickHouse [^1] For more details: The birth of chDB

Features

  • In-process SQL OLAP Engine, powered by ClickHouse
  • No need to install ClickHouse
  • Minimized data copy from C++ to Python with python memoryview
  • Input&Output support Parquet, CSV, JSON, Arrow, ORC and 60+more formats, samples
  • Support Python DB API 2.0, example

Arch

Get Started

Get started with chdb using our Installation and Usage Examples


Installation

Currently, chDB supports Python 3.8+ on macOS and Linux (x86_64 and ARM64).

pip install chdb

Usage

Run in command line

python3 -m chdb SQL [OutputFormat]

python3 -m chdb "SELECT 1,'abc'" Pretty

Data Input

The following methods are available to access on-disk and in-memory data formats:

🗂️ Query On File

(Parquet, CSV, JSON, Arrow, ORC and 60+)

You can execute SQL and return desired format data.

import chdb
res = chdb.query('select version()', 'Pretty'); print(res)

Work with Parquet or CSV

# See more data type format in tests/format_output.py
res = chdb.query('select * from file("data.parquet", Parquet)', 'JSON'); print(res)
res = chdb.query('select * from file("data.csv", CSV)', 'CSV');  print(res)
print(f"SQL read {res.rows_read()} rows, {res.bytes_read()} bytes, elapsed {res.elapsed()} seconds")

Pandas dataframe output

# See more in https://clickhouse.com/docs/en/interfaces/formats
chdb.query('select * from file("data.parquet", Parquet)', 'Dataframe')

🗂️ Query On Table

(Pandas DataFrame, Parquet file/bytes, Arrow bytes)

Query On Pandas DataFrame

import chdb.dataframe as cdf
import pandas as pd
# Join 2 DataFrames
df1 = pd.DataFrame({'a': [1, 2, 3], 'b': ["one", "two", "three"]})
df2 = pd.DataFrame({'c': [1, 2, 3], 'd': ["①", "②", "③"]})
ret_tbl = cdf.query(sql="select * from __tbl1__ t1 join __tbl2__ t2 on t1.a = t2.c",
                  tbl1=df1, tbl2=df2)
print(ret_tbl)
# Query on the DataFrame Table
print(ret_tbl.query('select b, sum(a) from __table__ group by b'))

🗂️ Query with Stateful Session

from chdb import session as chs

## Create DB, Table, View in temp session, auto cleanup when session is deleted.
sess = chs.Session()
sess.query("CREATE DATABASE IF NOT EXISTS db_xxx ENGINE = Atomic")
sess.query("CREATE TABLE IF NOT EXISTS db_xxx.log_table_xxx (x String, y Int) ENGINE = Log;")
sess.query("INSERT INTO db_xxx.log_table_xxx VALUES ('a', 1), ('b', 3), ('c', 2), ('d', 5);")
sess.query(
    "CREATE VIEW db_xxx.view_xxx AS SELECT * FROM db_xxx.log_table_xxx LIMIT 4;"
)
print("Select from view:\n")
print(sess.query("SELECT * FROM db_xxx.view_xxx", "Pretty"))

see also: test_stateful.py.

🗂️ Query with Python DB-API 2.0

import chdb.dbapi as dbapi
print("chdb driver version: {0}".format(dbapi.get_client_info()))

conn1 = dbapi.connect()
cur1 = conn1.cursor()
cur1.execute('select version()')
print("description: ", cur1.description)
print("data: ", cur1.fetchone())
cur1.close()
conn1.close()

🗂️ Query with UDF (User Defined Functions)

from chdb.udf import chdb_udf
from chdb import query

@chdb_udf()
def sum_udf(lhs, rhs):
    return int(lhs) + int(rhs)

print(query("select sum_udf(12,22)"))

Some notes on chDB Python UDF(User Defined Function) decorator.

  1. The function should be stateless. So, only UDFs are supported, not UDAFs(User Defined Aggregation Function).
  2. Default return type is String. If you want to change the return type, you can pass in the return type as an argument. The return type should be one of the following: https://clickhouse.com/docs/en/sql-reference/data-types
  3. The function should take in arguments of type String. As the input is TabSeparated, all arguments are strings.
  4. The function will be called for each line of input. Something like this:
    def sum_udf(lhs, rhs):
        return int(lhs) + int(rhs)
    
    for line in sys.stdin:
        args = line.strip().split('\t')
        lhs = args[0]
        rhs = args[1]
        print(sum_udf(lhs, rhs))
        sys.stdout.flush()
    
  5. The function should be pure python function. You SHOULD import all python modules used IN THE FUNCTION.
    def func_use_json(arg):
        import json
        ...
    
  6. Python interpertor used is the same as the one used to run the script. Get from sys.executable

see also: test_udf.py.

🗂️ Python Table Engine

Query on Pandas DataFrame

import chdb
import pandas as pd
df = pd.DataFrame(
    {
        "a": [1, 2, 3, 4, 5, 6],
        "b": ["tom", "jerry", "auxten", "tom", "jerry", "auxten"],
    }
)

chdb.query("SELECT b, sum(a) FROM Python(df) GROUP BY b ORDER BY b").show()

Query on Arrow Table

import chdb
import pyarrow as pa
arrow_table = pa.table(
    {
        "a": [1, 2, 3, 4, 5, 6],
        "b": ["tom", "jerry", "auxten", "tom", "jerry", "auxten"],
    }
)

chdb.query(
    "SELECT b, sum(a) FROM Python(arrow_table) GROUP BY b ORDER BY b", "debug"
).show()

Query on chdb.PyReader class instance

  1. You must inherit from chdb.PyReader class and implement the read method.
  2. The read method should:
    1. return a list of lists, the first demension is the column, the second dimension is the row, the columns order should be the same as the first arg col_names of read.
    2. return an empty list when there is no more data to read.
    3. be stateful, the cursor should be updated in the read method.
  3. An optional get_schema method can be implemented to return the schema of the table. The prototype is def get_schema(self) -> List[Tuple[str, str]]:, the return value is a list of tuples, each tuple contains the column name and the column type. The column type should be one of the following: https://clickhouse.com/docs/en/sql-reference/data-types
import chdb

class myReader(chdb.PyReader):
    def __init__(self, data):
        self.data = data
        self.cursor = 0
        super().__init__(data)

    def read(self, col_names, count):
        print("Python func read", col_names, count, self.cursor)
        if self.cursor >= len(self.data["a"]):
            return []
        block = [self.data[col] for col in col_names]
        self.cursor += len(block[0])
        return block

reader = myReader(
    {
        "a": [1, 2, 3, 4, 5, 6],
        "b": ["tom", "jerry", "auxten", "tom", "jerry", "auxten"],
    }
)

chdb.query(
    "SELECT b, sum(a) FROM Python(reader) GROUP BY b ORDER BY b"
).show()

see also: test_query_py.py.

Limitations

  1. Column types supported: pandas.Series, pyarrow.array, chdb.PyReader
  2. Data types supported: Int, UInt, Float, String, Date, DateTime, Decimal
  3. Python Object type will be converted to String
  4. Pandas DataFrame performance is all of the best, Arrow Table is better than PyReader

For more examples, see examples and tests.


Demos and Examples

Benchmark

Documentation

Events

Contributing

Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated. There are something you can help:

  • Help test and report bugs
  • Help improve documentation
  • Help improve code quality and performance

Bindings

We welcome bindings for other languages, please refer to bindings for more details.

License

Apache 2.0, see LICENSE for more information.

Acknowledgments

chDB is mainly based on ClickHouse [^1] for trade mark and other reasons, I named it chDB.

Contact


[^1]: ClickHouse® is a trademark of ClickHouse Inc. All trademarks, service marks, and logos mentioned or depicted are the property of their respective owners. The use of any third-party trademarks, brand names, product names, and company names does not imply endorsement, affiliation, or association with the respective owners.

Project details


Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

chdb-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (113.8 MB view details)

Uploaded CPython 3.12 manylinux: glibc 2.17+ ARM64

chdb-2.1.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (140.7 MB view details)

Uploaded CPython 3.12 manylinux: glibc 2.17+ x86-64 manylinux: glibc 2.5+ x86-64

chdb-2.1.1-cp312-cp312-macosx_11_0_arm64.whl (78.1 MB view details)

Uploaded CPython 3.12 macOS 11.0+ ARM64

chdb-2.1.1-cp312-cp312-macosx_10_15_x86_64.whl (102.5 MB view details)

Uploaded CPython 3.12 macOS 10.15+ x86-64

chdb-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (113.8 MB view details)

Uploaded CPython 3.11 manylinux: glibc 2.17+ ARM64

chdb-2.1.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (140.7 MB view details)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64 manylinux: glibc 2.5+ x86-64

chdb-2.1.1-cp311-cp311-macosx_11_0_arm64.whl (78.1 MB view details)

Uploaded CPython 3.11 macOS 11.0+ ARM64

chdb-2.1.1-cp311-cp311-macosx_10_15_x86_64.whl (102.5 MB view details)

Uploaded CPython 3.11 macOS 10.15+ x86-64

chdb-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (113.8 MB view details)

Uploaded CPython 3.10 manylinux: glibc 2.17+ ARM64

chdb-2.1.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (140.7 MB view details)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64 manylinux: glibc 2.5+ x86-64

chdb-2.1.1-cp310-cp310-macosx_11_0_arm64.whl (78.1 MB view details)

Uploaded CPython 3.10 macOS 11.0+ ARM64

chdb-2.1.1-cp310-cp310-macosx_10_15_x86_64.whl (102.5 MB view details)

Uploaded CPython 3.10 macOS 10.15+ x86-64

chdb-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (113.8 MB view details)

Uploaded CPython 3.9 manylinux: glibc 2.17+ ARM64

chdb-2.1.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (140.7 MB view details)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64 manylinux: glibc 2.5+ x86-64

chdb-2.1.1-cp39-cp39-macosx_11_0_arm64.whl (78.1 MB view details)

Uploaded CPython 3.9 macOS 11.0+ ARM64

chdb-2.1.1-cp39-cp39-macosx_10_15_x86_64.whl (102.5 MB view details)

Uploaded CPython 3.9 macOS 10.15+ x86-64

chdb-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (113.8 MB view details)

Uploaded CPython 3.8 manylinux: glibc 2.17+ ARM64

chdb-2.1.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (140.7 MB view details)

Uploaded CPython 3.8 manylinux: glibc 2.17+ x86-64 manylinux: glibc 2.5+ x86-64

chdb-2.1.1-cp38-cp38-macosx_10_15_x86_64.whl (102.5 MB view details)

Uploaded CPython 3.8 macOS 10.15+ x86-64

File details

Details for the file chdb-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 8dc8a8b345ee45d7b70552aa35076cc48383ce73d6e4bfaa42e36c0254df31bf
MD5 c90d5b021a6011b2db802c3f0b1a9caa
BLAKE2b-256 6cbbc202561fcd0e968f044f94fd28b526f1dc439634c902b961a45c6721f4a5

See more details on using hashes here.

File details

Details for the file chdb-2.1.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9edb828963275a804eb139b16a4d5641351fe36730a6cfcb4f0a6c6d08a07139
MD5 2d1711e12f9dd365b12159c595dadb3b
BLAKE2b-256 0a7115e67635275e6cb576e40281d539d268abdae8c708ee49750ff29709dd81

See more details on using hashes here.

File details

Details for the file chdb-2.1.1-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 d48906d62ac2371642bbcc083e20c55e4cb1c343cc1c7ea86302266feacd0e25
MD5 78c07bb74b161099206a99a53a517fc0
BLAKE2b-256 ed2337bfa75ab34575b359cb785fea7bf7b0f1a6663db165317f0800c9c9d7b5

See more details on using hashes here.

File details

Details for the file chdb-2.1.1-cp312-cp312-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp312-cp312-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 752b4ddc8c9e0f4c8bb7640befc5aa74ae26360db726ca0f5491f9ab6af84aaa
MD5 1bb958c41079e9cd2996104f29ced75b
BLAKE2b-256 57839acfdc20b8b9bb9dc7612b2100e29411f8f72375d4a85b0f225360094b61

See more details on using hashes here.

File details

Details for the file chdb-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 ea6add429ce0d253dbe50a243ffd68837d547f0b1450e06368348a6fb9351432
MD5 48f95f27dd98441d661d47356f4abffa
BLAKE2b-256 bed58e3b84c66abd5605f28333ffd5d85b7eab5fd80debf2f90462d803da7fc0

See more details on using hashes here.

File details

Details for the file chdb-2.1.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 d904cfd5d7eda5c6833c1b49929cf897dcd2eba3fc1be6fb1bb7018ff87a77fa
MD5 6b0c8746b74b3d3dd09a79753e374a36
BLAKE2b-256 8baffd2e1987c0d3116b529720396cee5dd3f47c9254dd514ff958a138c5e0d3

See more details on using hashes here.

File details

Details for the file chdb-2.1.1-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 e75a3c68d6e8e3282b3a234ff509b44f3da9130946de5630eebc4c89c60ed919
MD5 9235efdda4cfedba8816c96777974279
BLAKE2b-256 27d0a5473d7d1a04d211e1cd712beea00ff50fa5d6b57b6a74d11356cc6907db

See more details on using hashes here.

File details

Details for the file chdb-2.1.1-cp311-cp311-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp311-cp311-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 e9e44db9fc6e07987192470eff742727e7ff71c9ed4a5c18244b1ca55cee52b7
MD5 6ef9769b8b42c459e811a62635985189
BLAKE2b-256 4f56354ac78b7411a9a56ad4c0855cfaa6a2747a555e224a7cd2647f5147b839

See more details on using hashes here.

File details

Details for the file chdb-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 07482673c8e38faf96050815dd9dcc08da31f32e35f44a76ef20bc2f30078808
MD5 e133914eb437270578e980369e968c54
BLAKE2b-256 fa1935a10e803eedb0afd6b7cb7f94764bd6c853dedc6a35f46642d7ffb72cff

See more details on using hashes here.

File details

Details for the file chdb-2.1.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 614ac76312b0b31497a712d31e591e758cf66373a62b4edcd1b3ccd1b1ab92a2
MD5 45f9a52b0374b23fcfdd57beb2533722
BLAKE2b-256 c67accafd21283cba64f5f7f51e83a4a8a357ac2c3baa2ee6266ca67ad827693

See more details on using hashes here.

File details

Details for the file chdb-2.1.1-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 2a7464c7b65f21bb75d001e90fe457a67d426e7a225c36e30763c2403cfbb894
MD5 01bd5152c11ea62cd79d1e4207d4147f
BLAKE2b-256 6b6d3ff5016b88b82fb21798aabaf336d24ef9f02902778f4b63285006a37ee0

See more details on using hashes here.

File details

Details for the file chdb-2.1.1-cp310-cp310-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp310-cp310-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 1c388183e3f0b35eb76eaa901aef11860aef2b5c120cd457d85f831999496530
MD5 d17de9cc6f7ac61e48d01867e97005d9
BLAKE2b-256 462ac5ac6a6bf6bd674642221aa52d7cd1a30e51b55436437f2bc12fbb6ccc21

See more details on using hashes here.

File details

Details for the file chdb-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 e8035a0efc7efdcd0c9a8e0e2795679af6efe1c008befb85733e9337d963286b
MD5 522e8d8798b8ba46d7b2cf8f53f3e051
BLAKE2b-256 12ff4eb205abbeca5deeaa26954fcf24967a08f906cb259a36b721d102277f3c

See more details on using hashes here.

File details

Details for the file chdb-2.1.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 19ae7312972ba537d883d0a5174bdce5c85d2f0a135f72bababfb87749f5e652
MD5 9c8d1b3f75cf92cdad5941914b081875
BLAKE2b-256 cc97ec9f03d23ebac677329d8088e3b77f83192a4f2cd798bcf05c8b875d99b4

See more details on using hashes here.

File details

Details for the file chdb-2.1.1-cp39-cp39-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp39-cp39-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 01c0cee7690575d293f938931d1f112e45c016a5089e9fa5bb902da48ae36886
MD5 cdedbf7a8a634811323685852d427c35
BLAKE2b-256 7304ba3cf7fe85d6211b614e034aac0aa43a4a4c7c392213b96e480bcb067917

See more details on using hashes here.

File details

Details for the file chdb-2.1.1-cp39-cp39-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp39-cp39-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 883cc393b4c88fb75250b508cb14840efa78c85f61266922ae1963d6b0f0cdb9
MD5 76b6cb9fe61f64c95883585203277027
BLAKE2b-256 77822840f11266e268d7270f047b34ec749fef5bec07d5f277a88dfd80c5db36

See more details on using hashes here.

File details

Details for the file chdb-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 83327fc062aacceba52e92cc8417da6304d59b7be1e10f2ae4d16058c5371d56
MD5 89fa0b1b61e9647e7e1ebbf649038523
BLAKE2b-256 1bd9c7c0e6f0eddca905ef813f37a83641689b6a7c5cc61a6d5af798413d540c

See more details on using hashes here.

File details

Details for the file chdb-2.1.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 47f6ba2524d0ec1a718bd1252594c62944c22554e7109fb640edbfac2f0b4179
MD5 c3e891bbdb40f069a5fb66184a3afd5f
BLAKE2b-256 4946487e6ebe43a124ff76e2dbb8dad3b39c310d986a8ed2b6cc82cba1ed5ac2

See more details on using hashes here.

File details

Details for the file chdb-2.1.1-cp38-cp38-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.1.1-cp38-cp38-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 cc6469e620a82d5823573aad0bd2c0752e7e90110f63a3980afc31465695667f
MD5 b9156465efe14041739fb0723bed7fd5
BLAKE2b-256 8bdb6829dce7257408abd1b76412b5e94e694b698ee27ece015e658572ae8700

See more details on using hashes here.

Supported by

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