From c8733ce3c026417eaa318a498c752381053a1fd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aubin=20Lambar=C3=A9?= Date: Fri, 9 Aug 2024 10:09:38 +0200 Subject: [PATCH] refactor(server): logs format (#1238) --- eodag/cli.py | 36 +++++++++---- eodag/rest/server.py | 36 ++++++------- eodag/utils/logging.py | 114 +++++++++++++---------------------------- 3 files changed, 80 insertions(+), 106 deletions(-) diff --git a/eodag/cli.py b/eodag/cli.py index cc15809f2..0dcacbcf9 100755 --- a/eodag/cli.py +++ b/eodag/cli.py @@ -39,6 +39,7 @@ noqa: D103 """ + from __future__ import annotations import json @@ -684,19 +685,32 @@ def serve_rest( else: sys.exit(0) else: + import logging + logging_config = uvicorn.config.LOGGING_CONFIG - if debug: - logging_config["loggers"]["uvicorn"]["level"] = "DEBUG" - logging_config["loggers"]["uvicorn.error"]["level"] = "DEBUG" - logging_config["loggers"]["uvicorn.access"]["level"] = "DEBUG" - logging_config["formatters"]["default"][ - "fmt" - ] = "%(asctime)-15s %(name)-32s [%(levelname)-8s] (%(module)-17s) %(message)s" - logging_config["loggers"]["eodag"] = { - "handlers": ["default"], - "level": "DEBUG" if debug else "INFO", - "propagate": False, + uvicorn_fmt = "%(asctime)-15s %(name)-32s [%(levelname)-8s] %(message)s" + logging_config["formatters"]["access"]["fmt"] = uvicorn_fmt + logging_config["formatters"]["default"]["fmt"] = uvicorn_fmt + + eodag_formatter = logging.Formatter( + "%(asctime)-15s %(name)-32s [%(levelname)-8s] (tid=%(thread)d) %(message)s" + ) + logging.getLogger("eodag").handlers[0].setFormatter(eodag_formatter) + + if ctx.obj["verbosity"] <= 1: + logging_config["handlers"]["null"] = { + "level": "DEBUG", + "class": "logging.NullHandler", } + logging_config["loggers"]["uvicorn"]["handlers"] = ["null"] + logging_config["loggers"]["uvicorn.error"]["handlers"] = ["null"] + logging_config["loggers"]["uvicorn.access"]["handlers"] = ["null"] + else: + log_level = "INFO" if ctx.obj["verbosity"] == 2 else "DEBUG" + logging_config["loggers"]["uvicorn"]["level"] = log_level + logging_config["loggers"]["uvicorn.error"]["level"] = log_level + logging_config["loggers"]["uvicorn.access"]["level"] = log_level + uvicorn.run( "eodag.rest.server:app", host=bind_host, diff --git a/eodag/rest/server.py b/eodag/rest/server.py index a668e4355..a5085330f 100755 --- a/eodag/rest/server.py +++ b/eodag/rest/server.py @@ -355,7 +355,7 @@ async def handle_timeout(request: Request, error: Exception) -> ORJSONResponse: @router.api_route(methods=["GET", "HEAD"], path="/", tags=["Capabilities"]) async def catalogs_root(request: Request) -> ORJSONResponse: """STAC catalogs root""" - logger.debug("URL: %s", request.url) + logger.info(f"{request.method} {request.state.url}") response = await get_stac_catalogs( request=request, @@ -367,9 +367,9 @@ async def catalogs_root(request: Request) -> ORJSONResponse: @router.api_route(methods=["GET", "HEAD"], path="/conformance", tags=["Capabilities"]) -def conformance() -> ORJSONResponse: +def conformance(request: Request) -> ORJSONResponse: """STAC conformance""" - logger.debug("URL: /conformance") + logger.info(f"{request.method} {request.state.url}") response = get_stac_conformance() return ORJSONResponse(response) @@ -382,7 +382,7 @@ def conformance() -> ORJSONResponse: ) def stac_extension_oseo(request: Request) -> ORJSONResponse: """STAC OGC / OpenSearch extension for EO""" - logger.debug("URL: %s", request.url) + logger.info(f"{request.method} {request.state.url}") response = get_stac_extension_oseo(url=request.state.url) return ORJSONResponse(response) @@ -398,7 +398,7 @@ def stac_collections_item_download( collection_id: str, item_id: str, request: Request ) -> StarletteResponse: """STAC collection item download""" - logger.debug("URL: %s", request.url) + logger.info(f"{request.method} {request.state.url}") arguments = dict(request.query_params) provider = arguments.pop("provider", None) @@ -422,7 +422,7 @@ def stac_collections_item_download_asset( collection_id: str, item_id: str, asset: str, request: Request ): """STAC collection item asset download""" - logger.debug("URL: %s", request.url) + logger.info(f"{request.method} {request.state.url}") arguments = dict(request.query_params) provider = arguments.pop("provider", None) @@ -446,7 +446,7 @@ def stac_collections_item( collection_id: str, item_id: str, request: Request, provider: Optional[str] = None ) -> ORJSONResponse: """STAC collection item by id""" - logger.debug("URL: %s", request.url) + logger.info(f"{request.method} {request.state.url}") search_request = SearchPostRequest( provider=provider, ids=[item_id], collections=[collection_id], limit=1 @@ -522,7 +522,7 @@ async def list_collection_queryables( :param collection_id: The identifier of the collection for which to retrieve queryable properties. :returns: A json object containing the list of available queryable properties for the specified collection. """ - logger.debug(f"URL: {request.url}") + logger.info(f"{request.method} {request.state.url}") additional_params = dict(request.query_params) provider = additional_params.pop("provider", None) @@ -545,7 +545,7 @@ async def collection_by_id( collection_id: str, request: Request, provider: Optional[str] = None ) -> ORJSONResponse: """STAC collection by id""" - logger.debug("URL: %s", request.url) + logger.info(f"{request.method} {request.state.url}") response = await get_collection( request=request, @@ -576,7 +576,7 @@ async def collections( Can be filtered using parameters: instrument, platform, platformSerialIdentifier, sensorType, processingLevel """ - logger.debug("URL: %s", request.url) + logger.info(f"{request.method} {request.state.url}") collections = await all_collections( request, provider, q, platform, instrument, constellation, datetime @@ -594,7 +594,7 @@ def stac_catalogs_item_download( catalogs: str, item_id: str, request: Request ) -> StarletteResponse: """STAC Catalog item download""" - logger.debug("URL: %s", request.url) + logger.info(f"{request.method} {request.state.url}") arguments = dict(request.query_params) provider = arguments.pop("provider", None) @@ -620,7 +620,7 @@ def stac_catalogs_item_download_asset( catalogs: str, item_id: str, asset_filter: str, request: Request ): """STAC Catalog item asset download""" - logger.debug("URL: %s", request.url) + logger.info(f"{request.method} {request.state.url}") arguments = dict(request.query_params) provider = arguments.pop("provider", None) @@ -647,7 +647,7 @@ def stac_catalogs_item( catalogs: str, item_id: str, request: Request, provider: Optional[str] = None ): """Fetch catalog's single features.""" - logger.debug("URL: %s", request.url) + logger.info(f"{request.method} {request.state.url}") list_catalog = catalogs.strip("/").split("/") @@ -682,7 +682,7 @@ def stac_catalogs_items( crunch: Optional[str] = None, ) -> ORJSONResponse: """Fetch catalog's features""" - logger.debug("URL: %s", request.state.url) + logger.info(f"{request.method} {request.state.url}") base_args = { "provider": provider, @@ -721,7 +721,7 @@ async def stac_catalogs( catalogs: str, request: Request, provider: Optional[str] = None ) -> ORJSONResponse: """Describe the given catalog and list available sub-catalogs""" - logger.debug("URL: %s", request.url) + logger.info(f"{request.method} {request.state.url}") if not catalogs: raise HTTPException( @@ -756,7 +756,7 @@ async def list_queryables(request: Request) -> ORJSONResponse: :param request: The incoming request object. :returns: A json object containing the list of available queryable terms. """ - logger.debug(f"URL: {request.url}") + logger.info(f"{request.method} {request.state.url}") additional_params = dict(request.query_params.items()) provider = additional_params.pop("provider", None) queryables = await get_queryables( @@ -789,7 +789,7 @@ def get_search( crunch: Optional[str] = None, ) -> ORJSONResponse: """Handler for GET /search""" - logger.debug("URL: %s", request.state.url) + logger.info(f"{request.method} {request.state.url}") query_params = str(request.query_params) @@ -843,7 +843,7 @@ def get_search( ) async def post_search(request: Request) -> ORJSONResponse: """STAC post search""" - logger.debug("URL: %s", request.url) + logger.info(f"{request.method} {request.state.url}") content_type = request.headers.get("Content-Type") diff --git a/eodag/utils/logging.py b/eodag/utils/logging.py index d4a75a867..04b753d7e 100644 --- a/eodag/utils/logging.py +++ b/eodag/utils/logging.py @@ -37,88 +37,48 @@ def setup_logging(verbose: int, no_progress_bar: bool = False) -> None: global disable_tqdm disable_tqdm = no_progress_bar + if verbose > 3: + raise ValueError("'verbose' must be one of: 0, 1, 2, 3") + if verbose < 1: disable_tqdm = True - if verbose <= 1: - logging.config.dictConfig( - { - "version": 1, - "disable_existing_loggers": False, - "handlers": { - "null": {"level": "DEBUG", "class": "logging.NullHandler"} - }, - "loggers": { - "eodag": {"handlers": ["null"], "propagate": True, "level": "INFO"} - }, - } - ) - elif verbose == 2: - logging.config.dictConfig( - { - "version": 1, - "disable_existing_loggers": False, - "formatters": { - "standard": { - "format": "%(asctime)-15s %(name)-32s [%(levelname)-8s] %(message)s" - } - }, - "handlers": { - "console": { - "level": "DEBUG", - "class": "logging.StreamHandler", - "formatter": "standard", - } - }, - "loggers": { - "eodag": { - "handlers": ["console"], - "propagate": True, - "level": "INFO", - }, - "sentinelsat": { - "handlers": ["console"], - "propagate": True, - "level": "INFO", - }, - }, - } - ) - elif verbose == 3: - logging.config.dictConfig( - { - "version": 1, - "disable_existing_loggers": False, - "formatters": { - "verbose": { - "format": ( - "%(asctime)-15s %(name)-32s [%(levelname)-8s] (tid=%(thread)d) %(message)s" - ) - } - }, - "handlers": { - "console": { - "level": "DEBUG", - "class": "logging.StreamHandler", - "formatter": "verbose", - } + level = "DEBUG" if verbose == 3 else "INFO" + + handlers = { + "console": { + "level": level, + "class": "logging.StreamHandler", + "formatter": "standard", + }, + "null": {"level": level, "class": "logging.NullHandler"}, + } + handler = "console" if verbose > 1 else "null" + + logging.config.dictConfig( + { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "standard": { + "format": "%(asctime)-15s %(name)-32s [%(levelname)-8s] %(message)s" + } + }, + "handlers": handlers, + "loggers": { + "eodag": { + "handlers": [handler], + "propagate": True, + "level": f"{level}", }, - "loggers": { - "eodag": { - "handlers": ["console"], - "propagate": True, - "level": "DEBUG", - }, - "sentinelsat": { - "handlers": ["console"], - "propagate": True, - "level": "DEBUG", - }, + "eodag-cube": { + "handlers": [handler], + "propagate": True, + "level": f"{level}", }, - } - ) - else: - raise ValueError("'verbose' must be one of: 0, 1, 2, 3") + }, + } + ) def get_logging_verbose() -> Optional[int]: