Recently, when I was using FastAPI, I found that the official documentation of FastAPI did not have instructions related to configuring logs. Today, I will share three methods of configuring logs for FastAPI.

 

The first one, logging like writing a script

This method is the simplest and most straightforward, how to record logs when writing scripts, how to record logs here, usually is to first configure the log format, and then logger.info in the required place a:

Configuration Log:

import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)
ch = logging.StreamHandler()
fh = logging.FileHandler(filename='./server.log')
formatter = logging.Formatter(
    "%(asctime)s - %(module)s - %(funcName)s - line:%(lineno)d - %(levelname)s - %(message)s"
)

ch.setFormatter(formatter)
fh.setFormatter(formatter)
logger.addHandler(ch) #Exporting logs to the screen
logger.addHandler(fh) #Exporting logs to a file

If you are afraid that the file will be too large, you can use the circular log:

fh = logging.handlers.RotatingFileHandler("api.log",mode="a",maxBytes = 100*1024, backupCount = 3)

Then, add logger.info / logger.warning / logger.debug / logger.error to the places where you need to log

from fastapi import FastAPI

# setup loggers
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
ch = logging.StreamHandler()
fh = logging.FileHandler(filename='./server.log'))
ch.setFormatter(LogFormatter())
fh.setFormatter(LogFormatter())
logger.addHandler(ch) #Exporting logs to the screen
logger.addHandler(fh) #Exporting logs to a file



app = FastAPI()

@app.get("/")
async def root():
    logger.info("logging from the root logger")
    return {"status": "alive"}

You might say, "I have a particularly large number of interfaces, should I add them line by line?

No, you can intercept all requests inside the middleware and log each request, the full code is shown below:

File name main.py, focus on log_requests function:

import logging
from fastapi import FastAPI
import time
import random
import string

logger = logging.getLogger()
logger.setLevel(logging.INFO)
ch = logging.StreamHandler()
fh = logging.FileHandler(filename='./server.log')
formatter = logging.Formatter(
    "%(asctime)s - %(module)s - %(funcName)s - line:%(lineno)d - %(levelname)s - %(message)s"
)

ch.setFormatter(formatter)
fh.setFormatter(formatter)
logger.addHandler(ch) #Exporting logs to the screen
logger.addHandler(fh) #Exporting logs to a file


logger = logging.getLogger(__name__)

app = FastAPI()

@app.middleware("http")
async def log_requests(request, call_next):
    idem = ''.join(random.choices(string.ascii_uppercase + string.digits, k=6))
    logger.info(f"rid={idem} start request path={request.url.path}")
    start_time = time.time()
    
    response = await call_next(request)
    
    process_time = (time.time() - start_time) * 1000
    formatted_process_time = '{0:.2f}'.format(process_time)
    logger.info(f"rid={idem} completed_in={formatted_process_time}ms status_code={response.status_code}")
    
    return response


@app.get("/")
async def root():
    return {"status": "alive"}

Command line uvicorn main:app --host 0.0.0.0 --port 8081 Then visit http://localhost:8081 and you will see the log output, which is also saved in the server.log file:

FastAPI

The second one, logging uvicorn logs

fastapi is actually uvicorn-driven, and uvicorn itself will output information in the terminal:

❯ uvicorn main:app --host 0.0.0.0 --port 8081
INFO:     Started server process [88064]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8081 (Press CTRL+C to quit)

Just record this information in a file, which can be configured when fastapi starts:

@app.on_event("startup")
async def startup_event():
    logger = logging.getLogger("uvicorn.access")
    handler = logging.handlers.RotatingFileHandler("api.log",mode="a",maxBytes = 100*1024, backupCount = 3)
    handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
    logger.addHandler(handler)

这样,uvicorn 的输出,就会记录在 api.log 中。

Third, configure uvicorn's logs

If you are running FastApi this way:

app = FastAPI()
uvicorn.run(app, host="0.0.0.0", port=8000)

Then you can configure uvicorn's logging in the code, and then pass in the logging configuration information in the run function, and you're done:

log_config = uvicorn.config.LOGGING_CONFIG
log_config["formatters"]["access"]["fmt"] = "%(asctime)s - %(levelname)s - %(message)s"
log_config["formatters"]["default"]["fmt"] = "%(asctime)s - %(levelname)s - %(message)s"
uvicorn.run(app, log_config=log_config)

Of course, the configuration file can also be passed in from the command line via uvicorn --log-config=log.ymal:

version: 1
formatters:
  simple:
    format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
handlers:
  console:
    class: logging.StreamHandler
    level: DEBUG
    formatter: simple
    stream: ext://sys.stdout
loggers:
  simpleExample:
    level: DEBUG
    handlers: [console]
    propagate: no
root:
  level: DEBUG
  handlers: [console]

Log files support .ini, .json, .yaml formats.

Related articles

FastAPI interface flow limitation

Without interface flow limiting, it may lead to server load imbalance, brute force password cracking, malicious requests, extra server charges, denial of service attacks, etc. Therefore it is necessary to do a good job of interface flow limiting.

Replacing excel with Mito

Mito is a spreadsheet library in Python. If you can edit Excel files, you can write code. That's because for every action we perform in a table, Mito will automatically generate the corresponding Python code. Say goodbye to repetitive and boring operation

Python face recognition algorithm

Today we give you a summary of a few simple and good face recognition algorithms. Face recognition is a relatively common technology in computer vision. In life, the face recognition scenario that we have the most contact with is face attendance.

Three ways to parse parameters in Python

Like the diagram above, we have a standard structure to organize our small projects: The folder named data that contains our dataset train.py file The options.py file for specifying hyperparameters

Seaborn draws 11 bar charts

This article is about how to use seaborn to draw various bar charts Base Bar Chart Horizontal Bar Chart Title Settings DataFrame based drawing hue parameter setting Color processing Multi-dimensional processing

Tips for speeding up pandas

When people talk about data analysis, the most mentioned languages are Python and SQL. python is suitable for data analysis because it has many powerful third-party libraries to assist, pandas being one of them. pandas is described in the documentation as

Speed up pandas with Modin

Modin exists for a reason: to change one line of code to speed up the pandas workflow.Pandas needs no introduction in the field of data science, providing high-performance, easy-to-use data structures and data analysis tools. However, when dealing

How to open a txt file in python

Two ways to open a file f = open("data.txt","r") #Setting the file object f.close() #Close file #For convenience, and to avoid forgetting to close the file object, you can use the following instead

python how to add new content to the dictionary

Adding new content to the dictionary is done by adding new key/value pairs, modifying or deleting existing key/value pairs as shown in the following examples: #!/usr/bin/python dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}