actually use fastapi lifetime manager to setup logging
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				Run testing on the backend code / Build (pull_request) Has been cancelled
				
			
		
			
				
	
				Run linting on the backend code / Build (pull_request) Has been cancelled
				
			
		
			
				
	
				Build and deploy the backend to staging / Deploy to staging (pull_request) Has been cancelled
				
			
		
			
				
	
				Build and deploy the backend to staging / Build and push image (pull_request) Has been cancelled
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	Run testing on the backend code / Build (pull_request) Has been cancelled
				
			Run linting on the backend code / Build (pull_request) Has been cancelled
				
			Build and deploy the backend to staging / Deploy to staging (pull_request) Has been cancelled
				
			Build and deploy the backend to staging / Build and push image (pull_request) Has been cancelled
				
			This commit is contained in:
		
							
								
								
									
										56
									
								
								backend/src/logging_config.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								backend/src/logging_config.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| """Sets up global logging configuration for the application.""" | ||||
|  | ||||
| import logging | ||||
| import os | ||||
|  | ||||
| logger = logging.getLogger(__name__) | ||||
|  | ||||
|  | ||||
| def configure_logging(): | ||||
|     """ | ||||
|     Called at startup of a FastAPI application instance to setup logging. Depending on the environment, it will log to stdout or to Loki. | ||||
|     """ | ||||
|  | ||||
|     is_debug = os.getenv('DEBUG', "false") == "true" | ||||
|     is_kubernetes = os.getenv('KUBERNETES_SERVICE_HOST') is not None | ||||
|  | ||||
|  | ||||
|     if not 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') | ||||
|         loki_url = "http://localhost:3100/loki/api/v1/push" | ||||
|         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=}") | ||||
|         logging_handlers = [loki_handler, logging.StreamHandler()] | ||||
|         logging_level = logging.DEBUG if is_debug else logging.INFO | ||||
|         # no need for time since it's added by loki or can be shown in kube logs | ||||
|         logging_format = '%(name)s - %(levelname)s - %(message)s' | ||||
|  | ||||
|     else: | ||||
|         # if we are in a debug (local) session, set verbose and rich logging | ||||
|         from rich.logging import RichHandler | ||||
|         logging_handlers = [RichHandler()] | ||||
|         logging_level = logging.DEBUG if is_debug else logging.INFO | ||||
|         logging_format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' | ||||
|  | ||||
|  | ||||
|  | ||||
|     logging.basicConfig( | ||||
|         level = logging_level, | ||||
|         format = logging_format, | ||||
|         handlers = logging_handlers | ||||
|     ) | ||||
|  | ||||
|     # also overwrite the uvicorn loggers | ||||
|     logging.getLogger('uvicorn').handlers = logging_handlers | ||||
|     logging.getLogger('uvicorn.access').handlers = logging_handlers | ||||
|     logging.getLogger('uvicorn.error').handlers = logging_handlers | ||||
|  | ||||
| @@ -2,7 +2,9 @@ | ||||
|  | ||||
| import logging | ||||
| from fastapi import FastAPI, HTTPException, Query | ||||
| from contextlib import asynccontextmanager | ||||
|  | ||||
| from .logging_config import configure_logging | ||||
| from .structs.landmark import Landmark, Toilets | ||||
| from .structs.preferences import Preferences | ||||
| from .structs.linked_landmarks import LinkedLandmarks | ||||
| @@ -13,15 +15,26 @@ from .utils.optimizer import Optimizer | ||||
| from .utils.refiner import Refiner | ||||
| from .cache import client as cache_client | ||||
|  | ||||
|  | ||||
| logger = logging.getLogger(__name__) | ||||
|  | ||||
| app = FastAPI() | ||||
| manager = LandmarkManager() | ||||
| optimizer = Optimizer() | ||||
| refiner = Refiner(optimizer=optimizer) | ||||
|  | ||||
|  | ||||
| @asynccontextmanager | ||||
| async def lifespan(app: FastAPI): | ||||
|     """Function to run at the start of the app""" | ||||
|     logger.info("Setting up logging") | ||||
|     configure_logging() | ||||
|     yield | ||||
|     logger.info("Shutting down logging") | ||||
|  | ||||
|  | ||||
| app = FastAPI(lifespan=lifespan) | ||||
|  | ||||
|  | ||||
|  | ||||
| @app.post("/trip/new") | ||||
| def new_trip(preferences: Preferences, | ||||
|              start: tuple[float, float], | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| """Definition of the Landmark class to handle visitable objects across the world.""" | ||||
|  | ||||
| from typing import Optional, Literal | ||||
| from uuid import uuid4 | ||||
| from uuid import uuid4, UUID | ||||
| from pydantic import BaseModel, Field | ||||
|  | ||||
|  | ||||
| @@ -29,12 +29,12 @@ class Landmark(BaseModel) : | ||||
|         description (Optional[str]): A text description of the landmark. | ||||
|         duration (Optional[int]): The estimated time to visit the landmark (in minutes). | ||||
|         name_en (Optional[str]): The English name of the landmark. | ||||
|         uuid (str): A unique identifier for the landmark, generated by default using uuid4. | ||||
|         uuid (UUID): A unique identifier for the landmark, generated by default using uuid4. | ||||
|         must_do (Optional[bool]): Whether the landmark is a "must-do" attraction. | ||||
|         must_avoid (Optional[bool]): Whether the landmark should be avoided. | ||||
|         is_secondary (Optional[bool]): Whether the landmark is secondary or less important. | ||||
|         time_to_reach_next (Optional[int]): Estimated time (in minutes) to reach the next landmark. | ||||
|         next_uuid (Optional[str]): UUID of the next landmark in sequence (if applicable). | ||||
|         next_uuid (Optional[UUID]): UUID of the next landmark in sequence (if applicable). | ||||
|     """ | ||||
|  | ||||
|     # Properties of the landmark | ||||
| @@ -52,7 +52,7 @@ class Landmark(BaseModel) : | ||||
|     name_en : Optional[str] = None | ||||
|  | ||||
|     # Unique ID of a given landmark | ||||
|     uuid: str = Field(default_factory=uuid4) | ||||
|     uuid: UUID = Field(default_factory=uuid4) | ||||
|  | ||||
|     # Additional properties depending on specific tour | ||||
|     must_do : Optional[bool] = False | ||||
| @@ -60,7 +60,7 @@ class Landmark(BaseModel) : | ||||
|     is_secondary : Optional[bool] = False | ||||
|  | ||||
|     time_to_reach_next : Optional[int] = 0 | ||||
|     next_uuid : Optional[str] = None | ||||
|     next_uuid : Optional[UUID] = None | ||||
|  | ||||
|     def __str__(self) -> str: | ||||
|         """ | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| """Definition of the Trip class.""" | ||||
|  | ||||
| import uuid | ||||
| from uuid import uuid4, UUID | ||||
| from pydantic import BaseModel, Field | ||||
| from pymemcache.client.base import Client | ||||
|  | ||||
| @@ -19,9 +19,9 @@ class Trip(BaseModel): | ||||
|     Methods: | ||||
|         from_linked_landmarks: create a Trip from LinkedLandmarks object. | ||||
|     """ | ||||
|     uuid: str = Field(default_factory=uuid.uuid4) | ||||
|     uuid: UUID = Field(default_factory=uuid4) | ||||
|     total_time: int | ||||
|     first_landmark_uuid: str | ||||
|     first_landmark_uuid: UUID | ||||
|  | ||||
|  | ||||
|     @classmethod | ||||
| @@ -31,7 +31,7 @@ class Trip(BaseModel): | ||||
|         """ | ||||
|         trip = Trip( | ||||
|             total_time = landmarks.total_time, | ||||
|             first_landmark_uuid = str(landmarks[0].uuid) | ||||
|             first_landmark_uuid = landmarks[0].uuid | ||||
|         ) | ||||
|  | ||||
|         # Store the trip in the cache | ||||
|   | ||||
		Reference in New Issue
	
	Block a user