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
pip install bugsradar
Set it up
Call init once, at the start of the program:
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:
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
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:
import os
import bugsradar
bugsradar.init(api_key=os.environ["BUGSRADAR_KEY"])
Flask
Flask logs unhandled exceptions through app.logger, so init is enough:
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:
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:
bugsradar.flush() # waits up to shutdown_timeout
How events travel
- Events go to a queue and are sent by a background thread; your code never waits for the network.
- Repeats of the same error within
repeat_interval(5 seconds) are folded into one request with a count. A crash loop costs one request every few seconds, not thousands per second. - The same exception object seen twice — logged and reported by hand — is sent once.
- On
429the client waits as long as the server asks; on5xxand network failures it retries three times.
Configuration
Argument of init | Default | Meaning |
|---|---|---|
api_key | — | Project API key from app.bugsradar.com. Required. |
environment | None | Environment name for events (Production, Staging). |
host | socket.gethostname() | Host for events. |
app_version | None | Version of your application. Not used for grouping. |
logging_level | logging.ERROR | Lowest level of the log records that go to BugsRadar; None leaves logging alone. |
capture_uncaught | True | Report exceptions that end the program or a thread. |
repeat_interval | 5 s | Repeats within this interval travel as one request. |
queue_capacity | 1000 | Queued events beyond this are dropped with a warning. |
shutdown_timeout | 5 s | How long flush(), the exit hook and an uncaught exception wait for the queue. |
request_timeout | 15 s | One request to the server. |
api_url | api.bugsradar.com | Change it only for a self-hosted BugsRadar. |
Something doesn't arrive? Write to support@bistriy.com and include the warnings of the bugsradar logger.