Coverage for src/local_deep_research/database/models/logs.py: 94%
17 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-06 15:42 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-06 15:42 +0000
1"""
2Logging model for storing application logs.
4The ``Journal`` model used to live here too but was moved to
5``journal.py`` for discoverability — it's unrelated to the
6``ResearchLog`` table this file owns. Compat imports of
7``from ...database.models.logs import Journal`` still work via the
8re-export below.
9"""
11from sqlalchemy import (
12 Column,
13 ForeignKey,
14 Index,
15 Integer,
16 Sequence,
17 String,
18 Text,
19)
20from sqlalchemy_utc import UtcDateTime, utcnow
22from .base import Base
23from .journal import Journal # noqa: F401 — compat re-export
26class ResearchLog(Base):
27 """
28 Logging table for all research operations.
30 All logging from research operations, including debug messages,
31 errors, and milestones are stored here.
32 """
34 __tablename__ = "app_logs"
35 __table_args__ = (
36 Index(
37 "ix_app_logs_research_id_timestamp_id",
38 "research_id",
39 "timestamp",
40 "id",
41 ),
42 )
44 id = Column(Integer, Sequence("reseach_log_id_seq"), primary_key=True)
46 timestamp = Column(UtcDateTime, server_default=utcnow(), nullable=False)
47 message = Column(Text, nullable=False)
48 # Module that the log message came from.
49 module = Column(Text, nullable=False)
50 # Function that the log message came from.
51 function = Column(Text, nullable=False)
52 # Line number that the log message came from.
53 line_no = Column(Integer, nullable=False)
54 # Log level.
55 level = Column(String(32), nullable=False)
56 research_id = Column(
57 String(36), # UUID as string
58 ForeignKey("research_history.id", ondelete="CASCADE"),
59 nullable=True,
60 index=True,
61 )
63 def __repr__(self):
64 return f"<ResearchLog({self.level}: '{self.message[:50]}...')>"