Skip to main content
LogBrew is an observability platform for developers and coding agents, with a generous free tier and no card needed. This guide covers Python logging with the standard logging module, the 5 Python log levels, Python error handling, and the common Python error types. The last sections send the same logs and crashes to LogBrew with logbrew-sdk 0.1.29. Each example ran on Python 3.13, and each output block shows its real output. For a Flask app, use Flask logging instead. It adds request traces to the same logging setup.

Write your first Python log

Save this file as app.py. Call logging.basicConfig() once, at the entry point of the program. Get a named logger in each module.
Run python3 app.py. The output goes to standard error.
The debug record does not appear, because the level is INFO. logger.exception() logs at ERROR and adds the traceback. Call it only in an except block. Pass values as arguments, as in "payment retry %d of %d", 2, 3. Python builds the message only when a handler accepts the record. The message template stays the same for every retry, so you can search for it.

Python log levels

A logger sends a record only when the record level is equal to or higher than the logger level. A handler can set a second, higher level. The root logger starts at WARNING. A new logger has the level NOTSET (0) and uses the level of its parent. Set INFO in production and DEBUG only in development or for a short diagnosis.
The first line shows debug records for one module. The second line removes noise from a library.

Loggers, handlers, and formatters

  • A logger receives the call. Use logging.getLogger(__name__) so the logger name follows the module path.
  • A handler sends records to a destination, such as the console, a file, or LogBrew.
  • A formatter turns a record into text.
A library must not configure logging. It adds only a logging.NullHandler() to its own logger. The application configures handlers and levels once. For a large configuration, use logging.config.dictConfig().

Python error handling

Catch the most specific exception that you can handle. Use else for code that runs only on success and finally for code that always runs. Use raise ... from error to keep the original cause. Save this file as orders.py.
The output shows both exceptions in the chain.
Follow these rules for each exception.
  • Log an exception once, where you handle it. Do not log it and raise it again at each layer, because each layer adds a duplicate record.
  • Do not write except Exception: pass. If you ignore an error, log it at WARNING or higher with the reason.
  • Catch Exception, not BaseException. BaseException also catches KeyboardInterrupt and SystemExit, which stop the program on purpose.
  • Define your own exception classes for errors that callers must handle, as OrderError does.

Report more than one error

Python 3.11 and newer can raise an ExceptionGroup. Use it when one check finds more than one problem. Handle each type with except*.

Common Python error types

All built-in errors that a program can handle inherit from Exception. This table lists the Python errors that you see most often and the first check for each. KeyboardInterrupt and SystemExit inherit from BaseException, not Exception. They are not errors in your code.

Send Python logs to LogBrew

LogBrewLoggingHandler is a standard logging handler. It sends each record that it accepts to LogBrew. The console handler stays the same.
1

Create a project key

Sign in with the CLI. Create a project and store its ingest key in an owner-only file.
The CLI does not print the key. In production, use the secret manager of your platform.
2

Install the SDK

Activate the virtual environment of the application. Then install the package. It requires Python 3.10 or newer.
3

Set the key and the deployment identity

The client adds the service, environment, and release to each event.
4

Add the handler

Save this file as worker.py. Call logging.basicConfig() before you create the client. The client adds a handler to the root logger, and basicConfig() does nothing when the root logger already has a handler.
HttpTransport() sends events in the background, 1 second after the first event or at 50 events. client.shutdown() sends the remaining events and closes the client.
5

Run the program

The console output does not change. LogBrew receives 1 log event for each record. This is the first event, without the shared runtime context.
Primitive values from extra={...} become metadata. The second event has exceptionName KeyError and exceptionMessage 'seats'. To send the full traceback text, create the handler with include_exception_text=True.
6

Read the logs back

A matching read shows that LogBrew stored the logs. To read from CI or a coding agent, use a project read key. See Verify your setup.

Choose which records go to LogBrew

Give the handler its own level to send fewer records. The console still gets INFO and higher.
Python levels become LogBrew levels. The original level name and number stay in metadata.

Report Python crashes as issues

install_process_error_capture(client) reports uncaught exceptions in scripts, workers, startup code, and threads. Each crash becomes 1 issue with the exception type, the message, the stack frames, and the chained causes. Python still prints the traceback and exits as before. Save this file as startup.py and run it.
LogBrew receives an issue with the title FileNotFoundError, the level critical, and the mechanism python.excepthook. Its frames contain the file name, line, and function, but not the full path. A crash in a thread has the level error. Before Python exits, the SDK waits at most 2 seconds for delivery.
The issue includes the exception message. Do not put credentials or personal data in exception messages or log messages. See Safe capture.

Recover from problems

For web apps, see Flask logging. To choose a log format, see Structured logging. For other runtimes, see SDK integration.