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.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (108.0 MB view details)

Uploaded CPython 3.12 manylinux: glibc 2.17+ ARM64

chdb-2.0.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (134.8 MB view details)

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

chdb-2.0.2-cp312-cp312-macosx_11_0_arm64.whl (73.6 MB view details)

Uploaded CPython 3.12 macOS 11.0+ ARM64

chdb-2.0.2-cp312-cp312-macosx_10_15_x86_64.whl (92.1 MB view details)

Uploaded CPython 3.12 macOS 10.15+ x86-64

chdb-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (108.0 MB view details)

Uploaded CPython 3.11 manylinux: glibc 2.17+ ARM64

chdb-2.0.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (134.8 MB view details)

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

chdb-2.0.2-cp311-cp311-macosx_11_0_arm64.whl (73.6 MB view details)

Uploaded CPython 3.11 macOS 11.0+ ARM64

chdb-2.0.2-cp311-cp311-macosx_10_15_x86_64.whl (92.1 MB view details)

Uploaded CPython 3.11 macOS 10.15+ x86-64

chdb-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (108.0 MB view details)

Uploaded CPython 3.10 manylinux: glibc 2.17+ ARM64

chdb-2.0.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (134.8 MB view details)

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

chdb-2.0.2-cp310-cp310-macosx_11_0_arm64.whl (73.6 MB view details)

Uploaded CPython 3.10 macOS 11.0+ ARM64

chdb-2.0.2-cp310-cp310-macosx_10_15_x86_64.whl (92.1 MB view details)

Uploaded CPython 3.10 macOS 10.15+ x86-64

chdb-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (108.0 MB view details)

Uploaded CPython 3.9 manylinux: glibc 2.17+ ARM64

chdb-2.0.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (134.8 MB view details)

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

chdb-2.0.2-cp39-cp39-macosx_11_0_arm64.whl (73.6 MB view details)

Uploaded CPython 3.9 macOS 11.0+ ARM64

chdb-2.0.2-cp39-cp39-macosx_10_15_x86_64.whl (92.1 MB view details)

Uploaded CPython 3.9 macOS 10.15+ x86-64

chdb-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (108.0 MB view details)

Uploaded CPython 3.8 manylinux: glibc 2.17+ ARM64

chdb-2.0.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (134.8 MB view details)

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

chdb-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl (92.1 MB view details)

Uploaded CPython 3.8 macOS 10.15+ x86-64

File details

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

File metadata

File hashes

Hashes for chdb-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 854075d09a321003fe423c18e71908262a9c72f189942d0ebcf8072aed8dd4f8
MD5 9c31b217db6b14c4eadae34a06cbc147
BLAKE2b-256 a0284cefd61264e4832f6b7fee697275e347628768fd073153308a001192adad

See more details on using hashes here.

File details

Details for the file chdb-2.0.2-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.0.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 e13ff068bed262a2385d617c63d4899997057a4ddb446ba1d413a65c0322974a
MD5 ed5cb87f2db1e9806ba55ef143c6ae8a
BLAKE2b-256 843d777efe791f9aed386fc94c7790d314faca6233726f554b82394978180db3

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for chdb-2.0.2-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 948d246a9568cad0715f7c2d359d24a67719e08fcf443a8320f2f9aada7d5455
MD5 fd4e03a8ff27333d4ddde015bbea331f
BLAKE2b-256 33ba346b0dffb267430c8c170881042948048724a037cf2c2b9a6e9c98dc7baf

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for chdb-2.0.2-cp312-cp312-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 77043fc56f509aaf466be6a6e9bec60408a397729334f68d528300e1af4b5acb
MD5 6e1731d3608567ff453c51e703c387ee
BLAKE2b-256 2cf6b0f6d235044a0a395234182c08d7285bc33d7aa8fc4d83618fa9f7bf8f2e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for chdb-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 4cc2b59fd3dff3e536a0e5d408a0b1e36d70f9f2960a5dbe42c9d0fc2671c48c
MD5 cdc88aa431f354e1b149f063704a7026
BLAKE2b-256 e787fb5e8353b97630d4f9cfe48f12399f7c5b8a76cf671314560428ed704746

See more details on using hashes here.

File details

