BugsRadar

BugsRadar for Python

One package from PyPI for Python 3.9 and later: the standard logging module, uncaught exceptions and direct calls, with no dependencies outside the standard library.

You need a BugsRadar project with a channel and the project's API key first: see Get started.

The API key is secret: use it only in code that runs on your servers. Never put it in a desktop app you ship to others — PyInstaller, PySide or PyQt builds — or in a public repository: anyone can take the key out of them. For such apps, public keys are on the way. Where the key may go

Install the package

Terminal
pip install bugsradar

Set it up

Call init once, at the start of the program:

main.py
import os
import bugsradar

bugsradar.init(
    api_key=os.environ["BUGSRADAR_KEY"],
    environment="Production",  # optional
)

init connects BugsRadar to logging and to uncaught exceptions. It adds no handlers, so your logging setup works as before. Keep the key out of the source, for example in an environment variable. The key is required: an empty one raises ValueError.

logging

Records at ERROR and above go to BugsRadar from every logger, whatever handlers your logging setup has:

orders.py
import logging

logger = logging.getLogger(__name__)

try:
    create_order(order_id)
except Exception:
    logger.exception("Order %s failed", order_id)

logger.exception and exc_info=True bring the exception with its traceback. The format string Order %s failed becomes the message template, so failures of different orders are one error with a count, not a message each.

Choose another level with logging_level=logging.WARNING. To leave logging alone, pass logging_level=None and add bugsradar.LoggingHandler() to the loggers you choose.

Uncaught exceptions

init sets sys.excepthook and threading.excepthook. An exception that ends the program or a thread is reported, BugsRadar waits up to shutdown_timeout for the report to leave, and then the previous hook runs as before: the traceback is still printed. Pass capture_uncaught=False to turn this off.

Direct calls

orders.py
try:
    create_order(order_id)
except Exception as error:
    bugsradar.send_exception(error, module="Orders")

    # or the full event
    bugsradar.send(
        exception=error,
        message_template="Order {order_id} failed",
        message=f"Order {order_id} failed",
        properties={"order_id": order_id},
        module="Orders",
    )

send and send_exception queue the event and return at once, so reporting an error never adds network time to your code. Nothing raises: delivery problems are logged as warnings by the bugsradar logger, which BugsRadar itself never sends anywhere.

Django

Django logs every unhandled exception of a view to the django.request logger, so init in settings.py is enough. Your LOGGING setting stays as it is:

settings.py
import os
import bugsradar

bugsradar.init(api_key=os.environ["BUGSRADAR_KEY"])

Flask

Flask logs unhandled exceptions through app.logger, so init is enough:

app.py
import os
import bugsradar
from flask import Flask

bugsradar.init(api_key=os.environ["BUGSRADAR_KEY"])
app = Flask(__name__)

FastAPI

Uvicorn logs every unhandled exception to its uvicorn.error logger, so init is enough. To see the path of the request as well, report from an exception handler; the error still arrives once:

main.py
import os
import bugsradar
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

bugsradar.init(api_key=os.environ["BUGSRADAR_KEY"])
app = FastAPI()

@app.exception_handler(Exception)
async def report_error(request: Request, error: Exception):
    bugsradar.send_exception(error, properties={"path": request.url.path})
    return JSONResponse(status_code=500, content={"detail": "Internal Server Error"})

Before the program exits

init registers an atexit hook that waits up to shutdown_timeout for queued reports. In a short script you can also wait yourself:

job.py
bugsradar.flush()  # waits up to shutdown_timeout

How events travel

Configuration

Argument of initDefaultMeaning
api_key—Project API key from app.bugsradar.com. Required.
environmentNoneEnvironment name for events (Production, Staging).
hostsocket.gethostname()Host for events.
app_versionNoneVersion of your application. Not used for grouping.
logging_levellogging.ERRORLowest level of the log records that go to BugsRadar; None leaves logging alone.
capture_uncaughtTrueReport exceptions that end the program or a thread.
repeat_interval5 sRepeats within this interval travel as one request.
queue_capacity1000Queued events beyond this are dropped with a warning.
shutdown_timeout5 sHow long flush(), the exit hook and an uncaught exception wait for the queue.
request_timeout15 sOne request to the server.
api_urlapi.bugsradar.comChange it only for a self-hosted BugsRadar.

Something doesn't arrive? Write to support@bistriy.com and include the warnings of the bugsradar logger.