Skip to main content

Implementation of Optimal Sparse Survival Trees

Project description

OSST Documentation

Implementation of Optimal Sparse Survival Trees (OSST), an optimal decision tree algorithm for survival analysis. This is implemented based on Generalized Optimal Sparse Decision Tree framework (GOSDT). If you need classification trees, please use GOSDT. If you need regression trees, please use Optimal Sparse Regression Trees (OSRT).


Installation

You may use the following commands to install OSST along with its dependencies on macOS, Ubuntu and Windows.
You need Python 3.9 or later to use the module osst in your project.

pip3 install attrs packaging editables pandas scikit-learn sortedcontainers gmpy2 matplotlib scikit-survival
pip3 install osst

You need to install gmpy2==2.0.a1 if You are using Python 3.12

Configuration

The configuration is a JSON object and has the following structure and default values:

{ 
  "regularization": 0.01,
  "depth_budget": 5,
  "minimum_captured_points": 7,
  "bucketize": false,
  "number_of_buckets": 0,
  "warm_LB": false,
  "path_to_labels": "",
  
  "uncertainty_tolerance": 0.0,
  "upperbound": 0.0,
  "worker_limit": 1,
  "precision_limit": 0,
  "model_limit": 1,
  "time_limit": 0,

  "verbose": false,
  "diagnostics": false,
  "look_ahead": true,

  "model": "",
  "timing": "",
  "trace": "",
  "tree": "",
  "profile": ""
}

Key parameters

regularization

  • Values: Decimal within range [0,1]
  • Description: Used to penalize complexity. A complexity penalty is added to the risk in the following way.
    ComplexityPenalty = # Leaves x regularization
    
  • Default: 0.01
  • Note: We highly recommend setting the regularization to a value larger than 1/num_samples. A small regularization could lead to a longer training time and possible overfitting.

depth_budget

  • Values: Integers >= 1
  • Description: Used to set the maximum tree depth for solutions, counting a tree with just the root node as depth 1. 0 means unlimited.
  • Default: 5

minimum_captured_points

  • Values: Integers >= 1
  • Description: Minimum number of sample points each leaf node must capture
  • Default: 7

bucketize

  • Values: true or false
  • Description: Enables bucketization of time threshold for training
  • Default: false

number_of_buckets

  • Values: Integers
  • Description: The number of time thresholds to which origin data mapping to if bucktize flag is set to True
  • Default: 0

warm_LB

  • Values: true or false
  • Description: Enables the reference lower bound
  • Default: false

path_to_labels

  • Values: string representing a path to a directory.
  • Description: IBS loss of reference model
  • Special Case: When set to empty string, no reference IBS loss are stored.
  • Default: Empty string

time_limit

  • Values: Decimal greater than or equal to 0
  • Description: A time limit upon which the algorithm will terminate. If the time limit is reached, the algorithm will terminate with an error.
  • Special Cases: When set to 0, no time limit is imposed.
  • Default: 0

More parameters

Flag

look_ahead

  • Values: true or false
  • Description: Enables the one-step look-ahead bound implemented via scopes
  • Default: true

diagnostics

  • Values: true or false
  • Description: Enables printing of diagnostic trace when an error is encountered to standard output
  • Default: false

verbose

  • Values: true or false
  • Description: Enables printing of configuration, progress, and results to standard output
  • Default: false

Tuners

uncertainty_tolerance

  • Values: Decimal within range [0,1]
  • Description: Used to allow early termination of the algorithm. Any models produced as a result are guaranteed to score within the lowerbound and upperbound at the time of termination. However, the algorithm does not guarantee that the optimal model is within the produced model unless the uncertainty value has reached 0.
  • Default: 0.0

upperbound

  • Values: Decimal within range [0,1]
  • Description: Used to limit the risk of model search space. This can be used to ensure that no models are produced if even the optimal model exceeds a desired maximum risk. This also accelerates learning if the upperbound is taken from the risk of a nearly optimal model.
  • Special Cases: When set to 0, the bound is not activated.
  • Default: 0.0

Limits

model_limit

  • Values: Decimal greater than or equal to 0
  • Description: The maximum number of models that will be extracted into the output.
  • Special Cases: When set to 0, no output is produced.
  • Default: 1

precision_limit

  • Values: Decimal greater than or equal to 0
  • Description: The maximum number of significant figures considered when converting ordinal features into binary features.
  • Special Cases: When set to 0, no limit is imposed.
  • Default: 0

worker_limit

  • Values: Decimal greater than or equal to 1
  • Description: The maximum number of threads allocated to executing th algorithm.
  • Special Cases: When set to 0, a single thread is created for each core detected on the machine.
  • Default: 1

