Skip to content
87 changes: 80 additions & 7 deletions titiler/cmr/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""TiTiler+cmr FastAPI application."""

import json
import logging
from logging import config as logging_config
import os
from contextlib import asynccontextmanager

Expand Down Expand Up @@ -33,12 +35,42 @@
auth_config = AuthSettings()


class JSONFormatter(logging.Formatter):
"""Custom JSON formatter for request logs."""

def format(self, record):
"""Format a log record as a JSON object."""
log_entry = {
"timestamp": self.formatTime(record),
"level": record.levelname,
"logger": record.name,
"message": record.getMessage(),
}

# Add extra fields if they exist
extra_fields = [
"method",
"path",
"query_params",
"path_params",
"headers",
"referer",
"origin",
"route",
]

for field in extra_fields:
if hasattr(record, field):
value = getattr(record, field)
# Convert query_params and path_params to dict if they're not already
if field in ["query_params", "path_params"] and hasattr(value, "items"):
value = dict(value)
log_entry[field] = value

return json.dumps(log_entry)


log_level = os.getenv("LOG_LEVEL", "INFO")
logging.basicConfig(
level=getattr(logging, log_level),
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
handlers=[logging.StreamHandler()],
)


@asynccontextmanager
Expand Down Expand Up @@ -152,8 +184,49 @@ async def lifespan(app: FastAPI):

app.add_middleware(CacheControlMiddleware, cachecontrol=settings.cachecontrol)

if settings.debug:
app.add_middleware(LoggerMiddleware, headers=True, querystrings=True)
# Configure logging with support for extra fields
logging_config.dictConfig(
{
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"default": {
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
},
"json": {
"()": JSONFormatter,
},
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"level": log_level,
"formatter": "default",
},
"console_request": {
"class": "logging.StreamHandler",
"level": log_level,
"formatter": "json",
},
},
"loggers": {
"": { # Root logger
"level": log_level,
"handlers": ["console"],
},
"titiler.requests": { # Logger used by LoggerMiddleware
"level": log_level,
"handlers": ["console_request"],
"propagate": False,
},
},
}
)

app.add_middleware(
LoggerMiddleware,
logger=logging.getLogger("titiler.requests"),
)

###############################################################################
# application endpoints
Expand Down
1 change: 0 additions & 1 deletion titiler/cmr/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ class ApiSettings(BaseSettings):
time_series_max_image_size: float = 5.625e7
time_series_statistics_max_total_size: float = 1.5e10
time_series_image_max_total_size: float = 1e8
debug: bool = False

model_config = {
"env_prefix": "TITILER_CMR_",
Expand Down
Loading