Skip to content
LINEARJEPH
Sign inCreate account
Products
  • GPU Cloud
  • Maintenance
  • Cloud Servers
  • One-click Apps
  • AI Models
  • Developer Tools
Solutions
  • For Developers
  • For Startups
  • For AI Teams
  • For Agencies
  • For Enterprises
Resources
  • Open-Source Library
  • Technology Trends
  • Pricing
  • FAQ
Company
  • Legal & Privacy
  • Support
Sign inCreate account
Maintenance
OverviewPythonNode.jsGoIngest HTTP API

Python SDK

Package linearjeph 1.0.0, MIT licensed, Python 3.8+, no dependencies.

Install

pip install https://linearjeph.cc/sdk/linearjeph-1.0.0.tar.gz
# or from the public source repository
pip install "git+https://github.com/kingtechies/linearjeph-sdk@python/v1.0.0#subdirectory=python"

Quickstart

import linearjeph

linearjeph.init("lj_app_YOUR_KEY", release="1.4.2", environment="production")

try:
    risky()
except Exception as exc:
    linearjeph.capture_exception(exc)   # or just let it crash: unhandled exceptions are captured too

Get the key from Dashboard > Maintenance > your application > Reveal key. Prefer reading it from the environment: linearjeph.init(os.environ["LINEARJEPH_KEY"], ...).

init installs sys.excepthook and threading.excepthook (pass hooks=False to skip) and registers an atexit flush. It never raises and returns True when the SDK is enabled.

init

init(key, release=None, environment="production", endpoint="https://linearjeph.cc", **options) -> bool
ArgumentTypeDefaultMeaning
keystrrequiredApplication ingest key. An empty key leaves the SDK disabled.
releasestrNoneVersion or build identifier, up to 100 chars. Drives release tracking and regression detection.
environmentstr"production"Up to 40 chars, for example staging.
endpointstrhttps://linearjeph.ccBase URL; change only for a private deployment.
sample_ratefloat1.0Fraction of errors and messages sent, 0.0 to 1.0.
traces_sample_ratefloat1.0Fraction of transactions sent.
before_sendcallable(event) -> event or NoneNoneChange the event dict or return None to drop it. If it raises, the event is dropped.
scrub_keyslist[str][]Extra tag-key substrings to filter, case-insensitive.
max_queueint100Items waiting to be sent. When full, new items are dropped (never blocks).
batch_sizeint20Events per request, 1 to 100.
retriesint4Retries after the first attempt for 429, 5xx and network errors.
backofffloat0.5Base delay in seconds; doubles each attempt with jitter. A Retry-After header on 429 is used instead (max 60 s).
timeoutfloat10.0Seconds per HTTP request.
flush_timeoutfloat5.0Longest wait for the flush at interpreter exit.
in_app_excludetuple[str]site-packages, dist-packages, /lib/pythonFilename fragments for frames that are not your code (affects grouping).
hooksboolTrueInstall the uncaught exception hooks.
debugboolFalseLog SDK problems to the linearjeph logger at DEBUG.

Calling init again replaces the configuration (the previous queue is flushed first).

Functions

FunctionDescription
capture_exception(exc=None, tags=None)Report an exception. With no argument it reports the exception being handled. Accepts an exception instance or a sys.exc_info() tuple.
capture_message(message, level="info", tags=None)Report a message as an event of type Message. The level is added as the tag level.
capture_transaction(name, duration_ms, status="ok", tags=None)Report one timed operation.
start_transaction(name) / transaction(name)Context manager and decorator that times a block and reports it. Status is error if the block raises (the exception is not swallowed).
heartbeat(name, status="ok", interval_s=None)Check in. status is ok or error; interval_s is 30 to 2,592,000. name must match [A-Za-z0-9._-]{1,64}, otherwise the call is ignored.
monitor(name, interval_s=None, capture=False)Context manager and decorator for cron jobs: heartbeat ok on success, error if the block raises (then the exception continues). capture=True also reports the exception.
report_packages()Send the installed distributions to the dependency audit. Returns the number queued.
set_tag(key, value)Add a tag to every later event. At most 20 tags per event.
set_user(user_id)Attach a user id (a string you choose; None clears it).
scrub(data)Return a copy of a dict, list or string with sensitive values replaced by [Filtered].
flush(timeout=5.0)Block until the queue is delivered or the timeout passes. Returns True when empty.
close(timeout=5.0)Flush and stop the sender.
serialize_exception(type, value, tb)Build the raw error event (used by tests and custom integrations).

All functions return quickly and swallow their own errors.

Django

Add the middleware near the top of MIDDLEWARE and initialise in settings.py (or an AppConfig.ready):

# settings.py
import linearjeph, os

linearjeph.init(os.environ["LINEARJEPH_KEY"], release=os.environ.get("RELEASE"),
                environment=os.environ.get("ENVIRONMENT", "production"))

MIDDLEWARE = [
    "linearjeph.integrations.django.LinearjephMiddleware",
    # ...
]
LINEARJEPH_IGNORE_PATHS = ("/health", "/static/")   # optional, path prefixes not timed

The middleware times every request using the URL route (GET /items/<int:pk>/) and captures exceptions raised in views.

Flask

import linearjeph
from flask import Flask
from linearjeph.integrations.flask import init_app

linearjeph.init("lj_app_YOUR_KEY", release="1.4.2")
app = Flask(__name__)
init_app(app, ignore_paths=("/health",))

Request timings use the route rule (/items/<int:id>); unhandled exceptions are captured through Flask's got_request_exception signal.

FastAPI, Starlette and any ASGI app

import linearjeph
from fastapi import FastAPI
from linearjeph.integrations.asgi import LinearjephASGIMiddleware

linearjeph.init("lj_app_YOUR_KEY", release="1.4.2")
app = FastAPI()
app.add_middleware(LinearjephASGIMiddleware, ignore_paths=("/health",))

Transactions are named after the matched route when the framework provides it, otherwise the raw path. Exceptions that escape the app are captured and re-raised.

Performance beyond web requests

with linearjeph.start_transaction("nightly-import"):
    import_everything()

@linearjeph.transaction("send-invoice")
def send_invoice(order): ...

Transactions need the Professional plan or above.

Cron jobs and heartbeats

import linearjeph

linearjeph.init("lj_app_YOUR_KEY")

@linearjeph.monitor("nightly-report", interval_s=86400)
def main():
    build_report()

if __name__ == "__main__":
    main()      # the atexit flush delivers the heartbeat before the interpreter exits

The first check-in creates the monitor. If the job fails, or does not check in within the interval plus 5 minutes, an incident opens and alerts are sent. As a context manager: with linearjeph.monitor("sync", interval_s=900): .... Plain function: linearjeph.heartbeat("worker", "ok", interval_s=60).

Dependency audit

linearjeph.report_packages()   # call on startup or deploy, not per request

Sends every installed distribution (normalised lowercase name and version). The list is replaced on each call. In CI you can run it from a script after pip install, with the same init call.

Release tracking in CI

# .github/workflows/deploy.yml
env:
  RELEASE: ${{ github.ref_name }}+${{ github.run_number }}
linearjeph.init(os.environ["LINEARJEPH_KEY"], release=os.environ["RELEASE"])

A new release string on each deploy lets LINEARJEPH show which release introduced an issue and flag regressions of resolved issues.

Sampling

linearjeph.init(key, sample_rate=0.5, traces_sample_rate=0.1)   # half the errors, a tenth of transactions

Sampled-out events never leave the process. Sampling applies before before_send.

Scrubbing and before_send

Tag values under sensitive keys are replaced by [Filtered]: any key containing password, secret, token, authorization, auth, cookie, api_key, session, csrf, bearer, credential or private_key, plus your scrub_keys. Text such as password=hunter2 or Bearer eyJ... in exception and message text is masked too. The SDK does not read or send request headers, bodies, cookies or local variables.

def before_send(event):
    if event["type"] == "error" and "HealthCheckError" in event["exception"]["type"]:
        return None                       # drop
    event["tags"]["tenant"] = current_tenant()
    return event

linearjeph.init(key, before_send=before_send, scrub_keys=["ssn", "iban"])

Remember that anything you put in a tag is sent; use linearjeph.scrub(...) for your own structures.

Fork-based servers

gunicorn and uWSGI workers that fork after init are handled: each process starts its own sender thread and queue on first use. Call init once in the master or in each worker.

Troubleshooting

  • Turn on debug=True and attach a log handler for the linearjeph logger.
  • A 401 logs "ingest key rejected" once and stops sending: check the key and that the application is active.
  • init returns False when the key is empty.
  • Heartbeat names with spaces or other characters are ignored; use letters, digits, dot, dash, underscore.
  • capture_exception() with no active exception does nothing.
  • For python -c or other very short scripts, call linearjeph.flush() before exiting through os._exit.
  • See also Troubleshooting and the Ingest HTTP API.
LINEARJEPH LTD

Your infrastructure. Your tools. Your freedom to build.

    Products

    • GPU Cloud
    • Maintenance
    • Cloud Servers
    • One-click Apps
    • AI Models
    • Developer Tools

    Solutions

    • For Developers
    • For Startups
    • For AI Teams
    • For Agencies
    • For Enterprises

    Resources

    • Open-Source Library
    • Technology Trends
    • Pricing
    • FAQ

    Company

    • Legal & Privacy
    • Support
    © 2026 LINEARJEPH LTD. All rights reserved.
    Prices in USD. Taxes may apply.