Files

model

  • Values: string representing a path to a file.
  • Description: The output models will be written to this file.
  • Special Case: When set to empty string, no model will be stored.
  • Default: Empty string

profile

  • Values: string representing a path to a file.
  • Description: Various analytics will be logged to this file.
  • Special Case: When set to empty string, no analytics will be stored.
  • Default: Empty string

timing

  • Values: string representing a path to a file.
  • Description: The training time will be appended to this file.
  • Special Case: When set to empty string, no training time will be stored.
  • Default: Empty string

trace

  • Values: string representing a path to a directory.
  • Description: snapshots used for trace visualization will be stored in this directory
  • Special Case: When set to empty string, no snapshots are stored.
  • Default: Empty string

tree

  • Values: string representing a path to a directory.
  • Description: snapshots used for trace-tree visualization will be stored in this directory
  • Special Case: When set to empty string, no snapshots are stored.
  • Default: Empty string

Example

Example code to run OSST with lower bound guessing, and depth limit. The example python file is available in osst/example.py.

import pandas as pd
import numpy as np
from osst.model.osst import OSST
from osst.model.metrics import harrell_c_index, uno_c_index, integrated_brier_score, cumulative_dynamic_auc, compute_ibs_per_sample
from sklearn.model_selection import train_test_split
from sksurv.ensemble import RandomSurvivalForest
from sksurv.datasets import get_x_y
import pathlib


dataset_path = "experiments/datasets/churn/churn.csv"

# read the dataset
# preprocess your data otherwise OSST will binarize continuous feature using all threshold values.
df = pd.read_csv(dataset_path)
X, event, y = df.iloc[:,:-2].values, df.iloc[:,-2].values.astype(int), df.iloc[:,-1].values
h = df.columns[:-2]
X = pd.DataFrame(X, columns=h)
event = pd.DataFrame(event)
y = pd.DataFrame(y)
_, y_sksurv = get_x_y(df, df.columns[-2:], 1)
print("X shape: ", X.shape)
# split train and test set
X_train, X_test, event_train, event_test, y_train, y_test, y_sksurv_train, y_sksurv_test \
      = train_test_split(X, event, y, y_sksurv, test_size=0.2, random_state=2024)

times_train = np.unique(y_train.values.reshape(-1))
times_test = np.unique(y_test.values.reshape(-1))
print("Train time thresholds range: ({:.1f}, {:.1f}),  Test time thresholds range: ({:.1f}, {:.1f})".format(\
    times_train[0], times_train[-1], times_test[0], times_test[-1]))

# compute reference lower bounds
ref_model = RandomSurvivalForest(n_estimators=100, max_depth=3, random_state=2024)
ref_model.fit(X_train, y_sksurv_train)
ref_S_hat = ref_model.predict_survival_function(X_train)
ref_estimates = np.array([f(times_train) for f in ref_S_hat])
ibs_loss_per_sample = compute_ibs_per_sample(event_train, y_train, event_train, y_train, ref_estimates, times_train)

labelsdir = pathlib.Path('/tmp/warm_lb_labels')
labelsdir.mkdir(exist_ok=True, parents=True)

labelpath = labelsdir / 'warm_label.tmp'
labelpath = str(labelpath)

pd.DataFrame(ibs_loss_per_sample, columns=['class_labels']).to_csv(labelpath, header='class_labels', index=None)

# fit model

config = {
    "look_ahead": True,
    "diagnostics": True,
    "verbose": False,

    "regularization": 0.01,
    "uncertainty_tolerance": 0.0,
    "upperbound": 0.0,
    "depth_budget": 5,
    "minimum_captured_points": 7,

    "model_limit": 100,
    
    "warm_LB": True,
    "path_to_labels": labelpath,
  }


model = OSST(config)
model.fit(X_train, event_train, y_train)
print("evaluate the model, extracting tree and scores", flush=True)

# evaluation
n_leaves = model.leaves()
n_nodes = model.nodes()
time = model.time
print("Model training time: {}".format(time))
print("# of leaves: {}".format(n_leaves))

print("Train IBS score: {:.6f} , Test IBS score: {:.6f}".format(\
    model.score(X_train, event_train, y_train), model.score(X_test, event_test, y_test)))

S_hat_train = model.predict_survival_function(X_train)
estimates_train = np.array([f(times_train) for f in S_hat_train])

S_hat_test = model.predict_survival_function(X_test)
estimates_test = np.array([f(times_test) for f in S_hat_test])

