Skip to content

Instantly share code, notes, and snippets.

@liviaerxin
Last active June 5, 2025 07:23
Show Gist options
  • Save liviaerxin/d320e33cbcddcc5df76dd92948e5be3b to your computer and use it in GitHub Desktop.
Save liviaerxin/d320e33cbcddcc5df76dd92948e5be3b to your computer and use it in GitHub Desktop.
FastAPI and Uvicorn Logging #python #fastapi #uvicorn #logging

FastAPI and Uvicorn Logging

When running FastAPI app, all the logs in console are from Uvicorn and they do not have timestamp and other useful information. As Uvicorn applies python logging module, we can override Uvicorn logging formatter by applying a new logging configuration.

Meanwhile, it's able to unify the your endpoints logging with the Uvicorn logging by configuring all of them in the config file log_conf.yaml.

Before overriding:

uvicorn main:app --reload
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [34318] using StatReload
INFO:     Started server process [34320]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     127.0.0.1:50062 - "GET / HTTP/1.1" 200 OK

After applying log_conf.yaml:

uvicorn main:app --reload --log-config=log_conf.yaml
2023-03-08 15:40:41,170 - uvicorn.error - INFO - Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
2023-03-08 15:40:41,170 - uvicorn.error - INFO - Started reloader process [34322] using StatReload
2023-03-08 15:40:41,297 - asyncio - DEBUG - Using selector: EpollSelector
2023-03-08 15:40:41,432 - uvicorn.error - INFO - Started server process [34324]
2023-03-08 15:40:41,432 - uvicorn.error - INFO - Waiting for application startup.
2023-03-08 15:40:41,432 - uvicorn.error - INFO - Application startup complete.
2023-03-08 15:48:21,450 - main - INFO - request / endpoint!
2023-03-08 15:48:21,450 - uvicorn.access - INFO - 127.0.0.1:59782 - "GET / HTTP/1.1" 200

logs with FastAPI and Uvicorn · tiangolo/fastapi · Discussion #7457 · GitHub

Python Comprehensive Logging using YAML Configuration · GitHub

version: 1
disable_existing_loggers: False
formatters:
default:
# "()": uvicorn.logging.DefaultFormatter
format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
access:
# "()": uvicorn.logging.AccessFormatter
format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
handlers:
default:
formatter: default
class: logging.StreamHandler
stream: ext://sys.stderr
access:
formatter: access
class: logging.StreamHandler
stream: ext://sys.stdout
loggers:
uvicorn.error:
level: INFO
handlers:
- default
propagate: no
uvicorn.access:
level: INFO
handlers:
- access
propagate: no
root:
level: DEBUG
handlers:
- default
propagate: no
from fastapi import FastAPI
import logging
logger = logging.getLogger(__name__)
app = FastAPI()
@app.get("/")
async def func():
logger.info(f"request / endpoint!")
return {"message": "hello world!"}
uvicorn>=0.20.0
fastapi>=0.89.1
PyYAML>=6.0
@gemartinezr
Copy link

gemartinezr commented Apr 18, 2024

you sir (or lady), are very nice! thank you

@4vadim4
Copy link

4vadim4 commented Jul 2, 2024

it great to find this,
thanks !!!

@synthpop123
Copy link

Thanks!

Hi, earlier the message was: "GET / HTTP/1.1" 200 OK, but after manual logging config the mesaage is like: "GET / HTTP/1.1" 200, here we can see that the last mesaage "OK" from line is missing. Also if we hit error 404 then it only shows "404", instead of "404 Not Found".

Just a quick note, updating the format section in config file with "%(asctime)s - %(name)s - %(levelname)s - %(client_addr)s - \"%(request_line)s\" %(status_code)s" will restore the full status message.

Alternatively, a simpler method that worked for me:

# Display Uvicorn access logs with timestamps
log_config = uvicorn.config.LOGGING_CONFIG
log_config["formatters"]["access"]["fmt"] = (
    '%(asctime)s - %(name)s - %(levelname)s - %(client_addr)s - "%(request_line)s" %(status_code)s'
)

uvicorn.run("app:create_app", host="127.0.0.1", port=8000, log_config=log_config)

Hope this helps :)

@lakshman7781
Copy link

thanks working

@adosib
Copy link

adosib commented Nov 15, 2024

If you only really care about logging some extra info for HTTP requests, I've found @app.middleware("http") to be the silver bullet. Excellent example at this SO answer.

@hegerdes
Copy link

Tank you so much for this!

In case you also want to use gunicorn, you just have to convert the conf to JSON and start gunicorn with --log-config-json log_conf.json.
The loggers for gunicorn are called:

"gunicorn.error": {
    "level": "INFO",
    "handlers": [
        "default"
    ],
    "propagate": "no"
},
"gunicorn.access": {
    "level": "INFO",
    "handlers": [
        "access"
    ],
    "propagate": "no"
}

@msissican
Copy link

It is very helpful, thanks a lot!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment