anyway/backend/launcher.py
Remy Moll bc63b57154
Some checks failed
Run linting on the backend code / Build (pull_request) Has been cancelled
Run testing on the backend code / Build (pull_request) Has been cancelled
Build and deploy the backend to staging / Build and push image (pull_request) Successful in 2m14s
Build and deploy the backend to staging / Deploy to staging (pull_request) Successful in 38s
dumb type conversion
2024-12-28 22:34:14 +01:00

83 lines
3.0 KiB
Python

"""Launcher for the FastAPI application. Fundametally this replicates the functionality of the uvicorn and fastapi CLI interfaces, but we need this to setup the logging correctly (and most importantly globally)"""
import os
import uvicorn
import logging
logger = logging.getLogger(__name__)
is_debug = os.getenv('DEBUG', "false") == "true"
is_kubernetes = os.getenv('KUBERNETES_SERVICE_HOST', None) is not None
def logger_setup():
"""
Setup the global logging configuration
"""
logging_format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
# Make uvicorn conform to the global logging configuration
uvicorn_logger = logging.getLogger('uvicorn')
uvicorn_logger.propagate = True
uvicorn_logger.handlers = [] # Remove default handlers to avoid duplicate logs
if is_kubernetes:
# in that case we want to log to stdout and also to loki
from loki_logger_handler.loki_logger_handler import LokiLoggerHandler
loki_url = os.getenv('LOKI_URL')
if loki_url is None:
raise ValueError("LOKI_URL environment variable is not set")
loki_handler = LokiLoggerHandler(
url = loki_url,
labels = {'app': 'anyway', 'environment': 'staging' if is_debug else 'production'}
)
logger.info(f"Logging to Loki at {loki_url} with {loki_handler.labels} and {is_debug=}")
if is_debug:
logging.basicConfig(
format = logging_format,
level = logging.DEBUG,
handlers = [loki_handler, logging.StreamHandler()]
)
# we need to silence the debug logs made by the loki handler
logging.getLogger('urllib3.connectionpool').setLevel(logging.INFO)
else:
logging.basicConfig(
format = logging_format,
level = logging.INFO,
handlers = [loki_handler, logging.StreamHandler()]
)
else:
# if we are in a debug (local) session, set verbose and rich logging
from rich.logging import RichHandler
logging.basicConfig(
format = logging_format,
level = logging.DEBUG,
handlers = [RichHandler()]
)
def uvicorn_run():
"""
Run the FastAPI application using uvicorn
"""
num_workers = int(os.getenv('NUM_WORKERS', 1))
logger.info(f"Starting FastAPI+uvicorn with {num_workers=}, {is_debug=}, {is_kubernetes=}")
uvicorn.run(
# we could in theory directly import the app and pass it as an object
# this 'import string' is required for hot reloading and scaling
'src.main:app',
host = '0.0.0.0',
port = 8000,
log_config = None,
access_log = True,
# Disable uvicorn's logging configuration so that it inherits the global one
workers = num_workers,
# Hot reload breaks logging, so we leave it disabled
# reload = is_debug
)
if __name__ == '__main__':
logger_setup()
uvicorn_run()