Skip to content

Logging

Uvicorn uses Python's built-in logging module, and provides three loggers out of the box:

Logger name Purpose
uvicorn Parent logger (rarely used directly)
uvicorn.error Server-level messages (startup, shutdown, errors)
uvicorn.access Per-request access log lines

Note

Despite its name, uvicorn.error is not limited to error messages. It is the general-purpose server logger, similar to how Gunicorn names its main logger. See #562 for background.

Default Configuration

By default, Uvicorn applies the following dictConfig() configuration:

LOGGING_CONFIG = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "default": {
            "()": "uvicorn.logging.DefaultFormatter",
            "fmt": "%(levelprefix)s %(message)s",
            "use_colors": None,
        },
        "access": {
            "()": "uvicorn.logging.AccessFormatter",
            "fmt": '%(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s',
        },
    },
    "handlers": {
        "default": {
            "formatter": "default",
            "class": "logging.StreamHandler",
            "stream": "ext://sys.stderr",
        },
        "access": {
            "formatter": "access",
            "class": "logging.StreamHandler",
            "stream": "ext://sys.stdout",
        },
    },
    "loggers": {
        "uvicorn": {"handlers": ["default"], "level": "INFO", "propagate": False},
        "uvicorn.error": {"level": "INFO"},
        "uvicorn.access": {"handlers": ["access"], "level": "INFO", "propagate": False},
    },
}

Custom Logging Configuration

You can supply a custom logging configuration file with the --log-config option (or log_config when calling uvicorn.run()).

Uvicorn supports three file formats:

Extension Loader Notes
.json logging.config.dictConfig Standard JSON dictConfig schema.
.yaml/.yml logging.config.dictConfig Requires PyYAML (uvicorn[standard]).
Any other logging.config.fileConfig Classic INI-style format.

YAML Example

Create a file named log_config.yaml:

version: 1
disable_existing_loggers: false
formatters:
  default:
    "()": uvicorn.logging.DefaultFormatter
    fmt: "%(asctime)s - %(levelprefix)s %(message)s"
    datefmt: "%Y-%m-%d %H:%M:%S"
    use_colors: null
  access:
    "()": uvicorn.logging.AccessFormatter
    fmt: '%(asctime)s - %(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s'
    datefmt: "%Y-%m-%d %H:%M:%S"
handlers:
  default:
    formatter: default
    class: logging.StreamHandler
    stream: ext://sys.stderr
  access:
    formatter: access
    class: logging.StreamHandler
    stream: ext://sys.stdout
loggers:
  uvicorn:
    handlers:
      - default
    level: INFO
    propagate: false
  uvicorn.error:
    level: INFO
  uvicorn.access:
    handlers:
      - access
    level: INFO
    propagate: false

Then pass it to Uvicorn:

uvicorn main:app --log-config log_config.yaml
uvicorn.run("main:app", log_config="log_config.yaml")

JSON Example

Create a file named log_config.json:

{
  "version": 1,
  "disable_existing_loggers": false,
  "formatters": {
    "default": {
      "()": "uvicorn.logging.DefaultFormatter",
      "fmt": "%(asctime)s - %(levelprefix)s %(message)s",
      "datefmt": "%Y-%m-%d %H:%M:%S",
      "use_colors": null
    },
    "access": {
      "()": "uvicorn.logging.AccessFormatter",
      "fmt": "%(asctime)s - %(levelprefix)s %(client_addr)s - \"%(request_line)s\" %(status_code)s",
      "datefmt": "%Y-%m-%d %H:%M:%S"
    }
  },
  "handlers": {
    "default": {
      "formatter": "default",
      "class": "logging.StreamHandler",
      "stream": "ext://sys.stderr"
    },
    "access": {
      "formatter": "access",
      "class": "logging.StreamHandler",
      "stream": "ext://sys.stdout"
    }
  },
  "loggers": {
    "uvicorn": {
      "handlers": ["default"],
      "level": "INFO",
      "propagate": false
    },
    "uvicorn.error": {
      "level": "INFO"
    },
    "uvicorn.access": {
      "handlers": ["access"],
      "level": "INFO",
      "propagate": false
    }
  }
}

