79 lines
2.6 KiB
Python
79 lines
2.6 KiB
Python
import json
|
|
import os
|
|
import sqlite3
|
|
import time
|
|
import uuid
|
|
|
|
|
|
DEFAULT_DB_PATH = "/var/lib/recipe/metrics.sqlite3"
|
|
|
|
|
|
def db_path() -> str:
|
|
return os.environ.get("RECIPE_METRICS_DB", DEFAULT_DB_PATH)
|
|
|
|
|
|
def initialize() -> None:
|
|
path = db_path()
|
|
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
with sqlite3.connect(path) as connection:
|
|
connection.execute("PRAGMA journal_mode=WAL")
|
|
connection.execute("""
|
|
CREATE TABLE IF NOT EXISTS requests (
|
|
request_id TEXT PRIMARY KEY,
|
|
started_at TEXT NOT NULL,
|
|
client_ip TEXT,
|
|
user_agent TEXT,
|
|
method TEXT NOT NULL,
|
|
path TEXT NOT NULL,
|
|
image_mime TEXT,
|
|
image_bytes INTEGER,
|
|
prompt_chars INTEGER,
|
|
status_code INTEGER NOT NULL,
|
|
duration_ms INTEGER NOT NULL,
|
|
response_bytes INTEGER,
|
|
usage_json TEXT,
|
|
error TEXT
|
|
)
|
|
""")
|
|
connection.execute("CREATE INDEX IF NOT EXISTS idx_requests_started_at ON requests(started_at)")
|
|
connection.execute("CREATE INDEX IF NOT EXISTS idx_requests_status_code ON requests(status_code)")
|
|
connection.execute(
|
|
"CREATE INDEX IF NOT EXISTS idx_requests_client_ip_started_at ON requests(client_ip, started_at)"
|
|
)
|
|
|
|
|
|
def record(**values) -> None:
|
|
columns = [
|
|
"request_id", "started_at", "client_ip", "user_agent", "method",
|
|
"path", "image_mime", "image_bytes", "prompt_chars", "status_code",
|
|
"duration_ms", "response_bytes", "usage_json", "error",
|
|
]
|
|
payload = [values.get(column) for column in columns]
|
|
with sqlite3.connect(db_path()) as connection:
|
|
connection.execute(
|
|
f"INSERT INTO requests ({','.join(columns)}) VALUES ({','.join('?' for _ in columns)})",
|
|
payload,
|
|
)
|
|
|
|
|
|
def count_since(client_ip: str, started_at_from: str) -> int:
|
|
with sqlite3.connect(db_path()) as connection:
|
|
row = connection.execute(
|
|
"""
|
|
SELECT COUNT(*)
|
|
FROM requests
|
|
WHERE client_ip = ?
|
|
AND started_at >= ?
|
|
AND path IN ('/receipt', '/receipt/', '/recipe', '/recipe/')
|
|
""",
|
|
(client_ip, started_at_from),
|
|
).fetchone()
|
|
return int(row[0] if row else 0)
|
|
|
|
|
|
def request_context() -> tuple[str, str, float]:
|
|
return str(uuid.uuid4()), time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), time.monotonic()
|
|
|
|
|
|
def usage_json(usage: dict) -> str:
|
|
return json.dumps(usage, ensure_ascii=True, separators=(",", ":")) |