print("Train Harrell's c-index: {:.6f}, Test Harrell's c-index: {:.6f}".format(\
    harrell_c_index(event_train, y_train, estimates_train, times_train)[0], \
    harrell_c_index(event_test, y_test, estimates_test, times_test)[0]))

print("Train Uno's c-index: {:.6f}, Test Uno's c-index: {:.6f}".format(\
    uno_c_index(event_train, y_train, event_train, y_train, estimates_train, times_train)[0],\
    uno_c_index(event_train, y_train, event_test, y_test, estimates_test, times_test)[0]))

print("Train AUC: {:.6f}, Test AUC: {:.6f}".format(\
    cumulative_dynamic_auc(event_train, y_train, event_train, y_train, estimates_train, times_train)[0],\
    cumulative_dynamic_auc(event_train, y_train, event_test, y_test, estimates_test, times_test)[0]))

print(model.tree)

Output

X shape:  (2000, 42)
Train time thresholds range: (0.0, 12.0),  Test time thresholds range: (0.0, 12.0)
osst reported successful execution
training completed. 4.968 seconds.
bounds: [0.168379..0.168379] (0.000000) IBS loss = 0.118379, iterations=16920
evaluate the model, extracting tree and scores
Model training time: 4.9679999351501465
# of leaves: 5
Train IBS score: 0.118379 , Test IBS score: 0.124289
Train Harrell's c-index: 0.737871, Test Harrell's c-index: 0.734727
Train Uno's c-index: 0.689405, Test Uno's c-index: 0.706680
Train AUC: 0.800940, Test AUC: 0.806016
if product_accounting_No = 1 then:
    predicted time: 4
    normalized loss penalty: 0.0
    complexity penalty: 0.01

else if csat_score_7 = 1 and product_accounting_No != 1 then:
    predicted time: 3
    normalized loss penalty: 0.0
    complexity penalty: 0.01

else if csat_score_7 != 1 and product_accounting_No != 1 and product_payroll_No = 1 then:
    predicted time: 2
    normalized loss penalty: 0.0
    complexity penalty: 0.01

else if csat_score_7 != 1 and csat_score_8 = 1 and product_accounting_No != 1 and product_payroll_No != 1 then:
    predicted time: 1
    normalized loss penalty: 0.0
    complexity penalty: 0.01

else if csat_score_7 != 1 and csat_score_8 != 1 and product_accounting_No != 1 and product_payroll_No != 1 then:
    predicted time: 0
    normalized loss penalty: 0.0
    complexity penalty: 0.01

License

This software is licensed under a 3-clause BSD license (see the LICENSE file for details).


Project details


Download files

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

Source Distribution

osst-0.1.4.tar.gz (6.0 MB view details)

Uploaded Source

Built Distributions

osst-0.1.4-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (536.2 kB view details)

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

osst-0.1.4-cp312-abi3-macosx_14_0_arm64.whl (577.2 kB view details)

Uploaded CPython 3.12+ macOS 14.0+ ARM64

osst-0.1.4-cp312-abi3-macosx_13_0_x86_64.whl (671.8 kB view details)

Uploaded CPython 3.12+ macOS 13.0+ x86-64

osst-0.1.4-cp312-abi3-macosx_12_0_x86_64.whl (660.7 kB view details)

Uploaded CPython 3.12+ macOS 12.0+ x86-64

osst-0.1.4-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (536.2 kB view details)

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

osst-0.1.4-cp311-abi3-macosx_14_0_arm64.whl (577.2 kB view details)

Uploaded CPython 3.11+ macOS 14.0+ ARM64

osst-0.1.4-cp311-abi3-macosx_13_0_x86_64.whl (671.8 kB view details)

Uploaded CPython 3.11+ macOS 13.0+ x86-64

osst-0.1.4-cp311-abi3-macosx_12_0_x86_64.whl (660.7 kB view details)

Uploaded CPython 3.11+ macOS 12.0+ x86-64

osst-0.1.4-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (536.2 kB view details)

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

osst-0.1.4-cp310-abi3-macosx_14_0_arm64.whl (577.2 kB view details)

Uploaded CPython 3.10+ macOS 14.0+ ARM64

osst-0.1.4-cp310-abi3-macosx_13_0_x86_64.whl (671.8 kB view details)

Uploaded CPython 3.10+ macOS 13.0+ x86-64

osst-0.1.4-cp310-abi3-macosx_12_0_x86_64.whl (660.7 kB view details)

Uploaded CPython 3.10+ macOS 12.0+ x86-64

osst-0.1.4-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (536.2 kB view details)

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

osst-0.1.4-cp39-abi3-macosx_14_0_arm64.whl (577.2 kB view details)

Uploaded CPython 3.9+ macOS 14.0+ ARM64

osst-0.1.4-cp39-abi3-macosx_13_0_x86_64.whl (671.8 kB view details)

Uploaded CPython 3.9+ macOS 13.0+ x86-64

osst-0.1.4-cp39-abi3-macosx_12_0_x86_64.whl (660.8 kB view details)

Uploaded CPython 3.9+ macOS 12.0+ x86-64

File details

Details for the file osst-0.1.4.tar.gz.

File metadata

  • Download URL: osst-0.1.4.tar.gz
  • Upload date:
  • Size: 6.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.0 CPython/3.9.19

File hashes

Hashes for osst-0.1.4.tar.gz
Algorithm Hash digest
SHA256 ef7063555e2c41f704bae67a4c32707b0db24528f1d6e7d5a812a3cbf2586477
MD5 c9e034d3c5977831085aa970912da715
BLAKE2b-256 1500918a1da40bd597275115578a85f2af3bf0e09c298b40c032b3b671d2eeaf

See more details on using hashes here.

File details

Details for the file osst-0.1.4-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.4-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 dd52bf0f6e0304a5095941f1d3ac18530402158d86031cd0ffea392973e425da
MD5 b87acfc53a3994b0471f9f4c1ab25c7f
BLAKE2b-256 64ea0cf288820a65323561892716ce28623f3eacdd30e940f457731f5cf75df2

See more details on using hashes here.

File details

Details for the file osst-0.1.4-cp312-abi3-macosx_14_0_arm64.whl.

File metadata

File hashes

Hashes for osst-0.1.4-cp312-abi3-macosx_14_0_arm64.whl
Algorithm Hash digest
SHA256 16d881096d733f0db27420cd721ab59d894ef6e661b9887dfdfda1eb2da4f107
MD5 de4b4d410a157829d212ab3cc9282b7d
BLAKE2b-256 c06d28ddb4fba42bfc1da251d9d30bb5b265094efad8f29091e247347ffee8f0

See more details on using hashes here.

File details

Details for the file osst-0.1.4-cp312-abi3-macosx_13_0_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.4-cp312-abi3-macosx_13_0_x86_64.whl
Algorithm Hash digest
SHA256 58ed843ccd75580fcde48597ad07eac4b8e4a1608795d1f81b16822bd06f3b45
MD5 e6a033564a4d3dcacabf8abc8102abbb
BLAKE2b-256 c8003165044272e7f89b4cde6f6bf59ff2ac8052ec0758c9ad2a6cf412c44c87

See more details on using hashes here.

File details

Details for the file osst-0.1.4-cp312-abi3-macosx_12_0_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.4-cp312-abi3-macosx_12_0_x86_64.whl
Algorithm Hash digest
SHA256 f9f81c57873876973533d221c43040585d7c2c3bb33f93441c1d0712d9a66816
MD5 8cd14c6a7b2d60b9c2cc4ccf5fbcf54b
BLAKE2b-256 23dcbd5294476075fb570652487b0b0a564f2ffe5619c1b57bc1651f7c5254fb

See more details on using hashes here.

File details

Details for the file osst-0.1.4-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.4-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 eeb226372d97b17791f09c6bebd65cddf995db015a3dedf9f82b0bcf9f5d1041
MD5 5309ac1d912dee5128a75dddc49dbf0b
BLAKE2b-256 72d392f4d9adeb7f7c063acd42991c50c32dfd73eb9963f463e44f061b0166f3

See more details on using hashes here.

File details

Details for the file osst-0.1.4-cp311-abi3-macosx_14_0_arm64.whl.

File metadata

File hashes

Hashes for osst-0.1.4-cp311-abi3-macosx_14_0_arm64.whl
Algorithm Hash digest
SHA256 6b2e6da6a7354a6396eeb854858d7366b2027400091e8d6a4c0de78661749ded
MD5 805d4a01c95d3971e3117a4735ab036a
BLAKE2b-256 bf955e24182f735091654a6dd61bb71f5c50108692308dee731bf0aec538d624

See more details on using hashes here.

File details

Details for the file osst-0.1.4-cp311-abi3-macosx_13_0_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.4-cp311-abi3-macosx_13_0_x86_64.whl
Algorithm Hash digest
SHA256 90f7d83e8ba35055da3c8ec2262569e6843efb83ad446fe853240266c59b34cc
MD5 b1641453fe9cf0cfcce2fb4b9b3e25c0
BLAKE2b-256 55db614fd1c7b667d4fb2a8bc675b8e44ed926551b463f04edda75eed5b1919d

See more details on using hashes here.

File details