Programmatic dictConfig

You can also pass a dictionary directly when running programmatically:

import uvicorn

log_config = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "default": {
            "()": "uvicorn.logging.DefaultFormatter",
            "fmt": "%(asctime)s - %(levelprefix)s %(message)s",
            "datefmt": "%Y-%m-%d %H:%M:%S",
        },
        "access": {
            "()": "uvicorn.logging.AccessFormatter",
            "fmt": '%(asctime)s - %(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s',
            "datefmt": "%Y-%m-%d %H:%M:%S",
        },
    },
    "handlers": {
        "default": {
            "formatter": "default",
            "class": "logging.StreamHandler",
            "stream": "ext://sys.stderr",
        },
        "access": {
            "formatter": "access",
            "class": "logging.StreamHandler",
            "stream": "ext://sys.stdout",
        },
    },
    "loggers": {
        "uvicorn": {"handlers": ["default"], "level": "INFO", "propagate": False},
        "uvicorn.error": {"level": "INFO"},
        "uvicorn.access": {"handlers": ["access"], "level": "INFO", "propagate": False},
    },
}

uvicorn.run("main:app", log_config=log_config)

Common Recipes

Writing Logs to a File

To write Uvicorn's server logs to a file in addition to the console, add a FileHandler to the uvicorn logger:

version: 1
disable_existing_loggers: false
formatters:
  default:
    "()": uvicorn.logging.DefaultFormatter
    fmt: "%(asctime)s - %(levelprefix)s %(message)s"
    datefmt: "%Y-%m-%d %H:%M:%S"
    use_colors: false
  access:
    "()": uvicorn.logging.AccessFormatter
    fmt: '%(asctime)s - %(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s'
    datefmt: "%Y-%m-%d %H:%M:%S"
handlers:
  default:
    formatter: default
    class: logging.StreamHandler
    stream: ext://sys.stderr
  access:
    formatter: access
    class: logging.StreamHandler
    stream: ext://sys.stdout
  file:
    formatter: default
    class: logging.FileHandler
    filename: uvicorn.log
loggers:
  uvicorn:
    handlers:
      - default
      - file
    level: INFO
    propagate: false
  uvicorn.error:
    level: INFO
  uvicorn.access:
    handlers:
      - access
    level: INFO
    propagate: false

In this example, uvicorn.access still writes to stdout only. To write access logs to the file as well, add file to the uvicorn.access.handlers list.

Disabling Access Logs

Use the --no-access-log CLI flag, or set access_log=False programmatically. This removes all handlers from uvicorn.access without affecting the uvicorn.error logger.

Disabling Colors

Pass --no-use-colors on the command line, or set use_colors=False programmatically. When using a custom --log-config, set use_colors: false on each formatter that extends uvicorn.logging.ColourizedFormatter.

Using a Standard Formatter

If you do not need Uvicorn's colorized output, you can use the standard logging.Formatter instead:

version: 1
disable_existing_loggers: false
formatters:
  default:
    format: "%(asctime)s [%(levelname)s] %(name)s: %(message)s"
    datefmt: "%Y-%m-%d %H:%M:%S"
handlers:
  default:
    formatter: default
    class: logging.StreamHandler
    stream: ext://sys.stderr
loggers:
  uvicorn:
    handlers:
      - default
    level: INFO
    propagate: false
  uvicorn.error:
    level: INFO
  uvicorn.access:
    handlers:
      - default
    level: INFO
    propagate: false

Warning

When using a standard logging.Formatter for the access logger, the %(client_addr)s, %(request_line)s, and %(status_code)s placeholders are not available. The access log line will be formatted using only the standard %(message)s field.