Coverage for src/couchers/models/logging.py: 100%
25 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-12-25 10:58 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-12-25 10:58 +0000
1from datetime import datetime
3from sqlalchemy import BigInteger, Boolean, DateTime, Float, String, func
4from sqlalchemy import LargeBinary as Binary
5from sqlalchemy.orm import Mapped, mapped_column
6from sqlalchemy.sql import expression
8from couchers.config import config
9from couchers.models.base import Base
12class APICall(Base):
13 """
14 API call logs
15 """
17 __tablename__ = "api_calls"
18 __table_args__ = {"schema": "logging"}
20 id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
22 # whether the call was made using an api key or session cookies
23 is_api_key: Mapped[bool] = mapped_column(Boolean, server_default=expression.false())
25 # backend version (normally e.g. develop-31469e3), allows us to figure out which proto definitions were used
26 # note that `default` is a python side default, not hardcoded into DB schema
27 version: Mapped[str] = mapped_column(String, default=config["VERSION"])
29 # approximate time of the call
30 time: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
32 # the method call name, e.g. "/org.couchers.api.core.API/ListFriends"
33 method: Mapped[str] = mapped_column(String)
35 # gRPC status code name, e.g. FAILED_PRECONDITION, None if success
36 status_code: Mapped[str | None] = mapped_column(String, nullable=True)
38 # handler duration (excluding serialization, etc)
39 duration: Mapped[float] = mapped_column(Float)
41 # user_id of caller, None means not logged in
42 user_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
44 # sanitized request bytes
45 request: Mapped[bytes | None] = mapped_column(Binary, nullable=True)
47 # sanitized response bytes
48 response: Mapped[bytes | None] = mapped_column(Binary, nullable=True)
50 # whether response bytes have been truncated
51 response_truncated: Mapped[bool] = mapped_column(Boolean, server_default=expression.false())
53 # the exception traceback, if any
54 traceback: Mapped[str | None] = mapped_column(String, nullable=True)
56 # human readable perf report
57 perf_report: Mapped[str | None] = mapped_column(String, nullable=True)
59 # details of the browser, if available
60 ip_address: Mapped[str | None] = mapped_column(String, nullable=True)
61 user_agent: Mapped[str | None] = mapped_column(String, nullable=True)