Details for the file osst-0.1.4-cp311-abi3-macosx_12_0_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.4-cp311-abi3-macosx_12_0_x86_64.whl
Algorithm Hash digest
SHA256 4cf203e59b632a0a5090816ca5b08afed9c6c09713c31346afb06358a74a1142
MD5 581514362653000fe5982581ee804e35
BLAKE2b-256 bf62eb8e3813f9e6df791c397eb25176288976fb5836b89a34bf84fb1a19cb6f

See more details on using hashes here.

File details

Details for the file osst-0.1.4-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.4-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 5685961bf4fe449e013680144335aaaa43a13df9b69d18a6826338e18b69a3e1
MD5 85a4b40dbdb3786e021fb499a59badcc
BLAKE2b-256 3f8227cf9893d48607fc5682e2602e0e7b4dc78f44f03f132f213c4ec0b5379d

See more details on using hashes here.

File details

Details for the file osst-0.1.4-cp310-abi3-macosx_14_0_arm64.whl.

File metadata

File hashes

Hashes for osst-0.1.4-cp310-abi3-macosx_14_0_arm64.whl
Algorithm Hash digest
SHA256 cc7ae711b6e484e987cca97b73b88b64c87de16997b27b91031de421708e399f
MD5 6b44e4b121179efc17aa4da1dbfc2da7
BLAKE2b-256 2ec8afc67be1cb94c749441b56c7d5da96e6d3606bc93d1df6c31355d9b3d8cc

See more details on using hashes here.

File details

Details for the file osst-0.1.4-cp310-abi3-macosx_13_0_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.4-cp310-abi3-macosx_13_0_x86_64.whl
Algorithm Hash digest
SHA256 cd19277111cdc49ec11c8fac46d44a5c476b610cdc72fb2e2d3f0887e767dfa0
MD5 0faddfdf19282528665af2307775da71
BLAKE2b-256 ca11d05dd0699c9aae38fbe5207c05654fd3e6125d6a8276e35770628420980a

See more details on using hashes here.

File details

Details for the file osst-0.1.4-cp310-abi3-macosx_12_0_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.4-cp310-abi3-macosx_12_0_x86_64.whl
Algorithm Hash digest
SHA256 1486d7550cb8354102473c84dc4aeaa0f0e1ffbc2d5b32a3f1446a8d59b03626
MD5 e0574da68c2bee694d6bba41e22aafcd
BLAKE2b-256 a6786ed0811773cc840f78d1f6dfe07f818203cee1b705a5f54c0b12d59108dd

See more details on using hashes here.

File details

Details for the file osst-0.1.4-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.4-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 23b64e1a9dd56cad2a36bc1426a7e4b4bea62bc8ab55cb4da7aeee0851905d3d
MD5 f48f389e089c734e9c2b53d6d1d63384
BLAKE2b-256 1521d3ba7cee902bc94b4e8c02bfcf53ea2bfbbd1636ac8bb307b56a735b340d

See more details on using hashes here.

File details

Details for the file osst-0.1.4-cp39-abi3-macosx_14_0_arm64.whl.

File metadata

File hashes

Hashes for osst-0.1.4-cp39-abi3-macosx_14_0_arm64.whl
Algorithm Hash digest
SHA256 2236112e03d5d99f65ce65151023870877fbb8f3696efbbb3401001ed3fbe45f
MD5 e1388dfb14d17485f73b47b8a5016a04
BLAKE2b-256 70e0405bf27a41eaf758bf340813c68941b95f930bc26fb997bb3f4751b7ad40

See more details on using hashes here.

File details

Details for the file osst-0.1.4-cp39-abi3-macosx_13_0_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.4-cp39-abi3-macosx_13_0_x86_64.whl
Algorithm Hash digest
SHA256 5a4766254c3dab6cd722eed3034fc4fd4ddf31a69a0ac9bb025080e0642b2520
MD5 f4301067d9fcc3f6ea69e5f39fd7d59a
BLAKE2b-256 56e62f48c9b6759153b153891dbd5ec029b6faf248cf24e3c35fbddce7fa3e56

See more details on using hashes here.

File details

Details for the file osst-0.1.4-cp39-abi3-macosx_12_0_x86_64.whl.

File metadata

File hashes

Hashes for osst-0.1.4-cp39-abi3-macosx_12_0_x86_64.whl
Algorithm Hash digest
SHA256 a7809d09733d6eac9a4eb7830362e68520e77131cd6b146875658db7cc92766f
MD5 580dc82867612cd950a8aba25a37a139
BLAKE2b-256 eee374c806ced850a0eca497314f5b84b6db61f6f1ca12ff2ca298dff1ed0373

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