# Logging

aiohttp uses standard `logging` for tracking the library activity.

We have the following loggers enumerated by names:

- `'aiohttp.access'`

- `'aiohttp.client'`

- `'aiohttp.internal'`

- `'aiohttp.server'`

- `'aiohttp.web'`

- `'aiohttp.websocket'`

You may subscribe to these loggers for getting logging messages. The page does not provide instructions for logging subscribing while the most friendly method is `logging.config.dictConfig()` for configuring whole loggers in your application.

Logging does not work out of the box. It requires at least minimal `'logging'` configuration. Example of minimal working logger setup:

    import logging
    from aiohttp import web

    app = web.Application()
    logging.basicConfig(level=logging.DEBUG)
    web.run_app(app, port=5000)

New in version 4.0.0.

## Access logs

Access logs are enabled by default. If the debug flag is set, and the default logger `'aiohttp.access'` is used, access logs will be output to `stderr` if no handlers are attached. Furthermore, if the default logger has no log level set, the log level will be set to `logging.DEBUG`.

This logging may be controlled by `aiohttp.web.AppRunner()` and `aiohttp.web.run_app()`.

To override the default logger, pass an instance of `logging.Logger` to override the default logger.

Note

Use `web.run_app(app, access_log=None)` to disable access logs.

In addition, access_log_format may be used to specify the log format.

### Format specification

The library provides custom micro-language to specifying info about request and response:

Option | Meaning
--- | ---
`%%` | The percent sign
`%a` | Remote IP-address (IP-address of proxy if using reverse proxy)
`%t` | Time when the request was started to process
`%P` | The process ID of the child that serviced the request
`%r` | First line of request
`%s` | Response status code
`%b` | Size of response in bytes, including HTTP headers
`%T` | The time taken to serve the request, in seconds
`%Tf` | The time taken to serve the request, in seconds with fraction in %.06f format
`%D` | The time taken to serve the request, in microseconds
`%{FOO}i` | `request.headers['FOO']`
`%{FOO}o` | `response.headers['FOO']`

The default access log format is:

    '%a %t "%r" %s %b "%{Referer}i" "%{User-Agent}i"'

New in version 2.3.0.

access_log_class introduced.

Example of a drop-in replacement for the default access logger:

    from aiohttp.abc import AbstractAccessLogger

    class AccessLogger(AbstractAccessLogger):

        def log(self, request, response, time):
            self.logger.info(f'{request.remote} '
                             f'"{request.method} {request.path} '
                             f'done in {time}s: {response.status}')

### Gunicorn access logs

When Gunicorn is used for deployment, its default access log format will be automatically replaced with the default aiohttp’s access log format.

If Gunicorn’s option access_logformat is specified explicitly, it should use aiohttp’s format specification.

Gunicorn’s access log works only if accesslog is specified explicitly in your config or as a command line option. This configuration can be either a path or `'-'`. If the application uses a custom logging setup intercepting the `'gunicorn.access'` logger, accesslog should be set to `'-'` to prevent Gunicorn to create an empty access log file upon every startup.

## Error logs

`aiohttp.web` uses a logger named `'aiohttp.server'` to store errors given on web requests handling.

This log is enabled by default.

To use a different logger name, pass logger (`logging.Logger` instance) to the `aiohttp.web.AppRunner()` constructor.