Skip to main content

pitchfork_cli/log_store/
mod.rs

1use crate::Result;
2use crate::daemon_id::DaemonId;
3use chrono::{DateTime, Local};
4
5/// A single log entry.
6#[derive(Debug, Clone)]
7pub struct LogEntry {
8    pub id: i64,
9    pub daemon_id: String,
10    pub timestamp: DateTime<Local>,
11    pub message: String,
12}
13
14/// Options for querying logs.
15#[derive(Debug, Clone, Default)]
16pub struct LogQuery {
17    pub daemon_ids: Vec<String>,
18    pub from: Option<DateTime<Local>>,
19    pub to: Option<DateTime<Local>>,
20    pub limit: Option<usize>,
21    pub order_desc: bool,
22    pub after_id: Option<i64>,
23}
24
25/// Parsed retention policy.
26#[derive(Debug, Clone, Copy)]
27pub struct RetentionPolicy {
28    /// Maximum age of entries to keep.
29    pub age: Option<chrono::Duration>,
30    /// Maximum number of entries to keep.
31    pub count: Option<u64>,
32}
33
34impl RetentionPolicy {
35    #[allow(dead_code)]
36    pub fn is_none(&self) -> bool {
37        self.age.is_none() && self.count.is_none()
38    }
39}
40
41/// Unified interface for log storage and retrieval.
42pub trait LogStore: Send + Sync {
43    /// Append a single log line.
44    fn append(&self, daemon_id: &DaemonId, message: &str) -> Result<()>;
45
46    /// Query logs according to the given options.
47    fn query(&self, opts: &LogQuery) -> Result<Vec<LogEntry>>;
48
49    /// Read new log entries for a daemon.
50    /// When `after_id` is Some(id), returns only entries with row id > id.
51    /// When `after_id` is None, returns all entries for the daemon.
52    fn tail(&self, daemon_id: &DaemonId, after_id: Option<i64>) -> Result<Vec<LogEntry>>;
53
54    /// Clear all logs for the given daemon(s).
55    fn clear(&self, daemon_ids: &[DaemonId]) -> Result<()>;
56
57    /// Apply a retention policy (age-based and/or count-based pruning).
58    ///
59    /// By default this applies to all daemons; `excluded_daemon_ids` can be
60    /// used to skip daemons that have their own per-daemon overrides, so the
61    /// global policy does not accidentally prune entries those daemons intend
62    /// to keep.
63    fn apply_retention(
64        &self,
65        policy: &RetentionPolicy,
66        excluded_daemon_ids: &[DaemonId],
67    ) -> Result<u64> {
68        let _ = (policy, excluded_daemon_ids);
69        Ok(0)
70    }
71
72    /// Apply a retention policy to a specific daemon's logs.
73    fn apply_retention_for_daemon(
74        &self,
75        daemon_id: &DaemonId,
76        policy: &RetentionPolicy,
77    ) -> Result<u64> {
78        let _ = (daemon_id, policy);
79        Ok(0)
80    }
81
82    /// List all daemon IDs that have log entries.
83    fn list_daemon_ids(&self) -> Result<Vec<String>>;
84
85    /// Return the generation number for the daemon's last clear operation.
86    /// Each call to `clear` bumps the generation, so SSE streams can detect
87    /// when logs have been wiped and refresh their display.
88    fn last_clear_generation(&self, daemon_id: &DaemonId) -> Result<Option<u64>> {
89        let _ = daemon_id;
90        Ok(None)
91    }
92}
93
94pub mod sqlite;