feat: add cache and logging

This commit is contained in:
2024-07-31 00:18:32 +03:00
parent 7f0e19fb5a
commit 891869c58c
7 changed files with 85 additions and 7 deletions

View File

@@ -21,4 +21,4 @@ COPY --from=builder /app ./
COPY gismeteo gismeteo/ COPY gismeteo gismeteo/
COPY weather weather/ COPY weather weather/
CMD ["uvicorn", "weather.main:app", "--host", "0.0.0.0", "--port", "80"] CMD ["uvicorn", "weather.main:app", "--host", "0.0.0.0", "--port", "80", "--log-config", "weather/logging.yaml"]

View File

@@ -1,7 +1,9 @@
import datetime import datetime
import logging
from typing import Any, Dict, List from typing import Any, Dict, List
import aiohttp import aiohttp
from aiocache import cached
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from weather.api import WeatherApi from weather.api import WeatherApi
@@ -11,15 +13,27 @@ from . import datehelp
from .location import LOCATION_BUNDLE from .location import LOCATION_BUNDLE
from .parser import DAYS_PARSER, LOCATION_PARSER, ONE_DAY_PARSER, ROW_PARSERS from .parser import DAYS_PARSER, LOCATION_PARSER, ONE_DAY_PARSER, ROW_PARSERS
logger = logging.getLogger("gismeteo")
class GismeteoApi(WeatherApi): class GismeteoApi(WeatherApi):
BASE_URL = "https://www.gismeteo.ru" BASE_URL = "https://www.gismeteo.ru"
CACHE_TTL = 10 * 60
USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" USER_AGENT = (
COOKIE = "cf_clearance=U28mYVC0ENu88vorlL_CWmWOoevvXp0vb4xCqfqYC9s-1722273367-1.0.1.1-IDV73azTHY0V.NAnmEvok3zf5HHEkvF098pmya7IiqRRB5nk3FhbLCb0AeWm_kpTFqi1niFk2mYN_ramGTSl0A" "Mozilla/5.0 (X11; Linux x86_64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/126.0.0.0 Safari/537.36"
)
COOKIE = (
"cf_clearance=U28mYVC0ENu88vorlL_CWmWOoevvXp0vb4xCqfqYC9s-"
"1722273367-1.0.1.1-"
"IDV73azTHY0V.NAnmEvok3zf5HHEkvF098pmya7IiqRRB5nk3FhbLCb0AeWm_kpTFqi1niFk2mYN_ramGTSl0A"
)
async def _request(self, endpoint: str) -> str: async def _request(self, endpoint: str) -> str:
url = f"{self.BASE_URL}/{endpoint}" url = f"{self.BASE_URL}/{endpoint}"
logger.info(url)
async with aiohttp.ClientSession( async with aiohttp.ClientSession(
headers={ headers={
"User-Agent": self.USER_AGENT, "User-Agent": self.USER_AGENT,
@@ -58,7 +72,6 @@ class GismeteoApi(WeatherApi):
while len(result) < index + 1: while len(result) < index + 1:
result.append({}) result.append({})
result[index][parser.KEY] = value result[index][parser.KEY] = value
print(">", result)
values = [WeatherValue(**item) for item in result] values = [WeatherValue(**item) for item in result]
return WeatherResponse( return WeatherResponse(
location=location or "n/a", location=location or "n/a",
@@ -67,11 +80,13 @@ class GismeteoApi(WeatherApi):
values=values, values=values,
) )
@cached(ttl=CACHE_TTL)
async def get_day(self, location_id: str, date: datetime.date) -> WeatherResponse: async def get_day(self, location_id: str, date: datetime.date) -> WeatherResponse:
location = LOCATION_BUNDLE.parse(location_id) location = LOCATION_BUNDLE.parse(location_id)
data = await self._request(f"weather-{location}/{datehelp.dump(date)}") data = await self._request(f"weather-{location}/{datehelp.dump(date)}")
return self._parse_oneday(date, data) return self._parse_oneday(date, data)
@cached(ttl=CACHE_TTL)
async def get_days(self, location_id: str, days: int) -> WeatherResponse: async def get_days(self, location_id: str, days: int) -> WeatherResponse:
location = LOCATION_BUNDLE.parse(location_id) location = LOCATION_BUNDLE.parse(location_id)
data = await self._request(f"weather-{location}/{days}-days") data = await self._request(f"weather-{location}/{days}-days")

18
poetry.lock generated
View File

@@ -1,5 +1,21 @@
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. # This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
[[package]]
name = "aiocache"
version = "0.12.2"
description = "multi backend asyncio cache"
optional = false
python-versions = "*"
files = [
{file = "aiocache-0.12.2-py2.py3-none-any.whl", hash = "sha256:9b6fa30634ab0bfc3ecc44928a91ff07c6ea16d27d55469636b296ebc6eb5918"},
{file = "aiocache-0.12.2.tar.gz", hash = "sha256:b41c9a145b050a5dcbae1599f847db6dd445193b1f3bd172d8e0fe0cb9e96684"},
]
[package.extras]
memcached = ["aiomcache (>=0.5.2)"]
msgpack = ["msgpack (>=0.5.5)"]
redis = ["redis (>=4.2.0)"]
[[package]] [[package]]
name = "aiohttp" name = "aiohttp"
version = "3.9.5" version = "3.9.5"
@@ -1795,4 +1811,4 @@ multidict = ">=4.0"
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.12" python-versions = "^3.12"
content-hash = "bc04729da7680c2e078b4abd6e402186b54a938ef5cee388b0b2c462f6c167f1" content-hash = "61e9ac2e623a1f5f543705c252f34f8e15b58e164b0a8c14330b12d814a3c778"

View File

@@ -12,6 +12,7 @@ aiohttp = "^3.9.5"
beautifulsoup4 = "^4.12.3" beautifulsoup4 = "^4.12.3"
dateparser = "^1.2.0" dateparser = "^1.2.0"
pydantic = "^2.8.2" pydantic = "^2.8.2"
aiocache = "^0.12.2"
[tool.poetry.group.app.dependencies] [tool.poetry.group.app.dependencies]
fastapi = "^0.111.1" fastapi = "^0.111.1"

View File

@@ -23,7 +23,12 @@
"type": "debugpy", "type": "debugpy",
"request": "launch", "request": "launch",
"module": "uvicorn", "module": "uvicorn",
"args": ["weather.main:app", "--reload"] "args": [
"weather.main:app",
"--reload",
"--log-config",
"weather/logging.yaml"
]
} }
] ]
} }

34
weather/logging.yaml Normal file
View File

@@ -0,0 +1,34 @@
version: 1
disable_existing_loggers: False
formatters:
default:
# "()": uvicorn.logging.DefaultFormatter
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
access:
# "()": uvicorn.logging.AccessFormatter
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
handlers:
default:
formatter: default
class: logging.StreamHandler
stream: ext://sys.stderr
access:
formatter: access
class: logging.StreamHandler
stream: ext://sys.stdout
loggers:
uvicorn.error:
level: INFO
handlers:
- default
propagate: no
uvicorn.access:
level: INFO
handlers:
- access
propagate: no
root:
level: INFO
handlers:
- default
propagate: no

View File

@@ -1,4 +1,5 @@
from os import environ from os import environ
from pathlib import Path
import uvicorn import uvicorn
@@ -9,4 +10,10 @@ app = build_app(GismeteoApi())
def run(): def run():
uvicorn.run("weather.main:app", host="0.0.0.0", port=8000, reload="DEBUG" in environ) uvicorn.run(
"weather.main:app",
host="0.0.0.0",
port=8000,
log_config=str(Path(__file__).parent / "logging.yaml"),
reload="DEBUG" in environ,
)