Skip to content

Proxying a Standard logger to `containerlog

There may be times when your application relies on a framework, e.g. uvicorn and fastapi, and you want log output to be consistent between your application logs and those third-party libraries.

For libraries which use Python's built-in logging library, functionality exists to patch the logging.Logger instances used by third party libraries so they instead use a containerlog.proxy.std.StdLoggerProxy, which has the same interface as the logging.Logger, but uses a containerlog.Logger to do the actual logging.

To use it, you should call patch as early on in your application as possible. Passing no arguments to patch will update the logging.Manager so all existing instances of logging.Logger get replaced and sets the loggerClass on the manager so all future loggers get initialized as a StdLoggerProxy from the start.

If you do provide args, it will only replace the loggger(s) which match the name globs provided. Not only does it update the references in the logging.Manager, but it also traverses all imported modules and replaces the logger if it is defined in the module's global scope.

Note

Once you do this, you've allowed containerlog to go and modify things at Runtime. There are no capabilities current or planned to enable rolling back these modifications, so use at your own risk/convenience.

Example

Given a simple file, main.py defining a FastAPI app, e.g.

from fastapi import FastAPI

app = FastAPI(
    title='test application',
)

and running it with

uvicorn main:app --host 0.0.0.0

You'd get output similar to:

INFO:     Started server process [99362]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

Using containerlog, you can patch the standard logger for fastapi and uvicorn, e.g.

from fastapi import FastAPI
from containerlog.proxy.std import patch

patch('fastapi', 'uvicorn*', 'websockets*')

app = FastAPI(
    title='test application',
)

Re-running the same command as before, you should now see log output similar to:

timestamp='2020-07-24T15:36:00.981228Z' logger='uvicorn.error' level='info' event='Started server process [99395]' color_message='Started server process [%d]'
timestamp='2020-07-24T15:36:00.981435Z' logger='uvicorn.error' level='info' event='Waiting for application startup.'
timestamp='2020-07-24T15:36:00.981634Z' logger='uvicorn.error' level='info' event='Application startup complete.'
timestamp='2020-07-24T15:36:00.982344Z' logger='uvicorn.error' level='info' event='Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)' color_message='Uvicorn running on %s://%s:%d (Press CTRL+C to quit)'