Details for the file chdb-2.0.2-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.0.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 47c33cebd960a5b02c98479cf06b8353ba5e6f6d6659f60c173a1d9bf3ad1bf4
MD5 6dc044df72785e5c51f4d7f857f488f8
BLAKE2b-256 7d8062e5fd32d0f00e728c8ccaf00136cf341157c4b4d9f62694426d03a93252

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for chdb-2.0.2-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 411c7d5cef57cb27244bb2627a937aba218bc8c6c82d1e18b1cc1ebabce8173f
MD5 17ecda2f49a2a65aecb153f2c45ccfce
BLAKE2b-256 2e795fab5cdb7a171b40858e026e28835c177d598959804708d7aea1c2e00590

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for chdb-2.0.2-cp311-cp311-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 111fd6cd6264b4608bdfe0a565c73664c7c49dffcf0d34b2f180048151170806
MD5 23a5b129dee9fb40eb4844c1bfc6f644
BLAKE2b-256 8629bc4920dbfcf2415c1678add9346531a867fe7a552a41befb9f25253b33c5

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for chdb-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 dca19265fab6964f444b064646b431d56a986fd4630a153b48755bd83cd9e8e9
MD5 b5f42a8fca65134e2e0787010cfe0e8a
BLAKE2b-256 7645b2aaa9d8a0acbaa6341f3f5b1774ffc9664168a766e1a0022cb401671252

See more details on using hashes here.

File details

Details for the file chdb-2.0.2-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.0.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0885a29b8b3d9a9f5c807c1abca024864e5e0c83826acdb4a385d405741dc47e
MD5 05cae7ffb4aeef5a0258eab527016205
BLAKE2b-256 c27fcbd2dcb2c4a666c14e3758c707a7f2ce41c714c52d045b8362b13bf8cc01

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for chdb-2.0.2-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 97294f35e8ad18f7f3045ae9b6a3f945efac4fc20bfec62cfd4204cafe265b23
MD5 7c14e8baa3e092d04db43ad134ad34d1
BLAKE2b-256 e55383870327134b867332476714134dd5bb0543b96a3521d363deb5a1969487

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for chdb-2.0.2-cp310-cp310-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 f59507b95f694b5080ec717a5e67b02da9c5e0ab459d4cd5ea74f9e3efddd45f
MD5 976b4d886a25192f75526f603fcefc13
BLAKE2b-256 4de8f4448bf6a7db7f54eeee0cc187e1ccf58fb369c10d5a1a28029f8da3aa72

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for chdb-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 490d7bbc1536c5d4852ced0c7c7f4eb68b1b9493dd04fc331bd3f9bc294f6f3b
MD5 cf24e6fc385b1dfc0aa5532ef0a28548
BLAKE2b-256 0492bfcb68d0d513837712083f1060a2b0fcc2045629d17a05069715476db920

See more details on using hashes here.

File details

Details for the file chdb-2.0.2-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.0.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ac393f896bfa1c1ed9bc8ae5a97a12b3e45d67fa8e368cdd5ecc3569225f00bf
MD5 af642a5572742db70103185f79855ee8
BLAKE2b-256 b7d3d3944085844aaff13228ca8890de808016af86dcc39364cee38fb8df7f4d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for chdb-2.0.2-cp39-cp39-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 f6693e8b73077e14717b65c04cbd25288635b73bf49ef48de8d20583ad1e34f8
MD5 e74917fa8040b98d832a21fb7097d731
BLAKE2b-256 4582ab41dffeada045bad1bd7ab6ea3adb0eba5f9fdebc77cd3d0c01c372cc58

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for chdb-2.0.2-cp39-cp39-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 2feb7e18bd070eafb31e2bc63168571edfd427da1a45dc928281dd14908b8c5b
MD5 4dc732683c06a56a3821fa38b64074b6
BLAKE2b-256 a3d5fe5977064aeb5879fe113fe5b6350e49f0fa04eed8365dffe4d6f32b4d5a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for chdb-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 eaf9926647ca5d4f602deadb2f3c1b1a5d7337636b50992863ed2044a9ce6398
MD5 4f31a40d3f19b37239af920a17e13379
BLAKE2b-256 55c1151a9504b9c3698bd4b25531b7b731777abdc445d396ada0fcfca574d713

See more details on using hashes here.

File details

Details for the file chdb-2.0.2-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.0.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 d57558bb634f6371868cf457b0a8020f63fba7d2cad1bf3d8559517a7ec14619
MD5 91d3ca3a92af31ddff0b5b56ba47578b
BLAKE2b-256 aa0d746112857da342f4259b9934112c033166f2b56b06ac60c3104680c8dcb7

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for chdb-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 7697fedb4b06f394165f21f085f5ccdcf1879fd6dbed554f174b259d83ff0112
MD5 a57dcab7ccdb476dce782061f168d6a2
BLAKE2b-256 e198fdd69f21ba7f14a599d30c5e4f8391eb466ebdfc630cd36abfb33853e0af

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